pax_global_header00006660000000000000000000000064137047257430014526gustar00rootroot0000000000000052 comment=c301f71d1a759320c92163f21850f78e5556c7ef olive-continuous/000077500000000000000000000000001370472574300144145ustar00rootroot00000000000000olive-continuous/.appveyor/000077500000000000000000000000001370472574300163375ustar00rootroot00000000000000olive-continuous/.appveyor/build.bat000066400000000000000000000107501370472574300201310ustar00rootroot00000000000000REM Get git hash in variable [this seems to be the most efficient way] git rev-parse --short=8 HEAD > hash.txt git rev-parse HEAD > longhash.txt set /p GITHASH= < hash.txt set /p GITLONGHASH= < longhash.txt set /p TRAVIS_COMMIT= < longhash.txt REM Set up Visual Studio x64 environment call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" REM Install 64-bit packages set VCPKG_DEFAULT_TRIPLET=x64-windows REM Hack to only install release builds for time echo set(VCPKG_BUILD_TYPE release) >> C:\Tools\vcpkg\triplets\x64-windows.cmake REM Install Open*IO libraries vcpkg install opencolorio vcpkg install openimageio REM Integrate libraries cd c:\tools\vcpkg vcpkg integrate install cd %APPVEYOR_BUILD_FOLDER% REM Acquire FFmpeg set FFMPEG_VER=ffmpeg-4.2.1-win64 curl https://ffmpeg.zeranoe.com/builds/win64/dev/%FFMPEG_VER%-dev.zip > %FFMPEG_VER%-dev.zip curl https://ffmpeg.zeranoe.com/builds/win64/shared/%FFMPEG_VER%-shared.zip > %FFMPEG_VER%-shared.zip 7z x %FFMPEG_VER%-dev.zip 7z x %FFMPEG_VER%-shared.zip REM Add Qt and FFmpeg directory to path set PATH=%PATH%;C:\Qt\5.13.2\msvc2017_64\bin;%APPVEYOR_BUILD_FOLDER%\%FFMPEG_VER%-dev REM Run cmake cmake -G "Ninja" . -DCMAKE_TOOLCHAIN_FILE=c:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo REM Build with Ninja ninja.exe || exit /B 1 REM If this is a pull request, no further packaging/deploying needs to be done if NOT "%APPVEYOR_PULL_REQUEST_NUMBER%" == "" goto end REM Start building package mkdir olive-editor cd olive-editor copy ..\app\olive-editor.exe . copy ..\app\olive-editor.pdb . copy ..\app\crashhandler.exe . windeployqt olive-editor.exe copy ..\%FFMPEG_VER%-shared\bin\*.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\OpenColorIO.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\OpenImageIO.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\yaml-cpp.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\Half-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\Iex-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\IexMath-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\IlmImf-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\IlmImfUtil-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\IlmThread-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\Imath-2_3.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\*.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\*.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\*.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\*.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\libpng16.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\jpeg62.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\tiff.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\zlib1.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\lzma.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\boost_date_time-vc141-mt-x64-1_72.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\boost_filesystem-vc141-mt-x64-1_72.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\boost_thread-vc141-mt-x64-1_72.dll . REM Package done, begin deployment cd .. set PKGNAME=Olive-%GITHASH%-Windows-x86_64 REM Create installer copy app\packaging\windows\nsis\* . "C:/Program Files (x86)/NSIS/makensis.exe" -V4 -DX64 "-XOutFile %PKGNAME%.exe" olive.nsi REM Create portable copy nul olive-editor\portable 7z a %PKGNAME%.zip olive-editor REM We're ready to upload, but we only upload *sometimes* REM set PATH=%PATH%;C:\msys64\usr\bin REM If this was a tagged build, upload if "%APPVEYOR_REPO_TAG%"=="true" GOTO upload REM Else, if this is a continuous build, check if this commit is the most recent REM Force locale to UTF-8 or grep -P fails set LC_ALL=en_US.UTF-8 curl -H "Authorization: token %GITHUB_TOKEN%" https://api.github.com/repos/olive-editor/olive/commits/master > repoinfo.txt grep -Po '(?^<=: \")(([a-z0-9])\w+)(?=\")' -m 1 repoinfo.txt > latestcommit.txt set /p REMOTEHASH= < latestcommit.txt if "%REMOTEHASH%"=="%GITLONGHASH%" GOTO upload REM The previous if statements failed, skip to the end GOTO end :upload set /p UPLOADTOOL_BODY= < latestcommit.txt curl -L https://github.com/probonopd/uploadtool/raw/master/upload.sh > upload.sh bash upload.sh Olive*.zip bash upload.sh Olive*.exe :end REM Check if this build should set up a debugging session IF "%ENABLE_RDP%"=="1" ( powershell -command "$blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))" ) olive-continuous/.clang-format000066400000000000000000000076411370472574300167770ustar00rootroot00000000000000--- Language: Cpp # BasedOnStyle: Google AccessModifierOffset: -1 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: true AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true AlwaysBreakTemplateDeclarations: Yes BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: true DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve IncludeCategories: - Regex: '^' Priority: 2 - Regex: '^<.*\.h>' Priority: 1 - Regex: '^<.*' Priority: 2 - Regex: '.*' Priority: 3 IncludeIsMainRegex: '([-_](test|unittest))?$' IndentCaseLabels: true IndentPPDirectives: None IndentWidth: 2 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Never ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left RawStringFormats: - Language: Cpp Delimiters: - cc - CC - cpp - Cpp - CPP - 'c++' - 'C++' CanonicalDelimiter: '' BasedOnStyle: google - Language: TextProto Delimiters: - pb - PB - proto - PROTO EnclosingFunctions: - EqualsProto - EquivToProto - PARSE_PARTIAL_TEXT_PROTO - PARSE_TEST_PROTO - PARSE_TEXT_PROTO - ParseTextOrDie - ParseTextProtoOrDie CanonicalDelimiter: '' BasedOnStyle: google ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto TabWidth: 8 UseTab: Never ... olive-continuous/.gitattributes000066400000000000000000000001701370472574300173050ustar00rootroot00000000000000# Default behavior * text=auto # Enforce LF line endings on source files *.h text eol=lf *.cpp text eol=lf olive-continuous/.github/000077500000000000000000000000001370472574300157545ustar00rootroot00000000000000olive-continuous/.github/ISSUE_TEMPLATE/000077500000000000000000000000001370472574300201375ustar00rootroot00000000000000olive-continuous/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000014331370472574300226320ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: "[Bug]" labels: '' assignees: '' --- **Your Setup:** - Olive version (window title or Help > About): - Source: (e.g. AppImage, PPA, AUR, website etc.) - Operating system: (e.g. Ubuntu 18.04 64-bit) - CPU: (e.g. Intel i5-4300U) - RAM: (e.g. 8GB) - GPU: (e.g. NVIDIA Geforce GT 1030 2GB (Driver ver xxx.xx.xx)) **Describe the Bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Screenshots** If applicable, add screenshots to help explain your problem. ** Debug Log and/or Crash Report ** ``` [Paste log/report] ``` **Additional Details** Add any other information about the problem here. olive-continuous/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000013631370472574300236670ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: "[Feature Request]" labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Do you know any libraries or sources that can help the Olive Team include the feature?** List open-source libraries related to the feature. **Additional context** Add any other context or screenshots about the feature request here. olive-continuous/.gitignore000066400000000000000000000014071370472574300164060ustar00rootroot00000000000000*.pro.user* Makefile .qmake.stash effects/frei0r ts/*.qm docs history build/ .DS_Store .vscode .vs CmakeSettings.json # # Qt ignores taken from https://github.com/github/gitignore # # C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib # Qt-es object_script.*.Release object_script.*.Debug *_plugin_import.cpp /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp moc_*.h qrc_*.cpp ui_*.h *.qmlc *.jsc Makefile* *build-* # Qt unit tests target_wrapper.* # QtCreator *.autosave # QtCreator Qml *.qmlproject.user *.qmlproject.user.* # QtCreator CMake CMakeLists.txt.user* # QtCreator 4.8< compilation database compile_commands.json # QtCreator local machine specific files for imported projects *creator.user* olive-continuous/.travis.yml000066400000000000000000000016111370472574300165240ustar00rootroot00000000000000language: cpp matrix: include: - os: linux env: ARCH=x86_64 compiler: gcc sudo: require dist: xenial - os: osx osx_image: xcode10.3 before_cache: - brew cleanup cache: directories: - $HOME/Library/Caches/Homebrew addons: homebrew: packages: - ffmpeg - qt5 - grep - opencolorio - openimageio update: true # Can't build on Windows - affected by https://travis-ci.community/t/current-known-issues-please-read-this-before-posting-a-new-topic/264/10 # - os: windows before_install: - source ./.travis/before_install.sh install: - source ./.travis/install.sh script: - source ./.travis/script.sh after_success: - source ./.travis/after_success.sh branches: except: - # Do not build tags that we create when we upload to GitHub Releases - /^(?i:continuous)/ olive-continuous/.travis/000077500000000000000000000000001370472574300160025ustar00rootroot00000000000000olive-continuous/.travis/after_success.sh000066400000000000000000000022101370472574300211620ustar00rootroot00000000000000#!/bin/bash # Check if there's been a new commit since this build, and if so don't upload it GREP_PATH=grep if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then GREP_PATH=ggrep fi # Get current repo commit from GitHub (problems arose from trying to pipe cURL directly into grep, so we buffer it through a file) REMOTE=$(curl -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/olive-editor/olive/commits/master | $GREP_PATH -Po '(?<=: \")(([a-z0-9])\w+)(?=\")' -m 1 --) LOCAL=$(git rev-parse HEAD) if [ "$TRAVIS_TAG" != "" ] || [ "$REMOTE" == "$LOCAL" ] then echo "[INFO] Still current. Uploading..." export UPLOADTOOL_BODY=$(cat release.txt) # Retrieve upload tool wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then bash upload.sh Olive*.zip elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then find appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq bash upload.sh Olive*.AppImage* fi else echo "[INFO] No longer current. $REMOTE vs $LOCAL - aborting upload." fi olive-continuous/.travis/before_install.sh000066400000000000000000000005211370472574300213240ustar00rootroot00000000000000#!/bin/bash if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then # Qt 5.11 sudo add-apt-repository ppa:beineri/opt-qt-5.11.0-xenial -y # FFmpeg 4.x sudo add-apt-repository ppa:jonathonf/ffmpeg-4 -y # OpenColorIO sudo add-apt-repository ppa:olive-editor/opencolorio -y # Update apt sudo apt-get update -qq fi olive-continuous/.travis/install.sh000066400000000000000000000014161370472574300200060ustar00rootroot00000000000000#!/bin/bash if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH="/usr/local/opt/qt/bin:/usr/local/opt/python@2/libexec/bin:$PATH" elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -y -o Dpkg::Options::="--force-overwrite" install qt511base qt511multimedia qt511svg qt511tools libavformat-dev libavcodec-dev libavfilter-dev libavutil-dev libswscale-dev libswresample-dev libopencolorio-dev libopenimageio-dev libgl1-mesa-dev source /opt/qt*/bin/qt*-env.sh # Acquire latest cmake (apt somehow gets the wrong version?) wget -c https://github.com/Kitware/CMake/releases/download/v3.17.2/cmake-3.17.2-Linux-x86_64.sh -O cmake.sh chmod +x cmake.sh ./cmake.sh --skip-license --prefix=cmake --exclude-dir export PATH=$PWD/cmake/bin:$PATH fi olive-continuous/.travis/script.sh000066400000000000000000000040601370472574300176420ustar00rootroot00000000000000#!/bin/bash # linuxdeployqt uses this for naming the file export VERSION=$(git rev-parse --short=8 HEAD) if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then # Generate Makefile cmake . # Make make -j$(sysctl -n hw.ncpu) # Handle compile failure if [ "$?" != "0" ] then exit 1 fi BUNDLE_NAME=Olive.app # Move bundle to working directory mv app/$BUNDLE_NAME . # Move Qt deps into bundle macdeployqt $BUNDLE_NAME # Fix other deps that macdeployqt missed wget -c -nv https://github.com/arl/macdeployqtfix/raw/master/macdeployqtfix.py python2 macdeployqtfix.py $BUNDLE_NAME/Contents/MacOS/Olive /usr/local/Cellar/qt5/5.*/ # Fix deps on crash handler python2 macdeployqtfix.py $BUNDLE_NAME/Contents/MacOS/olive-crashhandler /usr/local/Cellar/qt5/5.*/ # Fix OpenEXR libs that seem to be missed by both macdeployqt _and_ macdeployqtfix cd $BUNDLE_NAME/Contents/Frameworks exrlib=(libImath-*.dylib libHalf-*.dylib libIexMath-*.dylib libIex-*.dylib libIlmThread-*.dylib) for a in ${exrlib[@]}; do for b in ${exrlib[@]}; do install_name_tool -change @rpath/$b @executable_path/../Frameworks/$b $a done done cd ../../.. # Distribute in zip zip -r Olive-$VERSION-macOS.zip $BUNDLE_NAME elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then # Generate Makefile cmake . # Make make -j$(nproc) # Handle compile failure if [ "$?" != "0" ] then exit 1 fi # Use `make install` on `appdir` to place files in the correct place make DESTDIR=appdir install # Download linuxdeployqt wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" chmod a+x linuxdeployqt-continuous-x86_64.AppImage unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH # Use linuxdeployqt to set up dependencies ./linuxdeployqt-continuous-x86_64.AppImage appdir/usr/local/share/applications/*.desktop -extra-plugins=imageformats/libqsvg.so -appimage fi olive-continuous/CMakeLists.txt000066400000000000000000000052201370472574300171530ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(olive-editor VERSION 0.2.0 LANGUAGES CXX) option(UPDATE_TS "Update translations" OFF) option(BUILD_DOXYGEN "Build Doxygen documentation" OFF) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) set(OLIVE_DEFINITIONS -DAPPVERSION="${PROJECT_VERSION}" -DQT_DEPRECATED_WARNINGS) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") if(UNIX AND NOT APPLE AND NOT DEFINED OpenGL_GL_PREFERENCE) set(OpenGL_GL_PREFERENCE LEGACY) endif() find_package(OpenGL REQUIRED) find_package(OpenColorIO REQUIRED) find_package(OpenImageIO 1.6 REQUIRED) find_package(OpenEXR REQUIRED) find_package(Qt5 5.6 REQUIRED COMPONENTS Core Gui Widgets Multimedia OpenGL Svg LinguistTools Concurrent ) find_package(FFMPEG 3.0 REQUIRED COMPONENTS avutil avcodec avformat avfilter swscale swresample ) if(EXISTS "${CMAKE_SOURCE_DIR}/.git") find_package(Git) if(GIT_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() elseif(UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD") # Fallback for Ubuntu/Launchpad (extracts Git hash from debian/changelog rather than Git repo) # (see https://answers.launchpad.net/launchpad/+question/678556) execute_process(COMMAND sh -c "grep -Po '(?<=-)(([a-z0-9])\\w+)(?=\\+)' -m 1 changelog" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/debian OUTPUT_VARIABLE GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() if(DEFINED GIT_HASH) message("Olive: Git hash = " "${GIT_HASH}") list(APPEND OLIVE_DEFINITIONS -DGITHASH="${GIT_HASH}") else() message("Olive: No Git hash defined!") endif() if(BUILD_DOXYGEN) find_package(Doxygen) endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) add_subdirectory(app) olive-continuous/CONTRIBUTING.md000066400000000000000000000017361370472574300166540ustar00rootroot00000000000000# Contributing to Olive Thank you for your interest in contributing to Olive! In order to keep the code as readable and maintainable as possible, code submitted should abide by the following standards: ### Standards When contributing to Olive, it's recommended to use the following rules: * The code style generally follows the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) including, but not limited to: * Indentation is 2 spaces wide, spaces only (no tabs) * `lowercase_underscored_variable_names` * `lowercase_underscored_functions()` or `SentenceCaseFunctions()` * `class SentenceCaseClassesAndStructs {}` * `kSentenceCaseConstants` prepended with a lowercase `k` * `UPPERCASE_UNDERSCORED_MACROS` for variables or same style as functions for macro functions * `class_member_variables_` end with a `_` * 100 column limit (where it doesn't impair readability) * Unix line endings (only LF no CRLF) * Javadoc documentation where appropriate olive-continuous/LICENSE000066400000000000000000001045131370472574300154250ustar00rootroot00000000000000 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 . olive-continuous/README.md000066400000000000000000000036121370472574300156750ustar00rootroot00000000000000# Olive Video Editor [![Build Status](https://travis-ci.org/olive-editor/olive.svg?branch=master)](https://travis-ci.org/olive-editor/olive) [![Build Status](https://ci.appveyor.com/api/projects/status/5s4jabxayg51rv95?svg=true)](https://ci.appveyor.com/project/itsmattkc/olive) Olive is a free non-linear video editor for Windows, macOS, and Linux. ![screen](https://www.olivevideoeditor.org/img/screenshot.jpg) **Discover more:** [Website](https://www.olivevideoeditor.org/) | [Twitter](https://twitter.com/oliveteam) | [Discord](https://discord.gg/4Ae9KZn) | [Code Documentation](http://olivevideoeditor.org/doxygen/) **NOTE: The issue tracker is temporarily closed while Olive's core is getting rewritten. We apologize for any inconvenience. Please check back soon for the next release, as well as the [Patreon page](https://www.patreon.com/olivevideoeditor) for news and updates.** ## Getting Started with Olive: Installation of Olive is available at: https://olivevideoeditor.org/download.php Instructions on how to use Olive are available on our wiki: https://github.com/olive-editor/olive/wiki/Overview-Guide **NOTE: Olive is Alpha Software, and it should be treated as highly unstable. Work at your own risk.** ## Support Olive: Please consider supporting Olive: [![Become a Patron](https://olivevideoeditor.org/img/become_a_patron_button.png)](https://www.patreon.com/olivevideoeditor) **NOTE: It is strongly discouraged to use or compile the `master` branch in its current state as it's under heavy restructuring. Please use the 0.1.x code from the "Releases" tab instead.** ## Compiling from Source: Compiling instructions for Windows, macOS, and Linux can be found [on the main site](https://olivevideoeditor.org/compile.php). Olive has Doxygen-compatible documentation hosted at http://olivevideoeditor.org/doxygen/. You can also run `doxygen` in the source root directory to generate a local copy. olive-continuous/app/000077500000000000000000000000001370472574300151745ustar00rootroot00000000000000olive-continuous/app/CMakeLists.txt000066400000000000000000000111351370472574300177350ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Set Olive sources and resources set(OLIVE_SOURCES ${OLIVE_SOURCES} core.h core.cpp main.cpp ) if (WIN32) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} packaging/windows/resources.rc ) endif() add_subdirectory(audio) add_subdirectory(cli) add_subdirectory(codec) add_subdirectory(common) add_subdirectory(config) add_subdirectory(dialog) add_subdirectory(node) add_subdirectory(panel) add_subdirectory(project) add_subdirectory(render) add_subdirectory(shaders) add_subdirectory(task) add_subdirectory(timeline) add_subdirectory(tool) add_subdirectory(ui) add_subdirectory(undo) add_subdirectory(widget) add_subdirectory(window) # Create main application target set(OLIVE_TARGET "olive-editor") if(APPLE) set(OLIVE_TARGET "Olive") set(OLIVE_ICON packaging/macos/olive.icns) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ${OLIVE_ICON} ) endif() # Add executable add_executable(${OLIVE_TARGET} ${OLIVE_SOURCES} ${OLIVE_RESOURCES} ${OLIVE_QM_FILES} ) if(APPLE) set_target_properties(${OLIVE_TARGET} PROPERTIES MACOSX_BUNDLE TRUE MACOSX_BUNDLE_GUI_IDENTIFIER org.olivevideoeditor.Olive MACOSX_BUNDLE_ICON_FILE olive.icns RESOURCE "${OLIVE_ICON}" ) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9") endif() # Set compiler definitions target_compile_definitions(${OLIVE_TARGET} PRIVATE ${OLIVE_DEFINITIONS}) # Set compiler options if(MSVC) target_compile_options( ${OLIVE_TARGET} PRIVATE /WX /wd4267 /wd4244 /experimental:external /external:anglebrackets /external:W0 "$<$:/O2>" "$<$:/MP>" ) else() target_compile_options( ${OLIVE_TARGET} PRIVATE "$<$:-O2>" -Werror -Wuninitialized -pedantic-errors -Wall -Wextra -Wno-unused-parameter -Wshadow ) endif() if(UNIX AND NOT APPLE) target_link_options( ${OLIVE_TARGET} PRIVATE -rdynamic ) endif() # Set include directories target_include_directories( ${OLIVE_TARGET} PRIVATE ${FFMPEG_INCLUDE_DIRS} ${OCIO_INCLUDE_DIRS} ${OIIO_INCLUDE_DIRS} ${OPENEXR_INCLUDE_DIR} ) # Set link libraries target_link_libraries( ${OLIVE_TARGET} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Multimedia Qt5::OpenGL Qt5::Svg Qt5::Concurrent OpenGL::GL FFMPEG::avutil FFMPEG::avcodec FFMPEG::avformat FFMPEG::avfilter FFMPEG::swscale FFMPEG::swresample ${OCIO_LIBRARIES} ${OIIO_LIBRARIES} ${OPENEXR_LIBRARIES} ) if (WIN32) target_link_libraries( ${OLIVE_TARGET} PRIVATE DbgHelp ) elseif (APPLE) target_link_libraries( ${OLIVE_TARGET} PRIVATE "-framework ApplicationServices" ) endif() set(OLIVE_TS_FILES # FIXME: Empty variable ) if(UPDATE_TS) qt5_create_translation(OLIVE_QM_FILES ${CMAKE_SOURCE_DIR} ${OLIVE_TS_FILES}) else() qt5_add_translation(OLIVE_QM_FILES ${OLIVE_TS_FILES}) endif() add_subdirectory(packaging) if(DOXYGEN_FOUND) set(DOXYGEN_PROJECT_NAME "Olive") set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/docs") set(DOXYGEN_EXTRACT_ALL "YES") set(DOXYGEN_EXTRACT_PRIVATE "YES") doxygen_add_docs(docs ALL ${OLIVE_SOURCES}) endif() set(OLIVE_CRASH_TARGET "olive-crashhandler") set(OLIVE_CRASH_SOURCES dialog/crashhandler/crashhandler.h dialog/crashhandler/crashhandler.cpp dialog/crashhandler/crashhandlermain.cpp ) if (WIN32) add_executable( ${OLIVE_CRASH_TARGET} WIN32 ${OLIVE_CRASH_SOURCES} ) else() add_executable( ${OLIVE_CRASH_TARGET} ${OLIVE_CRASH_SOURCES} ) endif() target_link_libraries( ${OLIVE_CRASH_TARGET} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets ) if(UNIX AND NOT APPLE) install(TARGETS ${OLIVE_TARGET} ${OLIVE_CRASH_TARGET} RUNTIME DESTINATION bin) endif() if(APPLE) # Move crash handler program inside Mac app bundle add_custom_command(TARGET ${OLIVE_CRASH_TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${OLIVE_CRASH_TARGET} $ ) endif() olive-continuous/app/audio/000077500000000000000000000000001370472574300162755ustar00rootroot00000000000000olive-continuous/app/audio/CMakeLists.txt000066400000000000000000000020631370472574300210360ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} audio/audiomanager.h audio/audiomanager.cpp audio/audiovisualwaveform.h audio/audiovisualwaveform.cpp audio/outputdeviceproxy.h audio/outputdeviceproxy.cpp audio/outputmanager.h audio/outputmanager.cpp audio/sampleformat.h audio/sampleformat.cpp audio/tempoprocessor.h audio/tempoprocessor.cpp PARENT_SCOPE ) olive-continuous/app/audio/audiomanager.cpp000066400000000000000000000205011370472574300214330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiomanager.h" #include #include "config/config.h" OLIVE_NAMESPACE_ENTER AudioManager* AudioManager::instance_ = nullptr; void AudioManager::CreateInstance() { if (instance_ == nullptr) { instance_ = new AudioManager(); } } void AudioManager::DestroyInstance() { delete instance_; instance_ = nullptr; } AudioManager *AudioManager::instance() { return instance_; } void AudioManager::RefreshDevices() { if (!is_refreshing_outputs_) { QFutureWatcher< QList >* output_watcher = new QFutureWatcher< QList >(); connect(output_watcher, &QFutureWatcher< QList >::finished, this, &AudioManager::OutputDevicesRefreshed); output_watcher->setFuture(QtConcurrent::run(QAudioDeviceInfo::availableDevices, QAudio::AudioOutput)); is_refreshing_outputs_ = true; } if (!is_refreshing_inputs_) { QFutureWatcher< QList >* input_watcher = new QFutureWatcher< QList >(); connect(input_watcher, &QFutureWatcher< QList >::finished, this, &AudioManager::InputDevicesRefreshed); input_watcher->setFuture(QtConcurrent::run(QAudioDeviceInfo::availableDevices, QAudio::AudioInput)); is_refreshing_inputs_ = true; } } bool AudioManager::IsRefreshingOutputs() { return is_refreshing_outputs_; } bool AudioManager::IsRefreshingInputs() { return is_refreshing_inputs_; } void AudioManager::PushToOutput(const QByteArray &samples) { output_manager_.Push(samples); emit OutputPushed(samples); } void AudioManager::StartOutput(const QString &filename, qint64 offset, int playback_speed) { QMetaObject::invokeMethod(&output_manager_, "PullFromDevice", Qt::QueuedConnection, Q_ARG(const QString&, filename), Q_ARG(qint64, offset), Q_ARG(int, playback_speed)); emit OutputDeviceStarted(filename, offset, playback_speed); } void AudioManager::StopOutput() { QMetaObject::invokeMethod(&output_manager_, "ResetToPushMode", Qt::QueuedConnection); emit Stopped(); } void AudioManager::SetOutputDevice(const QAudioDeviceInfo &info) { qInfo() << "Setting output audio device to" << info.deviceName(); StopOutput(); output_device_info_ = info; if (output_params_.is_valid()) { QAudioFormat format; format.setSampleRate(output_params_.sample_rate()); format.setChannelCount(output_params_.channel_count()); format.setCodec("audio/pcm"); format.setByteOrder(QAudioFormat::LittleEndian); switch (output_params_.format()) { case SampleFormat::SAMPLE_FMT_U8: format.setSampleSize(8); format.setSampleType(QAudioFormat::UnSignedInt); break; case SampleFormat::SAMPLE_FMT_S16: format.setSampleSize(16); format.setSampleType(QAudioFormat::SignedInt); break; case SampleFormat::SAMPLE_FMT_S32: format.setSampleSize(32); format.setSampleType(QAudioFormat::SignedInt); break; case SampleFormat::SAMPLE_FMT_S64: format.setSampleSize(64); format.setSampleType(QAudioFormat::SignedInt); break; case SampleFormat::SAMPLE_FMT_FLT: format.setSampleSize(32); format.setSampleType(QAudioFormat::Float); break; case SampleFormat::SAMPLE_FMT_DBL: format.setSampleSize(64); format.setSampleType(QAudioFormat::Float); break; case SampleFormat::SAMPLE_FMT_COUNT: case SampleFormat::SAMPLE_FMT_INVALID: abort(); } if (info.isFormatSupported(format)) { QMetaObject::invokeMethod(&output_manager_, "SetOutputDevice", Qt::QueuedConnection, Q_ARG(const QAudioDeviceInfo&, info), Q_ARG(const QAudioFormat&, format)); output_is_set_ = true; } else { qWarning() << "Output format not supported by device"; } } } void AudioManager::SetOutputParams(const AudioParams ¶ms) { if (output_params_ != params) { output_params_ = params; QMetaObject::invokeMethod(&output_manager_, "SetParameters", Qt::QueuedConnection, OLIVE_NS_ARG(AudioParams, params)); // Refresh output device SetOutputDevice(output_device_info_); emit AudioParamsChanged(output_params_); } } void AudioManager::SetInputDevice(const QAudioDeviceInfo &info) { input_ = std::unique_ptr(new QAudioInput(info, QAudioFormat(), this)); input_device_info_ = info; } const QList &AudioManager::ListInputDevices() { return input_devices_; } const QList &AudioManager::ListOutputDevices() { return output_devices_; } void AudioManager::ReverseBuffer(char *buffer, int buffer_size, int sample_size) { int half_buffer_sz = buffer_size / 2; char* temp_buffer = new char[sample_size]; for (int src_index=0;src_index(sample_size)); memcpy(src_ptr, dst_ptr, static_cast(sample_size)); memcpy(dst_ptr, temp_buffer, static_cast(sample_size)); } delete [] temp_buffer; } AudioManager::AudioManager() : is_refreshing_inputs_(false), is_refreshing_outputs_(false), output_is_set_(false), input_(nullptr), input_file_(nullptr) { RefreshDevices(); output_thread_.start(QThread::TimeCriticalPriority); output_manager_.moveToThread(&output_thread_); connect(&output_manager_, &AudioOutputManager::OutputNotified, this, &AudioManager::OutputNotified); } AudioManager::~AudioManager() { QMetaObject::invokeMethod(&output_manager_, "Close", Qt::QueuedConnection); output_thread_.quit(); output_thread_.wait(); } void AudioManager::OutputDevicesRefreshed() { QFutureWatcher< QList >* watcher = static_cast >*>(sender()); output_devices_ = watcher->result(); watcher->deleteLater(); is_refreshing_outputs_ = false; QString preferred_audio_output = Config::Current()["PreferredAudioOutput"].toString(); if (!output_is_set_ || (!preferred_audio_output.isEmpty() && output_device_info_.deviceName() != preferred_audio_output)) { if (preferred_audio_output.isEmpty()) { SetOutputDevice(QAudioDeviceInfo::defaultOutputDevice()); } else { foreach (const QAudioDeviceInfo& info, output_devices_) { if (info.deviceName() == preferred_audio_output) { SetOutputDevice(info); break; } } } } emit OutputListReady(); } void AudioManager::InputDevicesRefreshed() { QFutureWatcher< QList >* watcher = static_cast >*>(sender()); input_devices_ = watcher->result(); watcher->deleteLater(); is_refreshing_inputs_ = false; QString preferred_audio_input = Config::Current()["PreferredAudioInput"].toString(); if (input_ == nullptr || (!preferred_audio_input.isEmpty() && input_device_info_.deviceName() != preferred_audio_input)) { if (preferred_audio_input.isEmpty()) { SetInputDevice(QAudioDeviceInfo::defaultInputDevice()); } else { foreach (const QAudioDeviceInfo& info, input_devices_) { if (info.deviceName() == preferred_audio_input) { SetInputDevice(info); break; } } } } emit InputListReady(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/audio/audiomanager.h000066400000000000000000000060111370472574300211000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOMANAGER_H #define AUDIOMANAGER_H #include #include #include #include #include #include "common/define.h" #include "outputmanager.h" #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER /** * @brief Audio input and output management class * * Wraps around a QAudioOutput and AudioHybridDevice, connecting them together and exposing audio functionality to * the rest of the system. */ class AudioManager : public QObject { Q_OBJECT public: static void CreateInstance(); static void DestroyInstance(); static AudioManager* instance(); void RefreshDevices(); bool IsRefreshingOutputs(); bool IsRefreshingInputs(); void PushToOutput(const QByteArray& samples); /** * @brief Start playing audio from QIODevice * * This takes ownership of the QIODevice and will delete it when StopOutput() is called */ void StartOutput(const QString& filename, qint64 offset, int playback_speed); /** * @brief Stop audio output immediately */ void StopOutput(); void SetOutputDevice(const QAudioDeviceInfo& info); void SetOutputParams(const AudioParams& params); void SetInputDevice(const QAudioDeviceInfo& info); const QList& ListInputDevices(); const QList& ListOutputDevices(); static void ReverseBuffer(char* buffer, int size, int resolution); signals: void OutputListReady(); void InputListReady(); void OutputNotified(); void OutputDeviceStarted(const QString& filename, qint64 offset, int playback_speed); void AudioParamsChanged(const AudioParams& params); void OutputPushed(const QByteArray& data); void Stopped(); private: AudioManager(); virtual ~AudioManager() override; QList input_devices_; QList output_devices_; bool is_refreshing_inputs_; bool is_refreshing_outputs_; static AudioManager* instance_; QThread output_thread_; AudioOutputManager output_manager_; bool output_is_set_; QAudioDeviceInfo output_device_info_; AudioParams output_params_; std::unique_ptr input_; QAudioDeviceInfo input_device_info_; QIODevice* input_file_; private slots: void OutputDevicesRefreshed(); void InputDevicesRefreshed(); }; OLIVE_NAMESPACE_EXIT #endif // AUDIOMANAGER_H olive-continuous/app/audio/audiovisualwaveform.cpp000066400000000000000000000240051370472574300230760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiovisualwaveform.h" #include #include "config/config.h" OLIVE_NAMESPACE_ENTER const int AudioVisualWaveform::kSumSampleRate = 200; void AudioVisualWaveform::AddSum(const float *samples, int nb_samples, int nb_channels) { data_.append(SumSamples(samples, nb_samples, nb_channels)); } void AudioVisualWaveform::OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational &start) { if (!channels_) { qWarning() << "Failed to write samples - channel count is zero"; } int start_index = time_to_samples(start); int samples_length = time_to_samples(static_cast(samples->sample_count()) / static_cast(sample_rate)); int end_index = start_index + samples_length; if (data_.size() < end_index) { data_.resize(end_index); } int chunk_size = sample_rate / kSumSampleRate; for (int i=0; i summary = SumSamples(samples, src_index, qMin(chunk_size, samples->sample_count() - src_index)); memcpy(&data_.data()[i + start_index], summary.constData(), summary.size() * sizeof(SamplePerChannel)); } } void AudioVisualWaveform::OverwriteSums(const AudioVisualWaveform &sums, const rational &dest, const rational& offset, const rational& length) { if (sums.data_.isEmpty()) { return; } int start_index = time_to_samples(dest); int sample_start = time_to_samples(offset); int copy_len = sums.data_.size() - sample_start; if (!length.isNull()) { copy_len = qMin(copy_len, time_to_samples(length)); } int end_index = start_index + copy_len; if (data_.size() < end_index) { data_.resize(end_index); } memcpy(reinterpret_cast(data_.data()) + start_index * sizeof(SamplePerChannel), reinterpret_cast(sums.data_.constData()) + time_to_samples(offset) * sizeof(SamplePerChannel), copy_len * sizeof(SamplePerChannel)); } AudioVisualWaveform AudioVisualWaveform::Mid(const rational &time) const { int sample_index = time_to_samples(time); // Create a copy of this waveform chop the early section off AudioVisualWaveform copy = *this; copy.data_ = data_.mid(sample_index); return copy; } void AudioVisualWaveform::Append(const AudioVisualWaveform &waveform) { data_.append(waveform.data_); } void AudioVisualWaveform::TrimIn(const rational &time) { data_ = data_.mid(time_to_samples(time)); } void AudioVisualWaveform::TrimOut(const rational &time) { data_.resize(data_.size() - time_to_samples(time)); } void AudioVisualWaveform::PrependSilence(const rational &time) { int added_samples = time_to_samples(time); // Resize buffer for extra space data_.resize(data_.size() + added_samples); // Shift all data forward for (int i=data_.size()-1; i>=added_samples; i--) { data_[i] = data_[i - added_samples]; } // Fill remainder with silence memset(reinterpret_cast(data_.data()), 0, added_samples * sizeof(SamplePerChannel)); } void AudioVisualWaveform::AppendSilence(const rational &time) { int added_samples = time_to_samples(time); // Resize buffer for extra space int old_size = data_.size(); data_.resize(old_size + added_samples); // Fill remainder with silence memset(reinterpret_cast(&data_[old_size]), 0, (data_.size() - old_size) * sizeof(SamplePerChannel)); } void AudioVisualWaveform::Shift(const rational &from, const rational &to) { int from_index = time_to_samples(from); int to_index = time_to_samples(to); if (from_index == to_index) { return; } if (from_index > to_index) { // Shifting backwards <- int copy_sz = data_.size() - from_index; for (int i=0; i int old_sz = data_.size(); int distance = (to_index - from_index); data_.resize(data_.size() + distance); int copy_sz = old_sz - from_index; for (int i=0; i(&data_[from_index]), 0, distance * sizeof(SamplePerChannel)); } } QVector AudioVisualWaveform::SumSamples(const float *samples, int nb_samples, int nb_channels) { return SumSamplesInternal(samples, nb_samples, nb_channels); } QVector AudioVisualWaveform::SumSamples(const qfloat16 *samples, int nb_samples, int nb_channels) { return SumSamplesInternal(samples, nb_samples, nb_channels); } QVector AudioVisualWaveform::SumSamples(SampleBufferPtr samples, int start_index, int length) { QVector summed_samples(samples->audio_params().channel_count()); int end_index = start_index + length; for (int i=start_index; iaudio_params().channel_count(); channel++) { ExpandMinMax(summed_samples[channel], samples->data()[channel][i]); } } return summed_samples; } QVector AudioVisualWaveform::ReSumSamples(const SamplePerChannel* samples, int nb_samples, int nb_channels) { QVector summed_samples(nb_channels); for (int i=0;i summed_samples[j].max) { summed_samples[j].max = sample.max; } } } return summed_samples; } void AudioVisualWaveform::DrawSample(QPainter *painter, const QVector& sample, int x, int y, int height) { int channel_height = height / sample.size(); int channel_half_height = channel_height / 2; for (int i=0;i(1.0f)); qfloat16 min = qMax(sample.at(i).min, static_cast(-1.0)); if (Config::Current()[QStringLiteral("RectifiedWaveforms")].toBool()) { int channel_bottom = y + channel_height * (i + 1); int diff = qRound((max - min) * channel_half_height); painter->drawLine(x, channel_bottom - diff, x, channel_bottom); } else { int channel_mid = y + channel_height * i + channel_half_height; painter->drawLine(x, channel_mid + qRound(min * static_cast(channel_half_height)), x, channel_mid + qRound(max * static_cast(channel_half_height))); } } } void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, const double& scale, const AudioVisualWaveform &samples, const rational& start_time) { int start_sample_index = samples.time_to_samples(start_time); if (start_sample_index >= samples.nb_samples()) { return; } int next_sample_index = start_sample_index; int sample_index; QVector summary; int summary_index = -1; const QRect& viewport = painter->viewport(); QPoint top_left = painter->transform().map(viewport.topLeft()); int start = qMax(rect.x(), -top_left.x()); int end = qMin(rect.right(), -top_left.x() + viewport.width()); for (int i=start;i(kSumSampleRate) * static_cast(i - rect.x() + 1) / scale) * samples.channel_count()); if (summary_index != sample_index) { summary = AudioVisualWaveform::ReSumSamples(&samples.data_.at(sample_index), qMax(samples.channel_count(), next_sample_index - sample_index), samples.channel_count()); summary_index = sample_index; } DrawSample(painter, summary, i, rect.y(), rect.height()); } } int AudioVisualWaveform::time_to_samples(const rational &time) const { return time_to_samples(time.toDouble()); } int AudioVisualWaveform::time_to_samples(const double &time) const { return qFloor(time * kSumSampleRate) * channels_; } template QVector AudioVisualWaveform::SumSamplesInternal(const T *samples, int nb_samples, int nb_channels) { QVector summed_samples(nb_channels); for (int i=0;i(summed_samples[i%nb_channels], samples[i]); } return summed_samples; } template void AudioVisualWaveform::ExpandMinMax(AudioVisualWaveform::SamplePerChannel &sum, T value) { if (value < sum.min) { sum.min = value; } if (value > sum.max) { sum.max = value; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/audio/audiovisualwaveform.h000066400000000000000000000066041370472574300225500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SUMSAMPLES_H #define SUMSAMPLES_H #include #include #include #include "codec/samplebuffer.h" OLIVE_NAMESPACE_ENTER /** * @brief A buffer of data used to store a visual representation of audio * * This differs from a SampleBuffer as the data in an AudioVisualWaveform has been reduced * significantly and optimized for visual display. */ class AudioVisualWaveform { public: AudioVisualWaveform() = default; struct SamplePerChannel { qfloat16 min; qfloat16 max; }; using Sample = QVector; int channel_count() const { return channels_; } void set_channel_count(int channels) { channels_ = channels; } int nb_samples() const { return data_.size(); } const SamplePerChannel* const_data() const { return data_.constData(); } void AddSum(const float* samples, int nb_samples, int nb_channels); void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start = rational()); void OverwriteSums(const AudioVisualWaveform& sums, const rational& dest, const rational& offset = rational(), const rational &length = rational()); AudioVisualWaveform Mid(const rational& time) const; void Append(const AudioVisualWaveform& waveform); void TrimIn(const rational& time); void TrimOut(const rational& time); void PrependSilence(const rational& time); void AppendSilence(const rational& time); void Shift(const rational& from, const rational& to); // FIXME: Move to dynamic static const int kSumSampleRate; static QVector SumSamples(const float* samples, int nb_samples, int nb_channels); static QVector SumSamples(const qfloat16* samples, int nb_samples, int nb_channels); static QVector SumSamples(SampleBufferPtr samples, int start_index, int length); static QVector ReSumSamples(const SamplePerChannel *samples, int nb_samples, int nb_channels); static void DrawSample(QPainter* painter, const QVector &sample, int x, int y, int height); static void DrawWaveform(QPainter* painter, const QRect &rect, const double &scale, const AudioVisualWaveform& samples, const rational &start_time); private: template static QVector SumSamplesInternal(const T* samples, int nb_samples, int nb_channels); template static void ExpandMinMax(SamplePerChannel &sum, T value); int time_to_samples(const rational& time) const; int time_to_samples(const double& time) const; int channels_ = 0; QVector data_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::AudioVisualWaveform) #endif // SUMSAMPLES_H olive-continuous/app/audio/outputdeviceproxy.cpp000066400000000000000000000056431370472574300226330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "outputdeviceproxy.h" #include "audiomanager.h" OLIVE_NAMESPACE_ENTER AudioOutputDeviceProxy::~AudioOutputDeviceProxy() { if (file_.isOpen()) { file_.close(); } } void AudioOutputDeviceProxy::SetParameters(const AudioParams ¶ms) { params_ = params; } void AudioOutputDeviceProxy::SetDevice(const QString &filename, qint64 offset, int playback_speed) { if (file_.isOpen()) { file_.close(); } file_.setFileName(filename); if (!file_.open(QFile::ReadOnly)) { qCritical() << "Failed to open" << filename << "for audio playback"; return; } file_.seek(offset); playback_speed_ = playback_speed; if (qAbs(playback_speed_) != 1) { tempo_processor_.Open(params_, qAbs(playback_speed_)); } } void AudioOutputDeviceProxy::close() { QIODevice::close(); file_.close(); if (tempo_processor_.IsOpen()) { tempo_processor_.Close(); } } qint64 AudioOutputDeviceProxy::readData(char *data, qint64 maxlen) { if (!file_.isOpen()) { return 0; } qint64 read_count; if (tempo_processor_.IsOpen()) { while ((read_count = tempo_processor_.Pull(data, static_cast(maxlen))) == 0) { int dev_read = static_cast(ReverseAwareRead(data, maxlen)); if (!dev_read) { break; } tempo_processor_.Push(data, dev_read); } } else { // If we aren't doing any tempo processing, simply passthrough the read signal read_count = ReverseAwareRead(data, maxlen); } return read_count; } qint64 AudioOutputDeviceProxy::writeData(const char *data, qint64 maxSize) { Q_UNUSED(data) Q_UNUSED(maxSize) return 0; } qint64 AudioOutputDeviceProxy::ReverseAwareRead(char *data, qint64 maxlen) { qint64 new_pos = -1; if (playback_speed_ < 0) { // If we're reversing, we'll seek back by maxlen bytes before we read new_pos = file_.pos() - maxlen; if (new_pos < 0) { maxlen = file_.pos(); new_pos = 0; } file_.seek(new_pos); } qint64 read_count = file_.read(data, maxlen); if (playback_speed_ < 0) { file_.seek(new_pos); // Reverse the samples here AudioManager::ReverseBuffer(data, static_cast(read_count), params_.samples_to_bytes(1)); } return read_count; } OLIVE_NAMESPACE_EXIT olive-continuous/app/audio/outputdeviceproxy.h000066400000000000000000000031561370472574300222750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOOUTPUTDEVICEPROXY_H #define AUDIOOUTPUTDEVICEPROXY_H #include #include "common/define.h" #include "tempoprocessor.h" OLIVE_NAMESPACE_ENTER /** * @brief QIODevice wrapper that can adjust speed/reverse an audio file */ class AudioOutputDeviceProxy : public QIODevice { Q_OBJECT public: AudioOutputDeviceProxy() = default; virtual ~AudioOutputDeviceProxy() override; void SetParameters(const AudioParams& params); void SetDevice(const QString &filename, qint64 offset, int playback_speed); virtual void close() override; protected: virtual qint64 readData(char *data, qint64 maxlen) override; virtual qint64 writeData(const char *data, qint64 maxSize) override; private: qint64 ReverseAwareRead(char* data, qint64 maxlen); QFile file_; TempoProcessor tempo_processor_; AudioParams params_; int playback_speed_; }; OLIVE_NAMESPACE_EXIT #endif // AUDIOOUTPUTDEVICEPROXY_H olive-continuous/app/audio/outputmanager.cpp000066400000000000000000000101711370472574300216740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "outputmanager.h" #include #include #include OLIVE_NAMESPACE_ENTER AudioOutputManager::AudioOutputManager(QObject *parent) : QObject(parent), output_(nullptr), push_device_(nullptr) { } AudioOutputManager::~AudioOutputManager() { Close(); } void AudioOutputManager::Push(const QByteArray& samples) { // This function is not queued and is intended to be called from the caller's thread QMutexLocker lock(&push_sample_lock_); // Replace sample buffer with this one push_samples_ = samples; push_sample_index_ = 0; // If we had another device connected, disconnect it now QMetaObject::invokeMethod(this, "ResetToPushMode", Qt::QueuedConnection); // Start pushing samples to the output QMetaObject::invokeMethod(this, "PushMoreSamples", Qt::QueuedConnection); } void AudioOutputManager::ResetToPushMode() { // If we have a null push device, then we currently have the output in pull mode. We restore it to push mode here. if (output_ && !push_device_) { output_->stop(); device_proxy_.close(); // Put QAudioOutput back into push mode push_device_ = output_->start(); } } void AudioOutputManager::SetParameters(AudioParams params) { device_proxy_.SetParameters(params); } void AudioOutputManager::Close() { if (output_) { output_->stop(); if (device_proxy_.isOpen()) { device_proxy_.close(); } output_->deleteLater(); output_ = nullptr; } } void AudioOutputManager::PullFromDevice(const QString &filename, qint64 offset, int playback_speed) { if (!output_) { return; } // Stop any current output and disable push mode output_->stop(); push_device_ = nullptr; push_samples_.clear(); // Pull from the device device_proxy_.SetDevice(filename, offset, playback_speed); device_proxy_.open(QIODevice::ReadOnly); output_->start(&device_proxy_); } void AudioOutputManager::PushMoreSamples() { QMutexLocker lock(&push_sample_lock_); // Check if we're currently in push mode and if we have samples to push if (!push_device_ || push_samples_.isEmpty()) { return; } const char* read_ptr = push_samples_.constData() + push_sample_index_; // Push the bytes we have to the audio output qint64 write_count = push_device_->write(read_ptr, push_samples_.size() - push_sample_index_); // Increment sample buffer index (faster than shift the bytes up) push_sample_index_ += static_cast(write_count); // If we've pushed all samples, we can clear this array if (push_sample_index_ == push_samples_.size()) { push_samples_.clear(); } } void AudioOutputManager::SetOutputDevice(QAudioDeviceInfo info, QAudioFormat format) { // Whatever the output is doing right now, stop it Close(); // Create a new output device and start it in push mode output_ = new QAudioOutput(info, format, this); output_->setBufferSize(131072); output_->setNotifyInterval(1); push_device_ = output_->start(); connect(output_, &QAudioOutput::notify, this, &AudioOutputManager::PushMoreSamples); connect(output_, &QAudioOutput::notify, this, &AudioOutputManager::OutputNotified); // Un-comment this to get debug information about what the audio output is doing //connect(output_, &QAudioOutput::stateChanged, this, &AudioOutputManager::OutputStateChanged); } void AudioOutputManager::OutputStateChanged(QAudio::State state) { qDebug() << state << output_->error(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/audio/outputmanager.h000066400000000000000000000040631370472574300213440ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOHYBRIDDEVICE_H #define AUDIOHYBRIDDEVICE_H #include #include #include #include #include #include #include "outputdeviceproxy.h" OLIVE_NAMESPACE_ENTER class AudioOutputManager : public QObject { Q_OBJECT public: AudioOutputManager(QObject* parent = nullptr); virtual ~AudioOutputManager() override; // Thread-safe void Push(const QByteArray &samples); public slots: // Queued void SetOutputDevice(QAudioDeviceInfo info, QAudioFormat format); /** * @brief Connect a QIODevice (e.g. QFile) to start sending to the audio output * * This will clear any pushed samples or QIODevices currently being read and will start reading from this next time * the audio output requests data. */ void PullFromDevice(const QString &filename, qint64 offset, int playback_speed); // Queued void ResetToPushMode(); // Queued void SetParameters(OLIVE_NAMESPACE::AudioParams params); // Queued void Close(); signals: void OutputNotified(); private: QAudioOutput* output_; QIODevice* push_device_; QMutex push_sample_lock_; QByteArray push_samples_; int push_sample_index_; AudioOutputDeviceProxy device_proxy_; private slots: void PushMoreSamples(); void OutputStateChanged(QAudio::State state); }; OLIVE_NAMESPACE_EXIT #endif // AUDIOHYBRIDDEVICE_H olive-continuous/app/audio/sampleformat.cpp000066400000000000000000000025571370472574300215040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sampleformat.h" #include "core.h" OLIVE_NAMESPACE_ENTER const SampleFormat::Format SampleFormat::kInternalFormat = SAMPLE_FMT_FLT; QString SampleFormat::GetSampleFormatName(const SampleFormat::Format &f) { switch (f) { case SAMPLE_FMT_U8: return tr("Unsigned 8-bit"); case SAMPLE_FMT_S16: return tr("Signed 16-bit"); case SAMPLE_FMT_S32: return tr("Signed 32-bit"); case SAMPLE_FMT_S64: return tr("Signed 64-bit"); case SAMPLE_FMT_FLT: return tr("32-bit Float"); case SAMPLE_FMT_DBL: return tr("64-bit Float"); case SAMPLE_FMT_COUNT: case SAMPLE_FMT_INVALID: break; } return tr("Invalid"); } OLIVE_NAMESPACE_EXIT olive-continuous/app/audio/sampleformat.h000066400000000000000000000024101370472574300211350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SAMPLEFORMAT_H #define SAMPLEFORMAT_H #include #include "common/define.h" #include "render/rendermodes.h" OLIVE_NAMESPACE_ENTER class SampleFormat : public QObject { Q_OBJECT public: SampleFormat() = default; enum Format { SAMPLE_FMT_INVALID = -1, SAMPLE_FMT_U8, SAMPLE_FMT_S16, SAMPLE_FMT_S32, SAMPLE_FMT_S64, SAMPLE_FMT_FLT, SAMPLE_FMT_DBL, SAMPLE_FMT_COUNT }; static const Format kInternalFormat; static QString GetSampleFormatName(const Format& f); }; OLIVE_NAMESPACE_EXIT #endif // SAMPLEFORMAT_H olive-continuous/app/audio/tempoprocessor.cpp000066400000000000000000000165071370472574300220760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "tempoprocessor.h" extern "C" { #include #include #include } #include #include "codec/ffmpeg/ffmpegcommon.h" OLIVE_NAMESPACE_ENTER TempoProcessor::TempoProcessor() : filter_graph_(nullptr), buffersrc_ctx_(nullptr), buffersink_ctx_(nullptr), processed_frame_(nullptr), open_(false) { } bool TempoProcessor::IsOpen() const { return open_; } const double &TempoProcessor::GetSpeed() const { return speed_; } bool TempoProcessor::Open(const AudioParams ¶ms, const double& speed) { if (open_) { return true; } params_ = params; speed_ = speed; // Create AVFilterGraph instance filter_graph_ = avfilter_graph_alloc(); if (!filter_graph_) { qCritical() << "Failed to create AVFilterGraph"; Close(); return false; } // Set up audio buffer args char filter_args[200]; snprintf(filter_args, 200, "time_base=%d/%d:sample_rate=%d:sample_fmt=%d:channel_layout=0x%" PRIx64, 1, params_.sample_rate(), params_.sample_rate(), FFmpegCommon::GetFFmpegSampleFormat(params_.format()), params.channel_layout()); // Create buffer and buffersink if (avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("abuffer"), "in", filter_args, nullptr, filter_graph_) < 0) { qCritical() << "Failed to create audio buffer source"; Close(); return false; } if (avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("abuffersink"), "out", nullptr, nullptr, filter_graph_) < 0) { qCritical() << "Failed to create audio buffer sink"; Close(); return false; } // Create audio tempo filters: FFmpeg's atempo can only be set between 0.5 and 2.0. If the requested speed is outside // those boundaries, we need to daisychain more than one together. double base = (speed_ > 1.0) ? 2.0 : 0.5; double speed_log = log(speed_) / log(base); // This is the number of how many 0.5 or 2.0 tempos we need to daisychain int whole = qFloor(speed_log); // Set speed_log to the remainder speed_log -= whole; AVFilterContext* previous_filter = buffersrc_ctx_; for (int i=0;i<=whole;i++) { double filter_tempo = (i == whole) ? qPow(base, speed_log) : base; if (qFuzzyCompare(filter_tempo, 1.0)) { // This filter would do nothing continue; } previous_filter = CreateTempoFilter(filter_graph_, previous_filter, filter_tempo); if (!previous_filter) { qCritical() << "Failed to create audio tempo filter"; Close(); return false; } } // Link the last filter to the buffersink if (avfilter_link(previous_filter, 0, buffersink_ctx_, 0) != 0) { qCritical() << "Failed to link final filter and buffer sink"; Close(); return false; } // Config graph if (avfilter_graph_config(filter_graph_, nullptr) < 0) { qCritical() << "Failed to configure filter graph"; Close(); return false; } timestamp_ = 0; open_ = true; flushed_ = false; return true; } void TempoProcessor::Push(const char *data, int length) { if (flushed_) { if (length > 0) { qCritical() << "Tried to push" << length << "bytes after TempoProcessor was closed"; } return; } AVFrame* src_frame; if (length == 0) { // No audio data, flush the last out of the filter graph src_frame = nullptr; flushed_ = true; } else { src_frame = av_frame_alloc(); if (!src_frame) { qCritical() << "Failed to allocate source frame"; return; } // Allocate a buffer for the number of samples we got src_frame->sample_rate = params_.sample_rate(); src_frame->format = FFmpegCommon::GetFFmpegSampleFormat(params_.format()); src_frame->channel_layout = params_.channel_layout(); src_frame->nb_samples = params_.bytes_to_samples(length); src_frame->pts = timestamp_; timestamp_ += src_frame->nb_samples; if (av_frame_get_buffer(src_frame, 0) < 0) { qCritical() << "Failed to allocate buffer for source frame"; av_frame_free(&src_frame); return; } // Copy buffer from data array to frame memcpy(src_frame->data[0], data, static_cast(length)); } int ret = av_buffersrc_add_frame_flags(buffersrc_ctx_, src_frame, AV_BUFFERSRC_FLAG_KEEP_REF); if (ret < 0) { qCritical() << "Failed to feed buffer source" << ret; } if (src_frame) { av_frame_free(&src_frame); } } int TempoProcessor::Pull(char *data, int max_length) { if (!processed_frame_) { processed_frame_ = av_frame_alloc(); // Try to pull samples from the buffersink int ret = av_buffersink_get_frame(buffersink_ctx_, processed_frame_); if (ret < 0) { // We couldn't pull for some reason, if the error was EAGAIN, we just need to send more samples. Otherwise the // error might be fatal... if (ret != AVERROR(EAGAIN)) { qCritical() << "Failed to pull from buffersink" << ret; } av_frame_free(&processed_frame_); return 0; } processed_frame_byte_index_ = 0; processed_frame_max_bytes_ = params_.samples_to_bytes(processed_frame_->nb_samples); } // Determine how many bytes we should copy into the data array int copy_length = qMin(max_length, processed_frame_max_bytes_ - processed_frame_byte_index_); // Copy the bytes memcpy(data, processed_frame_->data[0] + processed_frame_byte_index_, static_cast(copy_length)); // Add the copied amount to the current index processed_frame_byte_index_ += copy_length; // If the index has reached the limit of this processed frame, we can dispose of the frame now if (processed_frame_byte_index_ == processed_frame_max_bytes_) { av_frame_free(&processed_frame_); processed_frame_ = nullptr; } return copy_length; } void TempoProcessor::Close() { open_ = false; if (filter_graph_) { avfilter_graph_free(&filter_graph_); filter_graph_ = nullptr; } if (processed_frame_) { av_frame_free(&processed_frame_); processed_frame_ = nullptr; } buffersrc_ctx_ = nullptr; buffersink_ctx_ = nullptr; } AVFilterContext *TempoProcessor::CreateTempoFilter(AVFilterGraph* graph, AVFilterContext* link, const double &tempo) { // Set up tempo param, which is taken as a C string char speed_param[20]; snprintf(speed_param, 20, "%f", tempo); AVFilterContext* tempo_ctx = nullptr; if (avfilter_graph_create_filter(&tempo_ctx, avfilter_get_by_name("atempo"), "atempo", speed_param, nullptr, graph) >= 0 && avfilter_link(link, 0, tempo_ctx, 0) == 0) { return tempo_ctx; } return nullptr; } OLIVE_NAMESPACE_EXIT olive-continuous/app/audio/tempoprocessor.h000066400000000000000000000033131370472574300215320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TEMPOPROCESSOR_H #define TEMPOPROCESSOR_H #ifdef __MINGW32__ #ifndef __USE_MINGW_ANSI_STDIO #define __USE_MINGW_ANSI_STDIO #endif #endif #include extern "C" { #include } #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER class TempoProcessor { public: TempoProcessor(); bool IsOpen() const; const double& GetSpeed() const; bool Open(const AudioParams& params, const double &speed); void Push(const char *data, int length); int Pull(char* data, int max_length); void Close(); private: static AVFilterContext* CreateTempoFilter(AVFilterGraph *graph, AVFilterContext *link, const double& tempo); AVFilterGraph* filter_graph_; AVFilterContext* buffersrc_ctx_; AVFilterContext* buffersink_ctx_; AVFrame* processed_frame_; int processed_frame_byte_index_; int processed_frame_max_bytes_; AudioParams params_; int64_t timestamp_; double speed_; bool open_; bool flushed_; }; OLIVE_NAMESPACE_EXIT #endif // TEMPOPROCESSOR_H olive-continuous/app/cli/000077500000000000000000000000001370472574300157435ustar00rootroot00000000000000olive-continuous/app/cli/CMakeLists.txt000066400000000000000000000014561370472574300205110ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(cliprogress) add_subdirectory(clitask) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/cli/cliexport/000077500000000000000000000000001370472574300177545ustar00rootroot00000000000000olive-continuous/app/cli/cliexport/cliexportmanager.cpp000066400000000000000000000014761370472574300240340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "cliexportmanager.h" OLIVE_NAMESPACE_ENTER CLIExportManager::CLIExportManager() { } OLIVE_NAMESPACE_EXIT olive-continuous/app/cli/cliexport/cliexportmanager.h000066400000000000000000000016661370472574300235020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CLIEXPORTMANAGER_H #define CLIEXPORTMANAGER_H #include "task/export/export.h" OLIVE_NAMESPACE_ENTER class CLIExportManager : public QObject { public: CLIExportManager(); }; OLIVE_NAMESPACE_EXIT #endif // CLIEXPORTMANAGER_H olive-continuous/app/cli/cliprogress/000077500000000000000000000000001370472574300202775ustar00rootroot00000000000000olive-continuous/app/cli/cliprogress/CMakeLists.txt000066400000000000000000000015031370472574300230360ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} cli/cliprogress/cliprogressdialog.h cli/cliprogress/cliprogressdialog.cpp PARENT_SCOPE ) olive-continuous/app/cli/cliprogress/cliprogressdialog.cpp000066400000000000000000000045751370472574300245320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "cliprogressdialog.h" #include OLIVE_NAMESPACE_ENTER CLIProgressDialog::CLIProgressDialog(const QString& title, QObject *parent) : QObject(parent), title_(title), progress_(-1), drawn_(false) { SetProgress(0); } void CLIProgressDialog::Update() { if (drawn_) { // We've been here before, do a carriage return back to the start of the terminal line std::cout << "\r"; } else { drawn_ = true; } // FIXME: Get real column count int columns = 80; int title_columns = columns / 2 - 1; // Print "title" text QString sized_title = title_; if (title_.size() > title_columns) { sized_title = title_.left(title_columns - 3).append(QStringLiteral("...")); } else { sized_title = title_; } std::cout << sized_title.toUtf8().constData(); // Pad out the rest of the title area if necessary for (int i=sized_title.size(); i. ***/ #ifndef CLIPROGRESSDIALOG_H #define CLIPROGRESSDIALOG_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class CLIProgressDialog : public QObject { public: CLIProgressDialog(const QString &title, QObject* parent = nullptr); public slots: void SetProgress(double p); private: void Update(); QString title_; double progress_; bool drawn_; }; OLIVE_NAMESPACE_EXIT #endif // CLIPROGRESSDIALOG_H olive-continuous/app/cli/clitask/000077500000000000000000000000001370472574300173755ustar00rootroot00000000000000olive-continuous/app/cli/clitask/CMakeLists.txt000066400000000000000000000014631370472574300221410ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} cli/clitask/clitaskdialog.h cli/clitask/clitaskdialog.cpp PARENT_SCOPE ) olive-continuous/app/cli/clitask/clitaskdialog.cpp000066400000000000000000000020231370472574300227100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "clitaskdialog.h" OLIVE_NAMESPACE_ENTER CLITaskDialog::CLITaskDialog(Task *task, QObject* parent) : CLIProgressDialog(task->GetTitle(), parent), task_(task) { connect(task_, &Task::ProgressChanged, this, &CLITaskDialog::SetProgress); } bool CLITaskDialog::Run() { return task_->Start(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/cli/clitask/clitaskdialog.h000066400000000000000000000020601370472574300223560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CLITASKDIALOG_H #define CLITASKDIALOG_H #include "cli/cliprogress/cliprogressdialog.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class CLITaskDialog : public CLIProgressDialog { Q_OBJECT public: CLITaskDialog(Task *task, QObject* parent = nullptr); bool Run(); private: Task* task_; }; OLIVE_NAMESPACE_EXIT #endif // CLITASKDIALOG_H olive-continuous/app/codec/000077500000000000000000000000001370472574300162515ustar00rootroot00000000000000olive-continuous/app/codec/CMakeLists.txt000066400000000000000000000021701370472574300210110ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(ffmpeg) add_subdirectory(oiio) set(OLIVE_SOURCES ${OLIVE_SOURCES} codec/decoder.h codec/decoder.cpp codec/encoder.h codec/encoder.cpp codec/exportcodec.h codec/exportcodec.cpp codec/exportformat.h codec/exportformat.cpp codec/frame.h codec/frame.cpp codec/samplebuffer.h codec/samplebuffer.cpp codec/waveinput.h codec/waveinput.cpp codec/waveoutput.h codec/waveoutput.cpp PARENT_SCOPE ) olive-continuous/app/codec/decoder.cpp000066400000000000000000000115321370472574300203640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "decoder.h" #include #include #include #include "codec/ffmpeg/ffmpegcommon.h" #include "codec/ffmpeg/ffmpegdecoder.h" #include "codec/oiio/oiiodecoder.h" #include "codec/waveinput.h" #include "codec/waveoutput.h" #include "task/taskmanager.h" OLIVE_NAMESPACE_ENTER Decoder::Decoder() : open_(false), stream_(nullptr) { } Decoder::Decoder(Stream *fs) : open_(false), stream_(fs) { } StreamPtr Decoder::stream() const { return stream_; } void Decoder::set_stream(StreamPtr fs) { Close(); stream_ = fs; } FramePtr Decoder::RetrieveVideo(const rational &/*timecode*/, const int &/*divider*/) { return nullptr; } SampleBufferPtr Decoder::RetrieveAudio(const rational &/*timecode*/, const rational &/*length*/, const AudioParams &/*params*/) { return nullptr; } bool Decoder::SupportsVideo() { return false; } bool Decoder::SupportsAudio() { return false; } /* * DECODER STATIC PUBLIC MEMBERS */ QVector ReceiveListOfAllDecoders() { QVector decoders; // The order in which these decoders are added is their priority when probing. Hence FFmpeg should usually be last, // since it supports so many formats and we presumably want to override those formats with a more specific decoder. decoders.append(std::make_shared()); decoders.append(std::make_shared()); return decoders; } bool Decoder::ProbeMedia(Footage *f, const QAtomicInt* cancelled) { // Check for a valid filename if (f->filename().isEmpty()) { qWarning() << "Tried to probe media with an empty filename"; return false; } // Check file exists if (!QFileInfo::exists(f->filename())) { qWarning() << "Tried to probe file that doesn't exist:" << f->filename(); return false; } // Reset Footage state for probing f->Clear(); // Create list to iterate through QVector decoder_list = ReceiveListOfAllDecoders(); // Pass Footage through each Decoder's probe function for (int i=0;iProbe(f, cancelled)) { // We found a Decoder, so we can set this media as valid f->set_status(Footage::kReady); // Attach the successful Decoder to this Footage object f->set_decoder(decoder->id()); // FIXME: Cache the results so we don't have to probe if this media is added a second time return true; } } // We aren't able to use this Footage f->set_status(Footage::kInvalid); f->set_decoder(QString()); return false; } DecoderPtr Decoder::CreateFromID(const QString &id) { if (id.isEmpty()) { return nullptr; } // Create list to iterate through QVector decoder_list = ReceiveListOfAllDecoders(); foreach (DecoderPtr d, decoder_list) { if (d->id() == id) { return d; } } return nullptr; } QString Decoder::GetConformedFilename(const AudioParams ¶ms) { QString index_fn = GetIndexFilename(); index_fn.append('.'); index_fn.append(QString::number(params.sample_rate())); index_fn.append('.'); index_fn.append(QString::number(params.format())); index_fn.append('.'); index_fn.append(QString::number(params.channel_layout())); return index_fn; } bool Decoder::ConformAudio(const QAtomicInt *, const AudioParams& ) { return false; } bool Decoder::HasConformedVersion(const AudioParams ¶ms) { if (stream()->type() != Stream::kAudio) { return false; } AudioStreamPtr audio_stream = std::static_pointer_cast(stream()); if (audio_stream->has_conformed_version(params)) { return true; } // Get indexed WAV file WaveInput input(GetIndexFilename()); bool index_already_matches = false; if (input.open()) { index_already_matches = (input.params() == params); input.close(); } return index_already_matches; } void Decoder::SignalProcessingProgress(const int64_t &ts) { if (stream()->duration() != AV_NOPTS_VALUE && stream()->duration() != 0) { emit IndexProgress(static_cast(ts) / static_cast(stream()->duration())); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/decoder.h000066400000000000000000000237731370472574300200430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef DECODER_H #define DECODER_H extern "C" { #include } #include #include #include #include "codec/frame.h" #include "codec/samplebuffer.h" #include "codec/waveoutput.h" #include "common/rational.h" #include "project/item/footage/footage.h" OLIVE_NAMESPACE_ENTER class Decoder; using DecoderPtr = std::shared_ptr; /** * @brief A decoder's is the main class for bringing external media into Olive * * Its responsibilities are to serve as * abstraction from codecs/decoders and provide complete frames. These frames can be video or audio data and are * provided as Frame objects in shared pointers to alleviate the responsibility of memory handling. * * The main function in a decoder is Retrieve() which should return complete image/audio data. A decoder should * alleviate all the complexities of codec compression from the rest of the application (i.e. a decoder should never * return a partial frame or require other parts of the system to interface directly with the codec). Often this will * necessitate pre-emptively caching, indexing, or even fully transcoding media before using it which can be implemented * through the Analyze() function. * * A decoder does NOT perform any pixel/sample format conversion. Frames should pass through the PixelService * to be utilized in the rest of the rendering pipeline. */ class Decoder : public QObject { Q_OBJECT public: enum RetrieveState { kReady, kFailedToOpen, kIndexUnavailable }; Decoder(); Decoder(Stream* fs); DISABLE_COPY_MOVE(Decoder) virtual QString id() = 0; StreamPtr stream() const; void set_stream(StreamPtr fs); /** * @brief Probe a footage file and dump metadata about it * * When a Footage file is imported, we'll need to know whether Olive is equipped with a decoder for utilizing it * and metadata should be retrieved about it if so. For this purpose, the Footage object is passed through all * Probe() functions of available deocders until one returns TRUE. A FALSE return means the Decoder was unable to * parse this file and the next should be tried. * * Probe() differs from Open() since it focuses on a file as a whole rather than one particular stream. Probe() * should be able to be run directly without calling Open() or Close() and should free its memory before returning. * * Probe() will never be called on an object that is also used for decoding. In other words, it will never be called * alongside Open() or Close() externally, so Probe() can use variables that would otherwise be used for decoding * without conflict. * * @param f * * A Footage object to probe. The Footage object will have a valid filename and will be empty prior to being sent * to this function (i.e. Footage::Clear() will not have to be called). * * @return * * TRUE if the Decoder was able to decode this file. FALSE if not. This function should have filled the Footage * object with metadata if it returns TRUE. Otherwise, the Footage object should be untouched. */ virtual bool Probe(Footage* f, const QAtomicInt* cancelled) = 0; /** * @brief Open media/allocate memory * * Any file handles or memory allocation that needs to be done before this instance of a Decoder can return data * should be done here. * * @return * * TRUE if successful and ready to return data, FALSE if failed to open and unable to retrieve data. If the function * fails, any memory allocated should be free'd before returning FALSE, possibly by calling Close(). */ virtual bool Open() = 0; /** * @brief Retrieve video frame * * The main function for retrieving video data from the Decoder. This function should always provide complete frame * data (i.e. no partial frames) at the timecode provided. The Decoder should perform any steps required to retrieve * a complete frame separate from the rest of the program, using any form of caching/indexing to keep this as * performant as possible. * * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns * false, this function should return nullptr. * * @param timecode * * The timecode (a rational in seconds) to retrieve the frame at. If there is not a frame at this precise location * this should be corrected internally to the closest fit for the timecode. * * @return * * A FramePtr of valid data at this timecode or nullptr if there was nothing to retrieve at the provided timecode or * the media could not be opened. */ virtual FramePtr RetrieveVideo(const rational& timecode, const int& divider); /** * @brief Retrieve video frame * * The main function for retrieving audio data from the Decoder. This function should always provide complete frame * data (i.e. no missing samples) at the timecode and length requested. The Decoder should perform any steps * required to retrieve a complete frame separate from the rest of the program, using any form of caching/indexing * to keep this as performant as possible. * * It's acceptable for this function to check whether the Decoder is open, and call Open() if not. If Open() returns * false, this function should return nullptr. * * @param timecode * * The starting timecode (a rational in seconds) to retrieve the data at. * * @param length * * The total length of audio data to retrieve (a rational in seconds). * * @return * * A FramePtr of valid data at this timecode of the requested length or nullptr if there was nothing to retrieve at * the provided timecode or the media could not be opened. */ virtual SampleBufferPtr RetrieveAudio(const rational& timecode, const rational& length, const AudioParams& params); virtual bool SupportsVideo(); virtual bool SupportsAudio(); /** * @brief Close media/deallocate memory * * Any file handles or memory allocations opened in Open() should be cleaned up here. * * As the main memory freeing function, it's good practice to call this in Open() if there's an error that prevents * correct function before Open() returns. As such, Close() should be prepared for not all memory/file handles to * have been opened successfully. */ virtual void Close() = 0; /** * @brief Try to probe a Footage file by passing it through all available Decoders * * This is a helper function designed to abstract the process of communicating with several Decoders from the rest of * the application. This function will take a Footage file and manually pass it through the available Decoders' Probe() * functions until one indicates that it can decode this file. That Decoder will then dump information about the file * into the Footage object for use throughout the program. * * Probing may be a lengthy process and it's recommended to run this in a separate thread. * * @param f * * A Footage object with a valid filename. If the Footage does not have a valid filename (e.g. is empty or file doesn't * exist), this function will return FALSE. * * @return * * TRUE if a Decoder was successfully able to parse and probe this file. FALSE if not. */ static bool ProbeMedia(Footage* f, const QAtomicInt *cancelled); /** * @brief Create a Decoder instance using a Decoder ID * * @return * * A Decoder instance or nullptr if a Decoder with this ID does not exist */ static DecoderPtr CreateFromID(const QString& id); /** * @brief AUDIO ONLY: Produces a complete PCM extraction of the audio stream * * Internally, our render engine only deals with PCM since it provides the least headaches and * modern computers have the processing power to do it. * * Resamples and converts the currently open audio to match the params. If the audio doesn't need * conforming (e.g. audio params already match or a conformed match already exists), this function * will return immediately. Otherwise it will block the calling thread until the conform is * complete. This function should therefore only be called from a background render thread. * * All audio decoders must override this. It's not pure since video decoders don't need to use * this, but default behavior will abort since it should never be called. */ virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioParams ¶ms); /** * @brief AUDIO ONLY: Returns whether a transcode of this audio matching the specified params * already exists */ bool HasConformedVersion(const AudioParams& params); signals: /** * @brief While indexing, this signal will provide progress as a percentage (0-100 inclusive) if * available */ void IndexProgress(double); protected: void SignalProcessingProgress(const int64_t& ts); /** * @brief Returns the filename for the index * * Retrieves the absolute filename of the index file for this stream. Decoder must be open for * this to work correctly. */ virtual QString GetIndexFilename() const = 0; /** * @brief Get the destination filename of an audio stream conformed to a set of parameters */ QString GetConformedFilename(const AudioParams ¶ms); bool open_; QMutex mutex_; private: StreamPtr stream_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::Decoder::RetrieveState) #endif // DECODER_H olive-continuous/app/codec/encoder.cpp000066400000000000000000000134641370472574300204040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "encoder.h" #include "ffmpeg/ffmpegencoder.h" OLIVE_NAMESPACE_ENTER Encoder::Encoder(const EncodingParams ¶ms) : params_(params) { } const EncodingParams &Encoder::params() const { return params_; } EncodingParams::EncodingParams() : video_enabled_(false), video_bit_rate_(0), video_max_bit_rate_(0), video_buffer_size_(0), video_threads_(0), audio_enabled_(false) { } void EncodingParams::SetFilename(const QString &filename) { filename_ = filename; } void EncodingParams::EnableVideo(const VideoParams &video_params, const ExportCodec::Codec &vcodec) { video_enabled_ = true; video_params_ = video_params; video_codec_ = vcodec; } void EncodingParams::EnableAudio(const AudioParams &audio_params, const ExportCodec::Codec &acodec) { audio_enabled_ = true; audio_params_ = audio_params; audio_codec_ = acodec; } void EncodingParams::set_video_option(const QString &key, const QString &value) { video_opts_.insert(key, value); } void EncodingParams::set_video_bit_rate(const int64_t &rate) { video_bit_rate_ = rate; } void EncodingParams::set_video_max_bit_rate(const int64_t &rate) { video_max_bit_rate_ = rate; } void EncodingParams::set_video_buffer_size(const int64_t &sz) { video_buffer_size_ = sz; } void EncodingParams::set_video_threads(const int &threads) { video_threads_ = threads; } const QString &EncodingParams::filename() const { return filename_; } bool EncodingParams::video_enabled() const { return video_enabled_; } const ExportCodec::Codec &EncodingParams::video_codec() const { return video_codec_; } const VideoParams &EncodingParams::video_params() const { return video_params_; } const QHash &EncodingParams::video_opts() const { return video_opts_; } const int64_t &EncodingParams::video_bit_rate() const { return video_bit_rate_; } const int64_t &EncodingParams::video_max_bit_rate() const { return video_max_bit_rate_; } const int64_t &EncodingParams::video_buffer_size() const { return video_buffer_size_; } const int &EncodingParams::video_threads() const { return video_threads_; } bool EncodingParams::audio_enabled() const { return audio_enabled_; } const ExportCodec::Codec &EncodingParams::audio_codec() const { return audio_codec_; } const AudioParams &EncodingParams::audio_params() const { return audio_params_; } const rational &EncodingParams::GetExportLength() const { return export_length_; } void EncodingParams::SetExportLength(const rational &export_length) { export_length_ = export_length; } void EncodingParams::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("encode")); writer->writeTextElement(QStringLiteral("filename"), filename_); writer->writeStartElement(QStringLiteral("video")); writer->writeAttribute(QStringLiteral("enabled"), QString::number(video_enabled_)); if (video_enabled_) { writer->writeTextElement(QStringLiteral("codec"), QString::number(video_codec_)); writer->writeTextElement(QStringLiteral("width"), QString::number(video_params_.width())); writer->writeTextElement(QStringLiteral("height"), QString::number(video_params_.height())); writer->writeTextElement(QStringLiteral("format"), QString::number(video_params_.format())); writer->writeTextElement(QStringLiteral("timebase"), video_params_.time_base().toString()); writer->writeTextElement(QStringLiteral("divider"), QString::number(video_params_.divider())); writer->writeTextElement(QStringLiteral("bitrate"), QString::number(video_bit_rate_)); writer->writeTextElement(QStringLiteral("maxbitrate"), QString::number(video_max_bit_rate_)); writer->writeTextElement(QStringLiteral("bufsize"), QString::number(video_buffer_size_)); writer->writeTextElement(QStringLiteral("threads"), QString::number(video_threads_)); if (!video_opts_.isEmpty()) { writer->writeStartElement(QStringLiteral("opts")); QHash::const_iterator i; for (i=video_opts_.constBegin(); i!=video_opts_.constEnd(); i++) { writer->writeStartElement(QStringLiteral("entry")); writer->writeTextElement(QStringLiteral("key"), i.key()); writer->writeTextElement(QStringLiteral("value"), i.value()); writer->writeEndElement(); // entry } writer->writeEndElement(); // opts } } writer->writeEndElement(); // video writer->writeStartElement(QStringLiteral("audio")); writer->writeAttribute(QStringLiteral("enabled"), QString::number(audio_enabled_)); if (audio_enabled_) { writer->writeTextElement(QStringLiteral("codec"), QString::number(audio_codec_)); writer->writeTextElement(QStringLiteral("samplerate"), QString::number(audio_params_.sample_rate())); writer->writeTextElement(QStringLiteral("channellayout"), QString::number(audio_params_.channel_layout())); writer->writeTextElement(QStringLiteral("format"), QString::number(audio_params_.format())); } writer->writeEndElement(); // audio writer->writeEndElement(); // encode } Encoder* Encoder::CreateFromID(const QString &id, const EncodingParams& params) { Q_UNUSED(id) return new FFmpegEncoder(params); } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/encoder.h000066400000000000000000000065201370472574300200440ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef ENCODER_H #define ENCODER_H #include #include #include #include "codec/exportcodec.h" #include "codec/exportformat.h" #include "codec/frame.h" #include "common/timerange.h" #include "render/audioparams.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER class Encoder; using EncoderPtr = std::shared_ptr; class EncodingParams { public: EncodingParams(); void SetFilename(const QString& filename); void EnableVideo(const VideoParams& video_params, const ExportCodec::Codec& vcodec); void EnableAudio(const AudioParams& audio_params, const ExportCodec::Codec &acodec); void set_video_option(const QString& key, const QString& value); void set_video_bit_rate(const int64_t& rate); void set_video_max_bit_rate(const int64_t& rate); void set_video_buffer_size(const int64_t& sz); void set_video_threads(const int& threads); const QString& filename() const; bool video_enabled() const; const ExportCodec::Codec& video_codec() const; const VideoParams& video_params() const; const QHash& video_opts() const; const int64_t& video_bit_rate() const; const int64_t& video_max_bit_rate() const; const int64_t& video_buffer_size() const; const int& video_threads() const; bool audio_enabled() const; const ExportCodec::Codec &audio_codec() const; const AudioParams& audio_params() const; const rational& GetExportLength() const; void SetExportLength(const rational& GetExportLength); virtual void Save(QXmlStreamWriter* writer) const; private: QString filename_; bool video_enabled_; ExportCodec::Codec video_codec_; VideoParams video_params_; QHash video_opts_; int64_t video_bit_rate_; int64_t video_max_bit_rate_; int64_t video_buffer_size_; int video_threads_; bool audio_enabled_; ExportCodec::Codec audio_codec_; AudioParams audio_params_; rational export_length_; }; class Encoder : public QObject { Q_OBJECT public: Encoder(const EncodingParams& params); /** * @brief Create a Encoder instance using a Encoder ID * * @return * * A Encoder instance or nullptr if a Decoder with this ID does not exist */ static Encoder *CreateFromID(const QString& id, const EncodingParams ¶ms); const EncodingParams& params() const; virtual bool Open() = 0; virtual bool WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time) = 0; virtual void WriteAudio(OLIVE_NAMESPACE::AudioParams pcm_info, const QString& pcm_filename) = 0; virtual void Close() = 0; private: EncodingParams params_; }; OLIVE_NAMESPACE_EXIT #endif // ENCODER_H olive-continuous/app/codec/exportcodec.cpp000066400000000000000000000033571370472574300213040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "exportcodec.h" OLIVE_NAMESPACE_ENTER QString ExportCodec::GetCodecName(ExportCodec::Codec c) { switch (c) { case kCodecDNxHD: return tr("DNxHD"); case kCodecH264: return tr("H.264"); case kCodecH265: return tr("H.265"); case kCodecOpenEXR: return tr("OpenEXR"); case kCodecPNG: return tr("PNG"); case kCodecProRes: return tr("ProRes"); case kCodecTIFF: return tr("TIFF"); case kCodecMP2: return tr("MP2"); case kCodecMP3: return tr("MP3"); case kCodecAAC: return tr("AAC"); case kCodecPCM: return tr("PCM (Uncompressed)"); case kCodecCount: break; } return tr("Unknown"); } bool ExportCodec::IsCodecAStillImage(ExportCodec::Codec c) { switch (c) { case kCodecDNxHD: case kCodecH264: case kCodecH265: case kCodecProRes: case kCodecMP2: case kCodecMP3: case kCodecAAC: case kCodecPCM: return false; case kCodecOpenEXR: case kCodecPNG: case kCodecTIFF: return true; case kCodecCount: break; } return false; } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/exportcodec.h000066400000000000000000000023331370472574300207420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTCODEC_H #define EXPORTCODEC_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ExportCodec : public QObject { public: enum Codec { kCodecDNxHD, kCodecH264, kCodecH265, kCodecOpenEXR, kCodecPNG, kCodecProRes, kCodecTIFF, kCodecMP2, kCodecMP3, kCodecAAC, kCodecPCM, kCodecCount }; static QString GetCodecName(Codec c); static bool IsCodecAStillImage(Codec c); }; OLIVE_NAMESPACE_EXIT #endif // EXPORTCODEC_H olive-continuous/app/codec/exportformat.cpp000066400000000000000000000066621370472574300215210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "exportformat.h" OLIVE_NAMESPACE_ENTER QString ExportFormat::GetName(olive::ExportFormat::Format f) { switch (f) { case kFormatDNxHD: return tr("DNxHD"); case kFormatMatroska: return tr("Matroska Video"); case kFormatMPEG4: return tr("MPEG-4 Video"); case kFormatOpenEXR: return tr("OpenEXR"); case kFormatPNG: return tr("PNG"); case kFormatTIFF: return tr("TIFF"); case kFormatQuickTime: return tr("QuickTime"); case kFormatCount: break; } return tr("Unknown"); } QString ExportFormat::GetExtension(ExportFormat::Format f) { switch (f) { case kFormatDNxHD: return QStringLiteral("mxf"); case kFormatMatroska: return QStringLiteral("mkv"); case kFormatMPEG4: return QStringLiteral("mp4"); case kFormatOpenEXR: return QStringLiteral("exr"); case kFormatPNG: return QStringLiteral("png"); case kFormatTIFF: return QStringLiteral("tiff"); case kFormatQuickTime: return QStringLiteral("mov"); case kFormatCount: break; } return QString(); } QString ExportFormat::GetEncoder(ExportFormat::Format f) { switch (f) { case kFormatDNxHD: case kFormatMatroska: case kFormatQuickTime: case kFormatMPEG4: return QStringLiteral("ffmpeg"); case kFormatOpenEXR: case kFormatPNG: case kFormatTIFF: return QStringLiteral("oiio"); case kFormatCount: break; } return QString(); } QList ExportFormat::GetVideoCodecs(ExportFormat::Format f) { switch (f) { case kFormatDNxHD: return {ExportCodec::kCodecDNxHD}; case kFormatMatroska: return {ExportCodec::kCodecH264, ExportCodec::kCodecH265}; case kFormatMPEG4: return {ExportCodec::kCodecH264, ExportCodec::kCodecH265}; case kFormatOpenEXR: return {ExportCodec::kCodecOpenEXR}; case kFormatPNG: return {ExportCodec::kCodecPNG}; case kFormatTIFF: return {ExportCodec::kCodecTIFF}; case kFormatQuickTime: return {ExportCodec::kCodecH264, ExportCodec::kCodecH265, ExportCodec::kCodecProRes}; case kFormatCount: break; } return {}; } QList ExportFormat::GetAudioCodecs(ExportFormat::Format f) { switch (f) { case kFormatDNxHD: return {ExportCodec::kCodecPCM}; case kFormatMatroska: return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM}; case kFormatMPEG4: return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM}; case kFormatQuickTime: return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM}; case kFormatOpenEXR: case kFormatPNG: case kFormatTIFF: return {}; case kFormatCount: break; } return {}; } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/exportformat.h000066400000000000000000000026001370472574300211520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTFORMAT_H #define EXPORTFORMAT_H #include #include #include "common/define.h" #include "exportcodec.h" OLIVE_NAMESPACE_ENTER class ExportFormat : public QObject { public: enum Format { kFormatDNxHD, kFormatMatroska, kFormatMPEG4, kFormatOpenEXR, kFormatQuickTime, kFormatPNG, kFormatTIFF, kFormatCount }; static QString GetName(Format f); static QString GetExtension(Format f); static QString GetEncoder(Format f); static QList GetVideoCodecs(ExportFormat::Format f); static QList GetAudioCodecs(ExportFormat::Format f); }; OLIVE_NAMESPACE_EXIT #endif // EXPORTFORMAT_H olive-continuous/app/codec/ffmpeg/000077500000000000000000000000001370472574300175155ustar00rootroot00000000000000olive-continuous/app/codec/ffmpeg/CMakeLists.txt000066400000000000000000000020231370472574300222520ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} codec/ffmpeg/avframeptr.h codec/ffmpeg/ffmpegcommon.h codec/ffmpeg/ffmpegcommon.cpp codec/ffmpeg/ffmpegdecoder.h codec/ffmpeg/ffmpegdecoder.cpp codec/ffmpeg/ffmpegencoder.h codec/ffmpeg/ffmpegencoder.cpp codec/ffmpeg/ffmpegframepool.h codec/ffmpeg/ffmpegframepool.cpp PARENT_SCOPE ) olive-continuous/app/codec/ffmpeg/avframeptr.h000066400000000000000000000023671370472574300220450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AVFRAMEPTR_H #define AVFRAMEPTR_H extern "C" { #include } #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class AVFrameWrapper { public: AVFrameWrapper() { frame_ = av_frame_alloc(); } virtual ~AVFrameWrapper() { av_frame_free(&frame_); } DISABLE_COPY_MOVE(AVFrameWrapper) inline AVFrame* frame() const { return frame_; } private: AVFrame* frame_; }; using AVFramePtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // AVFRAMEPTR_H olive-continuous/app/codec/ffmpeg/ffmpegcommon.cpp000066400000000000000000000076231370472574300227060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "ffmpegcommon.h" OLIVE_NAMESPACE_ENTER AVPixelFormat FFmpegCommon::GetCompatiblePixelFormat(const AVPixelFormat &pix_fmt) { AVPixelFormat possible_pix_fmts[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_NONE }; return avcodec_find_best_pix_fmt_of_list(possible_pix_fmts, pix_fmt, 1, nullptr); } SampleFormat::Format FFmpegCommon::GetNativeSampleFormat(const AVSampleFormat &smp_fmt) { switch (smp_fmt) { case AV_SAMPLE_FMT_U8: return SampleFormat::SAMPLE_FMT_U8; case AV_SAMPLE_FMT_S16: return SampleFormat::SAMPLE_FMT_S16; case AV_SAMPLE_FMT_S32: return SampleFormat::SAMPLE_FMT_S32; case AV_SAMPLE_FMT_S64: return SampleFormat::SAMPLE_FMT_S64; case AV_SAMPLE_FMT_FLT: return SampleFormat::SAMPLE_FMT_FLT; case AV_SAMPLE_FMT_DBL: return SampleFormat::SAMPLE_FMT_DBL; case AV_SAMPLE_FMT_U8P : case AV_SAMPLE_FMT_S16P: case AV_SAMPLE_FMT_S32P: case AV_SAMPLE_FMT_S64P: case AV_SAMPLE_FMT_FLTP: case AV_SAMPLE_FMT_DBLP: case AV_SAMPLE_FMT_NONE: case AV_SAMPLE_FMT_NB: break; } return SampleFormat::SAMPLE_FMT_INVALID; } AVSampleFormat FFmpegCommon::GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt) { switch (smp_fmt) { case SampleFormat::SAMPLE_FMT_U8: return AV_SAMPLE_FMT_U8; case SampleFormat::SAMPLE_FMT_S16: return AV_SAMPLE_FMT_S16; case SampleFormat::SAMPLE_FMT_S32: return AV_SAMPLE_FMT_S32; case SampleFormat::SAMPLE_FMT_S64: return AV_SAMPLE_FMT_S64; case SampleFormat::SAMPLE_FMT_FLT: return AV_SAMPLE_FMT_FLT; case SampleFormat::SAMPLE_FMT_DBL: return AV_SAMPLE_FMT_DBL; case SampleFormat::SAMPLE_FMT_INVALID: case SampleFormat::SAMPLE_FMT_COUNT: break; } return AV_SAMPLE_FMT_NONE; } AVPixelFormat FFmpegCommon::GetFFmpegPixelFormat(const PixelFormat::Format &pix_fmt) { switch (pix_fmt) { case PixelFormat::PIX_FMT_RGBA8: return AV_PIX_FMT_RGBA; case PixelFormat::PIX_FMT_RGBA16U: return AV_PIX_FMT_RGBA64; case PixelFormat::PIX_FMT_RGB8: return AV_PIX_FMT_RGB24; case PixelFormat::PIX_FMT_RGB16U: return AV_PIX_FMT_RGB48; case PixelFormat::PIX_FMT_RGBA16F: case PixelFormat::PIX_FMT_RGBA32F: case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return AV_PIX_FMT_NONE; } PixelFormat::Format FFmpegCommon::GetCompatiblePixelFormat(const PixelFormat::Format &pix_fmt) { switch (pix_fmt) { case PixelFormat::PIX_FMT_RGB8: return PixelFormat::PIX_FMT_RGB8; case PixelFormat::PIX_FMT_RGBA8: return PixelFormat::PIX_FMT_RGBA8; case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGB32F: return PixelFormat::PIX_FMT_RGB16U; case PixelFormat::PIX_FMT_RGBA16U: case PixelFormat::PIX_FMT_RGBA16F: case PixelFormat::PIX_FMT_RGBA32F: return PixelFormat::PIX_FMT_RGBA16U; case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return PixelFormat::PIX_FMT_INVALID; } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/ffmpeg/ffmpegcommon.h000066400000000000000000000036371370472574300223540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FFMPEGABSTRACTION_H #define FFMPEGABSTRACTION_H extern "C" { #include } #include "audio/sampleformat.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER class FFmpegCommon { public: /** * @brief Returns an AVPixelFormat that can be used to convert a frame to a data type Olive supports with minimal data loss */ static AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt); /** * @brief Returns a native pixel format that can be used to convert from a native frame to an AVFrame with minimal data loss */ static PixelFormat::Format GetCompatiblePixelFormat(const PixelFormat::Format& pix_fmt); /** * @brief Returns an FFmpeg pixel format for a given native pixel format */ static AVPixelFormat GetFFmpegPixelFormat(const PixelFormat::Format& pix_fmt); /** * @brief Returns a native sample format type for a given AVSampleFormat */ static SampleFormat::Format GetNativeSampleFormat(const AVSampleFormat& smp_fmt); /** * @brief Returns an FFmpeg sample format type for a given native type */ static AVSampleFormat GetFFmpegSampleFormat(const SampleFormat::Format &smp_fmt); }; OLIVE_NAMESPACE_EXIT #endif // FFMPEGABSTRACTION_H olive-continuous/app/codec/ffmpeg/ffmpegdecoder.cpp000066400000000000000000001176501370472574300230250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "ffmpegdecoder.h" extern "C" { #include #include #include #include } #include #include #include #include #include #include #include #include #include "codec/waveinput.h" #include "common/define.h" #include "common/filefunctions.h" #include "common/functiontimer.h" #include "common/timecodefunctions.h" #include "ffmpegcommon.h" #include "render/framehashcache.h" #include "render/diskmanager.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER QHash< Stream*, QList > FFmpegDecoder::instance_map_; QMutex FFmpegDecoder::instance_map_lock_; QHash< Stream*, FFmpegFramePool* > FFmpegDecoder::frame_pool_map_; // FIXME: Hardcoded, ideally this value is dynamically chosen based on memory restraints const int FFmpegDecoderInstance::kMaxFrameLife = 2000; FFmpegDecoder::FFmpegDecoder() : scale_ctx_(nullptr), scale_divider_(0) { } FFmpegDecoder::~FFmpegDecoder() { Close(); } bool FFmpegDecoder::Open() { QMutexLocker locker(&mutex_); if (open_) { return true; } Q_ASSERT(stream()); // Convert QString to a C string QByteArray fn_bytes = stream()->footage()->filename().toUtf8(); FFmpegDecoderInstance* our_instance = new FFmpegDecoderInstance(fn_bytes.constData(), stream()->index()); if (!our_instance->IsValid()) { delete our_instance; return false; } if (stream()->type() == Stream::kImage || stream()->type() == Stream::kVideo) { // Get an Olive compatible AVPixelFormat src_pix_fmt_ = static_cast(our_instance->stream()->codecpar->format); ideal_pix_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(src_pix_fmt_); if (stream()->type() == Stream::kVideo) { QMutexLocker map_locker(&instance_map_lock_); // FIXME: Test code, this should be changed later FFmpegFramePool* frame_pool = frame_pool_map_.value(stream().get()); if (!frame_pool) { frame_pool = new FFmpegFramePool(256, our_instance->stream()->codecpar->width, our_instance->stream()->codecpar->height, static_cast(our_instance->stream()->codecpar->format)); frame_pool_map_.insert(stream().get(), frame_pool); } our_instance->SetFramePool(frame_pool); // End test code } // Determine which Olive native pixel format we retrieved // Note that FFmpeg doesn't support float formats native_pix_fmt_ = GetNativePixelFormat(ideal_pix_fmt_); Q_ASSERT(native_pix_fmt_ != PixelFormat::PIX_FMT_INVALID); aspect_ratio_ = our_instance->sample_aspect_ratio(); } time_base_ = our_instance->stream()->time_base; start_time_ = our_instance->stream()->start_time; // All allocation succeeded so we set the state to open open_ = true; { QMutexLocker l(&instance_map_lock_); QList list = instance_map_.value(stream().get()); list.append(our_instance); instance_map_.insert(stream().get(), list); } return true; } FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode, const int ÷r) { QMutexLocker locker(&mutex_); if (!open_) { qWarning() << "Tried to retrieve video on a decoder that's still closed"; return nullptr; } if (stream()->type() != Stream::kImage && stream()->type() != Stream::kVideo) { return nullptr; } ImageStreamPtr is = std::static_pointer_cast(stream()); if (stream()->type() == Stream::kImage) { // FIXME: Hacky FFmpegDecoderInstance i(stream()->footage()->filename().toUtf8(), stream()->index()); AVPacket* pkt = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); FramePtr output_frame = nullptr; int ret = i.GetFrame(pkt, frame); if (ret >= 0) { output_frame = BuffersToNativeFrame(divider, is->width(), is->height(), 0, frame->data, frame->linesize); } else { qWarning() << "Failed to retrieve still image from decoder"; } av_frame_free(&frame); av_packet_free(&pkt); return output_frame; } else { FFmpegFramePool::ElementPtr return_frame = nullptr; int64_t target_ts = Timecode::time_to_timestamp(timecode, time_base_) + start_time_; VideoStreamPtr vs = std::static_pointer_cast(stream()); FFmpegDecoderInstance* working_instance = nullptr; // Find instance do { QMutexLocker list_locker(&instance_map_lock_); QList non_ideal_contenders; QList instances = instance_map_.value(stream().get()); foreach (FFmpegDecoderInstance* i, instances) { i->cache_lock()->lock(); if (i->CacheContainsTime(target_ts)) { // Found our instance, allow others to enter the list list_locker.unlock(); // Get the frame from this cache return_frame = i->GetFrameFromCache(target_ts); // Got our frame, allow cache to continue i->cache_lock()->unlock(); break; } else if (i->CacheWillContainTime(target_ts) || i->CacheCouldContainTime(target_ts)) { // Found our instance, allow others to enter the list list_locker.unlock(); // If the instance is currently in use, enter into a loop of seeing from frames come up next in case one is ours if (i->IsWorking()) { do { // Allow instance to continue to the next frame i->cache_wait_cond()->wait(i->cache_lock()); // See if the cache now contains this frame, if so we'll exit this loop if (i->CacheContainsTime(target_ts)) { // Grab the frame return_frame = i->GetFrameFromCache(target_ts); // We can release this worker now since we don't need it anymore i->cache_lock()->unlock(); } else if (!i->IsWorking()) { // This instance finished and we didn't get our frame, we'll take it and continue it working_instance = i; break; } } while (!return_frame); } else { // Otherwise, we'll grab this instance and continue it ourselves working_instance = i; } break; } else if (i->IsWorking()) { // Ignore currently working instances i->cache_lock()->unlock(); } else if (i->CacheIsEmpty()) { // Prioritize this cache over others (leaves this instance LOCKED in case we end up using it later) non_ideal_contenders.prepend(i); } else { // De-prioritize this cache (leaves this instance LOCKED in case we end up using it later) non_ideal_contenders.append(i); } } // If we didn't find a suitable contender, grab the first non-suitable and roll with that if (!return_frame && !working_instance && !non_ideal_contenders.isEmpty()) { working_instance = non_ideal_contenders.takeFirst(); } // For all instances we left locked but didn't end up using, lock them now foreach (FFmpegDecoderInstance* unsuitable_instance, non_ideal_contenders) { unsuitable_instance->cache_lock()->unlock(); } } while (!return_frame && !working_instance); if (!return_frame && working_instance) { // This instance SHOULD remain locked from our earlier loop, making this operation safe working_instance->SetWorking(true); // Retrieve frame return_frame = working_instance->RetrieveFrame(target_ts, true); // Set working to false and wake any threads waiting working_instance->cache_lock()->lock(); working_instance->SetWorking(false); working_instance->cache_wait_cond()->wakeAll(); working_instance->cache_lock()->unlock(); } // We found the frame, we'll return a copy if (return_frame) { // Align buffer to data/linesize points that can be passed to sws_scale uint8_t* input_data[4]; int input_linesize[4]; av_image_fill_arrays(input_data, input_linesize, reinterpret_cast(return_frame->data()), src_pix_fmt_, vs->width(), vs->height(), 1); return BuffersToNativeFrame(divider, vs->width(), vs->height(), target_ts, input_data, input_linesize); } } return nullptr; } SampleBufferPtr FFmpegDecoder::RetrieveAudio(const rational &timecode, const rational &length, const AudioParams ¶ms) { QMutexLocker locker(&mutex_); if (!open_) { qWarning() << "Tried to retrieve audio on a decoder that's still closed"; return nullptr; } if (stream()->type() != Stream::kAudio) { return nullptr; } QString wav_fn = GetConformedFilename(params); WaveInput input(wav_fn); if (input.open()) { const AudioParams& input_params = input.params(); // Read bytes from wav QByteArray packed_data = input.read(input_params.time_to_bytes(timecode), input_params.time_to_bytes(length)); input.close(); // Create sample buffer SampleBufferPtr sample_buffer = SampleBuffer::CreateFromPackedData(input_params, packed_data); return sample_buffer; } qCritical() << "Failed to open cached file" << wav_fn; return nullptr; } void FFmpegDecoder::Close() { QMutexLocker locker(&mutex_); { // Clear whichever instance is not in use and is least useful (there are only ever as many instances as there are // threads so if this thread is closing, an instance MUST be inactive) QMutexLocker l(&instance_map_lock_); QList list = instance_map_.value(stream().get()); if (!list.isEmpty()) { // Rank the instances by least useful (the top one should be one that isn't working and isn't in use) QList least_useful; foreach (FFmpegDecoderInstance* i, list) { i->cache_lock()->lock(); if (i->IsWorking()) { // Don't bother any currently working instances i->cache_lock()->unlock(); continue; } if (i->CacheIsEmpty()) { least_useful.prepend(i); } else { least_useful.append(i); } } // Remove the least useful from the list and re-insert it into the map FFmpegDecoderInstance* least_useful_instance = least_useful.first(); list.removeOne(least_useful_instance); instance_map_.insert(stream().get(), list); // If there are no more instances, destroy frame pool if (list.isEmpty()) { FFmpegFramePool* frame_pool = frame_pool_map_.take(stream().get()); delete frame_pool; } // We're done with the list now, we can unlock it and allow others to use it l.unlock(); // Unlock all the instances we locked foreach (FFmpegDecoderInstance* i, least_useful) { i->cache_lock()->unlock(); } // Delete this least useful instance now that we've definitely taken ownership of it least_useful_instance->deleteLater(); } } ClearResources(); } QString FFmpegDecoder::id() { return QStringLiteral("ffmpeg"); } bool FFmpegDecoder::SupportsVideo() { return true; } bool FFmpegDecoder::SupportsAudio() { return true; } bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled) { if (open_) { qWarning() << "Probe must be called while the Decoder is closed"; return false; } // Variable for receiving errors from FFmpeg int error_code; // Result to return bool result = false; // Convert QString to a C string QByteArray ba = f->filename().toUtf8(); const char* filename = ba.constData(); // Open file in a format context AVFormatContext* fmt_ctx = nullptr; error_code = avformat_open_input(&fmt_ctx, filename, nullptr, nullptr); // Handle format context error if (error_code == 0) { // Retrieve metadata about the media avformat_find_stream_info(fmt_ctx, nullptr); // Dump it into the Footage object for (unsigned int i=0;inb_streams;i++) { AVStream* avstream = fmt_ctx->streams[i]; StreamPtr str; if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { bool image_is_still = false; ImageStream::Interlacing interlacing = ImageStream::kInterlaceNone; { // Read at least two frames to get more information about this video stream AVPacket* pkt = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); { FFmpegDecoderInstance instance(filename, i); // Read first frame and retrieve some metadata if (instance.GetFrame(pkt, frame) >= 0) { // Check if video is interlaced and what field dominance it has if so if (frame->interlaced_frame) { if (frame->top_field_first) { interlacing = ImageStream::kInterlacedTopFirst; } else { interlacing = ImageStream::kInterlacedBottomFirst; } } } // Read second frame int ret = instance.GetFrame(pkt, frame); if (ret >= 0) { // Check if we need a manual duration if (avstream->duration == AV_NOPTS_VALUE) { int64_t new_dur; do { new_dur = frame->pts; } while (instance.GetFrame(pkt, frame) >= 0); avstream->duration = new_dur; } } else if (ret == AVERROR_EOF) { // Video has only one frame in it, treat it like a still image image_is_still = true; } } av_frame_free(&frame); av_packet_free(&pkt); } ImageStreamPtr image_stream; if (image_is_still) { image_stream = std::make_shared(); } else { VideoStreamPtr video_stream = std::make_shared(); video_stream->set_frame_rate(av_guess_frame_rate(fmt_ctx, avstream, nullptr)); video_stream->set_start_time(avstream->start_time); image_stream = video_stream; } image_stream->set_width(avstream->codecpar->width); image_stream->set_height(avstream->codecpar->height); image_stream->set_format(GetNativePixelFormat(FFmpegCommon::GetCompatiblePixelFormat(static_cast(avstream->codecpar->format)))); image_stream->set_interlacing(interlacing); str = image_stream; } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // Create an audio stream object AudioStreamPtr audio_stream = std::make_shared(); uint64_t channel_layout = avstream->codecpar->channel_layout; if (!channel_layout) { channel_layout = static_cast(av_get_default_channel_layout(avstream->codecpar->channels)); } audio_stream->set_channel_layout(channel_layout); audio_stream->set_channels(avstream->codecpar->channels); audio_stream->set_sample_rate(avstream->codecpar->sample_rate); str = audio_stream; } else { // This is data we can't utilize at the moment, but we make a Stream object anyway to keep parity with the file str = std::make_shared(); // Set the correct codec type based on FFmpeg's result switch (avstream->codecpar->codec_type) { case AVMEDIA_TYPE_UNKNOWN: str->set_type(Stream::kUnknown); break; case AVMEDIA_TYPE_DATA: str->set_type(Stream::kData); break; case AVMEDIA_TYPE_SUBTITLE: str->set_type(Stream::kSubtitle); break; case AVMEDIA_TYPE_ATTACHMENT: str->set_type(Stream::kAttachment); break; default: // We should never realistically get here, but we make an "invalid" stream just in case str->set_type(Stream::kUnknown); break; } } str->set_index(avstream->index); str->set_timebase(avstream->time_base); str->set_duration(avstream->duration); f->add_stream(str); } // As long as we can open the container and retrieve information, this was a successful probe result = true; } // Free all memory avformat_close_input(&fmt_ctx); return result; } void FFmpegDecoder::FFmpegError(int error_code) { char err[1024]; av_strerror(error_code, err, 1024); Error(QStringLiteral("Error decoding %1 - %2 %3").arg(stream()->footage()->filename(), QString::number(error_code), err)); } void FFmpegDecoder::Error(const QString &s) { qWarning() << s; ClearResources(); } QMutex scaler_lock; void SaveCacheFrame(FFmpegDecoder* decoder, SwsContext* scaler, AVFrame* frame, VideoParams params, QString dst_fn) { QByteArray converted_buffer(PixelFormat::GetBufferSize(params.format(), params.width(), params.height()), Qt::Uninitialized); uint8_t* converted_data = reinterpret_cast(converted_buffer.data()); int converted_linesize = PixelFormat::GetBufferSize(params.format(), params.width(), 1); scaler_lock.lock(); sws_scale(scaler, frame->data, frame->linesize, 0, frame->height, &converted_data, &converted_linesize); scaler_lock.unlock(); if (!FrameHashCache::SaveCacheFrame(dst_fn, converted_buffer.data(), params, converted_linesize)) { qCritical() <<" Failed to save cache frame" << dst_fn; } av_frame_free(&frame); } bool FFmpegDecoder::ConformAudio(const QAtomicInt *cancelled, const AudioParams &p) { // Iterate through each audio frame and extract the PCM data AudioStreamPtr audio_stream = std::static_pointer_cast(stream()); // Check if we already have a conform of this type QString conformed_fn = GetConformedFilename(p); if (QFileInfo::exists(conformed_fn)) { // If we have one, and we can open it correctly, we can use it as-is WaveInput input(conformed_fn); if (input.open()) { audio_stream->append_conformed_version(p); input.close(); return true; } } // Conform doesn't exist, we'll have to produce one FFmpegDecoderInstance index_instance(stream()->footage()->filename().toUtf8(), stream()->index()); // Handle NULL channel layout uint64_t channel_layout = ValidateChannelLayout(index_instance.stream()); if (!channel_layout) { qCritical() << "Failed to determine channel layout of audio file, could not conform"; return false; } // Create resampling context SwrContext* resampler = swr_alloc_set_opts(nullptr, p.channel_layout(), FFmpegCommon::GetFFmpegSampleFormat(p.format()), p.sample_rate(), channel_layout, static_cast(index_instance.stream()->codecpar->format), index_instance.stream()->codecpar->sample_rate, 0, nullptr); swr_init(resampler); WaveOutput wave_out(conformed_fn, p); AVPacket* pkt = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); int ret; bool success = false; if (wave_out.open()) { while (true) { // Check if we have a `cancelled` ptr and its value if (cancelled && *cancelled) { break; } ret = index_instance.GetFrame(pkt, frame); if (ret < 0) { if (ret == AVERROR_EOF) { success = true; } else { char err_str[50]; av_strerror(ret, err_str, 50); qWarning() << "Failed to conform:" << ret << err_str; } break; } // Allocate buffers int nb_samples = swr_get_out_samples(resampler, frame->nb_samples); char* data = new char[p.samples_to_bytes(nb_samples)]; // Resample audio to our destination parameters nb_samples = swr_convert(resampler, reinterpret_cast(&data), nb_samples, const_cast(frame->data), frame->nb_samples); if (nb_samples < 0) { char err_str[50]; av_strerror(nb_samples, err_str, 50); qWarning() << "libswresample failed with error:" << nb_samples << err_str; break; } // Write packed WAV data to the disk cache wave_out.write(data, p.samples_to_bytes(nb_samples)); // If we allocated an output for the resampler, delete it here if (data != reinterpret_cast(frame->data[0])) { delete [] data; } SignalProcessingProgress(frame->pts); } wave_out.close(); if (success) { // If our conform succeeded, add it audio_stream->append_conformed_version(p); } else { // Audio index didn't complete, delete it QFile(conformed_fn).remove(); } } else { qWarning() << "Failed to open WAVE output for indexing"; } swr_free(&resampler); av_frame_free(&frame); av_packet_free(&pkt); return success; } QString FFmpegDecoder::GetIndexFilename() const { return FileFunctions::GetMediaIndexFilename(FileFunctions::GetUniqueFileIdentifier(stream()->footage()->filename())) .append(QString::number(stream()->index())); } QString FFmpegDecoder::GetProxyFilename(int divider) const { return GetIndexFilename().append('d').append(QString::number(divider)); } int FFmpegDecoder::GetScaledDimension(int dim, int divider) { return dim / divider; } PixelFormat::Format FFmpegDecoder::GetNativePixelFormat(AVPixelFormat pix_fmt) { switch (pix_fmt) { case AV_PIX_FMT_RGB24: return PixelFormat::PIX_FMT_RGB8; case AV_PIX_FMT_RGBA: return PixelFormat::PIX_FMT_RGBA8; case AV_PIX_FMT_RGB48: return PixelFormat::PIX_FMT_RGB16U; case AV_PIX_FMT_RGBA64: return PixelFormat::PIX_FMT_RGBA16U; default: return PixelFormat::PIX_FMT_INVALID; } } uint64_t FFmpegDecoder::ValidateChannelLayout(AVStream* stream) { if (stream->codecpar->channel_layout) { return stream->codecpar->channel_layout; } return av_get_default_channel_layout(stream->codecpar->channels); } FramePtr FFmpegDecoder::BuffersToNativeFrame(int divider, int width, int height, int64_t ts, uint8_t** input_data, int* input_linesize) { if (divider != scale_divider_) { FreeScaler(); InitScaler(divider); } // Create frame to return FramePtr copy = Frame::Create(); copy->set_video_params(VideoParams(width, height, native_pix_fmt_, divider)); copy->set_timestamp(Timecode::timestamp_to_time(ts, time_base_)); copy->set_sample_aspect_ratio(aspect_ratio_); copy->allocate(); // Convert frame to RGB/A for the rest of the pipeline uint8_t* output_data = reinterpret_cast(copy->data()); int output_linesize = copy->linesize_bytes(); sws_scale(scale_ctx_, input_data, input_linesize, 0, height, &output_data, &output_linesize); return copy; } int FFmpegDecoderInstance::GetFrame(AVPacket *pkt, AVFrame *frame) { bool eof = false; int ret; // Clear any previous frames av_frame_unref(frame); while ((ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN) && !eof) { // Find next packet in the correct stream index do { // Free buffer in packet if there is one av_packet_unref(pkt); // Read packet from file ret = av_read_frame(fmt_ctx_, pkt); } while (pkt->stream_index != avstream_->index && ret >= 0); if (ret == AVERROR_EOF) { // Don't break so that receive gets called again, but don't try to read again eof = true; // Send a null packet to signal end of avcodec_send_packet(codec_ctx_, nullptr); } else if (ret < 0) { // Handle other error by breaking loop and returning the code we received break; } else { // Successful read, send the packet ret = avcodec_send_packet(codec_ctx_, pkt); // We don't need the packet anymore, so free it av_packet_unref(pkt); if (ret < 0) { break; } } } return ret; } QMutex *FFmpegDecoderInstance::cache_lock() { return &cache_lock_; } QWaitCondition *FFmpegDecoderInstance::cache_wait_cond() { return &cache_wait_cond_; } bool FFmpegDecoderInstance::IsWorking() const { return is_working_; } void FFmpegDecoderInstance::SetWorking(bool working) { is_working_ = working; } void FFmpegDecoderInstance::Seek(int64_t timestamp) { avcodec_flush_buffers(codec_ctx_); av_seek_frame(fmt_ctx_, avstream_->index, timestamp, AVSEEK_FLAG_BACKWARD); } /* OLD UNUSED CODE: Keeping this around in case the code proves useful void FFmpegDecoder::CacheFrameToDisk(AVFrame *f) { QFile save_frame(GetIndexFilename().append(QString::number(f->pts))); if (save_frame.open(QFile::WriteOnly)) { // Save frame to media index int cached_buffer_sz = av_image_get_buffer_size(static_cast(f->format), f->width, f->height, 1); QByteArray cached_frame(cached_buffer_sz, Qt::Uninitialized); av_image_copy_to_buffer(reinterpret_cast(cached_frame.data()), cached_frame.size(), f->data, f->linesize, static_cast(f->format), f->width, f->height, 1); save_frame.write(qCompress(cached_frame, 1)); save_frame.close(); DiskManager::instance()->CreatedFile(save_frame.fileName(), QByteArray()); } // See if we stored this frame in the disk cache QByteArray frame_loader; if (!got_frame) { QFile compressed_frame(GetIndexFilename().append(QString::number(target_ts))); if (compressed_frame.exists() && compressed_frame.size() > 0 && compressed_frame.open(QFile::ReadOnly)) { DiskManager::instance()->Accessed(compressed_frame.fileName()); // Read data frame_loader = qUncompress(compressed_frame.readAll()); av_image_fill_arrays(input_data, input_linesize, reinterpret_cast(frame_loader.data()), static_cast(avstream_->codecpar->format), avstream_->codecpar->width, avstream_->codecpar->height, 1); got_frame = true; } } } */ void FFmpegDecoderInstance::ClearFrameCache() { cached_frames_.clear(); cache_at_eof_ = false; cache_at_zero_ = false; } FFmpegFramePool::ElementPtr FFmpegDecoderInstance::RetrieveFrame(const int64_t& target_ts, bool cache_is_locked) { if (!cache_is_locked) { cache_lock_.lock(); } int64_t seek_ts = target_ts; bool still_seeking = false; // CacheCouldContainTime uses cache_target_time_, so we'll temporarily set it to the last frame's TS if (!cached_frames_.isEmpty()) { cache_target_time_ = cached_frames_.last()->timestamp(); } // If the frame wasn't in the frame cache, see if this frame cache is too old to use if (!CacheCouldContainTime(target_ts)) { ClearFrameCache(); Seek(seek_ts); if (seek_ts == 0) { cache_at_zero_ = true; } still_seeking = true; } cache_target_time_ = target_ts; int ret; AVPacket* pkt = av_packet_alloc(); FFmpegFramePool::ElementPtr return_frame = nullptr; // Allocate a new frame AVFrameWrapper working_frame; bool unlocked = false; while (true) { // Pull from the decoder ret = GetFrame(pkt, working_frame.frame()); // Handle any errors that aren't EOF (EOF is handled later on) if (ret < 0 && ret != AVERROR_EOF) { cache_lock_.unlock(); qCritical() << "Failed to retrieve frame:" << ret; break; } if (still_seeking) { // Handle a failure to seek (occurs on some media) // We'll only be here if the frame cache was emptied earlier if (!cache_at_zero_ && (ret == AVERROR_EOF || working_frame.frame()->pts > target_ts)) { seek_ts = qMax(static_cast(0), seek_ts - second_ts_); Seek(seek_ts); if (seek_ts == 0) { cache_at_zero_ = true; } continue; } else { still_seeking = false; } } if (cache_is_locked) { cache_is_locked = false; } else if (unlocked) { cache_lock_.lock(); } if (ret == AVERROR_EOF) { // Handle an "expected" EOF by using the last frame of our cache cache_at_eof_ = true; return_frame = cached_frames_.last(); cache_wait_cond_.wakeAll(); cache_lock_.unlock(); break; } else { // Whatever it is, keep this frame in memory for the time being just in case if (!frame_pool_) { qCritical() << "Cannot retrieve video without a valid frame pool"; cache_lock_.unlock(); break; } FFmpegFramePool::ElementPtr cached = frame_pool_->Get(working_frame.frame()); if (!cached) { qCritical() << "Frame pool failed to return a valid frame - out of memory?"; cache_lock_.unlock(); break; } // Set timestamp so this frame can be identified later cached->set_timestamp(working_frame.frame()->pts); // Store frame before just in case FFmpegFramePool::ElementPtr previous; if (cached_frames_.isEmpty()) { previous = nullptr; } else { previous = cached_frames_.last(); } // Clear early frames // FIXME: Hardcoded value (only stores a maximum of 2 seconds in the cache at any time) TruncateCacheRangeTo(2*second_ts_); // Append this frame and signal to other threads that a new frame has arrived cached_frames_.append(cached); cache_wait_cond_.wakeAll(); cache_lock_.unlock(); unlocked = true; // If this is a valid frame, see if this or the frame before it are the one we need if (cached->timestamp() == target_ts) { return_frame = cached; break; } else if (cached->timestamp() > target_ts) { if (!previous && cache_at_zero_) { return_frame = cached; break; } else { return_frame = previous; break; } } } } av_packet_free(&pkt); return return_frame; } void FFmpegDecoder::ClearResources() { FreeScaler(); open_ = false; } void FFmpegDecoder::InitScaler(int divider) { VideoStream* vs = static_cast(stream().get()); scale_ctx_ = sws_getContext(vs->width(), vs->height(), src_pix_fmt_, GetScaledDimension(vs->width(), divider), GetScaledDimension(vs->height(), divider), ideal_pix_fmt_, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); if (scale_ctx_) { scale_divider_ = divider; } else { scale_divider_ = 0; } } void FFmpegDecoder::FreeScaler() { if (scale_ctx_) { sws_freeContext(scale_ctx_); scale_ctx_ = nullptr; scale_divider_ = 0; } } QString FFmpegDecoder::GetProxyFrameFilename(const int64_t ×tamp, const int& divider) const { QString dst_fn = GetProxyFilename(divider); dst_fn.append(QString::number(timestamp)); dst_fn.append(FrameHashCache::GetFormatExtension()); return dst_fn; } int64_t FFmpegDecoderInstance::RangeStart() const { if (cached_frames_.isEmpty()) { return AV_NOPTS_VALUE; } return cached_frames_.first()->timestamp(); } int64_t FFmpegDecoderInstance::RangeEnd() const { if (cached_frames_.isEmpty()) { return AV_NOPTS_VALUE; } return cached_frames_.last()->timestamp(); } bool FFmpegDecoderInstance::CacheContainsTime(const int64_t &t) const { return !cached_frames_.isEmpty() && ((RangeStart() <= t && RangeEnd() >= t) || (cache_at_zero_ && t < cached_frames_.first()->timestamp()) || (cache_at_eof_ && t > cached_frames_.last()->timestamp())); } bool FFmpegDecoderInstance::CacheWillContainTime(const int64_t &t) const { return !cached_frames_.isEmpty() && t >= cached_frames_.first()->timestamp() && t <= cache_target_time_; } bool FFmpegDecoderInstance::CacheCouldContainTime(const int64_t &t) const { return !cached_frames_.isEmpty() && t >= cached_frames_.first()->timestamp() && t <= (cache_target_time_ + 2*second_ts_); } bool FFmpegDecoderInstance::CacheIsEmpty() const { return cached_frames_.isEmpty(); } FFmpegFramePool::ElementPtr FFmpegDecoderInstance::GetFrameFromCache(const int64_t &t) const { if (t < cached_frames_.first()->timestamp()) { if (cache_at_zero_) { cached_frames_.first()->access(); return cached_frames_.first(); } } else if (t > cached_frames_.last()->timestamp()) { if (cache_at_eof_) { cached_frames_.last()->access(); return cached_frames_.last(); } } else { // We already have this frame in the cache, find it for (int i=0;itimestamp() == t // Test for an exact match || (i < cached_frames_.size() - 1 && cached_frames_.at(i+1)->timestamp() > t)) { // Or for this frame to be the "closest" this_frame->access(); return this_frame; } } } return nullptr; } void FFmpegDecoderInstance::RemoveFramesBefore(const qint64 &t) { // We keep one frame in memory as an identifier for what pts the decoder is up to while (cached_frames_.size() > 1 && cached_frames_.first()->last_accessed() < t) { cached_frames_.removeFirst(); cache_at_zero_ = false; } } void FFmpegDecoderInstance::TruncateCacheRangeTo(const qint64 &t) { // We keep one frame in memory as an identifier for what pts the decoder is up to while (cached_frames_.size() > 1 && (RangeEnd() - RangeStart()) > t) { cached_frames_.removeFirst(); cache_at_zero_ = false; } } rational FFmpegDecoderInstance::sample_aspect_ratio() const { return av_guess_sample_aspect_ratio(fmt_ctx_, avstream_, nullptr); } AVStream *FFmpegDecoderInstance::stream() const { return avstream_; } FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_index) : fmt_ctx_(nullptr), opts_(nullptr), frame_pool_(nullptr), is_working_(false), cache_at_zero_(false), cache_at_eof_(false), clear_timer_(nullptr) { // Open file in a format context int error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr); // Handle format context error if (error_code != 0) { qCritical() << "Failed to open input:" << filename << error_code; ClearResources(); return; } // Get stream information from format error_code = avformat_find_stream_info(fmt_ctx_, nullptr); // Handle get stream information error if (error_code < 0) { qCritical() << "Failed to find stream info:" << error_code; ClearResources(); return; } // Get reference to correct AVStream avstream_ = fmt_ctx_->streams[stream_index]; // Find decoder AVCodec* codec = avcodec_find_decoder(avstream_->codecpar->codec_id); // Handle failure to find decoder if (codec == nullptr) { qCritical() << "Failed to find appropriate decoder for this codec:" << filename << stream_index << avstream_->codecpar->codec_id; ClearResources(); return; } // Allocate context for the decoder codec_ctx_ = avcodec_alloc_context3(codec); if (codec_ctx_ == nullptr) { qCritical() << "Failed to allocate codec context"; ClearResources(); return; } // Copy parameters from the AVStream to the AVCodecContext error_code = avcodec_parameters_to_context(codec_ctx_, avstream_->codecpar); // Handle failure to copy parameters if (error_code < 0) { qCritical() << "Failed to copy parameters from AVStream to AVCodecContext"; ClearResources(); return; } // Set multithreading setting error_code = av_dict_set(&opts_, "threads", "auto", 0); // Handle failure to set multithreaded decoding if (error_code < 0) { qCritical() << "Failed to set codec options, performance may suffer"; } // Open codec error_code = avcodec_open2(codec_ctx_, codec, &opts_); if (error_code < 0) { char buf[50]; av_strerror(error_code, buf, 50); qCritical() << "Failed to open codec" << codec->id << error_code << buf; ClearResources(); return; } // Create frame pool if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // Start clear timer clear_timer_ = new QTimer(); clear_timer_->setInterval(kMaxFrameLife); //clear_timer_->moveToThread(qApp->thread()); connect(clear_timer_, &QTimer::timeout, this, &FFmpegDecoderInstance::ClearTimerEvent); QMetaObject::invokeMethod(clear_timer_, "start", Qt::QueuedConnection); } // Store one second in the source's timebase second_ts_ = qRound64(av_q2d(av_inv_q(avstream_->time_base))); } FFmpegDecoderInstance::~FFmpegDecoderInstance() { ClearResources(); } bool FFmpegDecoderInstance::IsValid() const { return codec_ctx_; } void FFmpegDecoderInstance::SetFramePool(FFmpegFramePool *frame_pool) { frame_pool_ = frame_pool; } void FFmpegDecoderInstance::ClearResources() { ClearFrameCache(); // Stop timer if (clear_timer_) { if (clear_timer_->thread() == QThread::currentThread()) { clear_timer_->stop(); } else { QMetaObject::invokeMethod(clear_timer_, "stop", Qt::BlockingQueuedConnection); } QMetaObject::invokeMethod(clear_timer_, "deleteLater", Qt::QueuedConnection); clear_timer_ = nullptr; } if (opts_) { av_dict_free(&opts_); opts_ = nullptr; } if (codec_ctx_) { avcodec_free_context(&codec_ctx_); codec_ctx_ = nullptr; } if (fmt_ctx_) { avformat_close_input(&fmt_ctx_); fmt_ctx_ = nullptr; } } void FFmpegDecoderInstance::ClearTimerEvent() { cache_lock()->lock(); RemoveFramesBefore(QDateTime::currentMSecsSinceEpoch() - kMaxFrameLife); cache_lock()->unlock(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/ffmpeg/ffmpegdecoder.h000066400000000000000000000125061370472574300224640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FFMPEGDECODER_H #define FFMPEGDECODER_H extern "C" { #include #include #include } #include #include #include #include #include "audio/sampleformat.h" #include "avframeptr.h" #include "codec/decoder.h" #include "codec/waveoutput.h" #include "ffmpegframepool.h" #include "project/item/footage/videostream.h" OLIVE_NAMESPACE_ENTER class FFmpegDecoderInstance : public QObject { Q_OBJECT public: FFmpegDecoderInstance(const char* filename, int stream_index); virtual ~FFmpegDecoderInstance(); DISABLE_COPY_MOVE(FFmpegDecoderInstance) bool IsValid() const; void SetFramePool(FFmpegFramePool* frame_pool); int64_t RangeStart() const; int64_t RangeEnd() const; bool CacheContainsTime(const int64_t& t) const; bool CacheWillContainTime(const int64_t& t) const; bool CacheCouldContainTime(const int64_t& t) const; bool CacheIsEmpty() const; FFmpegFramePool::ElementPtr GetFrameFromCache(const int64_t& t) const; void RemoveFramesBefore(const qint64& t); void TruncateCacheRangeTo(const qint64& t); rational sample_aspect_ratio() const; AVStream* stream() const; void ClearFrameCache(); FFmpegFramePool::ElementPtr RetrieveFrame(const int64_t &target_ts, bool cache_is_locked); /** * @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_) * * @return * * An FFmpeg error code, or >= 0 on success */ int GetFrame(AVPacket* pkt, AVFrame* frame); QMutex* cache_lock(); QWaitCondition* cache_wait_cond(); bool IsWorking() const; void SetWorking(bool working); private: void ClearResources(); void Seek(int64_t timestamp); AVFormatContext* fmt_ctx_; AVCodecContext* codec_ctx_; AVStream* avstream_; AVDictionary* opts_; int64_t second_ts_; QWaitCondition cache_wait_cond_; QMutex cache_lock_; QList cached_frames_; FFmpegFramePool* frame_pool_; int64_t cache_target_time_; bool is_working_; bool cache_at_zero_; bool cache_at_eof_; QTimer* clear_timer_; static const int kMaxFrameLife; private slots: void ClearTimerEvent(); }; /** * @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder */ class FFmpegDecoder : public Decoder { Q_OBJECT public: // Constructor FFmpegDecoder(); // Destructor virtual ~FFmpegDecoder() override; virtual bool Probe(Footage *f, const QAtomicInt *cancelled) override; virtual bool Open() override; virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override; virtual SampleBufferPtr RetrieveAudio(const rational &timecode, const rational &length, const AudioParams& params) override; virtual void Close() override; virtual QString id() override; virtual bool SupportsVideo() override; virtual bool SupportsAudio() override; virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioParams& p) override; private: /** * @brief Handle an error * * Immediately closes the Decoder (freeing memory resources) and sends the string provided to the warning stream. * As this function closes the Decoder, no further Decoder functions should be performed after this is called * (unless the Decoder is opened again first). */ void Error(const QString& s); /** * @brief Handle an FFmpeg error code * * Uses the FFmpeg API to retrieve a descriptive string for this error code and sends it to Error(). As such, this * function also automatically closes the Decoder. * * @param error_code */ void FFmpegError(int error_code); virtual QString GetIndexFilename() const override; QString GetProxyFilename(int divider) const; void ClearResources(); void InitScaler(int divider); void FreeScaler(); QString GetProxyFrameFilename(const int64_t& timestamp, const int ÷r) const; static int GetScaledDimension(int dim, int divider); static PixelFormat::Format GetNativePixelFormat(AVPixelFormat pix_fmt); static uint64_t ValidateChannelLayout(AVStream *stream); FramePtr BuffersToNativeFrame(int divider, int width, int height, int64_t ts, uint8_t **input_data, int* input_linesize); SwsContext* scale_ctx_; int scale_divider_; AVPixelFormat src_pix_fmt_; AVPixelFormat ideal_pix_fmt_; PixelFormat::Format native_pix_fmt_; rational time_base_; rational aspect_ratio_; int64_t start_time_; static QHash< Stream*, QList > instance_map_; static QHash< Stream*, FFmpegFramePool* > frame_pool_map_; static QMutex instance_map_lock_; }; OLIVE_NAMESPACE_EXIT #endif // FFMPEGDECODER_H olive-continuous/app/codec/ffmpeg/ffmpegencoder.cpp000066400000000000000000000417101370472574300230300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "ffmpegencoder.h" #include #include "ffmpegcommon.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER FFmpegEncoder::FFmpegEncoder(const EncodingParams ¶ms) : Encoder(params), fmt_ctx_(nullptr), video_stream_(nullptr), video_codec_ctx_(nullptr), video_scale_ctx_(nullptr), audio_stream_(nullptr), audio_codec_ctx_(nullptr), audio_resample_ctx_(nullptr), open_(false) { } bool FFmpegEncoder::Open() { if (open_) { return true; } int error_code; // Convert QString to C string that FFmpeg expects QByteArray filename_bytes = params().filename().toUtf8(); const char* filename_c_str = filename_bytes.constData(); // Create output format context error_code = avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, filename_c_str); // Check error code if (error_code < 0) { FFmpegError("Failed to allocate output context", error_code); return false; } // Initialize a video stream if it's enabled if (params().video_enabled()) { if (!InitializeStream(AVMEDIA_TYPE_VIDEO, &video_stream_, &video_codec_ctx_, params().video_codec())) { return false; } // This is the format we will expect frames received in Write() to be in PixelFormat::Format native_pixel_fmt = params().video_params().format(); // This is the format we will need to convert the frame to for swscale to understand it video_conversion_fmt_ = FFmpegCommon::GetCompatiblePixelFormat(native_pixel_fmt); // This is the equivalent pixel format above as an AVPixelFormat that swscale can understand AVPixelFormat src_pix_fmt = FFmpegCommon::GetFFmpegPixelFormat(video_conversion_fmt_); // This is the pixel format the encoder wants to encode to AVPixelFormat encoder_pix_fmt = video_codec_ctx_->pix_fmt; // Set up a scaling context - if the native pixel format is not equal to the encoder's, we'll need to convert it // before encoding. Even if we don't, this may be useful for converting between linesizes, etc. video_scale_ctx_ = sws_getContext(params().video_params().width(), params().video_params().height(), src_pix_fmt, params().video_params().width(), params().video_params().height(), encoder_pix_fmt, 0, nullptr, nullptr, nullptr); } // Initialize an audio stream if it's enabled if (params().audio_enabled() && !InitializeStream(AVMEDIA_TYPE_AUDIO, &audio_stream_, &audio_codec_ctx_, params().audio_codec())) { return false; } av_dump_format(fmt_ctx_, 0, filename_c_str, 1); // Open output file for writing error_code = avio_open(&fmt_ctx_->pb, filename_c_str, AVIO_FLAG_WRITE); if (error_code < 0) { FFmpegError("Failed to open IO context", error_code); return false; } // Write header error_code = avformat_write_header(fmt_ctx_, nullptr); if (error_code < 0) { FFmpegError("Failed to write format header", error_code); return false; } open_ = true; return true; } bool FFmpegEncoder::WriteFrame(FramePtr frame, rational time) { bool success = false; AVFrame* encoded_frame = av_frame_alloc(); int error_code; const char* input_data; int input_linesize; // Frame must be video encoded_frame->width = frame->width(); encoded_frame->height = frame->height(); encoded_frame->format = video_codec_ctx_->pix_fmt; error_code = av_frame_get_buffer(encoded_frame, 0); if (error_code < 0) { FFmpegError("Failed to create AVFrame buffer", error_code); goto fail; } // We may need to convert this frame to a frame that swscale will understand if (frame->format() != video_conversion_fmt_) { frame = PixelFormat::ConvertPixelFormat(frame, video_conversion_fmt_); } // Use swscale context to convert formats/linesizes input_data = frame->const_data(); input_linesize = frame->linesize_bytes(); error_code = sws_scale(video_scale_ctx_, reinterpret_cast(&input_data), &input_linesize, 0, frame->height(), encoded_frame->data, encoded_frame->linesize); if (error_code < 0) { FFmpegError("Failed to scale frame", error_code); goto fail; } encoded_frame->pts = qRound64(time.toDouble() / av_q2d(video_codec_ctx_->time_base)); success = WriteAVFrame(encoded_frame, video_codec_ctx_, video_stream_); fail: av_frame_free(&encoded_frame); return success; } void FFmpegEncoder::WriteAudio(AudioParams pcm_info, const QString &pcm_filename) { QFile pcm(pcm_filename); if (pcm.open(QFile::ReadOnly)) { // Divide PCM stream into AVFrames // See if the codec defines a number of samples per frame int maximum_frame_samples = audio_codec_ctx_->frame_size; if (!maximum_frame_samples) { // If not, use another frame size if (params().video_enabled()) { // If we're encoding video, use enough samples to cover roughly one frame of video maximum_frame_samples = params().audio_params().time_to_samples(params().video_params().time_base()); } else { // If no video, just use an arbitrary number maximum_frame_samples = 256; } } SwrContext* swr_ctx = swr_alloc_set_opts(nullptr, static_cast(audio_codec_ctx_->channel_layout), audio_codec_ctx_->sample_fmt, audio_codec_ctx_->sample_rate, static_cast(pcm_info.channel_layout()), FFmpegCommon::GetFFmpegSampleFormat(pcm_info.format()), pcm_info.sample_rate(), 0, nullptr); swr_init(swr_ctx); // Loop through PCM queueing write events AVFrame* frame = av_frame_alloc(); // Set up frame and allocate its buffers frame->channel_layout = audio_codec_ctx_->channel_layout; frame->nb_samples = maximum_frame_samples; frame->format = audio_codec_ctx_->sample_fmt; av_frame_get_buffer(frame, 0); // Keep track of sample count to use as each frame's timebase int sample_counter = 0; while (true) { // Calculate how many samples should input this frame int64_t samples_needed = av_rescale_rnd(maximum_frame_samples + swr_get_delay(swr_ctx, pcm_info.sample_rate()), audio_codec_ctx_->sample_rate, pcm_info.sample_rate(), AV_ROUND_UP); // Calculate how many bytes this is int max_read = pcm_info.samples_to_bytes(samples_needed); // Read bytes from PCM QByteArray input_data = pcm.read(max_read); // Use swresample to convert the data into the correct format const char* input_data_array = input_data.constData(); int converted = swr_convert(swr_ctx, // output data frame->data, // output sample count (maximum amount of samples in output) maximum_frame_samples, // input data reinterpret_cast(&input_data_array), // input sample count (maximum amount of samples we read from pcm file) pcm_info.bytes_to_samples(input_data.size())); // Update the frame's number of samples to the amount we actually received frame->nb_samples = converted; // Update frame timestamp frame->pts = sample_counter; // Increment timestamp for the next frame by the amount of samples in this one sample_counter += converted; // Write the frame if (!WriteAVFrame(frame, audio_codec_ctx_, audio_stream_)) { qCritical() << "Failed to write audio AVFrame"; break; } // Break if we've reached the end point if (pcm.atEnd()) { break; } } av_frame_free(&frame); swr_free(&swr_ctx); pcm.close(); } } void FFmpegEncoder::Close() { if (open_) { // Flush encoders FlushEncoders(); // We've written a header, so we'll write a trailer av_write_trailer(fmt_ctx_); avio_closep(&fmt_ctx_->pb); open_ = false; } if (video_scale_ctx_) { sws_freeContext(video_scale_ctx_); video_scale_ctx_ = nullptr; } if (video_codec_ctx_) { avcodec_free_context(&video_codec_ctx_); video_codec_ctx_ = nullptr; } if (audio_codec_ctx_) { avcodec_free_context(&audio_codec_ctx_); audio_codec_ctx_ = nullptr; } if (fmt_ctx_) { // NOTE: This also frees video_stream_ and audio_stream_ avformat_free_context(fmt_ctx_); fmt_ctx_ = nullptr; } } void FFmpegEncoder::FFmpegError(const char* context, int error_code) { char err[128]; av_strerror(error_code, err, 128); Error(QStringLiteral("%1 for %2 - %3 %4").arg(context, params().filename(), QString::number(error_code), err)); } bool FFmpegEncoder::WriteAVFrame(AVFrame *frame, AVCodecContext* codec_ctx, AVStream* stream) { // Send raw frame to the encoder int error_code = avcodec_send_frame(codec_ctx, frame); if (error_code < 0) { FFmpegError("Failed to send frame to encoder", error_code); return false; } bool succeeded = false; AVPacket* pkt = av_packet_alloc(); // Retrieve packets from encoder while (error_code >= 0) { error_code = avcodec_receive_packet(codec_ctx, pkt); // EAGAIN just means the encoder wants another frame before encoding if (error_code == AVERROR(EAGAIN)) { break; } else if (error_code < 0) { FFmpegError("Failed to receive packet from decoder", error_code); goto fail; } // Set packet stream index pkt->stream_index = stream->index; av_packet_rescale_ts(pkt, codec_ctx->time_base, stream->time_base); // Write packet to file av_interleaved_write_frame(fmt_ctx_, pkt); // Unref packet in case we're getting another av_packet_unref(pkt); } succeeded = true; fail: av_packet_free(&pkt); return succeeded; } bool FFmpegEncoder::InitializeStream(AVMediaType type, AVStream** stream_ptr, AVCodecContext** codec_ctx_ptr, const ExportCodec::Codec& codec) { if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) { Error(QStringLiteral("Cannot initialize a stream that is not a video or audio type")); return false; } // Retrieve codec AVCodecID codec_id = AV_CODEC_ID_NONE; switch (codec) { case ExportCodec::kCodecDNxHD: codec_id = AV_CODEC_ID_DNXHD; break; case ExportCodec::kCodecAAC: codec_id = AV_CODEC_ID_AAC; break; case ExportCodec::kCodecMP2: codec_id = AV_CODEC_ID_MP2; break; case ExportCodec::kCodecMP3: codec_id = AV_CODEC_ID_MP3; break; case ExportCodec::kCodecH264: codec_id = AV_CODEC_ID_H264; break; case ExportCodec::kCodecH265: codec_id = AV_CODEC_ID_HEVC; break; case ExportCodec::kCodecOpenEXR: codec_id = AV_CODEC_ID_EXR; break; case ExportCodec::kCodecPNG: codec_id = AV_CODEC_ID_PNG; break; case ExportCodec::kCodecTIFF: codec_id = AV_CODEC_ID_TIFF; break; case ExportCodec::kCodecProRes: codec_id = AV_CODEC_ID_PRORES; break; case ExportCodec::kCodecPCM: codec_id = AV_CODEC_ID_PCM_S16LE; break; case ExportCodec::kCodecCount: break; } if (codec_id == AV_CODEC_ID_NONE) { Error(QStringLiteral("Unknown internal codec")); return false; } // Find encoder with this name AVCodec* encoder = avcodec_find_encoder(codec_id); if (!encoder) { Error(QStringLiteral("Failed to find codec for %1").arg(codec)); return false; } if (encoder->type != type) { Error(QStringLiteral("Retrieved unexpected codec type %1 for codec %2").arg(QString::number(encoder->type), codec)); return false; } if (!InitializeCodecContext(stream_ptr, codec_ctx_ptr, encoder)) { return false; } // Set codec parameters AVCodecContext* codec_ctx = *codec_ctx_ptr; AVStream* stream = *stream_ptr; if (type == AVMEDIA_TYPE_VIDEO) { codec_ctx->width = params().video_params().width(); codec_ctx->height = params().video_params().height(); codec_ctx->sample_aspect_ratio = {1, 1}; codec_ctx->time_base = params().video_params().time_base().toAVRational(); // FIXME: Make this customizable again codec_ctx->pix_fmt = encoder->pix_fmts[0]; // Set custom options { QHash::const_iterator i; for (i=params().video_opts().begin();i!=params().video_opts().end();i++) { av_opt_set(video_codec_ctx_->priv_data, i.key().toUtf8(), i.value().toUtf8(), AV_OPT_SEARCH_CHILDREN); } if (params().video_bit_rate() > 0) { video_codec_ctx_->bit_rate = params().video_bit_rate(); } if (params().video_max_bit_rate() > 0) { video_codec_ctx_->rc_max_rate = params().video_max_bit_rate(); } if (params().video_buffer_size() > 0) { video_codec_ctx_->rc_buffer_size = static_cast(params().video_buffer_size()); } } } else { codec_ctx->sample_rate = params().audio_params().sample_rate(); codec_ctx->channel_layout = params().audio_params().channel_layout(); codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout); codec_ctx->sample_fmt = encoder->sample_fmts[0]; codec_ctx->time_base = {1, codec_ctx->sample_rate}; } if (!SetupCodecContext(stream, codec_ctx, encoder)) { return false; } return true; } bool FFmpegEncoder::InitializeCodecContext(AVStream **stream, AVCodecContext **codec_ctx, AVCodec* codec) { *stream = avformat_new_stream(fmt_ctx_, nullptr); if (!(*stream)) { Error(QStringLiteral("Failed to allocate AVStream")); return false; } // Allocate a codec context *codec_ctx = avcodec_alloc_context3(codec); if (!(*codec_ctx)) { Error(QStringLiteral("Failed to allocate AVCodecContext")); return false; } return true; } bool FFmpegEncoder::SetupCodecContext(AVStream* stream, AVCodecContext* codec_ctx, AVCodec* codec) { int error_code; if (fmt_ctx_->oformat->flags & AVFMT_GLOBALHEADER) { codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } AVDictionary* codec_opts = nullptr; // Set thread count if (params().video_threads() == 0) { av_dict_set(&codec_opts, "threads", "auto", 0); } else { QString thread_val = QString::number(params().video_threads()); av_dict_set(&codec_opts, "threads", thread_val.toUtf8(), 0); } // Try to open encoder error_code = avcodec_open2(codec_ctx, codec, &codec_opts); if (error_code < 0) { FFmpegError("Failed to open encoder", error_code); return false; } // Copy context settings to codecpar object error_code = avcodec_parameters_from_context(stream->codecpar, codec_ctx); if (error_code < 0) { FFmpegError("Failed to copy codec parameters to stream", error_code); return false; } return true; } void FFmpegEncoder::FlushEncoders() { if (video_codec_ctx_) { FlushCodecCtx(video_codec_ctx_, video_stream_); } if (audio_codec_ctx_) { FlushCodecCtx(audio_codec_ctx_, audio_stream_); } } void FFmpegEncoder::FlushCodecCtx(AVCodecContext *codec_ctx, AVStream* stream) { avcodec_send_frame(codec_ctx, nullptr); AVPacket* pkt = av_packet_alloc(); int error_code; do { error_code = avcodec_receive_packet(codec_ctx, pkt); if (error_code < 0) { break; } pkt->stream_index = stream->index; av_packet_rescale_ts(pkt, codec_ctx->time_base, stream->time_base); av_interleaved_write_frame(fmt_ctx_, pkt); av_packet_unref(pkt); } while (error_code >= 0); av_packet_free(&pkt); } void FFmpegEncoder::Error(const QString &s) { qWarning() << s; Close(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/ffmpeg/ffmpegencoder.h000066400000000000000000000054601370472574300224770ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FFMPEGENCODER_H #define FFMPEGENCODER_H extern "C" { #include #include #include #include } #include "codec/encoder.h" OLIVE_NAMESPACE_ENTER class FFmpegEncoder : public Encoder { Q_OBJECT public: FFmpegEncoder(const EncodingParams ¶ms); virtual bool Open() override; virtual bool WriteFrame(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::rational time) override; virtual void WriteAudio(OLIVE_NAMESPACE::AudioParams pcm_info, const QString& pcm_filename) override; virtual void Close() override; private: /** * @brief Handle an error * * Immediately closes the Decoder (freeing memory resources) and sends the string provided to the warning stream. * As this function closes the Decoder, no further Decoder functions should be performed after this is called * (unless the Decoder is opened again first). */ void Error(const QString& s); /** * @brief Handle an FFmpeg error code * * Uses the FFmpeg API to retrieve a descriptive string for this error code and sends it to Error(). As such, this * function also automatically closes the Decoder. * * @param error_code */ void FFmpegError(const char *context, int error_code); bool WriteAVFrame(AVFrame* frame, AVCodecContext *codec_ctx, AVStream *stream); bool InitializeStream(enum AVMediaType type, AVStream** stream, AVCodecContext** codec_ctx, const ExportCodec::Codec &codec); bool InitializeCodecContext(AVStream** stream, AVCodecContext** codec_ctx, AVCodec* codec); bool SetupCodecContext(AVStream *stream, AVCodecContext *codec_ctx, AVCodec *codec); void FlushEncoders(); void FlushCodecCtx(AVCodecContext* codec_ctx, AVStream *stream); AVFormatContext* fmt_ctx_; AVStream* video_stream_; AVCodecContext* video_codec_ctx_; SwsContext* video_scale_ctx_; PixelFormat::Format video_conversion_fmt_; AVStream* audio_stream_; AVCodecContext* audio_codec_ctx_; SwrContext* audio_resample_ctx_; bool open_; }; OLIVE_NAMESPACE_EXIT #endif // FFMPEGENCODER_H olive-continuous/app/codec/ffmpeg/ffmpegframepool.cpp000066400000000000000000000034741370472574300234020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "ffmpegframepool.h" extern "C" { #include } OLIVE_NAMESPACE_ENTER FFmpegFramePool::FFmpegFramePool(int element_count, int width, int height, AVPixelFormat format) : MemoryPool(element_count), width_(width), height_(height), format_(format) { } FFmpegFramePool::ElementPtr FFmpegFramePool::Get(AVFrame *copy) { ElementPtr ele = MemoryPool::Get(); if (ele) { av_image_copy_to_buffer(ele->data(), GetElementSize(), copy->data, copy->linesize, format_, width_, height_, 1); } return ele; } size_t FFmpegFramePool::GetElementSize() { int buf_sz = av_image_get_buffer_size(static_cast(format_), width_, height_, 1); if (buf_sz < 0) { qDebug() << "Failed to find buffer size:" << buf_sz; return 0; } return buf_sz; } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/ffmpeg/ffmpegframepool.h000066400000000000000000000024151370472574300230410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FFMPEGFRAMEPOOL_H #define FFMPEGFRAMEPOOL_H #include "common/memorypool.h" #include "render/pixelformat.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER class FFmpegFramePool : public MemoryPool { public: FFmpegFramePool(int element_count, int width, int height, AVPixelFormat format); ElementPtr Get(AVFrame* copy); protected: virtual size_t GetElementSize() override; private: int width_; int height_; AVPixelFormat format_; }; OLIVE_NAMESPACE_EXIT #endif // FFMPEGFRAMEPOOL_H olive-continuous/app/codec/frame.cpp000066400000000000000000000066011370472574300200520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "frame.h" #include #include #include OLIVE_NAMESPACE_ENTER Frame::Frame() : timestamp_(0), sample_aspect_ratio_(1) { } FramePtr Frame::Create() { return std::make_shared(); } const VideoParams &Frame::video_params() const { return params_; } void Frame::set_video_params(const VideoParams ¶ms) { params_ = params; // Align linesize to 16 linesize_ = qCeil(static_cast(width()) / 16.0) * 16; } int Frame::linesize_pixels() const { return linesize_; } int Frame::linesize_bytes() const { return linesize_pixels() * PixelFormat::BytesPerPixel(params_.format()); } const int &Frame::width() const { return params_.effective_width(); } const int &Frame::height() const { return params_.effective_height(); } const PixelFormat::Format &Frame::format() const { return params_.format(); } Color Frame::get_pixel(int x, int y) const { if (!contains_pixel(x, y)) { return Color(); } int pixel_index = y * linesize_pixels() + x; int byte_offset = PixelFormat::GetBufferSize(video_params().format(), pixel_index, 1); return Color(data_.data() + byte_offset, video_params().format()); } bool Frame::contains_pixel(int x, int y) const { return (is_allocated() && x >= 0 && x < width() && y >= 0 && y < height()); } void Frame::set_pixel(int x, int y, const Color &c) { if (!contains_pixel(x, y)) { return; } int pixel_index = y * linesize_pixels() + x; int byte_offset = PixelFormat::GetBufferSize(video_params().format(), pixel_index, 1); c.toData(data_.data() + byte_offset, video_params().format()); } const rational &Frame::sample_aspect_ratio() const { return sample_aspect_ratio_; } void Frame::set_sample_aspect_ratio(const rational &aspect_ratio) { sample_aspect_ratio_ = aspect_ratio; } const rational &Frame::timestamp() const { return timestamp_; } void Frame::set_timestamp(const rational ×tamp) { timestamp_ = timestamp; } const int64_t &Frame::native_timestamp() { return native_timestamp_; } void Frame::set_native_timestamp(const int64_t ×tamp) { native_timestamp_ = timestamp; } char *Frame::data() { return data_.data(); } const char *Frame::const_data() const { return data_.constData(); } void Frame::allocate() { // Assume this frame is intended to be a video frame if (!params_.is_valid()) { qWarning() << "Tried to allocate a frame with invalid parameters"; return; } data_.resize(PixelFormat::GetBufferSize(params_.format(), linesize_, params_.height())); } bool Frame::is_allocated() const { return !data_.isEmpty(); } void Frame::destroy() { data_.clear(); } int Frame::allocated_size() const { return data_.size(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/frame.h000066400000000000000000000057221370472574300175220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FRAME_H #define FRAME_H #include #include #include "common/rational.h" #include "render/color.h" #include "render/pixelformat.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER class Frame; using FramePtr = std::shared_ptr; /** * @brief Video frame data or audio sample data from a Decoder */ class Frame { public: Frame(); static FramePtr Create(); const VideoParams& video_params() const; void set_video_params(const VideoParams& params); int linesize_pixels() const; int linesize_bytes() const; const int& width() const; const int& height() const; const PixelFormat::Format& format() const; Color get_pixel(int x, int y) const; bool contains_pixel(int x, int y) const; void set_pixel(int x, int y, const Color& c); const rational& sample_aspect_ratio() const; void set_sample_aspect_ratio(const rational& sample_aspect_ratio); /** * @brief Get frame's timestamp. * * This timestamp is always a rational that will equate to the time in seconds. */ const rational& timestamp() const; void set_timestamp(const rational& timestamp); const int64_t& native_timestamp(); void set_native_timestamp(const int64_t& timestamp); /** * @brief Get the data buffer of this frame */ char* data(); /** * @brief Get the const data buffer of this frame */ const char* const_data() const; /** * @brief Allocate memory buffer to store data based on parameters * * For video frames, the width(), height(), and format() must be set for this function to work. * * If a memory buffer has been previously allocated without destroying, this function will destroy it. */ void allocate(); /** * @brief Return whether the frame is allocated or not */ bool is_allocated() const; /** * @brief Destroy a memory buffer allocated with allocate() */ void destroy(); /** * @brief Returns the size of the array returned in data() in bytes * * Returns 0 if nothing is allocated. */ int allocated_size() const; private: VideoParams params_; QByteArray data_; rational timestamp_; int64_t native_timestamp_; rational sample_aspect_ratio_; int linesize_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::FramePtr) #endif // FRAME_H olive-continuous/app/codec/oiio/000077500000000000000000000000001370472574300172105ustar00rootroot00000000000000olive-continuous/app/codec/oiio/CMakeLists.txt000066400000000000000000000014551370472574300217550ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} codec/oiio/oiiodecoder.h codec/oiio/oiiodecoder.cpp PARENT_SCOPE ) olive-continuous/app/codec/oiio/oiiodecoder.cpp000066400000000000000000000273551370472574300222150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "oiiodecoder.h" #include #include #include #include #include #include "common/define.h" #include "config/config.h" #include "core.h" OLIVE_NAMESPACE_ENTER QStringList OIIODecoder::supported_formats_; OIIODecoder::OIIODecoder() : image_(nullptr), buffer_(nullptr) { } QString OIIODecoder::id() { return QStringLiteral("oiio"); } bool OIIODecoder::Probe(Footage *f, const QAtomicInt *cancelled) { if (!FileTypeIsSupported(f->filename())) { return false; } std::string std_filename = f->filename().toStdString(); auto in = OIIO::ImageInput::open(std_filename); if (!in) { return false; } if (!strcmp(in->format_name(), "FFmpeg movie")) { // If this is FFmpeg via OIIO, fall-through to our native FFmpeg decoder return false; } is_sequence_ = false; // Heuristically determine whether this file is part of an image sequence or not if (GetImageSequenceDigitCount(f->filename()) > 0) { int64_t ind = GetImageSequenceIndex(f->filename()); // Check if files around exist around it with that follow a sequence if (QFileInfo::exists(TransformImageSequenceFileName(f->filename(), ind - 1)) || QFileInfo::exists(TransformImageSequenceFileName(f->filename(), ind + 1))) { // We need user feedback here and since UI must occur in the UI thread (and we could be in any thread), we defer // to the Core which will definitely be in the UI thread and block here until we get an answer from the user QMetaObject::invokeMethod(Core::instance(), "ConfirmImageSequence", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, is_sequence_), Q_ARG(QString, f->filename())); } } ImageStreamPtr image_stream; if (is_sequence_) { VideoStreamPtr video_stream = std::make_shared(); image_stream = video_stream; rational default_timebase = Config::Current()["DefaultSequenceFrameRate"].value(); video_stream->set_timebase(default_timebase); video_stream->set_frame_rate(default_timebase.flipped()); video_stream->set_image_sequence(true); int64_t seq_index = GetImageSequenceIndex(f->filename()); int64_t start_index = seq_index; int64_t end_index = seq_index; // Heuristic to find the first and last images (users can always override this later in FootagePropertiesDialog) while (QFileInfo::exists(TransformImageSequenceFileName(f->filename(), start_index-1))) { start_index--; } while (QFileInfo::exists(TransformImageSequenceFileName(f->filename(), end_index+1))) { end_index++; } video_stream->set_start_time(start_index); video_stream->set_duration(end_index - start_index + 1); } else { image_stream = std::make_shared(); } image_stream->set_width(in->spec().width); image_stream->set_height(in->spec().height); image_stream->set_format(GetFormatFromOIIOBasetype(in->spec())); // Images will always have just one stream image_stream->set_index(0); // OIIO automatically premultiplies alpha // FIXME: We usually disassociate the alpha for the color management later, for 8-bit images this likely reduces the // fidelity? image_stream->set_premultiplied_alpha(true); // Get stats for this image and dump them into the Footage file f->add_stream(image_stream); // If we're here, we have a successful image open in->close(); #if OIIO_VERSION < 10903 OIIO::ImageInput::destroy(in); #endif return true; } bool OIIODecoder::Open() { QMutexLocker locker(&mutex_); Q_ASSERT(stream()); if (stream()->type() != Stream::kVideo && !OpenImageHandler(stream()->footage()->filename())) { return false; } open_ = true; return true; } FramePtr OIIODecoder::RetrieveVideo(const rational &timecode, const int& divider) { QMutexLocker locker(&mutex_); if (!open_) { return nullptr; } if (stream()->type() == Stream::kVideo) { int64_t ts = Timecode::time_to_timestamp(timecode, stream()->timebase()); ts += static_cast(stream().get())->start_time(); if (!OpenImageHandler(TransformImageSequenceFileName(stream()->footage()->filename(), ts))) { return nullptr; } } FramePtr frame = Frame::Create(); frame->set_video_params(VideoParams(buffer_->spec().width, buffer_->spec().height, pix_fmt_, divider)); frame->allocate(); if (divider == 1) { BufferToFrame(buffer_, frame); } else { // Will need to resize the image OIIO::ImageBuf dst(OIIO::ImageSpec(frame->width(), frame->height(), buffer_->spec().nchannels, buffer_->spec().format)); if (!OIIO::ImageBufAlgo::resample(dst, *buffer_)) { qWarning() << "OIIO resize failed"; } BufferToFrame(&dst, frame); } if (stream()->type() == Stream::kVideo) { CloseImageHandle(); } return frame; } void OIIODecoder::Close() { QMutexLocker locker(&mutex_); CloseImageHandle(); } bool OIIODecoder::SupportsVideo() { return true; } QString OIIODecoder::GetIndexFilename() const { return QString(); } void OIIODecoder::FrameToBuffer(FramePtr frame, OIIO::ImageBuf *buf) { #if OIIO_VERSION < 20112 // // Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12 // // See more: https://github.com/OpenImageIO/oiio/pull/2487 // int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format()); for (int i=0;ispec().height;i++) { memcpy( #if OIIO_VERSION < 10903 reinterpret_cast(buf->localpixels()) + i * width_in_bytes, #else reinterpret_cast(buf->localpixels()) + i * buf->scanline_stride(), #endif frame->data() + i * frame->linesize_bytes(), width_in_bytes); } #else buf->set_pixels(OIIO::ROI(), buf->spec().format, frame->data(), OIIO::AutoStride, frame->linesize_bytes()); #endif } void OIIODecoder::BufferToFrame(OIIO::ImageBuf *buf, FramePtr frame) { #if OIIO_VERSION < 20112 // // Workaround for OIIO bug that ignores destination stride in versions OLDER than 2.1.12 // // See more: https://github.com/OpenImageIO/oiio/pull/2487 // int width_in_bytes = frame->width() * PixelFormat::BytesPerPixel(frame->format()); for (int i=0;ispec().height;i++) { memcpy(frame->data() + i * frame->linesize_bytes(), #if OIIO_VERSION < 10903 reinterpret_cast(buf->localpixels()) + i * width_in_bytes, #else reinterpret_cast(buf->localpixels()) + i * buf->scanline_stride(), #endif width_in_bytes); } #else buf->get_pixels(OIIO::ROI(), buf->spec().format, frame->data(), OIIO::AutoStride, frame->linesize_bytes()); #endif } PixelFormat::Format OIIODecoder::GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec) { bool has_alpha = (spec.nchannels == kRGBAChannels); if (spec.format == OIIO::TypeDesc::UINT8) { return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8; } else if (spec.format == OIIO::TypeDesc::UINT16) { return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U; } else if (spec.format == OIIO::TypeDesc::HALF) { return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F; } else if (spec.format == OIIO::TypeDesc::FLOAT) { return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F; } else { return PixelFormat::PIX_FMT_INVALID; } } bool OIIODecoder::FileTypeIsSupported(const QString& fn) { // We prioritize OIIO over FFmpeg to pick up still images more effectively, but some OIIO decoders (notably OpenJPEG) // will segfault entirely if given unexpected data (an MPEG-4 for instance). To workaround this issue, we use OIIO's // "extension_list" attribute and match it with the extension of the file. // Check if we've created the supported formats list, create it if not if (supported_formats_.isEmpty()) { QStringList extension_list = QString::fromStdString(OIIO::get_string_attribute("extension_list")).split(';'); // The format of "extension_list" is "format:ext", we want to separate it into a simple list of extensions foreach (const QString& ext, extension_list) { QStringList format_and_ext = ext.split(':'); supported_formats_.append(format_and_ext.at(1).split(',')); } } if (!supported_formats_.contains(QFileInfo(fn).completeSuffix(), Qt::CaseInsensitive)) { return false; } return true; } int OIIODecoder::GetImageSequenceDigitCount(const QString &filename) { QString basename = QFileInfo(filename).baseName(); // See if basename contains a number at the end int digit_count = 0; for (int i=basename.size()-1;i>=0;i--) { if (basename.at(i).isDigit()) { digit_count++; } else { break; } } return digit_count; } QString OIIODecoder::TransformImageSequenceFileName(const QString &filename, const int64_t& number) { int digit_count = GetImageSequenceDigitCount(filename); QFileInfo file_info(filename); QString original_basename = file_info.baseName(); QString new_basename = original_basename.left(original_basename.size() - digit_count) .append(QStringLiteral("%1").arg(number, digit_count, 10, QChar('0'))); return file_info.dir().filePath(file_info.fileName().replace(original_basename, new_basename)); } int64_t OIIODecoder::GetImageSequenceIndex(const QString &filename) { int digit_count = GetImageSequenceDigitCount(filename); QFileInfo file_info(filename); QString original_basename = file_info.baseName(); QString number_only = original_basename.mid(original_basename.size() - digit_count); return number_only.toLongLong(); } bool OIIODecoder::OpenImageHandler(const QString &fn) { image_ = OIIO::ImageInput::open(fn.toStdString()); if (!image_) { return false; } // Check if we can work with this pixel format const OIIO::ImageSpec& spec = image_->spec(); is_rgba_ = (spec.nchannels == kRGBAChannels); pix_fmt_ = GetFormatFromOIIOBasetype(spec); if (pix_fmt_ == PixelFormat::PIX_FMT_INVALID) { qWarning() << "Failed to convert OIIO::ImageDesc to native pixel format"; return false; } // FIXME: Many OIIO pixel formats are not handled here OIIO::TypeDesc type = PixelFormat::GetOIIOTypeDesc(pix_fmt_); #if OIIO_VERSION < 20100 buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type)); #else buffer_ = new OIIO::ImageBuf(OIIO::ImageSpec(spec.width, spec.height, spec.nchannels, type), OIIO::InitializePixels::No); #endif image_->read_image(type, buffer_->localpixels()); return true; } void OIIODecoder::CloseImageHandle() { if (image_) { image_->close(); #if OIIO_VERSION < 10903 OIIO::ImageInput::destroy(image_); #endif image_ = nullptr; } if (buffer_) { delete buffer_; buffer_ = nullptr; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/oiio/oiiodecoder.h000066400000000000000000000044001370472574300216440ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OIIODECODER_H #define OIIODECODER_H #include #include #include "codec/decoder.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER class OIIODecoder : public Decoder { Q_OBJECT public: OIIODecoder(); enum ExportCodec { kCodecEXR, kCodecPNG, kCodecTIFF }; virtual QString id() override; virtual bool Probe(Footage *f, const QAtomicInt* cancelled) override; virtual bool Open() override; virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override; virtual void Close() override; virtual bool SupportsVideo() override; virtual QString GetIndexFilename() const override; static void FrameToBuffer(FramePtr frame, OIIO::ImageBuf* buf); static void BufferToFrame(OIIO::ImageBuf* buf, FramePtr frame); static PixelFormat::Format GetFormatFromOIIOBasetype(const OIIO::ImageSpec& spec); private: #if OIIO_VERSION < 10903 OIIO::ImageInput* image_; #else std::unique_ptr image_; #endif static bool FileTypeIsSupported(const QString& fn); static int GetImageSequenceDigitCount(const QString& filename); static QString TransformImageSequenceFileName(const QString& filename, const int64_t& number); static int64_t GetImageSequenceIndex(const QString& filename); bool OpenImageHandler(const QString& fn); void CloseImageHandle(); PixelFormat::Format pix_fmt_; bool is_rgba_; bool is_sequence_; OIIO::ImageBuf* buffer_; static QStringList supported_formats_; }; OLIVE_NAMESPACE_EXIT #endif // OIIODECODER_H olive-continuous/app/codec/samplebuffer.cpp000066400000000000000000000157671370472574300214500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "samplebuffer.h" OLIVE_NAMESPACE_ENTER SampleBuffer::SampleBuffer() : sample_count_per_channel_(0), data_(nullptr) { } SampleBuffer::~SampleBuffer() { destroy(); } SampleBufferPtr SampleBuffer::Create() { return std::make_shared(); } SampleBufferPtr SampleBuffer::CreateAllocated(const AudioParams &audio_params, int samples_per_channel) { SampleBufferPtr buffer = Create(); buffer->set_audio_params(audio_params); buffer->set_sample_count(samples_per_channel); buffer->allocate(); return buffer; } SampleBufferPtr SampleBuffer::CreateFromPackedData(const AudioParams &audio_params, const QByteArray &bytes) { if (!audio_params.is_valid()) { qWarning() << "Tried to create from packed data with invalid parameters"; return nullptr; } int samples_per_channel = audio_params.bytes_to_samples(bytes.size()); SampleBufferPtr buffer = CreateAllocated(audio_params, samples_per_channel); int total_samples = samples_per_channel * audio_params.channel_count(); const float* packed_data = reinterpret_cast(bytes.constData()); for (int i=0;idata_[channel][index] = packed_data[i]; } return buffer; } const AudioParams &SampleBuffer::audio_params() const { return audio_params_; } void SampleBuffer::set_audio_params(const AudioParams ¶ms) { if (data_) { qWarning() << "Tried to set parameters on allocated sample buffer"; return; } audio_params_ = params; } const int &SampleBuffer::sample_count() const { return sample_count_per_channel_; } void SampleBuffer::set_sample_count(const int &sample_count) { if (data_) { qWarning() << "Tried to set sample count on allocated sample buffer"; return; } sample_count_per_channel_ = sample_count; } float **SampleBuffer::data() { return data_; } const float **SampleBuffer::const_data() const { return const_cast(data_); } float *SampleBuffer::channel_data(int channel) { return data_[channel]; } bool SampleBuffer::is_allocated() const { return data_; } void SampleBuffer::allocate() { if (!audio_params_.is_valid()) { qWarning() << "Tried to allocate sample buffer with invalid audio parameters"; return; } if (!sample_count_per_channel_) { qWarning() << "Tried to allocate sample buffer with zero sample count"; return; } if (data_) { qWarning() << "Tried to allocate already allocated sample buffer"; return; } allocate_sample_buffer(&data_, audio_params_.channel_count(), sample_count_per_channel_); } void SampleBuffer::destroy() { destroy_sample_buffer(&data_, audio_params_.channel_count()); } void SampleBuffer::reverse() { if (!is_allocated()) { qWarning() << "Tried to reverse an unallocated sample buffer"; return; } int half_nb_sample = sample_count_per_channel_ / 2; for (int i=0;i(sample_count_per_channel_) / speed); float** input_data = data_; float** output_data; allocate_sample_buffer(&output_data, audio_params_.channel_count(), sample_count_per_channel_); for (int i=0;i(i) * speed); for (int j=0;j(packed_data.data()); int output_index = 0; for (int j=0;j 0); *data = new float* [nb_channels]; for (int i=0;i. ***/ #ifndef SAMPLEBUFFER_H #define SAMPLEBUFFER_H #include #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER class SampleBuffer; using SampleBufferPtr = std::shared_ptr; /** * @brief A buffer of audio samples * * Audio samples in this structure are always stored in PLANAR (separated by channel). This is done to simplify audio * rendering code. This replaces the old system of using QByteArrays (containing packed audio) and while SampleBuffer * replaces many of those in the rendering/processing side of things, QByteArrays are currently still in use for * playback, including reading to and from the cache. */ class SampleBuffer { public: SampleBuffer(); virtual ~SampleBuffer(); static SampleBufferPtr Create(); static SampleBufferPtr CreateAllocated(const AudioParams& audio_params, int samples_per_channel); static SampleBufferPtr CreateFromPackedData(const AudioParams& audio_params, const QByteArray& bytes); DISABLE_COPY_MOVE(SampleBuffer) const AudioParams& audio_params() const; void set_audio_params(const AudioParams& params); const int &sample_count() const; void set_sample_count(const int &sample_count); float** data(); const float** const_data() const; float* channel_data(int channel); bool is_allocated() const; void allocate(); void destroy(); void reverse(); void speed(double speed); void transform_volume(float f); void transform_volume_for_channel(int channel, float volume); void transform_volume_for_sample(int sample_index, float volume); void transform_volume_for_sample_on_channel(int sample_index, int channel, float volume); void fill(const float& f); void fill(const float& f, int start_sample, int end_sample); void set(const float** data, int sample_offset, int sample_length); void set(const float** data, int sample_length); QByteArray toPackedData() const; private: static void allocate_sample_buffer(float*** data, int nb_channels, int nb_samples); static void destroy_sample_buffer(float*** data, int nb_channels); AudioParams audio_params_; int sample_count_per_channel_; float** data_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::SampleBufferPtr) #endif // SAMPLEBUFFER_H olive-continuous/app/codec/waveinput.cpp000066400000000000000000000113631370472574300210030ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "waveinput.h" extern "C" { #include } #include #include OLIVE_NAMESPACE_ENTER WaveInput::WaveInput(const QString &f) : file_(f) { } WaveInput::~WaveInput() { close(); } bool WaveInput::open() { if (!file_.open(QFile::ReadOnly)) { return false; } if (file_.read(4) != "RIFF") { close(); qCritical() << "No RIFF found"; return false; } // Skip filesize bytes file_.seek(file_.pos() + 4); if (file_.read(4) != "WAVE") { close(); qCritical() << "No WAVE found"; return false; } // Find fmt_ section if (!find_str(&file_, "fmt ")) { close(); qCritical() << "No fmt found"; return false; } // Skip fmt_ section size file_.seek(file_.pos()+4); // Create data stream for reading bytes into types QDataStream data_stream(&file_); data_stream.setByteOrder(QDataStream::LittleEndian); // Read data type uint16_t data_type; data_stream >> data_type; bool data_is_float; switch (data_type) { case 1: // PCM Integer data_is_float = false; break; case 3: data_is_float = true; break; default: // If it's neither float nor int, we can't work with this file close(); qCritical() << "Invalid WAV type" << data_type; return false; } // Read number of channels uint16_t channel_count; data_stream >> channel_count; uint64_t channel_layout = static_cast(av_get_default_channel_layout(channel_count)); int32_t sample_rate; data_stream >> sample_rate; // Skip bytes per second value and bytes per sample value file_.seek(file_.pos() + 6); uint16_t bits_per_sample; data_stream >> bits_per_sample; SampleFormat::Format format; switch (bits_per_sample) { case 8: format = SampleFormat::SAMPLE_FMT_U8; break; case 16: format = SampleFormat::SAMPLE_FMT_S16; break; case 32: if (data_is_float) { format = SampleFormat::SAMPLE_FMT_FLT; } else { format = SampleFormat::SAMPLE_FMT_S32; } break; case 64: if (data_is_float) { format = SampleFormat::SAMPLE_FMT_DBL; } else { format = SampleFormat::SAMPLE_FMT_S64; } break; default: // We don't know this format... close(); qCritical() << "Invalid format found" << bits_per_sample; return false; } // We're good to go! params_ = AudioParams(sample_rate, channel_layout, format); if (!find_str(&file_, "data")) { close(); qCritical() << "No data tag found"; return false; } data_stream >> data_size_; data_position_ = file_.pos(); return true; } bool WaveInput::is_open() const { return file_.isOpen(); } QByteArray WaveInput::read(int length) { if (!is_open()) { return QByteArray(); } return file_.read(qMin(calculate_max_read(), static_cast(length))); } QByteArray WaveInput::read(int offset, int length) { if (!is_open()) { return QByteArray(); } seek(offset); return file_.read(qMin(calculate_max_read(), static_cast(length))); } qint64 WaveInput::read(int offset, char *buffer, int length) { if (!is_open()) { return 0; } seek(offset); return file_.read(buffer, qMin(calculate_max_read(), static_cast(length))); } bool WaveInput::seek(qint64 pos) { return file_.seek(data_position_ + qMin(pos, static_cast(data_size_))); } bool WaveInput::at_end() const { return file_.pos() == (data_position_ + data_size_); } const AudioParams &WaveInput::params() const { return params_; } void WaveInput::close() { if (file_.isOpen()) { file_.close(); } } const quint32 &WaveInput::data_length() const { return data_size_; } int WaveInput::sample_count() const { return params_.bytes_to_samples(static_cast(data_size_)); } bool WaveInput::find_str(QFile *f, const char *str) { qint64 pos = f->pos(); while (f->read(4) != str) { if (f->atEnd()) { return false; } pos++; f->seek(pos); } return true; } qint64 WaveInput::calculate_max_read() const { return data_size_ - (file_.pos() - data_position_ ); } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/waveinput.h000066400000000000000000000027401370472574300204470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef WAVEINPUT_H #define WAVEINPUT_H #include #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER class WaveInput { public: WaveInput(const QString& f); ~WaveInput(); DISABLE_COPY_MOVE(WaveInput) bool open(); bool is_open() const; QByteArray read(int length); QByteArray read(int offset, int length); qint64 read(int offset, char *buffer, int length); bool seek(qint64 pos); bool at_end() const; const AudioParams& params() const; void close(); const quint32& data_length() const; int sample_count() const; private: bool find_str(QFile* f, const char* str); qint64 calculate_max_read() const; AudioParams params_; QFile file_; qint64 data_position_; quint32 data_size_; }; OLIVE_NAMESPACE_EXIT #endif // WAVEINPUT_H olive-continuous/app/codec/waveoutput.cpp000066400000000000000000000077771370472574300212220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "waveoutput.h" OLIVE_NAMESPACE_ENTER const int16_t kWAVIntegerFormat = 1; const int16_t kWAVFloatFormat = 3; WaveOutput::WaveOutput(const QString &f, const AudioParams& params) : file_(f), params_(params) { Q_ASSERT(params_.is_valid()); } WaveOutput::~WaveOutput() { close(); } bool WaveOutput::open() { data_length_ = 0; if (file_.open(QFile::WriteOnly)) { // RIFF header file_.write("RIFF"); // Total file size minus RIFF and this integer (minus 8 bytes, filled in later) write_int(&file_, 0); // File type header file_.write("WAVE"); // Begin format descriptor chunk file_.write("fmt "); // Format chunk size write_int(&file_, 16); // Type of format switch (params_.format()) { case SampleFormat::SAMPLE_FMT_U8: case SampleFormat::SAMPLE_FMT_S16: case SampleFormat::SAMPLE_FMT_S32: case SampleFormat::SAMPLE_FMT_S64: write_int(&file_, kWAVIntegerFormat); break; case SampleFormat::SAMPLE_FMT_FLT: case SampleFormat::SAMPLE_FMT_DBL: write_int(&file_, kWAVFloatFormat); break; case SampleFormat::SAMPLE_FMT_INVALID: case SampleFormat::SAMPLE_FMT_COUNT: qWarning() << "Invalid sample format for WAVE audio"; file_.close(); return false; } // Number of channels write_int(&file_, static_cast(params_.channel_count())); // Sample rate write_int(&file_, params_.sample_rate()); // Bytes per second write_int(&file_, params_.samples_to_bytes(params_.sample_rate())); // Bytes per sample write_int(&file_, static_cast(params_.samples_to_bytes(1))); // Bits per sample per channel write_int(&file_, static_cast(params_.bits_per_sample())); // Data chunk header file_.write("data"); // Size of data chunk (filled in later) write_int(&file_, 0); return true; } return false; } void WaveOutput::write(const QByteArray &bytes) { if (file_.isOpen()) { file_.write(bytes); data_length_ += bytes.size(); } } void WaveOutput::write(const char *bytes, int length) { if (file_.isOpen()) { file_.write(bytes, length); data_length_ += length; } } void WaveOutput::close() { if (file_.isOpen()) { // Write file sizes file_.seek(4); write_int(&file_, data_length_ + 36); file_.seek(40); write_int(&file_, data_length_); file_.close(); } } const int& WaveOutput::data_length() const { return data_length_; } const AudioParams &WaveOutput::params() const { return params_; } void WaveOutput::switch_endianness(QByteArray& array) { int half_sz = array.size()/2; for (int i=0;i void WaveOutput::write_int(QFile *file, T integer) { QByteArray bytes; bytes.resize(sizeof(T)); memcpy(bytes.data(), &integer, static_cast(bytes.size())); // WAV expects little-endian, so if the integer is big endian we need to switch if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { switch_endianness(bytes); } file->write(bytes); } OLIVE_NAMESPACE_EXIT olive-continuous/app/codec/waveoutput.h000066400000000000000000000026551370472574300206550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef WAVEAUDIO_H #define WAVEAUDIO_H #include #include #include "audio/sampleformat.h" #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER class WaveOutput { public: WaveOutput(const QString& f, const AudioParams& params); ~WaveOutput(); DISABLE_COPY_MOVE(WaveOutput) bool open(); void write(const QByteArray& bytes); void write(const char* bytes, int length); void close(); const int& data_length() const; const AudioParams& params() const; private: template void write_int(QFile* file, T integer); void switch_endianness(QByteArray &array); QFile file_; AudioParams params_; int data_length_; }; OLIVE_NAMESPACE_EXIT #endif // WAVEAUDIO_H olive-continuous/app/common/000077500000000000000000000000001370472574300164645ustar00rootroot00000000000000olive-continuous/app/common/CMakeLists.txt000066400000000000000000000026541370472574300212330ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} common/bezier.h common/bezier.cpp common/cancelableobject.h common/channellayout.h common/clamp.h common/crashhandler.h common/crashhandler.cpp common/debug.h common/debug.cpp common/define.h common/filefunctions.h common/filefunctions.cpp common/flipmodifiers.h common/flipmodifiers.cpp common/functiontimer.h common/lerp.h common/memorypool.h common/qtutils.h common/qtutils.cpp common/range.h common/rational.h common/rational.cpp common/threadedobject.h common/threadedobject.cpp common/timecodefunctions.h common/timecodefunctions.cpp common/timerange.h common/timerange.cpp common/tohex.h common/xmlutils.h common/xmlutils.cpp PARENT_SCOPE ) olive-continuous/app/common/autoscroll.h000066400000000000000000000016511370472574300210270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUTOSCROLL_H #define AUTOSCROLL_H #include "common/define.h" OLIVE_NAMESPACE_ENTER class AutoScroll { public: enum Method { kNone, kPage, kSmooth }; }; OLIVE_NAMESPACE_EXIT #endif // AUTOSCROLL_H olive-continuous/app/common/bezier.cpp000066400000000000000000000032751370472574300204570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "bezier.h" #include OLIVE_NAMESPACE_ENTER double Bezier::QuadraticXtoT(double x, double a, double b, double c) { return (a - b + qSqrt(a*x + c*x - 2*b*x + qPow(b, 2) - a*c))/(a - 2*b + c); } double Bezier::QuadraticTtoY(double a, double b, double c, double t) { return qPow(1.0 - t, 2)*a + 2*(1.0 - t)*t*b + qPow(t, 2)*c; } double Bezier::CubicXtoT(double x_target, double a, double b, double c, double d) { double tolerance = 0.0001; double lower = 0.0; double upper = 1.0; double percent = 0.5; double x = CubicTtoY(a, b, c, d, percent); while (qAbs(x_target - x) > tolerance) { if (x_target > x) { lower = percent; } else { upper = percent; } percent = (upper + lower) / 2.0; x = CubicTtoY(a, b, c, d, percent); } return percent; } double Bezier::CubicTtoY(double a, double b, double c, double d, double t) { return qPow(1.0 - t, 3)*a + 3*qPow(1.0 - t, 2)*t*b + 3*(1.0 - t)*qPow(t, 2)*c + qPow(t, 3)*d; } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/bezier.h000066400000000000000000000022241370472574300201150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef BEZIER_H #define BEZIER_H #include "common/define.h" OLIVE_NAMESPACE_ENTER class Bezier { public: static double QuadraticXtoT(double x, double a, double b, double c); static double QuadraticTtoY(double a, double b, double c, double t); static double CubicXtoT(double x_target, double a, double b, double c, double d); static double CubicTtoY(double a, double b, double c, double d, double t); }; OLIVE_NAMESPACE_EXIT #endif // BEZIER_H olive-continuous/app/common/cancelableobject.h000066400000000000000000000021561370472574300221010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CANCELABLEOBJECT_H #define CANCELABLEOBJECT_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class CancelableObject { public: CancelableObject() : cancelled_(false) { } void Cancel() { cancelled_ = true; } const QAtomicInt& IsCancelled() const { return cancelled_; } private: QAtomicInt cancelled_; }; OLIVE_NAMESPACE_EXIT #endif // CANCELABLEOBJECT_H olive-continuous/app/common/channellayout.h000066400000000000000000000017601370472574300215070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CHANNELLAYOUT_H #define CHANNELLAYOUT_H /** * Channel Layouts header * * We don't do much here at the moment, audio is a much simpler beast than video nowadays and FFmpeg seems to cover it * fairly well. */ extern "C" { #include } #endif // CHANNELLAYOUT_H olive-continuous/app/common/clamp.h000066400000000000000000000024471370472574300177400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CLAMP_H #define CLAMP_H template /** * @brief Clamp a value between a minimum and a maximum value * * Similar to using min() and max() functions, but performs both at once. If value is less than minimum, this returns * minimum. If it is more than maximum, this returns maximum. Otherwise it returns value as-is. * * @return * * Will always return a value between minimum and maximum (inclusive). */ T clamp(T value, T minimum, T maximum) { if (value < minimum) { return minimum; } if (value > maximum) { return maximum; } return value; } #endif // CLAMP_H olive-continuous/app/common/crashhandler.cpp000066400000000000000000000101101370472574300216170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "crashhandler.h" #include #include #include #include #include #include #include #if defined(Q_OS_WINDOWS) #include #include #include #include #elif defined(Q_OS_MAC) || defined(Q_OS_LINUX) #include #endif #include "common/filefunctions.h" OLIVE_NAMESPACE_ENTER void crash_handler(int sig) { QString log_path = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("olive_crash")); QFile output(log_path); output.open(QFile::WriteOnly); QTextStream ostream(&output); #ifdef GITHASH ostream << "Version: " << GITHASH << "\n"; #endif ostream << "Signal: " << sig << "\n\n"; #if defined(Q_OS_WINDOWS) // Use Windows stackwalk API HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); CONTEXT context; memset(&context, 0, sizeof(CONTEXT)); context.ContextFlags = CONTEXT_FULL; RtlCaptureContext(&context); SymInitialize(process, NULL, TRUE); DWORD image; STACKFRAME64 stackframe; ZeroMemory(&stackframe, sizeof(STACKFRAME64)); #ifdef _M_IX86 image = IMAGE_FILE_MACHINE_I386; stackframe.AddrPC.Offset = context.Eip; stackframe.AddrPC.Mode = AddrModeFlat; stackframe.AddrFrame.Offset = context.Ebp; stackframe.AddrFrame.Mode = AddrModeFlat; stackframe.AddrStack.Offset = context.Esp; stackframe.AddrStack.Mode = AddrModeFlat; #elif _M_X64 image = IMAGE_FILE_MACHINE_AMD64; stackframe.AddrPC.Offset = context.Rip; stackframe.AddrPC.Mode = AddrModeFlat; stackframe.AddrFrame.Offset = context.Rsp; stackframe.AddrFrame.Mode = AddrModeFlat; stackframe.AddrStack.Offset = context.Rsp; stackframe.AddrStack.Mode = AddrModeFlat; #elif _M_IA64 image = IMAGE_FILE_MACHINE_IA64; stackframe.AddrPC.Offset = context.StIIP; stackframe.AddrPC.Mode = AddrModeFlat; stackframe.AddrFrame.Offset = context.IntSp; stackframe.AddrFrame.Mode = AddrModeFlat; stackframe.AddrBStore.Offset = context.RsBSP; stackframe.AddrBStore.Mode = AddrModeFlat; stackframe.AddrStack.Offset = context.IntSp; stackframe.AddrStack.Mode = AddrModeFlat; #endif for (int i = 0; i < 50; i++) { BOOL result = StackWalk64( image, process, thread, &stackframe, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); if (!result) { break; } char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = MAX_SYM_NAME; DWORD64 displacement = 0; ostream << "[" << i << "] "; if (SymFromAddr(process, stackframe.AddrPC.Offset, &displacement, symbol)) { ostream << symbol->Name; //printf("[%i] %s\n", i, symbol->Name); } else { ostream << "???"; //printf("[%i] ???\n", i); } ostream << "\n"; } SymCleanup(process); #elif defined(Q_OS_MAC) || defined(Q_OS_LINUX) void *array[10]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, 10); // print out all the frames to stderr backtrace_symbols_fd(array, size, output.handle()); #endif output.close(); QString crash_handler_exe = QDir(qApp->applicationDirPath()).filePath(QStringLiteral("olive-crashhandler")); QProcess::startDetached(crash_handler_exe, {log_path}); exit(1); } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/crashhandler.h000066400000000000000000000015671370472574300213040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CRASHHANDLER_H #define CRASHHANDLER_H #include "common/define.h" OLIVE_NAMESPACE_ENTER void crash_handler(int sig); OLIVE_NAMESPACE_EXIT #endif // CRASHHANDLER_H olive-continuous/app/common/debug.cpp000066400000000000000000000027761370472574300202720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "debug.h" OLIVE_NAMESPACE_ENTER void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { QByteArray localMsg = msg.toLocal8Bit(); const char* msg_type = "UNKNOWN"; switch (type) { case QtDebugMsg: msg_type = "DEBUG"; break; case QtInfoMsg: msg_type = "INFO"; break; case QtWarningMsg: msg_type = "WARNING"; break; case QtCriticalMsg: msg_type = "ERROR"; break; case QtFatalMsg: msg_type = "FATAL"; break; } fprintf(stderr, "[%s] %s (%s:%u)\n", msg_type, localMsg.constData(), context.function, context.line); #ifdef Q_OS_WINDOWS // Windows still seems to buffer stderr and we want to see debug messages immediately, so here we make sure each line // is flushed fflush(stderr); #endif } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/debug.h000066400000000000000000000016621370472574300177300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef DEBUG_H #define DEBUG_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER void DebugHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg); OLIVE_NAMESPACE_EXIT #endif // DEBUG_H olive-continuous/app/common/define.h000066400000000000000000000042621370472574300200730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OLIVECOMMONDEFINE_H #define OLIVECOMMONDEFINE_H #define OLIVE_NAMESPACE olive #define OLIVE_NAMESPACE_ENTER namespace OLIVE_NAMESPACE { #define OLIVE_NAMESPACE_EXIT } OLIVE_NAMESPACE_ENTER const int kHSVChannels = 3; const int kRGBChannels = 3; const int kRGBAChannels = 4; /// The minimum size an icon in ProjectExplorer can be const int kProjectIconSizeMinimum = 16; /// The maximum size an icon in ProjectExplorer can be const int kProjectIconSizeMaximum = 256; /// The default size an icon in ProjectExplorer can be const int kProjectIconSizeDefault = 64; OLIVE_NAMESPACE_EXIT #define MACRO_NAME_AS_STR(s) #s #define MACRO_VAL_AS_STR(s) MACRO_NAME_AS_STR(s) #define OLIVE_NS_CONST_ARG(x, y) QArgument("const " MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) #define OLIVE_NS_ARG(x, y) QArgument(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) #define OLIVE_NS_RETURN_ARG(x, y) QReturnArgument(MACRO_VAL_AS_STR(OLIVE_NAMESPACE) "::" #x, y) /** * Copy/move deleters. Similar to Q_DISABLE_COPY_MOVE, et al. but those functions are not present in Qt < 5.13 so we * use our own functions for portability. */ #define DISABLE_COPY(Class) \ Class(const Class &) = delete;\ Class &operator=(const Class &) = delete; #define DISABLE_MOVE(Class) \ Class(Class &&) = delete; \ Class &operator=(Class &&) = delete; #define DISABLE_COPY_MOVE(Class) \ DISABLE_COPY(Class) \ DISABLE_MOVE(Class) #endif // OLIVECOMMONDEFINE_H olive-continuous/app/common/filefunctions.cpp000066400000000000000000000076111370472574300220450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "filefunctions.h" #include #include #include #include #include #include #include "config/config.h" OLIVE_NAMESPACE_ENTER QString FileFunctions::GetUniqueFileIdentifier(const QString &filename) { QFileInfo info(filename); if (!info.exists()) { return QString(); } QCryptographicHash hash(QCryptographicHash::Sha1); hash.addData(info.absoluteFilePath().toUtf8()); hash.addData(info.lastModified().toString().toUtf8()); QByteArray result = hash.result(); return QString(result.toHex()); } QString FileFunctions::GetMediaIndexLocation() { QDir local_appdata_dir(Config::Current()["DiskCachePath"].toString()); QDir media_index_dir = local_appdata_dir.filePath("mediaindex"); // Attempt to ensure this folder exists media_index_dir.mkpath("."); return media_index_dir.absolutePath(); } QString FileFunctions::GetMediaIndexFilename(const QString &filename) { return QDir(GetMediaIndexLocation()).filePath(filename); } QString FileFunctions::GetMediaCacheLocation() { QDir local_appdata_dir(Config::Current()["DiskCachePath"].toString()); QDir media_cache_dir = local_appdata_dir.filePath("mediacache"); // Attempt to ensure this folder exists media_cache_dir.mkpath("."); return media_cache_dir.absolutePath(); } QString FileFunctions::GetConfigurationLocation() { if (IsPortable()) { return GetApplicationPath(); } else { QString s = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); QDir(s).mkpath("."); return s; } } bool FileFunctions::IsPortable() { return QFileInfo::exists(QDir(GetApplicationPath()).filePath("portable")); } QString FileFunctions::GetApplicationPath() { return QCoreApplication::applicationDirPath(); } QString FileFunctions::GetTempFilePath() { QString temp_path = QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)) .filePath(QCoreApplication::organizationName())) .filePath(QCoreApplication::applicationName()); // Ensure it exists QDir(temp_path).mkpath("."); return temp_path; } void FileFunctions::CopyDirectory(const QString &source, const QString &dest, bool overwrite) { QDir d(source); if (!d.exists()) { qCritical() << "Failed to copy directory, source" << source << "didn't exist"; return; } QDir dest_dir(dest); if (!dest_dir.mkpath(QStringLiteral("."))) { qCritical() << "Failed to create destination directory" << dest; return; } QFileInfoList l = d.entryInfoList(); foreach (const QFileInfo& info, l) { // QDir::NoDotAndDotDot continues to not work, so we have to check manually if (info.fileName() == QStringLiteral(".") || info.fileName() == QStringLiteral("..")) { continue; } QString dest_file_path = dest_dir.filePath(info.fileName()); if (info.isDir()) { // Copy dir CopyDirectory(info.absoluteFilePath(), dest_file_path, overwrite); } else { // Copy file if (overwrite && QFile::exists(dest_file_path)) { QFile::remove(dest_file_path); } QFile::copy(info.absoluteFilePath(), dest_file_path); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/filefunctions.h000066400000000000000000000032441370472574300215100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FILEFUNCTIONS_H #define FILEFUNCTIONS_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief A collection of static file and directory functions */ class FileFunctions { public: /** * @brief Returns true if the application is running in portable mode * * In portable mode, any persistent configuration files should be made in a path relative to the application rather * than in the user's home folder. */ static bool IsPortable(); static QString GetUniqueFileIdentifier(const QString& filename); static QString GetMediaIndexLocation(); static QString GetMediaIndexFilename(const QString& filename); static QString GetMediaCacheLocation(); static QString GetConfigurationLocation(); static QString GetApplicationPath(); static QString GetTempFilePath(); static void CopyDirectory(const QString& source, const QString& dest, bool overwrite = false); }; OLIVE_NAMESPACE_EXIT #endif // FILEFUNCTIONS_H olive-continuous/app/common/flipmodifiers.cpp000066400000000000000000000021671370472574300220320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "flipmodifiers.h" OLIVE_NAMESPACE_ENTER Qt::KeyboardModifiers FlipControlAndShiftModifiers(Qt::KeyboardModifiers e) { if (e & Qt::ControlModifier & Qt::ShiftModifier) { return e; } if (e & Qt::ShiftModifier) { e |= Qt::ControlModifier; e &= ~Qt::ShiftModifier; } else if (e & Qt::ControlModifier) { e |= Qt::ShiftModifier; e &= ~Qt::ControlModifier; } return e; } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/flipmodifiers.h000066400000000000000000000016751370472574300215020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FLIPMODIFIERS_H #define FLIPMODIFIERS_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER Qt::KeyboardModifiers FlipControlAndShiftModifiers(Qt::KeyboardModifiers e); OLIVE_NAMESPACE_EXIT #endif // FLIPMODIFIERS_H olive-continuous/app/common/functiontimer.h000066400000000000000000000023351370472574300215260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FUNCTIONTIMER_H #define FUNCTIONTIMER_H #include #include #define TIME_THIS_FUNCTION FunctionTimer __f(__FUNCTION__) class FunctionTimer { public: FunctionTimer(const char* s) { name_ = s; time_ = QDateTime::currentMSecsSinceEpoch(); } ~FunctionTimer() { qint64 elapsed = (QDateTime::currentMSecsSinceEpoch() - time_); if (elapsed > 1) { qDebug() << name_ << "took" << elapsed; } } private: const char* name_; qint64 time_; }; #endif // FUNCTIONTIMER_H olive-continuous/app/common/lerp.h000066400000000000000000000022251370472574300176000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef LERP_H #define LERP_H template /** * @brief Linearly interpolate a value between a and b using t * * t should be a number between 0.0 and 1.0. 0.0 will return a, 1.0 will return b, and between will return a value * in between a and b at that point linearly. */ T lerp(T a, T b, double t) { return (a * (1.0 - t)) + (b * t); } template T lerp(T a, T b, float t) { return (a * (1.0f - t)) + (b * t); } #endif // LERP_H olive-continuous/app/common/memorypool.h000066400000000000000000000210611370472574300210370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MEMORYPOOL_H #define MEMORYPOOL_H #include #include #include #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER template /** * @brief MemoryPool base class * * A custom memory system that allocates can allocate several objects in a large chunk (as opposed to several small * allocations). Improves performance and memory consumption. * * As a class, this base is usable by setting the template to an object of your choosing. The pool will then allocate * `(element_count * sizeof(T))` per arena. Arenas are allocated and destroyed on the fly - when an arena fills up, * another is allocated. * * `Get()` will return an ElementPtr. The original desired data can be accessed through ElementPtr::data(). This data * will belong to the caller until ElementPtr goes out of scope and the memory is freed back into the pool. */ class MemoryPool { public: /** * @brief Constructor * @param element_count * * Number of elements per arena */ MemoryPool(int element_count) { element_count_ = element_count; ignore_arena_empty_signal_ = false; } /** * @brief Destructor * * Deletes all arenas. */ virtual ~MemoryPool() { ignore_arena_empty_signal_ = true; qDeleteAll(arenas_); } DISABLE_COPY_MOVE(MemoryPool) /** * @brief Returns whether any arenas are successfully allocated */ inline bool IsAllocated() const { return !arenas_.isEmpty(); } /** * @brief Returns current number of allocated arenas */ inline int GetArenaCount() const { return arenas_.size(); } class Arena; /** * @brief A handle for a chunk of memory in an arena * * Calling Get() on the pool or arena will return a shared pointer to an element which will contain a pointer to * the desired object/data in data(). When Element is destroyed (i.e. when ElementPtr goes out of scope), the memory * is released back into the pool so it can be used by another class. */ class Element { public: /** * @brief Element Constructor * * There is no need to use this outside of the memory pool's internal functions. */ Element(Arena* parent, T* data) { parent_ = parent; data_ = data; accessed_ = QDateTime::currentMSecsSinceEpoch(); } /** * @brief Element Destructor * * Automatically releases this element's memory back to the arena it was retrieved from. */ ~Element() { release(); } DISABLE_COPY_MOVE(Element) /** * @brief Access data represented in the pool */ inline T* data() const { return data_; } inline const int64_t& timestamp() const { return timestamp_; } inline void set_timestamp(const int64_t& timestamp) { timestamp_ = timestamp; } /** * @brief Register that this element has been accessed * * \see last_accessed() */ inline void access() { accessed_ = QDateTime::currentMSecsSinceEpoch(); } /** * @brief Returns the last time `access()` was called on this function * * Useful for determining the relative age of an element (i.e. if it hasn't been accessed for a certain amount of * time, it can probably be freed back into the pool). This requires all usages to call `access()`. */ inline const int64_t& last_accessed() const { return accessed_; } void release() { if (data_) { parent_->Release(this); data_ = nullptr; } } private: Arena* parent_; T* data_; int64_t timestamp_; int64_t accessed_; }; using ElementPtr = std::shared_ptr; /** * @brief A memory pool arena - a subsection of memory * * The pool itself does not store memory, it stores "arenas". This is so that the pool can handle the situation of * an arena becoming full with no more memory to lend. A pool can automatically allocate another arena and continue * providing memory (and freeing arenas when they're no longer in use). */ class Arena { public: Arena(MemoryPool* parent) { parent_ = parent; data_ = nullptr; } ~Arena() { std::list copy = lent_elements_; foreach (Element* e, copy) { e->release(); } delete [] data_; } DISABLE_COPY_MOVE(Arena) /** * @brief Returns an element if there is free memory to do so */ ElementPtr Get() { QMutexLocker locker(&lock_); for (int i=0;i(this, reinterpret_cast(data_ + i * element_sz_)); lent_elements_.push_back(e.get()); return e; } } return nullptr; } /** * @brief Releases an element back into the pool for use elsewhere */ void Release(Element* e) { QMutexLocker locker(&lock_); quintptr diff = reinterpret_cast(e->data()) - reinterpret_cast(data_); int index = diff / element_sz_; available_.replace(index, true); lent_elements_.remove(e); if (lent_elements_.empty()) { locker.unlock(); parent_->ArenaIsEmpty(this); } } int GetUsageCount() { QMutexLocker locker(&lock_); return lent_elements_.size(); } bool Allocate(size_t ele_sz, size_t nb_elements) { if (IsAllocated()) { return true; } element_sz_ = ele_sz; if ((data_ = new char[element_sz_ * nb_elements])) { available_.resize(nb_elements); available_.fill(true); return true; } else { available_.clear(); return false; } } inline int GetElementCount() const { return available_.size(); } inline bool IsAllocated() const { return data_; } private: MemoryPool* parent_; char* data_; QVector available_; QMutex lock_; size_t element_sz_; std::list lent_elements_; }; /** * @brief Retrieves an element from an available arena */ ElementPtr Get() { QMutexLocker locker(&lock_); // Attempt to get an element from an arena foreach (Arena* a, arenas_) { ElementPtr e = a->Get(); if (e) { return e; } } // All arenas were empty, we'll need to create a new one if (arenas_.empty()) { qDebug() << "No arenas, creating new..."; } else { qDebug() << "All arenas are full, creating new..."; } size_t ele_sz = GetElementSize(); if (!ele_sz) { qCritical() << "Failed to create arena, element size was 0"; return nullptr; } if (element_count_ <= 0) { qCritical() << "Failed to create arena, element count was invalid:" << element_count_; return nullptr; } Arena* a = new Arena(this); if (!a->Allocate(ele_sz, element_count_)) { qCritical() << "Failed to create arena, allocation failed. Out of memory?"; delete a; return nullptr; } arenas_.push_back(a); return a->Get(); } void ArenaIsEmpty(Arena* a) { // FIXME: Does this need to be mutexed? if (ignore_arena_empty_signal_) { return; } QMutexLocker locker(&lock_); if (!a->GetUsageCount()) { qDebug() << "Removing an empty arena"; arenas_.remove(a); delete a; } } protected: /** * @brief The size of each element * * Override this to use a custom size (e.g. a char array where T = char but the element size is > 1) */ virtual size_t GetElementSize() { return sizeof(T); } private: int element_count_; std::list arenas_; QMutex lock_; bool ignore_arena_empty_signal_; }; OLIVE_NAMESPACE_EXIT #endif // MEMORYPOOL_H olive-continuous/app/common/power.h000066400000000000000000000022301370472574300177660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef POWER_H #define POWER_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER uint32_t ceil_to_power_of_2(uint32_t v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } uint32_t floor_to_power_of_2(uint32_t x) { x = x | (x >> 1); x = x | (x >> 2); x = x | (x >> 4); x = x | (x >> 8); x = x | (x >> 16); return x - (x >> 1); } OLIVE_NAMESPACE_EXIT #endif // POWER_H olive-continuous/app/common/qtutils.cpp000066400000000000000000000016711370472574300207020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "qtutils.h" OLIVE_NAMESPACE_ENTER int QFontMetricsWidth(QFontMetrics fm, const QString& s) { #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) return fm.width(s); #else return fm.horizontalAdvance(s); #endif } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/qtutils.h000066400000000000000000000025431370472574300203460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef QTVERSIONABSTRACTION_H #define QTVERSIONABSTRACTION_H /** * * A fairly simple header for reducing the amount of Qt version checks necessary throughout the code * */ #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief Retrieves the width of a string according to certain QFontMetrics * * QFontMetrics::width() has been deprecatd in favor of QFontMetrics::horizontalAdvance(), but the * latter was only introduced in 5.11+. This function wraps the latter for 5.11+ and the former for * earlier. */ int QFontMetricsWidth(QFontMetrics fm, const QString& s); OLIVE_NAMESPACE_EXIT #endif // QTVERSIONABSTRACTION_H olive-continuous/app/common/range.h000066400000000000000000000015431370472574300177340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RANGE_H #define RANGE_H template bool InRange(T a, T b, T range) { return (a >= b - range && a <= b + range); } #endif // RANGE_H olive-continuous/app/common/rational.cpp000066400000000000000000000156731370472574300210150ustar00rootroot00000000000000//Copyright 2015 Adam Quintero //This program is distributed under the terms of the GNU General Public License. #include "rational.h" OLIVE_NAMESPACE_ENTER rational rational::fromDouble(const double &flt) { // Use FFmpeg function for the time being return av_d2q(flt, INT_MAX); } rational rational::fromString(const QString &str) { QStringList elements = str.split('/'); switch (elements.size()) { case 0: return rational(); case 1: return rational(elements.first().toLongLong()); default: return rational(elements.at(0).toLongLong(), elements.at(1).toLongLong()); } } //Function: print number to cout void rational::print(std::ostream &out) const { out << this->numer_ << "/" << this->denom_; } //Function: ensures denom >= 0 void rational::fix_signs() { if (denom_ < 0) { denom_ = -denom_; numer_ = -numer_; } if (numer_ == intType(0) || denom_ == intType(0)) { numer_ = intType(0); denom_ = intType(0); } } //Function: ensures lowest form void rational::reduce() { if (!isNull()) { // Euclidean often fails if numbers are negative, we abs it and re-neg it later if necessary bool neg = numer_ < 0; numer_ = qAbs(numer_); intType d = gcd(numer_, denom_); if (d > 1) { numer_ /= d; denom_ /= d; } if (neg) { numer_ = -numer_; } } } //Function: finds greatest common denominator intType rational::gcd(const intType &x, const intType &y) { if (y == 0) { return x; } else { return gcd(y, x % y); } } //Function: convert to double double rational::toDouble() const { if (denom_ != 0) { return static_cast(numer_) / static_cast(denom_); } else { return static_cast(0); } } AVRational rational::toAVRational() const { AVRational r; r.num = static_cast(numer_); r.den = static_cast(denom_); return r; } rational rational::flipped() const { return rational(denom_, numer_); } bool rational::isNull() const { return denominator() == 0; } const intType &rational::numerator() const { return numer_; } const intType &rational::denominator() const { return denom_; } QString rational::toString() const { return QStringLiteral("%1/%2").arg(QString::number(numer_), QString::number(denom_)); } //Assignment Operators const rational& rational::operator=(const rational &rhs) { if (this != &rhs) { numer_ = rhs.numer_; denom_ = rhs.denom_; } return *this; } const rational& rational::operator+=(const rational &rhs) { if (!rhs.isNull()) { if (isNull()) { numer_ = rhs.numer_; denom_ = rhs.denom_; } else { numer_ = (numer_ * rhs.denom_) + (rhs.numer_ * denom_); denom_ = denom_ * rhs.denom_; fix_signs(); reduce(); } } return *this; } const rational& rational::operator-=(const rational &rhs) { if (!rhs.isNull()) { if (isNull()) { numer_ = -rhs.numer_; denom_ = rhs.denom_; } else { numer_ = (numer_ * rhs.denom_) - (rhs.numer_ * denom_); denom_ = denom_ * rhs.denom_; fix_signs(); reduce(); } } return *this; } const rational& rational::operator/=(const rational &rhs) { numer_ = numer_ * rhs.denom_; denom_ = denom_ * rhs.numer_; fix_signs(); reduce(); return *this; } const rational& rational::operator*=(const rational &rhs) { numer_ = numer_ * rhs.numer_; denom_ = denom_ * rhs.denom_; fix_signs(); reduce(); return *this; } //Binary math operators rational rational::operator+(const rational &rhs) const { rational answer(*this); answer += rhs; return answer; } rational rational::operator-(const rational &rhs) const { rational answer(*this); answer -= rhs; return answer; } rational rational::operator/(const rational &rhs) const { rational answer(*this); answer /= rhs; return answer; } rational rational::operator*(const rational &rhs) const { rational answer(*this); answer *= rhs; return answer; } //Relational and equality operators bool rational::operator<(const rational &rhs) const { if (isNull() && rhs.isNull()) { return false; } if (rhs == RATIONAL_MAX || *this == RATIONAL_MIN) { // We will always wither be LESS THAN (true) or EQUAL (false) return (*this != rhs); } if (*this == RATIONAL_MAX || rhs == RATIONAL_MIN) { // We will always be GREATER THAN (false) or EQUAL (false) return false; } if (!isNull() && rhs.isNull()) { return (numer_ * denom_ < intType(0)); } if (isNull() && !rhs.isNull()) { return !(rhs.numer_ * rhs.denom_ < intType(0)); } return ((numer_ * rhs.denom_) < (denom_ * rhs.numer_)); } bool rational::operator<=(const rational &rhs) const { if (isNull() && rhs.isNull()) { return true; } if (rhs == RATIONAL_MAX || *this == RATIONAL_MIN) { // We will always wither be LESS THAN (true) or EQUAL (true) return true; } if (*this == RATIONAL_MAX || rhs == RATIONAL_MIN) { // We will always be GREATER THAN (false) or EQUAL (true) return rhs == *this; } if (!isNull() && rhs.isNull()) { return (numer_ * denom_ < intType(0)); } if (isNull() && !rhs.isNull()) { return !(rhs.numer_ * rhs.denom_ < intType(0)); } return ((numer_ * rhs.denom_) <= (denom_ * rhs.numer_)); } bool rational::operator>(const rational &rhs) const { return rhs < *this; } bool rational::operator>=(const rational &rhs) const { return rhs <= *this; } bool rational::operator==(const rational &rhs) const { return (numer_ == rhs.numer_ && denom_ == rhs.denom_); } bool rational::operator!=(const rational &rhs) const { return (numer_ != rhs.numer_) || (denom_ != rhs.denom_); } //Unary operators const rational& rational::operator++() { numer_ += denom_; return *this; } rational rational::operator++(int) { rational tmp = *this; numer_ += denom_; return tmp; } const rational& rational::operator--() { numer_ -= denom_; return *this; } rational rational::operator--(int) { rational tmp; numer_ -= denom_; return tmp; } const rational& rational::operator+() const { return *this; } rational rational::operator-() const { return rational(numer_, -denom_); } bool rational::operator!() const { return !numer_; } //IO std::ostream& operator<<(std::ostream &out, const rational &value) { out << value.numer_; if (value.denom_ != 1) { out << '/' << value.denom_; return out; } return out; } std::istream& operator>>(std::istream &in, rational &value) { in >> value.numer_; value.denom_ = 1; char ch; in.get(ch); if(!in.eof()) { if(ch == '/') { in >> value.denom_; value.fix_signs(); value.reduce(); } else { in.putback(ch); } } return in; } uint qHash(const rational &r, uint seed) { return ::qHash(r.toDouble(), seed); } OLIVE_NAMESPACE_EXIT QDebug operator<<(QDebug debug, const OLIVE_NAMESPACE::rational &r) { return debug.space() << r.toDouble(); /* debug.nospace() << r.numerator() << "/" << r.denominator(); return debug.space(); */ } olive-continuous/app/common/rational.h000066400000000000000000000064001370472574300204460ustar00rootroot00000000000000//Copyright 2015 Adam Quintero //This program is distributed under the terms of the GNU General Public License. // Adapted by MattKC for the Olive Video Editor (2019) #ifndef RATIONAL_H #define RATIONAL_H #include #include #include extern "C" { #include } #include "common/define.h" OLIVE_NAMESPACE_ENTER typedef int64_t intType; /* * Zero Handling * 0/0 = 0 * 0/non-zero = 0 * non-zero/0 = 0 */ class rational { public: //constructors rational(const intType &numerator = 0) : numer_(numerator) { if (numer_ == 0) { denom_ = 0; } else { denom_ = 1; } } rational(const intType &numerator, const intType &denominator) : numer_(numerator), denom_(denominator) { fix_signs(); reduce(); } rational(const rational &rhs) = default; rational(const AVRational& r) : numer_(r.num), denom_(r.den) { fix_signs(); reduce(); } static rational fromDouble(const double& flt); static rational fromString(const QString& str); //Assignment Operators const rational& operator=(const rational &rhs); const rational& operator+=(const rational &rhs); const rational& operator-=(const rational &rhs); const rational& operator/=(const rational &rhs); const rational& operator*=(const rational &rhs); //Binary math operators rational operator+(const rational &rhs) const; rational operator-(const rational &rhs) const; rational operator/(const rational &rhs) const; rational operator*(const rational &rhs) const; //Relational and equality operators bool operator<(const rational &rhs) const; bool operator<=(const rational &rhs) const; bool operator>(const rational &rhs) const; bool operator>=(const rational &rhs) const; bool operator==(const rational &rhs) const; bool operator!=(const rational &rhs) const; //Unary operators const rational& operator++(); //prefix rational operator++(int); //postfix const rational& operator--(); //prefix rational operator--(int); //postfix const rational& operator+() const; rational operator-() const; bool operator!() const; //Function: convert to double double toDouble() const; AVRational toAVRational() const; // Produce "flipped" version rational flipped() const; // Returns whether the rational is null or not bool isNull() const; //Function: print number to cout void print(std::ostream &out = std::cout) const; //IO friend std::ostream& operator<<(std::ostream &out, const rational &value); friend std::istream& operator>>(std::istream &in, rational &value); const intType& numerator() const; const intType& denominator() const; QString toString() const; private: //numerator and denominator intType numer_; intType denom_; //Function: ensures denom >= 0 void fix_signs(); //Function: ensures lowest form void reduce(); //Function: finds greatest common denominator static intType gcd(const intType &x, const intType &y); }; #define RATIONAL_MIN rational(INT64_MIN, 1) #define RATIONAL_MAX rational(INT64_MAX, 1) uint qHash(const rational& r, uint seed); OLIVE_NAMESPACE_EXIT QDebug operator<<(QDebug debug, const OLIVE_NAMESPACE::rational& r); Q_DECLARE_METATYPE(OLIVE_NAMESPACE::rational) #endif // RATIONAL_H olive-continuous/app/common/threadedobject.cpp000066400000000000000000000024021370472574300221350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "threadedobject.h" OLIVE_NAMESPACE_ENTER void ThreadedObject::LockDeletes() { threadobj_delete_lock_++; } void ThreadedObject::UnlockDeletes() { Q_ASSERT(AreDeletesLocked()); threadobj_delete_lock_--; } bool ThreadedObject::AreDeletesLocked() { return (threadobj_delete_lock_ > 0); } void ThreadedObject::LockMutex() { threadobj_main_lock_.lock(); } void ThreadedObject::UnlockMutex() { threadobj_main_lock_.unlock(); } bool ThreadedObject::TryLockMutex(int timeout) { return threadobj_main_lock_.tryLock(timeout); } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/threadedobject.h000066400000000000000000000021771370472574300216130ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef THREADEDOBJECT_H #define THREADEDOBJECT_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ThreadedObject { public: void LockMutex(); void UnlockMutex(); bool TryLockMutex(int timeout = 0); void LockDeletes(); void UnlockDeletes(); bool AreDeletesLocked(); private: QMutex threadobj_main_lock_; QAtomicInt threadobj_delete_lock_; }; OLIVE_NAMESPACE_EXIT #endif // THREADEDOBJECT_H olive-continuous/app/common/timecodefunctions.cpp000066400000000000000000000220351370472574300227140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timecodefunctions.h" #include #include "config/config.h" OLIVE_NAMESPACE_ENTER QString padded(int64_t arg, int padding) { return QStringLiteral("%1").arg(arg, padding, 10, QChar('0')); } QString Timecode::timestamp_to_timecode(const int64_t ×tamp, const rational& timebase, const Display& display, bool show_plus_if_positive) { if (timebase.isNull()) { return QStringLiteral("INVALID TIMEBASE"); } double timestamp_dbl = (rational(timestamp) * timebase).toDouble(); switch (display) { case kTimecodeNonDropFrame: case kTimecodeDropFrame: case kTimecodeSeconds: { QString prefix; if (timestamp_dbl < 0) { prefix = "-"; } else if (show_plus_if_positive) { prefix = "+"; } if (display == kTimecodeSeconds) { timestamp_dbl = qAbs(timestamp_dbl); int64_t total_seconds = qFloor(timestamp_dbl); int64_t hours = total_seconds / 3600; int64_t mins = total_seconds / 60 - hours * 60; int64_t secs = total_seconds - mins * 60; int64_t fraction = qRound64((timestamp_dbl - static_cast(total_seconds)) * 1000); return QStringLiteral("%1%2:%3:%4.%5").arg(prefix, padded(hours, 2), padded(mins, 2), padded(secs, 2), padded(fraction, 3)); } else { // Determine what symbol to separate frames (";" is used for drop frame, ":" is non-drop frame) QString frame_token; double frame_rate = timebase.flipped().toDouble(); int rounded_frame_rate = qRound(frame_rate); int64_t frames, secs, mins, hours; int64_t f = qAbs(timestamp); if (display == kTimecodeDropFrame && TimebaseIsDropFrame(timebase)) { frame_token = ";"; /** * CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE * * Code by David Heidelberger, adapted from Andrew Duncan, further adapted for Olive by Olive Team * Given an int called framenumber and a double called framerate * Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off. */ // If frame number is greater than 24 hrs, next operation will rollover clock f %= (qRound(frame_rate*3600)*24); // Number of frames per ten minutes int64_t framesPer10Minutes = qRound(frame_rate * 600); int64_t d = f / framesPer10Minutes; int64_t m = f % framesPer10Minutes; // Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate int64_t dropFrames = qRound(frame_rate * (2.0/30.0)); // Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames f += dropFrames*9*d; if (m > dropFrames) { f += dropFrames * ((m - dropFrames) / (qRound(frame_rate)*60 - dropFrames)); } } else { frame_token = ":"; } // non-drop timecode hours = f / (3600*rounded_frame_rate); mins = f / (60*rounded_frame_rate) % 60; secs = f / rounded_frame_rate % 60; frames = f % rounded_frame_rate; return QStringLiteral("%1%2:%3:%4%5%6").arg(prefix, padded(hours, 2), padded(mins, 2), padded(secs, 2), frame_token, padded(frames, 2)); } } case kFrames: return QString::number(timestamp); case kMilliseconds: return QString::number(qRound(timestamp_dbl * 1000)); } return QStringLiteral("INVALID TIMECODE MODE"); } int64_t Timecode::timecode_to_timestamp(const QString &timecode, const rational &timebase, const Display &display, bool* ok) { double timebase_dbl = timebase.toDouble(); if (timecode.isEmpty()) { goto err_fatal; } switch (display) { case kTimecodeNonDropFrame: case kTimecodeDropFrame: case kTimecodeSeconds: { const int kTimecodeElementCount = 4; QStringList timecode_split = timecode.split(QRegExp("(:)|(;)|(\\.)")); bool valid; // We only deal with HH, MM, SS, and FF. Any values after that are ignored. while (timecode_split.size() > kTimecodeElementCount) { timecode_split.removeLast(); } // Convert values to integers QList timecode_numbers; foreach (const QString& element, timecode_split) { valid = true; timecode_numbers.append((element.isEmpty()) ? 0 : element.toLong(&valid)); // If element cannot be converted to a number, if (!valid) { goto err_fatal; } } // Ensure value size is always 4 while (timecode_numbers.size() < 4) { timecode_numbers.prepend(0); } double frame_rate = timebase.flipped().toDouble(); int rounded_frame_rate = qRound(frame_rate); int64_t hours = timecode_numbers.at(0); int64_t mins = timecode_numbers.at(1); int64_t secs = timecode_numbers.at(2); int64_t frames = timecode_numbers.at(3); int64_t sec_count = (hours*3600 + mins*60 + secs); int64_t timestamp = sec_count*rounded_frame_rate + frames; if (display == kTimecodeDropFrame && TimebaseIsDropFrame(timebase)) { // Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate int64_t dropFrames = qRound64(frame_rate * (2.0/30.0)); // d and m need to be calculated from int64_t real_fr_ts = qRound64(static_cast(sec_count)*frame_rate) + frames; int64_t framesPer10Minutes = qRound(frame_rate * 600); int64_t d = real_fr_ts / framesPer10Minutes; int64_t m = real_fr_ts % framesPer10Minutes; if (m > dropFrames) { timestamp -= dropFrames * ((m - dropFrames) / (qRound(frame_rate)*60 - dropFrames)); } timestamp -= dropFrames*9*d; } if (ok) *ok = true; return timestamp; } case kMilliseconds: { bool valid; double timecode_secs = timecode.toDouble(&valid); if (valid) { // Convert milliseconds to seconds timecode_secs *= 0.001; // Convert seconds to frames timecode_secs /= timebase_dbl; if (ok) *ok = true; return qRound(timecode_secs); } else { goto err_fatal; } } case kFrames: if (ok) *ok = true; return timecode.toLong(ok); } err_fatal: if (ok) *ok = false; return 0; } rational Timecode::snap_time_to_timebase(const rational &time, const rational &timebase) { // Just convert to a timestamp in timebase units and back int64_t timestamp = time_to_timestamp(time, timebase); return timestamp_to_time(timestamp, timebase); } rational Timecode::timestamp_to_time(const int64_t ×tamp, const rational &timebase) { return rational(timestamp) * timebase; } QString Timecode::time_to_timecode(const rational &time, const rational &timebase, const Timecode::Display &display, bool show_plus_if_positive) { return timestamp_to_timecode(time_to_timestamp(time, timebase), timebase, display, show_plus_if_positive); } bool Timecode::TimebaseIsDropFrame(const rational &timebase) { return (timebase.numerator() == 1001); } QString Timecode::TimeToString(int64_t ms) { int64_t total_seconds = ms / 1000; int64_t ss = total_seconds % 60; int64_t mm = (total_seconds / 60) % 60; int64_t hh = total_seconds / 3600; return QStringLiteral("%1:%2:%3") .arg(hh, 2, 10, QChar('0')) .arg(mm, 2, 10, QChar('0')) .arg(ss, 2, 10, QChar('0')); } int64_t Timecode::time_to_timestamp(const rational &time, const rational &timebase) { return time_to_timestamp(time.toDouble(), timebase); } int64_t Timecode::time_to_timestamp(const double &time, const rational &timebase) { return qRound64(time * timebase.flipped().toDouble()); } int64_t Timecode::rescale_timestamp(const int64_t &ts, const rational &source, const rational &dest) { return qRound64(static_cast(ts) * source.toDouble() / dest.toDouble()); } int64_t Timecode::rescale_timestamp_ceil(const int64_t &ts, const rational &source, const rational &dest) { return qCeil(static_cast(ts) * source.toDouble() / dest.toDouble()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/timecodefunctions.h000066400000000000000000000052561370472574300223670ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMECODEFUNCTIONS_H #define TIMECODEFUNCTIONS_H #include #include "common/rational.h" OLIVE_NAMESPACE_ENTER /** * @brief Functions for converting times/timecodes/timestamps * * Olive uses the following terminology through its code: * * `time` - time in seconds presented in a rational form * `timebase` - the base time unit of an audio/video stream in seconds * `timestamp` - an integer representation of a time in timebase units (in many cases is used like a frame number) * `timecode` a user-friendly string representation of a time according to Timecode::Display */ class Timecode { public: enum Display { kTimecodeDropFrame, kTimecodeNonDropFrame, kTimecodeSeconds, kFrames, kMilliseconds }; /** * @brief Convert a timestamp (according to a rational timebase) to a user-friendly string representation */ static QString timestamp_to_timecode(const int64_t ×tamp, const rational& timebase, const Display &display, bool show_plus_if_positive = false); static int64_t timecode_to_timestamp(const QString& timecode, const rational& timebase, const Display& display, bool *ok = nullptr); static rational snap_time_to_timebase(const rational& time, const rational& timebase); static int64_t time_to_timestamp(const rational& time, const rational& timebase); static int64_t time_to_timestamp(const double& time, const rational& timebase); static int64_t rescale_timestamp(const int64_t& ts, const rational& source, const rational& dest); static int64_t rescale_timestamp_ceil(const int64_t& ts, const rational& source, const rational& dest); static rational timestamp_to_time(const int64_t& timestamp, const rational& timebase); static QString time_to_timecode(const rational& time, const rational& timebase, const Display &display, bool show_plus_if_positive = false); static bool TimebaseIsDropFrame(const rational& timebase); static QString TimeToString(int64_t ms); }; OLIVE_NAMESPACE_EXIT #endif // TIMECODEFUNCTIONS_H olive-continuous/app/common/timerange.cpp000066400000000000000000000136211370472574300211460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timerange.h" #include OLIVE_NAMESPACE_ENTER TimeRange::TimeRange(const rational &in, const rational &out) : in_(in), out_(out) { normalize(); } const rational &TimeRange::in() const { return in_; } const rational &TimeRange::out() const { return out_; } const rational &TimeRange::length() const { return length_; } void TimeRange::set_in(const rational &in) { in_ = in; normalize(); } void TimeRange::set_out(const rational &out) { out_ = out; normalize(); } void TimeRange::set_range(const rational &in, const rational &out) { in_ = in; out_ = out; normalize(); } bool TimeRange::operator==(const TimeRange &r) const { return in() == r.in() && out() == r.out(); } bool TimeRange::operator!=(const TimeRange &r) const { return in() != r.in() || out() != r.out(); } bool TimeRange::OverlapsWith(const TimeRange &a, bool in_inclusive, bool out_inclusive) const { bool overlaps_in = (in_inclusive) ? (a.out() < in()) : (a.out() <= in()); bool overlaps_out = (out_inclusive) ? (a.in() > out()) : (a.in() >= out()); return !(overlaps_in || overlaps_out); } TimeRange TimeRange::Combined(const TimeRange &a) const { return Combine(a, *this); } bool TimeRange::Contains(const TimeRange &compare, bool in_inclusive, bool out_inclusive) const { bool contains_in = (in_inclusive) ? (compare.in() >= in()) : (compare.in() > in()); bool contains_out = (out_inclusive) ? (compare.out() <= out()) : (compare.out() < out()); return contains_in && contains_out; } bool TimeRange::Contains(const rational &r) const { return r >= in_ && r < out_; } TimeRange TimeRange::Combine(const TimeRange &a, const TimeRange &b) { return TimeRange(qMin(a.in(), b.in()), qMax(a.out(), b.out())); } TimeRange TimeRange::Intersected(const TimeRange &a) const { return Intersect(a, *this); } TimeRange TimeRange::Intersect(const TimeRange &a, const TimeRange &b) { return TimeRange(qMax(a.in(), b.in()), qMin(a.out(), b.out())); } TimeRange TimeRange::operator+(const rational &rhs) const { TimeRange answer(*this); answer += rhs; return answer; } TimeRange TimeRange::operator-(const rational &rhs) const { TimeRange answer(*this); answer -= rhs; return answer; } const TimeRange &TimeRange::operator+=(const rational &rhs) { set_range(in_ + rhs, out_ + rhs); return *this; } const TimeRange &TimeRange::operator-=(const rational &rhs) { set_range(in_ - rhs, out_ - rhs); return *this; } void TimeRange::normalize() { // If `out` is earlier than `in`, swap them if (out_ < in_) { std::swap(out_, in_); } // Calculate length length_ = out_ - in_; } void TimeRangeList::InsertTimeRange(const TimeRange &range) { for (int i=0;isize(); for (int i=0;iremoveAt(i); i--; sz--; } else if (compare.Contains(remove, false, false)) { // The remove range is within this element, only choice is to split the element into two TimeRange before(compare.in(), remove.in()); TimeRange after(remove.out(), compare.out()); this->removeAt(i); i--; sz--; InsertTimeRange(before); InsertTimeRange(after); } else if (compare.in() < remove.in() && compare.out() > remove.in()) { // This element's out point overlaps the range's in, we'll trim it compare.set_out(remove.in()); } else if (compare.in() < remove.out() && compare.out() > remove.out()) { // This element's in point overlaps the range's out, we'll trim it compare.set_in(remove.out()); } } } bool TimeRangeList::ContainsTimeRange(const TimeRange &range, bool in_inclusive, bool out_inclusive) const { for (int i=0;i= range.out()) { // No intersect continue; } else { // Crop the time range to the range and add it to the list TimeRange cropped(qMax(range.in(), compare.in()), qMin(range.out(), compare.out())); intersect_list.append(cropped); } } return intersect_list; } void TimeRangeList::PrintTimeList() { qDebug() << "TimeRangeList now contains:"; for (int i=0;i. ***/ #ifndef TIMERANGE_H #define TIMERANGE_H #include "rational.h" OLIVE_NAMESPACE_ENTER class TimeRange { public: TimeRange() = default; TimeRange(const rational& in, const rational& out); const rational& in() const; const rational& out() const; const rational& length() const; void set_in(const rational& in); void set_out(const rational& out); void set_range(const rational& in, const rational& out); bool operator==(const TimeRange& r) const; bool operator!=(const TimeRange& r) const; bool OverlapsWith(const TimeRange& a, bool in_inclusive = true, bool out_inclusive = true) const; bool Contains(const TimeRange& a, bool in_inclusive = true, bool out_inclusive = true) const; bool Contains(const rational& r) const; TimeRange Combined(const TimeRange& a) const; static TimeRange Combine(const TimeRange &a, const TimeRange &b); TimeRange Intersected(const TimeRange& a) const; static TimeRange Intersect(const TimeRange &a, const TimeRange &b); TimeRange operator+(const rational& rhs) const; TimeRange operator-(const rational& rhs) const; const TimeRange& operator+=(const rational &rhs); const TimeRange& operator-=(const rational &rhs); private: void normalize(); rational in_; rational out_; rational length_; }; class TimeRangeList : public QList { public: TimeRangeList() = default; TimeRangeList(std::initializer_list r) : QList(r) { } void InsertTimeRange(const TimeRange& range); void RemoveTimeRange(const TimeRange& remove); bool ContainsTimeRange(const TimeRange& range, bool in_inclusive = true, bool out_inclusive = true) const; TimeRangeList Intersects(const TimeRange& range) const; private: void PrintTimeList(); }; uint qHash(const TimeRange& r, uint seed); OLIVE_NAMESPACE_EXIT QDebug operator<<(QDebug debug, const OLIVE_NAMESPACE::TimeRange& r); Q_DECLARE_METATYPE(OLIVE_NAMESPACE::TimeRange) #endif // TIMERANGE_H olive-continuous/app/common/tohex.h000066400000000000000000000003431370472574300177640ustar00rootroot00000000000000#ifndef TOHEX_H #define TOHEX_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER inline QString ToHex(quint64 t) { return QStringLiteral("%1").arg(t, 0, 16); } OLIVE_NAMESPACE_EXIT #endif // TOHEX_H olive-continuous/app/common/xmlutils.cpp000066400000000000000000000061251370472574300210550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "xmlutils.h" #include "node/block/block.h" #include "node/factory.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER Node* XMLLoadNode(QXmlStreamReader* reader) { QString node_id; quintptr node_ptr = 0; QPointF node_pos; QString node_label; XMLAttributeLoop(reader, attr) { if (attr.name() == QStringLiteral("id")) { node_id = attr.value().toString(); } else if (attr.name() == QStringLiteral("ptr")) { node_ptr = attr.value().toULongLong(); } else if (attr.name() == QStringLiteral("pos")) { QStringList pos = attr.value().toString().split(':'); // Protection in case this file has been messed with if (pos.size() == 2) { node_pos.setX(pos.at(0).toDouble()); node_pos.setY(pos.at(1).toDouble()); } } else if (attr.name() == QStringLiteral("label")) { node_label = attr.value().toString(); } } if (node_id.isEmpty()) { qWarning() << "Found node with no ID"; return nullptr; } Node* node = NodeFactory::CreateFromID(node_id); if (node) { node->setProperty("xml_ptr", node_ptr); node->SetPosition(node_pos); node->SetLabel(node_label); } else { qWarning() << "Failed to load" << node_id << "- no node with that ID is installed"; } return node; } void XMLConnectNodes(const XMLNodeData &xml_node_data, QUndoCommand *command) { foreach (const XMLNodeData::SerializedConnection& con, xml_node_data.desired_connections) { NodeOutput* out = xml_node_data.output_ptrs.value(con.output); if (out) { if (command) { new NodeEdgeAddCommand(out, con.input, command); } else { NodeParam::ConnectEdge(out, con.input); } } } } bool XMLReadNextStartElement(QXmlStreamReader *reader) { QXmlStreamReader::TokenType token; while ((token = reader->readNext()) != QXmlStreamReader::Invalid && token != QXmlStreamReader::EndDocument) { if (reader->isEndElement()) { return false; } else if (reader->isStartElement()) { return true; } } return false; } void XMLLinkBlocks(const XMLNodeData &xml_node_data) { foreach (const XMLNodeData::BlockLink& l1, xml_node_data.block_links) { foreach (const XMLNodeData::BlockLink& l2, xml_node_data.block_links) { if (l1.link == l2.block->property("xml_ptr")) { Block::Link(l1.block, l2.block); break; } } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/common/xmlutils.h000066400000000000000000000036771370472574300205330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef XMLREADLOOP_H #define XMLREADLOOP_H #include #include #include "project/item/footage/stream.h" OLIVE_NAMESPACE_ENTER class Block; class Node; class NodeParam; class NodeInput; class NodeOutput; class Item; #define XMLAttributeLoop(reader, item) \ QXmlStreamAttributes __attributes = reader->attributes(); \ foreach (const QXmlStreamAttribute& item, __attributes) Node *XMLLoadNode(QXmlStreamReader* reader); struct XMLNodeData { struct SerializedConnection { NodeInput* input; quintptr output; }; struct FootageConnection { NodeInput* input; quintptr footage; }; struct BlockLink { Block* block; quintptr link; }; QHash output_ptrs; QList desired_connections; QHash footage_ptrs; QList footage_connections; QList block_links; QHash item_ptrs; QString real_project_url; QString saved_project_url; }; void XMLConnectNodes(const XMLNodeData& xml_node_data, QUndoCommand* command = nullptr); bool XMLReadNextStartElement(QXmlStreamReader* reader); void XMLLinkBlocks(const XMLNodeData& xml_node_data); OLIVE_NAMESPACE_EXIT #endif // XMLREADLOOP_H olive-continuous/app/config/000077500000000000000000000000001370472574300164415ustar00rootroot00000000000000olive-continuous/app/config/CMakeLists.txt000066400000000000000000000014331370472574300212020ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} config/config.h config/config.cpp PARENT_SCOPE ) olive-continuous/app/config/config.cpp000066400000000000000000000203541370472574300204160ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "config.h" #include #include #include #include #include #include #include "common/autoscroll.h" #include "common/filefunctions.h" #include "common/xmlutils.h" #include "core.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER Config Config::current_config_; Config::Config() { SetDefaults(); } QString Config::GetConfigFilePath() { return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("config.xml")); } Config &Config::Current() { return current_config_; } void Config::SetDefaults() { config_map_.clear(); config_map_["TimecodeDisplay"] = Timecode::kTimecodeDropFrame; config_map_["DefaultStillLength"] = QVariant::fromValue(rational(2)); config_map_["HoverFocus"] = false; config_map_["AudioScrubbing"] = true; config_map_["AutorecoveryInterval"] = 1; config_map_["Language"] = "en_US"; config_map_["ScrollZooms"] = false; config_map_["EnableSeekToImport"] = false; config_map_["EditToolAlsoSeeks"] = false; config_map_["EditToolSelectsLinks"] = false; config_map_["EnableDragFilesToTimeline"] = true; config_map_["InvertTimelineScrollAxes"] = true; config_map_["SelectAlsoSeeks"] = false; config_map_["PasteSeeks"] = true; config_map_["SelectAlsoSeeks"] = false; config_map_["SetNameWithMarker"] = false; config_map_["AutoSeekToBeginning"] = true; config_map_["DropFileOnMediaToReplace"] = false; config_map_["AddDefaultEffectsToClips"] = true; config_map_["AutoscaleByDefault"] = false; config_map_["Autoscroll"] = AutoScroll::kPage; config_map_["AutoSelectDivider"] = true; config_map_["SetNameWithMarker"] = false; config_map_["RectifiedWaveforms"] = false; config_map_["DropWithoutSequenceBehavior"] = TimelineWidget::kDWSAsk; config_map_["Loop"] = false; config_map_["AutoCacheInterval"] = 250; config_map_["NodeCatColor0"] = QVariant::fromValue(Color(0.75f, 0.75f, 0.75f)); config_map_["NodeCatColor1"] = QVariant::fromValue(Color(0.25f, 0.25f, 0.25f)); config_map_["NodeCatColor2"] = QVariant::fromValue(Color(0.75f, 0.75f, 0.25f)); config_map_["NodeCatColor3"] = QVariant::fromValue(Color(0.75f, 0.25f, 0.75f)); config_map_["NodeCatColor4"] = QVariant::fromValue(Color(0.25f, 0.75f, 0.75f)); config_map_["NodeCatColor5"] = QVariant::fromValue(Color(0.50f, 0.50f, 0.50f)); config_map_["NodeCatColor6"] = QVariant::fromValue(Color(0.25f, 0.75f, 0.25f)); config_map_["NodeCatColor7"] = QVariant::fromValue(Color(0.25f, 0.25f, 0.75f)); config_map_["NodeCatColor8"] = QVariant::fromValue(Color(0.75f, 0.25f, 0.25f)); config_map_["AudioOutput"] = QString(); config_map_["AudioInput"] = QString(); config_map_["DiskCachePath"] = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); config_map_["DiskCacheSize"] = 20.0; config_map_["DiskCacheBehind"] = QVariant::fromValue(rational(1)); config_map_["DiskCacheAhead"] = QVariant::fromValue(rational(5)); config_map_["ClearDiskCacheOnClose"] = false; config_map_["DefaultSequenceWidth"] = 1920; config_map_["DefaultSequenceHeight"] = 1080; config_map_["DefaultSequenceFrameRate"] = QVariant::fromValue(rational(1001, 30000)); config_map_["DefaultSequenceAudioFrequency"] = 48000; config_map_["DefaultSequenceAudioLayout"] = QVariant::fromValue(static_cast(AV_CH_LAYOUT_STEREO)); config_map_["DefaultSequencePreviewFormat"] = PixelFormat::PIX_FMT_RGBA16F; // Online/offline settings config_map_["OnlinePixelFormat"] = PixelFormat::PIX_FMT_RGBA32F; config_map_["OfflinePixelFormat"] = PixelFormat::PIX_FMT_RGBA16F; config_map_["OnlineOCIOMethod"] = ColorManager::kOCIOAccurate; config_map_["OfflineOCIOMethod"] = ColorManager::kOCIOFast; } void Config::Load() { QFile config_file(GetConfigFilePath()); if (!config_file.exists()) { return; } if (!config_file.open(QFile::ReadOnly)) { qWarning() << "Failed to load application settings. This session will use defaults."; return; } // Reset to defaults current_config_.SetDefaults(); QXmlStreamReader reader(&config_file); QString config_version; while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("Configuration")) { while (XMLReadNextStartElement(&reader)) { QString key = reader.name().toString(); QString value = reader.readElementText(); if (key == QStringLiteral("Version")) { config_version = value; if (!value.contains(".")) { qDebug() << "CONFIG: This is a 0.1.x config file, upconvert"; } } else if (key == QStringLiteral("DefaultSequenceFrameRate") && !config_version.contains('.')) { // 0.1.x stored this value as a float while we now use rationals, we'll use a heuristic to find the closest // supported rational qDebug() << " CONFIG: Finding closest match to" << value; double config_fr = value.toDouble(); QList supported_frame_rates = Core::SupportedFrameRates(); rational match = supported_frame_rates.first(); double match_diff = qAbs(match.toDouble() - config_fr); for (int i=1;imain_window(), QCoreApplication::translate("Config", "Error loading settings"), QCoreApplication::translate("Config", "Failed to load application settings. This session will " "use defaults.\n\n%1").arg(reader.errorString()), QMessageBox::Ok); current_config_.SetDefaults(); } config_file.close(); } void Config::Save() { QFile config_file(GetConfigFilePath()); if (!config_file.open(QFile::WriteOnly)) { QMessageBox::critical(Core::instance()->main_window(), QCoreApplication::translate("Config", "Error saving settings"), QCoreApplication::translate("Config", "Failed to save application settings. The application " "may lack write permissions to this location."), QMessageBox::Ok); return; } QXmlStreamWriter writer(&config_file); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement("Configuration"); // Anything after the hyphen is considered "unimportant" information writer.writeTextElement("Version", QCoreApplication::applicationVersion().split('-').first()); QMapIterator iterator(current_config_.config_map_); while (iterator.hasNext()) { iterator.next(); writer.writeTextElement(iterator.key(), iterator.value().toString()); } writer.writeEndElement(); // Configuration writer.writeEndDocument(); config_file.close(); } QVariant Config::operator[](const QString &key) const { return config_map_[key]; } QVariant &Config::operator[](const QString &key) { return config_map_[key]; } OLIVE_NAMESPACE_EXIT olive-continuous/app/config/config.h000066400000000000000000000023441370472574300200620ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CONFIG_H #define CONFIG_H #include #include #include #include "common/timecodefunctions.h" OLIVE_NAMESPACE_ENTER class Config { public: static Config& Current(); void SetDefaults(); static void Load(); static void Save(); QVariant operator[](const QString&) const; QVariant& operator[](const QString&); private: Config(); QMap config_map_; static Config current_config_; static QString GetConfigFilePath(); }; OLIVE_NAMESPACE_EXIT #endif // CONFIG_H olive-continuous/app/core.cpp000066400000000000000000001055451370472574300166420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "core.h" #include #include #include #include #include #include #include #include #include #include #include "audio/audiomanager.h" #include "cli/clitask/clitaskdialog.h" #include "common/filefunctions.h" #include "common/xmlutils.h" #include "config/config.h" #include "dialog/about/about.h" #include "dialog/export/export.h" #include "dialog/sequence/sequence.h" #include "dialog/task/task.h" #include "dialog/preferences/preferences.h" #include "dialog/projectproperties/projectproperties.h" #include "node/factory.h" #include "panel/panelmanager.h" #include "panel/project/project.h" #include "panel/viewer/viewer.h" #include "render/backend/opengl/opengltexturecache.h" #include "render/colormanager.h" #include "render/diskmanager.h" #include "render/pixelformat.h" #include "render/shaderinfo.h" #include "task/cache/cache.h" #include "task/project/import/import.h" #include "task/project/load/load.h" #include "task/project/save/save.h" #include "task/taskmanager.h" #include "ui/style/style.h" #include "undo/undostack.h" #include "widget/menu/menushared.h" #include "widget/taskview/taskviewitem.h" #include "widget/viewer/viewer.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER Core Core::instance_; Core::Core() : main_window_(nullptr), tool_(Tool::kPointer), addable_object_(Tool::kAddableEmpty), snapping_(true), gui_active_(false) { } Core *Core::instance() { return &instance_; } int Core::execute(QCoreApplication* a) { int exit_code = 1; // Start core OLIVE_NAMESPACE::Core::instance()->Start(); // // Parse command line arguments // QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); // Project from command line option // FIXME: What's the correct way to make a visually "optional" positional argument, or is manually adding square // brackets like this correct? parser.addPositionalArgument("[project]", tr("Project to open on startup")); // Create fullscreen option QCommandLineOption fullscreen_option({"f", "fullscreen"}, tr("Start in full screen mode")); parser.addOption(fullscreen_option); // Create headless export option QCommandLineOption headless_export_option({"x", "export"}, tr("Export project from command line")); parser.addOption(headless_export_option); // Parse options parser.process(*a); QStringList args = parser.positionalArguments(); // Detect project to load on startup if (!args.isEmpty()) { startup_project_ = args.first(); } gui_active_ = !parser.isSet(headless_export_option); if (gui_active_) { // Start GUI StartGUI(parser.isSet(fullscreen_option)); // If we have a startup QMetaObject::invokeMethod(this, "OpenStartupProject", Qt::QueuedConnection); // Run application loop and receive exit code exit_code = a->exec(); } else { if (parser.isSet(headless_export_option)) { // Start a headless export if (StartHeadlessExport()) { exit_code = 0; } } } // Clear core memory OLIVE_NAMESPACE::Core::instance()->Stop(); return exit_code; } void Core::DeclareTypesForQt() { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); } void Core::Start() { // Reset config (Config sets to default on construction already, but we do it again here as a workaround that fixes // the fact that some of the config paths set by default rely on the app name having been set (in main()) Config::Current().SetDefaults(); // Load application config Config::Load(); // Declare custom types for Qt signal/slot system DeclareTypesForQt(); // Set up node factory/library NodeFactory::Initialize(); // Set up color manager's default config ColorManager::SetUpDefaultConfig(); // Initialize task manager TaskManager::CreateInstance(); // Initialize OpenGL service OpenGLProxy::CreateInstance(); // // Start application // qInfo() << "Using Qt version:" << qVersion(); } void Core::Stop() { // Save Config //Config::Save(); // Save recently opened projects { QFile recent_projects_file(GetRecentProjectsFilePath()); if (recent_projects_file.open(QFile::WriteOnly | QFile::Text)) { QTextStream ts(&recent_projects_file); foreach (const QString& s, recent_projects_) { ts << s << "\n"; } recent_projects_file.close(); } } OpenGLProxy::DestroyInstance(); MenuShared::DestroyInstance(); TaskManager::DestroyInstance(); PanelManager::DestroyInstance(); AudioManager::DestroyInstance(); DiskManager::DestroyInstance(); PixelFormat::DestroyInstance(); NodeFactory::Destroy(); delete main_window_; } MainWindow *Core::main_window() { return main_window_; } UndoStack *Core::undo_stack() { return &undo_stack_; } void Core::ImportFiles(const QStringList &urls, ProjectViewModel* model, Folder* parent) { if (urls.isEmpty()) { QMessageBox::critical(main_window_, tr("Import error"), tr("Nothing to import")); return; } ProjectImportTask* pim = new ProjectImportTask(model, parent, urls); if (!pim->GetFileCount()) { // No files to import delete pim; return; } TaskDialog* task_dialog = new TaskDialog(pim, tr("Importing..."), main_window()); connect(task_dialog, &TaskDialog::TaskSucceeded, this, &Core::ImportTaskComplete); task_dialog->open(); } const Tool::Item &Core::tool() const { return tool_; } const Tool::AddableObject &Core::GetSelectedAddableObject() const { return addable_object_; } const QString &Core::GetSelectedTransition() const { return selected_transition_; } void Core::SetSelectedAddableObject(const Tool::AddableObject &obj) { addable_object_ = obj; } void Core::SetSelectedTransitionObject(const QString &obj) { selected_transition_ = obj; } void Core::ClearOpenRecentList() { recent_projects_.clear(); } void Core::CreateNewProject() { // If we already have an empty/new project, switch to it foreach (ProjectPtr already_open, open_projects_) { if (already_open->is_new()) { AddOpenProject(already_open); return; } } AddOpenProject(std::make_shared()); } const bool &Core::snapping() const { return snapping_; } const QStringList &Core::GetRecentProjects() const { return recent_projects_; } ProjectPtr Core::GetSharedPtrFromProject(Project *project) const { foreach (ProjectPtr p, open_projects_) { if (p.get() == project) { return p; } } return nullptr; } void Core::SetTool(const Tool::Item &tool) { tool_ = tool; emit ToolChanged(tool_); } void Core::SetSnapping(const bool &b) { snapping_ = b; emit SnappingChanged(snapping_); } void Core::DialogAboutShow() { AboutDialog a(main_window_); a.exec(); } void Core::DialogImportShow() { // Open dialog for user to select files QStringList files = QFileDialog::getOpenFileNames(main_window_, tr("Import footage...")); // Check if the user actually selected files to import if (!files.isEmpty()) { // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused(); Project* active_project; if (active_project_panel == nullptr // Check that we found a Project panel || (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project QMessageBox::critical(main_window_, tr("Failed to import footage"), tr("Failed to find active Project panel")); return; } // Get the selected folder in this panel Folder* folder = active_project_panel->GetSelectedFolder(); ImportFiles(files, active_project_panel->model(), folder); } } void Core::DialogPreferencesShow() { PreferencesDialog pd(main_window_, main_window_->menuBar()); pd.exec(); } void Core::DialogProjectPropertiesShow() { ProjectPtr proj = GetActiveProject(); if (proj) { ProjectPropertiesDialog ppd(proj.get(), main_window_); ppd.exec(); } else { QMessageBox::critical(main_window_, tr("No Active Project"), tr("No project is currently open to set the properties for"), QMessageBox::Ok); } } void Core::DialogExportShow() { TimeBasedPanel* latest_time_based = PanelManager::instance()->MostRecentlyFocused(); if (latest_time_based && latest_time_based->GetConnectedViewer()) { if (latest_time_based->GetConnectedViewer()->GetLength() == 0) { QMessageBox::critical(main_window_, tr("Error"), tr("This Sequence is empty. There is nothing to export."), QMessageBox::Ok); } else { ExportDialog ed(latest_time_based->GetConnectedViewer(), main_window_); ed.exec(); } } } void Core::CreateNewFolder() { // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused(); Project* active_project; if (active_project_panel == nullptr // Check that we found a Project panel || (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project QMessageBox::critical(main_window_, tr("Failed to create new folder"), tr("Failed to find active project")); return; } // Get the selected folder in this panel Folder* folder = active_project_panel->GetSelectedFolder(); // Create new folder ItemPtr new_folder = std::make_shared(); // Set a default name new_folder->set_name(tr("New Folder")); // Create an undoable command ProjectViewModel::AddItemCommand* aic = new ProjectViewModel::AddItemCommand(active_project_panel->model(), folder, new_folder); Core::instance()->undo_stack()->push(aic); // Trigger an automatic rename so users can enter the folder name active_project_panel->Edit(new_folder.get()); } void Core::CreateNewSequence() { ProjectPtr active_project = GetActiveProject(); if (!active_project) { QMessageBox::critical(main_window_, tr("Failed to create new sequence"), tr("Failed to find active project")); return; } // Create new sequence SequencePtr new_sequence = CreateNewSequenceForProject(active_project.get()); // Set all defaults for the sequence new_sequence->set_default_parameters(); SequenceDialog sd(new_sequence.get(), SequenceDialog::kNew, main_window_); // Make sure SequenceDialog doesn't make an undo command for editing the sequence, since we make an undo command for // adding it later on sd.SetUndoable(false); if (sd.exec() == QDialog::Accepted) { // Create an undoable command ProjectViewModel::AddItemCommand* aic = new ProjectViewModel::AddItemCommand(GetActiveProjectModel(), GetSelectedFolderInActiveProject(), new_sequence); new_sequence->add_default_nodes(); Core::instance()->undo_stack()->push(aic); Core::instance()->main_window()->OpenSequence(new_sequence.get()); } } void Core::AddOpenProject(ProjectPtr p) { // Ensure project is not open at the moment foreach (ProjectPtr already_open, open_projects_) { if (already_open == p) { // Signal UI to switch to this project emit ProjectOpened(p.get()); return; } } // If we currently have an empty project, close it first if (!open_projects_.isEmpty() && open_projects_.last()->is_new()) { CloseProject(open_projects_.last(), false); } connect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified); open_projects_.append(p); PushRecentlyOpenedProject(p->filename()); emit ProjectOpened(p.get()); } void Core::AddOpenProjectFromTask(Task *task) { QList projects = static_cast(task)->GetLoadedProjects(); QList layouts = static_cast(task)->GetLoadedLayouts(); for (int i=0; iLoadLayout(layouts.at(i)); } } void Core::ImportTaskComplete(Task* task) { QUndoCommand *command = static_cast(task)->GetCommand(); undo_stack_.pushIfHasChildren(command); } bool Core::ConfirmImageSequence(const QString& filename) { QMessageBox mb(main_window_); mb.setIcon(QMessageBox::Question); mb.setWindowTitle(tr("Possible image sequence detected")); mb.setText(tr("The file '%1' looks like it might be part of an image " "sequence. Would you like to import it as such?").arg(filename)); mb.addButton(QMessageBox::Yes); mb.addButton(QMessageBox::No); return (mb.exec() == QMessageBox::Yes); } void Core::ProjectWasModified(bool e) { //Project* p = static_cast(sender()); if (e) { // If this project is modified, we know for sure the window should show a "modified" flag (the * in the titlebar) main_window_->setWindowModified(true); } else { // If we just set this project to "not modified", see if all projects are not modified in which case we can hide // the modified flag foreach (ProjectPtr open, open_projects_) { if (open->is_modified()) { main_window_->setWindowModified(true); return; } } main_window_->setWindowModified(false); } } bool Core::StartHeadlessExport() { if (startup_project_.isEmpty()) { qCritical().noquote() << tr("You must specify a project file to export"); return false; } if (!QFileInfo::exists(startup_project_)) { qCritical().noquote() << tr("Specified project does not exist"); return false; } // Start a load task and try running it ProjectLoadTask plm(startup_project_); CLITaskDialog task_dialog(&plm); if (task_dialog.Run()) { ProjectPtr p = plm.GetLoadedProjects().first(); QList items = p->get_items_of_type(Item::kSequence); // Check if this project contains sequences if (items.isEmpty()) { qCritical().noquote() << tr("Project contains no sequences, nothing to export"); return false; } SequencePtr sequence = nullptr; // Check if this project contains multiple sequences if (items.size() > 1) { qInfo().noquote() << tr("This project has multiple sequences. Which do you wish to export?"); for (int i=0;iname().toStdString(); } QTextStream stream(stdin); QString sequence_read; int sequence_index = -1; QString quit_code = QStringLiteral("q"); std::string prompt = tr("Enter number (or %1 to cancel): ").arg(quit_code).toStdString(); forever { std::cout << prompt; stream.readLineInto(&sequence_read); if (!QString::compare(sequence_read, quit_code, Qt::CaseInsensitive)) { return false; } bool ok; sequence_index = sequence_read.toInt(&ok); if (ok && sequence_index >= 0 && sequence_index < items.size()) { break; } else { qCritical().noquote() << tr("Invalid sequence number"); } } sequence = std::static_pointer_cast(items.at(sequence_index)); } else { sequence = std::static_pointer_cast(items.first()); } ExportParams params; ExportTask export_task(sequence->viewer_output(), p->color_manager(), params); CLITaskDialog export_dialog(&export_task); if (export_dialog.Run()) { qInfo().noquote() << tr("Export succeeded"); return true; } else { qInfo().noquote() << tr("Export failed: %1").arg(export_task.GetError()); return false; } } else { qCritical().noquote() << tr("Project failed to load: %1").arg(plm.GetError()); return false; } } void Core::OpenStartupProject() { // Load startup project if (!startup_project_.isEmpty() && !QFileInfo::exists(startup_project_)) { QMessageBox::warning(main_window_, tr("Failed to open startup file"), tr("The project \"%1\" doesn't exist. A new project will be started instead.").arg(startup_project_), QMessageBox::Ok); startup_project_.clear(); } if (startup_project_.isEmpty()) { // If no load project is set, create a new one on open CreateNewProject(); } else { OpenProjectInternal(startup_project_); } } void Core::StartGUI(bool full_screen) { // Set UI style qApp->setStyle(QStyleFactory::create("Fusion")); StyleManager::SetStyle(StyleManager::DefaultStyle()); // Set up shared menus MenuShared::CreateInstance(); // Since we're starting GUI mode, create a PanelFocusManager (auto-deletes with QObject) PanelManager::CreateInstance(); // Initialize audio service AudioManager::CreateInstance(); // Initialize disk service DiskManager::CreateInstance(); // Initialize pixel service PixelFormat::CreateInstance(); // Connect the PanelFocusManager to the application's focus change signal connect(qApp, &QApplication::focusChanged, PanelManager::instance(), &PanelManager::FocusChanged); // Create main window and open it main_window_ = new MainWindow(); if (full_screen) { main_window_->showFullScreen(); } else { main_window_->showMaximized(); } // When a new project is opened, update the mainwindow connect(this, &Core::ProjectOpened, main_window_, &MainWindow::ProjectOpen); connect(this, &Core::ProjectClosed, main_window_, &MainWindow::ProjectClose); // Start autorecovery timer using the config value as its interval SetAutorecoveryInterval(Config::Current()["AutorecoveryInterval"].toInt()); autorecovery_timer_.start(); // Load recently opened projects list { QFile recent_projects_file(GetRecentProjectsFilePath()); if (recent_projects_file.open(QFile::ReadOnly | QFile::Text)) { QTextStream ts(&recent_projects_file); while (!ts.atEnd()) { recent_projects_.append(ts.readLine()); } recent_projects_file.close(); } } } void Core::SaveProjectInternal(ProjectPtr project) { // Create save manager ProjectSaveTask* psm = new ProjectSaveTask(project); TaskDialog* task_dialog = new TaskDialog(psm, tr("Save Project"), main_window_); connect(task_dialog, &TaskDialog::TaskSucceeded, this, &Core::ProjectSaveSucceeded); task_dialog->open(); } void Core::SaveAutorecovery() { foreach (ProjectPtr p, open_projects_) { if (!p->has_autorecovery_been_saved()) { // FIXME: SAVE AN AUTORECOVERY PROJECT p->set_autorecovery_saved(true); } } } void Core::ProjectSaveSucceeded(Task* task) { ProjectPtr p = static_cast(task)->GetProject(); PushRecentlyOpenedProject(p->filename()); p->set_modified(false); } ProjectPtr Core::GetActiveProject() const { ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused(); if (active_project_panel && active_project_panel->project()) { return GetSharedPtrFromProject(active_project_panel->project()); } return nullptr; } ProjectViewModel *Core::GetActiveProjectModel() const { ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused(); if (active_project_panel) { return active_project_panel->model(); } else { return nullptr; } } Folder *Core::GetSelectedFolderInActiveProject() const { ProjectPanel* active_project_panel = PanelManager::instance()->MostRecentlyFocused(); if (active_project_panel) { return active_project_panel->GetSelectedFolder(); } else { return nullptr; } } Timecode::Display Core::GetTimecodeDisplay() const { return static_cast(Config::Current()["TimecodeDisplay"].toInt()); } void Core::SetTimecodeDisplay(Timecode::Display d) { Config::Current()["TimecodeDisplay"] = d; emit TimecodeDisplayChanged(d); } void Core::SetAutorecoveryInterval(int minutes) { // Convert minutes to milliseconds autorecovery_timer_.setInterval(minutes * 60000); } void Core::CopyStringToClipboard(const QString &s) { QGuiApplication::clipboard()->setText(s); } QString Core::PasteStringFromClipboard() { return QGuiApplication::clipboard()->text(); } bool Core::SaveActiveProject() { ProjectPtr active_project = GetActiveProject(); if (active_project) { return SaveProject(active_project); } return false; } bool Core::SaveActiveProjectAs() { ProjectPtr active_project = GetActiveProject(); if (active_project) { return SaveProjectAs(active_project); } return false; } bool Core::SaveAllProjects() { foreach (ProjectPtr p, open_projects_) { if (!SaveProject(p)) { return false; } } return true; } bool Core::CloseActiveProject() { return CloseProject(GetActiveProject(), true); } bool Core::CloseAllExceptActiveProject() { ProjectPtr active_proj = GetActiveProject(); QList copy = open_projects_; foreach (ProjectPtr p, copy) { if (p != active_proj) { if (!CloseProject(p, true)) { return false; } } } return true; } QList Core::SupportedFrameRates() { QList frame_rates; frame_rates.append(rational(10, 1)); // 10 FPS frame_rates.append(rational(15, 1)); // 15 FPS frame_rates.append(rational(24000, 1001)); // 23.976 FPS frame_rates.append(rational(24, 1)); // 24 FPS frame_rates.append(rational(25, 1)); // 25 FPS frame_rates.append(rational(30000, 1001)); // 29.97 FPS frame_rates.append(rational(30, 1)); // 30 FPS frame_rates.append(rational(48000, 1001)); // 47.952 FPS frame_rates.append(rational(48, 1)); // 48 FPS frame_rates.append(rational(50, 1)); // 50 FPS frame_rates.append(rational(60000, 1001)); // 59.94 FPS frame_rates.append(rational(60, 1)); // 60 FPS return frame_rates; } QList Core::SupportedSampleRates() { QList sample_rates; sample_rates.append(8000); // 8000 Hz sample_rates.append(11025); // 11025 Hz sample_rates.append(16000); // 16000 Hz sample_rates.append(22050); // 22050 Hz sample_rates.append(24000); // 24000 Hz sample_rates.append(32000); // 32000 Hz sample_rates.append(44100); // 44100 Hz sample_rates.append(48000); // 48000 Hz sample_rates.append(88200); // 88200 Hz sample_rates.append(96000); // 96000 Hz return sample_rates; } QList Core::SupportedChannelLayouts() { QList channel_layouts; channel_layouts.append(AV_CH_LAYOUT_MONO); channel_layouts.append(AV_CH_LAYOUT_STEREO); channel_layouts.append(AV_CH_LAYOUT_2_1); channel_layouts.append(AV_CH_LAYOUT_5POINT1); channel_layouts.append(AV_CH_LAYOUT_7POINT1); return channel_layouts; } QList Core::SupportedDividers() { return {1, 2, 3, 4, 6, 8, 12, 16}; } QString Core::FrameRateToString(const rational &frame_rate) { return tr("%1 FPS").arg(frame_rate.toDouble()); } QString Core::SampleRateToString(const int &sample_rate) { return tr("%1 Hz").arg(sample_rate); } QString Core::ChannelLayoutToString(const uint64_t &layout) { switch (layout) { case AV_CH_LAYOUT_MONO: return tr("Mono"); case AV_CH_LAYOUT_STEREO: return tr("Stereo"); case AV_CH_LAYOUT_2_1: return tr("2.1"); case AV_CH_LAYOUT_5POINT1: return tr("5.1"); case AV_CH_LAYOUT_7POINT1: return tr("7.1"); default: return tr("Unknown (0x%1)").arg(layout, 1, 16); } } QString Core::GetProjectFilter() { return QStringLiteral("%1 (*.ove)").arg(tr("Olive Project")); } QString Core::GetRecentProjectsFilePath() { return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("recent")); } bool Core::SaveProject(ProjectPtr p) { if (p->filename().isEmpty()) { return SaveProjectAs(p); } else { SaveProjectInternal(p); return true; } } bool Core::SaveProjectAs(ProjectPtr p) { QString fn = QFileDialog::getSaveFileName(main_window_, tr("Save Project As"), QString(), GetProjectFilter()); if (!fn.isEmpty()) { QString extension(QStringLiteral(".ove")); if (!fn.endsWith(extension, Qt::CaseInsensitive)) { fn.append(extension); } p->set_filename(fn); SaveProjectInternal(p); return true; } return false; } void Core::PushRecentlyOpenedProject(const QString& s) { if (s.isEmpty()) { return; } int existing_index = recent_projects_.indexOf(s); if (existing_index >= 0) { recent_projects_.move(existing_index, 0); } else { recent_projects_.prepend(s); } } void Core::OpenProjectInternal(const QString &filename) { // See if this project is open already foreach (ProjectPtr p, open_projects_) { if (p->filename() == filename) { // This project is already open AddOpenProject(p); return; } } ProjectLoadTask* plm = new ProjectLoadTask(filename); TaskDialog* task_dialog = new TaskDialog(plm, tr("Load Project"), main_window()); connect(task_dialog, &TaskDialog::TaskSucceeded, this, &Core::AddOpenProjectFromTask); task_dialog->open(); } int Core::CountFilesInFileList(const QFileInfoList &filenames) { int file_count = 0; foreach (const QFileInfo& f, filenames) { // For some reason QDir::NoDotAndDotDot doesn't work with entryInfoList, so we have to check manually if (f.fileName() == "." || f.fileName() == "..") { continue; } else if (f.isDir()) { QFileInfoList info_list = QDir(f.absoluteFilePath()).entryInfoList(); file_count += CountFilesInFileList(info_list); } else { file_count++; } } return file_count; } QString GetRenderModePreferencePrefix(RenderMode::Mode mode, const QString &preference) { QString key; key.append((mode == RenderMode::kOffline) ? QStringLiteral("Offline") : QStringLiteral("Online")); key.append(preference); return key; } QVariant Core::GetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference) { return Config::Current()[GetRenderModePreferencePrefix(mode, preference)]; } void Core::SetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference, const QVariant &value) { Config::Current()[GetRenderModePreferencePrefix(mode, preference)] = value; } void Core::LabelNodes(const QList &nodes) const { if (nodes.isEmpty()) { return; } bool ok; QString start_label = nodes.first()->GetLabel(); for (int i=1; iGetLabel() != start_label) { // Not all the nodes share the same name, so we'll start with a blank one start_label.clear(); break; } } QString s = QInputDialog::getText(main_window_, tr("Label Node"), tr("Set node label"), QLineEdit::Normal, start_label, &ok); if (ok) { foreach (Node* n, nodes) { n->SetLabel(s); } } } SequencePtr Core::CreateNewSequenceForProject(Project* project) const { SequencePtr new_sequence = std::make_shared(); // Get default name for this sequence (in the format "Sequence N", the first that doesn't exist) int sequence_number = 1; QString sequence_name; do { sequence_name = tr("Sequence %1").arg(sequence_number); sequence_number++; } while (project->root()->ChildExistsWithName(sequence_name)); new_sequence->set_name(sequence_name); return new_sequence; } void Core::OpenProjectFromRecentList(int index) { const QString& open_fn = recent_projects_.at(index); if (QFileInfo::exists(open_fn)) { OpenProjectInternal(open_fn); } else if (QMessageBox::information(main_window(), tr("Cannot open recent project"), tr("The project \"%1\" doesn't exist. Would you like to remove this file from the recent list?").arg(open_fn), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { recent_projects_.removeAt(index); } } bool Core::CloseProject(ProjectPtr p, bool auto_open_new) { CloseProjectBehavior b = kCloseProjectOnlyOne; return CloseProject(p, auto_open_new, b); } bool Core::CloseProject(ProjectPtr p, bool auto_open_new, CloseProjectBehavior &confirm_behavior) { for (int i=0;iis_modified() && confirm_behavior != kCloseProjectDontSave) { bool save_this_project; if (confirm_behavior == kCloseProjectAsk || confirm_behavior == kCloseProjectOnlyOne) { QMessageBox mb(main_window_); mb.setWindowModality(Qt::WindowModal); mb.setIcon(QMessageBox::Question); mb.setWindowTitle(tr("Unsaved Changes")); mb.setText(tr("The project '%1' has unsaved changes. Would you like to save them?") .arg(p->name())); QPushButton* yes_btn = mb.addButton(tr("Save"), QMessageBox::YesRole); QPushButton* yes_to_all_btn; if (confirm_behavior == kCloseProjectOnlyOne) { yes_to_all_btn = nullptr; } else { yes_to_all_btn = mb.addButton(tr("Save All"), QMessageBox::YesRole); } mb.addButton(tr("Don't Save"), QMessageBox::NoRole); QPushButton* no_to_all_btn; if (confirm_behavior == kCloseProjectOnlyOne) { no_to_all_btn = nullptr; } else { no_to_all_btn = mb.addButton(tr("Don't Save All"), QMessageBox::NoRole); } QPushButton* cancel_btn = mb.addButton(QMessageBox::Cancel); mb.exec(); if (mb.clickedButton() == cancel_btn) { // Stop closing projects if the user clicked cancel return false; } else if (mb.clickedButton() == yes_to_all_btn) { // Set flag that other CloseProject commands are going to use confirm_behavior = kCloseProjectSave; } else if (mb.clickedButton() == no_to_all_btn) { // Set flag that other CloseProject commands are going to use confirm_behavior = kCloseProjectDontSave; } save_this_project = (mb.clickedButton() == yes_btn || mb.clickedButton() == yes_to_all_btn); } else { // We must be saving this project save_this_project = true; } if (save_this_project && !SaveProject(p)) { // The save failed, stop closing projects return false; } } // For safety, the undo stack is cleared so no commands try to affect a freed project undo_stack_.clear(); disconnect(p.get(), &Project::ModifiedChanged, this, &Core::ProjectWasModified); emit ProjectClosed(p.get()); open_projects_.removeAt(i); break; } } // Ensure a project is always active if (auto_open_new && open_projects_.isEmpty()) { CreateNewProject(); } return true; } bool Core::CloseAllProjects(bool auto_open_new) { QList copy = open_projects_; // See how many projects are modified so we can set "behavior" correctly // (i.e. whether to show "Yes/No To All" buttons or not) int modified_count = 0; foreach (ProjectPtr p, copy) { if (p->is_modified()) { modified_count++; } } CloseProjectBehavior behavior; if (modified_count > 1) { behavior = kCloseProjectAsk; } else { behavior = kCloseProjectOnlyOne; } foreach (ProjectPtr p, copy) { // If this is the only remaining project and the user hasn't chose "yes/no to all", hide those buttons if (modified_count == 1 && behavior == kCloseProjectAsk) { behavior = kCloseProjectOnlyOne; } if (!CloseProject(p, auto_open_new, behavior)) { return false; } modified_count--; } return true; } void Core::CacheActiveSequence(bool in_out_only) { TimeBasedPanel* p = PanelManager::instance()->MostRecentlyFocused(); if (p && p->GetConnectedViewer()) { CacheTask* task = new CacheTask(p->GetConnectedViewer(), p->GetConnectedViewer()->video_params(), p->GetConnectedViewer()->audio_params(), in_out_only); // Stop any current auto-cache tasks ViewerWidget::StopAllBackgroundCacheTasks(true); ViewerWidget::SetBackgroundCacheTask(task); TaskDialog* dialog = new TaskDialog(task, tr("Caching Sequence"), main_window_); connect(dialog, &TaskDialog::TaskSucceeded, this, [] { ViewerWidget::SetBackgroundCacheTask(nullptr); }); dialog->open(); } } bool Core::CloseAllProjects() { return CloseAllProjects(true); } void Core::OpenProject() { QString file = QFileDialog::getOpenFileName(main_window_, tr("Open Project"), QString(), GetProjectFilter()); if (!file.isEmpty()) { OpenProjectInternal(file); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/core.h000066400000000000000000000314271370472574300163040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CORE_H #define CORE_H #include #include #include #include "common/rational.h" #include "common/timecodefunctions.h" #include "project/item/footage/footage.h" #include "project/item/sequence/sequence.h" #include "project/project.h" #include "project/projectviewmodel.h" #include "task/task.h" #include "tool/tool.h" #include "undo/undostack.h" OLIVE_NAMESPACE_ENTER class MainWindow; /** * @brief The main central Olive application instance * * This runs both in GUI and CLI modes (and handles what to init based on that). * It also contains various global functions/variables for use throughout Olive. * * The "public slots" are usually user-triggered actions and can be connected to UI elements (e.g. creating a folder, * opening the import dialog, etc.) */ class Core : public QObject { Q_OBJECT public: /** * @brief Core Constructor * * Currently empty */ Core(); /** * @brief Core object accessible from anywhere in the code * * Use this to access Core functions. */ static Core* instance(); int execute(QCoreApplication *a); /** * @brief Start Olive Core * * Main application launcher. Parses command line arguments and constructs main window (if entering a GUI mode). */ void Start(); /** * @brief Stop Olive Core * * Ends all threads and frees all memory ready for the application to exit. */ void Stop(); /** * @brief Retrieve main window instance * * @return * * Pointer to the olive::MainWindow object, or nullptr if running in CLI mode. */ MainWindow* main_window(); /** * @brief Retrieve UndoStack object */ UndoStack* undo_stack(); /** * @brief Import a list of files * * FIXME: I kind of hate this, it needs a model to update correctly. Is there a way that Items can signal enough to * make passing references to the model unnecessary? * * @param urls */ void ImportFiles(const QStringList& urls, ProjectViewModel *model, Folder *parent); /** * @brief Get the currently active tool */ const Tool::Item& tool() const; /** * @brief Get the currently selected object that the add tool should make (if the add tool is active) */ const Tool::AddableObject& GetSelectedAddableObject() const; /** * @brief Get the currently selected node that the transition tool should make (if the transition tool is active) */ const QString& GetSelectedTransition() const; /** * @brief Get current snapping value */ const bool& snapping() const; /** * @brief Returns a list of the most recently opened/saved projects */ const QStringList& GetRecentProjects() const; /** * @brief Convenience function to retrieve a Project's shared pointer */ ProjectPtr GetSharedPtrFromProject(Project* project) const; /** * @brief Get the currently active project * * Uses the UI/Panel system to determine which Project was the last focused on and assumes this is the active Project * that the user wishes to work on. * * @return * * The active Project file, or nullptr if the heuristic couldn't find one. */ ProjectPtr GetActiveProject() const; ProjectViewModel* GetActiveProjectModel() const; Folder* GetSelectedFolderInActiveProject() const; /** * @brief Gets current timecode display mode */ Timecode::Display GetTimecodeDisplay() const; /** * @brief Sets current timecode display mode */ void SetTimecodeDisplay(Timecode::Display d); /** * @brief Set how frequently an autorecovery should be saved (if the project has changed, see SetProjectModified()) */ void SetAutorecoveryInterval(int minutes); static void CopyStringToClipboard(const QString& s); static QString PasteStringFromClipboard(); /** * @brief Return a list of supported frame rates in rational form * * These rationals can be flipped to create a timebase in this frame rate. */ static QList SupportedFrameRates(); /** * @brief Return a list of supported sample rates in integer form */ static QList SupportedSampleRates(); /** * @brief Return a list of supported channel layouts as or'd flags */ static QList SupportedChannelLayouts(); /** * @brief Return a list of supported dividers */ static QList SupportedDividers(); /** * @brief Convert rational frame rate (i.e. flipped timebase) to a user-friendly string */ static QString FrameRateToString(const rational& frame_rate); /** * @brief Convert integer sample rate to a user-friendly string */ static QString SampleRateToString(const int &sample_rate); /** * @brief Convert channel layout to a user-friendly string */ static QString ChannelLayoutToString(const uint64_t &layout); /** * @brief Recursively count files in a file/directory list */ static int CountFilesInFileList(const QFileInfoList &filenames); static QVariant GetPreferenceForRenderMode(RenderMode::Mode mode, const QString& preference); static void SetPreferenceForRenderMode(RenderMode::Mode mode, const QString& preference, const QVariant& value); /** * @brief Show a dialog to the user to rename a set of nodes */ void LabelNodes(const QList& nodes) const; /** * @brief Create a new sequence named appropriately for the active project */ SequencePtr CreateNewSequenceForProject(Project *project) const; /** * @brief Opens a project from the recently opened list */ void OpenProjectFromRecentList(int index); enum CloseProjectBehavior { kCloseProjectOnlyOne, kCloseProjectAsk, kCloseProjectSave, kCloseProjectDontSave }; /** * @brief Closes a project */ bool CloseProject(ProjectPtr p, bool auto_open_new, CloseProjectBehavior& confirm_behavior); bool CloseProject(ProjectPtr p, bool auto_open_new); /** * @brief Closes all open projects */ bool CloseAllProjects(bool auto_open_new); /** * @brief Runs a modal cache task on the currently active sequence */ void CacheActiveSequence(bool in_out_only); public slots: /** * @brief Starts an open file dialog to load a project from file */ void OpenProject(); /** * @brief Save the currently active project * * If the project hasn't been saved before, this will be equivalent to calling SaveActiveProjectAs(). */ bool SaveActiveProject(); /** * @brief Save the currently active project with a new filename */ bool SaveActiveProjectAs(); /** * @brief Save all currently open projects */ bool SaveAllProjects(); /** * @brief Closes the active project * * If no other projects are open, a new one is created automatically. */ bool CloseActiveProject(); /** * @brief Closes all projects except the active project */ bool CloseAllExceptActiveProject(); /** * @brief Closes all open projects * * Equivalent to `CloseAllProjects(true)`, but useful for the signal/slot system where you may not be able to specify * parameters. */ bool CloseAllProjects(); /** * @brief Set the current application-wide tool * * @param tool */ void SetTool(const Tool::Item& tool); /** * @brief Set the current snapping setting */ void SetSnapping(const bool& b); /** * @brief Show an About dialog */ void DialogAboutShow(); /** * @brief Open the import footage dialog and import the files selected (runs ImportFiles()) */ void DialogImportShow(); /** * @brief Show Preferences dialog */ void DialogPreferencesShow(); /** * @brief Show Project Properties dialog */ void DialogProjectPropertiesShow(); /** * @brief Show Export dialog */ void DialogExportShow(); /** * @brief Create a new folder in the currently active project */ void CreateNewFolder(); /** * @brief Create a new sequence in the currently active project */ void CreateNewSequence(); /** * @brief Set the currently selected object that the add tool should make */ void SetSelectedAddableObject(const Tool::AddableObject& obj); /** * @brief Set the currently selected object that the add tool should make */ void SetSelectedTransitionObject(const QString& obj); /** * @brief Clears the list of recently opened/saved projects */ void ClearOpenRecentList(); /** * @brief Creates a new empty project and opens it */ void CreateNewProject(); signals: /** * @brief Signal emitted when a project is opened * * Connects to main window so its UI can update based on the project * * @param p */ void ProjectOpened(Project* p); /** * @brief Signal emitted when a project is closed */ void ProjectClosed(Project* p); /** * @brief Signal emitted when the tool is changed from somewhere */ void ToolChanged(const Tool::Item& tool); /** * @brief Signal emitted when the snapping setting is changed */ void SnappingChanged(const bool& b); /** * @brief Signal emitted when the default timecode display mode changed */ void TimecodeDisplayChanged(Timecode::Display d); private: /** * @brief Get the file filter than can be used with QFileDialog to open and save compatible projects */ static QString GetProjectFilter(); /** * @brief Returns the filename where the recently opened/saved projects should be stored */ static QString GetRecentProjectsFilePath(); /** * @brief Saves a specific project */ bool SaveProject(ProjectPtr p); /** * @brief Performs a "save as" on a specific project */ bool SaveProjectAs(ProjectPtr p); /** * @brief Adds a filename to the top of the recently opened projects list (or moves it if it already exists) */ void PushRecentlyOpenedProject(const QString &s); /** * @brief Declare custom types/classes for Qt's signal/slot system * * Qt's signal/slot system requires types to be declared. In the interest of doing this only at startup, we contain * them all in a function here. */ void DeclareTypesForQt(); /** * @brief Start GUI portion of Olive * * Starts services and objects required for the GUI of Olive. It's guaranteed that running without this function will * create an application instance that is completely valid minus the UI (e.g. for CLI modes). */ void StartGUI(bool full_screen); /** * @brief Internal function for saving a project to a file */ void SaveProjectInternal(ProjectPtr project); /** * @brief Internal main window object */ MainWindow* main_window_; /** * @brief Internal startup project object * * If the user specifies a project file on the command line, the command line parser in Start() will write the * project URL here to be loaded once Olive has finished initializing. */ QString startup_project_; /** * @brief List of currently open projects */ QList open_projects_; /** * @brief Currently active tool */ Tool::Item tool_; /** * @brief Currently active addable object */ Tool::AddableObject addable_object_; /** * @brief Currently selected transition */ QString selected_transition_; /** * @brief Current snapping setting */ bool snapping_; /** * @brief Internal timer for saving autorecovery files */ QTimer autorecovery_timer_; /** * @brief Application-wide undo stack instance */ UndoStack undo_stack_; /** * @brief List of most recently opened/saved projects */ QStringList recent_projects_; /** * @brief Internal variable for whether the GUI is active */ bool gui_active_; /** * @brief Static singleton core instance */ static Core instance_; private slots: void SaveAutorecovery(); void ProjectSaveSucceeded(Task *task); /** * @brief Adds a project to the "open projects" list */ void AddOpenProject(OLIVE_NAMESPACE::ProjectPtr p); void AddOpenProjectFromTask(Task* task); void ImportTaskComplete(Task *task); bool ConfirmImageSequence(const QString &filename); void ProjectWasModified(bool e); bool StartHeadlessExport(); void OpenStartupProject(); /** * @brief Internal project open */ void OpenProjectInternal(const QString& filename); }; OLIVE_NAMESPACE_EXIT #endif // CORE_H olive-continuous/app/dialog/000077500000000000000000000000001370472574300164335ustar00rootroot00000000000000olive-continuous/app/dialog/CMakeLists.txt000066400000000000000000000022201370472574300211670ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(about) add_subdirectory(actionsearch) add_subdirectory(color) add_subdirectory(export) add_subdirectory(footageproperties) add_subdirectory(keyframeproperties) add_subdirectory(preferences) add_subdirectory(progress) add_subdirectory(projectproperties) add_subdirectory(rendercancel) add_subdirectory(richtext) add_subdirectory(sequence) add_subdirectory(speedduration) add_subdirectory(task) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/dialog/about/000077500000000000000000000000001370472574300175455ustar00rootroot00000000000000olive-continuous/app/dialog/about/CMakeLists.txt000066400000000000000000000014451370472574300223110ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/about/about.h dialog/about/about.cpp PARENT_SCOPE ) olive-continuous/app/dialog/about/about.cpp000066400000000000000000000054061370472574300213700ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "about.h" #include #include #include #include OLIVE_NAMESPACE_ENTER AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("About %1").arg(QApplication::applicationName())); QVBoxLayout* layout = new QVBoxLayout(this); //layout->setSpacing(20); // Construct About text QLabel* label = new QLabel(QStringLiteral("" "

" "

" "" "https://www.olivevideoeditor.org/" "

" "

%1 %2

" // AppName (version identifier) "

%3

" // First statement "

%4

" // Second statement "").arg(QApplication::applicationName(), QApplication::applicationVersion(), tr("Olive is a non-linear video editor. This software is free and " "protected by the GNU GPL."), tr("Olive Team is obliged to inform users that Olive source code is " "available for download from its website.")),this); // Set text formatting label->setAlignment(Qt::AlignCenter); label->setTextInteractionFlags(Qt::TextSelectableByMouse); label->setCursor(Qt::IBeamCursor); label->setWordWrap(true); layout->addWidget(label); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok, this); buttons->setCenterButtons(true); layout->addWidget(buttons); connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/about/about.h000066400000000000000000000024601370472574300210320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef ABOUTDIALOG_H #define ABOUTDIALOG_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief The AboutDialog class * * The About dialog (accessible through Help > About). Contains license and version information. This can be run from * anywhere */ class AboutDialog : public QDialog { Q_OBJECT public: /** * @brief AboutDialog Constructor * * Creates About dialog. * * @param parent * * QWidget parent object. Usually this will be MainWindow. */ explicit AboutDialog(QWidget *parent = nullptr); }; OLIVE_NAMESPACE_EXIT #endif // ABOUTDIALOG_H olive-continuous/app/dialog/actionsearch/000077500000000000000000000000001370472574300210765ustar00rootroot00000000000000olive-continuous/app/dialog/actionsearch/CMakeLists.txt000066400000000000000000000015011370472574300236330ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/actionsearch/actionsearch.h dialog/actionsearch/actionsearch.cpp PARENT_SCOPE ) olive-continuous/app/dialog/actionsearch/actionsearch.cpp000066400000000000000000000203221370472574300242440ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "actionsearch.h" #include #include #include #include OLIVE_NAMESPACE_ENTER ActionSearch::ActionSearch(QWidget *parent) : QDialog(parent), menu_bar_(nullptr) { // ActionSearch requires a parent widget Q_ASSERT(parent != nullptr); // Set styling (object name is required for CSS specific to this object) setObjectName("ASDiag"); setStyleSheet("#ASDiag{border: 2px solid #808080;}"); // Size proportionally to the parent (usually MainWindow). resize(parent->width()/3, parent->height()/3); // Show dialog as a "popup", which will make the dialog close if the user clicks out of it. setWindowFlags(Qt::Popup); QVBoxLayout* layout = new QVBoxLayout(this); // Construct the main entry text field. ActionSearchEntry* entry_field = new ActionSearchEntry(this); // Set the main entry field font size to 1.2x its standard font size. QFont entry_field_font = entry_field->font(); entry_field_font.setPointSize(qRound(entry_field_font.pointSize()*1.2)); entry_field->setFont(entry_field_font); // Set placeholder text for the main entry field entry_field->setPlaceholderText(tr("Search for action...")); // Connect signals/slots connect(entry_field, SIGNAL(textChanged(const QString&)), this, SLOT(search_update(const QString &))); connect(entry_field, SIGNAL(returnPressed()), this, SLOT(perform_action())); // moveSelectionUp() and moveSelectionDown() are emitted when the user pressed up or down on the text field. // We override it here to select the upper or lower item in the list. connect(entry_field, SIGNAL(moveSelectionUp()), this, SLOT(move_selection_up())); connect(entry_field, SIGNAL(moveSelectionDown()), this, SLOT(move_selection_down())); layout->addWidget(entry_field); // Construct list of actions list_widget = new ActionSearchList(this); // Set list's font to 1.2x its standard font size QFont list_widget_font = list_widget->font(); list_widget_font.setPointSize(qRound(list_widget_font.pointSize()*1.2)); list_widget->setFont(list_widget_font); layout->addWidget(list_widget); connect(list_widget, SIGNAL(dbl_click()), this, SLOT(perform_action())); // Instantly focus on the entry field to allow for fully keyboard operation (if this popup was initiated by keyboard // shortcut for example). entry_field->setFocus(); } void ActionSearch::SetMenuBar(QMenuBar *menu_bar) { menu_bar_ = menu_bar; } void ActionSearch::search_update(const QString &s, const QString &p, QMenu *parent) { // Do nothing if there's no menu bar to work with if (menu_bar_ == nullptr) { return; } // This function is recursive, using the `parent` parameter to loop through a menu's items. It functions in two // modes - the parent being NULL, meaning it'll get MainWindow's menubar and loop over its menus, and the parent // referring to a menu at which point it'll loop over its actions (and call itself recursively if it finds any // submenus). if (parent == nullptr) { // If parent is NULL, we'll pull from the MainWindow's menubar and call this recursively on all of its submenus // (and their submenus). // We'll clear all the current items in the list since if we're here, we're just starting. list_widget->clear(); QList menus = menu_bar_->actions(); // Loop through all menus from the menubar and run this function on each one. for (int i=0;imenu(); search_update(s, p, menu); } // Once we're here, all the recursion/item retrieval is complete. We auto-select the first item for better // keyboard-exclusive functionality. if (list_widget->count() > 0) { list_widget->item(0)->setSelected(true); } } else { // Parent was not NULL, so we loop over the actions in the menu we were given in `parent`. // The list shows a '>' delimited hierarchy of the menus in which this action came from. We construct it here by // adding the current menu's text to the existing hierarchy (passed in `p`). QString menu_text; if (!p.isEmpty()) menu_text += p + " > "; menu_text += parent->title().replace("&", ""); // Strip out any &s used in menu action names // Loop over the menu's actions QList actions = parent->actions(); for (int i=0;iisSeparator()) { if (a->menu() != nullptr) { // If the action is a menu, run this function recursively on it search_update(s, menu_text, a->menu()); } else { // This is a valid non-separator non-menu action, so check it against the currently entered string. // Strip out all &s from the action's name QString comp = a->text().replace("&", ""); // See if the action's name contains any of the currently entered string if (comp.contains(s, Qt::CaseInsensitive)) { // If so, we add it to the list widget. QListWidgetItem* item = new QListWidgetItem(QStringLiteral("%1\n(%2)").arg(comp, menu_text), list_widget); // Add a pointer to the original QAction in the item's data item->setData(Qt::UserRole+1, reinterpret_cast(a)); list_widget->addItem(item); } } } } } } void ActionSearch::perform_action() { // Loop over all the items in the list and if we find one that's selected, we trigger it. QList selected_items = list_widget->selectedItems(); if (list_widget->count() > 0 && selected_items.size() > 0) { QListWidgetItem* item = selected_items.at(0); // Get QAction pointer from item's data QAction* a = reinterpret_cast(item->data(Qt::UserRole+1).value()); a->trigger(); } // Close this popup accept(); } void ActionSearch::move_selection_up() { // Here we loop over all the items to find the currently selected one, and then select the one above it. We start // iterating at 1 (instead of 0) to efficiently ignore the first item (since the selection can't go below the very // bottom item). int lim = list_widget->count(); for (int i=1;iitem(i)->isSelected()) { list_widget->item(i-1)->setSelected(true); list_widget->scrollToItem(list_widget->item(i-1)); break; } } } void ActionSearch::move_selection_down() { // Here we loop over all the items to find the currently selected one, and then select the one below it. We limit it // one entry before count() to efficiently ignore the item at the end (since the selection can't go below the very // bottom item). int lim = list_widget->count()-1; for (int i=0;iitem(i)->isSelected()) { list_widget->item(i+1)->setSelected(true); list_widget->scrollToItem(list_widget->item(i+1)); break; } } } ActionSearchEntry::ActionSearchEntry(QWidget *parent) : QLineEdit(parent) {} void ActionSearchEntry::keyPressEvent(QKeyEvent * event) { // Listen for up/down, otherwise pass the key event to the base class. switch (event->key()) { case Qt::Key_Up: emit moveSelectionUp(); break; case Qt::Key_Down: emit moveSelectionDown(); break; default: QLineEdit::keyPressEvent(event); } } ActionSearchList::ActionSearchList(QWidget *parent) : QListWidget(parent) {} void ActionSearchList::mouseDoubleClickEvent(QMouseEvent *) { // Indiscriminately emit a signal on any double click emit dbl_click(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/actionsearch/actionsearch.h000066400000000000000000000122731370472574300237170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef ACTIONSEARCH_H #define ACTIONSEARCH_H #include #include #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ActionSearchList; /** * @brief The ActionSearch class * * A popup window (accessible through Help > Action Search) that allows users to search for a menu command by typing * rather than browsing through the menu bar. This can be created from anywhere provided olive::MainWindow is valid. */ class ActionSearch : public QDialog { Q_OBJECT public: /** * @brief ActionSearch Constructor * * Create ActionSearch popup. * * @param parent * * QWidget parent. Usually MainWindow. */ ActionSearch(QWidget* parent); /** * @brief Set the menu bar to use in this action search */ void SetMenuBar(QMenuBar* menu_bar); private slots: /** * @brief Update the list of actions according to a search query * * This function adds/removes actions in the action list according to a given search query entered by the user. * * To loop over the menubar and all of its menus and submenus, this function will call itself recursively. As such * some of its parameters do not need to be set externally, as these will be set by the function itself as it calls * itself. * * @param s * * The search text. This is the only parameter that should be set externally. * * @param p * * The current parent hierarchy. In most cases, this should be left as nullptr when called externally. * search_update() will fill this automatically as it needs while calling itself recursively. * * @param parent * * The current menu to loop over. In most cases, this should be left as nullptr when called externally. * search_update() will fill this automatically as it needs while calling itself recursively. */ void search_update(const QString& s, const QString &p = nullptr, QMenu *parent = nullptr); /** * @brief Perform the currently selected action * * Usually triggered by pressing Enter on the ActionSearchEntry field, this will trigger whatever action is currently * highlighted and then close this popup. If no entries are highlighted (i.e. the list is empty), no action is * triggered and the popup closes anyway. */ void perform_action(); /** * @brief Move selection up * * A slot for pressing up on the ActionSearchEntry field. Moves the selection in the list up once. If the * selection is already at the top of the list, this is a no-op. */ void move_selection_up(); /** * @brief Move selection down * * A slot for pressing down on the ActionSearchEntry field. Moves the selection in the list down once. If the * selection is already at the bottom of the list, this is a no-op. */ void move_selection_down(); private: /** * @brief Main widget that shows the list of commands */ ActionSearchList* list_widget; /** * @brief Attached menu bar object */ QMenuBar* menu_bar_; }; /** * @brief The ActionSearchList class * * Simple wrapper around QListWidget that emits a signal when an item is double clicked that ActionSearch connects * to a slot that triggers the currently selected action. */ class ActionSearchList : public QListWidget { Q_OBJECT public: /** * @brief ActionSearchList Constructor * @param parent * * Usually ActionSearch. */ ActionSearchList(QWidget* parent); protected: /** * @brief Override of QListWidget's double click event that emits a signal. */ void mouseDoubleClickEvent(QMouseEvent *); signals: /** * @brief Signal emitted when a QListWidget item is double clicked. */ void dbl_click(); }; /** * @brief The ActionSearchEntry class * * Simple wrapper around QLineEdit that emits signals when the up or down arrow keys are pressed so that ActionSearch * can connect them to moving the current selection up or down. */ class ActionSearchEntry : public QLineEdit { Q_OBJECT public: /** * @brief ActionSearchEntry * @param parent * * Usually ActionSearch. */ ActionSearchEntry(QWidget* parent); protected: /** * @brief Override of QLineEdit's key press event that listens for up/down key presses. * @param event */ void keyPressEvent(QKeyEvent * event); signals: /** * @brief Emitted when the user presses the up arrow key. */ void moveSelectionUp(); /** * @brief Emitted when the user presses the down arrow key. */ void moveSelectionDown(); }; OLIVE_NAMESPACE_EXIT #endif // ACTIONSEARCH_H olive-continuous/app/dialog/color/000077500000000000000000000000001370472574300175515ustar00rootroot00000000000000olive-continuous/app/dialog/color/CMakeLists.txt000066400000000000000000000014611370472574300223130ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/color/colordialog.h dialog/color/colordialog.cpp PARENT_SCOPE ) olive-continuous/app/dialog/color/colordialog.cpp000066400000000000000000000143441370472574300225610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colordialog.h" #include #include #include #include "common/qtutils.h" OLIVE_NAMESPACE_ENTER ColorDialog::ColorDialog(ColorManager* color_manager, const ManagedColor& start, QWidget *parent) : QDialog(parent), color_manager_(color_manager) { setWindowTitle(tr("Select Color")); QVBoxLayout* layout = new QVBoxLayout(this); QSplitter* splitter = new QSplitter(Qt::Horizontal); splitter->setChildrenCollapsible(false); layout->addWidget(splitter); QWidget* wheel_area = new QWidget(); QHBoxLayout* wheel_layout = new QHBoxLayout(wheel_area); splitter->addWidget(wheel_area); color_wheel_ = new ColorWheelWidget(); wheel_layout->addWidget(color_wheel_); hsv_value_gradient_ = new ColorGradientWidget(Qt::Vertical); hsv_value_gradient_->setFixedWidth(QFontMetricsWidth(fontMetrics(), QStringLiteral("HHH"))); wheel_layout->addWidget(hsv_value_gradient_); QWidget* value_area = new QWidget(); QVBoxLayout* value_layout = new QVBoxLayout(value_area); value_layout->setSpacing(0); splitter->addWidget(value_area); color_values_widget_ = new ColorValuesWidget(color_manager_); value_layout->addWidget(color_values_widget_); chooser_ = new ColorSpaceChooser(color_manager_); chooser_->set_input(start.color_input()); chooser_->set_output(start.color_output()); value_layout->addWidget(chooser_); // Split window 50/50 splitter->setSizes({INT_MAX, INT_MAX}); connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, color_values_widget_, &ColorValuesWidget::SetColor); connect(color_wheel_, &ColorWheelWidget::SelectedColorChanged, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor); connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, color_values_widget_, &ColorValuesWidget::SetColor); connect(hsv_value_gradient_, &ColorGradientWidget::SelectedColorChanged, color_wheel_, &ColorWheelWidget::SetSelectedColor); connect(color_values_widget_, &ColorValuesWidget::ColorChanged, hsv_value_gradient_, &ColorGradientWidget::SetSelectedColor); connect(color_values_widget_, &ColorValuesWidget::ColorChanged, color_wheel_, &ColorWheelWidget::SetSelectedColor); connect(color_wheel_, &ColorWheelWidget::DiameterChanged, hsv_value_gradient_, &ColorGradientWidget::setFixedHeight); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); layout->addWidget(buttons); Color managed_start; if (start.color_input().isEmpty()) { managed_start = start; } else { // Convert reference color to the input space ColorProcessorPtr linear_to_input = ColorProcessor::Create(color_manager_, color_manager_->GetReferenceColorSpace(), start.color_input()); managed_start = linear_to_input->ConvertColor(start); } color_wheel_->SetSelectedColor(managed_start); hsv_value_gradient_->SetSelectedColor(managed_start); color_values_widget_->SetColor(managed_start); connect(chooser_, &ColorSpaceChooser::ColorSpaceChanged, this, &ColorDialog::ColorSpaceChanged); ColorSpaceChanged(chooser_->input(), chooser_->output()); // Set default size ratio to 2:1 resize(sizeHint().height() * 2, sizeHint().height()); } ManagedColor ColorDialog::GetSelectedColor() const { ManagedColor selected = color_wheel_->GetSelectedColor(); // Convert to linear and return a linear color if (input_to_ref_processor_) { selected = input_to_ref_processor_->ConvertColor(selected); } selected.set_color_input(GetColorSpaceInput()); selected.set_color_output(GetColorSpaceOutput()); return selected; } QString ColorDialog::GetColorSpaceInput() const { return chooser_->input(); } ColorTransform ColorDialog::GetColorSpaceOutput() const { return chooser_->output(); } void ColorDialog::ColorSpaceChanged(const QString &input, const ColorTransform &output) { input_to_ref_processor_ = ColorProcessor::Create(color_manager_, input, color_manager_->GetReferenceColorSpace()); ColorProcessorPtr ref_to_display = ColorProcessor::Create(color_manager_, color_manager_->GetReferenceColorSpace(), output); ColorProcessorPtr ref_to_input = ColorProcessor::Create(color_manager_, color_manager_->GetReferenceColorSpace(), input); // FIXME: For some reason, using OCIO::TRANSFORM_DIR_INVERSE (wrapped by ColorProcessor::kInverse) causes OCIO to // crash. We've disabled that functionality for now (also disabling display_tab_ in ColorValuesWidget) /*ColorProcessorPtr display_to_ref = ColorProcessor::Create(color_manager_->GetConfig(), color_manager_->GetReferenceColorSpace(), display, view, look, ColorProcessor::kInverse);*/ color_wheel_->SetColorProcessor(input_to_ref_processor_, ref_to_display); hsv_value_gradient_->SetColorProcessor(input_to_ref_processor_, ref_to_display); color_values_widget_->SetColorProcessor(input_to_ref_processor_, ref_to_display, nullptr, ref_to_input); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/color/colordialog.h000066400000000000000000000045431370472574300222260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORDIALOG_H #define COLORDIALOG_H #include #include "render/color.h" #include "render/colormanager.h" #include "render/managedcolor.h" #include "widget/colorwheel/colorgradientwidget.h" #include "widget/colorwheel/colorspacechooser.h" #include "widget/colorwheel/colorvalueswidget.h" #include "widget/colorwheel/colorwheelwidget.h" OLIVE_NAMESPACE_ENTER class ColorDialog : public QDialog { Q_OBJECT public: /** * @brief ColorDialog Constructor * * @param color_manager * * The ColorManager to use for color management. This must be valid. * * @param start * * The color to start with. This must be in the color_manager's reference space * * @param input_cs * * The input range that the user should see. The start color will be converted to this for UI object. * * @param parent * * QWidget parent. */ ColorDialog(ColorManager* color_manager, const ManagedColor &start = Color(1.0f, 1.0f, 1.0f), QWidget* parent = nullptr); /** * @brief Retrieves the color selected by the user * * The color is always returned in the ColorManager's reference space (usually scene linear). */ ManagedColor GetSelectedColor() const; QString GetColorSpaceInput() const; ColorTransform GetColorSpaceOutput() const; private: ColorManager* color_manager_; ColorWheelWidget* color_wheel_; ColorValuesWidget* color_values_widget_; ColorGradientWidget* hsv_value_gradient_; ColorProcessorPtr input_to_ref_processor_; ColorSpaceChooser* chooser_; private slots: void ColorSpaceChanged(const QString& input, const ColorTransform &output); }; OLIVE_NAMESPACE_EXIT #endif // COLORDIALOG_H olive-continuous/app/dialog/crashhandler/000077500000000000000000000000001370472574300210715ustar00rootroot00000000000000olive-continuous/app/dialog/crashhandler/crashhandler.cpp000066400000000000000000000052541370472574300242410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "crashhandler.h" #include #include #include #include #include #include OLIVE_NAMESPACE_ENTER CrashHandlerDialog::CrashHandlerDialog(const char *log_file) { setWindowTitle(tr("Olive")); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(new QLabel(tr("We're sorry, Olive has crashed. Please send the following log to the developers to " "help resolve this."))); QTextEdit* edit = new QTextEdit(); edit->setReadOnly(true); layout->addWidget(edit); edit->append(QStringLiteral("Build Environment: %1 (%2)").arg(QSysInfo::buildCpuArchitecture(), QSysInfo::buildAbi())); edit->append(QStringLiteral("Run Environment: %1").arg(QSysInfo::currentCpuArchitecture())); edit->append(QStringLiteral("Kernel: %1 %2").arg(QSysInfo::kernelType(), QSysInfo::kernelVersion())); edit->append(QStringLiteral("System: %1 (%2 %3)").arg(QSysInfo::prettyProductName(), QSysInfo::productType(), QSysInfo::productVersion())); edit->append(QString()); QDialogButtonBox* buttons = new QDialogButtonBox(); // FIXME: Implement auto-reporting //buttons->addButton(tr("Send Error Report"), QDialogButtonBox::AcceptRole); //buttons->addButton(tr("Don't Send"), QDialogButtonBox::RejectRole); buttons->addButton(QDialogButtonBox::Ok); connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); layout->addWidget(buttons); QFile log(log_file); if (log.open(QFile::ReadOnly | QFile::Text)) { edit->append(log.readAll()); QMetaObject::invokeMethod(edit->verticalScrollBar(), "setValue", Qt::QueuedConnection, Q_ARG(int, 0)); log.close(); } } void CrashHandlerDialog::accept() { QDialog::accept(); } void CrashHandlerDialog::reject() { QDialog::reject(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/crashhandler/crashhandler.h000066400000000000000000000021031370472574300236740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CRASHHANDLERDIALOG_H #define CRASHHANDLERDIALOG_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class CrashHandlerDialog : public QDialog { Q_OBJECT public: CrashHandlerDialog(const char* log_file); public slots: virtual void accept() override; virtual void reject() override; }; OLIVE_NAMESPACE_EXIT #endif // CRASHHANDLERDIALOG_H olive-continuous/app/dialog/crashhandler/crashhandlermain.cpp000066400000000000000000000016731370472574300251070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "crashhandler.h" #include int main(int argc, char *argv[]) { if (argc < 2) { return 1; } QApplication a(argc, argv); OLIVE_NAMESPACE::CrashHandlerDialog chd(argv[1]); chd.open(); return a.exec(); } olive-continuous/app/dialog/export/000077500000000000000000000000001370472574300177545ustar00rootroot00000000000000olive-continuous/app/dialog/export/CMakeLists.txt000066400000000000000000000020441370472574300225140ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(codec) set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/export/export.h dialog/export/export.cpp dialog/export/exportadvancedvideodialog.h dialog/export/exportadvancedvideodialog.cpp dialog/export/exportaudiotab.h dialog/export/exportaudiotab.cpp dialog/export/exportvideotab.h dialog/export/exportvideotab.cpp PARENT_SCOPE ) olive-continuous/app/dialog/export/codec/000077500000000000000000000000001370472574300210315ustar00rootroot00000000000000olive-continuous/app/dialog/export/codec/CMakeLists.txt000066400000000000000000000017271370472574300236000ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/export/codec/codecsection.h dialog/export/codec/codecsection.cpp dialog/export/codec/h264section.h dialog/export/codec/h264section.cpp dialog/export/codec/imagesection.h dialog/export/codec/imagesection.cpp PARENT_SCOPE ) olive-continuous/app/dialog/export/codec/codecsection.cpp000066400000000000000000000015241370472574300242010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "codecsection.h" OLIVE_NAMESPACE_ENTER CodecSection::CodecSection(QWidget *parent) : QWidget(parent) { } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/codec/codecsection.h000066400000000000000000000017751370472574300236560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CODECSECTION_H #define CODECSECTION_H #include #include "codec/encoder.h" OLIVE_NAMESPACE_ENTER class CodecSection : public QWidget { public: CodecSection(QWidget* parent = nullptr); virtual void AddOpts(EncodingParams* params){} }; OLIVE_NAMESPACE_EXIT #endif // CODECSECTION_H olive-continuous/app/dialog/export/codec/h264section.cpp000066400000000000000000000133771370472574300236200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "h264section.h" #include #include #include #include #include "common/qtutils.h" #include "widget/slider/integerslider.h" OLIVE_NAMESPACE_ENTER H264Section::H264Section(QWidget *parent) : CodecSection(parent) { QGridLayout* layout = new QGridLayout(this); layout->setMargin(0); int row = 0; layout->addWidget(new QLabel(tr("Compression Method:")), row, 0); QComboBox* compression_box = new QComboBox(); // These items must correspond to the CompressionMethod enum compression_box->addItem(tr("Constant Rate Factor")); compression_box->addItem(tr("Target Bit Rate")); compression_box->addItem(tr("Target File Size")); layout->addWidget(compression_box, row, 1); row++; compression_method_stack_ = new QStackedWidget(); layout->addWidget(compression_method_stack_, row, 0, 1, 2); crf_section_ = new H264CRFSection(); compression_method_stack_->addWidget(crf_section_); bitrate_section_ = new H264BitRateSection(); compression_method_stack_->addWidget(bitrate_section_); filesize_section_ = new H264FileSizeSection(); compression_method_stack_->addWidget(filesize_section_); connect(compression_box, static_cast(&QComboBox::currentIndexChanged), compression_method_stack_, &QStackedWidget::setCurrentIndex); } void H264Section::AddOpts(EncodingParams *params) { // FIXME: Implement two-pass CompressionMethod method = static_cast(compression_method_stack_->currentIndex()); if (method == kConstantRateFactor) { // Simply set CRF value params->set_video_option(QStringLiteral("crf"), QString::number(crf_section_->GetValue())); } else { int64_t target_rate, max_rate; if (method == kTargetBitRate) { // Use user-supplied values for the bit rate target_rate = bitrate_section_->GetTargetBitRate(); max_rate = bitrate_section_->GetMaximumBitRate(); } else { // Calculate the bit rate from the file size divided by the sequence length in seconds (bits per second) target_rate = qRound64(static_cast(filesize_section_->GetFileSize()) / params->GetExportLength().toDouble()); max_rate = target_rate; } // Disable CRF encoding params->set_video_option(QStringLiteral("crf"), QStringLiteral("-1")); params->set_video_bit_rate(target_rate); params->set_video_max_bit_rate(max_rate); params->set_video_buffer_size(2000000); } } H264CRFSection::H264CRFSection(QWidget *parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); crf_slider_ = new QSlider(Qt::Horizontal); crf_slider_->setMinimum(kMinimumCRF); crf_slider_->setMaximum(kMaximumCRF); crf_slider_->setValue(kDefaultCRF); layout->addWidget(crf_slider_); IntegerSlider* crf_input = new IntegerSlider(); crf_input->setMaximumWidth(QFontMetricsWidth(crf_input->fontMetrics(), QStringLiteral("HHHH"))); crf_input->SetMinimum(kMinimumCRF); crf_input->SetMaximum(kMaximumCRF); crf_input->SetValue(kDefaultCRF); crf_input->SetDefaultValue(kDefaultCRF); layout->addWidget(crf_input); connect(crf_slider_, &QSlider::valueChanged, crf_input, &IntegerSlider::SetValue); connect(crf_input, &IntegerSlider::ValueChanged, crf_slider_, &QSlider::setValue); } int H264CRFSection::GetValue() const { return crf_slider_->value(); } H264BitRateSection::H264BitRateSection(QWidget *parent) : QWidget(parent) { QGridLayout* layout = new QGridLayout(this); layout->setMargin(0); int row = 0; layout->addWidget(new QLabel(tr("Target Bit Rate (Mbps):")), row, 0); target_rate_ = new FloatSlider(); target_rate_->SetMinimum(0); layout->addWidget(target_rate_, row, 1); row++; layout->addWidget(new QLabel(tr("Maximum Bit Rate (Mbps):")), row, 0); max_rate_ = new FloatSlider(); max_rate_->SetMinimum(0); layout->addWidget(max_rate_, row, 1); row++; layout->addWidget(new QLabel(tr("Two-Pass")), row, 0); QCheckBox* two_pass_box = new QCheckBox(); layout->addWidget(two_pass_box, row, 1); // Bit rate defaults target_rate_->SetValue(16.0); max_rate_->SetValue(32.0); } int64_t H264BitRateSection::GetTargetBitRate() const { return qRound64(target_rate_->GetValue() * 1000000.0); } int64_t H264BitRateSection::GetMaximumBitRate() const { return qRound64(max_rate_->GetValue() * 1000000.0); } H264FileSizeSection::H264FileSizeSection(QWidget *parent) : QWidget(parent) { QGridLayout* layout = new QGridLayout(this); layout->setMargin(0); int row = 0; layout->addWidget(new QLabel(tr("Target File Size (MB):")), row, 0); file_size_ = new FloatSlider(); file_size_->SetMinimum(0); layout->addWidget(file_size_, row, 1); row++; layout->addWidget(new QLabel(tr("Two-Pass")), row, 0); QCheckBox* two_pass_box = new QCheckBox(); layout->addWidget(two_pass_box, row, 1); // File size defaults file_size_->SetValue(700.0); } int64_t H264FileSizeSection::GetFileSize() const { // Convert megabytes to BITS return qRound64(file_size_->GetValue() * 1024.0 * 1024.0 * 8.0); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/codec/h264section.h000066400000000000000000000043241370472574300232550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef H264SECTION_H #define H264SECTION_H #include #include #include "codecsection.h" #include "widget/slider/floatslider.h" OLIVE_NAMESPACE_ENTER class H264CRFSection : public QWidget { public: H264CRFSection(QWidget* parent = nullptr); int GetValue() const; private: static const int kMinimumCRF = 0; static const int kDefaultCRF = 23; static const int kMaximumCRF = 51; QSlider* crf_slider_; }; class H264BitRateSection : public QWidget { public: H264BitRateSection(QWidget* parent = nullptr); /** * @brief Get user-selected target bit rate (returns in BITS) */ int64_t GetTargetBitRate() const; /** * @brief Get user-selected maximum bit rate (returns in BITS) */ int64_t GetMaximumBitRate() const; private: FloatSlider* target_rate_; FloatSlider* max_rate_; }; class H264FileSizeSection : public QWidget { public: H264FileSizeSection(QWidget* parent = nullptr); /** * @brief Returns file size in BITS */ int64_t GetFileSize() const; private: FloatSlider* file_size_; }; class H264Section : public CodecSection { public: enum CompressionMethod { kConstantRateFactor, kTargetBitRate, kTargetFileSize }; H264Section(QWidget* parent = nullptr); virtual void AddOpts(EncodingParams* params) override; private: QStackedWidget* compression_method_stack_; H264CRFSection* crf_section_; H264BitRateSection* bitrate_section_; H264FileSizeSection* filesize_section_; }; OLIVE_NAMESPACE_EXIT #endif // H264SECTION_H olive-continuous/app/dialog/export/codec/imagesection.cpp000066400000000000000000000023311370472574300242030ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "imagesection.h" #include #include OLIVE_NAMESPACE_ENTER ImageSection::ImageSection(QWidget* parent) : CodecSection(parent) { QGridLayout* layout = new QGridLayout(this); layout->setMargin(0); int row = 0; layout->addWidget(new QLabel(tr("Image Sequence:")), row, 0); image_sequence_checkbox_ = new QCheckBox(); layout->addWidget(new QCheckBox(), row, 1); } QCheckBox *ImageSection::image_sequence_checkbox() const { return image_sequence_checkbox_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/codec/imagesection.h000066400000000000000000000020611370472574300236500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef IMAGESECTION_H #define IMAGESECTION_H #include #include "codecsection.h" OLIVE_NAMESPACE_ENTER class ImageSection : public CodecSection { public: ImageSection(QWidget* parent = nullptr); QCheckBox* image_sequence_checkbox() const; private: QCheckBox* image_sequence_checkbox_; }; OLIVE_NAMESPACE_EXIT #endif // IMAGESECTION_H olive-continuous/app/dialog/export/export.cpp000066400000000000000000000427111370472574300220060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "export.h" #include #include #include #include #include #include #include #include #include #include "core.h" #include "dialog/task/task.h" #include "project/item/sequence/sequence.h" #include "project/project.h" #include "render/pixelformat.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : QDialog(parent), viewer_node_(viewer_node) { QHBoxLayout* layout = new QHBoxLayout(this); QSplitter* splitter = new QSplitter(Qt::Horizontal); splitter->setChildrenCollapsible(false); layout->addWidget(splitter); preferences_area_ = new QWidget(); QGridLayout* preferences_layout = new QGridLayout(preferences_area_); preferences_layout->setMargin(0); int row = 0; QLabel* fn_lbl = new QLabel(tr("Filename:")); fn_lbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); preferences_layout->addWidget(fn_lbl, row, 0); filename_edit_ = new QLineEdit(); preferences_layout->addWidget(filename_edit_, row, 1, 1, 2); QPushButton* file_browse_btn = new QPushButton(); file_browse_btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); file_browse_btn->setIcon(icon::Folder); file_browse_btn->setToolTip(tr("Browse for exported file filename")); connect(file_browse_btn, &QPushButton::clicked, this, &ExportDialog::BrowseFilename); preferences_layout->addWidget(file_browse_btn, row, 3); row++; QLabel* preset_lbl = new QLabel(tr("Preset:")); preset_lbl->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); preferences_layout->addWidget(preset_lbl, row, 0); QComboBox* preset_combobox = new QComboBox(); preset_combobox->addItem(tr("Same As Source - High Quality")); preset_combobox->addItem(tr("Same As Source - Medium Quality")); preset_combobox->addItem(tr("Same As Source - Low Quality")); preferences_layout->addWidget(preset_combobox, row, 1); QPushButton* preset_load_btn = new QPushButton(); preset_load_btn->setIcon(icon::Open); preset_load_btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); preferences_layout->addWidget(preset_load_btn, row, 2); QPushButton* preset_save_btn = new QPushButton(); preset_save_btn->setIcon(icon::Save); preset_save_btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); preferences_layout->addWidget(preset_save_btn, row, 3); row++; QFrame* horizontal_line = new QFrame(); horizontal_line->setFrameShape(QFrame::HLine); horizontal_line->setFrameShadow(QFrame::Sunken); preferences_layout->addWidget(horizontal_line, row, 0, 1, 4); row++; preferences_layout->addWidget(new QLabel(tr("Format:")), row, 0); format_combobox_ = new QComboBox(); preferences_layout->addWidget(format_combobox_, row, 1, 1, 3); row++; QHBoxLayout* av_enabled_layout = new QHBoxLayout(); video_enabled_ = new QCheckBox(tr("Export Video")); video_enabled_->setChecked(true); av_enabled_layout->addWidget(video_enabled_); audio_enabled_ = new QCheckBox(tr("Export Audio")); audio_enabled_->setChecked(true); av_enabled_layout->addWidget(audio_enabled_); preferences_layout->addLayout(av_enabled_layout, row, 0, 1, 4); row++; QTabWidget* preferences_tabs = new QTabWidget(); QScrollArea* video_area = new QScrollArea(); color_manager_ = static_cast(viewer_node_->parent())->project()->color_manager(); video_tab_ = new ExportVideoTab(color_manager_); video_area->setWidgetResizable(true); video_area->setWidget(video_tab_); preferences_tabs->addTab(video_area, tr("Video")); QScrollArea* audio_area = new QScrollArea(); audio_tab_ = new ExportAudioTab(); audio_area->setWidgetResizable(true); audio_area->setWidget(audio_tab_); preferences_tabs->addTab(audio_area, tr("Audio")); preferences_layout->addWidget(preferences_tabs, row, 0, 1, 4); row++; buttons_ = new QDialogButtonBox(); buttons_->setCenterButtons(true); buttons_->addButton(tr("Export"), QDialogButtonBox::AcceptRole); buttons_->addButton(QDialogButtonBox::Cancel); connect(buttons_, &QDialogButtonBox::accepted, this, &ExportDialog::StartExport); connect(buttons_, &QDialogButtonBox::rejected, this, &ExportDialog::reject); preferences_layout->addWidget(buttons_, row, 0, 1, 4); splitter->addWidget(preferences_area_); QWidget* preview_area = new QWidget(); QVBoxLayout* preview_layout = new QVBoxLayout(preview_area); preview_layout->addWidget(new QLabel(tr("Preview"))); preview_viewer_ = new ViewerWidget(); preview_viewer_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); preview_layout->addWidget(preview_viewer_); splitter->addWidget(preview_area); // Set default filename SetDefaultFilename(); // Populate combobox formats for (int i=0; iaddItem(ExportFormat::GetName(static_cast(i))); } // Set defaults previously_selected_format_ = ExportFormat::kFormatMPEG4; format_combobox_->setCurrentIndex(ExportFormat::kFormatMPEG4); connect(format_combobox_, static_cast(&QComboBox::currentIndexChanged), this, &ExportDialog::FormatChanged); FormatChanged(ExportFormat::kFormatMPEG4); video_tab_->width_slider()->SetValue(viewer_node_->video_params().width()); video_tab_->width_slider()->SetDefaultValue(viewer_node_->video_params().width()); video_tab_->height_slider()->SetValue(viewer_node_->video_params().height()); video_tab_->height_slider()->SetDefaultValue(viewer_node_->video_params().height()); video_tab_->set_frame_rate(viewer_node_->video_params().time_base().flipped()); audio_tab_->set_sample_rate(viewer_node_->audio_params().sample_rate()); audio_tab_->set_channel_layout(viewer_node_->audio_params().channel_layout()); video_aspect_ratio_ = static_cast(viewer_node_->video_params().width()) / static_cast(viewer_node_->video_params().height()); connect(video_tab_->width_slider(), &IntegerSlider::ValueChanged, this, &ExportDialog::ResolutionChanged); connect(video_tab_->height_slider(), &IntegerSlider::ValueChanged, this, &ExportDialog::ResolutionChanged); connect(video_tab_->scaling_method_combobox(), static_cast(&QComboBox::currentIndexChanged), this, &ExportDialog::UpdateViewerDimensions); connect(video_tab_->maintain_aspect_checkbox(), &QCheckBox::toggled, this, &ExportDialog::ResolutionChanged); connect(video_tab_->codec_combobox(), static_cast(&QComboBox::currentIndexChanged), this, &ExportDialog::VideoCodecChanged); connect(video_tab_, &ExportVideoTab::ColorSpaceChanged, preview_viewer_, static_cast(&ViewerWidget::SetColorTransform)); // Set viewer to view the node preview_viewer_->ConnectViewerNode(viewer_node_); preview_viewer_->SetColorMenuEnabled(false); preview_viewer_->SetColorTransform(video_tab_->CurrentOCIOColorSpace()); } void ExportDialog::StartExport() { if (!video_enabled_->isChecked() && !audio_enabled_->isChecked()) { QMessageBox b(this); b.setIcon(QMessageBox::Critical); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Invalid parameters")); b.setText(tr("Both video and audio are disabled. There's nothing to export.")); b.addButton(QMessageBox::Ok); b.exec(); return; } // Validate if the entered filename contains the correct extension (the extension is necessary for both FFmpeg and // OIIO to determine the output format) QString necessary_ext = QStringLiteral(".%1").arg(ExportFormat::GetExtension(static_cast(format_combobox_->currentIndex()))); // If it doesn't, see if the user wants to append it automatically. If not, we don't abort the export. if (!filename_edit_->text().endsWith(necessary_ext, Qt::CaseInsensitive)) { QMessageBox b(this); b.setIcon(QMessageBox::Warning); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Invalid filename")); b.setText(tr("The filename must contain the extension \".%1\". Would you like to append it " "automatically?")); b.addButton(QMessageBox::Yes); b.addButton(QMessageBox::No); if (b.exec() == QMessageBox::Yes) { filename_edit_->setText(filename_edit_->text().append(necessary_ext)); } else { return; } } // Validate the intended path QFileInfo file_info(filename_edit_->text()); QFileInfo dir_info(file_info.path()); // If the directory does not exist, try to create it if (!QDir(file_info.path()).mkpath(QStringLiteral("."))) { QMessageBox b(this); b.setIcon(QMessageBox::Critical); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Failed to create output directory")); b.setText(tr("The intended output directory doesn't exist and Olive couldn't create it. " "Please choose a different filename.")); b.addButton(QMessageBox::Ok); b.exec(); return; } // Validate if the file exists and whether the user wishes to overwrite it if (file_info.exists()) { QMessageBox b(this); b.setIcon(QMessageBox::Warning); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Confirm Overwrite")); b.setText(tr("The file \"%1\" already exists. Do you want to overwrite it?") .arg(filename_edit_->text())); b.addButton(QMessageBox::Yes); b.addButton(QMessageBox::No); if (b.exec() == QMessageBox::No) { return; } } // Validate video resolution if (video_enabled_->isChecked()) { if (video_tab_->width_slider()->GetValue() % 2 != 0 || video_tab_->height_slider()->GetValue() % 2 != 0) { QMessageBox b(this); b.setIcon(QMessageBox::Critical); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(tr("Invalid parameters")); b.setText(tr("Width and height must be multiples of 2.")); b.exec(); return; } } ExportTask* task = new ExportTask(viewer_node_, color_manager_, GenerateParams()); TaskDialog* td = new TaskDialog(task, tr("Export"), this); connect(td, &TaskDialog::TaskSucceeded, this, &QDialog::accept); td->open(); } void ExportDialog::closeEvent(QCloseEvent *e) { preview_viewer_->ConnectViewerNode(nullptr); QDialog::closeEvent(e); } void ExportDialog::BrowseFilename() { ExportFormat::Format f = static_cast(format_combobox_->currentIndex()); QString browsed_fn = QFileDialog::getSaveFileName(this, "", filename_edit_->text(), QStringLiteral("%1 (*.%2)").arg(ExportFormat::GetName(f), ExportFormat::GetExtension(f)), nullptr, // We don't confirm overwrite here because we do it later QFileDialog::DontConfirmOverwrite); if (!browsed_fn.isEmpty()) { filename_edit_->setText(browsed_fn); } } void ExportDialog::FormatChanged(int index) { QString current_filename = filename_edit_->text(); QString previously_selected_ext = ExportFormat::GetExtension(previously_selected_format_); ExportFormat::Format current_format = static_cast(index); QString currently_selected_ext = ExportFormat::GetExtension(current_format); // If the previous extension was added, remove it if (current_filename.endsWith(previously_selected_ext, Qt::CaseInsensitive)) { current_filename.resize(current_filename.size() - previously_selected_ext.size() - 1); } // Add the extension and set it current_filename.append('.'); current_filename.append(currently_selected_ext); filename_edit_->setText(current_filename); previously_selected_format_ = current_format; // Update video and audio comboboxes video_tab_->codec_combobox()->clear(); foreach (ExportCodec::Codec vcodec, ExportFormat::GetVideoCodecs(current_format)) { video_tab_->codec_combobox()->addItem(ExportCodec::GetCodecName(vcodec), vcodec); } VideoCodecChanged(); audio_tab_->codec_combobox()->clear(); foreach (ExportCodec::Codec acodec, ExportFormat::GetAudioCodecs(current_format)) { audio_tab_->codec_combobox()->addItem(ExportCodec::GetCodecName(acodec), acodec); } } void ExportDialog::ResolutionChanged() { if (video_tab_->maintain_aspect_checkbox()->isChecked()) { // Keep aspect ratio maintained if (sender() == video_tab_->height_slider()) { // Convert height to float double new_width = video_tab_->height_slider()->GetValue(); // Generate width from aspect ratio new_width *= video_aspect_ratio_; // Align to even number and set video_tab_->width_slider()->SetValue(AlignEvenNumber(new_width)); } else { // Convert width to float double new_height = video_tab_->width_slider()->GetValue(); // Generate height from aspect ratio new_height /= video_aspect_ratio_; // Align to even number and set video_tab_->height_slider()->SetValue(AlignEvenNumber(new_height)); } } UpdateViewerDimensions(); } void ExportDialog::VideoCodecChanged() { ExportCodec::Codec codec = static_cast(video_tab_->codec_combobox()->currentData().toInt()); if (codec == ExportCodec::kCodecH264) { video_tab_->SetCodecSection(video_tab_->h264_section()); } else if (ExportCodec::IsCodecAStillImage(codec)) { video_tab_->SetCodecSection(video_tab_->image_section()); } } void ExportDialog::LoadPresets() { } void ExportDialog::SetDefaultFilename() { Sequence* s = static_cast(viewer_node_->parent()); Project* p = s->project(); QDir doc_location; if (p->filename().isEmpty()) { doc_location.setPath(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); } else { doc_location = QFileInfo(p->filename()).dir(); } QString file_location = doc_location.filePath(s->name()); filename_edit_->setText(file_location); } int ExportDialog::AlignEvenNumber(double d) { return qCeil(d * 0.5) * 2; } ExportParams ExportDialog::GenerateParams() const { RenderMode::Mode render_mode = RenderMode::kOnline; VideoParams video_render_params(static_cast(video_tab_->width_slider()->GetValue()), static_cast(video_tab_->height_slider()->GetValue()), video_tab_->frame_rate().flipped(), PixelFormat::instance()->GetConfiguredFormatForMode(render_mode), render_mode); AudioParams audio_render_params(audio_tab_->sample_rate_combobox()->currentData().toInt(), audio_tab_->channel_layout_combobox()->currentData().toULongLong(), SampleFormat::kInternalFormat); ExportParams params; params.SetFilename(filename_edit_->text()); params.SetExportLength(viewer_node_->GetLength()); if (video_tab_->scaling_method_combobox()->isEnabled()) { params.set_video_scaling_method(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt())); } if (video_enabled_->isChecked()) { ExportCodec::Codec video_codec = static_cast(video_tab_->codec_combobox()->currentData().toInt()); params.EnableVideo(video_render_params, video_codec); params.set_video_threads(video_tab_->threads()); video_tab_->GetCodecSection()->AddOpts(¶ms); params.set_color_transform(video_tab_->CurrentOCIOColorSpace()); } if (audio_enabled_->isChecked()) { ExportCodec::Codec audio_codec = static_cast(audio_tab_->codec_combobox()->currentData().toInt()); params.EnableAudio(audio_render_params, audio_codec); } return params; } void ExportDialog::UpdateViewerDimensions() { preview_viewer_->SetOverrideSize(static_cast(video_tab_->width_slider()->GetValue()), static_cast(video_tab_->height_slider()->GetValue())); QMatrix4x4 transform = ExportParams::GenerateMatrix(static_cast(video_tab_->scaling_method_combobox()->currentData().toInt()), viewer_node_->video_params().width(), viewer_node_->video_params().height(), static_cast(video_tab_->width_slider()->GetValue()), static_cast(video_tab_->height_slider()->GetValue())); preview_viewer_->SetMatrix(transform); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/export.h000066400000000000000000000040401370472574300214440ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTDIALOG_H #define EXPORTDIALOG_H #include #include #include #include #include #include "codec/exportcodec.h" #include "codec/exportformat.h" #include "exportaudiotab.h" #include "exportvideotab.h" #include "task/export/export.h" #include "widget/viewer/viewer.h" OLIVE_NAMESPACE_ENTER class ExportDialog : public QDialog { Q_OBJECT public: ExportDialog(ViewerOutput* viewer_node, QWidget* parent = nullptr); protected: virtual void closeEvent(QCloseEvent *e) override; private: void LoadPresets(); void SetDefaultFilename(); static int AlignEvenNumber(double d); ExportParams GenerateParams() const; ViewerOutput* viewer_node_; ExportFormat::Format previously_selected_format_; QCheckBox* video_enabled_; QCheckBox* audio_enabled_; ViewerWidget* preview_viewer_; QLineEdit* filename_edit_; QComboBox* format_combobox_; ExportVideoTab* video_tab_; ExportAudioTab* audio_tab_; double video_aspect_ratio_; ColorManager* color_manager_; QWidget* preferences_area_; QDialogButtonBox* buttons_; private slots: void BrowseFilename(); void FormatChanged(int index); void ResolutionChanged(); void VideoCodecChanged(); void UpdateViewerDimensions(); void StartExport(); }; OLIVE_NAMESPACE_EXIT #endif // EXPORTDIALOG_H olive-continuous/app/dialog/export/exportadvancedvideodialog.cpp000066400000000000000000000021061370472574300256750ustar00rootroot00000000000000#include "exportadvancedvideodialog.h" #include #include #include OLIVE_NAMESPACE_ENTER ExportAdvancedVideoDialog::ExportAdvancedVideoDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Advanced")); QGridLayout* layout = new QGridLayout(this); int row = 0; layout->addWidget(new QLabel(tr("Threads:")), row, 0); thread_slider_ = new IntegerSlider(); thread_slider_->SetMinimum(0); thread_slider_->SetDefaultValue(0); layout->addWidget(thread_slider_, row, 1); row++; QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttons, &QDialogButtonBox::accepted, this, &ExportAdvancedVideoDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &ExportAdvancedVideoDialog::reject); layout->addWidget(buttons, row, 0, 1, 2); } int ExportAdvancedVideoDialog::threads() const { return static_cast(thread_slider_->GetValue()); } void ExportAdvancedVideoDialog::set_threads(int t) { thread_slider_->SetValue(t); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/exportadvancedvideodialog.h000066400000000000000000000006731370472574300253510ustar00rootroot00000000000000#ifndef EXPORTADVANCEDVIDEODIALOG_H #define EXPORTADVANCEDVIDEODIALOG_H #include #include "widget/slider/integerslider.h" OLIVE_NAMESPACE_ENTER class ExportAdvancedVideoDialog : public QDialog { Q_OBJECT public: ExportAdvancedVideoDialog(QWidget* parent = nullptr); int threads() const; void set_threads(int t); private: IntegerSlider* thread_slider_; }; OLIVE_NAMESPACE_EXIT #endif // EXPORTADVANCEDVIDEODIALOG_H olive-continuous/app/dialog/export/exportaudiotab.cpp000066400000000000000000000051011370472574300235070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "exportaudiotab.h" #include #include #include "core.h" OLIVE_NAMESPACE_ENTER ExportAudioTab::ExportAudioTab(QWidget* parent) : QWidget(parent) { QVBoxLayout* outer_layout = new QVBoxLayout(this); QGridLayout* layout = new QGridLayout(); outer_layout->addLayout(layout); int row = 0; layout->addWidget(new QLabel(tr("Codec:")), row, 0); codec_combobox_ = new QComboBox(); layout->addWidget(codec_combobox_, row, 1); row++; layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); sample_rate_combobox_ = new QComboBox(); sample_rates_ = Core::SupportedSampleRates(); foreach (const int& sr, sample_rates_) { sample_rate_combobox_->addItem(Core::SampleRateToString(sr), sr); } layout->addWidget(sample_rate_combobox_, row, 1); row++; layout->addWidget(new QLabel(tr("Channel Layout:")), row, 0); channel_layout_combobox_ = new QComboBox(); channel_layouts_ = Core::SupportedChannelLayouts(); foreach (const uint64_t& ch_layout, channel_layouts_) { channel_layout_combobox_->addItem(Core::ChannelLayoutToString(ch_layout), QVariant::fromValue(ch_layout)); } layout->addWidget(channel_layout_combobox_, row, 1); row++; layout->addWidget(new QLabel(tr("Format:")), row, 0); layout->addWidget(new QComboBox(), row, 1); outer_layout->addStretch(); } QComboBox *ExportAudioTab::codec_combobox() const { return codec_combobox_; } QComboBox *ExportAudioTab::sample_rate_combobox() const { return sample_rate_combobox_; } QComboBox *ExportAudioTab::channel_layout_combobox() const { return channel_layout_combobox_; } void ExportAudioTab::set_sample_rate(int rate) { sample_rate_combobox_->setCurrentIndex(sample_rates_.indexOf(rate)); } void ExportAudioTab::set_channel_layout(uint64_t layout) { channel_layout_combobox_->setCurrentIndex(channel_layouts_.indexOf(layout)); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/exportaudiotab.h000066400000000000000000000025531370472574300231640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTAUDIOTAB_H #define EXPORTAUDIOTAB_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ExportAudioTab : public QWidget { public: ExportAudioTab(QWidget* parent = nullptr); QComboBox* codec_combobox() const; QComboBox* sample_rate_combobox() const; QComboBox* channel_layout_combobox() const; void set_sample_rate(int rate); void set_channel_layout(uint64_t layout); private: QComboBox* codec_combobox_; QComboBox* sample_rate_combobox_; QComboBox* channel_layout_combobox_; QList sample_rates_; QList channel_layouts_; }; OLIVE_NAMESPACE_EXIT #endif // EXPORTAUDIOTAB_H olive-continuous/app/dialog/export/exportvideotab.cpp000066400000000000000000000134321370472574300235220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "exportvideotab.h" #include #include #include #include #include #include "core.h" #include "exportadvancedvideodialog.h" #include "render/colormanager.h" #include "task/export/exportparams.h" OLIVE_NAMESPACE_ENTER ExportVideoTab::ExportVideoTab(ColorManager* color_manager, QWidget *parent) : QWidget(parent), color_manager_(color_manager), threads_(0) { QVBoxLayout* outer_layout = new QVBoxLayout(this); outer_layout->addWidget(SetupResolutionSection()); outer_layout->addWidget(SetupCodecSection()); outer_layout->addWidget(SetupColorSection()); outer_layout->addStretch(); } QComboBox *ExportVideoTab::codec_combobox() const { return codec_combobox_; } IntegerSlider *ExportVideoTab::width_slider() const { return width_slider_; } IntegerSlider *ExportVideoTab::height_slider() const { return height_slider_; } QCheckBox *ExportVideoTab::maintain_aspect_checkbox() const { return maintain_aspect_checkbox_; } QComboBox *ExportVideoTab::scaling_method_combobox() const { return scaling_method_combobox_; } const rational &ExportVideoTab::frame_rate() const { return frame_rates_.at(frame_rate_combobox_->currentIndex()); } void ExportVideoTab::set_frame_rate(const rational &frame_rate) { frame_rate_combobox_->setCurrentIndex(frame_rates_.indexOf(frame_rate)); } QString ExportVideoTab::CurrentOCIOColorSpace() { return color_space_chooser_->input(); } CodecSection *ExportVideoTab::GetCodecSection() const { return static_cast(codec_stack_->currentWidget()); } void ExportVideoTab::SetCodecSection(CodecSection *section) { codec_stack_->setCurrentWidget(section); } ImageSection *ExportVideoTab::image_section() const { return image_section_; } H264Section *ExportVideoTab::h264_section() const { return h264_section_; } const int &ExportVideoTab::threads() const { return threads_; } QWidget* ExportVideoTab::SetupResolutionSection() { int row = 0; QGroupBox* resolution_group = new QGroupBox(); resolution_group->setTitle(tr("Basic")); QGridLayout* layout = new QGridLayout(resolution_group); layout->addWidget(new QLabel(tr("Width:")), row, 0); width_slider_ = new IntegerSlider(); width_slider_->SetMinimum(1); layout->addWidget(width_slider_, row, 1); row++; layout->addWidget(new QLabel(tr("Height:")), row, 0); height_slider_ = new IntegerSlider(); height_slider_->SetMinimum(1); layout->addWidget(height_slider_, row, 1); row++; layout->addWidget(new QLabel(tr("Maintain Aspect Ratio:")), row, 0); maintain_aspect_checkbox_ = new QCheckBox(); maintain_aspect_checkbox_->setChecked(true); layout->addWidget(maintain_aspect_checkbox_, row, 1); row++; layout->addWidget(new QLabel(tr("Scaling Method:")), row, 0); scaling_method_combobox_ = new QComboBox(); scaling_method_combobox_->setEnabled(false); scaling_method_combobox_->addItem(tr("Fit"), ExportParams::kFit); scaling_method_combobox_->addItem(tr("Stretch"), ExportParams::kStretch); scaling_method_combobox_->addItem(tr("Crop"), ExportParams::kCrop); layout->addWidget(scaling_method_combobox_, row, 1); // Automatically enable/disable the scaling method depending on maintain aspect ratio connect(maintain_aspect_checkbox_, &QCheckBox::toggled, this, &ExportVideoTab::MaintainAspectRatioChanged); row++; layout->addWidget(new QLabel(tr("Frame Rate:")), row, 0); frame_rate_combobox_ = new QComboBox(); frame_rates_ = Core::SupportedFrameRates(); foreach (const rational& fr, frame_rates_) { frame_rate_combobox_->addItem(Core::FrameRateToString(fr)); } layout->addWidget(frame_rate_combobox_, row, 1); return resolution_group; } QWidget* ExportVideoTab::SetupColorSection() { color_space_chooser_ = new ColorSpaceChooser(color_manager_, true, false); connect(color_space_chooser_, &ColorSpaceChooser::InputColorSpaceChanged, this, &ExportVideoTab::ColorSpaceChanged); return color_space_chooser_; } QWidget *ExportVideoTab::SetupCodecSection() { int row = 0; QGroupBox* codec_group = new QGroupBox(); codec_group->setTitle(tr("Codec")); QGridLayout* codec_layout = new QGridLayout(codec_group); codec_layout->addWidget(new QLabel(tr("Codec:")), row, 0); codec_combobox_ = new QComboBox(); codec_layout->addWidget(codec_combobox_, row, 1); row++; codec_stack_ = new QStackedWidget(); codec_layout->addWidget(codec_stack_, row, 0, 1, 2); image_section_ = new ImageSection(); codec_stack_->addWidget(image_section_); h264_section_ = new H264Section(); codec_stack_->addWidget(h264_section_); row++; QPushButton* advanced_btn = new QPushButton(tr("Advanced")); connect(advanced_btn, &QPushButton::clicked, this, &ExportVideoTab::OpenAdvancedDialog); codec_layout->addWidget(advanced_btn, row, 1); return codec_group; } void ExportVideoTab::MaintainAspectRatioChanged(bool val) { scaling_method_combobox_->setEnabled(!val); } void ExportVideoTab::OpenAdvancedDialog() { ExportAdvancedVideoDialog d(this); d.set_threads(threads_); if (d.exec() == QDialog::Accepted) { threads_ = d.threads(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/export/exportvideotab.h000066400000000000000000000047161370472574300231740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTVIDEOTAB_H #define EXPORTVIDEOTAB_H #include #include #include #include "common/rational.h" #include "dialog/export/codec/h264section.h" #include "dialog/export/codec/imagesection.h" #include "render/colormanager.h" #include "widget/colorwheel/colorspacechooser.h" #include "widget/slider/integerslider.h" OLIVE_NAMESPACE_ENTER class ExportVideoTab : public QWidget { Q_OBJECT public: ExportVideoTab(ColorManager* color_manager, QWidget* parent = nullptr); QComboBox* codec_combobox() const; IntegerSlider* width_slider() const; IntegerSlider* height_slider() const; QCheckBox* maintain_aspect_checkbox() const; QComboBox* scaling_method_combobox() const; const rational& frame_rate() const; void set_frame_rate(const rational& frame_rate); QString CurrentOCIOColorSpace(); CodecSection* GetCodecSection() const; void SetCodecSection(CodecSection* section); ImageSection* image_section() const; H264Section* h264_section() const; const int& threads() const; signals: void ColorSpaceChanged(const QString& colorspace); private: QWidget* SetupResolutionSection(); QWidget* SetupColorSection(); QWidget* SetupCodecSection(); QComboBox* codec_combobox_; QComboBox* frame_rate_combobox_; QCheckBox* maintain_aspect_checkbox_; QComboBox* scaling_method_combobox_; QStackedWidget* codec_stack_; ImageSection* image_section_; H264Section* h264_section_; ColorSpaceChooser* color_space_chooser_; IntegerSlider* width_slider_; IntegerSlider* height_slider_; QList frame_rates_; ColorManager* color_manager_; int threads_; private slots: void MaintainAspectRatioChanged(bool val); void OpenAdvancedDialog(); }; OLIVE_NAMESPACE_EXIT #endif // EXPORTVIDEOTAB_H olive-continuous/app/dialog/footageproperties/000077500000000000000000000000001370472574300221745ustar00rootroot00000000000000olive-continuous/app/dialog/footageproperties/CMakeLists.txt000066400000000000000000000015711370472574300247400ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(streamproperties) set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/footageproperties/footageproperties.h dialog/footageproperties/footageproperties.cpp PARENT_SCOPE ) olive-continuous/app/dialog/footageproperties/footageproperties.cpp000066400000000000000000000135341370472574300264470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "footageproperties.h" #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "render/colormanager.h" #include "streamproperties/audiostreamproperties.h" #include "streamproperties/videostreamproperties.h" OLIVE_NAMESPACE_ENTER FootagePropertiesDialog::FootagePropertiesDialog(QWidget *parent, Footage *footage) : QDialog(parent), footage_(footage) { QGridLayout* layout = new QGridLayout(this); setWindowTitle(tr("\"%1\" Properties").arg(footage_->name())); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); int row = 0; layout->addWidget(new QLabel(tr("Name:")), row, 0); footage_name_field_ = new QLineEdit(footage_->name()); layout->addWidget(footage_name_field_, row, 1); row++; layout->addWidget(new QLabel(tr("Tracks:")), row, 0, 1, 2); row++; track_list = new QListWidget(); layout->addWidget(track_list, row, 0, 1, 2); row++; stacked_widget_ = new QStackedWidget(); layout->addWidget(stacked_widget_, row, 0, 1, 2); int first_usable_stream = -1; for (int i=0;istreams().size();i++) { StreamPtr stream = footage_->stream(i); QListWidgetItem* item = new QListWidgetItem(stream->description(), track_list); item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setCheckState(stream->enabled() ? Qt::Checked : Qt::Unchecked); track_list->addItem(item); switch (stream->type()) { case Stream::kVideo: case Stream::kImage: stacked_widget_->addWidget(new VideoStreamProperties(std::static_pointer_cast(stream))); break; case Stream::kAudio: stacked_widget_->addWidget(new AudioStreamProperties(std::static_pointer_cast(stream))); break; default: stacked_widget_->addWidget(new StreamProperties()); } if (first_usable_stream == -1 && (stream->type() == Stream::kVideo || stream->type() == Stream::kAudio || stream->type() == Stream::kImage)) { first_usable_stream = i; } } row++; QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttons->setCenterButtons(true); layout->addWidget(buttons, row, 0, 1, 2); connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(track_list, &QListWidget::currentRowChanged, stacked_widget_, &QStackedWidget::setCurrentIndex); // Auto-select first item that actually has properties if (first_usable_stream >= 0) { track_list->setCurrentRow(first_usable_stream); } track_list->setFocus(); } void FootagePropertiesDialog::accept() { // Perform sanity check on all pages for (int i=0;icount();i++) { if (!static_cast(stacked_widget_->widget(i))->SanityCheck()) { // Switch to the failed panel in question stacked_widget_->setCurrentIndex(i); // Do nothing (it's up to the property panel itself to throw the error message) return; } } QUndoCommand* command = new QUndoCommand(); if (footage_->name() != footage_name_field_->text()) { new FootageChangeCommand(footage_, footage_name_field_->text(), command); } for (int i=0;istreams().size();i++) { bool stream_enabled = (track_list->item(i)->checkState() == Qt::Checked); if (footage_->stream(i)->enabled() != stream_enabled) { new StreamEnableChangeCommand(footage_->stream(i), stream_enabled, command); } } for (int i=0;icount();i++) { static_cast(stacked_widget_->widget(i))->Accept(command); } Core::instance()->undo_stack()->pushIfHasChildren(command); QDialog::accept(); } FootagePropertiesDialog::FootageChangeCommand::FootageChangeCommand(Footage *footage, const QString &name, QUndoCommand* command) : UndoCommand(command), footage_(footage), new_name_(name) { } Project *FootagePropertiesDialog::FootageChangeCommand::GetRelevantProject() const { return footage_->project(); } void FootagePropertiesDialog::FootageChangeCommand::redo_internal() { old_name_ = footage_->name(); footage_->set_name(new_name_); } void FootagePropertiesDialog::FootageChangeCommand::undo_internal() { footage_->set_name(old_name_); } FootagePropertiesDialog::StreamEnableChangeCommand::StreamEnableChangeCommand(StreamPtr stream, bool enabled, QUndoCommand *command) : UndoCommand(command), stream_(stream), old_enabled_(stream->enabled()), new_enabled_(enabled) { } Project *FootagePropertiesDialog::StreamEnableChangeCommand::GetRelevantProject() const { return stream_->footage()->project(); } void FootagePropertiesDialog::StreamEnableChangeCommand::redo_internal() { stream_->set_enabled(new_enabled_); } void FootagePropertiesDialog::StreamEnableChangeCommand::undo_internal() { stream_->set_enabled(old_enabled_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/footageproperties/footageproperties.h000066400000000000000000000063301370472574300261100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MEDIAPROPERTIESDIALOG_H #define MEDIAPROPERTIESDIALOG_H #include #include #include #include #include #include #include #include "project/item/footage/footage.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER /** * @brief The MediaPropertiesDialog class * * A dialog for setting properties on Media. This can be loaded from any part of the application provided it's given * a valid Media object. */ class FootagePropertiesDialog : public QDialog { Q_OBJECT public: /** * @brief MediaPropertiesDialog Constructor * * @param parent * * QWidget parent. Usually MainWindow or Project panel. * * @param i * * Media object to set properties for. */ FootagePropertiesDialog(QWidget *parent, Footage* footage); private: class FootageChangeCommand : public UndoCommand { public: FootageChangeCommand(Footage* footage, const QString& name, QUndoCommand *command = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Footage* footage_; QString new_name_; QString old_name_; }; class StreamEnableChangeCommand : public UndoCommand { public: StreamEnableChangeCommand(StreamPtr stream, bool enabled, QUndoCommand* command = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: StreamPtr stream_; bool old_enabled_; bool new_enabled_; }; /** * @brief Stack of widgets that changes based on whether the stream is a video or audio stream */ QStackedWidget* stacked_widget_; /** * @brief ComboBox for interlacing setting */ QComboBox* interlacing_box; /** * @brief Media name text field */ QLineEdit* footage_name_field_; /** * @brief Internal pointer to Media object (set in constructor) */ Footage* footage_; /** * @brief A list widget for listing the tracks in Media */ QListWidget* track_list; /** * @brief Frame rate to conform to */ QDoubleSpinBox* conform_fr; private slots: /** * @brief Overridden accept function for saving the properties back to the Media class */ void accept(); }; OLIVE_NAMESPACE_EXIT #endif // MEDIAPROPERTIESDIALOG_H olive-continuous/app/dialog/footageproperties/streamproperties/000077500000000000000000000000001370472574300256045ustar00rootroot00000000000000olive-continuous/app/dialog/footageproperties/streamproperties/CMakeLists.txt000066400000000000000000000022111370472574300303400ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/footageproperties/streamproperties/streamproperties.h dialog/footageproperties/streamproperties/streamproperties.cpp dialog/footageproperties/streamproperties/audiostreamproperties.h dialog/footageproperties/streamproperties/audiostreamproperties.cpp dialog/footageproperties/streamproperties/videostreamproperties.h dialog/footageproperties/streamproperties/videostreamproperties.cpp PARENT_SCOPE ) olive-continuous/app/dialog/footageproperties/streamproperties/audiostreamproperties.cpp000066400000000000000000000016541370472574300327500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiostreamproperties.h" OLIVE_NAMESPACE_ENTER AudioStreamProperties::AudioStreamProperties(AudioStreamPtr stream) : stream_(stream) { } void AudioStreamProperties::Accept(QUndoCommand*) { } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/footageproperties/streamproperties/audiostreamproperties.h000066400000000000000000000021641370472574300324120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOSTREAMPROPERTIES_H #define AUDIOSTREAMPROPERTIES_H #include "project/item/footage/audiostream.h" #include "streamproperties.h" OLIVE_NAMESPACE_ENTER class AudioStreamProperties : public StreamProperties { public: AudioStreamProperties(AudioStreamPtr stream); virtual void Accept(QUndoCommand* parent) override; private: AudioStreamPtr stream_; }; OLIVE_NAMESPACE_EXIT #endif // AUDIOSTREAMPROPERTIES_H olive-continuous/app/dialog/footageproperties/streamproperties/streamproperties.cpp000066400000000000000000000015401370472574300317200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "streamproperties.h" OLIVE_NAMESPACE_ENTER StreamProperties::StreamProperties(QWidget *parent) : QWidget(parent) { } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/footageproperties/streamproperties/streamproperties.h000066400000000000000000000021131370472574300313620ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef STREAMPROPERTIES_H #define STREAMPROPERTIES_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class StreamProperties : public QWidget { public: StreamProperties(QWidget* parent = nullptr); virtual void Accept(QUndoCommand*){} virtual bool SanityCheck(){return true;} }; OLIVE_NAMESPACE_EXIT #endif // STREAMPROPERTIES_H olive-continuous/app/dialog/footageproperties/streamproperties/videostreamproperties.cpp000066400000000000000000000167531370472574300327630ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "videostreamproperties.h" #include #include #include #include #include namespace OCIO = OCIO_NAMESPACE::v1; #include "project/item/footage/footage.h" #include "project/project.h" #include "undo/undostack.h" OLIVE_NAMESPACE_ENTER VideoStreamProperties::VideoStreamProperties(ImageStreamPtr stream) : stream_(stream) { QGridLayout* video_layout = new QGridLayout(this); video_layout->setMargin(0); int row = 0; video_layout->addWidget(new QLabel(tr("Interlacing:")), row, 0); video_interlace_combo_ = new QComboBox(); // These must match the Interlacing enum in ImageStream video_interlace_combo_->addItem(tr("None (Progressive)")); video_interlace_combo_->addItem(tr("Top-Field First")); video_interlace_combo_->addItem(tr("Bottom-Field First")); video_interlace_combo_->setCurrentIndex(stream->interlacing()); video_layout->addWidget(video_interlace_combo_, row, 1); row++; video_layout->addWidget(new QLabel(tr("Color Space:")), row, 0); video_color_space_ = new QComboBox(); OCIO::ConstConfigRcPtr config = stream->footage()->project()->color_manager()->GetConfig(); int number_of_colorspaces = config->getNumColorSpaces(); video_color_space_->addItem(tr("Default (%1)").arg(stream->footage()->project()->color_manager()->GetDefaultInputColorSpace())); for (int i=0;igetColorSpaceNameByIndex(i); video_color_space_->addItem(colorspace); } video_color_space_->setCurrentText(stream_->colorspace(false)); video_layout->addWidget(video_color_space_, row, 1); row++; video_premultiply_alpha_ = new QCheckBox(tr("Premultiplied Alpha")); video_premultiply_alpha_->setChecked(stream_->premultiplied_alpha()); video_layout->addWidget(video_premultiply_alpha_, row, 0, 1, 2); row++; if (IsImageSequence(stream.get())) { QGroupBox* imgseq_group = new QGroupBox(tr("Image Sequence")); QGridLayout* imgseq_layout = new QGridLayout(imgseq_group); int imgseq_row = 0; VideoStream* video_stream = static_cast(stream.get()); imgseq_layout->addWidget(new QLabel(tr("Start Index:")), imgseq_row, 0); imgseq_start_time_ = new IntegerSlider(); imgseq_start_time_->SetMinimum(0); imgseq_start_time_->SetValue(video_stream->start_time()); imgseq_layout->addWidget(imgseq_start_time_, imgseq_row, 1); imgseq_row++; imgseq_layout->addWidget(new QLabel(tr("End Index:")), imgseq_row, 0); imgseq_end_time_ = new IntegerSlider(); imgseq_end_time_->SetMinimum(0); imgseq_end_time_->SetValue(video_stream->start_time() + video_stream->duration() - 1); imgseq_layout->addWidget(imgseq_end_time_, imgseq_row, 1); video_layout->addWidget(imgseq_group, row, 0, 1, 2); } } void VideoStreamProperties::Accept(QUndoCommand *parent) { QString set_colorspace; if (video_color_space_->currentIndex() > 0) { set_colorspace = video_color_space_->currentText(); } if (video_premultiply_alpha_->isChecked() != stream_->premultiplied_alpha() || set_colorspace != stream_->colorspace(false)) { new VideoStreamChangeCommand(stream_, video_premultiply_alpha_->isChecked(), set_colorspace, static_cast(video_interlace_combo_->currentIndex()), parent); } if (IsImageSequence(stream_.get())) { VideoStreamPtr video_stream = std::static_pointer_cast(stream_); int64_t new_dur = imgseq_end_time_->GetValue() - imgseq_start_time_->GetValue() + 1; if (video_stream->start_time() != imgseq_start_time_->GetValue() || video_stream->duration() != new_dur) { new ImageSequenceChangeCommand(video_stream, imgseq_start_time_->GetValue(), new_dur, parent); } } } bool VideoStreamProperties::SanityCheck() { if (IsImageSequence(stream_.get())) { if (imgseq_start_time_->GetValue() >= imgseq_end_time_->GetValue()) { QMessageBox::critical(this, tr("Invalid Configuration"), tr("Image sequence end index must be a value higher than the start index."), QMessageBox::Ok); return false; } } return true; } bool VideoStreamProperties::IsImageSequence(ImageStream *stream) { return (stream->type() == Stream::kVideo && static_cast(stream)->is_image_sequence()); } VideoStreamProperties::VideoStreamChangeCommand::VideoStreamChangeCommand(ImageStreamPtr stream, bool premultiplied, QString colorspace, ImageStream::Interlacing interlacing, QUndoCommand *parent) : UndoCommand(parent), stream_(stream), new_premultiplied_(premultiplied), new_colorspace_(colorspace), new_interlacing_(interlacing) { } Project *VideoStreamProperties::VideoStreamChangeCommand::GetRelevantProject() const { return stream_->footage()->project(); } void VideoStreamProperties::VideoStreamChangeCommand::redo_internal() { old_premultiplied_ = stream_->premultiplied_alpha(); old_colorspace_ = stream_->colorspace(false); old_interlacing_ = stream_->interlacing(); stream_->set_premultiplied_alpha(new_premultiplied_); stream_->set_colorspace(new_colorspace_); stream_->set_interlacing(new_interlacing_); } void VideoStreamProperties::VideoStreamChangeCommand::undo_internal() { stream_->set_premultiplied_alpha(old_premultiplied_); stream_->set_colorspace(old_colorspace_); stream_->set_interlacing(old_interlacing_); } VideoStreamProperties::ImageSequenceChangeCommand::ImageSequenceChangeCommand(VideoStreamPtr video_stream, int64_t start_index, int64_t duration, QUndoCommand *parent) : UndoCommand(parent), video_stream_(video_stream), new_start_index_(start_index), new_duration_(duration) { } Project *VideoStreamProperties::ImageSequenceChangeCommand::GetRelevantProject() const { return video_stream_->footage()->project(); } void VideoStreamProperties::ImageSequenceChangeCommand::redo_internal() { old_start_index_ = video_stream_->start_time(); video_stream_->set_start_time(new_start_index_); old_duration_ = video_stream_->duration(); video_stream_->set_duration(new_duration_); } void VideoStreamProperties::ImageSequenceChangeCommand::undo_internal() { video_stream_->set_start_time(old_start_index_); video_stream_->set_duration(old_duration_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/footageproperties/streamproperties/videostreamproperties.h000066400000000000000000000063111370472574300324150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIDEOSTREAMPROPERTIES_H #define VIDEOSTREAMPROPERTIES_H #include #include #include "project/item/footage/videostream.h" #include "streamproperties.h" #include "undo/undocommand.h" #include "widget/slider/integerslider.h" OLIVE_NAMESPACE_ENTER class VideoStreamProperties : public StreamProperties { public: VideoStreamProperties(ImageStreamPtr stream); virtual void Accept(QUndoCommand* parent) override; virtual bool SanityCheck() override; private: static bool IsImageSequence(ImageStream* stream); /** * @brief Attached video stream */ ImageStreamPtr stream_; /** * @brief Setting for associated/premultiplied alpha */ QCheckBox* video_premultiply_alpha_; /** * @brief Setting for this media's color space */ QComboBox* video_color_space_; /** * @brief Setting for video interlacing */ QComboBox* video_interlace_combo_; /** * @brief Sets the start index for image sequences */ IntegerSlider* imgseq_start_time_; /** * @brief Sets the end index for image sequences */ IntegerSlider* imgseq_end_time_; class VideoStreamChangeCommand : public UndoCommand { public: VideoStreamChangeCommand(ImageStreamPtr stream, bool premultiplied, QString colorspace, ImageStream::Interlacing interlacing, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: ImageStreamPtr stream_; bool new_premultiplied_; QString new_colorspace_; ImageStream::Interlacing new_interlacing_; bool old_premultiplied_; QString old_colorspace_; ImageStream::Interlacing old_interlacing_; }; class ImageSequenceChangeCommand : public UndoCommand { public: ImageSequenceChangeCommand(VideoStreamPtr video_stream, int64_t start_index, int64_t duration, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: VideoStreamPtr video_stream_; int64_t new_start_index_; int64_t old_start_index_; int64_t new_duration_; int64_t old_duration_; }; }; OLIVE_NAMESPACE_EXIT #endif // VIDEOSTREAMPROPERTIES_H olive-continuous/app/dialog/keyframeproperties/000077500000000000000000000000001370472574300223535ustar00rootroot00000000000000olive-continuous/app/dialog/keyframeproperties/CMakeLists.txt000066400000000000000000000015311370472574300251130ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/keyframeproperties/keyframeproperties.h dialog/keyframeproperties/keyframeproperties.cpp PARENT_SCOPE ) olive-continuous/app/dialog/keyframeproperties/keyframeproperties.cpp000066400000000000000000000167201370472574300270050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keyframeproperties.h" #include #include #include "core.h" #include "common/timecodefunctions.h" #include "widget/keyframeview/keyframeviewundo.h" #include "widget/nodeparamview/nodeparamviewundo.h" OLIVE_NAMESPACE_ENTER KeyframePropertiesDialog::KeyframePropertiesDialog(const QList &keys, const rational &timebase, QWidget *parent) : QDialog(parent), keys_(keys), timebase_(timebase) { setWindowTitle(tr("Keyframe Properties")); QGridLayout* layout = new QGridLayout(this); int row = 0; layout->addWidget(new QLabel("Time:"), row, 0); time_slider_ = new TimeSlider(); time_slider_->SetTimebase(timebase_); layout->addWidget(time_slider_, row, 1); row++; layout->addWidget(new QLabel("Type:"), row, 0); type_select_ = new QComboBox(); connect(type_select_, SIGNAL(currentIndexChanged(int)), this, SLOT(KeyTypeChanged(int))); layout->addWidget(type_select_, row, 1); row++; // Bezier handles bezier_group_ = new QGroupBox(); QGridLayout* bezier_group_layout = new QGridLayout(bezier_group_); bezier_group_layout->addWidget(new QLabel(tr("In:")), 0, 0); bezier_in_x_slider_ = new FloatSlider(); bezier_group_layout->addWidget(bezier_in_x_slider_, 0, 1); bezier_in_y_slider_ = new FloatSlider(); bezier_group_layout->addWidget(bezier_in_y_slider_, 0, 2); bezier_group_layout->addWidget(new QLabel(tr("Out:")), 1, 0); bezier_out_x_slider_ = new FloatSlider(); bezier_group_layout->addWidget(bezier_out_x_slider_, 1, 1); bezier_out_y_slider_ = new FloatSlider(); bezier_group_layout->addWidget(bezier_out_y_slider_, 1, 2); layout->addWidget(bezier_group_, row, 0, 1, 2); bool all_same_time = true; bool can_set_time = true; bool all_same_type = true; bool all_same_bezier_in_x = true; bool all_same_bezier_in_y = true; bool all_same_bezier_out_x = true; bool all_same_bezier_out_y = true; for (int i=0;i 0) { NodeKeyframePtr prev_key = keys_.at(i-1); NodeKeyframePtr this_key = keys_.at(i); // Determine if the keyframes are all the same time or not if (all_same_time) { all_same_time = (prev_key->time() == this_key->time()); } // Determine if the keyframes are all the same type if (all_same_type) { all_same_type = (prev_key->type() == this_key->type()); } // Check all four bezier control points if (all_same_bezier_in_x) { all_same_bezier_in_x = (prev_key->bezier_control_in().x() == this_key->bezier_control_in().x()); } if (all_same_bezier_in_y) { all_same_bezier_in_y = (prev_key->bezier_control_in().y() == this_key->bezier_control_in().y()); } if (all_same_bezier_out_x) { all_same_bezier_out_x = (prev_key->bezier_control_out().x() == this_key->bezier_control_out().x()); } if (all_same_bezier_out_y) { all_same_bezier_out_y = (prev_key->bezier_control_out().y() == this_key->bezier_control_out().y()); } } // Determine if any keyframes are on the same track (in which case we can't set the time) if (can_set_time) { for (int j=0;jtrack() == keys_.at(i)->track()) { can_set_time = false; break; } } } if (!all_same_time && !all_same_type && !can_set_time && !all_same_bezier_in_x && !all_same_bezier_in_y && !all_same_bezier_out_x && !all_same_bezier_out_y) { break; } } if (all_same_time) { time_slider_->SetValue(Timecode::time_to_timestamp(keys_.first()->time(), timebase_)); } else { time_slider_->SetTristate(); } time_slider_->setEnabled(can_set_time); if (!all_same_type) { // If all keyframes aren't the same type, add an empty item type_select_->addItem(QStringLiteral("--"), -1); // Ensure UI updates for the index being 0 KeyTypeChanged(0); } type_select_->addItem(tr("Linear"), NodeKeyframe::kLinear); type_select_->addItem(tr("Hold"), NodeKeyframe::kHold); type_select_->addItem(tr("Bezier"), NodeKeyframe::kBezier); if (all_same_type) { // If all keyframes are the same type, set it here for (int i=0;icount();i++) { if (type_select_->itemData(i).toInt() == keys_.first()->type()) { type_select_->setCurrentIndex(i); // Ensure UI updates for this index KeyTypeChanged(i); break; } } } SetUpBezierSlider(bezier_in_x_slider_, all_same_bezier_in_x, keys_.first()->bezier_control_in().x()); SetUpBezierSlider(bezier_in_y_slider_, all_same_bezier_in_y, keys_.first()->bezier_control_in().y()); SetUpBezierSlider(bezier_out_x_slider_, all_same_bezier_out_x, keys_.first()->bezier_control_out().x()); SetUpBezierSlider(bezier_out_y_slider_, all_same_bezier_out_y, keys_.first()->bezier_control_out().y()); row++; QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttons->setCenterButtons(true); layout->addWidget(buttons, row, 0, 1, 2); connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); } void KeyframePropertiesDialog::accept() { QUndoCommand* command = new QUndoCommand(); rational new_time = Timecode::timestamp_to_time(time_slider_->GetValue(), timebase_); int new_type = type_select_->currentData().toInt(); foreach (NodeKeyframePtr key, keys_) { if (time_slider_->isEnabled() && !time_slider_->IsTristate()) { new NodeParamSetKeyframeTimeCommand(key, new_time, command); } if (new_type > -1) { new KeyframeSetTypeCommand(key, static_cast(new_type), command); } if (bezier_group_->isEnabled()) { new KeyframeSetBezierControlPoint(key, NodeKeyframe::kInHandle, QPointF(bezier_in_x_slider_->GetValue(), bezier_in_y_slider_->GetValue()), command); new KeyframeSetBezierControlPoint(key, NodeKeyframe::kOutHandle, QPointF(bezier_out_x_slider_->GetValue(), bezier_out_y_slider_->GetValue()), command); } } Core::instance()->undo_stack()->pushIfHasChildren(command); QDialog::accept(); } void KeyframePropertiesDialog::SetUpBezierSlider(FloatSlider *slider, bool all_same, double value) { if (all_same) { slider->SetValue(value); } else { slider->SetTristate(); } } void KeyframePropertiesDialog::KeyTypeChanged(int index) { bezier_group_->setEnabled(type_select_->itemData(index) == NodeKeyframe::kBezier); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/keyframeproperties/keyframeproperties.h000066400000000000000000000032531370472574300264470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef KEYFRAMEPROPERTIESDIALOG_H #define KEYFRAMEPROPERTIESDIALOG_H #include #include #include #include "node/keyframe.h" #include "widget/slider/floatslider.h" #include "widget/slider/timeslider.h" OLIVE_NAMESPACE_ENTER class KeyframePropertiesDialog : public QDialog { Q_OBJECT public: KeyframePropertiesDialog(const QList& keys, const rational& timebase, QWidget* parent = nullptr); public slots: virtual void accept() override; private: void SetUpBezierSlider(FloatSlider *slider, bool all_same, double value); const QList& keys_; rational timebase_; TimeSlider* time_slider_; QComboBox* type_select_; QGroupBox* bezier_group_; FloatSlider* bezier_in_x_slider_; FloatSlider* bezier_in_y_slider_; FloatSlider* bezier_out_x_slider_; FloatSlider* bezier_out_y_slider_; private slots: void KeyTypeChanged(int index); }; OLIVE_NAMESPACE_EXIT #endif // KEYFRAMEPROPERTIESDIALOG_H olive-continuous/app/dialog/preferences/000077500000000000000000000000001370472574300207345ustar00rootroot00000000000000olive-continuous/app/dialog/preferences/CMakeLists.txt000066400000000000000000000016511370472574300234770ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(tabs) set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/preferences/keysequenceeditor.h dialog/preferences/keysequenceeditor.cpp dialog/preferences/preferences.h dialog/preferences/preferences.cpp PARENT_SCOPE ) olive-continuous/app/dialog/preferences/keysequenceeditor.cpp000066400000000000000000000026661370472574300252020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keysequenceeditor.h" #include OLIVE_NAMESPACE_ENTER KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a) : QKeySequenceEdit(parent), action(a) { setKeySequence(action->shortcut()); } void KeySequenceEditor::set_action_shortcut() { action->setShortcut(keySequence()); } void KeySequenceEditor::reset_to_default() { setKeySequence(action->property("keydefault").toString()); } QString KeySequenceEditor::action_name() { return action->property("id").toString(); } QString KeySequenceEditor::export_shortcut() { QString ks = keySequence().toString(); if (ks != action->property("keydefault")) { return action->property("id").toString() + "\t" + ks; } return nullptr; } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/keysequenceeditor.h000066400000000000000000000065641370472574300246500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef KEYSEQUENCEEDITOR_H #define KEYSEQUENCEEDITOR_H #include #include "common/debug.h" OLIVE_NAMESPACE_ENTER /** * @brief The KeySequenceEditor class * * Simple derived class of QKeySequenceEdit that attaches to a QAction and provides functions for transferring * keyboard shortcuts to and from it. */ class KeySequenceEditor : public QKeySequenceEdit { Q_OBJECT public: /** * @brief KeySequenceEditor Constructor * * @param parent * * QWidget parent. * * @param a * * The QAction to link to. This cannot be changed throughout the lifetime of a KeySequenceEditor. */ KeySequenceEditor(QWidget *parent, QAction* a); /** * @brief Sets the attached QAction's shortcut to the shortcut entered in this field. * * This is not done automatically in case the user cancels out of the Preferences dialog, in which case the * expectation is that the changes made will not be saved. Therefore, this needs to be triggered manually when * PreferencesDialog saves. */ void set_action_shortcut(); /** * @brief Set this shortcut back to the QAction's default shortcut * * Each QAction contains the default shortcut in its `property("default")` and can be used to restore the default * "hard-coded" shortcut with this function. * * This function does not save the default shortcut back into the QAction, it simply loads the default shortcut from * the QAction into this edit field. To save it into the QAction, it's necessary to call set_action_shortcut() after * calling this function. */ void reset_to_default(); /** * @brief Return attached QAction's unique ID * * Each of Olive's menu actions has a unique string ID (that, unlike the text, is not translated) for matching with * an external shortcut configuration file. The ID is stored in the QAction's `property("id")`. This function returns * that ID. * * @return * * The QAction's unique ID. */ QString action_name(); /** * @brief Serialize this shortcut entry into a string that can be saved to a file * * @return * * A string serialization of this shortcut. The format is "[ID]\t[SEQUENCE]" where [ID] is the attached QAction's * unique identifier and [SEQUENCE] is the current keyboard shortcut in the field (NOT necessarily the shortcut in * the QAction). If the entered shortcut is the same as the QAction's default shortcut, the return value is empty * because a default shortcut does not need to be saved to a file. */ QString export_shortcut(); private: /** * @brief Internal reference to the linked QAction */ QAction* action; }; OLIVE_NAMESPACE_EXIT #endif // KEYSEQUENCEEDITOR_H olive-continuous/app/dialog/preferences/preferences.cpp000066400000000000000000000055251370472574300237500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferences.h" #include #include #include #include #include "config/config.h" #include "tabs/preferencesgeneraltab.h" #include "tabs/preferencesbehaviortab.h" #include "tabs/preferencesappearancetab.h" #include "tabs/preferencesdisktab.h" #include "tabs/preferencesaudiotab.h" #include "tabs/preferenceskeyboardtab.h" OLIVE_NAMESPACE_ENTER PreferencesDialog::PreferencesDialog(QWidget *parent, QMenuBar* main_menu_bar) : QDialog(parent) { setWindowTitle(tr("Preferences")); QVBoxLayout* layout = new QVBoxLayout(this); QSplitter* splitter = new QSplitter(); splitter->setChildrenCollapsible(false); layout->addWidget(splitter); list_widget_ = new QListWidget(); preference_pane_stack_ = new QStackedWidget(this); AddTab(new PreferencesGeneralTab(), tr("General")); AddTab(new PreferencesAppearanceTab(), tr("Appearance")); AddTab(new PreferencesBehaviorTab(), tr("Behavior")); AddTab(new PreferencesDiskTab(), tr("Disk")); AddTab(new PreferencesAudioTab(), tr("Audio")); AddTab(new PreferencesKeyboardTab(main_menu_bar), tr("Keyboard")); splitter->addWidget(list_widget_); splitter->addWidget(preference_pane_stack_); QDialogButtonBox* button_box = new QDialogButtonBox(this); button_box->setOrientation(Qt::Horizontal); button_box->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); layout->addWidget(button_box); connect(button_box, &QDialogButtonBox::accepted, this, &PreferencesDialog::accept); connect(button_box, &QDialogButtonBox::rejected, this, &PreferencesDialog::reject); connect(list_widget_, &QListWidget::currentRowChanged, preference_pane_stack_, &QStackedWidget::setCurrentIndex); } void PreferencesDialog::accept() { foreach (PreferencesTab* tab, tabs_) { if (!tab->Validate()) { return; } } foreach (PreferencesTab* tab, tabs_) { tab->Accept(); } QDialog::accept(); } void PreferencesDialog::AddTab(PreferencesTab *tab, const QString &title) { list_widget_->addItem(title); preference_pane_stack_->addWidget(tab); tabs_.append(tab); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/preferences.h000066400000000000000000000033311370472574300234060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESDIALOG_H #define PREFERENCESDIALOG_H #include #include #include #include #include #include #include "tabs/preferencestab.h" OLIVE_NAMESPACE_ENTER /** * @brief The PreferencesDialog class * * A dialog for the global application settings. Mostly an interface for Config. Can be loaded from any part of the * application. */ class PreferencesDialog : public QDialog { Q_OBJECT public: /** * @brief PreferencesDialog Constructor * * @param parent * * QWidget parent. Usually MainWindow. */ explicit PreferencesDialog(QWidget *parent, QMenuBar* main_menu_bar); private slots: /** * @brief Override of accept to save preferences to Config. */ virtual void accept() override; private: void AddTab(PreferencesTab* tab, const QString& title); QListWidget* list_widget_; QStackedWidget* preference_pane_stack_; QList tabs_; }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESDIALOG_H olive-continuous/app/dialog/preferences/tabs/000077500000000000000000000000001370472574300216655ustar00rootroot00000000000000olive-continuous/app/dialog/preferences/tabs/CMakeLists.txt000066400000000000000000000026611370472574300244320ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/preferences/tabs/preferencesgeneraltab.h dialog/preferences/tabs/preferencesgeneraltab.cpp dialog/preferences/tabs/preferencesbehaviortab.h dialog/preferences/tabs/preferencesbehaviortab.cpp dialog/preferences/tabs/preferencesdisktab.h dialog/preferences/tabs/preferencesdisktab.cpp dialog/preferences/tabs/preferencesappearancetab.h dialog/preferences/tabs/preferencesappearancetab.cpp dialog/preferences/tabs/preferencesaudiotab.h dialog/preferences/tabs/preferencesaudiotab.cpp dialog/preferences/tabs/preferenceskeyboardtab.h dialog/preferences/tabs/preferenceskeyboardtab.cpp dialog/preferences/tabs/preferencestab.h dialog/preferences/tabs/preferencestab.cpp PARENT_SCOPE ) olive-continuous/app/dialog/preferences/tabs/preferencesappearancetab.cpp000066400000000000000000000065051370472574300274070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferencesappearancetab.h" #include #include #include #include #include #include "node/node.h" #include "widget/colorbutton/colorbutton.h" OLIVE_NAMESPACE_ENTER PreferencesAppearanceTab::PreferencesAppearanceTab() { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); QGridLayout* appearance_layout = new QGridLayout(); layout->addLayout(appearance_layout); int row = 0; // Appearance -> Theme appearance_layout->addWidget(new QLabel(tr("Theme")), row, 0); style_ = new QComboBox(); style_list_ = StyleManager::ListInternal(); foreach (const StyleDescriptor& s, style_list_) { style_->addItem(s.name(), s.path()); if (s.path() == StyleManager::GetStyle()) { style_->setCurrentIndex(style_->count()-1); } } appearance_layout->addWidget(style_, row, 1); row++; { QGroupBox* color_group = new QGroupBox(); color_group->setTitle(tr("Node Color Scheme")); QGridLayout* color_layout = new QGridLayout(color_group); for (int i=0; i(i)); color_layout->addWidget(new QLabel(cat_name), i, 0); Color c = Config::Current()[QStringLiteral("NodeCatColor%1").arg(i)].value(); colors_.append(c.toQColor()); QPushButton* color_btn = new QPushButton(); connect(color_btn, &QPushButton::clicked, this, &PreferencesAppearanceTab::ColorButtonClicked); color_layout->addWidget(color_btn, i, 1); color_btns_.append(color_btn); UpdateButtonColor(i); } appearance_layout->addWidget(color_group, row, 0, 1, 2); } layout->addStretch(); } void PreferencesAppearanceTab::Accept() { QString style_path = style_->currentData().toString(); if (style_path != StyleManager::GetStyle()) { StyleManager::SetStyle(style_path); Config::Current()["Style"] = style_path; } for (int i=0;isetStyleSheet(QStringLiteral("background: %1;") .arg(colors_.at(index).name())); } void PreferencesAppearanceTab::ColorButtonClicked() { int index = color_btns_.indexOf(static_cast(sender())); QColor new_color = QColorDialog::getColor(colors_.at(index), this); if (new_color.isValid()) { colors_.replace(index, new_color); UpdateButtonColor(index); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferencesappearancetab.h000066400000000000000000000031441370472574300270500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESAPPEARANCETAB_H #define PREFERENCESAPPEARANCETAB_H #include #include #include #include "preferencestab.h" #include "ui/style/style.h" OLIVE_NAMESPACE_ENTER class PreferencesAppearanceTab : public PreferencesTab { Q_OBJECT public: PreferencesAppearanceTab(); virtual void Accept() override; private: /** * @brief Show a file dialog to browse for an external CSS file to load for styling the application. */ void BrowseForCSS(); void UpdateButtonColor(int index); /** * @brief UI widget for selecting the current UI style */ QComboBox* style_; /** * @brief List of internal styles */ QList style_list_; QString custom_style_path_; QList colors_; QList color_btns_; private slots: void ColorButtonClicked(); }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESAPPEARANCETAB_H olive-continuous/app/dialog/preferences/tabs/preferencesaudiotab.cpp000066400000000000000000000144311370472574300264060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferencesaudiotab.h" #include #include #include "audio/audiomanager.h" #include "config/config.h" OLIVE_NAMESPACE_ENTER PreferencesAudioTab::PreferencesAudioTab() { QGridLayout* audio_tab_layout = new QGridLayout(this); audio_tab_layout->setMargin(0); int row = 0; // Audio -> Output Device audio_tab_layout->addWidget(new QLabel(tr("Output Device:")), row, 0); audio_output_devices_ = new QComboBox(); audio_tab_layout->addWidget(audio_output_devices_, row, 1); row++; // Audio -> Input Device audio_tab_layout->addWidget(new QLabel(tr("Input Device:")), row, 0); audio_input_devices_ = new QComboBox(); audio_tab_layout->addWidget(audio_input_devices_, row, 1); row++; // Audio -> Sample Rate audio_tab_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); audio_sample_rate_ = new QComboBox(); /*combobox_audio_sample_rates(audio_sample_rate); for (int i=0;icount();i++) { if (audio_sample_rate->itemData(i).toInt() == olive::config.audio_rate) { audio_sample_rate->setCurrentIndex(i); break; } }*/ audio_tab_layout->addWidget(audio_sample_rate_, row, 1); row++; // Audio -> Audio Recording audio_tab_layout->addWidget(new QLabel(tr("Audio Recording:"), this), row, 0); recording_combobox_ = new QComboBox(); recording_combobox_->addItem(tr("Mono")); recording_combobox_->addItem(tr("Stereo")); // recordingComboBox->setCurrentIndex(olive::config.recording_mode - 1); audio_tab_layout->addWidget(recording_combobox_, row, 1); row++; refresh_devices_btn_ = new QPushButton(tr("Refresh Devices")); audio_tab_layout->addWidget(refresh_devices_btn_, row, 1); row++; RetrieveDeviceLists(); connect(refresh_devices_btn_, &QPushButton::clicked, this, &PreferencesAudioTab::RefreshDevices); connect(AudioManager::instance(), &AudioManager::OutputListReady, this, &PreferencesAudioTab::RetrieveOutputList); connect(AudioManager::instance(), &AudioManager::InputListReady, this, &PreferencesAudioTab::RetrieveInputList); } void PreferencesAudioTab::Accept() { // FIXME: Qt documentation states that QAudioDeviceInfo::deviceName() is a "unique identifiers", which would make them // ideal for saving in preferences, but in practice they don't actually appear to be unique. // See: https://bugreports.qt.io/browse/QTBUG-16841 // If we don't have the device list, we can't set it if (audio_output_devices_->isEnabled()) { // Get device info QAudioDeviceInfo selected_output; QString selected_output_name; // Index 0 is always the default device if (audio_output_devices_->currentIndex() == 0) { selected_output = QAudioDeviceInfo::defaultOutputDevice(); } else { selected_output = AudioManager::instance()->ListOutputDevices().at(audio_output_devices_->currentData().toInt()); selected_output_name = selected_output.deviceName(); } // Save it in the global application preferences if (Config::Current()["AudioOutput"] != selected_output_name) { Config::Current()["AudioOutput"] = selected_output_name; AudioManager::instance()->SetOutputDevice(selected_output); } } if (audio_input_devices_->isEnabled()) { QAudioDeviceInfo selected_input; QString selected_input_name; // Index 0 is always the default device if (audio_input_devices_->currentIndex() == 0) { selected_input = QAudioDeviceInfo::defaultInputDevice(); } else { selected_input = AudioManager::instance()->ListInputDevices().at(audio_input_devices_->currentData().toInt()); selected_input_name = selected_input.deviceName(); } if (Config::Current()["AudioInput"] != selected_input_name) { Config::Current()["AudioInput"] = selected_input_name; AudioManager::instance()->SetInputDevice(selected_input); } } } void PreferencesAudioTab::RefreshDevices() { AudioManager::instance()->RefreshDevices(); RetrieveDeviceLists(); } void PreferencesAudioTab::RetrieveOutputList() { PopulateComboBox(audio_output_devices_, AudioManager::instance()->IsRefreshingOutputs(), AudioManager::instance()->ListOutputDevices(), Config::Current()["AudioOutput"].toString()); UpdateRefreshButtonEnabled(); } void PreferencesAudioTab::RetrieveInputList() { PopulateComboBox(audio_input_devices_, AudioManager::instance()->IsRefreshingInputs(), AudioManager::instance()->ListInputDevices(), Config::Current()["AudioInput"].toString()); UpdateRefreshButtonEnabled(); } void PreferencesAudioTab::RetrieveDeviceLists() { RetrieveOutputList(); RetrieveInputList(); } void PreferencesAudioTab::UpdateRefreshButtonEnabled() { refresh_devices_btn_->setEnabled(audio_output_devices_->isEnabled() && audio_input_devices_->isEnabled()); } void PreferencesAudioTab::PopulateComboBox(QComboBox *cb, bool still_refreshing, const QList &list, const QString& preferred) { cb->clear(); cb->setEnabled(!still_refreshing); if (still_refreshing) { cb->addItem(tr("Please wait...")); } else { bool found_preferred_device = false; // Add null default item cb->addItem(tr("Default"), QVariant()); // For each entry, add it to the combobox for (int i=0;iaddItem(list.at(i).deviceName(), i); if (!found_preferred_device && list.at(i).deviceName() == preferred) { cb->setCurrentIndex(cb->count()-1); found_preferred_device = true; } } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferencesaudiotab.h000066400000000000000000000036501370472574300260540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESAUDIOTAB_H #define PREFERENCESAUDIOTAB_H #include #include #include #include "preferencestab.h" OLIVE_NAMESPACE_ENTER class PreferencesAudioTab : public PreferencesTab { Q_OBJECT public: PreferencesAudioTab(); virtual void Accept() override; private: /** * @brief UI widget for selecting the output audio device */ QComboBox* audio_output_devices_; /** * @brief UI widget for selecting the input audio device */ QComboBox* audio_input_devices_; /** * @brief UI widget for selecting the audio sampling rates */ QComboBox* audio_sample_rate_; /** * @brief UI widget for editing the recording channels */ QComboBox* recording_combobox_; /** * @brief Button that triggers a refresh of the available audio devices */ QPushButton* refresh_devices_btn_; private slots: void RefreshDevices(); void RetrieveOutputList(); void RetrieveInputList(); private: void RetrieveDeviceLists(); void UpdateRefreshButtonEnabled(); static void PopulateComboBox(QComboBox* cb, bool still_refreshing, const QList& list, const QString &preferred); }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESAUDIOTAB_H olive-continuous/app/dialog/preferences/tabs/preferencesbehaviortab.cpp000066400000000000000000000117231370472574300271050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferencesbehaviortab.h" #include #include #include "config/config.h" OLIVE_NAMESPACE_ENTER PreferencesBehaviorTab::PreferencesBehaviorTab() { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); behavior_tree_ = new QTreeWidget(); layout->addWidget(behavior_tree_); behavior_tree_->setHeaderLabel(tr("Behavior")); QTreeWidgetItem* general_group = AddParent(tr("General")); AddItem(tr("Enable hover focus"), QStringLiteral("HoverFocus"), tr("Panels will be considered focused when the mouse cursor is over them without having to click them."), general_group); AddItem(tr("Scroll wheel zooms by default instead of scrolling"), QStringLiteral("ScrollZooms"), tr("Holding CTRL while using Olive toggles this setting"), general_group); QTreeWidgetItem* audio_group = AddParent(tr("Audio")); AddItem(tr("Enable audio scrubbing"), QStringLiteral("AudioScrubbing"), audio_group); QTreeWidgetItem* timeline_group = AddParent(tr("Timeline")); AddItem(tr("Auto-Seek to Imported Clips"), QStringLiteral("EnableSeekToImport"), timeline_group); AddItem(tr("Edit Tool Also Seeks"), QStringLiteral("EditToolAlsoSeeks"), timeline_group); AddItem(tr("Edit Tool Selects Links"), QStringLiteral("EditToolSelectsLinks"), timeline_group); AddItem(tr("Enable Drag Files to Timeline"), QStringLiteral("EnableDragFilesToTimeline"), timeline_group); AddItem(tr("Invert Timeline Scroll Axes"), QStringLiteral("InvertTimelineScrollAxes"), tr("Hold ALT on any UI element to switch scrolling axes"), timeline_group); AddItem(tr("Seek Also Selects"), QStringLiteral("SelectAlsoSeeks"), timeline_group); AddItem(tr("Seek to the End of Pastes"), QStringLiteral("PasteSeeks"), timeline_group); AddItem(tr("Selecting Also Seeks"), QStringLiteral("SelectAlsoSeeks"), timeline_group); QTreeWidgetItem* playback_group = AddParent(tr("Playback")); AddItem(tr("Ask For Name When Setting Marker"), QStringLiteral("SetNameWithMarker"), playback_group); AddItem(tr("Automatically rewind at the end of a sequence"), QStringLiteral("AutoSeekToBeginning"), playback_group); QTreeWidgetItem* project_group = AddParent(tr("Project")); AddItem(tr("Drop Files on Media to Replace"), QStringLiteral("DropFileOnMediaToReplace"), project_group); QTreeWidgetItem* node_group = AddParent(tr("Nodes")); AddItem(tr("Add Default Effects to New Clips"), QStringLiteral("AddDefaultEffectsToClips"), node_group); AddItem(tr("Auto-Scale By Default"), QStringLiteral("AutoscaleByDefault"), node_group); } void PreferencesBehaviorTab::Accept() { QMap::const_iterator iterator; for (iterator=config_map_.begin();iterator!=config_map_.end();iterator++) { Config::Current()[iterator.value()] = (iterator.key()->checkState(0) == Qt::Checked); } } QTreeWidgetItem* PreferencesBehaviorTab::AddItem(const QString &text, const QString &config_key, const QString& tooltip, QTreeWidgetItem* parent) { QTreeWidgetItem* item = new QTreeWidgetItem({text}); item->setToolTip(0, tooltip); item->setCheckState(0, Config::Current()[config_key].toBool() ? Qt::Checked : Qt::Unchecked); config_map_.insert(item, config_key); if (parent) { parent->addChild(item); } else { behavior_tree_->addTopLevelItem(item); } return item; } QTreeWidgetItem *PreferencesBehaviorTab::AddItem(const QString &text, const QString &config_key, QTreeWidgetItem *parent) { return AddItem(text, config_key, QString(), parent); } QTreeWidgetItem *PreferencesBehaviorTab::AddParent(const QString &text, const QString &tooltip, QTreeWidgetItem *parent) { QTreeWidgetItem* item = new QTreeWidgetItem({text}); item->setToolTip(0, tooltip); if (parent) { parent->addChild(item); } else { behavior_tree_->addTopLevelItem(item); } return item; } QTreeWidgetItem *PreferencesBehaviorTab::AddParent(const QString &text, QTreeWidgetItem *parent) { return AddParent(text, QString(), parent); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferencesbehaviortab.h000066400000000000000000000030401370472574300265430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESBEHAVIORTAB_H #define PREFERENCESBEHAVIORTAB_H #include #include "preferencestab.h" OLIVE_NAMESPACE_ENTER class PreferencesBehaviorTab : public PreferencesTab { Q_OBJECT public: PreferencesBehaviorTab(); virtual void Accept() override; private: QTreeWidgetItem *AddParent(const QString& text, const QString &tooltip, QTreeWidgetItem *parent = nullptr); QTreeWidgetItem *AddParent(const QString& text, QTreeWidgetItem *parent = nullptr); QTreeWidgetItem *AddItem(const QString& text, const QString& config_key, const QString &tooltip, QTreeWidgetItem *parent ); QTreeWidgetItem *AddItem(const QString& text, const QString& config_key, QTreeWidgetItem *parent); QMap config_map_; QTreeWidget* behavior_tree_; }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESBEHAVIORTAB_H olive-continuous/app/dialog/preferences/tabs/preferencesdisktab.cpp000066400000000000000000000130231370472574300262330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferencesdisktab.h" #include #include #include #include #include #include #include "render/diskmanager.h" OLIVE_NAMESPACE_ENTER PreferencesDiskTab::PreferencesDiskTab() { QVBoxLayout* outer_layout = new QVBoxLayout(this); QGroupBox* disk_management_group = new QGroupBox(tr("Disk Management")); outer_layout->addWidget(disk_management_group); QGridLayout* disk_management_layout = new QGridLayout(disk_management_group); int row = 0; disk_management_layout->addWidget(new QLabel(tr("Disk Cache Location:")), row, 0); disk_cache_location_ = new QLineEdit(); disk_cache_location_->setText(Config::Current()["DiskCachePath"].toString()); connect(disk_cache_location_, &QLineEdit::textChanged, this, &PreferencesDiskTab::DiskCacheLineEditChanged); disk_management_layout->addWidget(disk_cache_location_, row, 1); QPushButton* browse_btn = new QPushButton(tr("Browse")); connect(browse_btn, &QPushButton::clicked, this, &PreferencesDiskTab::BrowseDiskCachePath); disk_management_layout->addWidget(browse_btn, row, 2); row++; disk_management_layout->addWidget(new QLabel(tr("Maximum Disk Cache:")), row, 0); maximum_cache_slider_ = new FloatSlider(); maximum_cache_slider_->SetFormat(tr("%1 GB")); maximum_cache_slider_->SetMinimum(1.0); maximum_cache_slider_->SetValue(Config::Current()["DiskCacheSize"].toDouble()); disk_management_layout->addWidget(maximum_cache_slider_, row, 1, 1, 2); row++; clear_cache_btn_ = new QPushButton(tr("Clear Disk Cache")); connect(clear_cache_btn_, &QPushButton::clicked, this, &PreferencesDiskTab::ClearDiskCache); disk_management_layout->addWidget(clear_cache_btn_, row, 1, 1, 2); row++; clear_disk_cache_ = new QCheckBox(tr("Automatically clear disk cache on close")); clear_disk_cache_->setChecked(Config::Current()["ClearDiskCacheOnClose"].toBool()); disk_management_layout->addWidget(clear_disk_cache_, row, 1, 1, 2); QGroupBox* cache_behavior = new QGroupBox(tr("Cache Behavior")); outer_layout->addWidget(cache_behavior); QGridLayout* cache_behavior_layout = new QGridLayout(cache_behavior); row = 0; cache_behavior_layout->addWidget(new QLabel(tr("Cache Ahead:")), row, 0); cache_ahead_slider_ = new FloatSlider(); cache_ahead_slider_->SetFormat(tr("%1 seconds")); cache_ahead_slider_->SetMinimum(0); cache_ahead_slider_->SetValue(Config::Current()["DiskCacheAhead"].value().toDouble()); cache_behavior_layout->addWidget(cache_ahead_slider_, row, 1); cache_behavior_layout->addWidget(new QLabel(tr("Cache Behind:")), row, 2); cache_behind_slider_ = new FloatSlider(); cache_behind_slider_->SetMinimum(0); cache_behind_slider_->SetFormat(tr("%1 seconds")); cache_behind_slider_->SetValue(Config::Current()["DiskCacheBehind"].value().toDouble()); cache_behavior_layout->addWidget(cache_behind_slider_, row, 3); outer_layout->addStretch(); } void PreferencesDiskTab::Accept() { Config::Current()["DiskCachePath"] = disk_cache_location_->text(); Config::Current()["DiskCacheSize"] = maximum_cache_slider_->GetValue(); Config::Current()["ClearDiskCacheOnClose"] = clear_disk_cache_->isChecked(); Config::Current()["DiskCacheBehind"] = QVariant::fromValue(rational::fromDouble(cache_behind_slider_->GetValue())); Config::Current()["DiskCacheAhead"] = QVariant::fromValue(rational::fromDouble(cache_ahead_slider_->GetValue())); } void PreferencesDiskTab::DiskCacheLineEditChanged() { QString entered_dir = disk_cache_location_->text(); if (!entered_dir.isEmpty() && !QDir(entered_dir).exists()) { disk_cache_location_->setStyleSheet(QStringLiteral("color: red;")); } else { disk_cache_location_->setStyleSheet(QString()); } } void PreferencesDiskTab::BrowseDiskCachePath() { QString dir = QFileDialog::getExistingDirectory(this, tr("Browse for disk cache path"), disk_cache_location_->text()); if (!dir.isEmpty()) { disk_cache_location_->setText(dir); } } void PreferencesDiskTab::ClearDiskCache() { if (QMessageBox::question(this, tr("Clear Disk Cache"), tr("Are you sure you want to clear the disk cache in '%1'?").arg(Config::Current()["DiskCachePath"].toString()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { clear_cache_btn_->setEnabled(false); if (DiskManager::instance()->ClearDiskCache(false)) { clear_cache_btn_->setText(tr("Disk Cache Cleared")); } else { QMessageBox::information(this, tr("Clear Disk Cache"), tr("Disk cache failed to fully clear. You may have to delete the cache files manually."), QMessageBox::Ok); clear_cache_btn_->setText(tr("Disk Cache Partially Cleared")); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferencesdisktab.h000066400000000000000000000026511370472574300257050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESDISKTAB_H #define PREFERENCESDISKTAB_H #include #include #include #include "preferencestab.h" #include "widget/slider/floatslider.h" OLIVE_NAMESPACE_ENTER class PreferencesDiskTab : public PreferencesTab { Q_OBJECT public: PreferencesDiskTab(); virtual void Accept() override; private: QLineEdit* disk_cache_location_; FloatSlider* maximum_cache_slider_; FloatSlider* cache_ahead_slider_; FloatSlider* cache_behind_slider_; QCheckBox* clear_disk_cache_; QPushButton* clear_cache_btn_; private slots: void DiskCacheLineEditChanged(); void BrowseDiskCachePath(); void ClearDiskCache(); }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESDISKTAB_H olive-continuous/app/dialog/preferences/tabs/preferencesgeneraltab.cpp000066400000000000000000000102351370472574300267200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferencesgeneraltab.h" #include #include #include #include "common/autoscroll.h" #include "dialog/sequence/sequence.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER PreferencesGeneralTab::PreferencesGeneralTab() { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); QGridLayout* general_layout = new QGridLayout(); layout->addLayout(general_layout); int row = 0; // General -> Language general_layout->addWidget(new QLabel(tr("Language:")), row, 0); language_combobox_ = new QComboBox(); // Add default language (en-US) language_combobox_->addItem(QLocale("en_US").nativeLanguageName()); /* // add languages from file QList translation_paths = get_language_paths(); // iterate through all language search paths for (int j=0;jaddItem(QLocale(locale_str).nativeLanguageName(), locale_relative_path); if (olive::config.language_file == locale_relative_path) { language_combobox->setCurrentIndex(language_combobox->count() - 1); } } } } */ general_layout->addWidget(language_combobox_, row, 1); row++; general_layout->addWidget(new QLabel(tr("Auto-Scroll Method:")), row, 0); // ComboBox indices match enum indices autoscroll_method_ = new QComboBox(); autoscroll_method_->addItem(tr("None"), AutoScroll::kNone); autoscroll_method_->addItem(tr("Page Scrolling"), AutoScroll::kPage); autoscroll_method_->addItem(tr("Smooth Scrolling"), AutoScroll::kSmooth); autoscroll_method_->setCurrentIndex(Config::Current()["Autoscroll"].toInt()); general_layout->addWidget(autoscroll_method_, row, 1); row++; general_layout->addWidget(new QLabel(tr("Rectified Waveforms:")), row, 0); rectified_waveforms_ = new QCheckBox(); rectified_waveforms_->setChecked(Config::Current()["RectifiedWaveforms"].toBool()); general_layout->addWidget(rectified_waveforms_, row, 1); row++; general_layout->addWidget(new QLabel(tr("Default Still Image Length:")), row, 0); default_still_length_ = new FloatSlider(); default_still_length_->SetMinimum(0.1); default_still_length_->SetFormat(tr("%1 seconds")); default_still_length_->SetValue(Config::Current()["DefaultStillLength"].value().toDouble()); general_layout->addWidget(default_still_length_); layout->addStretch(); } void PreferencesGeneralTab::Accept() { Config::Current()["RectifiedWaveforms"] = rectified_waveforms_->isChecked(); Config::Current()["Autoscroll"] = autoscroll_method_->currentData(); Config::Current()["DefaultStillLength"] = QVariant::fromValue(rational::fromDouble(default_still_length_->GetValue())); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferencesgeneraltab.h000066400000000000000000000024531370472574300263700ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESGENERALTAB_H #define PREFERENCESGENERALTAB_H #include #include #include #include "preferencestab.h" #include "project/item/sequence/sequence.h" #include "widget/slider/floatslider.h" OLIVE_NAMESPACE_ENTER class PreferencesGeneralTab : public PreferencesTab { Q_OBJECT public: PreferencesGeneralTab(); virtual void Accept() override; private: QComboBox* language_combobox_; QComboBox* autoscroll_method_; QCheckBox* rectified_waveforms_; FloatSlider* default_still_length_; }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESGENERALTAB_H olive-continuous/app/dialog/preferences/tabs/preferenceskeyboardtab.cpp000066400000000000000000000201131370472574300270770ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferenceskeyboardtab.h" #include #include #include #include #include #include OLIVE_NAMESPACE_ENTER PreferencesKeyboardTab::PreferencesKeyboardTab(QMenuBar *menubar) { QVBoxLayout* shortcut_layout = new QVBoxLayout(this); shortcut_layout->setMargin(0); QLineEdit* key_search_line = new QLineEdit(); key_search_line->setPlaceholderText(tr("Search for action or shortcut")); connect(key_search_line, SIGNAL(textChanged(const QString &)), this, SLOT(refine_shortcut_list(const QString &))); shortcut_layout->addWidget(key_search_line); keyboard_tree_ = new QTreeWidget(); QTreeWidgetItem* tree_header = keyboard_tree_->headerItem(); tree_header->setText(0, tr("Action")); tree_header->setText(1, tr("Shortcut")); shortcut_layout->addWidget(keyboard_tree_); QHBoxLayout* reset_shortcut_layout = new QHBoxLayout(); QPushButton* import_shortcut_button = new QPushButton(tr("Import")); reset_shortcut_layout->addWidget(import_shortcut_button); connect(import_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(load_shortcut_file())); QPushButton* export_shortcut_button = new QPushButton(tr("Export")); reset_shortcut_layout->addWidget(export_shortcut_button); connect(export_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(save_shortcut_file())); reset_shortcut_layout->addStretch(); QPushButton* reset_selected_shortcut_button = new QPushButton(tr("Reset Selected")); reset_shortcut_layout->addWidget(reset_selected_shortcut_button); connect(reset_selected_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_default_shortcut())); QPushButton* reset_all_shortcut_button = new QPushButton(tr("Reset All")); reset_shortcut_layout->addWidget(reset_all_shortcut_button); connect(reset_all_shortcut_button, SIGNAL(clicked(bool)), this, SLOT(reset_all_shortcuts())); shortcut_layout->addLayout(reset_shortcut_layout); setup_kbd_shortcuts(menubar); } void PreferencesKeyboardTab::Accept() { // Save keyboard shortcuts for (int i=0;iset_action_shortcut(); } } void PreferencesKeyboardTab::setup_kbd_shortcuts(QMenuBar* menubar) { QList menus = menubar->actions(); for (int i=0;imenu(); QTreeWidgetItem* item = new QTreeWidgetItem(keyboard_tree_); item->setText(0, menu->title().replace("&", "")); keyboard_tree_->addTopLevelItem(item); setup_kbd_shortcut_worker(menu, item); } for (int i=0;iproperty("id").isNull()) { KeySequenceEditor* editor = new KeySequenceEditor(keyboard_tree_, key_shortcut_actions_.at(i)); keyboard_tree_->setItemWidget(key_shortcut_items_.at(i), 1, editor); key_shortcut_fields_.append(editor); } } } void PreferencesKeyboardTab::setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent) { QList actions = menu->actions(); for (int i=0;iisSeparator() && a->property("keyignore").isNull()) { QTreeWidgetItem* item = new QTreeWidgetItem(parent); item->setText(0, a->text().replace("&", "")); parent->addChild(item); if (a->menu() != nullptr) { item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); setup_kbd_shortcut_worker(a->menu(), item); } else { key_shortcut_items_.append(item); key_shortcut_actions_.append(a); } } } } void PreferencesKeyboardTab::reset_default_shortcut() { QList items = keyboard_tree_->selectedItems(); for (int i=0;iselectedItems().at(i); static_cast(keyboard_tree_->itemWidget(item, 1))->reset_to_default(); } } void PreferencesKeyboardTab::reset_all_shortcuts() { if (QMessageBox::question( this, tr("Confirm Reset All Shortcuts"), tr("Are you sure you wish to reset all keyboard shortcuts to their defaults?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { for (int i=0;ireset_to_default(); } } } bool PreferencesKeyboardTab::refine_shortcut_list(const QString &s, QTreeWidgetItem* parent) { if (parent == nullptr) { for (int i=0;itopLevelItemCount();i++) { refine_shortcut_list(s, keyboard_tree_->topLevelItem(i)); } } else { parent->setExpanded(!s.isEmpty()); bool all_children_are_hidden = !s.isEmpty(); for (int i=0;ichildCount();i++) { QTreeWidgetItem* item = parent->child(i); if (item->childCount() > 0) { all_children_are_hidden = refine_shortcut_list(s, item); } else { item->setHidden(false); if (s.isEmpty()) { all_children_are_hidden = false; } else { QString shortcut; if (keyboard_tree_->itemWidget(item, 1) != nullptr) { shortcut = static_cast(keyboard_tree_->itemWidget(item, 1))->keySequence().toString(); } if (item->text(0).contains(s, Qt::CaseInsensitive) || shortcut.contains(s, Qt::CaseInsensitive)) { all_children_are_hidden = false; } else { item->setHidden(true); } } } } if (parent->text(0).contains(s, Qt::CaseInsensitive)) all_children_are_hidden = false; parent->setHidden(all_children_are_hidden); return all_children_are_hidden; } return true; } void PreferencesKeyboardTab::load_shortcut_file() { QString fn = QFileDialog::getOpenFileName(this, tr("Import Keyboard Shortcuts")); if (!fn.isEmpty()) { QFile f(fn); if (f.exists() && f.open(QFile::ReadOnly)) { QByteArray ba = f.readAll(); f.close(); for (int i=0;iaction_name()); if (index == 0 || (index > 0 && ba.at(index-1) == '\n')) { while (index < ba.size() && ba.at(index) != '\t') index++; QString ks; index++; while (index < ba.size() && ba.at(index) != '\n') { ks.append(ba.at(index)); index++; } key_shortcut_fields_.at(i)->setKeySequence(ks); } else { key_shortcut_fields_.at(i)->reset_to_default(); } } } else { QMessageBox::critical( this, tr("Error saving shortcuts"), tr("Failed to open file for reading") ); } } } void PreferencesKeyboardTab::save_shortcut_file() { QString fn = QFileDialog::getSaveFileName(this, tr("Export Keyboard Shortcuts")); if (!fn.isEmpty()) { QFile f(fn); if (f.open(QFile::WriteOnly)) { bool start = true; for (int i=0;iexport_shortcut(); if (!s.isEmpty()) { if (!start) f.write("\n"); f.write(s.toUtf8()); start = false; } } f.close(); QMessageBox::information(this, tr("Export Shortcuts"), tr("Shortcuts exported successfully")); } else { QMessageBox::critical(this, tr("Error saving shortcuts"), tr("Failed to open file for writing")); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferenceskeyboardtab.h000066400000000000000000000101631370472574300265500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESKEYBOARDTAB_H #define PREFERENCESKEYBOARDTAB_H #include #include #include "preferencestab.h" #include "../keysequenceeditor.h" OLIVE_NAMESPACE_ENTER class PreferencesKeyboardTab : public PreferencesTab { Q_OBJECT public: PreferencesKeyboardTab(QMenuBar* menubar); virtual void Accept() override; private slots: /** * @brief Show a file dialog to load an external shortcut preset from file */ void load_shortcut_file(); /** * @brief Show a file dialog to save an external shortcut preset from file */ void save_shortcut_file(); /** * @brief Reset all selected shortcuts in keyboard_tree to their defaults */ void reset_default_shortcut(); /** * @brief Reset all shortcuts indiscriminately to their defaults * * This is safe to call directly as it'll ask the user if they wish to do so before it resets. */ void reset_all_shortcuts(); /** * @brief Shows/hides shortcut entries according to a shortcut query. * * This function can be directly connected to QLineEdit::textChanged() for simplicity. * * @param s * * The search query to compare shortcut names to. * * @param parent * * This is used as the function calls itself recursively to traverse the menu item hierarchy. This should be left as * nullptr when called externally. * * @return * * Value used as function calls itself recursively to determine if a menu parent has any children that are not hidden. * If so, TRUE is returned so the parent is shown too (even if it doesn't match the search query). If not, FALSE is * returned so the parent is hidden. */ bool refine_shortcut_list(const QString &s, QTreeWidgetItem* parent = nullptr); private: /** * @brief Populate keyboard shortcut panel with keyboard shortcuts from the menu bar * * @param menu * * A reference to the main application's menu bar. Usually MainWindow::menuBar(). */ void setup_kbd_shortcuts(QMenuBar* menu); /** * @brief Internal function called by setup_kbd_shortcuts() to traverse down the menu bar's hierarchy and populate the * shortcut panel. * * This function will call itself recursively as it finds submenus belong to the menu provided. It will also create * QTreeWidgetItems as children of the parent item provided, either using them as parents themselves for submenus * or attaching a KeySequenceEditor to them for shortcut editing. * * @param menu * * The current menu to traverse down. * * @param parent * * The parent item to add QTreeWidgetItems to. */ void setup_kbd_shortcut_worker(QMenu* menu, QTreeWidgetItem* parent); /** * @brief UI widget for editing keyboard shortcuts */ QTreeWidget* keyboard_tree_; /** * @brief List of keyboard shortcut actions that can be triggered (links with key_shortcut_items and * key_shortcut_fields) */ QVector key_shortcut_actions_; /** * @brief List of keyboard shortcut items in keyboard_tree corresponding to existing actions (links with * key_shortcut_actions and key_shortcut_fields) */ QVector key_shortcut_items_; /** * @brief List of keyboard shortcut editing fields in keyboard_tree corresponding to existing actions (links with * key_shortcut_actions and key_shortcut_fields) */ QVector key_shortcut_fields_; }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESKEYBOARDTAB_H olive-continuous/app/dialog/preferences/tabs/preferencestab.cpp000066400000000000000000000015051370472574300253620ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "preferencestab.h" OLIVE_NAMESPACE_ENTER bool PreferencesTab::Validate() { return true; } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/preferences/tabs/preferencestab.h000066400000000000000000000017771370472574300250420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PREFERENCESTAB_H #define PREFERENCESTAB_H #include #include "config/config.h" OLIVE_NAMESPACE_ENTER class PreferencesTab : public QWidget { public: PreferencesTab() = default; virtual bool Validate(); virtual void Accept() = 0; }; OLIVE_NAMESPACE_EXIT #endif // PREFERENCESTAB_H olive-continuous/app/dialog/progress/000077500000000000000000000000001370472574300202775ustar00rootroot00000000000000olive-continuous/app/dialog/progress/CMakeLists.txt000066400000000000000000000014611370472574300230410ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/progress/progress.h dialog/progress/progress.cpp PARENT_SCOPE ) olive-continuous/app/dialog/progress/progress.cpp000066400000000000000000000053241370472574300226530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "progress.h" #include #include #include #include #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER ProgressDialog::ProgressDialog(const QString& message, const QString& title, QWidget *parent) : QDialog(parent) { if (!title.isEmpty()) { setWindowTitle(title); } QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(new QLabel(message)); bar_ = new QProgressBar(); bar_->setMinimum(0); bar_->setValue(0); bar_->setMaximum(100); layout->addWidget(bar_); elapsed_timer_lbl_ = new ElapsedCounterWidget(); layout->addWidget(elapsed_timer_lbl_); QHBoxLayout* cancel_layout = new QHBoxLayout(); layout->addLayout(cancel_layout); cancel_layout->setMargin(0); cancel_layout->setSpacing(0); cancel_layout->addStretch(); QPushButton* cancel_btn = new QPushButton(tr("Cancel")); connect(cancel_btn, &QPushButton::clicked, this, &ProgressDialog::Cancelled); cancel_layout->addWidget(cancel_btn); cancel_layout->addStretch(); } void ProgressDialog::showEvent(QShowEvent *e) { QDialog::showEvent(e); elapsed_timer_lbl_->Start(); Core::instance()->main_window()->SetApplicationProgressStatus(MainWindow::kProgressShow); } void ProgressDialog::closeEvent(QCloseEvent *e) { QDialog::closeEvent(e); Core::instance()->main_window()->SetApplicationProgressStatus(MainWindow::kProgressNone); } void ProgressDialog::SetProgress(double value) { int percent = qRound(100.0 * value); bar_->setValue(percent); elapsed_timer_lbl_->SetProgress(value); Core::instance()->main_window()->SetApplicationProgressValue(percent); } void ProgressDialog::ShowErrorMessage(const QString &title, const QString &message) { Core::instance()->main_window()->SetApplicationProgressStatus(MainWindow::kProgressError); QMessageBox b(this); b.setIcon(QMessageBox::Critical); b.setWindowModality(Qt::WindowModal); b.setWindowTitle(title); b.setText(message); b.addButton(QMessageBox::Ok); b.exec(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/progress/progress.h000066400000000000000000000026701370472574300223210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROGRESSDIALOG_H #define PROGRESSDIALOG_H #include #include #include "common/debug.h" #include "widget/taskview/elapsedcounterwidget.h" OLIVE_NAMESPACE_ENTER class ProgressDialog : public QDialog { Q_OBJECT public: ProgressDialog(const QString &message, const QString &title, QWidget* parent = nullptr); protected: virtual void showEvent(QShowEvent* e) override; virtual void closeEvent(QCloseEvent *) override; public slots: void SetProgress(double value); signals: void Cancelled(); protected: void ShowErrorMessage(const QString& title, const QString& message); private: QProgressBar* bar_; ElapsedCounterWidget* elapsed_timer_lbl_; }; OLIVE_NAMESPACE_EXIT #endif // PROGRESSDIALOG_H olive-continuous/app/dialog/projectproperties/000077500000000000000000000000001370472574300222165ustar00rootroot00000000000000olive-continuous/app/dialog/projectproperties/CMakeLists.txt000066400000000000000000000015251370472574300247610ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/projectproperties/projectproperties.h dialog/projectproperties/projectproperties.cpp PARENT_SCOPE ) olive-continuous/app/dialog/projectproperties/projectproperties.cpp000066400000000000000000000157311370472574300265140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectproperties.h" #include #include #include #include #include #include #include namespace OCIO = OCIO_NAMESPACE::v1; #include "config/config.h" #include "core.h" #include "render/colormanager.h" OLIVE_NAMESPACE_ENTER ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : QDialog(parent), working_project_(p), ocio_config_is_valid_(true) { QVBoxLayout* layout = new QVBoxLayout(this); setWindowTitle(tr("Project Properties for '%1'").arg(working_project_->name())); QTabWidget* tabs = new QTabWidget; layout->addWidget(tabs); { // Color management group QWidget* color_group = new QWidget(); QGridLayout* color_layout = new QGridLayout(color_group); int row = 0; color_layout->addWidget(new QLabel(tr("OpenColorIO Configuration:")), row, 0); ocio_filename_ = new QLineEdit(); ocio_filename_->setPlaceholderText(tr("(default)")); color_layout->addWidget(ocio_filename_, row, 1); row++; color_layout->addWidget(new QLabel(tr("Default Input Color Space:")), row, 0); default_input_colorspace_ = new QComboBox(); color_layout->addWidget(default_input_colorspace_, row, 1, 1, 2); row++; QPushButton* browse_btn = new QPushButton(tr("Browse")); color_layout->addWidget(browse_btn, 0, 2); connect(browse_btn, &QPushButton::clicked, this, &ProjectPropertiesDialog::BrowseForOCIOConfig); ocio_filename_->setText(working_project_->color_manager()->GetConfigFilename()); connect(ocio_filename_, &QLineEdit::textChanged, this, &ProjectPropertiesDialog::OCIOFilenameUpdated); OCIOFilenameUpdated(); tabs->addTab(color_group, tr("Color Management")); } { // Paths group QWidget* paths_group = new QWidget(); QGridLayout* paths_layout = new QGridLayout(paths_group); cache_path_ = new PathWidget(working_project_->cache_path(), this); int row = 0; paths_layout->addWidget(new QLabel(tr("Cache Path:")), row, 0); paths_layout->addWidget(cache_path_->path_edit(), row, 1); paths_layout->addWidget(cache_path_->browse_btn(), row, 2); paths_layout->addWidget(cache_path_->default_box(), row, 3); tabs->addTab(paths_group, tr("Paths")); } QDialogButtonBox* dialog_btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); layout->addWidget(dialog_btns); connect(dialog_btns, &QDialogButtonBox::accepted, this, &ProjectPropertiesDialog::accept); connect(dialog_btns, &QDialogButtonBox::rejected, this, &ProjectPropertiesDialog::reject); } void ProjectPropertiesDialog::accept() { if (!ocio_config_is_valid_) { QMessageBox mb(this); mb.setWindowModality(Qt::WindowModal); mb.setIcon(QMessageBox::Critical); mb.setWindowTitle(tr("OpenColorIO Config Error")); mb.setText(tr("Failed to set OpenColorIO configuration: %1").arg(ocio_config_error_)); mb.addButton(QMessageBox::Ok); mb.exec(); return; } if (!cache_path_->PathIsValid(true)) { QMessageBox mb(this); mb.setWindowModality(Qt::WindowModal); mb.setIcon(QMessageBox::Critical); mb.setWindowTitle(tr("Invalid path")); mb.setText(tr("The cache path is invalid. Please check it and try again.")); mb.addButton(QMessageBox::Ok); mb.exec(); return; } working_project_->set_cache_path(cache_path_->path_edit()->text()); // This should ripple changes throughout the program that the color config has changed, therefore must be done last working_project_->color_manager()->SetConfigAndDefaultInput(ocio_filename_->text(), default_input_colorspace_->currentText()); QDialog::accept(); } void ProjectPropertiesDialog::BrowseForOCIOConfig() { QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration")); if (!fn.isEmpty()) { ocio_filename_->setText(fn); } } void ProjectPropertiesDialog::OCIOFilenameUpdated() { default_input_colorspace_->clear(); try { OCIO::ConstConfigRcPtr c; if (ocio_filename_->text().isEmpty()) { c = ColorManager::GetDefaultConfig(); } else { c = ColorManager::CreateConfigFromFile(ocio_filename_->text()); } ocio_filename_->setStyleSheet(QString()); ocio_config_is_valid_ = true; // List input color spaces QStringList input_cs = ColorManager::ListAvailableColorspaces(c); foreach (QString cs, input_cs) { default_input_colorspace_->addItem(cs); if (cs == working_project_->color_manager()->GetDefaultInputColorSpace()) { default_input_colorspace_->setCurrentIndex(default_input_colorspace_->count()-1); } } } catch (OCIO::Exception& e) { ocio_config_is_valid_ = false; ocio_filename_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}")); ocio_config_error_ = e.what(); } } PathWidget::PathWidget(const QString &path, QWidget *parent) : QObject(parent) { path_edit_ = new QLineEdit(); path_edit_->setText(path); connect(path_edit_, &QLineEdit::textChanged, this, &PathWidget::LineEditChanged); default_box_ = new QCheckBox(tr("Default")); browse_btn_ = new QPushButton(tr("Browse")); connect(default_box_, &QCheckBox::toggled, this, &PathWidget::DefaultToggled); default_box_->setChecked(path.isEmpty()); connect(browse_btn_, &QPushButton::clicked, this, &PathWidget::BrowseClicked); } bool PathWidget::PathIsValid(bool try_to_create) const { return default_box_->isChecked() || QDir(path_edit_->text()).exists() || (try_to_create && QDir(path_edit_->text()).mkpath(QStringLiteral("."))); } void PathWidget::DefaultToggled(bool e) { path_edit_->setEnabled(!e); } void PathWidget::BrowseClicked() { QString dir = QFileDialog::getExistingDirectory(static_cast(parent()), tr("Browse for path"), path_edit_->text()); if (!dir.isEmpty()) { path_edit_->setText(dir); } } void PathWidget::LineEditChanged() { if (PathIsValid(false)) { path_edit_->setStyleSheet(QString()); } else { path_edit_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}")); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/projectproperties/projectproperties.h000066400000000000000000000037751370472574300261660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTPROPERTIESDIALOG_H #define PROJECTPROPERTIESDIALOG_H #include #include #include #include #include #include "project/project.h" OLIVE_NAMESPACE_ENTER class PathWidget : public QObject { Q_OBJECT public: PathWidget(const QString& path, QWidget* parent = nullptr); bool PathIsValid(bool try_to_create) const; QLineEdit* path_edit() const { return path_edit_; } QCheckBox* default_box() const { return default_box_; } QPushButton* browse_btn() const { return browse_btn_; } private slots: void DefaultToggled(bool e); void BrowseClicked(); void LineEditChanged(); private: QLineEdit* path_edit_; QCheckBox* default_box_; QPushButton* browse_btn_; }; class ProjectPropertiesDialog : public QDialog { Q_OBJECT public: ProjectPropertiesDialog(Project *p, QWidget* parent); public slots: virtual void accept() override; private: Project* working_project_; QLineEdit* ocio_filename_; QComboBox* default_input_colorspace_; bool ocio_config_is_valid_; QString ocio_config_error_; PathWidget* cache_path_; private slots: void BrowseForOCIOConfig(); void OCIOFilenameUpdated(); }; OLIVE_NAMESPACE_EXIT #endif // PROJECTPROPERTIESDIALOG_H olive-continuous/app/dialog/rendercancel/000077500000000000000000000000001370472574300210605ustar00rootroot00000000000000olive-continuous/app/dialog/rendercancel/CMakeLists.txt000066400000000000000000000015011370472574300236150ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/rendercancel/rendercancel.h dialog/rendercancel/rendercancel.cpp PARENT_SCOPE ) olive-continuous/app/dialog/rendercancel/rendercancel.cpp000066400000000000000000000033431370472574300242140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "rendercancel.h" OLIVE_NAMESPACE_ENTER RenderCancelDialog::RenderCancelDialog(QWidget *parent) : ProgressDialog(tr("Waiting for workers to finish..."), tr("Renderer"), parent), busy_workers_(0), total_workers_(0) { } void RenderCancelDialog::RunIfWorkersAreBusy() { if (busy_workers_ > 0) { waiting_workers_ = busy_workers_; exec(); } } void RenderCancelDialog::SetWorkerCount(int count) { total_workers_ = count; UpdateProgress(); } void RenderCancelDialog::WorkerStarted() { busy_workers_++; UpdateProgress(); } void RenderCancelDialog::WorkerDone() { busy_workers_--; UpdateProgress(); } void RenderCancelDialog::showEvent(QShowEvent *event) { QDialog::showEvent(event); UpdateProgress(); } void RenderCancelDialog::UpdateProgress() { if (!total_workers_ || !isVisible()) { return; } SetProgress(qRound(100.0 * static_cast(waiting_workers_ - busy_workers_) / static_cast(waiting_workers_))); if (busy_workers_ == 0) { accept(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/rendercancel/rendercancel.h000066400000000000000000000024341370472574300236610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERCANCELDIALOG_H #define RENDERCANCELDIALOG_H #include "dialog/progress/progress.h" OLIVE_NAMESPACE_ENTER class RenderCancelDialog : public ProgressDialog { Q_OBJECT public: RenderCancelDialog(QWidget* parent = nullptr); void RunIfWorkersAreBusy(); void SetWorkerCount(int count); void WorkerStarted(); public slots: void WorkerDone(); protected: virtual void showEvent(QShowEvent* event) override; private: void UpdateProgress(); int busy_workers_; int total_workers_; int waiting_workers_; }; OLIVE_NAMESPACE_EXIT #endif // RENDERCANCELDIALOG_H olive-continuous/app/dialog/richtext/000077500000000000000000000000001370472574300202655ustar00rootroot00000000000000olive-continuous/app/dialog/richtext/CMakeLists.txt000066400000000000000000000014611370472574300230270ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/richtext/richtext.h dialog/richtext/richtext.cpp PARENT_SCOPE ) olive-continuous/app/dialog/richtext/richtext.cpp000066400000000000000000000252561370472574300226350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "richtext.h" #include #include #include #include #include #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER RichTextDialog::RichTextDialog(QString start, QWidget* parent) : QDialog(parent) { QVBoxLayout* layout = new QVBoxLayout(this); // Create toolbar QHBoxLayout* toolbar_layout = new QHBoxLayout(); bold_btn_ = CreateToolbarButton(tr("B"), tr("Bold"), {QStringLiteral("b"), QStringLiteral("strong")}); toolbar_layout->addWidget(bold_btn_); italic_btn_ = CreateToolbarButton(tr("I"), tr("Italic"), {QStringLiteral("i"), QStringLiteral("em")}); toolbar_layout->addWidget(italic_btn_); underline_btn_ = CreateToolbarButton(tr("U"), tr("Underline"), {QStringLiteral("u")}); toolbar_layout->addWidget(underline_btn_); strikeout_btn_ = CreateToolbarButton(tr("S"), tr("Strikethrough"), {QStringLiteral("strike")}); toolbar_layout->addWidget(strikeout_btn_); font_combo_ = new QFontComboBox(); font_combo_->setToolTip(tr("Font Family")); toolbar_layout->addWidget(font_combo_); size_slider_ = new FloatSlider(); size_slider_->SetMinimum(0.1); size_slider_->SetLadderElementCount(1); size_slider_->setToolTip(tr("Font Size")); toolbar_layout->addWidget(size_slider_); toolbar_layout->addStretch(); left_align_btn_ = CreateToolbarButton(tr("L"), tr("Left Align"), {}); toolbar_layout->addWidget(left_align_btn_); center_align_btn_ = CreateToolbarButton(tr("C"), tr("Center Align"), {}); toolbar_layout->addWidget(center_align_btn_); right_align_btn_ = CreateToolbarButton(tr("R"), tr("Right Align"), {}); toolbar_layout->addWidget(right_align_btn_); justify_align_btn_ = CreateToolbarButton(tr("J"), tr("Justify Align"), {}); toolbar_layout->addWidget(justify_align_btn_); layout->addLayout(toolbar_layout); // Create text edit widget text_edit_ = new QTextEdit(); text_edit_->setWordWrapMode(QTextOption::NoWrap); connect(text_edit_, &QTextEdit::cursorPositionChanged, this, &RichTextDialog::UpdateButtons); start.replace(QStringLiteral("
"), QStringLiteral("\n")); text_edit_->document()->setPlainText(start); layout->addWidget(text_edit_); // Create buttons QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(buttons); connect(buttons, &QDialogButtonBox::accepted, this, &RichTextDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &RichTextDialog::reject); // Connect font buttons /* connect(size_slider_, &FloatSlider::ValueChanged, text_edit_, &QTextEdit::setFontPointSize); connect(left_align_btn_, &QPushButton::clicked, this, [this](){ text_edit_->setAlignment(Qt::AlignLeft); UpdateButtons(); }); connect(center_align_btn_, &QPushButton::clicked, this, [this](){ text_edit_->setAlignment(Qt::AlignCenter); UpdateButtons(); }); connect(right_align_btn_, &QPushButton::clicked, this, [this](){ text_edit_->setAlignment(Qt::AlignRight); UpdateButtons(); }); connect(justify_align_btn_, &QPushButton::clicked, this, [this](){ text_edit_->setAlignment(Qt::AlignJustify); UpdateButtons(); }); connect(font_combo_, &QFontComboBox::currentTextChanged, this, [this](const QString& s){ text_edit_->setFontFamily(s); }); */ } QPushButton *RichTextDialog::CreateToolbarButton(const QString& label, const QString& tooltip, const QStringList &tags) { QPushButton* btn = new QPushButton(label); btn->setCheckable(true); btn->setToolTip(tooltip); btn->setFixedWidth(btn->sizeHint().height()); if (!tags.isEmpty()) { btn->setProperty("tag", tags); connect(btn, &QPushButton::clicked, this, &RichTextDialog::TagButtonToggled); } return btn; } int SnapPositionOutsideTags(const QString& text, int pos) { // Look for closest opening bracket before position int opening_bracket_pos = text.lastIndexOf('<', pos - text.size() -1); // Look for closest closing bracket before position int closing_bracket_pos = text.indexOf('>', opening_bracket_pos); if (opening_bracket_pos > -1 && closing_bracket_pos >= pos) { // Must be inside an angle bracket, snap to closest position outside of bracket closing_bracket_pos++; if (pos - opening_bracket_pos < closing_bracket_pos - pos) { // Closer to opening bracket pos return opening_bracket_pos; } else { return closing_bracket_pos; } } return pos; } void RichTextDialog::SetTags(const QStringList &t, bool enabled) { QString s = text_edit_->toPlainText(); int selection_start, selection_end; { QTextCursor c = text_edit_->textCursor(); if (c.hasSelection()) { selection_start = SnapPositionOutsideTags(s, c.selectionStart()); selection_end = SnapPositionOutsideTags(s, c.selectionEnd()); c.clearSelection(); c.setPosition(selection_start, QTextCursor::MoveAnchor); c.setPosition(selection_end, QTextCursor::KeepAnchor); } else { selection_start = SnapPositionOutsideTags(s, c.position()); selection_end = selection_start; c.setPosition(selection_start, QTextCursor::MoveAnchor); } text_edit_->setTextCursor(c); } QString open_tag = CreateOpeningTag(t.first()); QString close_tag = CreateClosingTag(t.first()); // Insert tags QString new_text; if (!enabled) { std::swap(open_tag, close_tag); } bool open_tag_cancels_out = !QString::compare(s.mid(selection_start - close_tag.size(), close_tag.size()), close_tag, Qt::CaseInsensitive); bool close_tag_cancels_out = !QString::compare(s.mid(selection_end, open_tag.size()), open_tag, Qt::CaseInsensitive); QString selected_text = text_edit_->textCursor().selectedText(); if (open_tag_cancels_out && close_tag_cancels_out) { // Both tags cancel each other out, simply remove selection_start -= close_tag.size(); QTextCursor c = text_edit_->textCursor(); c.clearSelection(); c.setPosition(selection_start, QTextCursor::MoveAnchor); c.setPosition(selection_end + open_tag.size(), QTextCursor::KeepAnchor); text_edit_->setTextCursor(c); selection_end -= close_tag.size(); new_text = selected_text; } else if (open_tag_cancels_out) { // Open tag cancels out, shift close tag rather than inserting new tags selection_start -= close_tag.size(); QTextCursor c = text_edit_->textCursor(); c.clearSelection(); c.setPosition(selection_start, QTextCursor::MoveAnchor); c.setPosition(selection_end, QTextCursor::KeepAnchor); text_edit_->setTextCursor(c); selection_end -= close_tag.size(); new_text = selected_text; new_text.append(close_tag); } else if (close_tag_cancels_out) { // Close tag cancels out, shift open tag rather than inserting new tags selection_end += open_tag.size(); QTextCursor c = text_edit_->textCursor(); c.clearSelection(); c.setPosition(selection_start, QTextCursor::MoveAnchor); c.setPosition(selection_end, QTextCursor::KeepAnchor); text_edit_->setTextCursor(c); selection_start += open_tag.size(); new_text = open_tag; new_text.append(selected_text); } else { // Nothing is cancelled out, simply insert tags new_text = QStringLiteral("%1%2%3").arg(open_tag, selected_text, close_tag); selection_start += open_tag.size(); selection_end += open_tag.size(); } text_edit_->insertPlainText(new_text); text_edit_->setFocus(); { // Re-select text QTextCursor c = text_edit_->textCursor(); c.clearSelection(); c.setPosition(selection_start, QTextCursor::MoveAnchor); c.setPosition(selection_end, QTextCursor::KeepAnchor); text_edit_->setTextCursor(c); } } QString RichTextDialog::CreateOpeningTag(const QString &s) { return QStringLiteral("<%1>").arg(s); } QString RichTextDialog::CreateClosingTag(const QString &s) { return QStringLiteral("").arg(s); } void RichTextDialog::UpdateTagButton(QPushButton *btn, const QString &text, int cursor_pos) { QStringList tags = btn->property("tag").toStringList(); foreach (const QString& t, tags) { QString opening = CreateOpeningTag(t); QString closing = CreateClosingTag(t); int opening_index = text.lastIndexOf(opening, cursor_pos - text.size() - 1, Qt::CaseInsensitive); int closing_index = text.indexOf(closing, opening_index, Qt::CaseInsensitive); if (opening_index > -1 && closing_index + closing.size() > cursor_pos) { btn->setChecked(true); btn->setProperty("foundtag", t); return; } } btn->setChecked(false); btn->setProperty("foundtag", QVariant()); } void RichTextDialog::TagButtonToggled(bool checked) { QPushButton* src = static_cast(sender()); QStringList tags; if (src->property("foundtag").isNull()) { tags = src->property("tag").toStringList(); } else { tags = QStringList({src->property("foundtag").toString()}); } SetTags(tags, checked); } void RichTextDialog::UpdateButtons() { QString text = text_edit_->toPlainText(); int cursor_pos = text_edit_->textCursor().position(); UpdateTagButton(bold_btn_, text, cursor_pos); UpdateTagButton(italic_btn_, text, cursor_pos); UpdateTagButton(underline_btn_, text, cursor_pos); UpdateTagButton(strikeout_btn_, text, cursor_pos); /* // Update font family font_combo_->blockSignals(true); font_combo_->setCurrentFont(text_edit_->currentFont().family()); font_combo_->blockSignals(false); size_slider_->SetValue(text_edit_->fontPointSize()); left_align_btn_->setChecked(text_edit_->alignment() == Qt::AlignLeft); center_align_btn_->setChecked(text_edit_->alignment() == Qt::AlignCenter); right_align_btn_->setChecked(text_edit_->alignment() == Qt::AlignRight); justify_align_btn_->setChecked(text_edit_->alignment() == Qt::AlignJustify); */ } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/richtext/richtext.h000066400000000000000000000042331370472574300222720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RICHTEXTDIALOG_H #define RICHTEXTDIALOG_H #include #include #include #include "common/define.h" #include "widget/slider/floatslider.h" OLIVE_NAMESPACE_ENTER class RichTextDialog : public QDialog { Q_OBJECT public: RichTextDialog(QString start, QWidget* parent = nullptr); QString text() const { QString s = text_edit_->document()->toPlainText(); // Convert linebreaks s.replace('\n', QStringLiteral("
")); return s; } private: QPushButton* CreateToolbarButton(const QString &label, const QString &tooltip, const QStringList& tags); void SetTags(const QStringList& t, bool enabled); static QString CreateOpeningTag(const QString& s); static QString CreateClosingTag(const QString& s); static void UpdateTagButton(QPushButton* btn, const QString &text, int cursor_pos); QFontDatabase font_db_; QTextEdit* text_edit_; QPushButton* bold_btn_; QPushButton* italic_btn_; QPushButton* underline_btn_; QPushButton* strikeout_btn_; QFontComboBox* font_combo_; FloatSlider* size_slider_; QPushButton* left_align_btn_; QPushButton* center_align_btn_; QPushButton* right_align_btn_; QPushButton* justify_align_btn_; private slots: void TagButtonToggled(bool checked); void UpdateButtons(); }; OLIVE_NAMESPACE_EXIT #endif // RICHTEXTDIALOG_H olive-continuous/app/dialog/sequence/000077500000000000000000000000001370472574300202435ustar00rootroot00000000000000olive-continuous/app/dialog/sequence/CMakeLists.txt000066400000000000000000000020161370472574300230020ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/sequence/sequence.h dialog/sequence/sequence.cpp dialog/sequence/sequencedialogparametertab.h dialog/sequence/sequencedialogparametertab.cpp dialog/sequence/sequencedialogpresettab.h dialog/sequence/sequencedialogpresettab.cpp dialog/sequence/sequencepreset.h PARENT_SCOPE ) olive-continuous/app/dialog/sequence/sequence.cpp000066400000000000000000000136661370472574300225730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sequence.h" #include #include #include #include #include #include #include #include "core.h" #include "common/channellayout.h" #include "common/rational.h" #include "undo/undostack.h" OLIVE_NAMESPACE_ENTER SequenceDialog::SequenceDialog(Sequence* s, Type t, QWidget* parent) : QDialog(parent), sequence_(s), make_undoable_(true) { QVBoxLayout* layout = new QVBoxLayout(this); QSplitter* splitter = new QSplitter(); layout->addWidget(splitter); preset_tab_ = new SequenceDialogPresetTab(); splitter->addWidget(preset_tab_); parameter_tab_ = new SequenceDialogParameterTab(sequence_); splitter->addWidget(parameter_tab_); connect(preset_tab_, &SequenceDialogPresetTab::PresetChanged, parameter_tab_, &SequenceDialogParameterTab::PresetChanged); connect(preset_tab_, &SequenceDialogPresetTab::PresetAccepted, this, &SequenceDialog::accept); connect(parameter_tab_, &SequenceDialogParameterTab::SaveParametersAsPreset, preset_tab_, &SequenceDialogPresetTab::SaveParametersAsPreset); // Set up name section QHBoxLayout* name_layout = new QHBoxLayout(); name_layout->addWidget(new QLabel(tr("Name:"))); name_field_ = new QLineEdit(); name_layout->addWidget(name_field_); layout->addLayout(name_layout); // Set up dialog buttons QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttons->setCenterButtons(true); connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); layout->addWidget(buttons); // Set window title based on type switch (t) { case kNew: setWindowTitle(tr("New Sequence")); break; case kExisting: setWindowTitle(tr("Editing \"%1\"").arg(sequence_->name())); break; } name_field_->setText(sequence_->name()); } void SequenceDialog::SetUndoable(bool u) { make_undoable_ = u; } void SequenceDialog::SetNameIsEditable(bool e) { name_field_->setEnabled(e); } void SequenceDialog::accept() { if (name_field_->isEnabled() && name_field_->text().isEmpty()) { QMessageBox::critical(this, tr("Error editing Sequence"), tr("Please enter a name for this Sequence.")); return; } // Get the rational at the combobox's index (which will be correct provided AddFrameRate() was used at all time) rational video_time_base = parameter_tab_->GetSelectedVideoFrameRate().flipped(); // Get the rational at the combobox's index (which will be correct provided AddFrameRate() was used at all time) int audio_sample_rate = parameter_tab_->GetSelectedAudioSampleRate(); // Get the audio channel layout value uint64_t channels = parameter_tab_->GetSelectedAudioChannelLayout(); // Generate video and audio parameter structs from data VideoParams video_params = VideoParams(parameter_tab_->GetSelectedVideoWidth(), parameter_tab_->GetSelectedVideoHeight(), video_time_base, parameter_tab_->GetSelectedPreviewFormat(), parameter_tab_->GetSelectedPreviewResolution()); AudioParams audio_params = AudioParams(audio_sample_rate, channels, SampleFormat::kInternalFormat); if (make_undoable_) { // Make undoable command to change the parameters SequenceParamCommand* param_command = new SequenceParamCommand(sequence_, video_params, audio_params, name_field_->text()); Core::instance()->undo_stack()->push(param_command); } else { // Set sequence values directly with no undo command sequence_->set_video_params(video_params); sequence_->set_audio_params(audio_params); sequence_->set_name(name_field_->text()); } QDialog::accept(); } SequenceDialog::SequenceParamCommand::SequenceParamCommand(Sequence* s, const VideoParams& video_params, const AudioParams &audio_params, const QString& name, QUndoCommand* parent) : UndoCommand(parent), sequence_(s), new_video_params_(video_params), new_audio_params_(audio_params), new_name_(name), old_video_params_(s->video_params()), old_audio_params_(s->audio_params()), old_name_(s->name()) { } Project *SequenceDialog::SequenceParamCommand::GetRelevantProject() const { return sequence_->project(); } void SequenceDialog::SequenceParamCommand::redo_internal() { sequence_->set_video_params(new_video_params_); sequence_->set_audio_params(new_audio_params_); sequence_->set_name(new_name_); } void SequenceDialog::SequenceParamCommand::undo_internal() { sequence_->set_video_params(old_video_params_); sequence_->set_audio_params(old_audio_params_); sequence_->set_name(old_name_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/sequence/sequence.h000066400000000000000000000076121370472574300222320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SEQUENCEDIALOG_H #define SEQUENCEDIALOG_H #include #include #include #include "project/item/sequence/sequence.h" #include "sequencedialogparametertab.h" #include "sequencedialogpresettab.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER /** * @brief A dialog for editing Sequence parameters * * This dialog exposes all the parameters of a Sequence to users allowing them to set up a Sequence however they wish. * A Sequence can be sent to this dialog through the constructor. All fields will be filled using that Sequence's * parameters, allowing the user to view and edit them. Accepting the dialog will apply them back to that Sequence, * either directly or using a QUndoCommand (see SetUndoable()). * * If creating a new Sequence, the Sequence must still be constructed first before sending it to SequenceDialog. * SequenceDialog does not create any new objects. In most cases when creating a new Sequence, editing its parameters * with SequenceDialog will be paired with the action of adding the Sequence to a project. In this situation, since the * latter will be the main undoable action, the parameter editing doesn't have to be undoable since to the user they'll * be viewed as one single action (see SetUndoable()). */ class SequenceDialog : public QDialog { Q_OBJECT public: /** * @brief Used to set the dialog mode of operation (see SequenceDialog()) */ enum Type { kNew, kExisting }; /** * @brief SequenceDialog Constructor * * @param s * Sequence to edit * * @param t * Mode of operation (changes some UI like the window title to best represent the action being performed) * * @param parent * QWidget parent */ SequenceDialog(Sequence* s, Type t = kExisting, QWidget* parent = nullptr); /** * @brief Set whether the parameter changes should be made into an undo command or not * * Defaults to true. */ void SetUndoable(bool u); /** * @brief Set whether the name of this Sequence can be edited with this dialog * * Defaults to true. */ void SetNameIsEditable(bool e); public slots: /** * @brief Function called when the user presses OK */ virtual void accept() override; private: Sequence* sequence_; SequenceDialogPresetTab* preset_tab_; SequenceDialogParameterTab* parameter_tab_; bool make_undoable_; QLineEdit* name_field_; /** * @brief A QUndoCommand for setting the parameters on a sequence */ class SequenceParamCommand : public UndoCommand { public: SequenceParamCommand(Sequence* s, const VideoParams& video_params, const AudioParams& audio_params, const QString& name, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Sequence* sequence_; VideoParams new_video_params_; AudioParams new_audio_params_; QString new_name_; VideoParams old_video_params_; AudioParams old_audio_params_; QString old_name_; }; }; OLIVE_NAMESPACE_EXIT #endif // SEQUENCEDIALOG_H olive-continuous/app/dialog/sequence/sequencedialogparametertab.cpp000066400000000000000000000203451370472574300263330ustar00rootroot00000000000000#include "sequencedialogparametertab.h" #include #include #include #include #include "core.h" OLIVE_NAMESPACE_ENTER SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidget* parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(this); int row = 0; // Set up video section QGroupBox* video_group = new QGroupBox(); video_group->setTitle(tr("Video")); QGridLayout* video_layout = new QGridLayout(video_group); video_layout->addWidget(new QLabel(tr("Width:")), row, 0); video_width_field_ = new IntegerSlider(); video_width_field_->SetMinimum(1); video_width_field_->SetMaximum(99999); connect(video_width_field_, &IntegerSlider::ValueChanged, this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel); video_layout->addWidget(video_width_field_, row, 1); row++; video_layout->addWidget(new QLabel(tr("Height:")), row, 0); video_height_field_ = new IntegerSlider(); video_height_field_->SetMinimum(1); video_height_field_->SetMaximum(99999); connect(video_height_field_, &IntegerSlider::ValueChanged, this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel); video_layout->addWidget(video_height_field_, row, 1); row++; video_layout->addWidget(new QLabel(tr("Frame Rate:")), row, 0); video_frame_rate_field_ = new QComboBox(); video_layout->addWidget(video_frame_rate_field_, row, 1); layout->addWidget(video_group); row = 0; // Set up audio section QGroupBox* audio_group = new QGroupBox(); audio_group->setTitle(tr("Audio")); QGridLayout* audio_layout = new QGridLayout(audio_group); audio_layout->addWidget(new QLabel(tr("Sample Rate:")), row, 0); audio_sample_rate_field_ = new QComboBox(); audio_layout->addWidget(audio_sample_rate_field_, row, 1); row++; audio_layout->addWidget(new QLabel(tr("Channels:")), row, 0); audio_channels_field_ = new QComboBox(); audio_layout->addWidget(audio_channels_field_, row, 1); layout->addWidget(audio_group); row = 0; // Set up preview section QGroupBox* preview_group = new QGroupBox(); preview_group->setTitle(tr("Preview")); QGridLayout* preview_layout = new QGridLayout(preview_group); preview_layout->addWidget(new QLabel(tr("Resolution:")), row, 0); preview_resolution_field_ = new QComboBox(); preview_layout->addWidget(preview_resolution_field_, row, 1); preview_resolution_label_ = new QLabel(); preview_layout->addWidget(preview_resolution_label_, row, 2); row++; preview_layout->addWidget(new QLabel(tr("Format:")), row, 0); preview_format_field_ = new QComboBox(); preview_layout->addWidget(preview_format_field_, row, 1, 1, 2); layout->addWidget(preview_group); // Set up available frame rates frame_rate_list_ = Core::SupportedFrameRates(); foreach (const rational& fr, frame_rate_list_) { video_frame_rate_field_->addItem(Core::FrameRateToString(fr)); } // Set up available sample rates sample_rate_list_ = Core::SupportedSampleRates(); foreach (const int& sr, sample_rate_list_) { audio_sample_rate_field_->addItem(Core::SampleRateToString(sr)); } // Set up available channel layouts channel_layout_list_ = Core::SupportedChannelLayouts(); foreach (const uint64_t& ch_layout, channel_layout_list_) { audio_channels_field_->addItem(Core::ChannelLayoutToString(ch_layout), QVariant::fromValue(ch_layout)); } // Set up preview dividers divider_list_ = Core::SupportedDividers(); foreach (int d, divider_list_) { QString name; if (d == 1) { name = tr("Full"); } else { name = tr("1/%1").arg(d); } preview_resolution_field_->addItem(name); } connect(preview_resolution_field_, static_cast(&QComboBox::currentIndexChanged), this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel); // Set up preview formats for (int i=0;i(i); // We always render with an alpha channel internally if (PixelFormat::FormatHasAlphaChannel(pix_fmt) && PixelFormat::FormatIsFloat(pix_fmt)) { preview_format_field_->addItem(PixelFormat::GetName(pix_fmt)); preview_format_list_.append(pix_fmt); } } // Set values based on input sequence video_width_field_->SetValue(sequence->video_params().width()); video_height_field_->SetValue(sequence->video_params().height()); int frame_rate_index = frame_rate_list_.indexOf(sequence->video_params().time_base().flipped()); video_frame_rate_field_->setCurrentIndex(frame_rate_index); int sample_rate_index = sample_rate_list_.indexOf(sequence->audio_params().sample_rate()); audio_sample_rate_field_->setCurrentIndex(sample_rate_index); for (int i=0;icount();i++) { if (audio_channels_field_->itemData(i).toULongLong() == sequence->audio_params().channel_layout()) { audio_channels_field_->setCurrentIndex(i); break; } } preview_resolution_field_->setCurrentIndex(divider_list_.indexOf(sequence->video_params().divider())); preview_format_field_->setCurrentIndex(preview_format_list_.indexOf(sequence->video_params().format())); layout->addStretch(); QPushButton* save_preset_btn = new QPushButton(tr("Save Preset")); connect(save_preset_btn, &QPushButton::clicked, this, &SequenceDialogParameterTab::SavePresetClicked); layout->addWidget(save_preset_btn); UpdatePreviewResolutionLabel(); } int SequenceDialogParameterTab::GetSelectedVideoWidth() const { return video_width_field_->GetValue(); } int SequenceDialogParameterTab::GetSelectedVideoHeight() const { return video_height_field_->GetValue(); } const rational &SequenceDialogParameterTab::GetSelectedVideoFrameRate() const { return frame_rate_list_.at(video_frame_rate_field_->currentIndex()); } int SequenceDialogParameterTab::GetSelectedAudioSampleRate() const { return sample_rate_list_.at(audio_sample_rate_field_->currentIndex()); } uint64_t SequenceDialogParameterTab::GetSelectedAudioChannelLayout() const { return audio_channels_field_->currentData().toULongLong(); } int SequenceDialogParameterTab::GetSelectedPreviewResolution() const { return divider_list_.at(preview_resolution_field_->currentIndex()); } PixelFormat::Format SequenceDialogParameterTab::GetSelectedPreviewFormat() const { return preview_format_list_.at(preview_format_field_->currentIndex()); } void SequenceDialogParameterTab::PresetChanged(const SequencePreset &preset) { video_width_field_->SetValue(preset.width); video_height_field_->SetValue(preset.height); video_frame_rate_field_->setCurrentIndex(frame_rate_list_.indexOf(preset.frame_rate)); audio_sample_rate_field_->setCurrentIndex(sample_rate_list_.indexOf(preset.sample_rate)); audio_channels_field_->setCurrentIndex(channel_layout_list_.indexOf(preset.channel_layout)); preview_resolution_field_->setCurrentIndex(divider_list_.indexOf(preset.preview_divider)); preview_format_field_->setCurrentIndex(preview_format_list_.indexOf(preset.preview_format)); } void SequenceDialogParameterTab::SavePresetClicked() { emit SaveParametersAsPreset({QString(), static_cast(video_width_field_->GetValue()), static_cast(video_height_field_->GetValue()), frame_rate_list_.at(video_frame_rate_field_->currentIndex()), sample_rate_list_.at(audio_sample_rate_field_->currentIndex()), channel_layout_list_.at(audio_channels_field_->currentIndex()), divider_list_.at(preview_resolution_field_->currentIndex()), preview_format_list_.at(preview_format_field_->currentIndex())}); } void SequenceDialogParameterTab::UpdatePreviewResolutionLabel() { VideoParams test_param(video_width_field_->GetValue(), video_height_field_->GetValue(), PixelFormat::PIX_FMT_INVALID, divider_list_.at(preview_resolution_field_->currentIndex())); preview_resolution_label_->setText(tr("(%1x%2)").arg(QString::number(test_param.effective_width()), QString::number(test_param.effective_height()))); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/sequence/sequencedialogparametertab.h000066400000000000000000000030101370472574300257660ustar00rootroot00000000000000#ifndef SEQUENCEDIALOGPARAMETERTAB_H #define SEQUENCEDIALOGPARAMETERTAB_H #include #include #include #include "project/item/sequence/sequence.h" #include "sequencepreset.h" #include "widget/slider/integerslider.h" OLIVE_NAMESPACE_ENTER class SequenceDialogParameterTab : public QWidget { Q_OBJECT public: SequenceDialogParameterTab(Sequence* sequence, QWidget* parent = nullptr); int GetSelectedVideoWidth() const; int GetSelectedVideoHeight() const; const rational& GetSelectedVideoFrameRate() const; int GetSelectedAudioSampleRate() const; uint64_t GetSelectedAudioChannelLayout() const; int GetSelectedPreviewResolution() const; PixelFormat::Format GetSelectedPreviewFormat() const; public slots: void PresetChanged(const SequencePreset& preset); signals: void SaveParametersAsPreset(const SequencePreset& preset); private: IntegerSlider* video_width_field_; IntegerSlider* video_height_field_; QComboBox* video_frame_rate_field_; QComboBox* audio_sample_rate_field_; QComboBox* audio_channels_field_; QComboBox* preview_resolution_field_; QLabel* preview_resolution_label_; QComboBox* preview_format_field_; QList frame_rate_list_; QList sample_rate_list_; QList channel_layout_list_; QList divider_list_; QList preview_format_list_; private slots: void SavePresetClicked(); void UpdatePreviewResolutionLabel(); }; OLIVE_NAMESPACE_EXIT #endif // SEQUENCEDIALOGPARAMETERTAB_H olive-continuous/app/dialog/sequence/sequencedialogpresettab.cpp000066400000000000000000000303001370472574300256450ustar00rootroot00000000000000#include "sequencedialogpresettab.h" #include #include #include #include #include #include #include #include #include "common/filefunctions.h" #include "node/input.h" #include "ui/icons/icons.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER const int kDataIsPreset = Qt::UserRole; const int kDataPresetIsCustomRole = Qt::UserRole + 1; const int kDataPresetDataRole = Qt::UserRole + 2; SequenceDialogPresetTab::SequenceDialogPresetTab(QWidget* parent) : QWidget(parent) { QVBoxLayout* outer_layout = new QVBoxLayout(this); outer_layout->setMargin(0); preset_tree_ = new QTreeWidget(); preset_tree_->setColumnCount(1); preset_tree_->setHeaderLabel(tr("Preset")); preset_tree_->setContextMenuPolicy(Qt::CustomContextMenu); connect(preset_tree_, &QTreeWidget::customContextMenuRequested, this, &SequenceDialogPresetTab::ShowContextMenu); outer_layout->addWidget(preset_tree_); connect(preset_tree_, &QTreeWidget::currentItemChanged, this, &SequenceDialogPresetTab::SelectedItemChanged); connect(preset_tree_, &QTreeWidget::itemDoubleClicked, this, &SequenceDialogPresetTab::ItemDoubleClicked); // Add "my presets" folder my_presets_folder_ = CreateFolder(tr("My Presets")); preset_tree_->addTopLevelItem(my_presets_folder_); // Add presets preset_tree_->addTopLevelItem(CreateHDPresetFolder(tr("4K UHD"), 3840, 2160, 6)); preset_tree_->addTopLevelItem(CreateHDPresetFolder(tr("1080p"), 1920, 1080, 3)); preset_tree_->addTopLevelItem(CreateHDPresetFolder(tr("720p"), 1280, 720, 2)); preset_tree_->addTopLevelItem(CreateSDPresetFolder(tr("NTSC"), 720, 480, rational(30000, 1001), 1)); preset_tree_->addTopLevelItem(CreateSDPresetFolder(tr("PAL"), 720, 576, rational(25, 1), 1)); // Load custom presets QFile preset_file(GetCustomPresetFilename()); if (preset_file.open(QFile::ReadOnly)) { QXmlStreamReader reader(&preset_file); while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("presets")) { while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("preset")) { SequencePreset p; while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("name")) { p.name = reader.readElementText(); } else if (reader.name() == QStringLiteral("width")) { p.width = reader.readElementText().toInt(); } else if (reader.name() == QStringLiteral("height")) { p.height = reader.readElementText().toInt(); } else if (reader.name() == QStringLiteral("framerate")) { p.frame_rate = rational::fromString(reader.readElementText()); } else if (reader.name() == QStringLiteral("samplerate")) { p.sample_rate = reader.readElementText().toInt(); } else if (reader.name() == QStringLiteral("chlayout")) { p.channel_layout = reader.readElementText().toULongLong(); } else if (reader.name() == QStringLiteral("divider")) { p.preview_divider = reader.readElementText().toInt(); } else if (reader.name() == QStringLiteral("format")) { p.preview_format = static_cast(reader.readElementText().toInt()); } else { reader.skipCurrentElement(); } } AddItem(my_presets_folder_, p, true); } else { reader.skipCurrentElement(); } } } else { reader.skipCurrentElement(); } } preset_file.close(); } } SequenceDialogPresetTab::~SequenceDialogPresetTab() { // Save custom presets to disk QFile preset_file(GetCustomPresetFilename()); if (preset_file.open(QFile::WriteOnly)) { QXmlStreamWriter writer(&preset_file); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement(QStringLiteral("presets")); foreach (const SequencePreset& p, custom_preset_data_) { writer.writeStartElement(QStringLiteral("preset")); writer.writeTextElement(QStringLiteral("name"), p.name); writer.writeTextElement(QStringLiteral("width"), QString::number(p.width)); writer.writeTextElement(QStringLiteral("height"), QString::number(p.height)); writer.writeTextElement(QStringLiteral("framerate"), p.frame_rate.toString()); writer.writeTextElement(QStringLiteral("samplerate"), QString::number(p.sample_rate)); writer.writeTextElement(QStringLiteral("chlayout"), QString::number(p.channel_layout)); writer.writeTextElement(QStringLiteral("divider"), QString::number(p.preview_divider)); writer.writeTextElement(QStringLiteral("format"), QString::number(p.preview_format)); writer.writeEndElement(); // preset } writer.writeEndElement(); // presets writer.writeEndDocument(); preset_file.close(); } } void SequenceDialogPresetTab::SaveParametersAsPreset(SequencePreset preset) { QString preset_name; int existing_preset; forever { preset_name = GetPresetName(preset_name); if (preset_name.isEmpty()) { // Dialog cancelled - leave function entirely return; } existing_preset = -1; for (int i=0; i= 0) { custom_preset_data_.replace(existing_preset, preset); } else { AddItem(my_presets_folder_, preset, true); } } QTreeWidgetItem* SequenceDialogPresetTab::CreateFolder(const QString &name) { QTreeWidgetItem* folder = new QTreeWidgetItem(); folder->setText(0, name); folder->setIcon(0, icon::Folder); return folder; } QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &name, int width, int height, int divider) { QTreeWidgetItem* parent = CreateFolder(name); AddItem(parent, {tr("%1 23.976 FPS").arg(name), width, height, rational(24000, 1001), 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); AddItem(parent, {tr("%1 25 FPS").arg(name), width, height, rational(25, 1), 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); AddItem(parent, {tr("%1 29.97 FPS").arg(name), width, height, rational(30000, 1001), 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); AddItem(parent, {tr("%1 50 FPS").arg(name), width, height, rational(50, 1), 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); AddItem(parent, {tr("%1 59.94 FPS").arg(name), width, height, rational(60000, 1001), 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); return parent; } QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, int divider) { QTreeWidgetItem* parent = CreateFolder(name); preset_tree_->addTopLevelItem(parent); AddItem(parent, {tr("%1 Standard").arg(name), width, height, frame_rate, 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); AddItem(parent, {tr("%1 Widescreen").arg(name), width, height, frame_rate, 48000, AV_CH_LAYOUT_STEREO, divider, PixelFormat::PIX_FMT_RGBA16F}); return parent; } QString SequenceDialogPresetTab::GetPresetName(QString start) { bool ok; forever { start = QInputDialog::getText(this, tr("Save Preset"), tr("Set preset name:"), QLineEdit::Normal, start, &ok); if (!ok) { // Dialog cancelled - leave function entirely return QString(); } if (start.isEmpty()) { // No preset name entered, start loop over QMessageBox::critical(this, tr("Invalid preset name"), tr("You must enter a preset name"), QMessageBox::Ok); } else { break; } } return start; } QTreeWidgetItem *SequenceDialogPresetTab::GetSelectedItem() { QList selected_items = preset_tree_->selectedItems(); if (selected_items.isEmpty()) { return nullptr; } else { return selected_items.first(); } } QTreeWidgetItem *SequenceDialogPresetTab::GetSelectedCustomPreset() { QTreeWidgetItem* sel = GetSelectedItem(); if (sel && sel->data(0, kDataIsPreset).toBool() && sel->data(0, kDataPresetIsCustomRole).toBool()) { return sel; } return nullptr; } QString SequenceDialogPresetTab::GetCustomPresetFilename() { return QDir(FileFunctions::GetConfigurationLocation()).filePath(QStringLiteral("presets")); } void SequenceDialogPresetTab::AddItem(QTreeWidgetItem *folder, const SequencePreset& preset, bool is_custom, const QString &description) { QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0, preset.name); item->setIcon(0, icon::Video); item->setToolTip(0, description); item->setData(0, kDataIsPreset, true); item->setData(0, kDataPresetIsCustomRole, is_custom); QList& list = is_custom ? custom_preset_data_ : default_preset_data_; item->setData(0, kDataPresetDataRole, list.size()); list.append(preset); folder->addChild(item); } void SequenceDialogPresetTab::SelectedItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) { Q_UNUSED(previous) if (current->data(0, kDataIsPreset).toBool()) { int preset_index = current->data(0, kDataPresetDataRole).toInt(); const SequencePreset& preset_data = (current->data(0, kDataPresetIsCustomRole).toBool()) ? custom_preset_data_.at(preset_index) : default_preset_data_.at(preset_index); emit PresetChanged(preset_data); } } void SequenceDialogPresetTab::ItemDoubleClicked(QTreeWidgetItem *item, int column) { Q_UNUSED(column) if (item->data(0, kDataIsPreset).toBool()) { emit PresetAccepted(); } } void SequenceDialogPresetTab::ShowContextMenu() { QTreeWidgetItem* sel = GetSelectedCustomPreset(); if (sel) { Menu m(this); QAction* delete_action = m.addAction(tr("Delete Preset")); connect(delete_action, &QAction::triggered, this, &SequenceDialogPresetTab::DeleteSelectedPreset); m.exec(QCursor::pos()); } } void SequenceDialogPresetTab::DeleteSelectedPreset() { QTreeWidgetItem* sel = GetSelectedCustomPreset(); if (sel) { int preset_index = sel->data(0, kDataPresetDataRole).toInt(); // Shift all items whose index was after this preset forward for (int i=0; ichildCount(); i++) { QTreeWidgetItem* custom_item = my_presets_folder_->child(i); int this_item_index = custom_item->data(0, kDataPresetDataRole).toInt(); if (this_item_index > preset_index) { custom_item->setData(0, kDataPresetDataRole, this_item_index - 1); } } // Remove the preset custom_preset_data_.removeAt(preset_index); // Delete the item delete sel; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/sequence/sequencedialogpresettab.h000066400000000000000000000030721370472574300253200ustar00rootroot00000000000000#ifndef SEQUENCEDIALOGPRESETTAB_H #define SEQUENCEDIALOGPRESETTAB_H #include #include #include #include "sequencepreset.h" OLIVE_NAMESPACE_ENTER class SequenceDialogPresetTab : public QWidget { Q_OBJECT public: SequenceDialogPresetTab(QWidget* parent = nullptr); virtual ~SequenceDialogPresetTab() override; public slots: void SaveParametersAsPreset(SequencePreset preset); signals: void PresetChanged(const SequencePreset& preset); void PresetAccepted(); private: QTreeWidgetItem *CreateFolder(const QString& name); QTreeWidgetItem *CreateHDPresetFolder(const QString& name, int width, int height, int divider); QTreeWidgetItem *CreateSDPresetFolder(const QString& name, int width, int height, const rational &frame_rate, int divider); QString GetPresetName(QString start); QTreeWidgetItem* GetSelectedItem(); QTreeWidgetItem* GetSelectedCustomPreset(); static QString GetCustomPresetFilename(); void AddItem(QTreeWidgetItem* folder, const SequencePreset& preset, bool is_custom = false, const QString& description = QString()); QTreeWidget* preset_tree_; QTreeWidgetItem* my_presets_folder_; QList default_preset_data_; QList custom_preset_data_; private slots: void SelectedItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void ItemDoubleClicked(QTreeWidgetItem *item, int column); void ShowContextMenu(); void DeleteSelectedPreset(); }; OLIVE_NAMESPACE_EXIT #endif // SEQUENCEDIALOGPRESETTAB_H olive-continuous/app/dialog/sequence/sequencepreset.h000066400000000000000000000021071370472574300234470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SEQUENCEPARAM_H #define SEQUENCEPARAM_H #include "common/rational.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER struct SequencePreset { QString name; int width; int height; rational frame_rate; int sample_rate; uint64_t channel_layout; int preview_divider; PixelFormat::Format preview_format; }; OLIVE_NAMESPACE_EXIT #endif // SEQUENCEPARAM_H olive-continuous/app/dialog/speedduration/000077500000000000000000000000001370472574300213015ustar00rootroot00000000000000olive-continuous/app/dialog/speedduration/CMakeLists.txt000066400000000000000000000015051370472574300240420ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/speedduration/speedduration.h dialog/speedduration/speedduration.cpp PARENT_SCOPE ) olive-continuous/app/dialog/speedduration/speedduration.cpp000066400000000000000000000255261370472574300246650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "speedduration.h" #include #include #include #include #include #include #include "core.h" #include "common/timecodefunctions.h" #include "widget/nodeview/nodeviewundo.h" #include "widget/timelinewidget/undo/undo.h" OLIVE_NAMESPACE_ENTER SpeedDurationDialog::SpeedDurationDialog(const rational& timebase, const QList &clips, QWidget *parent) : QDialog(parent), clips_(clips), timebase_(timebase) { setWindowTitle(tr("Speed/Duration")); QVBoxLayout* layout = new QVBoxLayout(this); { // Create groupbox for the speed/duration QGroupBox* speed_groupbox = new QGroupBox(tr("Speed/Duration")); layout->addWidget(speed_groupbox); QGridLayout* speed_layout = new QGridLayout(speed_groupbox); int row = 0; // For any other clips that are selected, determine if they share speeds and lengths. If they don't, the UI can't // show them all as having the same parameters bool same_speed = true; bool same_duration = true; bool all_reversed = true; for (int i=1;ispeed()) != qAbs(this_clip->speed())) { same_speed = false; } // Check if the durations are different if (same_duration && prev_clip->length() != this_clip->length()) { same_duration = false; } // Check if all are reversed if (all_reversed && prev_clip->is_reversed() != this_clip->is_reversed()) { all_reversed = false; } // If we've already determined both are different, no need to continue if (!same_speed && !same_duration && !all_reversed) { break; } } speed_layout->addWidget(new QLabel(tr("Speed:")), row, 0); // Create "Speed" slider speed_slider_ = new FloatSlider(); speed_slider_->SetMinimum(0); speed_slider_->SetDisplayType(FloatSlider::kPercentage); speed_slider_->SetDefaultValue(1); speed_layout->addWidget(speed_slider_, row, 1); if (same_speed) { // All clips share the same speed so we can show the value speed_slider_->SetValue(qAbs(clips_.first()->speed().toDouble())); } else { // Else, we show an invalid initial state speed_slider_->SetTristate(); } row++; speed_layout->addWidget(new QLabel(tr("Duration:")), row, 0); // Create "Duration" slider duration_slider_ = new TimeSlider(); duration_slider_->SetTimebase(timebase_); duration_slider_->SetMinimum(1); speed_layout->addWidget(duration_slider_, row, 1); // Calculate duration that would occur if the speed was 100% duration_slider_->SetDefaultValue(GetUnadjustedLengthTimestamp(clips_.first())); if (same_duration) { duration_slider_->SetValue(Timecode::time_to_timestamp(clips_.first()->length(), timebase_)); } else { duration_slider_->SetTristate(); } row++; link_speed_and_duration_ = new QCheckBox(tr("Link Speed and Duration")); link_speed_and_duration_->setChecked(true); speed_layout->addWidget(link_speed_and_duration_, row, 0, 1, 2); // Pick up when the speed or duration slider changes so we can programmatically link them connect(speed_slider_, &FloatSlider::ValueChanged, this, &SpeedDurationDialog::SpeedChanged); connect(duration_slider_, &TimeSlider::ValueChanged, this, &SpeedDurationDialog::DurationChanged); reverse_speed_checkbox_ = new QCheckBox(tr("Reverse Speed")); if (all_reversed) { reverse_speed_checkbox_->setChecked(clips_.first()->is_reversed()); } else { reverse_speed_checkbox_->setTristate(); } layout->addWidget(reverse_speed_checkbox_); } maintain_audio_pitch_checkbox_ = new QCheckBox(tr("Maintain Audio Pitch")); layout->addWidget(maintain_audio_pitch_checkbox_); ripple_clips_checkbox_ = new QCheckBox(tr("Ripple Clips")); layout->addWidget(ripple_clips_checkbox_); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttons->setCenterButtons(true); layout->addWidget(buttons); connect(buttons, &QDialogButtonBox::accepted, this, &SpeedDurationDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &SpeedDurationDialog::reject); } void SpeedDurationDialog::accept() { QUndoCommand* command = new QUndoCommand(); bool change_duration = !duration_slider_->IsTristate() || (!speed_slider_->IsTristate() && link_speed_and_duration_->isChecked()); bool change_speed = !speed_slider_->IsTristate() || (!duration_slider_->IsTristate() && link_speed_and_duration_->isChecked()); foreach (ClipBlock* clip, clips_) { double new_speed = speed_slider_->GetValue(); if (change_duration) { // Change the duration int64_t current_duration = Timecode::time_to_timestamp(clip->length(), timebase_); int64_t new_duration = current_duration; // Check if we're getting the duration value directly from the slider or calculating it from the speed if (duration_slider_->IsTristate()) { // Calculate duration from speed new_duration = GetAdjustedDuration(clip, new_speed); } else { // Get duration directly from slider new_duration = duration_slider_->GetValue(); // Check if we're calculating the speed from this duration if (speed_slider_->IsTristate() && change_speed) { // If we're here, the duration is going to override the speed new_speed = GetAdjustedSpeed(clip, new_duration); } } if (new_duration != current_duration) { // Calculate new clip length rational new_clip_length = Timecode::timestamp_to_time(new_duration, timebase_); if (ripple_clips_checkbox_->isChecked()) { // FIXME: Make this a REAL ripple... new BlockResizeCommand(clip, new_clip_length, command); } else { // If "ripple clips" isn't checked, we may be limited to how much we can change the length Block* next_block = clip->next(); if (next_block) { if (new_clip_length > clip->length()) { if (next_block->type() == Block::kGap) { // Check if next clip is a gap, and if so we can take it all up new_clip_length = qMin(next_block->out(), clip->in() + new_clip_length); } else { // Otherwise we can't extend any further new_clip_length = clip->length(); } } } if (new_clip_length != clip->length()) { new BlockTrimCommand(TrackOutput::TrackFromBlock(clip), clip, new_clip_length, Timeline::kTrimOut, command); } } } } if (change_speed) { rational new_block_speed = rational::fromDouble(new_speed); if (clip->is_reversed()) { new_block_speed = -new_block_speed; } // Change the speed new BlockSetSpeedCommand(clip, new_block_speed, command); } if (!reverse_speed_checkbox_->isTristate() && clip->is_reversed() != reverse_speed_checkbox_->isChecked()) { new BlockReverseCommand(clip, command); } } Core::instance()->undo_stack()->pushIfHasChildren(command); QDialog::accept(); } double SpeedDurationDialog::GetUnadjustedLengthTimestamp(ClipBlock *clip) const { double duration = static_cast(Timecode::time_to_timestamp(clip->length(), timebase_)); // Convert duration to non-speed adjusted duration duration *= qAbs(clip->speed().toDouble()); return duration; } int64_t SpeedDurationDialog::GetAdjustedDuration(ClipBlock *clip, const double &new_speed) const { double duration = GetUnadjustedLengthTimestamp(clip); // Re-adjust by new speed duration /= new_speed; // Return rounded time return qRound64(duration); } double SpeedDurationDialog::GetAdjustedSpeed(ClipBlock *clip, const int64_t &new_duration) const { double duration = GetUnadjustedLengthTimestamp(clip); // Create a fraction of the original duration over the new duration duration /= static_cast(new_duration); return duration; } void SpeedDurationDialog::SpeedChanged() { if (link_speed_and_duration_->isChecked()) { double new_speed = speed_slider_->GetValue(); if (qIsNull(new_speed)) { // A speed of 0 is considered a still frame. Since we can't divide by zero and a still frame could be any length, // we don't bother updating the return; } bool same_durations = true; int64_t new_duration = GetAdjustedDuration(clips_.first(), new_speed); for (int i=1;iSetValue(new_duration); } else { duration_slider_->SetTristate(); } } } void SpeedDurationDialog::DurationChanged() { if (link_speed_and_duration_->isChecked()) { int64_t new_duration = duration_slider_->GetValue(); bool same_speeds = true; double new_speed = GetAdjustedSpeed(clips_.first(), new_duration); for (int i=1;iSetValue(new_speed); } else { speed_slider_->SetTristate(); } } } BlockReverseCommand::BlockReverseCommand(Block *block, QUndoCommand *parent) : UndoCommand(parent), block_(block) { } Project *BlockReverseCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockReverseCommand::redo_internal() { block_->set_media_in(block_->media_out()); block_->set_speed(-block_->speed()); } void BlockReverseCommand::undo_internal() { redo_internal(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/speedduration/speedduration.h000066400000000000000000000042011370472574300243150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SPEEDDURATIONDIALOG_H #define SPEEDDURATIONDIALOG_H #include #include #include "node/block/clip/clip.h" #include "node/output/track/track.h" #include "widget/slider/floatslider.h" #include "widget/slider/timeslider.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER class SpeedDurationDialog : public QDialog { Q_OBJECT public: SpeedDurationDialog(const rational& timebase, const QList& clips, QWidget* parent = nullptr); public slots: virtual void accept() override; private: double GetUnadjustedLengthTimestamp(ClipBlock* clip) const; int64_t GetAdjustedDuration(ClipBlock* clip, const double& new_speed) const; double GetAdjustedSpeed(ClipBlock* clip, const int64_t& new_duration) const; QList clips_; FloatSlider* speed_slider_; TimeSlider* duration_slider_; rational timebase_; QCheckBox* link_speed_and_duration_; QCheckBox* reverse_speed_checkbox_; QCheckBox* maintain_audio_pitch_checkbox_; QCheckBox* ripple_clips_checkbox_; private slots: void SpeedChanged(); void DurationChanged(); }; class BlockReverseCommand : public UndoCommand { public: BlockReverseCommand(Block* block, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; }; OLIVE_NAMESPACE_EXIT #endif // SPEEDDURATIONDIALOG_H olive-continuous/app/dialog/task/000077500000000000000000000000001370472574300173755ustar00rootroot00000000000000olive-continuous/app/dialog/task/CMakeLists.txt000066400000000000000000000014411370472574300221350ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} dialog/task/task.h dialog/task/task.cpp PARENT_SCOPE ) olive-continuous/app/dialog/task/task.cpp000066400000000000000000000047101370472574300210450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "task.h" #include OLIVE_NAMESPACE_ENTER TaskDialog::TaskDialog(Task* task, const QString& title, QWidget *parent) : ProgressDialog(task->GetTitle(), title, parent), task_(task), destroy_on_close_(true) { // Clear task when this dialog is destroyed task_->setParent(this); // Connect the save manager progress signal to the progress bar update on the dialog connect(task_, &Task::ProgressChanged, this, &TaskDialog::SetProgress, Qt::QueuedConnection); // Connect cancel signal (must be a direct connection or it'll be queued after the task has // already finished) connect(this, &TaskDialog::Cancelled, task_, &Task::Cancel, Qt::DirectConnection); } void TaskDialog::showEvent(QShowEvent *e) { ProgressDialog::showEvent(e); // Create watcher for when the task finishes QFutureWatcher* task_watcher = new QFutureWatcher(); // Listen for when the task finishes connect(task_watcher, &QFutureWatcher::finished, this, &TaskDialog::TaskFinished, Qt::QueuedConnection); // Run task in another thread with QtConcurrent task_watcher->setFuture(QtConcurrent::run(task_, &Task::Start)); } void TaskDialog::closeEvent(QCloseEvent *e) { // Cancel task if it is running task_->Cancel(); // Standard close function ProgressDialog::closeEvent(e); // Clean up this task and dialog if (destroy_on_close_) { deleteLater(); } } void TaskDialog::TaskFinished() { QFutureWatcher* task_watcher = static_cast*>(sender()); if (task_watcher->result()) { emit TaskSucceeded(task_); } else { ShowErrorMessage(tr("Task Failed"), task_->GetError()); emit TaskFailed(task_); } task_watcher->deleteLater(); close(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/dialog/task/task.h000066400000000000000000000035371370472574300205200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TASKDIALOG_H #define TASKDIALOG_H #include "dialog/progress/progress.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class TaskDialog : public ProgressDialog { Q_OBJECT public: /** * @brief TaskDialog Constructor * * Creates a TaskDialog. The TaskDialog takes ownership of the Task and will destroy it on close. * Connect to the Task::Succeeded() if you want to retrieve information from the task before it * gets destroyed. */ TaskDialog(Task *task, const QString &title, QWidget* parent = nullptr); /** * @brief Set whether TaskDialog should destroy itself (and the task) when it's closed * * This is TRUE by default. */ void SetDestroyOnClose(bool e) { destroy_on_close_ = e; } /** * @brief Returns this dialog's task */ Task* GetTask() const { return task_; } protected: virtual void showEvent(QShowEvent* e) override; virtual void closeEvent(QCloseEvent* e) override; signals: void TaskSucceeded(Task* task); void TaskFailed(Task* task); private: Task* task_; bool destroy_on_close_; private slots: void TaskFinished(); }; OLIVE_NAMESPACE_EXIT #endif // TASKDIALOG_H olive-continuous/app/main.cpp000066400000000000000000000054211370472574300166260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ /** \mainpage Olive Video Editor - Code Documentation * * This documentation is a primarily a developer resource. For information on using Olive, visit the website * https://www.olivevideoeditor.org/ * * Use the navigation above to find documentation on classes or source files. */ extern "C" { #include #include } #include #include #include #include "core.h" #include "common/crashhandler.h" #include "common/debug.h" int main(int argc, char *argv[]) { signal(SIGSEGV, OLIVE_NAMESPACE::crash_handler); signal(SIGABRT, OLIVE_NAMESPACE::crash_handler); // Set OpenGL display profile (3.2 Core) QSurfaceFormat format; format.setVersion(3, 2); format.setDepthBufferSize(24); format.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(format); //QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); // Create application instance QApplication a(argc, argv); // Set application metadata QCoreApplication::setOrganizationName("olivevideoeditor.org"); QCoreApplication::setOrganizationDomain("olivevideoeditor.org"); QCoreApplication::setApplicationName("Olive"); QString app_version = APPVERSION; #ifdef GITHASH // Anything after the hyphen is considered "unimportant" information. Text BEFORE the hyphen is used in version // checking project files and config files app_version.append("-"); app_version.append(GITHASH); #endif QCoreApplication::setApplicationVersion(app_version); #if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) QGuiApplication::setDesktopFileName("org.olivevideoeditor.Olive"); #endif // Set up debug handler qInstallMessageHandler(OLIVE_NAMESPACE::DebugHandler); // Register FFmpeg codecs and filters (deprecated in 4.0+) #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) av_register_all(); #endif #if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(7, 14, 100) avfilter_register_all(); #endif return OLIVE_NAMESPACE::Core::instance()->execute(&a); } olive-continuous/app/node/000077500000000000000000000000001370472574300161215ustar00rootroot00000000000000olive-continuous/app/node/CMakeLists.txt000066400000000000000000000025131370472574300206620ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(audio) add_subdirectory(block) add_subdirectory(filter) add_subdirectory(generator) add_subdirectory(input) add_subdirectory(math) add_subdirectory(output) set(OLIVE_SOURCES ${OLIVE_SOURCES} node/edge.h node/edge.cpp node/factory.h node/factory.cpp node/graph.h node/graph.cpp node/input.h node/input.cpp node/inputarray.h node/inputarray.cpp node/inputdragger.h node/inputdragger.cpp node/keyframe.h node/keyframe.cpp node/node.h node/node.cpp node/output.h node/output.cpp node/param.h node/param.cpp node/traverser.h node/traverser.cpp node/value.h node/value.cpp PARENT_SCOPE ) olive-continuous/app/node/audio/000077500000000000000000000000001370472574300172225ustar00rootroot00000000000000olive-continuous/app/node/audio/CMakeLists.txt000066400000000000000000000014451370472574300217660ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(pan) add_subdirectory(volume) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/node/audio/pan/000077500000000000000000000000001370472574300200005ustar00rootroot00000000000000olive-continuous/app/node/audio/pan/CMakeLists.txt000066400000000000000000000014451370472574300225440ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/audio/pan/pan.h node/audio/pan/pan.cpp PARENT_SCOPE ) olive-continuous/app/node/audio/pan/pan.cpp000066400000000000000000000061001370472574300212570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "pan.h" OLIVE_NAMESPACE_ENTER PanNode::PanNode() { samples_input_ = new NodeInput("samples_in", NodeParam::kSamples); AddInput(samples_input_); panning_input_ = new NodeInput("panning_in", NodeParam::kFloat, 0.0); panning_input_->set_property("min", -1.0); panning_input_->set_property("max", 1.0); panning_input_->set_property("view", "percent"); AddInput(panning_input_); } Node *PanNode::copy() const { return new PanNode(); } QString PanNode::Name() const { return tr("Pan"); } QString PanNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.pan"); } QList PanNode::Category() const { return {kCategoryChannels}; } QString PanNode::Description() const { return tr("Adjust the stereo panning of an audio source."); } NodeValueTable PanNode::Value(NodeValueDatabase &value) const { // Create a sample job SampleJob job(samples_input_, value); job.InsertValue(panning_input_, value); // Push it to our table NodeValueTable table = value.Merge(); if (job.HasSamples()) { float pan_volume = job.GetValue(panning_input_).data().toFloat(); if (panning_input_->is_static()) { if (!qIsNull(pan_volume) && job.samples()->audio_params().channel_count() == 2) { if (pan_volume > 0) { job.samples()->transform_volume_for_channel(0, 1.0f - pan_volume); } else { job.samples()->transform_volume_for_channel(1, 1.0f + pan_volume); } } table.Push(NodeParam::kSamples, QVariant::fromValue(job.samples()), this); } else { table.Push(NodeParam::kSampleJob, QVariant::fromValue(job), this); } } return table; } void PanNode::ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const { if (input->audio_params().channel_count() != 2) { // This node currently only works for stereo audio return; } float pan_val = values[panning_input_].Get(NodeParam::kFloat).toFloat(); for (int i=0;iaudio_params().channel_count();i++) { output->data()[i][index] = input->data()[i][index]; } if (pan_val > 0) { output->data()[0][index] *= (1.0F - pan_val); } else if (pan_val < 0) { output->data()[1][index] *= (1.0F - qAbs(pan_val)); } } void PanNode::Retranslate() { samples_input_->set_name(tr("Samples")); panning_input_->set_name(tr("Pan")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/audio/pan/pan.h000066400000000000000000000026361370472574300207360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PANNODE_H #define PANNODE_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class PanNode : public Node { public: PanNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual void ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override; virtual void Retranslate() override; private: NodeInput* samples_input_; NodeInput* panning_input_; }; OLIVE_NAMESPACE_EXIT #endif // PANNODE_H olive-continuous/app/node/audio/volume/000077500000000000000000000000001370472574300205315ustar00rootroot00000000000000olive-continuous/app/node/audio/volume/CMakeLists.txt000066400000000000000000000014611370472574300232730ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/audio/volume/volume.h node/audio/volume/volume.cpp PARENT_SCOPE ) olive-continuous/app/node/audio/volume/volume.cpp000066400000000000000000000043401370472574300225450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "volume.h" OLIVE_NAMESPACE_ENTER VolumeNode::VolumeNode() { samples_input_ = new NodeInput("samples_in", NodeParam::kSamples); AddInput(samples_input_); volume_input_ = new NodeInput("volume_in", NodeParam::kFloat, 1.0); volume_input_->set_property("min", 0.0); volume_input_->set_property("view", "db"); AddInput(volume_input_); } Node *VolumeNode::copy() const { return new VolumeNode(); } QString VolumeNode::Name() const { return tr("Volume"); } QString VolumeNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.volume"); } QList VolumeNode::Category() const { return {kCategoryFilter}; } QString VolumeNode::Description() const { return tr("Adjusts the volume of an audio source."); } NodeValueTable VolumeNode::Value(NodeValueDatabase &value) const { return ValueInternal(value, kOpMultiply, kPairSampleNumber, samples_input_, value[samples_input_].TakeWithMeta(NodeParam::kSamples), volume_input_, value[volume_input_].TakeWithMeta(NodeParam::kFloat)); } void VolumeNode::ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const { return ProcessSamplesInternal(values, kOpMultiply, samples_input_, volume_input_, input, output, index); } void VolumeNode::Retranslate() { samples_input_->set_name(tr("Samples")); volume_input_->set_name(tr("Volume")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/audio/volume/volume.h000066400000000000000000000030111370472574300222040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VOLUMENODE_H #define VOLUMENODE_H #include "node/math/math/mathbase.h" OLIVE_NAMESPACE_ENTER class VolumeNode : public MathNodeBase { public: VolumeNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual void ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override; virtual void Retranslate() override; NodeInput* samples_input() const { return samples_input_; } private: NodeInput* samples_input_; NodeInput* volume_input_; }; OLIVE_NAMESPACE_EXIT #endif // VOLUMENODE_H olive-continuous/app/node/block/000077500000000000000000000000001370472574300172135ustar00rootroot00000000000000olive-continuous/app/node/block/CMakeLists.txt000066400000000000000000000015541370472574300217600ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(clip) add_subdirectory(gap) add_subdirectory(transition) set(OLIVE_SOURCES ${OLIVE_SOURCES} node/block/block.h node/block/block.cpp PARENT_SCOPE ) olive-continuous/app/node/block/block.cpp000066400000000000000000000170431370472574300210160ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "block.h" #include #include "node/output/track/track.h" #include "transition/transition.h" OLIVE_NAMESPACE_ENTER Block::Block() : previous_(nullptr), next_(nullptr) { length_input_ = new NodeInput("length_in", NodeParam::kRational); length_input_->set_connectable(false); length_input_->set_is_keyframable(false); AddInput(length_input_); disconnect(length_input_, &NodeInput::ValueChanged, this, &Block::InputChanged); connect(length_input_, &NodeInput::ValueChanged, this, &Block::LengthInputChanged); media_in_input_ = new NodeInput("media_in_in", NodeParam::kRational); media_in_input_->set_connectable(false); media_in_input_->set_is_keyframable(false); AddInput(media_in_input_); enabled_input_ = new NodeInput("enabled_in", NodeParam::kBoolean); enabled_input_->set_connectable(false); enabled_input_->set_is_keyframable(false); enabled_input_->set_standard_value(true); AddInput(enabled_input_); speed_input_ = new NodeInput("speed_in", NodeParam::kRational); speed_input_->set_standard_value(QVariant::fromValue(rational(1))); speed_input_->set_connectable(false); speed_input_->set_is_keyframable(false); AddInput(speed_input_); // A block's length must be greater than 0 set_length_and_media_out(1); } QList Block::Category() const { return {kCategoryTimeline}; } const rational &Block::in() const { return in_point_; } const rational &Block::out() const { return out_point_; } void Block::set_in(const rational &in) { in_point_ = in; } void Block::set_out(const rational &out) { out_point_ = out; } rational Block::length() const { return length_input_->get_standard_value().value(); } void Block::set_length_and_media_out(const rational &length) { Q_ASSERT(length > 0); if (length == this->length()) { return; } rational old_length = this->length(); set_length_internal(length); LengthChangedEvent(old_length, length, Timeline::kTrimOut); } void Block::set_length_and_media_in(const rational &length) { Q_ASSERT(length > 0); if (length == this->length()) { return; } // Calculate media_in adjustment set_media_in(media_in() + (this->length() - length) * speed()); rational old_length = this->length(); // Set the length without setting media out set_length_internal(length); LengthChangedEvent(old_length, length, Timeline::kTrimIn); } Block *Block::previous() { return previous_; } Block *Block::next() { return next_; } void Block::set_previous(Block *previous) { previous_ = previous; } void Block::set_next(Block *next) { next_ = next; } rational Block::media_in() const { return media_in_input_->get_standard_value().value(); } void Block::set_media_in(const rational &media_in) { media_in_input_->set_standard_value(QVariant::fromValue(media_in)); } rational Block::media_out() const { return media_in() + length() * speed(); } rational Block::speed() const { return speed_input_->get_standard_value().value(); } void Block::set_speed(const rational &speed) { speed_input_->set_standard_value(QVariant::fromValue(speed)); } bool Block::is_still() const { return speed() == 0; } bool Block::is_reversed() const { return speed() < 0; } bool Block::is_enabled() const { return enabled_input_->get_standard_value().toBool(); } void Block::set_enabled(bool e) { enabled_input_->set_standard_value(e); emit EnabledChanged(); } rational Block::SequenceToMediaTime(const rational &sequence_time) const { // These constants are not considered "values" per se, so we don't modify them if (sequence_time == RATIONAL_MIN || sequence_time == RATIONAL_MAX) { return sequence_time; } return (sequence_time - in()) * speed() + media_in(); } rational Block::MediaToSequenceTime(const rational &media_time) const { // These constants are not considered "values" per se, so we don't modify them if (media_time == RATIONAL_MIN || media_time == RATIONAL_MAX) { return media_time; } return (media_time - media_in()) / speed() + in(); } void Block::LoadInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data) { if (reader->name() == QStringLiteral("link")) { xml_node_data.block_links.append({this, reader->readElementText().toULongLong()}); } else { Node::LoadInternal(reader, xml_node_data); } } void Block::SaveInternal(QXmlStreamWriter *writer) const { foreach (Block* link, linked_clips_) { writer->writeTextElement(QStringLiteral("link"), QString::number(reinterpret_cast(link))); } } QList Block::GetInputsToHash() const { QList inputs = Node::GetInputsToHash(); // Ignore these inputs inputs.removeOne(media_in_input_); inputs.removeOne(speed_input_); inputs.removeOne(length_input_); return inputs; } void Block::LengthChangedEvent(const rational &, const rational &, const Timeline::MovementMode &) { } void Block::set_length_internal(const rational &length) { length_input_->set_standard_value(QVariant::fromValue(length)); } void Block::LengthInputChanged() { emit LengthChanged(length()); } bool Block::Link(Block *a, Block *b) { if (a == b || !a || !b) { return false; } // Prevent duplicate link entries (assume that we only need to check one clip since this should be the only function // that adds to the linked array) if (Block::AreLinked(a, b)) { return false; } a->linked_clips_.append(b); b->linked_clips_.append(a); emit a->LinksChanged(); emit b->LinksChanged(); return true; } void Block::Link(const QList& blocks) { foreach (Block* a, blocks) { foreach (Block* b, blocks) { Link(a, b); } } } bool Block::Unlink(Block *a, Block *b) { if (a == b || !a || !b) { return false; } if (!Block::AreLinked(a, b)) { return false; } a->linked_clips_.removeOne(b); b->linked_clips_.removeOne(a); emit a->LinksChanged(); emit b->LinksChanged(); return true; } void Block::Unlink(const QList &blocks) { foreach (Block* a, blocks) { foreach (Block* b, blocks) { Unlink(a, b); } } } bool Block::AreLinked(Block *a, Block *b) { return a->linked_clips_.contains(b); } const QVector &Block::linked_clips() { return linked_clips_; } bool Block::HasLinks() { return !linked_clips_.isEmpty(); } bool Block::IsBlock() const { return true; } void Block::Retranslate() { Node::Retranslate(); length_input_->set_name(tr("Length")); media_in_input_->set_name(tr("Media In")); enabled_input_->set_name(tr("Enabled")); speed_input_->set_name(tr("Speed")); } NodeInput *Block::length_input() const { return length_input_; } NodeInput *Block::media_in_input() const { return media_in_input_; } NodeInput *Block::speed_input() const { return speed_input_; } void Block::Hash(QCryptographicHash &, const rational &) const { // A block does nothing by default, so we hash nothing } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/block/block.h000066400000000000000000000070471370472574300204660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef BLOCK_H #define BLOCK_H #include "node/node.h" #include "timeline/timelinecommon.h" OLIVE_NAMESPACE_ENTER /** * @brief A Node that represents a block of time, also displayable on a Timeline */ class Block : public Node { Q_OBJECT public: Block(); enum Type { kClip, kGap, kTransition }; virtual Type type() const = 0; virtual QList Category() const override; const rational& in() const; const rational& out() const; void set_in(const rational& in); void set_out(const rational& out); rational length() const; void set_length_and_media_out(const rational &length); void set_length_and_media_in(const rational &length); Block* previous(); Block* next(); void set_previous(Block* previous); void set_next(Block* next); rational media_in() const; void set_media_in(const rational& media_in); rational media_out() const; rational speed() const; void set_speed(const rational& speed); bool is_still() const; bool is_reversed() const; bool is_enabled() const; void set_enabled(bool e); static bool Link(Block* a, Block* b); static void Link(const QList& blocks); static bool Unlink(Block* a, Block* b); static void Unlink(const QList& blocks); static bool AreLinked(Block* a, Block* b); const QVector& linked_clips(); bool HasLinks(); virtual bool IsBlock() const override; virtual void Retranslate() override; NodeInput* length_input() const; NodeInput* media_in_input() const; NodeInput* speed_input() const; virtual void Hash(QCryptographicHash &hash, const rational &time) const override; public slots: signals: /** * @brief Signal emitted when this Block is refreshed * * Can be used as essentially a "changed" signal for UI widgets to know when to update their views */ void Refreshed(); void LengthChanged(const rational& length); void LinksChanged(); void EnabledChanged(); protected: rational SequenceToMediaTime(const rational& sequence_time) const; rational MediaToSequenceTime(const rational& media_time) const; virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data) override; virtual void SaveInternal(QXmlStreamWriter* writer) const override; virtual QList GetInputsToHash() const override; virtual void LengthChangedEvent(const rational& old_length, const rational& new_length, const Timeline::MovementMode& mode); Block* previous_; Block* next_; private: void set_length_internal(const rational &length); NodeInput* length_input_; NodeInput* media_in_input_; NodeInput* speed_input_; NodeInput* enabled_input_; rational in_point_; rational out_point_; QVector linked_clips_; private slots: void LengthInputChanged(); }; OLIVE_NAMESPACE_EXIT #endif // BLOCK_H olive-continuous/app/node/block/clip/000077500000000000000000000000001370472574300201425ustar00rootroot00000000000000olive-continuous/app/node/block/clip/CMakeLists.txt000066400000000000000000000014511370472574300227030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/block/clip/clip.h node/block/clip/clip.cpp PARENT_SCOPE ) olive-continuous/app/node/block/clip/clip.cpp000066400000000000000000000062271370472574300216040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "clip.h" OLIVE_NAMESPACE_ENTER ClipBlock::ClipBlock() { texture_input_ = new NodeInput("buffer_in", NodeInput::kBuffer); texture_input_->set_is_keyframable(false); AddInput(texture_input_); } Node *ClipBlock::copy() const { return new ClipBlock(); } Block::Type ClipBlock::type() const { return kClip; } QString ClipBlock::Name() const { return tr("Clip"); } QString ClipBlock::id() const { return QStringLiteral("org.olivevideoeditor.Olive.clip"); } QString ClipBlock::Description() const { return tr("A time-based node that represents a media source."); } NodeInput *ClipBlock::texture_input() const { return texture_input_; } void ClipBlock::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source) { // If signal is from texture input, transform all times from media time to sequence time if (from == texture_input_) { // Adjust range from media time to sequence time rational start = MediaToSequenceTime(range.in()); rational end = MediaToSequenceTime(range.out()); Block::InvalidateCache(TimeRange(start, end), from, source); } else { // Otherwise, pass signal along normally Block::InvalidateCache(range, from, source); } } TimeRange ClipBlock::InputTimeAdjustment(NodeInput *input, const TimeRange &input_time) const { if (input == texture_input_) { return TimeRange(SequenceToMediaTime(input_time.in()), SequenceToMediaTime(input_time.out())); } return Block::InputTimeAdjustment(input, input_time); } TimeRange ClipBlock::OutputTimeAdjustment(NodeInput *input, const TimeRange &input_time) const { if (input == texture_input_) { return TimeRange(MediaToSequenceTime(input_time.in()), MediaToSequenceTime(input_time.out())); } return Block::InputTimeAdjustment(input, input_time); } NodeValueTable ClipBlock::Value(NodeValueDatabase &value) const { // We discard most values here except for the buffer we received NodeValue data = value[texture_input()].GetWithMeta(NodeParam::kBuffer); NodeValueTable table; if (data.type() != NodeParam::kNone) { table.Push(data); } return table; } void ClipBlock::Retranslate() { Block::Retranslate(); texture_input_->set_name(tr("Buffer")); } void ClipBlock::Hash(QCryptographicHash &hash, const rational &time) const { if (texture_input_->is_connected()) { rational t = InputTimeAdjustment(texture_input_, TimeRange(time, time)).in(); texture_input_->get_connected_node()->Hash(hash, t); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/block/clip/clip.h000066400000000000000000000033611370472574300212450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CLIPBLOCK_H #define CLIPBLOCK_H #include "node/block/block.h" OLIVE_NAMESPACE_ENTER /** * @brief Node that represents a block of Media */ class ClipBlock : public Block { Q_OBJECT public: ClipBlock(); virtual Node* copy() const override; virtual Type type() const override; virtual QString Name() const override; virtual QString id() const override; virtual QString Description() const override; NodeInput* texture_input() const; virtual void InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput* source) override; virtual TimeRange InputTimeAdjustment(NodeInput* input, const TimeRange& input_time) const override; virtual TimeRange OutputTimeAdjustment(NodeInput* input, const TimeRange& input_time) const override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; virtual void Retranslate() override; virtual void Hash(QCryptographicHash &hash, const rational &time) const override; private: NodeInput* texture_input_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEBLOCK_H olive-continuous/app/node/block/gap/000077500000000000000000000000001370472574300177625ustar00rootroot00000000000000olive-continuous/app/node/block/gap/CMakeLists.txt000066400000000000000000000014451370472574300225260ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/block/gap/gap.h node/block/gap/gap.cpp PARENT_SCOPE ) olive-continuous/app/node/block/gap/gap.cpp000066400000000000000000000022241370472574300212350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "gap.h" OLIVE_NAMESPACE_ENTER GapBlock::GapBlock() { } Node *GapBlock::copy() const { return new GapBlock(); } Block::Type GapBlock::type() const { return kGap; } QString GapBlock::Name() const { return tr("Gap"); } QString GapBlock::id() const { return QStringLiteral("org.olivevideoeditor.Olive.gap"); } QString GapBlock::Description() const { return tr("A time-based node that represents an empty space."); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/block/gap/gap.h000066400000000000000000000023321370472574300207020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef GAPBLOCK_H #define GAPBLOCK_H #include "node/block/block.h" OLIVE_NAMESPACE_ENTER /** * @brief Node that represents nothing in its respective track for a certain period of time */ class GapBlock : public Block { Q_OBJECT public: GapBlock(); virtual Node * copy() const override; virtual Type type() const override; virtual QString Name() const override; virtual QString id() const override; virtual QString Description() const override; private: }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEBLOCK_H olive-continuous/app/node/block/transition/000077500000000000000000000000001370472574300214055ustar00rootroot00000000000000olive-continuous/app/node/block/transition/CMakeLists.txt000066400000000000000000000015771370472574300241570ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(crossdissolve) add_subdirectory(diptocolor) set(OLIVE_SOURCES ${OLIVE_SOURCES} node/block/transition/transition.h node/block/transition/transition.cpp PARENT_SCOPE ) olive-continuous/app/node/block/transition/crossdissolve/000077500000000000000000000000001370472574300243075ustar00rootroot00000000000000olive-continuous/app/node/block/transition/crossdissolve/CMakeLists.txt000066400000000000000000000015671370472574300270600ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/block/transition/crossdissolve/crossdissolvetransition.h node/block/transition/crossdissolve/crossdissolvetransition.cpp PARENT_SCOPE ) olive-continuous/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp000066400000000000000000000047551370472574300320430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "crossdissolvetransition.h" OLIVE_NAMESPACE_ENTER CrossDissolveTransition::CrossDissolveTransition() { } Node *CrossDissolveTransition::copy() const { return new CrossDissolveTransition(); } QString CrossDissolveTransition::Name() const { return tr("Cross Dissolve"); } QString CrossDissolveTransition::id() const { return QStringLiteral("org.olivevideoeditor.Olive.crossdissolve"); } QList CrossDissolveTransition::Category() const { return {kCategoryTransition}; } QString CrossDissolveTransition::Description() const { return tr("Smoothly transition between two clips."); } ShaderCode CrossDissolveTransition::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(Node::ReadFileAsString(":/shaders/crossdissolve.frag"), QString()); } void CrossDissolveTransition::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const { for (int i=0; isample_count(); i++) { double this_sample_time = out_samples->audio_params().samples_to_time(i).toDouble() + time_in; double progress = GetTotalProgress(this_sample_time); for (int j=0; jaudio_params().channel_count(); j++) { out_samples->data()[j][i] = 0; if (from_samples) { if (i < from_samples->sample_count()) { out_samples->data()[j][i] += from_samples->data()[j][i] * TransformCurve(1.0 - progress); } } if (to_samples) { // Offset input samples from the end int in_index = i - (out_samples->sample_count() - to_samples->sample_count()); if (in_index >= 0) { out_samples->data()[j][i] += to_samples->data()[j][in_index] * TransformCurve(progress); } } } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/block/transition/crossdissolve/crossdissolvetransition.h000066400000000000000000000027511370472574300315020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CROSSDISSOLVETRANSITION_H #define CROSSDISSOLVETRANSITION_H #include "node/block/transition/transition.h" OLIVE_NAMESPACE_ENTER class CrossDissolveTransition : public TransitionBlock { public: CrossDissolveTransition(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; //virtual void Retranslate() override; virtual ShaderCode GetShaderCode(const QString& shader_id) const override; protected: virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const override; }; OLIVE_NAMESPACE_EXIT #endif // CROSSDISSOLVETRANSITION_H olive-continuous/app/node/block/transition/diptocolor/000077500000000000000000000000001370472574300235635ustar00rootroot00000000000000olive-continuous/app/node/block/transition/diptocolor/CMakeLists.txt000066400000000000000000000015531370472574300263270ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/block/transition/diptocolor/diptocolortransition.h node/block/transition/diptocolor/diptocolortransition.cpp PARENT_SCOPE ) olive-continuous/app/node/block/transition/diptocolor/diptocolortransition.cpp000066400000000000000000000034111370472574300305570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "diptocolortransition.h" OLIVE_NAMESPACE_ENTER DipToColorTransition::DipToColorTransition() { color_input_ = new NodeInput(QStringLiteral("color_in"), NodeParam::kColor, QVariant::fromValue(Color(0, 0, 0))); AddInput(color_input_); } Node *DipToColorTransition::copy() const { return new DipToColorTransition(); } QString DipToColorTransition::Name() const { return tr("Dip To Color"); } QString DipToColorTransition::id() const { return QStringLiteral("org.olivevideoeditor.Olive.diptocolor"); } QList DipToColorTransition::Category() const { return {kCategoryTransition}; } QString DipToColorTransition::Description() const { return tr("Transition between clips by dipping to a color."); } ShaderCode DipToColorTransition::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(Node::ReadFileAsString(":/shaders/diptoblack.frag"), QString()); } void DipToColorTransition::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const { job.InsertValue(color_input_, value); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/block/transition/diptocolor/diptocolortransition.h000066400000000000000000000026301370472574300302260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef DIPTOCOLORTRANSITION_H #define DIPTOCOLORTRANSITION_H #include "node/block/transition/transition.h" OLIVE_NAMESPACE_ENTER class DipToColorTransition : public TransitionBlock { public: DipToColorTransition(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual ShaderCode GetShaderCode(const QString& shader_id) const override; protected: virtual void ShaderJobEvent(NodeValueDatabase &value, ShaderJob& job) const override; private: NodeInput* color_input_; }; OLIVE_NAMESPACE_EXIT #endif // DIPTOCOLORTRANSITION_H olive-continuous/app/node/block/transition/transition.cpp000066400000000000000000000204121370472574300243020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "transition.h" #include "common/clamp.h" OLIVE_NAMESPACE_ENTER TransitionBlock::TransitionBlock() : connected_out_block_(nullptr), connected_in_block_(nullptr) { out_block_input_ = new NodeInput(QStringLiteral("out_block_in"), NodeParam::kBuffer); out_block_input_->set_is_keyframable(false); connect(out_block_input_, &NodeParam::EdgeAdded, this, &TransitionBlock::BlockConnected); connect(out_block_input_, &NodeParam::EdgeRemoved, this, &TransitionBlock::BlockDisconnected); AddInput(out_block_input_); in_block_input_ = new NodeInput(QStringLiteral("in_block_in"), NodeParam::kBuffer); in_block_input_->set_is_keyframable(false); connect(in_block_input_, &NodeParam::EdgeAdded, this, &TransitionBlock::BlockConnected); connect(in_block_input_, &NodeParam::EdgeRemoved, this, &TransitionBlock::BlockDisconnected); AddInput(in_block_input_); curve_input_ = new NodeInput(QStringLiteral("curve_in"), NodeParam::kCombo); curve_input_->set_is_keyframable(false); curve_input_->set_connectable(false); AddInput(curve_input_); } Block::Type TransitionBlock::type() const { return kTransition; } NodeInput *TransitionBlock::out_block_input() const { return out_block_input_; } NodeInput *TransitionBlock::in_block_input() const { return in_block_input_; } void TransitionBlock::Retranslate() { Block::Retranslate(); out_block_input_->set_name(tr("From")); in_block_input_->set_name(tr("To")); curve_input_->set_name(tr("Curve")); // These must correspond to the CurveType enum curve_input_->set_combobox_strings({ tr("Linear"), tr("Exponential"), tr("Logarithmic") }); } rational TransitionBlock::in_offset() const { // If no in block is connected, there's no in offset if (!connected_in_block()) { return 0; } if (!connected_out_block()) { // Assume only an in block is connected, in which case this entire transition length return length(); } // Assume both are connected return length() + media_in(); } rational TransitionBlock::out_offset() const { // If no in block is connected, there's no in offset if (!connected_out_block()) { return 0; } if (!connected_in_block()) { // Assume only an in block is connected, in which case this entire transition length return length(); } // Assume both are connected return -media_in(); } Block *TransitionBlock::connected_out_block() const { return connected_out_block_; } Block *TransitionBlock::connected_in_block() const { return connected_in_block_; } double TransitionBlock::GetTotalProgress(const double &time) const { return GetInternalTransitionTime(time) / length().toDouble(); } double TransitionBlock::GetOutProgress(const double &time) const { if (out_offset() == 0) { return 0; } return clamp(1.0 - (GetInternalTransitionTime(time) / out_offset().toDouble()), 0.0, 1.0); } double TransitionBlock::GetInProgress(const double &time) const { if (in_offset() == 0) { return 0; } return clamp((GetInternalTransitionTime(time) - out_offset().toDouble()) / in_offset().toDouble(), 0.0, 1.0); } void TransitionBlock::Hash(QCryptographicHash &hash, const rational &time) const { Node::Hash(hash, time); double time_dbl = time.toDouble(); double all_prog = GetTotalProgress(time_dbl); double in_prog = GetInProgress(time_dbl); double out_prog = GetOutProgress(time_dbl); hash.addData(reinterpret_cast(&all_prog), sizeof(double)); hash.addData(reinterpret_cast(&in_prog), sizeof(double)); hash.addData(reinterpret_cast(&out_prog), sizeof(double)); } double TransitionBlock::GetInternalTransitionTime(const double &time) const { return time - in().toDouble(); } void TransitionBlock::InsertTransitionTimes(AcceleratedJob *job, const double &time) const { // Provides total transition progress from 0.0 (start) - 1.0 (end) job->InsertValue(QStringLiteral("ove_tprog_all"), NodeValue(NodeParam::kFloat, GetTotalProgress(time), this)); // Provides progress of out section from 1.0 (start) - 0.0 (end) job->InsertValue(QStringLiteral("ove_tprog_out"), NodeValue(NodeParam::kFloat, GetOutProgress(time), this)); // Provides progress of in section from 0.0 (start) - 1.0 (end) job->InsertValue(QStringLiteral("ove_tprog_in"), NodeValue(NodeParam::kFloat, GetInProgress(time), this)); } void TransitionBlock::BlockConnected(NodeEdgePtr edge) { if (!edge->output()->parentNode()->IsBlock()) { return; } Block* block = static_cast(edge->output()->parentNode()); if (edge->input() == out_block_input_) { connected_out_block_ = block; } else { connected_in_block_ = block; } } void TransitionBlock::BlockDisconnected(NodeEdgePtr edge) { if (edge->input() == out_block_input_) { connected_out_block_ = nullptr; } else { connected_in_block_ = nullptr; } } NodeValueTable TransitionBlock::Value(NodeValueDatabase &value) const { NodeParam::DataType data_type; if (out_block_input()->is_connected()) { data_type = value[out_block_input()].GetWithMeta(NodeParam::kBuffer).type(); } else if (in_block_input()->is_connected()) { data_type = value[in_block_input()].GetWithMeta(NodeParam::kBuffer).type(); } else { data_type = NodeParam::kNone; } NodeParam::DataType job_type; QVariant push_job; if (data_type == NodeParam::kTexture) { // This must be a visual transition ShaderJob job; job.InsertValue(out_block_input(), value); job.InsertValue(in_block_input(), value); job.InsertValue(curve_input_, value); double time = value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_in")).toDouble(); InsertTransitionTimes(&job, time); ShaderJobEvent(value, job); job_type = NodeParam::kShaderJob; push_job = QVariant::fromValue(job); } else if (data_type == NodeParam::kSamples) { // This must be an audio transition SampleBufferPtr from_samples = value[out_block_input()].Take(NodeParam::kBuffer).value(); SampleBufferPtr to_samples = value[in_block_input()].Take(NodeParam::kBuffer).value(); if (from_samples || to_samples) { double time_in = value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_in")).toDouble(); double time_out = value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_out")).toDouble(); const AudioParams& params = (from_samples) ? from_samples->audio_params() : to_samples->audio_params(); int nb_samples = params.time_to_samples(time_out - time_in); SampleBufferPtr out_samples = SampleBuffer::CreateAllocated(params, nb_samples); SampleJobEvent(from_samples, to_samples, out_samples, time_in); job_type = NodeParam::kSamples; push_job = QVariant::fromValue(out_samples); } } NodeValueTable table = value.Merge(); if (!push_job.isNull()) { table.Push(job_type, push_job, this); } return table; } void TransitionBlock::ShaderJobEvent(NodeValueDatabase &value, ShaderJob &job) const { Q_UNUSED(value) Q_UNUSED(job) } void TransitionBlock::SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const { Q_UNUSED(from_samples) Q_UNUSED(to_samples) Q_UNUSED(out_samples) Q_UNUSED(time_in) } double TransitionBlock::TransformCurve(double linear) const { switch (static_cast(curve_input_->get_standard_value().toInt())) { case kLinear: break; case kExponential: linear *= linear; break; case kLogarithmic: linear = qSqrt(linear); break; } return linear; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/block/transition/transition.h000066400000000000000000000044031370472574300237510ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRANSITIONBLOCK_H #define TRANSITIONBLOCK_H #include "node/block/block.h" OLIVE_NAMESPACE_ENTER class TransitionBlock : public Block { public: TransitionBlock(); virtual Type type() const override; NodeInput* out_block_input() const; NodeInput* in_block_input() const; virtual void Retranslate() override; rational in_offset() const; rational out_offset() const; Block* connected_out_block() const; Block* connected_in_block() const; double GetTotalProgress(const double &time) const; double GetOutProgress(const double &time) const; double GetInProgress(const double &time) const; virtual void Hash(QCryptographicHash& hash, const rational &time) const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; protected: virtual void ShaderJobEvent(NodeValueDatabase &value, ShaderJob& job) const; virtual void SampleJobEvent(SampleBufferPtr from_samples, SampleBufferPtr to_samples, SampleBufferPtr out_samples, double time_in) const; double TransformCurve(double linear) const; private: enum CurveType { kLinear, kExponential, kLogarithmic }; double GetInternalTransitionTime(const double &time) const; void InsertTransitionTimes(AcceleratedJob* job, const double& time) const; NodeInput* out_block_input_; NodeInput* in_block_input_; NodeInput* curve_input_; Block* connected_out_block_; Block* connected_in_block_; private slots: void BlockConnected(NodeEdgePtr edge); void BlockDisconnected(NodeEdgePtr edge); }; OLIVE_NAMESPACE_EXIT #endif // TRANSITIONBLOCK_H olive-continuous/app/node/edge.cpp000066400000000000000000000017231370472574300175340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "edge.h" OLIVE_NAMESPACE_ENTER NodeEdge::NodeEdge(NodeOutput *output, NodeInput *input) : output_(output), input_(input) { } NodeOutput *NodeEdge::output() { return output_; } NodeInput *NodeEdge::input() { return input_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/edge.h000066400000000000000000000030361370472574300172000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EDGE_H #define EDGE_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class NodeOutput; class NodeInput; /** * @brief A connection between two node parameters (a NodeOutput and a NodeInput) * * To simplify memory management, it's recommended to use NodeEdgePtr instead of raw pointers when working with * NodeEdge. */ class NodeEdge { public: /** * @brief Create a node edge connecting an output to an input */ NodeEdge(NodeOutput* output, NodeInput* input); /** * @brief Return the output parameter this edge is connected to */ NodeOutput* output(); /** * @brief Return the input parameter this edge is connected to */ NodeInput* input(); private: NodeOutput* output_; NodeInput* input_; }; using NodeEdgePtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // EDGE_H olive-continuous/app/node/factory.cpp000066400000000000000000000132111370472574300202720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "factory.h" #include "audio/pan/pan.h" #include "audio/volume/volume.h" #include "block/clip/clip.h" #include "block/gap/gap.h" #include "block/transition/crossdissolve/crossdissolvetransition.h" #include "block/transition/diptocolor/diptocolortransition.h" #include "generator/matrix/matrix.h" #include "generator/polygon/polygon.h" #include "generator/solid/solid.h" #include "generator/text/text.h" #include "filter/blur/blur.h" #include "filter/stroke/stroke.h" #include "input/media/video/video.h" #include "input/media/audio/audio.h" #include "input/time/timeinput.h" #include "math/math/math.h" #include "math/merge/merge.h" #include "math/trigonometry/trigonometry.h" #include "output/track/track.h" #include "output/viewer/viewer.h" OLIVE_NAMESPACE_ENTER QList NodeFactory::library_; void NodeFactory::Initialize() { Destroy(); // Add internal types for (int i=0;i(i))); } /* library_.append(new ExternalTransition(":/shaders/crossdissolve.xml")); library_.append(new ExternalTransition(":/shaders/diptoblack.xml")); */ } void NodeFactory::Destroy() { qDeleteAll(library_); library_.clear(); } Menu *NodeFactory::CreateMenu(QWidget* parent, bool create_none_item, Node::CategoryID restrict_to) { Menu* menu = new Menu(parent); menu->setToolTipsVisible(true); for (int i=0;iCategory().contains(restrict_to)) { // Skip this node continue; } // Make sure nodes are up-to-date with the current translation n->Retranslate(); Menu* destination = nullptr; QString category_name = Node::GetCategoryName(n->Category().isEmpty() ? Node::kCategoryUnknown : n->Category().first()); // See if a menu with this category name already exists QList menu_actions = menu->actions(); foreach (QAction* action, menu_actions) { if (action->menu() && action->menu()->title() == category_name) { destination = static_cast(action->menu()); break; } } // Create menu here if it doesn't exist if (!destination) { destination = new Menu(category_name, menu); menu->InsertAlphabetically(destination); } // Add entry to menu QAction* a = destination->InsertAlphabetically(n->Name()); a->setData(i); a->setToolTip(n->Description()); } if (create_none_item) { QAction* none_item = new QAction(QCoreApplication::translate("NodeFactory", "None"), menu); none_item->setData(-1); if (menu->actions().isEmpty()) { menu->addAction(none_item); } else { QAction* separator = menu->insertSeparator(menu->actions().first()); menu->insertAction(separator, none_item); } } return menu; } Node* NodeFactory::CreateFromMenuAction(QAction *action) { int index = action->data().toInt(); if (index == -1) { return nullptr; } return library_.at(index)->copy(); } QString NodeFactory::GetIDFromMenuAction(QAction *action) { int index = action->data().toInt(); if (index == -1) { return QString(); } return library_.at(action->data().toInt())->id(); } QString NodeFactory::GetNameFromID(const QString &id) { if (!id.isEmpty()) { foreach (Node* n, library_) { if (n->id() == id) { return n->Name(); } } } return QString(); } Node *NodeFactory::CreateFromID(const QString &id) { foreach (Node* n, library_) { if (n->id() == id) { return n->copy(); } } return nullptr; } Node *NodeFactory::CreateFromFactoryIndex(const NodeFactory::InternalID &id) { switch (id) { case kClipBlock: return new ClipBlock(); case kGapBlock: return new GapBlock(); case kPolygonGenerator: return new PolygonGenerator(); case kMatrixGenerator: return new MatrixGenerator(); case kVideoInput: return new VideoInput(); case kAudioInput: return new AudioInput(); case kTrackOutput: return new TrackOutput(); case kViewerOutput: return new ViewerOutput(); case kAudioVolume: return new VolumeNode(); case kAudioPanning: return new PanNode(); case kMath: return new MathNode(); case kTrigonometry: return new TrigonometryNode(); case kTime: return new TimeInput(); case kBlurFilter: return new BlurFilterNode(); case kSolidGenerator: return new SolidGenerator(); case kMerge: return new MergeNode(); case kStrokeFilter: return new StrokeFilterNode(); case kTextGenerator: return new TextGenerator(); case kCrossDissolveTransition: return new CrossDissolveTransition(); case kDipToColorTransition: return new DipToColorTransition(); case kInternalNodeCount: break; } // We should never get here abort(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/factory.h000066400000000000000000000035471370472574300177520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEFACTORY_H #define NODEFACTORY_H #include #include "node.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER class NodeFactory { public: enum InternalID { kViewerOutput, kClipBlock, kGapBlock, kAudioInput, kPolygonGenerator, kMatrixGenerator, kVideoInput, kTrackOutput, kAudioVolume, kAudioPanning, kMath, kTime, kTrigonometry, kBlurFilter, kSolidGenerator, kMerge, kStrokeFilter, kTextGenerator, kCrossDissolveTransition, kDipToColorTransition, // Count value kInternalNodeCount }; NodeFactory() = default; static void Initialize(); static void Destroy(); static Menu* CreateMenu(QWidget *parent, bool create_none_item = false, Node::CategoryID restrict_to = Node::kCategoryUnknown); static Node* CreateFromMenuAction(QAction* action); static QString GetIDFromMenuAction(QAction* action); static QString GetNameFromID(const QString& id); static Node* CreateFromID(const QString& id); static Node* CreateFromFactoryIndex(const InternalID& id); private: static QList library_; }; OLIVE_NAMESPACE_EXIT #endif // NODEFACTORY_H olive-continuous/app/node/filter/000077500000000000000000000000001370472574300174065ustar00rootroot00000000000000olive-continuous/app/node/filter/CMakeLists.txt000066400000000000000000000014461370472574300221530ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(blur) add_subdirectory(stroke) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/node/filter/blur/000077500000000000000000000000001370472574300203525ustar00rootroot00000000000000olive-continuous/app/node/filter/blur/CMakeLists.txt000066400000000000000000000014531370472574300231150ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/filter/blur/blur.h node/filter/blur/blur.cpp PARENT_SCOPE ) olive-continuous/app/node/filter/blur/blur.cpp000066400000000000000000000074251370472574300220320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "blur.h" OLIVE_NAMESPACE_ENTER BlurFilterNode::BlurFilterNode() { texture_input_ = new NodeInput("tex_in", NodeParam::kTexture); AddInput(texture_input_); method_input_ = new NodeInput("method_in", NodeParam::kCombo, 0); AddInput(method_input_); radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); radius_input_->set_property(QStringLiteral("min"), 0.0f); AddInput(radius_input_); horiz_input_ = new NodeInput("horiz_in", NodeParam::kBoolean, true); AddInput(horiz_input_); vert_input_ = new NodeInput("vert_in", NodeParam::kBoolean, true); AddInput(vert_input_); repeat_edge_pixels_input_ = new NodeInput("repeat_edge_pixels_in", NodeParam::kBoolean, false); AddInput(repeat_edge_pixels_input_); } Node *BlurFilterNode::copy() const { return new BlurFilterNode(); } QString BlurFilterNode::Name() const { return tr("Blur"); } QString BlurFilterNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.blur"); } QList BlurFilterNode::Category() const { return {kCategoryFilter}; } QString BlurFilterNode::Description() const { return tr("Blurs an image."); } void BlurFilterNode::Retranslate() { texture_input_->set_name(tr("Input")); method_input_->set_name(tr("Method")); method_input_->set_combobox_strings({ tr("Box"), tr("Gaussian") }); radius_input_->set_name(tr("Radius")); horiz_input_->set_name(tr("Horizontal")); vert_input_->set_name(tr("Vertical")); repeat_edge_pixels_input_->set_name(tr("Repeat Edge Pixels")); } ShaderCode BlurFilterNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(ReadFileAsString(":/shaders/blur.frag"), QString()); } NodeValueTable BlurFilterNode::Value(NodeValueDatabase &value) const { ShaderJob job; job.InsertValue(texture_input_, value); job.InsertValue(method_input_, value); job.InsertValue(radius_input_, value); job.InsertValue(horiz_input_, value); job.InsertValue(vert_input_, value); job.InsertValue(repeat_edge_pixels_input_, value); NodeValueTable table = value.Merge(); // If there's no texture, no need to run an operation if (!job.GetValue(texture_input_).data().isNull()) { // Check if radius > 0, and both "horiz" and/or "vert" are enabled if ((job.GetValue(horiz_input_).data().toBool() || job.GetValue(vert_input_).data().toBool()) && job.GetValue(radius_input_).data().toDouble() > 0.0) { // Set iteration count to 2 if we're blurring both horizontally and vertically if (job.GetValue(horiz_input_).data().toBool() && job.GetValue(vert_input_).data().toBool()) { job.SetIterations(2, texture_input_); } // If we're not repeating pixels, expect an alpha channel to appear if (!job.GetValue(repeat_edge_pixels_input_).data().toBool()) { job.SetAlphaChannelRequired(true); } table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); } else { // If we're not performing the blur job, just push the texture table.Push(job.GetValue(texture_input_)); } } return table; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/filter/blur/blur.h000066400000000000000000000030011370472574300214610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef BLURFILTERNODE_H #define BLURFILTERNODE_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class BlurFilterNode : public Node { public: BlurFilterNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; private: NodeInput* texture_input_; NodeInput* method_input_; NodeInput* radius_input_; NodeInput* horiz_input_; NodeInput* vert_input_; NodeInput* repeat_edge_pixels_input_; }; OLIVE_NAMESPACE_EXIT #endif // BLURFILTERNODE_H olive-continuous/app/node/filter/stroke/000077500000000000000000000000001370472574300207155ustar00rootroot00000000000000olive-continuous/app/node/filter/stroke/CMakeLists.txt000066400000000000000000000014631370472574300234610ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/filter/stroke/stroke.h node/filter/stroke/stroke.cpp PARENT_SCOPE ) olive-continuous/app/node/filter/stroke/stroke.cpp000066400000000000000000000061271370472574300227360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "stroke.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER StrokeFilterNode::StrokeFilterNode() { tex_input_ = new NodeInput("tex_in", NodeParam::kTexture); AddInput(tex_input_); color_input_ = new NodeInput("color_in", NodeParam::kColor, QVariant::fromValue(Color(1.0f, 1.0f, 1.0f, 1.0f))); AddInput(color_input_); radius_input_ = new NodeInput("radius_in", NodeParam::kFloat, 10.0f); radius_input_->set_property("min", 0.0f); AddInput(radius_input_); opacity_input_ = new NodeInput("opacity_in", NodeParam::kFloat, 1.0f); opacity_input_->set_property("view", "percent"); opacity_input_->set_property("min", 0.0f); opacity_input_->set_property("max", 1.0f); AddInput(opacity_input_); inner_input_ = new NodeInput("inner_in", NodeParam::kBoolean, false); AddInput(inner_input_); } Node *StrokeFilterNode::copy() const { return new StrokeFilterNode(); } QString StrokeFilterNode::Name() const { return tr("Stroke"); } QString StrokeFilterNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.stroke"); } QList StrokeFilterNode::Category() const { return {kCategoryFilter}; } QString StrokeFilterNode::Description() const { return tr("Creates a stroke outline around an image."); } void StrokeFilterNode::Retranslate() { tex_input_->set_name(tr("Input")); color_input_->set_name(tr("Color")); radius_input_->set_name(tr("Radius")); opacity_input_->set_name(tr("Opacity")); inner_input_->set_name(tr("Inner")); } NodeValueTable StrokeFilterNode::Value(NodeValueDatabase &value) const { ShaderJob job; job.InsertValue(tex_input_, value); job.InsertValue(color_input_, value); job.InsertValue(radius_input_, value); job.InsertValue(opacity_input_, value); job.InsertValue(inner_input_, value); NodeValueTable table = value.Merge(); if (!job.GetValue(tex_input_).data().isNull()) { if (job.GetValue(radius_input_).data().toDouble() > 0.0 && job.GetValue(opacity_input_).data().toDouble() > 0.0) { table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); } else { table.Push(job.GetValue(tex_input_)); } } return table; } ShaderCode StrokeFilterNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(ReadFileAsString(":/shaders/stroke.frag"), QString()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/filter/stroke/stroke.h000066400000000000000000000027401370472574300224000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef STROKEFILTERNODE_H #define STROKEFILTERNODE_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class StrokeFilterNode : public Node { public: StrokeFilterNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; private: NodeInput* tex_input_; NodeInput* color_input_; NodeInput* radius_input_; NodeInput* opacity_input_; NodeInput* inner_input_; }; OLIVE_NAMESPACE_EXIT #endif // STROKEFILTERNODE_H olive-continuous/app/node/generator/000077500000000000000000000000001370472574300201075ustar00rootroot00000000000000olive-continuous/app/node/generator/CMakeLists.txt000066400000000000000000000015301370472574300226460ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(matrix) add_subdirectory(polygon) add_subdirectory(solid) add_subdirectory(text) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/node/generator/matrix/000077500000000000000000000000001370472574300214135ustar00rootroot00000000000000olive-continuous/app/node/generator/matrix/CMakeLists.txt000066400000000000000000000014711370472574300241560ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/generator/matrix/matrix.h node/generator/matrix/matrix.cpp PARENT_SCOPE ) olive-continuous/app/node/generator/matrix/matrix.cpp000066400000000000000000000213451370472574300234300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "matrix.h" #include #include #include #include "common/range.h" OLIVE_NAMESPACE_ENTER MatrixGenerator::MatrixGenerator() { position_input_ = new NodeInput("pos_in", NodeParam::kVec2, QVector2D()); AddInput(position_input_); rotation_input_ = new NodeInput("rot_in", NodeParam::kFloat, 0.0f); AddInput(rotation_input_); scale_input_ = new NodeInput("scale_in", NodeParam::kVec2, QVector2D(1.0f, 1.0f)); scale_input_->set_property("min", QVector2D(0, 0)); scale_input_->set_property("view", "percent"); scale_input_->set_property("disabley", true); AddInput(scale_input_); uniform_scale_input_ = new NodeInput("uniform_scale_in", NodeParam::kBoolean, true); uniform_scale_input_->set_is_keyframable(false); uniform_scale_input_->set_connectable(false); connect(uniform_scale_input_, &NodeInput::ValueChanged, this, &MatrixGenerator::UniformScaleChanged); AddInput(uniform_scale_input_); anchor_input_ = new NodeInput("anchor_in", NodeParam::kVec2, QVector2D()); AddInput(anchor_input_); } Node *MatrixGenerator::copy() const { return new MatrixGenerator(); } QString MatrixGenerator::Name() const { return tr("Orthographic Matrix"); } QString MatrixGenerator::ShortName() const { return tr("Ortho"); } QString MatrixGenerator::id() const { return QStringLiteral("org.olivevideoeditor.Olive.transform"); } QList MatrixGenerator::Category() const { return {kCategoryGenerator, kCategoryMath}; } QString MatrixGenerator::Description() const { return tr("Generate an orthographic matrix using position, rotation, and scale."); } void MatrixGenerator::Retranslate() { position_input_->set_name(tr("Position")); rotation_input_->set_name(tr("Rotation")); scale_input_->set_name(tr("Scale")); uniform_scale_input_->set_name(tr("Uniform Scale")); anchor_input_->set_name(tr("Anchor Point")); } NodeValueTable MatrixGenerator::Value(NodeValueDatabase &value) const { // Push matrix output QMatrix4x4 mat = GenerateMatrix(value); NodeValueTable output = value.Merge(); output.Push(NodeParam::kMatrix, mat, this); return output; } bool MatrixGenerator::GizmoPress(NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize &viewport) { GizmoSharedData gizmo_data(viewport, scale); QPointF anchor_pt = GetGizmoAnchorPoint(db, gizmo_data); int anchor_radius = GetGizmoAnchorPointRadius(); if (InRange(p.x(), anchor_pt.x(), anchor_radius * 2.0) && InRange(p.y(), anchor_pt.y(), anchor_radius * 2.0)) { gizmo_drag_ = anchor_input_; gizmo_start2_ = db[position_input_].Get(NodeParam::kVec2).value(); } else { gizmo_drag_ = position_input_; } gizmo_start_ = db[gizmo_drag_].Get(NodeParam::kVec2).value(); gizmo_mouse_start_ = p; return true; } void MatrixGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) { QVector2D movement = 2.0 * QVector2D(p - gizmo_mouse_start_) / scale; QVector2D new_pos = gizmo_start_ + movement; if (!gizmo_x_dragger_.IsStarted()) { gizmo_x_dragger_.Start(gizmo_drag_, time, 0); } if (!gizmo_y_dragger_.IsStarted()) { gizmo_y_dragger_.Start(gizmo_drag_, time, 1); } gizmo_x_dragger_.Drag(new_pos.x()); gizmo_y_dragger_.Drag(new_pos.y()); if (gizmo_drag_ == anchor_input_) { // If we're dragging the anchor, counter the position at the same time QVector2D new_pos2 = gizmo_start2_ + movement; if (!gizmo_x2_dragger_.IsStarted()) { gizmo_x2_dragger_.Start(position_input_, time, 0); } if (!gizmo_y2_dragger_.IsStarted()) { gizmo_y2_dragger_.Start(position_input_, time, 1); } gizmo_x2_dragger_.Drag(new_pos2.x()); gizmo_y2_dragger_.Drag(new_pos2.y()); } } void MatrixGenerator::GizmoRelease() { gizmo_x_dragger_.End(); gizmo_y_dragger_.End(); gizmo_x2_dragger_.End(); gizmo_y2_dragger_.End(); } bool MatrixGenerator::HasGizmos() const { return true; } void MatrixGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize& viewport) const { p->setPen(Qt::white); GizmoSharedData gizmo_data(viewport, scale); { // Fold values into a matrix QMatrix4x4 matrix; matrix.scale(gizmo_data.half_scale); matrix *= GenerateMatrix(db, false); matrix.scale(gizmo_data.inverted_half_scale); // Create rect and transform it QVector points = {QPointF(-100, -100), QPointF(100, -100), QPointF(100, 100), QPointF(-100, 100), QPointF(-100, -100)}; QPolygonF poly(points); poly = matrix.toTransform().map(poly); poly.translate(gizmo_data.half_viewport); // Draw square p->drawPolyline(poly); } { // Draw anchor point marker (with no anchor point translation) QPointF pt = GetGizmoAnchorPoint(db, gizmo_data); // Draw anchor point int anchor_pt_radius = GetGizmoAnchorPointRadius(); p->drawEllipse(pt, anchor_pt_radius, anchor_pt_radius); p->drawLines({QLineF(pt.x() - anchor_pt_radius, pt.y(), pt.x() + anchor_pt_radius, pt.y()), QLineF(pt.x(), pt.y() - anchor_pt_radius, pt.x(), pt.y() + anchor_pt_radius)}); } } QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value) const { return GenerateMatrix(value[position_input_].Take(NodeParam::kVec2).value(), value[rotation_input_].Take(NodeParam::kFloat).toFloat(), value[scale_input_].Take(NodeParam::kVec2).value(), value[uniform_scale_input_].Take(NodeParam::kBoolean).toBool(), value[anchor_input_].Take(NodeParam::kVec2).value()); } QMatrix4x4 MatrixGenerator::GenerateMatrix(NodeValueDatabase &value, bool ignore_anchor) const { QVector2D anchor; if (!ignore_anchor) { anchor = value[anchor_input_].Get(NodeParam::kVec2).value(); } return GenerateMatrix(value[position_input_].Get(NodeParam::kVec2).value(), value[rotation_input_].Get(NodeParam::kFloat).toFloat(), value[scale_input_].Get(NodeParam::kVec2).value(), value[uniform_scale_input_].Get(NodeParam::kBoolean).toBool(), anchor); } QMatrix4x4 MatrixGenerator::GenerateMatrix(const QVector2D& pos, const float& rot, const QVector2D& scale, bool uniform_scale, const QVector2D& anchor) { QMatrix4x4 mat; // Position mat.translate(pos); // Rotation mat.rotate(rot, 0, 0, 1); // Scale (convert to a QVector3D so that the identity matrix is preserved if all values are 1.0f) QVector3D full_scale; if (uniform_scale) { full_scale = QVector3D(scale.x(), scale.x(), 1.0f); } else { full_scale = QVector3D(scale, 1.0f); } mat.scale(full_scale); // Anchor Point mat.translate(-anchor); return mat; } QPointF MatrixGenerator::GetGizmoAnchorPoint(NodeValueDatabase &db, const GizmoSharedData& gizmo_data) const { QMatrix4x4 matrix; matrix.scale(gizmo_data.half_scale); matrix *= GenerateMatrix(db, true); matrix.scale(gizmo_data.inverted_half_scale); QPointF pt = matrix.toTransform().map(QPointF()); pt += gizmo_data.half_viewport; return pt; } int MatrixGenerator::GetGizmoAnchorPointRadius() { return QFontMetrics(qApp->font()).height() / 2; } void MatrixGenerator::UniformScaleChanged() { scale_input_->set_property("disabley", uniform_scale_input_->get_standard_value().toBool()); } MatrixGenerator::GizmoSharedData::GizmoSharedData(const QSize &viewport, const QVector2D &scale) { half_viewport = QPointF(viewport.width() / 2, viewport.height() / 2); half_scale = scale * 0.5; inverted_half_scale = QVector2D(1.0f / half_scale.x(), 1.0f / half_scale.y()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/generator/matrix/matrix.h000066400000000000000000000057421370472574300231000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MATRIXGENERATOR_H #define MATRIXGENERATOR_H #include #include "node/node.h" #include "node/inputdragger.h" OLIVE_NAMESPACE_ENTER class MatrixGenerator : public Node { Q_OBJECT public: MatrixGenerator(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString ShortName() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; virtual bool HasGizmos() const override; virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override; virtual bool GizmoPress(NodeValueDatabase& db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override; virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; virtual void GizmoRelease() override; private: struct GizmoSharedData { GizmoSharedData(const QSize& viewport, const QVector2D& scale); QPointF half_viewport; QVector2D half_scale; QVector2D inverted_half_scale; }; QMatrix4x4 GenerateMatrix(NodeValueDatabase& value) const; QMatrix4x4 GenerateMatrix(NodeValueDatabase &value, bool ignore_anchor) const; static QMatrix4x4 GenerateMatrix(const QVector2D &pos, const float &rot, const QVector2D &scale, bool uniform_scale, const QVector2D &anchor); QPointF GetGizmoAnchorPoint(NodeValueDatabase &db, const GizmoSharedData &gizmo_data) const; static int GetGizmoAnchorPointRadius(); NodeInput* gizmo_drag_; NodeInput* position_input_; NodeInput* rotation_input_; NodeInput* scale_input_; NodeInput* uniform_scale_input_; NodeInput* anchor_input_; QVector2D gizmo_start_; QVector2D gizmo_start2_; QPointF gizmo_mouse_start_; NodeInputDragger gizmo_x_dragger_; NodeInputDragger gizmo_y_dragger_; NodeInputDragger gizmo_x2_dragger_; NodeInputDragger gizmo_y2_dragger_; private slots: void UniformScaleChanged(); }; OLIVE_NAMESPACE_EXIT #endif // TRANSFORMDISTORT_H olive-continuous/app/node/generator/polygon/000077500000000000000000000000001370472574300215765ustar00rootroot00000000000000olive-continuous/app/node/generator/polygon/CMakeLists.txt000066400000000000000000000014751370472574300243450ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/generator/polygon/polygon.h node/generator/polygon/polygon.cpp PARENT_SCOPE ) olive-continuous/app/node/generator/polygon/polygon.cpp000066400000000000000000000122271370472574300237750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "polygon.h" #include #include OLIVE_NAMESPACE_ENTER PolygonGenerator::PolygonGenerator() { points_input_ = new NodeInputArray("points_in", NodeParam::kVec2); AddInput(points_input_); color_input_ = new NodeInput("color_in", NodeParam::kColor); AddInput(color_input_); // Default to "a color" that isn't color_input_->set_standard_value(1.0, 0); color_input_->set_standard_value(1.0, 1); color_input_->set_standard_value(1.0, 2); color_input_->set_standard_value(1.0, 3); // FIXME: Test code points_input_->SetSize(5); points_input_->At(0)->set_standard_value(960, 0); points_input_->At(0)->set_standard_value(240, 1); points_input_->At(1)->set_standard_value(640, 0); points_input_->At(1)->set_standard_value(480, 1); points_input_->At(2)->set_standard_value(760, 0); points_input_->At(2)->set_standard_value(800, 1); points_input_->At(3)->set_standard_value(1100, 0); points_input_->At(3)->set_standard_value(800, 1); points_input_->At(4)->set_standard_value(1280, 0); points_input_->At(4)->set_standard_value(480, 1); // End test } Node *PolygonGenerator::copy() const { return new PolygonGenerator(); } QString PolygonGenerator::Name() const { return tr("Polygon"); } QString PolygonGenerator::id() const { return QStringLiteral("org.olivevideoeditor.Olive.polygon"); } QList PolygonGenerator::Category() const { return {kCategoryGenerator}; } QString PolygonGenerator::Description() const { return tr("Generate a 2D polygon of any amount of points."); } void PolygonGenerator::Retranslate() { points_input_->set_name(tr("Points")); color_input_->set_name(tr("Color")); } ShaderCode PolygonGenerator::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(Node::ReadFileAsString(":/shaders/polygon.frag"), QString()); } NodeValueTable PolygonGenerator::Value(NodeValueDatabase &value) const { ShaderJob job; job.InsertValue(points_input_, value); job.InsertValue(color_input_, value); job.SetAlphaChannelRequired(true); NodeValueTable table = value.Merge(); table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); return table; } bool PolygonGenerator::HasGizmos() const { return true; } void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p, const QVector2D &scale, const QSize &viewport) const { Q_UNUSED(viewport) if (!points_input_->GetSize()) { return; } p->setPen(Qt::white); p->setBrush(Qt::white); QVector points = GetGizmoCoordinates(db, scale); QVector rects = GetGizmoRects(points); points.append(points.first()); p->drawPolyline(points.constData(), points.size()); p->drawRects(rects); } bool PolygonGenerator::GizmoPress(NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize& viewport) { Q_UNUSED(viewport) QVector points = GetGizmoCoordinates(db, scale); QVector rects = GetGizmoRects(points); for (int i=0;iAt(i); gizmo_drag_start_ = points.at(i); return true; } } return false; } void PolygonGenerator::GizmoMove(const QPointF &p, const QVector2D &scale, const rational& time) { QVector2D new_pos = QVector2D(p) / scale; if (!gizmo_x_dragger_.IsStarted()) { gizmo_x_dragger_.Start(gizmo_drag_, time, 0); } if (!gizmo_y_dragger_.IsStarted()) { gizmo_y_dragger_.Start(gizmo_drag_, time, 1); } gizmo_x_dragger_.Drag(new_pos.x()); gizmo_y_dragger_.Drag(new_pos.y()); } void PolygonGenerator::GizmoRelease() { gizmo_x_dragger_.End(); gizmo_y_dragger_.End(); } QVector PolygonGenerator::GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D& scale) const { QVector points(points_input_->GetSize()); for (int i=0;iGetSize();i++) { QVector2D v = db[points_input_->At(i)].Get(NodeParam::kVec2).value(); v *= scale; QPointF pt = v.toPointF(); points[i] = pt; } return points; } QVector PolygonGenerator::GetGizmoRects(const QVector &points) const { QVector rects(points.size()); int rect_sz = QFontMetrics(qApp->font()).height() / 8; for (int i=0;i. ***/ #ifndef POLYGONGENERATOR_H #define POLYGONGENERATOR_H #include "node/node.h" #include "node/inputdragger.h" OLIVE_NAMESPACE_ENTER class PolygonGenerator : public Node { public: PolygonGenerator(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual ShaderCode GetShaderCode(const QString& shader_id) const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual bool HasGizmos() const override; virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p, const QVector2D &scale, const QSize& viewport) const override; virtual bool GizmoPress(NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize& viewport) override; virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; virtual void GizmoRelease() override; private: QVector GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D &scale) const; QVector GetGizmoRects(const QVector& points) const; NodeInputArray* points_input_; NodeInput* color_input_; NodeInput* gizmo_drag_; QPointF gizmo_drag_start_; NodeInputDragger gizmo_x_dragger_; NodeInputDragger gizmo_y_dragger_; }; OLIVE_NAMESPACE_EXIT #endif // POLYGONGENERATOR_H olive-continuous/app/node/generator/solid/000077500000000000000000000000001370472574300212215ustar00rootroot00000000000000olive-continuous/app/node/generator/solid/CMakeLists.txt000066400000000000000000000014651370472574300237670ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/generator/solid/solid.h node/generator/solid/solid.cpp PARENT_SCOPE ) olive-continuous/app/node/generator/solid/solid.cpp000066400000000000000000000037471370472574300230520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "solid.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER SolidGenerator::SolidGenerator() { // Default to a color that isn't black color_input_ = new NodeInput("color_in", NodeInput::kColor, QVariant::fromValue(Color(1.0f, 0.0f, 0.0f, 1.0f))); AddInput(color_input_); } Node *SolidGenerator::copy() const { return new SolidGenerator(); } QString SolidGenerator::Name() const { return tr("Solid"); } QString SolidGenerator::id() const { return QStringLiteral("org.olivevideoeditor.Olive.solidgenerator"); } QList SolidGenerator::Category() const { return {kCategoryGenerator}; } QString SolidGenerator::Description() const { return tr("Generate a solid color."); } void SolidGenerator::Retranslate() { color_input_->set_name(tr("Color")); } NodeValueTable SolidGenerator::Value(NodeValueDatabase &value) const { ShaderJob job; job.InsertValue(color_input_, value); NodeValueTable table = value.Merge(); table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); return table; } ShaderCode SolidGenerator::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(ReadFileAsString(":/shaders/solid.frag"), QString()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/generator/solid/solid.h000066400000000000000000000025451370472574300225120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SOLIDGENERATOR_H #define SOLIDGENERATOR_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class SolidGenerator : public Node { public: SolidGenerator(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; private: NodeInput* color_input_; }; OLIVE_NAMESPACE_EXIT #endif // SOLIDGENERATOR_H olive-continuous/app/node/generator/text/000077500000000000000000000000001370472574300210735ustar00rootroot00000000000000olive-continuous/app/node/generator/text/CMakeLists.txt000066400000000000000000000014611370472574300236350ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/generator/text/text.h node/generator/text/text.cpp PARENT_SCOPE ) olive-continuous/app/node/generator/text/text.cpp000066400000000000000000000125731370472574300225730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "text.h" #include OLIVE_NAMESPACE_ENTER enum TextVerticalAlign { kVerticalAlignTop, kVerticalAlignCenter, kVerticalAlignBottom, }; TextGenerator::TextGenerator() { text_input_ = new NodeInput(QStringLiteral("text_in"), NodeParam::kText, tr("Sample Text")); AddInput(text_input_); color_input_ = new NodeInput(QStringLiteral("color_in"), NodeParam::kColor, QVariant::fromValue(Color(1.0f, 1.0f, 1.0))); AddInput(color_input_); valign_input_ = new NodeInput(QStringLiteral("valign_in"), NodeParam::kCombo, 1); AddInput(valign_input_); font_input_ = new NodeInput(QStringLiteral("font_in"), NodeParam::kFont); AddInput(font_input_); font_size_input_ = new NodeInput(QStringLiteral("font_size_in"), NodeParam::kFloat, 72.0f); AddInput(font_size_input_); } Node *TextGenerator::copy() const { return new TextGenerator(); } QString TextGenerator::Name() const { return tr("Text"); } QString TextGenerator::id() const { return QStringLiteral("org.olivevideoeditor.Olive.textgenerator"); } QList TextGenerator::Category() const { return {kCategoryGenerator}; } QString TextGenerator::Description() const { return tr("Generate rich text."); } void TextGenerator::Retranslate() { text_input_->set_name(tr("Text")); font_input_->set_name(tr("Font")); font_size_input_->set_name(tr("Font Size")); color_input_->set_name(tr("Color")); valign_input_->set_name(tr("Vertical Align")); valign_input_->set_combobox_strings({tr("Top"), tr("Center"), tr("Bottom")}); } NodeValueTable TextGenerator::Value(NodeValueDatabase &value) const { GenerateJob job; job.InsertValue(text_input_, value); job.InsertValue(color_input_, value); job.InsertValue(valign_input_, value); job.InsertValue(font_input_, value); job.InsertValue(font_size_input_, value); job.SetAlphaChannelRequired(true); NodeValueTable table = value.Merge(); if (!job.GetValue(text_input_).data().toString().isEmpty()) { table.Push(NodeParam::kGenerateJob, QVariant::fromValue(job), this); } return table; } void TextGenerator::GenerateFrame(FramePtr frame, const GenerateJob& job) const { // This could probably be more optimized, but for now we use Qt to draw to a QImage. // QImages only support integer pixels and we use float pixels, so what we do here is draw onto // a single-channel QImage (alpha only) and then transplant that alpha channel to our float buffer // with correct float RGB. QImage img(frame->width(), frame->height(), QImage::Format_Grayscale8); img.fill(0); QTextDocument text_doc; // Set default font QFont default_font; default_font.setFamily(job.GetValue(font_input_).data().toString()); default_font.setPointSizeF(job.GetValue(font_size_input_).data().toFloat()); text_doc.setDefaultFont(default_font); // Center by default text_doc.setDefaultTextOption(QTextOption(Qt::AlignCenter)); text_doc.setHtml(job.GetValue(text_input_).data().toString()); // Align to 80% width because that's considered the "title safe" area int tenth_of_width = frame->video_params().width() / 10; text_doc.setTextWidth(tenth_of_width * 8); // Draw rich text onto image QPainter p(&img); p.scale(1.0 / frame->video_params().divider(), 1.0 / frame->video_params().divider()); // Push 10% inwards to compensate for title safe area p.translate(tenth_of_width, 0); TextVerticalAlign valign = static_cast(job.GetValue(valign_input_).data().toInt()); int doc_height = text_doc.size().height(); switch (valign) { case kVerticalAlignTop: // Push 10% inwards for title safe area p.translate(0, frame->video_params().height() / 10); break; case kVerticalAlignCenter: // Center align p.translate(0, frame->video_params().height() / 2 - doc_height / 2); break; case kVerticalAlignBottom: // Push 10% inwards for title safe area p.translate(0, frame->video_params().height() - doc_height - frame->video_params().height() / 10); break; } text_doc.drawContents(&p); // Transplant alpha channel to frame Color rgb = job.GetValue(color_input_).data().value(); for (int x=0; xwidth(); x++) { for (int y=0; yheight(); y++) { uchar src_alpha = img.bits()[img.bytesPerLine() * y + x]; float alpha = float(src_alpha) / 255.0f; frame->set_pixel(x, y, Color(rgb.red() * alpha, rgb.green() * alpha, rgb.blue() * alpha, alpha)); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/generator/text/text.h000066400000000000000000000027341370472574300222360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TEXTGENERATOR_H #define TEXTGENERATOR_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class TextGenerator : public Node { public: TextGenerator(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const override; private: NodeInput* text_input_; NodeInput* color_input_; NodeInput* valign_input_; NodeInput* font_input_; NodeInput* font_size_input_; }; OLIVE_NAMESPACE_EXIT #endif // TEXTGENERATOR_H olive-continuous/app/node/graph.cpp000066400000000000000000000034671370472574300177400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "graph.h" OLIVE_NAMESPACE_ENTER void NodeGraph::Clear() { foreach (Node* node, node_children_) { delete node; } node_children_.clear(); } void NodeGraph::AddNode(Node *node) { if (ContainsNode(node)) { return; } node->setParent(this); connect(node, &Node::EdgeAdded, this, &NodeGraph::EdgeAdded); connect(node, &Node::EdgeRemoved, this, &NodeGraph::EdgeRemoved); node_children_.append(node); emit NodeAdded(node); } void NodeGraph::TakeNode(Node *node, QObject* new_parent) { if (!ContainsNode(node)) { return; } if (!node->CanBeDeleted()) { qWarning() << "Tried to delete a Node that's been flagged as not deletable"; return; } node->DisconnectAll(); disconnect(node, &Node::EdgeAdded, this, &NodeGraph::EdgeAdded); disconnect(node, &Node::EdgeRemoved, this, &NodeGraph::EdgeRemoved); node->setParent(new_parent); node_children_.removeAll(node); emit NodeRemoved(node); } const QList &NodeGraph::nodes() const { return node_children_; } bool NodeGraph::ContainsNode(Node *n) const { return (n->parent() == this); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/graph.h000066400000000000000000000045571370472574300174060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEGRAPH_H #define NODEGRAPH_H #include #include "node/node.h" OLIVE_NAMESPACE_ENTER /** * @brief A collection of nodes */ class NodeGraph : public QObject { Q_OBJECT public: /** * @brief NodeGraph Constructor */ NodeGraph() = default; /** * @brief Destructively destroys all nodes in the graph */ void Clear(); /** * @brief Add a node to this graph * * The node will get added to this graph. It is not automatically connected to anything, any connections will need to * be made manually after the node is added. The graph takes ownership of the Node. */ void AddNode(Node* node); /** * @brief Removes a Node from the graph BUT doesn't destroy it. Ownership is passed to `new_parent`. */ void TakeNode(Node* node, QObject* new_parent = nullptr); /** * @brief Retrieve a complete list of the nodes belonging to this graph */ const QList& nodes() const; /** * @brief Returns whether a certain Node is in the graph or not */ bool ContainsNode(Node* n) const; signals: /** * @brief Signal emitted when a Node is added to the graph */ void NodeAdded(Node* node); /** * @brief Signal emitted when a Node is removed from the graph */ void NodeRemoved(Node* node); /** * @brief Signal emitted when a member node of this graph has been connected to another (creating an "edge") */ void EdgeAdded(NodeEdgePtr edge); /** * @brief Signal emitted when a member node of this graph has been disconnected from another (removing an "edge") */ void EdgeRemoved(NodeEdgePtr edge); private: QList node_children_; }; OLIVE_NAMESPACE_EXIT #endif // NODEGRAPH_H olive-continuous/app/node/input.cpp000066400000000000000000000761451370472574300200010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "input.h" #include #include #include #include #include "common/bezier.h" #include "common/lerp.h" #include "common/tohex.h" #include "common/xmlutils.h" #include "node.h" #include "output.h" #include "inputarray.h" #include "project/item/footage/stream.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER NodeInput::NodeInput(const QString& id, const DataType &type, const QVector &default_value) : NodeParam(id) { Init(type); if (!default_value.isEmpty()) { SetDefaultValue(default_value); } } NodeInput::NodeInput(const QString &id, const NodeParam::DataType &type, const QVariant &default_value) : NodeParam(id) { Init(type); SetDefaultValue(split_normal_value_into_track_values(default_value)); } NodeInput::NodeInput(const QString &id, const NodeParam::DataType &type) : NodeParam(id) { Init(type); } bool NodeInput::IsArray() const { return false; } NodeParam::Type NodeInput::type() { return kInput; } QString NodeInput::name() { if (name_.isEmpty()) { return tr("Input"); } return NodeParam::name(); } void NodeInput::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) { { XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { return; } if (attr.name() == QStringLiteral("keyframing")) { set_is_keyframing(attr.value() == QStringLiteral("1")); } } } while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("standard")) { // Load standard value int val_index = 0; while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("value")) { QString value_text = reader->readElementText(); if (value_text.isEmpty()) { standard_value_.replace(val_index, QVariant()); } else { standard_value_.replace(val_index, StringToValue(value_text, xml_node_data.footage_connections)); } val_index++; } else { reader->skipCurrentElement(); } } } else if (reader->name() == QStringLiteral("keyframes")) { int track = 0; while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("track")) { while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("key")) { rational key_time; NodeKeyframe::Type key_type; QVariant key_value; QPointF key_in_handle; QPointF key_out_handle; XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { return; } if (attr.name() == QStringLiteral("time")) { key_time = rational::fromString(attr.value().toString()); } else if (attr.name() == QStringLiteral("type")) { key_type = static_cast(attr.value().toInt()); } else if (attr.name() == QStringLiteral("inhandlex")) { key_in_handle.setX(attr.value().toDouble()); } else if (attr.name() == QStringLiteral("inhandley")) { key_in_handle.setY(attr.value().toDouble()); } else if (attr.name() == QStringLiteral("outhandlex")) { key_out_handle.setX(attr.value().toDouble()); } else if (attr.name() == QStringLiteral("outhandley")) { key_out_handle.setY(attr.value().toDouble()); } } key_value = StringToValue(reader->readElementText(), xml_node_data.footage_connections); NodeKeyframePtr key = NodeKeyframe::Create(key_time, key_value, key_type, track); key->set_bezier_control_in(key_in_handle); key->set_bezier_control_out(key_out_handle); key->set_parent(this); keyframe_tracks_[track].append(key); } else { reader->skipCurrentElement(); } } track++; } else { reader->skipCurrentElement(); } } } else if (reader->name() == QStringLiteral("connections")) { while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("connection")) { xml_node_data.desired_connections.append({this, reader->readElementText().toULongLong()}); } else { reader->skipCurrentElement(); } } } else if (reader->name() == QStringLiteral("csinput")) { set_property(QStringLiteral("col_input"), reader->readElementText()); } else if (reader->name() == QStringLiteral("csdisplay")) { set_property(QStringLiteral("col_display"), reader->readElementText()); } else if (reader->name() == QStringLiteral("csview")) { set_property(QStringLiteral("col_view"), reader->readElementText()); } else if (reader->name() == QStringLiteral("cslook")) { set_property(QStringLiteral("col_look"), reader->readElementText()); } else { LoadInternal(reader, xml_node_data, cancelled); } } } void NodeInput::Save(QXmlStreamWriter *writer) const { writer->writeStartElement("input"); writer->writeAttribute("id", id()); writer->writeAttribute("keyframing", QString::number(keyframing_)); // Write standard value writer->writeStartElement("standard"); foreach (const QVariant& v, standard_value_) { writer->writeTextElement("value", ValueToString(v)); } writer->writeEndElement(); // standard // Write keyframes writer->writeStartElement("keyframes"); foreach (const KeyframeTrack& track, keyframe_tracks()) { writer->writeStartElement("track"); foreach (NodeKeyframePtr key, track) { writer->writeStartElement("key"); writer->writeAttribute("time", key->time().toString()); writer->writeAttribute("type", QString::number(key->type())); writer->writeAttribute("inhandlex", QString::number(key->bezier_control_in().x())); writer->writeAttribute("inhandley", QString::number(key->bezier_control_in().y())); writer->writeAttribute("outhandlex", QString::number(key->bezier_control_out().x())); writer->writeAttribute("outhandley", QString::number(key->bezier_control_out().y())); writer->writeCharacters(ValueToString(key->value())); writer->writeEndElement(); // key } writer->writeEndElement(); // track } writer->writeEndElement(); // keyframes if (data_type_ == NodeParam::kColor) { // Save color management information writer->writeTextElement(QStringLiteral("csinput"), get_property(QStringLiteral("col_input")).toString()); writer->writeTextElement(QStringLiteral("csdisplay"), get_property(QStringLiteral("col_display")).toString()); writer->writeTextElement(QStringLiteral("csview"), get_property(QStringLiteral("col_view")).toString()); writer->writeTextElement(QStringLiteral("cslook"), get_property(QStringLiteral("col_look")).toString()); } SaveConnections(writer); SaveInternal(writer); writer->writeEndElement(); // input } void NodeInput::SaveConnections(QXmlStreamWriter *writer) const { writer->writeStartElement("connections"); foreach (NodeEdgePtr edge, edges_) { writer->writeTextElement("connection", QString::number(reinterpret_cast(edge->output()))); } writer->writeEndElement(); // connections } const NodeParam::DataType &NodeInput::data_type() const { return data_type_; } void NodeInput::LoadInternal(QXmlStreamReader* reader, XMLNodeData &, const QAtomicInt*) { reader->skipCurrentElement(); } void NodeInput::SaveInternal(QXmlStreamWriter*) const { } void NodeInput::Init(DataType type) { keyframable_ = true; keyframing_ = false; data_type_ = type; int track_size; switch (data_type_) { case kVec2: track_size = 2; break; case kVec3: track_size = 3; break; case kVec4: case kColor: track_size = 4; break; default: track_size = 1; } keyframe_tracks_.resize(track_size); standard_value_.resize(track_size); } void NodeInput::SetDefaultValue(const QVector &default_value) { default_value_ = default_value; for (int i=0;i().toString(); case kFootage: return QString::number(reinterpret_cast(value.value().get())); default: if (value.canConvert()) { return value.toString(); } if (!value.isNull()) { qWarning() << "Failed to convert type" << ToHex(data_type) << "to string"; } /* fall through */ // These data types need no XML representation case kTexture: case kSamples: case kBuffer: return QString(); } } QVariant NodeInput::StringToValue(const DataType& data_type, const QString &string) { switch (data_type) { case kRational: return QVariant::fromValue(rational::fromString(string)); default: return string; } } void NodeInput::GetDependencies(QList &list, bool traverse, bool exclusive_only) const { if (is_connected() && (get_connected_output()->edges().size() == 1 || !exclusive_only)) { Node* connected = get_connected_node(); if (!list.contains(connected)) { list.append(connected); if (traverse) { QList connected_inputs = connected->GetInputsIncludingArrays(); foreach (NodeInput* i, connected_inputs) { i->GetDependencies(list, traverse, exclusive_only); } } } } } QVariant NodeInput::GetDefaultValue() const { if (default_value_.isEmpty()) { return QVariant(); } return combine_track_values_into_normal_value(default_value_); } QVariant NodeInput::GetDefaultValueForTrack(int track) const { if (default_value_.isEmpty()) { return QVariant(); } return default_value_.at(track); } QList NodeInput::GetDependencies(bool traverse, bool exclusive_only) const { QList list; GetDependencies(list, traverse, exclusive_only); return list; } QList NodeInput::GetExclusiveDependencies() const { return GetDependencies(true, true); } QList NodeInput::GetImmediateDependencies() const { return GetDependencies(false, false); } QVariant NodeInput::StringToValue(const QString &string, QList& footage_connections) { if (data_type_ == NodeParam::kFootage) { footage_connections.append({this, string.toULongLong()}); } return StringToValue(data_type_, string); } NodeOutput *NodeInput::get_connected_output() const { if (!edges_.isEmpty()) { return edges_.first()->output(); } return nullptr; } Node *NodeInput::get_connected_node() const { NodeOutput* output = get_connected_output(); if (output) { return output->parentNode(); } return nullptr; } bool NodeInput::type_can_be_interpolated(NodeParam::DataType type) { return type == kFloat || type == kVec2 || type == kVec3 || type == kVec4 || type == kColor; } QVariant NodeInput::get_value_at_time(const rational &time) const { return combine_track_values_into_normal_value(get_split_values_at_time(time)); } QVector NodeInput::get_split_values_at_time(const rational &time) const { QVector vals; for (int i=0;itime() >= time) { // This time precedes any keyframe, so we just return the first value return key_track.first()->value(); } if (key_track.last()->time() <= time) { // This time is after any keyframes so we return the last value return key_track.last()->value(); } // If we're here, the time must be somewhere in between the keyframes for (int i=0;itime() == time || !type_can_be_interpolated(data_type()) || (before->time() < time && before->type() == NodeKeyframe::kHold)) { // Time == keyframe time, so value is precise return before->value(); } else if (after->time() == time) { // Time == keyframe time, so value is precise return after->value(); } else if (before->time() < time && after->time() > time) { // We must interpolate between these keyframes if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) { // Perform a cubic bezier with two control points double t = Bezier::CubicXtoT(time.toDouble(), before->time().toDouble(), before->time().toDouble() + before->bezier_control_out().x(), after->time().toDouble() + after->bezier_control_in().x(), after->time().toDouble()); double y = Bezier::CubicTtoY(before->value().toDouble(), before->value().toDouble() + before->bezier_control_out().y(), after->value().toDouble() + after->bezier_control_in().y(), after->value().toDouble(), t); return y; } else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) { // Perform a quadratic bezier with only one control point QPointF control_point; double control_point_time; double control_point_value; if (before->type() == NodeKeyframe::kBezier) { control_point = before->bezier_control_out(); control_point_time = before->time().toDouble() + control_point.x(); control_point_value = before->value().toDouble() + control_point.y(); } else { control_point = after->bezier_control_in(); control_point_time = after->time().toDouble() + control_point.x(); control_point_value = after->value().toDouble() + control_point.y(); } // Generate T from time values - used to determine bezier progress double t = Bezier::QuadraticXtoT(time.toDouble(), before->time().toDouble(), control_point_time, after->time().toDouble()); // Generate value using T double y = Bezier::QuadraticTtoY(before->value().toDouble(), control_point_value, after->value().toDouble(), t); return y; } else { // To have arrived here, the keyframes must both be linear qreal period_progress = (time.toDouble() - before->time().toDouble()) / (after->time().toDouble() - before->time().toDouble()); return lerp(before->value().toDouble(), after->value().toDouble(), period_progress); } } } } return standard_value_.at(track); } QList NodeInput::get_keyframe_at_time(const rational &time) const { QList keys; for (int i=0;itime() == time) { return key; } } } return nullptr; } NodeKeyframePtr NodeInput::get_closest_keyframe_to_time_on_track(const rational &time, int track) const { if (is_using_standard_value(track)) { return nullptr; } const KeyframeTrack& key_track = keyframe_tracks_.at(track); if (time <= key_track.first()->time()) { return key_track.first(); } if (time >= key_track.last()->time()) { return key_track.last(); } for (int i=1;itime() <= time && next_key->time() >= time) { // Return whichever is closer rational prev_diff = time - prev_key->time(); rational next_diff = next_key->time() - time; if (next_diff < prev_diff) { return next_key; } else { return prev_key; } } } return nullptr; } NodeKeyframePtr NodeInput::get_closest_keyframe_before_time(const rational &time) const { NodeKeyframePtr key = nullptr; foreach (const KeyframeTrack& track, keyframe_tracks_) { foreach (NodeKeyframePtr k, track) { if (k->time() >= time) { break; } else if (!key || k->time() > key->time()) { key = k; } } } return key; } NodeKeyframePtr NodeInput::get_closest_keyframe_after_time(const rational &time) const { NodeKeyframePtr key = nullptr; foreach (const KeyframeTrack& track, keyframe_tracks_) { for (int i=track.size()-1;i>=0;i--) { NodeKeyframePtr k = track.at(i); if (k->time() <= time) { break; } else if (!key || k->time() < key->time()) { key = k; } } } return key; } NodeKeyframe::Type NodeInput::get_best_keyframe_type_for_time(const rational &time, int track) const { NodeKeyframePtr closest_key = get_closest_keyframe_to_time_on_track(time, track); if (closest_key) { return closest_key->type(); } return NodeKeyframe::kDefaultType; } int NodeInput::get_number_of_keyframe_tracks() const { return keyframe_tracks_.size(); } NodeKeyframePtr NodeInput::get_earliest_keyframe() const { NodeKeyframePtr earliest = nullptr; foreach (const KeyframeTrack& track, keyframe_tracks_) { if (!track.isEmpty()) { NodeKeyframePtr earliest_in_track = track.first(); if (!earliest || earliest_in_track->time() < earliest->time()) { earliest = earliest_in_track; } } } return earliest; } NodeKeyframePtr NodeInput::get_latest_keyframe() const { NodeKeyframePtr latest = nullptr; foreach (const KeyframeTrack& track, keyframe_tracks_) { if (!track.isEmpty()) { NodeKeyframePtr latest_in_track = track.last(); if (!latest || latest_in_track->time() > latest->time()) { latest = latest_in_track; } } } return latest; } void NodeInput::insert_keyframe(NodeKeyframePtr key) { Q_ASSERT(is_keyframable()); insert_keyframe_internal(key); connect(key.get(), &NodeKeyframe::TimeChanged, this, &NodeInput::KeyframeTimeChanged); connect(key.get(), &NodeKeyframe::ValueChanged, this, &NodeInput::KeyframeValueChanged); connect(key.get(), &NodeKeyframe::TypeChanged, this, &NodeInput::KeyframeTypeChanged); connect(key.get(), &NodeKeyframe::BezierControlInChanged, this, &NodeInput::KeyframeBezierInChanged); connect(key.get(), &NodeKeyframe::BezierControlOutChanged, this, &NodeInput::KeyframeBezierOutChanged); emit KeyframeAdded(key); emit_range_affected_by_keyframe(key.get()); } void NodeInput::remove_keyframe(NodeKeyframePtr key) { Q_ASSERT(is_keyframable()); TimeRange time_affected = get_range_affected_by_keyframe(key.get()); disconnect(key.get(), &NodeKeyframe::TimeChanged, this, &NodeInput::KeyframeTimeChanged); disconnect(key.get(), &NodeKeyframe::ValueChanged, this, &NodeInput::KeyframeValueChanged); disconnect(key.get(), &NodeKeyframe::TypeChanged, this, &NodeInput::KeyframeTypeChanged); disconnect(key.get(), &NodeKeyframe::BezierControlInChanged, this, &NodeInput::KeyframeBezierInChanged); disconnect(key.get(), &NodeKeyframe::BezierControlOutChanged, this, &NodeInput::KeyframeBezierOutChanged); keyframe_tracks_[key->track()].removeOne(key); key->set_parent(nullptr); emit KeyframeRemoved(key); emit_time_range(time_affected); } NodeKeyframePtr NodeInput::get_keyframe_shared_ptr_from_raw(NodeKeyframe* raw) const { foreach (const KeyframeTrack& track, keyframe_tracks_) { foreach (NodeKeyframePtr key, track) { if (key.get() == raw) { return key; } } } return nullptr; } void NodeInput::KeyframeTimeChanged() { NodeKeyframe* key = static_cast(sender()); int keyframe_index = FindIndexOfKeyframeFromRawPtr(key); Q_ASSERT(keyframe_index > -1); TimeRange original_range = get_range_around_index(keyframe_index, key->track()); if (!(original_range.in() < key->time() && original_range.out() > key->time())) { // This keyframe needs resorting, store it and remove it from the list NodeKeyframePtr key_shared_ptr = keyframe_tracks_.at(key->track()).at(keyframe_index); keyframe_tracks_[key->track()].removeAt(keyframe_index); // Automatically insertion sort insert_keyframe_internal(key_shared_ptr); // Invalidate new area that the keyframe has been moved to emit_time_range(get_range_around_index(FindIndexOfKeyframeFromRawPtr(key), key->track())); } // Invalidate entire area surrounding the keyframe (either where it currently is, or where it used to be before it // was resorted in the if block above) emit_time_range(original_range); } void NodeInput::KeyframeValueChanged() { emit_range_affected_by_keyframe(static_cast(sender())); } void NodeInput::KeyframeTypeChanged() { NodeKeyframe* key = static_cast(sender()); int keyframe_index = FindIndexOfKeyframeFromRawPtr(key); if (keyframe_tracks_.at(key->track()).size() == 1) { // If there are no other frames, the interpolation won't do anything return; } // Invalidate entire range emit_time_range(get_range_around_index(keyframe_index, key->track())); } void NodeInput::KeyframeBezierInChanged() { NodeKeyframe* key = static_cast(sender()); int keyframe_index = FindIndexOfKeyframeFromRawPtr(key); rational start = RATIONAL_MIN; rational end = key->time(); if (keyframe_index > 0) { start = keyframe_tracks_.at(key->track()).at(keyframe_index - 1)->time(); } emit ValueChanged(TimeRange(start, end)); } void NodeInput::KeyframeBezierOutChanged() { NodeKeyframe* key = static_cast(sender()); int keyframe_index = FindIndexOfKeyframeFromRawPtr(key); rational start = key->time(); rational end = RATIONAL_MAX; if (keyframe_index < keyframe_tracks_.at(key->track()).size() - 1) { end = keyframe_tracks_.at(key->track()).at(keyframe_index + 1)->time(); } emit ValueChanged(TimeRange(start, end)); } int NodeInput::FindIndexOfKeyframeFromRawPtr(NodeKeyframe *raw_ptr) const { const KeyframeTrack& track = keyframe_tracks_.at(raw_ptr->track()); for (int i=0;itrack()]; key->set_parent(this); for (int i=0;itime() != key->time()); if (compare->time() > key->time()) { key_track.insert(i, key); return; } } key_track.append(key); } bool NodeInput::is_using_standard_value(int track) const { return (!is_keyframing() || keyframe_tracks_.at(track).isEmpty()); } TimeRange NodeInput::get_range_affected_by_keyframe(NodeKeyframe *key) const { int keyframe_index = FindIndexOfKeyframeFromRawPtr(key); TimeRange range = get_range_around_index(keyframe_index, key->track()); const KeyframeTrack& key_track = keyframe_tracks_.at(key->track()); // If a previous key exists and it's a hold, we don't need to invalidate those frames if (key_track.size() > 1 && keyframe_index > 0 && key_track.at(keyframe_index - 1)->type() == NodeKeyframe::kHold) { range.set_in(key->time()); } return range; } TimeRange NodeInput::get_range_around_index(int index, int track) const { rational range_begin = RATIONAL_MIN; rational range_end = RATIONAL_MAX; const KeyframeTrack& key_track = keyframe_tracks_.at(track); if (key_track.size() > 1) { if (index > 0) { // If this is not the first key, we'll need to limit it to the key just before range_begin = key_track.at(index - 1)->time(); } if (index < key_track.size() - 1) { // If this is not the last key, we'll need to limit it to the key just after range_end = key_track.at(index + 1)->time(); } } return TimeRange(range_begin, range_end); } void NodeInput::emit_time_range(const TimeRange &range) { emit ValueChanged(range); } void NodeInput::emit_range_affected_by_keyframe(NodeKeyframe *key) { emit_time_range(get_range_affected_by_keyframe(key)); } bool NodeInput::has_keyframe_at_time(const rational &time) const { if (!is_keyframing()) { return false; } // Loop through keyframes to see if any match foreach (const KeyframeTrack& track, keyframe_tracks_) { foreach (NodeKeyframePtr key, track) { if (key->time() == time) { return true; } } } // None match return false; } bool NodeInput::is_keyframing() const { return keyframing_; } void NodeInput::set_is_keyframing(bool k) { keyframing_ = k; emit KeyframeEnableChanged(keyframing_); } bool NodeInput::is_keyframable() const { return keyframable_; } bool NodeInput::is_static() const { return !(this->is_connected() || this->is_keyframing()); } QVariant NodeInput::get_standard_value() const { return combine_track_values_into_normal_value(standard_value_); } const QVector &NodeInput::get_split_standard_value() const { return standard_value_; } void NodeInput::set_standard_value(const QVariant &value, int track) { standard_value_.replace(track, value); if (is_using_standard_value(track)) { // If this standard value is being used, we need to send a value changed signal emit ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX)); } } const QVector &NodeInput::keyframe_tracks() const { return keyframe_tracks_; } void NodeInput::set_is_keyframable(bool k) { keyframable_ = k; } void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_connections, bool traverse_arrays) { Q_ASSERT(source->id() == dest->id()); // Copy standard value dest->standard_value_ = source->standard_value_; // Copy keyframes for (int i=0;ikeyframe_tracks_.size();i++) { dest->keyframe_tracks_[i].clear(); foreach (NodeKeyframePtr key, source->keyframe_tracks_.at(i)) { dest->keyframe_tracks_[i].append(key->copy()); } } // Copy keyframing state dest->set_is_keyframing(source->is_keyframing()); // Copy connections if (include_connections && source->get_connected_output() != nullptr) { ConnectEdge(source->get_connected_output(), dest); } // If these inputs are an array, copy the subparams too if (dest->IsArray()) { NodeInputArray* src_array = static_cast(source); NodeInputArray* dst_array = static_cast(dest); dst_array->SetSize(src_array->GetSize()); if (traverse_arrays) { for (int i=0;iGetSize();i++) { CopyValues(src_array->At(i), dst_array->At(i), include_connections); } } } emit dest->ValueChanged(TimeRange(RATIONAL_MIN, RATIONAL_MAX)); } void NodeInput::set_property(const QString &key, const QVariant &value) { properties_.insert(key, value); emit PropertyChanged(key, value); } QVariant NodeInput::get_property(const QString &key) const { return properties_.value(key); } bool NodeInput::has_property(const QString &key) const { return properties_.contains(key); } const QHash &NodeInput::properties() const { return properties_; } QVector NodeInput::split_normal_value_into_track_values(const QVariant &value) const { QVector vals(get_number_of_keyframe_tracks()); switch (data_type_) { case kVec2: { QVector2D vec = value.value(); vals.replace(0, vec.x()); vals.replace(1, vec.y()); break; } case kVec3: { QVector3D vec = value.value(); vals.replace(0, vec.x()); vals.replace(1, vec.y()); vals.replace(2, vec.z()); break; } case kVec4: { QVector4D vec = value.value(); vals.replace(0, vec.x()); vals.replace(1, vec.y()); vals.replace(2, vec.z()); vals.replace(3, vec.w()); break; } case kColor: { Color c = value.value(); vals.replace(0, c.red()); vals.replace(1, c.green()); vals.replace(2, c.blue()); vals.replace(3, c.alpha()); break; } default: vals.replace(0, value); } return vals; } QVariant NodeInput::combine_track_values_into_normal_value(const QVector &split) const { switch (data_type_) { case kVec2: { return QVector2D(split.at(0).toFloat(), split.at(1).toFloat()); } case kVec3: { return QVector3D(split.at(0).toFloat(), split.at(1).toFloat(), split.at(2).toFloat()); } case kVec4: { return QVector4D(split.at(0).toFloat(), split.at(1).toFloat(), split.at(2).toFloat(), split.at(3).toFloat()); } case kColor: { return QVariant::fromValue(Color(split.at(0).toFloat(), split.at(1).toFloat(), split.at(2).toFloat(), split.at(3).toFloat())); } default: return split.first(); } } QStringList NodeInput::get_combobox_strings() const { return get_property(QStringLiteral("combo_str")).toStringList(); } void NodeInput::set_combobox_strings(const QStringList &strings) { set_property(QStringLiteral("combo_str"), strings); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/input.h000066400000000000000000000314771370472574300174450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEINPUT_H #define NODEINPUT_H #include "common/timerange.h" #include "keyframe.h" #include "param.h" OLIVE_NAMESPACE_ENTER /** * @brief A node parameter designed to take either user input or data from another node */ class NodeInput : public NodeParam { Q_OBJECT public: using KeyframeTrack = QList; /** * @brief NodeInput Constructor * * @param id * * Unique ID associated with this parameter for this Node. This ID only has to be unique within this Node. Used for * saving/loading data from this Node so that parameter order can be changed without issues loading data saved by an * older version. This of course assumes that parameters don't change their ID. */ NodeInput(const QString &id, const DataType& type, const QVector& default_value); NodeInput(const QString &id, const DataType& type, const QVariant& default_value); NodeInput(const QString &id, const DataType& type); virtual bool IsArray() const; /** * @brief Returns kInput */ virtual Type type() override; virtual QString name() override; virtual void Load(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; /** * @brief The data type this parameter outputs * * This can be used in conjunction with NodeInput::can_accept_type() to determine whether this parameter can be * connected to it. */ const DataType& data_type() const; /** * @brief If this input is connected to an output, retrieve the output parameter * * @return * * The output parameter if connected or nullptr if not */ NodeOutput* get_connected_output() const; /** * @brief If this input is connected to an output, retrieve the Node whose output is connected * * @return * * The connected Node if connected or nullptr if not */ Node* get_connected_node() const; /** * @brief Calculate what the stored value should be at a certain time * * If this is a multi-track data type (e.g. kVec2), this will automatically combine the result into a QVector2D. */ QVariant get_value_at_time(const rational& time) const; QVector get_split_values_at_time(const rational& time) const; /** * @brief Calculate the stored value for a specific track * * For most data types, there is only one track (e.g. `track == 0`), but multi-track data types like kVec2 will * produce the X value on track 0 and the Y value on track 1. */ QVariant get_value_at_time_for_track(const rational& time, int track) const; /** * @brief Retrieve a list of keyframe objects for all tracks at a given time * * List may be empty if this input is not keyframing or has no keyframes at this time. */ QList get_keyframe_at_time(const rational& time) const; /** * @brief Retrieve the keyframe object at a given time for a given track * * @return * * The keyframe object at this time or nullptr if there isn't one or if is_keyframing() is false. */ NodeKeyframePtr get_keyframe_at_time_on_track(const rational& time, int track) const; /** * @brief Gets the closest keyframe to a time * * If is_keyframing() is false or keyframes_ is empty, this will return nullptr. */ NodeKeyframePtr get_closest_keyframe_to_time_on_track(const rational& time, int track) const; /** * @brief Get closest keyframe that's before the time on any track * * If no keyframe is before this time, returns nullptr. */ NodeKeyframePtr get_closest_keyframe_before_time(const rational& time) const; /** * @brief Get closest keyframe that's before the time on any track * * If no keyframe is before this time, returns nullptr. */ NodeKeyframePtr get_closest_keyframe_after_time(const rational& time) const; /** * @brief A heuristic to determine what type a keyframe should be if it's inserted at a certain time (between keyframes) */ NodeKeyframe::Type get_best_keyframe_type_for_time(const rational& time, int track) const; /** * @brief Retrieve the number of */ int get_number_of_keyframe_tracks() const; /** * @brief Gets the earliest keyframe on any track */ NodeKeyframePtr get_earliest_keyframe() const; /** * @brief Gets the latest keyframe on any track */ NodeKeyframePtr get_latest_keyframe() const; /** * @brief Inserts a keyframe at the given time and returns a reference to it */ void insert_keyframe(NodeKeyframePtr key); /** * @brief Removes the keyframe */ void remove_keyframe(NodeKeyframePtr key); /** * @brief Hacky convenience function to turn a raw pointer into a shared pointer */ NodeKeyframePtr get_keyframe_shared_ptr_from_raw(NodeKeyframe *raw) const; /** * @brief Return whether a keyframe exists at this time * * If is_keyframing() is false, this will always return false. This checks all tracks and will return true if *any* * track has a keyframe. */ bool has_keyframe_at_time(const rational &time) const; /** * @brief Return whether keyframing is enabled on this input or not */ bool is_keyframing() const; /** * @brief Set whether keyframing is enabled on this input or not */ void set_is_keyframing(bool k); /** * @brief Return whether this input can be keyframed or not */ bool is_keyframable() const; /** * @brief Returns whether the value that this input returns is always the same or is expected to change * * Equivalent to `!(is_connected() || is_keyframing())` */ bool is_static() const; /** * @brief Get non-keyframed value */ QVariant get_standard_value() const; /** * @brief Get non-keyframed value split into components (the way it's stored) */ const QVector& get_split_standard_value() const; /** * @brief Set non-keyframed value */ void set_standard_value(const QVariant& value, int track = 0); /** * @brief Return list of keyframes in this parameter */ const QVector &keyframe_tracks() const; /** * @brief Set whether this input can be keyframed or not */ void set_is_keyframable(bool k); /** * @brief Copy all values including keyframe information and connections from another NodeInput */ static void CopyValues(NodeInput* source, NodeInput* dest, bool include_connections = true, bool traverse_arrays = true); /** * @brief Set an arbitrary property on this input to influence a UI representation's behavior * * NodeInputs also utilize QObject's property key/value system for arbitrary properties that can influence the UI * representation's behavior. * * Currently supported properties: * * - `min` - For any numeral type represented with a slider, prevents values going BELOW this number * - `max` - For any numeral type represented with a slider, prevents values going ABOVE this number * - `view` - For any numeral type represented with a slider, shows number either as `db`, `percent`, or `normal` * - `disablex` - For kVec2, kVec3, kVec4 and kColor types, disables the first/X/R UI widget * - `disabley` - For kVec2, kVec3, kVec4 and kColor types, disables the second/Y/G UI widget * - `disablez` - For kVec3, kVec4 and kColor types, disables the third/Z/B UI widget * - `disablew` - For kVec4 and kColor types, disables the fourth/W/A UI widget */ void set_property(const QString& key, const QVariant& value); /** * @brief Retrieve a property (or an empty QVariant if it hasn't been set) */ QVariant get_property(const QString& key) const; /** * @brief Return whether a certain property has been set or not */ bool has_property(const QString& key) const; /** * @brief Get properties hashmap (useful for iterating) */ const QHash& properties() const; QVector split_normal_value_into_track_values(const QVariant &value) const; QVariant combine_track_values_into_normal_value(const QVector& split) const; QStringList get_combobox_strings() const; void set_combobox_strings(const QStringList& strings); static QString ValueToString(const DataType& data_type, const QVariant& value); static QVariant StringToValue(const DataType &data_type, const QString &string); void GetDependencies(QList& list, bool traverse, bool exclusive_only) const; QVariant GetDefaultValue() const; QVariant GetDefaultValueForTrack(int track) const; QList GetDependencies(bool traverse = true, bool exclusive_only = false) const; QList GetExclusiveDependencies() const; QList GetImmediateDependencies() const; signals: void ValueChanged(const OLIVE_NAMESPACE::TimeRange& range); void KeyframeEnableChanged(bool); void KeyframeAdded(NodeKeyframePtr key); void KeyframeRemoved(NodeKeyframePtr key); void PropertyChanged(const QString& s, const QVariant& v); protected: virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled); virtual void SaveInternal(QXmlStreamWriter* writer) const; private: void Init(NodeParam::DataType type); void SetDefaultValue(const QVector &default_value); QString ValueToString(const QVariant& value) const; QVariant StringToValue(const QString &string, QList &footage_connections); void SaveConnections(QXmlStreamWriter* writer) const; /** * @brief Returns whether a data type can be interpolated or not */ static bool type_can_be_interpolated(DataType type); /** * @brief We use Qt signals/slots for keyframe communication but store them as shared ptrs. This function converts * a raw ptr to a list index */ int FindIndexOfKeyframeFromRawPtr(NodeKeyframe* raw_ptr) const; /** * @brief Internal insert function, automatically does an insertion sort based on the keyframe's time */ void insert_keyframe_internal(NodeKeyframePtr key); /** * @brief Return whether the standard value should be used over keyframe data */ bool is_using_standard_value(int track) const; /** * @brief Intelligently determine how what time range is affected by a keyframe */ TimeRange get_range_affected_by_keyframe(NodeKeyframe *key) const; /** * @brief Gets a time range between the previous and next keyframes of index */ TimeRange get_range_around_index(int index, int track) const; /** * @brief Convenience function - equivalent to calling `emit ValueChanged(range.in(), range.out())` */ void emit_time_range(const TimeRange& range); /** * @brief Convenience function - equivalent to calling `emit_time_range(get_range_affected_by_keyframe(key))` */ void emit_range_affected_by_keyframe(NodeKeyframe* key); /** * @brief Internal list of accepted data types * * Use can_accept_type() to check if a type is in this list */ DataType data_type_; /** * @brief Internal keyframable value */ bool keyframable_; /** * @brief Non-keyframed value */ QVector standard_value_; /** * @brief Default value that can be reset if the user requests */ QVector default_value_; /** * @brief Internal keyframe array * * If keyframing is enabled, this data is used instead of standard_value. */ QVector< QList > keyframe_tracks_; /** * @brief Internal keyframing enabled setting */ bool keyframing_; /** * @brief Internal properties variable */ QHash properties_; private slots: /** * @brief Slot when a keyframe's time changes to keep the keyframes correctly sorted by time */ void KeyframeTimeChanged(); /** * @brief Slot when a keyframe's value changes to signal that the cache needs updating */ void KeyframeValueChanged(); /** * @brief Slot when a keyframe's type changes to signal that the cache needs updating */ void KeyframeTypeChanged(); /** * @brief Slot when a keyframe's bezier in value changes to signal that the cache needs updating */ void KeyframeBezierInChanged(); /** * @brief Slot when a keyframe's bezier out value changes to signal that the cache needs updating */ void KeyframeBezierOutChanged(); }; OLIVE_NAMESPACE_EXIT #endif // NODEINPUT_H olive-continuous/app/node/input/000077500000000000000000000000001370472574300172605ustar00rootroot00000000000000olive-continuous/app/node/input/CMakeLists.txt000066400000000000000000000014451370472574300220240ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(media) add_subdirectory(time) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/node/input/media/000077500000000000000000000000001370472574300203375ustar00rootroot00000000000000olive-continuous/app/node/input/media/CMakeLists.txt000066400000000000000000000015361370472574300231040ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(audio) add_subdirectory(video) set(OLIVE_SOURCES ${OLIVE_SOURCES} node/input/media/media.h node/input/media/media.cpp PARENT_SCOPE ) olive-continuous/app/node/input/media/audio/000077500000000000000000000000001370472574300214405ustar00rootroot00000000000000olive-continuous/app/node/input/media/audio/CMakeLists.txt000066400000000000000000000014711370472574300242030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/input/media/audio/audio.h node/input/media/audio/audio.cpp PARENT_SCOPE ) olive-continuous/app/node/input/media/audio/audio.cpp000066400000000000000000000021141370472574300232430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audio.h" OLIVE_NAMESPACE_ENTER Node *AudioInput::copy() const { return new AudioInput(); } QString AudioInput::Name() const { return tr("Audio Input"); } QString AudioInput::id() const { return QStringLiteral("org.olivevideoeditor.Olive.audioinput"); } QString AudioInput::Description() const { return tr("Import an audio footage stream."); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/input/media/audio/audio.h000066400000000000000000000021051370472574300227100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOINPUT_H #define AUDIOINPUT_H #include "../media.h" OLIVE_NAMESPACE_ENTER class AudioInput : public MediaInput { public: AudioInput() = default; virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QString Description() const override; }; OLIVE_NAMESPACE_EXIT #endif // AUDIOINPUT_H olive-continuous/app/node/input/media/media.cpp000066400000000000000000000050771370472574300221330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "media.h" #include "common/timecodefunctions.h" #include "common/tohex.h" OLIVE_NAMESPACE_ENTER MediaInput::MediaInput() : connected_footage_(nullptr) { footage_input_ = new NodeInput("footage_in", NodeInput::kFootage); footage_input_->set_connectable(false); footage_input_->set_is_keyframable(false); connect(footage_input_, &NodeInput::ValueChanged, this, &MediaInput::FootageChanged); AddInput(footage_input_); } QList MediaInput::Category() const { return {kCategoryInput}; } StreamPtr MediaInput::footage() { return footage_input_->get_standard_value().value(); } void MediaInput::SetFootage(StreamPtr f) { footage_input_->set_standard_value(QVariant::fromValue(f)); } void MediaInput::Retranslate() { footage_input_->set_name(tr("Footage")); } NodeValueTable MediaInput::Value(NodeValueDatabase &value) const { NodeValueTable table = value.Merge(); if (connected_footage_) { rational media_duration = Timecode::timestamp_to_time(connected_footage_->duration(), connected_footage_->timebase()); table.Push(NodeInput::kRational, QVariant::fromValue(media_duration), this, "length"); } return table; } void MediaInput::FootageChanged() { StreamPtr new_footage = footage_input_->get_standard_value().value(); if (new_footage == connected_footage_) { return; } if (connected_footage_) { disconnect(connected_footage_.get(), &Stream::ParametersChanged, this, &MediaInput::FootageParametersChanged); } connected_footage_ = new_footage; if (connected_footage_) { connect(connected_footage_.get(), &Stream::ParametersChanged, this, &MediaInput::FootageParametersChanged); } } void MediaInput::FootageParametersChanged() { InvalidateCache(TimeRange(0, RATIONAL_MAX), footage_input_, footage_input_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/input/media/media.h000066400000000000000000000025331370472574300215720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MEDIAINPUT_H #define MEDIAINPUT_H #include "codec/decoder.h" #include "node/node.h" OLIVE_NAMESPACE_ENTER /** * @brief A node that imports an image */ class MediaInput : public Node { Q_OBJECT public: MediaInput(); virtual QList Category() const override; StreamPtr footage(); void SetFootage(StreamPtr f); virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; protected: NodeInput* footage_input_; StreamPtr connected_footage_; private slots: void FootageChanged(); void FootageParametersChanged(); }; OLIVE_NAMESPACE_EXIT #endif // MEDIAINPUT_H olive-continuous/app/node/input/media/video/000077500000000000000000000000001370472574300214455ustar00rootroot00000000000000olive-continuous/app/node/input/media/video/CMakeLists.txt000066400000000000000000000014711370472574300242100ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/input/media/video/video.h node/input/media/video/video.cpp PARENT_SCOPE ) olive-continuous/app/node/input/media/video/video.cpp000066400000000000000000000024401370472574300232570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "video.h" #include #include #include #include "codec/ffmpeg/ffmpegdecoder.h" #include "core.h" #include "project/item/footage/footage.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER Node *VideoInput::copy() const { return new VideoInput(); } QString VideoInput::Name() const { return tr("Video Input"); } QString VideoInput::id() const { return QStringLiteral("org.olivevideoeditor.Olive.videoinput"); } QString VideoInput::Description() const { return tr("Import a video footage stream."); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/input/media/video/video.h000066400000000000000000000022011370472574300227170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIDEOINPUT_H #define VIDEOINPUT_H #include #include "../media.h" #include "render/colormanager.h" OLIVE_NAMESPACE_ENTER class VideoInput : public MediaInput { public: VideoInput() = default; virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QString Description() const override; }; OLIVE_NAMESPACE_EXIT #endif // VIDEOINPUT_H olive-continuous/app/node/input/time/000077500000000000000000000000001370472574300202165ustar00rootroot00000000000000olive-continuous/app/node/input/time/CMakeLists.txt000066400000000000000000000014631370472574300227620ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/input/time/timeinput.h node/input/time/timeinput.cpp PARENT_SCOPE ) olive-continuous/app/node/input/time/timeinput.cpp000066400000000000000000000033271370472574300227450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timeinput.h" OLIVE_NAMESPACE_ENTER TimeInput::TimeInput() { } Node *TimeInput::copy() const { return new TimeInput(); } QString TimeInput::Name() const { return tr("Time"); } QString TimeInput::id() const { return QStringLiteral("org.olivevideoeditor.Olive.time"); } QList TimeInput::Category() const { return {kCategoryInput}; } QString TimeInput::Description() const { return tr("Generates the time (in seconds) at this frame"); } NodeValueTable TimeInput::Value(NodeValueDatabase &value) const { NodeValueTable table = value.Merge(); table.Push(NodeParam::kFloat, value[QStringLiteral("global")].Get(NodeParam::kFloat, QStringLiteral("time_in")), this, QStringLiteral("time")); return table; } void TimeInput::Hash(QCryptographicHash &hash, const rational &time) const { Node::Hash(hash, time); // Make sure time is hashed hash.addData(NodeParam::ValueToBytes(NodeParam::kRational, QVariant::fromValue(time))); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/input/time/timeinput.h000066400000000000000000000024241370472574300224070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMEINPUT_H #define TIMEINPUT_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class TimeInput : public Node { Q_OBJECT public: TimeInput(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual NodeValueTable Value(NodeValueDatabase& value) const override; virtual void Hash(QCryptographicHash& hash, const rational& time) const override; }; OLIVE_NAMESPACE_EXIT #endif // TIMEINPUT_H olive-continuous/app/node/inputarray.cpp000066400000000000000000000123021370472574300210210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "inputarray.h" #include #include "common/xmlutils.h" #include "node.h" OLIVE_NAMESPACE_ENTER NodeInputArray::NodeInputArray(const QString &id, const DataType &type, const QVariant &default_value) : NodeInput(id, type, default_value), default_value_(default_value) { } bool NodeInputArray::IsArray() const { return true; } int NodeInputArray::GetSize() const { return sub_params_.size(); } void NodeInputArray::Prepend() { InsertAt(0); } void NodeInputArray::SetSize(int size) { int old_size = GetSize(); if (size == old_size) { return; } if (size < old_size) { // If the new size is less, delete all extraneous parameters for (int i=size;i old_size) { // If the new size is greater, create valid parameters for each slot for (int i=old_size;iHasParamWithID(sub_id)); NodeInput* new_param = new NodeInput(sub_id, data_type(), default_value_); new_param->setParent(this); sub_params_.replace(i, new_param); connect(new_param, &NodeInput::ValueChanged, this, &NodeInput::ValueChanged); connect(new_param, &NodeInput::EdgeAdded, this, &NodeInputArray::SubParamEdgeAdded); connect(new_param, &NodeInput::EdgeRemoved, this, &NodeInputArray::SubParamEdgeRemoved); } } emit SizeChanged(size); } bool NodeInputArray::ContainsSubParameter(NodeInput *input) const { return sub_params_.contains(input); } int NodeInputArray::IndexOfSubParameter(NodeInput *input) const { return sub_params_.indexOf(input); } NodeInput *NodeInputArray::At(int index) const { return sub_params_.at(index); } NodeInput *NodeInputArray::First() const { return sub_params_.first(); } NodeInput *NodeInputArray::Last() const { return sub_params_.last(); } const QVector &NodeInputArray::sub_params() { return sub_params_; } void NodeInputArray::InsertAt(int index) { // Add another input at the end Append(); // Shift all connections from index down for (int i=sub_params_.size()-1;i>index;i--) { NodeInput* this_param = sub_params_.at(i); NodeInput* prev_param = sub_params_.at(i-1); if (this_param->is_connected()) { // Disconnect whatever is at this parameter (presumably its connection has already been copied so we can just remove it) NodeParam::DisconnectEdge(this_param->edges().first()); } if (prev_param->is_connected()) { // Get edge here (only one since it's an input) NodeEdgePtr edge = prev_param->edges().first(); // Disconnect it NodeParam::DisconnectEdge(edge); // Create a new edge between it and the next one down NodeParam::ConnectEdge(edge->output(), this_param); } } } void NodeInputArray::Append() { SetSize(GetSize() + 1); } void NodeInputArray::RemoveLast() { SetSize(GetSize() - 1); } void NodeInputArray::RemoveAt(int index) { // Shift all connections from index down for (int i=index;iis_connected()) { // Disconnect current edge NodeParam::DisconnectEdge(this_param->edges().first()); } if (i < sub_params_.size() - 1) { NodeInput* next_param = sub_params_.at(i + 1); if (next_param->is_connected()) { // Get edge from next param NodeEdgePtr edge = next_param->edges().first(); // Disconnect it NodeParam::DisconnectEdge(edge); // Reconnect it to this param NodeParam::ConnectEdge(edge->output(), this_param); } } } RemoveLast(); } void NodeInputArray::LoadInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const QAtomicInt* cancelled) { if (reader->name() == QStringLiteral("subparameters")) { while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("input")) { Append(); At(GetSize() - 1)->Load(reader, xml_node_data, cancelled); } else { reader->skipCurrentElement(); } } } else { NodeInput::Load(reader, xml_node_data, cancelled); } } void NodeInputArray::SaveInternal(QXmlStreamWriter *writer) const { writer->writeStartElement("subparameters"); foreach (NodeInput* sub, sub_params_) { sub->Save(writer); } writer->writeEndElement(); // subparameters } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/inputarray.h000066400000000000000000000035001370472574300204660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef INPUTARRAY_H #define INPUTARRAY_H #include "input.h" OLIVE_NAMESPACE_ENTER class NodeInputArray : public NodeInput { Q_OBJECT public: NodeInputArray(const QString &id, const DataType& type, const QVariant& default_value = 0); virtual bool IsArray() const override; int GetSize() const; void Prepend(); void Append(); void InsertAt(int index); void RemoveLast(); void RemoveAt(int index); void SetSize(int size); bool ContainsSubParameter(NodeInput* input) const; int IndexOfSubParameter(NodeInput* input) const; NodeInput* First() const; NodeInput* Last() const; NodeInput* At(int index) const; const QVector& sub_params(); signals: void SizeChanged(int size); void SubParamEdgeAdded(NodeEdgePtr edge); void SubParamEdgeRemoved(NodeEdgePtr edge); protected: virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt *cancelled) override; virtual void SaveInternal(QXmlStreamWriter* writer) const override; private: QVector sub_params_; QVariant default_value_; }; OLIVE_NAMESPACE_EXIT #endif // INPUTARRAY_H olive-continuous/app/node/inputdragger.cpp000066400000000000000000000061111370472574300213170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "inputdragger.h" #include "core.h" #include "node.h" #include "widget/nodeparamview/nodeparamviewundo.h" OLIVE_NAMESPACE_ENTER NodeInputDragger::NodeInputDragger() : input_(nullptr) { } bool NodeInputDragger::IsStarted() const { return input_; } void NodeInputDragger::Start(NodeInput *input, const rational &time, int track) { Q_ASSERT(!input_); // Set up new drag input_ = input; time_ = time; track_ = track; // Cache current value start_value_ = input_->get_value_at_time_for_track(time, track); // Determine whether we are creating a keyframe or not if (input_->is_keyframing()) { dragging_key_ = input_->get_keyframe_at_time_on_track(time, track); drag_created_key_ = !dragging_key_; if (drag_created_key_) { dragging_key_ = NodeKeyframe::Create(time, start_value_, input_->get_best_keyframe_type_for_time(time, track), track); // We disable default signal emitting during the drag //input_->blockSignals(true); input_->insert_keyframe(dragging_key_); //input_->blockSignals(false); emit input_->KeyframeAdded(dragging_key_); } } } void NodeInputDragger::Drag(const QVariant& value) { Q_ASSERT(input_); end_value_ = value; //input_->blockSignals(true); if (input_->is_keyframing()) { dragging_key_->set_value(value); } else { input_->set_standard_value(value, track_); } //input_->blockSignals(false); } void NodeInputDragger::End() { if (!IsStarted()) { return; } QUndoCommand* command = new QUndoCommand(); if (input_->is_keyframing()) { if (drag_created_key_) { // We created a keyframe in this process new NodeParamInsertKeyframeCommand(input_, dragging_key_, true, command); } // We just set a keyframe's value // We do this even when inserting a keyframe because we don't actually perform an insert in this undo command // so this will ensure the ValueChanged() signal is sent correctly new NodeParamSetKeyframeValueCommand(dragging_key_, end_value_, start_value_, command); } else { // We just set the standard value new NodeParamSetStandardValueCommand(input_, track_, end_value_, start_value_, command); } Core::instance()->undo_stack()->push(command); input_ = nullptr; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/inputdragger.h000066400000000000000000000023371370472574300207720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEINPUTDRAGGER_H #define NODEINPUTDRAGGER_H #include "node/input.h" OLIVE_NAMESPACE_ENTER class NodeInputDragger { public: NodeInputDragger(); bool IsStarted() const; void Start(NodeInput* input, const rational& time, int track); void Drag(const QVariant &value); void End(); private: NodeInput* input_; int track_; rational time_; QVariant start_value_; QVariant end_value_; NodeKeyframePtr dragging_key_; bool drag_created_key_; }; OLIVE_NAMESPACE_EXIT #endif // NODEINPUTDRAGGER_H olive-continuous/app/node/keyframe.cpp000066400000000000000000000064741370472574300204430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keyframe.h" OLIVE_NAMESPACE_ENTER const NodeKeyframe::Type NodeKeyframe::kDefaultType = kLinear; NodeKeyframe::NodeKeyframe(const rational &time, const QVariant &value, const NodeKeyframe::Type &type, const int &track) : parent_(nullptr), time_(time), value_(value), type_(type), bezier_control_in_(QPointF(-1.0, 0.0)), bezier_control_out_(QPointF(1.0, 0.0)), track_(track) { } NodeKeyframePtr NodeKeyframe::Create(const rational &time, const QVariant &value, const NodeKeyframe::Type &type, const int& track) { return std::make_shared(time, value, type, track); } NodeKeyframePtr NodeKeyframe::copy() const { NodeKeyframePtr copy = std::make_shared(time_, value_, type_, track_); copy->bezier_control_in_ = bezier_control_in_; copy->bezier_control_out_ = bezier_control_out_; return copy; } const rational &NodeKeyframe::time() const { return time_; } void NodeKeyframe::set_time(const rational &time) { time_ = time; emit TimeChanged(time_); } const QVariant &NodeKeyframe::value() const { return value_; } void NodeKeyframe::set_value(const QVariant &value) { value_ = value; emit ValueChanged(value_); } const NodeKeyframe::Type &NodeKeyframe::type() const { return type_; } void NodeKeyframe::set_type(const NodeKeyframe::Type &type) { type_ = type; emit TypeChanged(type_); } const QPointF &NodeKeyframe::bezier_control_in() const { return bezier_control_in_; } void NodeKeyframe::set_bezier_control_in(const QPointF &control) { bezier_control_in_ = control; emit BezierControlInChanged(bezier_control_in_); } const QPointF &NodeKeyframe::bezier_control_out() const { return bezier_control_out_; } void NodeKeyframe::set_bezier_control_out(const QPointF &control) { bezier_control_out_ = control; emit BezierControlOutChanged(bezier_control_out_); } const QPointF &NodeKeyframe::bezier_control(NodeKeyframe::BezierType type) const { if (type == kInHandle) { return bezier_control_in(); } else { return bezier_control_out(); } } void NodeKeyframe::set_bezier_control(NodeKeyframe::BezierType type, const QPointF &control) { if (type == kInHandle) { set_bezier_control_in(control); } else { set_bezier_control_out(control); } } const int &NodeKeyframe::track() const { return track_; } NodeKeyframe::BezierType NodeKeyframe::get_opposing_bezier_type(NodeKeyframe::BezierType type) { if (type == kInHandle) { return kOutHandle; } else { return kInHandle; } } NodeInput *NodeKeyframe::parent() const { return parent_; } void NodeKeyframe::set_parent(NodeInput *parent) { parent_ = parent; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/keyframe.h000066400000000000000000000102061370472574300200740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEKEYFRAME_H #define NODEKEYFRAME_H #include #include #include #include "common/rational.h" OLIVE_NAMESPACE_ENTER class NodeInput; class NodeKeyframe; using NodeKeyframePtr = std::shared_ptr; /** * @brief A point of data to be used at a certain time and interpolated with other data */ class NodeKeyframe : public QObject { Q_OBJECT public: /** * @brief Methods of interpolation to use with this keyframe */ enum Type { kLinear, kHold, kBezier }; /** * @brief The two types of bezier handles that are available on bezier keyframes */ enum BezierType { kInHandle, kOutHandle }; static const Type kDefaultType; /** * @brief NodeKeyframe Constructor */ NodeKeyframe(const rational& time, const QVariant& value, const Type& type, const int& track); static NodeKeyframePtr Create(const rational& time, const QVariant& value, const Type& type, const int &track); NodeKeyframePtr copy() const; /** * @brief The time this keyframe is set at */ const rational& time() const; void set_time(const rational& time); /** * @brief The value of this keyframe (i.e. the value to use at this keyframe's time) */ const QVariant& value() const; void set_value(const QVariant &value); /** * @brief The method of interpolation to use with this keyframe */ const Type& type() const; void set_type(const Type& type); /** * @brief For bezier interpolation, the control point leading into this keyframe */ const QPointF &bezier_control_in() const; void set_bezier_control_in(const QPointF& control); /** * @brief For bezier interpolation, the control point leading out of this keyframe */ const QPointF& bezier_control_out() const; void set_bezier_control_out(const QPointF& control); /** * @brief Convenience functions for retrieving/setting bezier handle information with a BezierType */ const QPointF& bezier_control(BezierType type) const; void set_bezier_control(BezierType type, const QPointF& control); /** * @brief The track that this keyframe belongs to * * For the majority of keyfreames, this will be 0, but for some types, such as kVec2, this will be 0 for X keyframes * and 1 for Y keyframes, etc. */ const int& track() const; /** * @brief Convenience function for getting the opposite handle type (e.g. kInHandle <-> kOutHandle) */ static BezierType get_opposing_bezier_type(BezierType type); NodeInput* parent() const; void set_parent(NodeInput* parent); signals: /** * @brief Signal emitted when this keyframe's time is changed */ void TimeChanged(const rational& time); /** * @brief Signal emitted when this keyframe's value is changed */ void ValueChanged(const QVariant& value); /** * @brief Signal emitted when this keyframe's value is changed */ void TypeChanged(const Type& type); /** * @brief Signal emitted when this keyframe's bezier in control point is changed */ void BezierControlInChanged(const QPointF& d); /** * @brief Signal emitted when this keyframe's bezier out control point is changed */ void BezierControlOutChanged(const QPointF& d); private: NodeInput* parent_; rational time_; QVariant value_; Type type_; QPointF bezier_control_in_; QPointF bezier_control_out_; int track_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeKeyframe::Type) #endif // NODEKEYFRAME_H olive-continuous/app/node/math/000077500000000000000000000000001370472574300170525ustar00rootroot00000000000000olive-continuous/app/node/math/CMakeLists.txt000066400000000000000000000015041370472574300216120ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(math) add_subdirectory(merge) add_subdirectory(trigonometry) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/node/math/math/000077500000000000000000000000001370472574300200035ustar00rootroot00000000000000olive-continuous/app/node/math/math/CMakeLists.txt000066400000000000000000000015411370472574300225440ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/math/math/math.h node/math/math/math.cpp node/math/math/mathbase.h node/math/math/mathbase.cpp PARENT_SCOPE ) olive-continuous/app/node/math/math/math.cpp000066400000000000000000000066161370472574300214510ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "math.h" OLIVE_NAMESPACE_ENTER MathNode::MathNode() { method_in_ = new NodeInput(QStringLiteral("method_in"), NodeParam::kCombo); method_in_->set_connectable(false); method_in_->set_is_keyframable(false); AddInput(method_in_); param_a_in_ = new NodeInput(QStringLiteral("param_a_in"), NodeParam::kFloat, 0.0); param_a_in_->set_property(QStringLiteral("decimalplaces"), 8); param_a_in_->set_property(QStringLiteral("autotrim"), true); AddInput(param_a_in_); param_b_in_ = new NodeInput(QStringLiteral("param_b_in"), NodeParam::kFloat, 0.0); param_b_in_->set_property(QStringLiteral("decimalplaces"), 8); param_b_in_->set_property(QStringLiteral("autotrim"), true); AddInput(param_b_in_); } Node *MathNode::copy() const { return new MathNode(); } QString MathNode::Name() const { return tr("Math"); } QString MathNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.math"); } QList MathNode::Category() const { return {kCategoryMath}; } QString MathNode::Description() const { return tr("Perform a mathematical operation between two values."); } void MathNode::Retranslate() { Node::Retranslate(); method_in_->set_name(tr("Method")); param_a_in_->set_name(tr("Value")); param_b_in_->set_name(tr("Value")); QStringList operations = {tr("Add"), tr("Subtract"), tr("Multiply"), tr("Divide"), QString(), tr("Power")}; method_in_->set_combobox_strings(operations); } ShaderCode MathNode::GetShaderCode(const QString &shader_id) const { return GetShaderCodeInternal(shader_id, param_a_in_, param_b_in_); } NodeValueTable MathNode::Value(NodeValueDatabase &value) const { // Auto-detect what values to operate with // FIXME: Add manual override for this PairingCalculator calc(value[param_a_in_], value[param_b_in_]); // Do nothing if no pairing was found if (!calc.FoundMostLikelyPairing()) { return value.Merge(); } NodeValue val_a = calc.GetMostLikelyValueA(); value[param_a_in_].Remove(val_a); NodeValue val_b = calc.GetMostLikelyValueB(); value[param_b_in_].Remove(val_b); return ValueInternal(value, GetOperation(), calc.GetMostLikelyPairing(), param_a_in_, val_a, param_b_in_, val_b); } void MathNode::ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const { return ProcessSamplesInternal(values, GetOperation(), param_a_in_, param_b_in_, input, output, index); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/math/math/math.h000066400000000000000000000035271370472574300211140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MATHNODE_H #define MATHNODE_H #include "mathbase.h" OLIVE_NAMESPACE_ENTER class MathNode : public MathNodeBase { public: MathNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; Operation GetOperation() const { return static_cast(method_in_->get_standard_value().toInt()); } void SetOperation(Operation o) { method_in_->set_standard_value(o); } NodeInput* param_a_in() const { return param_a_in_; } NodeInput* param_b_in() const { return param_b_in_; } virtual NodeValueTable Value(NodeValueDatabase &value) const override; virtual void ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const override; private: NodeInput* method_in_; NodeInput* param_a_in_; NodeInput* param_b_in_; }; OLIVE_NAMESPACE_EXIT #endif // MATHNODE_H olive-continuous/app/node/math/math/mathbase.cpp000066400000000000000000000443441370472574300223040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "math.h" #include #include #include "common/tohex.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER ShaderCode MathNodeBase::GetShaderCodeInternal(const QString &shader_id, NodeInput *param_a_in, olive::NodeInput *param_b_in) const { QStringList code_id = shader_id.split('.'); Operation op = static_cast(code_id.at(0).toInt()); Pairing pairing = static_cast(code_id.at(1).toInt()); NodeParam::DataType type_a = static_cast(code_id.at(2).toInt()); NodeParam::DataType type_b = static_cast(code_id.at(3).toInt()); QString operation, frag, vert; if (pairing == kPairTextureMatrix && op == kOpMultiply) { // Override the operation for this operation since we multiply texture COORDS by the matrix rather than NodeParam* tex_in = (type_a == NodeParam::kTexture) ? param_a_in : param_b_in; NodeParam* mat_in = (type_a == NodeParam::kTexture) ? param_b_in : param_a_in; // No-op frag shader (can we return QString() instead?) operation = QStringLiteral("texture(%1, ove_texcoord)").arg(tex_in->id()); vert = ReadFileAsString(":/shaders/matrix.vert").arg(mat_in->id(), tex_in->id()); } else { switch (op) { case kOpAdd: operation = QStringLiteral("%1 + %2"); break; case kOpSubtract: operation = QStringLiteral("%1 - %2"); break; case kOpMultiply: operation = QStringLiteral("%1 * %2"); break; case kOpDivide: operation = QStringLiteral("%1 / %2"); break; case kOpPower: if (pairing == kPairTextureNumber) { // The "number" in this operation has to be declared a vec4 if (type_a & NodeParam::kNumber) { operation = QStringLiteral("pow(%2, vec4(%1))"); } else { operation = QStringLiteral("pow(%1, vec4(%2))"); } } else { operation = QStringLiteral("pow(%1, %2)"); } break; } operation = operation.arg(GetShaderVariableCall(param_a_in->id(), type_a), GetShaderVariableCall(param_b_in->id(), type_b)); } frag = QStringLiteral("#version 150\n" "\n" "uniform %1 %3;\n" "uniform %2 %4;\n" "\n" "in vec2 ove_texcoord;\n" "\n" "out vec4 fragColor;\n" "\n" "void main(void) {\n" " fragColor = %5;\n" "}\n").arg(GetShaderUniformType(type_a), GetShaderUniformType(type_b), param_a_in->id(), param_b_in->id(), operation); return ShaderCode(frag, vert); } QString MathNodeBase::GetShaderUniformType(const NodeParam::DataType &type) { switch (type) { case NodeParam::kTexture: return QStringLiteral("sampler2D"); case NodeParam::kColor: return QStringLiteral("vec4"); case NodeParam::kMatrix: return QStringLiteral("mat4"); default: return QStringLiteral("float"); } } QString MathNodeBase::GetShaderVariableCall(const QString &input_id, const NodeParam::DataType &type, const QString& coord_op) { if (type == NodeParam::kTexture) { return QStringLiteral("texture(%1, ove_texcoord%2)").arg(input_id, coord_op); } return input_id; } QVector4D MathNodeBase::RetrieveVector(const NodeValue &val) { // QVariant doesn't know that QVector*D can convert themselves so we do it here switch (val.type()) { case NodeParam::kVec2: return val.data().value(); case NodeParam::kVec3: return val.data().value(); case NodeParam::kVec4: default: return val.data().value(); } } void MathNodeBase::PushVector(NodeValueTable *output, NodeParam::DataType type, const QVector4D &vec) const { switch (type) { case NodeParam::kVec2: output->Push(type, QVector2D(vec), this); break; case NodeParam::kVec3: output->Push(type, QVector3D(vec), this); break; case NodeParam::kVec4: output->Push(type, vec, this); break; default: break; } } NodeValueTable MathNodeBase::ValueInternal(NodeValueDatabase &value, Operation operation, Pairing pairing, NodeInput *param_a_in, const NodeValue& val_a, NodeInput *param_b_in, const NodeValue& val_b) const { NodeValueTable output = value.Merge(); switch (pairing) { case kPairNumberNumber: { if (val_a.type() == NodeParam::kRational && val_b.type() == NodeParam::kRational && operation != kOpPower) { // Preserve rationals output.Push(NodeParam::kRational, QVariant::fromValue(PerformAddSubMultDiv(operation, val_a.data().value(), val_b.data().value())), this); } else { output.Push(NodeParam::kFloat, PerformAll(operation, RetrieveNumber(val_a), RetrieveNumber(val_b)), this); } break; } case kPairVecVec: { // We convert all vectors to QVector4D just for simplicity and exploit the fact that kVec4 is higher than kVec2 in // the enum to find the largest data type PushVector(&output, qMax(val_a.type(), val_b.type()), PerformAddSubMultDiv(operation, RetrieveVector(val_a), RetrieveVector(val_b))); break; } case kPairMatrixVec: { QMatrix4x4 matrix = (val_a.type() == NodeParam::kMatrix) ? val_a.data().value() : val_b.data().value(); QVector4D vec = (val_a.type() == NodeParam::kMatrix) ? RetrieveVector(val_b) : RetrieveVector(val_a); // Only valid operation is multiply PushVector(&output, qMax(val_a.type(), val_b.type()), PerformMult(operation, vec, matrix)); break; } case kPairVecNumber: { QVector4D vec = (val_a.type() & NodeParam::kVector) ? RetrieveVector(val_a) : RetrieveVector(val_b); float number = RetrieveNumber((val_a.type() & NodeParam::kMatrix) ? val_b : val_a); // Only multiply and divide are valid operations PushVector(&output, val_a.type(), PerformMultDiv(operation, vec, number)); break; } case kPairMatrixMatrix: { QMatrix4x4 mat_a = val_a.data().value(); QMatrix4x4 mat_b = val_b.data().value(); output.Push(NodeParam::kMatrix, PerformAddSubMult(operation, mat_a, mat_b), this); break; } case kPairColorColor: { Color col_a = val_a.data().value(); Color col_b = val_b.data().value(); // Only add and subtract are valid operations output.Push(NodeParam::kColor, QVariant::fromValue(PerformAddSub(operation, col_a, col_b)), this); break; } case kPairNumberColor: { Color col = (val_a.type() == NodeParam::kColor) ? val_a.data().value() : val_b.data().value(); float num = (val_a.type() == NodeParam::kColor) ? val_b.data().toFloat() : val_a.data().toFloat(); // Only multiply and divide are valid operations output.Push(NodeParam::kColor, QVariant::fromValue(PerformMult(operation, col, num)), this); break; } case kPairSampleSample: { SampleBufferPtr samples_a = val_a.data().value(); SampleBufferPtr samples_b = val_b.data().value(); int max_samples = qMax(samples_a->sample_count(), samples_b->sample_count()); int min_samples = qMin(samples_a->sample_count(), samples_b->sample_count()); SampleBufferPtr mixed_samples = SampleBuffer::CreateAllocated(samples_a->audio_params(), max_samples); // Mix samples that are in both buffers for (int i=0;iaudio_params().channel_count();i++) { for (int j=0;jdata()[i][j] = PerformAll(operation, samples_a->data()[i][j], samples_b->data()[i][j]); } } if (max_samples > min_samples) { // Fill in remainder space with 0s int remainder = max_samples - min_samples; for (int i=0;iaudio_params().channel_count();i++) { memset(mixed_samples->data()[i] + min_samples * sizeof(float), 0, remainder * sizeof(float)); } } output.Push(NodeParam::kSamples, QVariant::fromValue(mixed_samples), this); break; } case kPairTextureColor: case kPairTextureNumber: case kPairTextureTexture: case kPairTextureMatrix: { ShaderJob job; job.SetShaderID(QStringLiteral("%1.%2.%3.%4").arg(QString::number(operation), QString::number(pairing), QString::number(val_a.type()), QString::number(val_b.type()))); job.InsertValue(param_a_in, val_a); job.InsertValue(param_b_in, val_b); bool operation_is_noop = false; const NodeValue& number_val = val_a.type() == NodeParam::kTexture ? val_b : val_a; if (pairing == kPairTextureNumber) { if (NumberIsNoOp(operation, RetrieveNumber(number_val))) { operation_is_noop = true; } } else if (pairing == kPairTextureMatrix) { // Only allow matrix multiplication bool matrix_is_identity = false; // FIXME: The matrix in the shader is transformed around footage+sequence resolution so we // need to do that here to determine if the matrix is truly identity. But to do that, // we need access to the texture parameters which is currently not possible. if (operation != kOpMultiply || matrix_is_identity) { operation_is_noop = true; } else { // It's likely an alpha channel will result from this operation job.SetAlphaChannelRequired(true); } } if (operation_is_noop) { // Just push texture as-is output.Push(val_a.type() == NodeParam::kTexture ? val_a : val_b); } else { // Push shader job output.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); } break; } case kPairSampleNumber: { // Queue a sample job const NodeValue& number_val = val_a.type() == NodeParam::kSamples ? val_b : val_a; NodeInput* number_param = val_a.type() == NodeParam::kSamples ? param_b_in : param_a_in; float number = RetrieveNumber(number_val); SampleJob job(val_a.type() == NodeParam::kSamples ? val_a : val_b); job.InsertValue(number_param, NodeValue(NodeParam::kFloat, number, this)); if (job.HasSamples()) { if (number_param->is_static()) { if (!NumberIsNoOp(operation, number)) { for (int i=0;iaudio_params().channel_count();i++) { for (int j=0;jsample_count();j++) { job.samples()->data()[i][j] = PerformAll(operation, job.samples()->data()[i][j], number); } } } output.Push(NodeParam::kSamples, QVariant::fromValue(job.samples()), this); } else { output.Push(NodeParam::kSampleJob, QVariant::fromValue(job), this); } } break; } case kPairNone: case kPairCount: break; } return output; } void MathNodeBase::ProcessSamplesInternal(NodeValueDatabase &values, MathNodeBase::Operation operation, NodeInput *param_a_in, NodeInput *param_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const { // This function is only used for sample+number pairing NodeValue number_val = values[param_a_in].GetWithMeta(NodeParam::kNumber); if (number_val.type() == NodeParam::kNone) { number_val = values[param_b_in].GetWithMeta(NodeParam::kNumber); if (number_val.type() == NodeParam::kNone) { return; } } float number_flt = RetrieveNumber(number_val); for (int i=0;iaudio_params().channel_count();i++) { output->data()[i][index] = PerformAll(operation, input->data()[i][index], number_flt); } } float MathNodeBase::RetrieveNumber(const NodeValue &val) { if (val.type() == NodeParam::kRational) { return val.data().value().toDouble(); } else { return val.data().toFloat(); } } bool MathNodeBase::NumberIsNoOp(const MathNodeBase::Operation &op, const float &number) { switch (op) { case kOpAdd: case kOpSubtract: if (qIsNull(number)) { return true; } break; case kOpMultiply: case kOpDivide: case kOpPower: if (qFuzzyCompare(number, 1.0f)) { return true; } break; } return false; } MathNodeBase::PairingCalculator::PairingCalculator(const NodeValueTable &table_a, const NodeValueTable &table_b) { QVector pair_likelihood_a = GetPairLikelihood(table_a); QVector pair_likelihood_b = GetPairLikelihood(table_b); int weight_a = qMax(0, table_b.Count() - table_a.Count()); int weight_b = qMax(0, table_a.Count() - table_b.Count()); QVector likelihoods(kPairCount); for (int i=0;i -1) { if (most_likely_pairing_ == kPairNone || likelihoods.at(i) > likelihoods.at(most_likely_pairing_)) { most_likely_pairing_ = static_cast(i); } } } if (most_likely_pairing_ != kPairNone) { most_likely_value_a_ = table_a.at(pair_likelihood_a.at(most_likely_pairing_)); most_likely_value_b_ = table_b.at(pair_likelihood_b.at(most_likely_pairing_)); } } QVector MathNodeBase::PairingCalculator::GetPairLikelihood(const NodeValueTable &table) { // FIXME: When we introduce a manual override, placing it here would be the least problematic QVector likelihood(kPairCount, -1); for (int i=0;i kPairNone && most_likely_pairing_ < kPairCount); } MathNodeBase::Pairing MathNodeBase::PairingCalculator::GetMostLikelyPairing() const { return most_likely_pairing_; } const NodeValue &MathNodeBase::PairingCalculator::GetMostLikelyValueA() const { return most_likely_value_a_; } const NodeValue &MathNodeBase::PairingCalculator::GetMostLikelyValueB() const { return most_likely_value_b_; } template T MathNodeBase::PerformAll(Operation operation, T a, U b) { switch (operation) { case kOpAdd: return a + b; case kOpSubtract: return a - b; case kOpMultiply: return a * b; case kOpDivide: return a / b; case kOpPower: return qPow(a, b); } return a; } template T MathNodeBase::PerformMultDiv(Operation operation, T a, U b) { switch (operation) { case kOpMultiply: return a * b; case kOpDivide: return a / b; case kOpAdd: case kOpSubtract: case kOpPower: break; } return a; } template T MathNodeBase::PerformAddSub(Operation operation, T a, U b) { switch (operation) { case kOpAdd: return a + b; case kOpSubtract: return a - b; case kOpMultiply: case kOpDivide: case kOpPower: break; } return a; } template T MathNodeBase::PerformMult(Operation operation, T a, U b) { switch (operation) { case kOpMultiply: return a * b; case kOpAdd: case kOpSubtract: case kOpDivide: case kOpPower: break; } return a; } template T MathNodeBase::PerformAddSubMult(Operation operation, T a, U b) { switch (operation) { case kOpAdd: return a + b; case kOpSubtract: return a - b; case kOpMultiply: return a * b; case kOpDivide: case kOpPower: break; } return a; } template T MathNodeBase::PerformAddSubMultDiv(Operation operation, T a, U b) { switch (operation) { case kOpAdd: return a + b; case kOpSubtract: return a - b; case kOpMultiply: return a * b; case kOpDivide: return a / b; case kOpPower: break; } return a; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/math/math/mathbase.h000066400000000000000000000066031370472574300217450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MATHNODEBASE_H #define MATHNODEBASE_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class MathNodeBase : public Node { public: MathNodeBase() = default; enum Operation { kOpAdd, kOpSubtract, kOpMultiply, kOpDivide, kOpPower }; protected: enum Pairing { kPairNone = -1, kPairNumberNumber, kPairVecVec, kPairMatrixMatrix, kPairColorColor, kPairTextureTexture, kPairVecNumber, kPairMatrixVec, kPairNumberColor, kPairTextureNumber, kPairTextureColor, kPairTextureMatrix, kPairSampleSample, kPairSampleNumber, kPairCount }; class PairingCalculator { public: PairingCalculator(const NodeValueTable &table_a, const NodeValueTable &table_b); bool FoundMostLikelyPairing() const; Pairing GetMostLikelyPairing() const; const NodeValue& GetMostLikelyValueA() const; const NodeValue& GetMostLikelyValueB() const; private: static QVector GetPairLikelihood(const NodeValueTable& table); Pairing most_likely_pairing_; NodeValue most_likely_value_a_; NodeValue most_likely_value_b_; }; template static T PerformAll(Operation operation, T a, U b); template static T PerformMultDiv(Operation operation, T a, U b); template static T PerformAddSub(Operation operation, T a, U b); template static T PerformMult(Operation operation, T a, U b); template static T PerformAddSubMult(Operation operation, T a, U b); template static T PerformAddSubMultDiv(Operation operation, T a, U b); static QString GetShaderUniformType(const NodeParam::DataType& type); static QString GetShaderVariableCall(const QString& input_id, const NodeParam::DataType& type, const QString &coord_op = QString()); static QVector4D RetrieveVector(const NodeValue& val); static float RetrieveNumber(const NodeValue& val); static bool NumberIsNoOp(const Operation& op, const float& number); ShaderCode GetShaderCodeInternal(const QString &shader_id, NodeInput* param_a_in, NodeInput* param_b_in) const; void PushVector(NodeValueTable* output, NodeParam::DataType type, const QVector4D& vec) const; NodeValueTable ValueInternal(NodeValueDatabase &value, Operation operation, Pairing pairing, NodeInput* param_a_in, const NodeValue &val_a, NodeInput* param_b_in, const NodeValue& val_b) const; void ProcessSamplesInternal(NodeValueDatabase &values, Operation operation, NodeInput* param_a_in, NodeInput* param_b_in, const SampleBufferPtr input, SampleBufferPtr output, int index) const; }; OLIVE_NAMESPACE_EXIT #endif // MATHNODEBASE_H olive-continuous/app/node/math/merge/000077500000000000000000000000001370472574300201515ustar00rootroot00000000000000olive-continuous/app/node/math/merge/CMakeLists.txt000066400000000000000000000014531370472574300227140ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/math/merge/merge.h node/math/merge/merge.cpp PARENT_SCOPE ) olive-continuous/app/node/math/merge/merge.cpp000066400000000000000000000054641370472574300217650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "merge.h" OLIVE_NAMESPACE_ENTER MergeNode::MergeNode() { base_in_ = new NodeInput("base_in", NodeParam::kTexture); AddInput(base_in_); blend_in_ = new NodeInput("blend_in", NodeParam::kTexture); AddInput(blend_in_); } Node *MergeNode::copy() const { return new MergeNode(); } QString MergeNode::Name() const { return tr("Merge"); } QString MergeNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.merge"); } QList MergeNode::Category() const { return {kCategoryMath}; } QString MergeNode::Description() const { return tr("Merge two textures together."); } void MergeNode::Retranslate() { base_in_->set_name(tr("Base")); blend_in_->set_name(tr("Blend")); } ShaderCode MergeNode::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(ReadFileAsString(":/shaders/alphaover.frag"), QString()); } NodeValueTable MergeNode::Value(NodeValueDatabase &value) const { ShaderJob job; job.InsertValue(base_in_, value); job.InsertValue(blend_in_, value); // FIXME: Check if "blend" is RGB-only, in which case it's a no-op NodeValueTable table = value.Merge(); if (!job.GetValue(base_in_).data().isNull() || !job.GetValue(blend_in_).data().isNull()) { if (job.GetValue(base_in_).data().isNull()) { // We only have a blend texture, no need to alpha over table.Push(job.GetValue(blend_in_)); } else if (job.GetValue(blend_in_).data().isNull()) { // We only have a base texture, no need to alpha over table.Push(job.GetValue(base_in_)); } else { // We have both textures, push the job table.Push(NodeParam::kShaderJob, QVariant::fromValue(job), this); } } return table; } NodeInput *MergeNode::base_in() const { return base_in_; } NodeInput *MergeNode::blend_in() const { return blend_in_; } void MergeNode::Hash(QCryptographicHash &hash, const rational &time) const { if (base_in_->is_connected()) { base_in_->get_connected_node()->Hash(hash, time); } if (blend_in_->is_connected()) { blend_in_->get_connected_node()->Hash(hash, time); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/math/merge/merge.h000066400000000000000000000027641370472574300214320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MERGENODE_H #define MERGENODE_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class MergeNode : public Node { public: MergeNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; NodeInput* base_in() const; NodeInput* blend_in() const; virtual void Hash(QCryptographicHash &hash, const rational &time) const override; private: NodeInput* base_in_; NodeInput* blend_in_; }; OLIVE_NAMESPACE_EXIT #endif // MERGENODE_H olive-continuous/app/node/math/trigonometry/000077500000000000000000000000001370472574300216145ustar00rootroot00000000000000olive-continuous/app/node/math/trigonometry/CMakeLists.txt000066400000000000000000000015071370472574300243570ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/math/trigonometry/trigonometry.h node/math/trigonometry/trigonometry.cpp PARENT_SCOPE ) olive-continuous/app/node/math/trigonometry/trigonometry.cpp000066400000000000000000000056011370472574300250640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "trigonometry.h" OLIVE_NAMESPACE_ENTER TrigonometryNode::TrigonometryNode() { method_in_ = new NodeInput(QStringLiteral("method_in"), NodeParam::kCombo); method_in_->set_connectable(false); method_in_->set_is_keyframable(false); AddInput(method_in_); x_in_ = new NodeInput(QStringLiteral("x_in"), NodeParam::kFloat, 0.0); AddInput(x_in_); } olive::Node *olive::TrigonometryNode::copy() const { return new TrigonometryNode(); } QString TrigonometryNode::Name() const { return tr("Trigonometry"); } QString TrigonometryNode::id() const { return QStringLiteral("org.olivevideoeditor.Olive.trigonometry"); } QList TrigonometryNode::Category() const { return {kCategoryMath}; } QString TrigonometryNode::Description() const { return tr("Perform a trigonometry operation on a value."); } void TrigonometryNode::Retranslate() { QStringList strings = {tr("Sine"), tr("Cosine"), tr("Tangent"), QString(), tr("Inverse Sine"), tr("Inverse Cosine"), tr("Inverse Tangent"), QString(), tr("Hyperbolic Sine"), tr("Hyperbolic Cosine"), tr("Hyperbolic Tangent")}; method_in_->set_combobox_strings(strings); method_in_->set_name(tr("Method")); } NodeValueTable TrigonometryNode::Value(NodeValueDatabase &value) const { float x = value[x_in_].Take(NodeParam::kFloat).toFloat(); NodeValueTable table = value.Merge(); switch (static_cast(method_in_->get_standard_value().toInt())) { case kOpSine: x = qSin(x); break; case kOpCosine: x = qCos(x); break; case kOpTangent: x = qTan(x); break; case kOpArcSine: x = qAsin(x); break; case kOpArcCosine: x = qAcos(x); break; case kOpArcTangent: x = qAtan(x); break; case kOpHypSine: x = std::sinh(x); break; case kOpHypCosine: x = std::cosh(x); break; case kOpHypTangent: x = std::tanh(x); break; } table.Push(NodeParam::kFloat, x, this); return table; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/math/trigonometry/trigonometry.h000066400000000000000000000027131370472574300245320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRIGNODE_H #define TRIGNODE_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class TrigonometryNode : public Node { public: TrigonometryNode(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; virtual void Retranslate() override; virtual NodeValueTable Value(NodeValueDatabase &value) const override; private: enum Operation { kOpSine, kOpCosine, kOpTangent, kOpArcSine, kOpArcCosine, kOpArcTangent, kOpHypSine, kOpHypCosine, kOpHypTangent }; NodeInput* method_in_; NodeInput* x_in_; }; OLIVE_NAMESPACE_EXIT #endif // TRIGNODE_H olive-continuous/app/node/node.cpp000066400000000000000000000514101370472574300175530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "node.h" #include #include #include #include "common/xmlutils.h" #include "project/project.h" #include "project/item/footage/footage.h" #include "project/item/footage/imagestream.h" OLIVE_NAMESPACE_ENTER Node::Node() : can_be_deleted_(true) { output_ = new NodeOutput("node_out"); AddParameter(output_); } Node::~Node() { DisconnectAll(); // We delete in the Node destructor rather than relying on the QObject system because the parameter may need to // perform actions on this Node object and we want them to be done before the Node object is fully destroyed foreach (NodeParam* param, params_) { // We disconnect input signals because these will try to send invalidate cache signals that may involve the derived // class (which is now destroyed). Any node that this is connected to will handle cache invalidation so it's a waste // of time anyway. if (param->type() == NodeParam::kInput) { DisconnectInput(static_cast(param)); } delete param; } } void Node::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled) { while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("input") || reader->name() == QStringLiteral("output")) { QString param_id; XMLAttributeLoop(reader, attr) { if (attr.name() == QStringLiteral("id")) { param_id = attr.value().toString(); break; } } if (param_id.isEmpty()) { qDebug() << "Found parameter with no ID"; continue; } NodeParam* param; if (reader->name() == QStringLiteral("input")) { param = GetInputWithID(param_id); } else { param = GetOutputWithID(param_id); } if (!param) { qDebug() << "No parameter in" << id() << "with parameter" << param_id; continue; } param->Load(reader, xml_node_data, cancelled); } else { LoadInternal(reader, xml_node_data); } } } void Node::Save(QXmlStreamWriter *writer, const QString &custom_name) const { writer->writeStartElement(custom_name.isEmpty() ? QStringLiteral("node") : custom_name); writer->writeAttribute(QStringLiteral("id"), id()); writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(this))); writer->writeAttribute(QStringLiteral("pos"), QStringLiteral("%1:%2").arg(QString::number(GetPosition().x()), QString::number(GetPosition().y()))); writer->writeAttribute(QStringLiteral("label"), GetLabel()); foreach (NodeParam* param, parameters()) { param->Save(writer); } SaveInternal(writer); writer->writeEndElement(); // node } QString Node::ShortName() const { return Name(); } QString Node::Description() const { // Return an empty string by default return QString(); } void Node::Retranslate() { } void Node::AddParameter(NodeParam *param) { // Ensure no other param with this ID has been added to this Node (since that defeats the purpose) Q_ASSERT(!HasParamWithID(param->id())); if (params_.contains(param)) { return; } param->setParent(this); // Keep main output as the last parameter, assume if there are no parameters that this is the output parameter if (params_.isEmpty()) { params_.append(param); } else { params_.insert(params_.size()-1, param); } connect(param, &NodeParam::EdgeAdded, this, &Node::EdgeAdded); connect(param, &NodeParam::EdgeRemoved, this, &Node::EdgeRemoved); if (param->type() == NodeParam::kInput) { ConnectInput(static_cast(param)); } } NodeValueTable Node::Value(NodeValueDatabase &value) const { return value.Merge(); } void Node::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source) { Q_UNUSED(from) SendInvalidateCache(range, source); } void Node::BeginOperation() { foreach (NodeParam* param, params_) { if (param->type() == NodeParam::kOutput) { foreach (NodeEdgePtr edge, param->edges()) { edge->input()->parentNode()->BeginOperation(); } } } } void Node::EndOperation() { foreach (NodeParam* param, params_) { if (param->type() == NodeParam::kOutput) { foreach (NodeEdgePtr edge, param->edges()) { edge->input()->parentNode()->EndOperation(); } } } } TimeRange Node::InputTimeAdjustment(NodeInput *, const TimeRange &input_time) const { // Default behavior is no time adjustment at all return input_time; } TimeRange Node::OutputTimeAdjustment(NodeInput *, const TimeRange &input_time) const { // Default behavior is no time adjustment at all return input_time; } void Node::SendInvalidateCache(const TimeRange &range, NodeInput *source) { // Loop through all parameters (there should be no children that are not NodeParams) foreach (NodeParam* param, params_) { // If the Node is an output, relay the signal to any Nodes that are connected to it if (param->type() == NodeParam::kOutput) { foreach (NodeEdgePtr edge, param->edges()) { NodeInput* connected_input = edge->input(); Node* connected_node = connected_input->parentNode(); // Send clear cache signal to the Node connected_node->InvalidateCache(range, connected_input, source); } } } } void Node::LoadInternal(QXmlStreamReader *reader, XMLNodeData &) { reader->skipCurrentElement(); } void Node::SaveInternal(QXmlStreamWriter *) const { } QList Node::GetInputsToHash() const { return GetInputsIncludingArrays(); } QString Node::ReadFileAsString(const QString &filename) { QFile f(filename); QString file_data; if (f.open(QFile::ReadOnly | QFile::Text)) { QTextStream text_stream(&f); file_data = text_stream.readAll(); f.close(); } return file_data; } void GetInputsIncludingArraysInternal(NodeInputArray* array, QList& list) { foreach (NodeInput* input, array->sub_params()) { list.append(input); if (input->IsArray()) { GetInputsIncludingArraysInternal(static_cast(input), list); } } } QList Node::GetInputsIncludingArrays() const { QList inputs; foreach (NodeParam* param, params_) { if (param->type() == NodeParam::kInput) { NodeInput* input = static_cast(param); inputs.append(input); if (input->IsArray()) { GetInputsIncludingArraysInternal(static_cast(input), inputs); } } } return inputs; } QList Node::GetOutputs() const { // The current design only uses one output per node. This function returns a list just in case that changes. return {output_}; } bool Node::HasGizmos() const { return false; } void Node::DrawGizmos(NodeValueDatabase &, QPainter *, const QVector2D &, const QSize &) const { } bool Node::GizmoPress(NodeValueDatabase &, const QPointF &, const QVector2D &, const QSize &) { return false; } void Node::GizmoMove(const QPointF &, const QVector2D &, const rational &) { } void Node::GizmoRelease() { } const QString &Node::GetLabel() const { return label_; } void Node::SetLabel(const QString &s) { if (label_ != s) { label_ = s; emit LabelChanged(label_); } } void Node::Hash(QCryptographicHash &hash, const rational& time) const { // Add this Node's ID hash.addData(id().toUtf8()); QList inputs = GetInputsToHash(); foreach (NodeInput* input, inputs) { // For each input, try to hash its value // Get time adjustment // For a single frame, we only care about one of the times rational input_time = InputTimeAdjustment(input, TimeRange(time, time)).in(); if (input->is_connected()) { // Traverse down this edge input->get_connected_node()->Hash(hash, input_time); } else { // Grab the value at this time QVariant value = input->get_value_at_time(input_time); hash.addData(NodeParam::ValueToBytes(input->data_type(), value)); } // We have one exception for FOOTAGE types, since we resolve the footage into a frame in the renderer if (input->data_type() == NodeParam::kFootage) { StreamPtr stream = input->get_standard_value().value(); if (stream) { // Add footage details to hash // Footage filename hash.addData(stream->footage()->filename().toUtf8()); // Footage last modified date hash.addData(stream->footage()->timestamp().toString().toUtf8()); // Footage stream hash.addData(QString::number(stream->index()).toUtf8()); if (stream->type() == Stream::kImage || stream->type() == Stream::kVideo) { ImageStreamPtr image_stream = std::static_pointer_cast(stream); // Current color config and space hash.addData(image_stream->footage()->project()->color_manager()->GetConfigFilename().toUtf8()); hash.addData(image_stream->colorspace().toUtf8()); // Alpha associated setting hash.addData(QString::number(image_stream->premultiplied_alpha()).toUtf8()); } // Footage timestamp if (stream->type() == Stream::kVideo) { hash.addData(QStringLiteral("%1/%2").arg(QString::number(input_time.numerator()), QString::number(input_time.denominator())).toUtf8()); hash.addData(QString::number(static_cast(stream.get())->start_time()).toUtf8()); } } } } } void Node::CopyInputs(Node *source, Node *destination, bool include_connections) { Q_ASSERT(source->id() == destination->id()); const QList& src_param = source->params_; const QList& dst_param = destination->params_; for (int i=0;itype() == NodeParam::kInput) { NodeInput* src = static_cast(p); NodeInput* dst = static_cast(dst_param.at(i)); NodeInput::CopyValues(src, dst, include_connections); } } destination->SetPosition(source->GetPosition()); destination->SetLabel(source->GetLabel()); } bool Node::CanBeDeleted() const { return can_be_deleted_; } void Node::SetCanBeDeleted(bool s) { can_be_deleted_ = s; } bool Node::IsBlock() const { return false; } bool Node::IsTrack() const { return false; } const QList& Node::parameters() const { return params_; } int Node::IndexOfParameter(NodeParam *param) const { return params_.indexOf(param); } /** * @brief Recursively collects dependencies of Node `n` and appends them to QList `list` * * @param traverse * * TRUE to recursively traverse each node for a complete dependency graph. FALSE to return only the immediate * dependencies. */ QList Node::GetDependenciesInternal(bool traverse, bool exclusive_only) const { QList inputs = GetInputsIncludingArrays(); QList list; foreach (NodeInput* i, inputs) { i->GetDependencies(list, traverse, exclusive_only); } return list; } QList Node::GetDependencies() const { return GetDependenciesInternal(true, false); } QList Node::GetExclusiveDependencies() const { return GetDependenciesInternal(true, true); } QList Node::GetImmediateDependencies() const { return GetDependenciesInternal(false, false); } ShaderCode Node::GetShaderCode(const QString &shader_id) const { Q_UNUSED(shader_id) return ShaderCode(QString(), QString()); } void Node::ProcessSamples(NodeValueDatabase &, const SampleBufferPtr, SampleBufferPtr, int) const { } void Node::GenerateFrame(FramePtr frame, const GenerateJob &job) const { Q_UNUSED(frame) Q_UNUSED(job) } NodeInput *Node::GetInputWithID(const QString &id) const { QList inputs = GetInputsIncludingArrays(); foreach (NodeInput* i, inputs) { if (i->id() == id) { return i; } } return nullptr; } NodeOutput *Node::GetOutputWithID(const QString &id) const { foreach (NodeParam* p, params_) { if (p->type() == NodeParam::kOutput && p->id() == id) { return static_cast(p); } } return nullptr; } bool Node::OutputsTo(Node *n, bool recursively) const { QList outputs = GetOutputs(); foreach (NodeOutput* output, outputs) { foreach (NodeEdgePtr edge, output->edges()) { Node* connected = edge->input()->parentNode(); if (connected == n) { return true; } else if (recursively && connected->OutputsTo(n, recursively)) { return true; } } } return false; } bool Node::OutputsTo(const QString &id, bool recursively) const { QList outputs = GetOutputs(); foreach (NodeOutput* output, outputs) { foreach (NodeEdgePtr edge, output->edges()) { Node* connected = edge->input()->parentNode(); if (connected->id() == id) { return true; } else if (recursively && connected->OutputsTo(id, recursively)) { return true; } } } return false; } bool Node::OutputsTo(NodeInput *input, bool recursively) const { QList outputs = GetOutputs(); foreach (NodeOutput* output, outputs) { foreach (NodeEdgePtr edge, output->edges()) { NodeInput* connected = edge->input(); if (connected == input) { return true; } else if (recursively && connected->parentNode()->OutputsTo(input, recursively)) { return true; } } } return false; } bool Node::InputsFrom(Node *n, bool recursively) const { QList inputs = GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { foreach (NodeEdgePtr edge, input->edges()) { Node* connected = edge->output()->parentNode(); if (connected == n) { return true; } else if (recursively && connected->InputsFrom(n, recursively)) { return true; } } } return false; } bool Node::InputsFrom(const QString &id, bool recursively) const { QList inputs = GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { foreach (NodeEdgePtr edge, input->edges()) { Node* connected = edge->output()->parentNode(); if (connected->id() == id) { return true; } else if (recursively && connected->InputsFrom(id, recursively)) { return true; } } } return false; } int Node::GetRoutesTo(Node *n) const { bool outputs_directly = false; int routes = 0; QList outputs = GetOutputs(); foreach (NodeOutput* o, outputs) { foreach (NodeEdgePtr edge, o->edges()) { Node* connected_node = edge->input()->parentNode(); if (connected_node == n) { outputs_directly = true; } else { routes += connected_node->GetRoutesTo(n); } } } if (outputs_directly) { routes++; } return routes; } bool Node::HasInputs() const { return HasParamOfType(NodeParam::kInput, false); } bool Node::HasOutputs() const { return HasParamOfType(NodeParam::kOutput, false); } bool Node::HasConnectedInputs() const { return HasParamOfType(NodeParam::kInput, true); } bool Node::HasConnectedOutputs() const { return HasParamOfType(NodeParam::kOutput, true); } void Node::DisconnectAll() { foreach (NodeParam* param, params_) { param->DisconnectAll(); } } QString Node::GetCategoryName(const CategoryID &c) { switch (c) { case kCategoryInput: return tr("Input"); case kCategoryOutput: return tr("Output"); case kCategoryGeneral: return tr("General"); case kCategoryMath: return tr("Math"); case kCategoryColor: return tr("Color"); case kCategoryFilter: return tr("Filter"); case kCategoryTimeline: return tr("Timeline"); case kCategoryGenerator: return tr("Generator"); case kCategoryChannels: return tr("Channel"); case kCategoryTransition: return tr("Transition"); case kCategoryUnknown: case kCategoryCount: break; } return tr("Uncategorized"); } QList Node::TransformTimeTo(const TimeRange &time, Node *target, NodeParam::Type direction) { QList paths_found; if (direction == NodeParam::kInput) { // Get list of all inputs QList inputs = GetInputsIncludingArrays(); // If this input is connected, traverse it to see if we stumble across the specified `node` foreach (NodeInput* input, inputs) { if (input->is_connected()) { TimeRange input_adjustment = InputTimeAdjustment(input, time); Node* connected = input->get_connected_node(); if (connected == target) { // We found the target, no need to keep traversing if (!paths_found.contains(input_adjustment)) { paths_found.append(input_adjustment); } } else { // We did NOT find the target, traverse this paths_found.append(connected->TransformTimeTo(input_adjustment, target, direction)); } } } } else { // Get list of all outputs QList outputs = GetOutputs(); // If this input is connected, traverse it to see if we stumble across the specified `node` foreach (NodeOutput* output, outputs) { if (output->is_connected()) { foreach (NodeEdgePtr edge, output->edges()) { Node* input_node = edge->input()->parentNode(); TimeRange output_adjustment = input_node->OutputTimeAdjustment(edge->input(), time); if (input_node == target) { paths_found.append(output_adjustment); } else { paths_found.append(input_node->TransformTimeTo(output_adjustment, target, direction)); } } } } } return paths_found; } QVariant Node::PtrToValue(void *ptr) { return reinterpret_cast(ptr); } bool Node::HasParamWithID(const QString &id) const { foreach (NodeParam* p, params_) { if (p->id() == id) { return true; } } return false; } NodeOutput *Node::output() const { return output_; } const QPointF &Node::GetPosition() const { return position_; } void Node::SetPosition(const QPointF &pos) { position_ = pos; emit PositionChanged(position_); } void Node::AddInput(NodeInput *input) { AddParameter(input); } bool Node::HasParamOfType(NodeParam::Type type, bool must_be_connected) const { foreach (NodeParam* p, params_) { if (p->type() == type && (p->is_connected() || !must_be_connected)) { return true; } } return false; } void Node::ConnectInput(NodeInput *input) { connect(input, &NodeInput::ValueChanged, this, &Node::InputChanged); connect(input, &NodeInput::EdgeAdded, this, &Node::InputConnectionChanged); connect(input, &NodeInput::EdgeRemoved, this, &Node::InputConnectionChanged); if (input->IsArray()) { NodeInputArray* array = static_cast(input); connect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::InputConnectionChanged); connect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::InputConnectionChanged); connect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::EdgeAdded); connect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::EdgeRemoved); } } void Node::DisconnectInput(NodeInput *input) { if (input->IsArray()) { NodeInputArray* array = static_cast(input); disconnect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::InputConnectionChanged); disconnect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::InputConnectionChanged); disconnect(array, &NodeInputArray::SubParamEdgeAdded, this, &Node::EdgeAdded); disconnect(array, &NodeInputArray::SubParamEdgeRemoved, this, &Node::EdgeRemoved); } disconnect(input, &NodeInput::ValueChanged, this, &Node::InputChanged); disconnect(input, &NodeInput::EdgeAdded, this, &Node::InputConnectionChanged); disconnect(input, &NodeInput::EdgeRemoved, this, &Node::InputConnectionChanged); } void Node::InputChanged(const TimeRange& range) { InvalidateCache(range, static_cast(sender()), static_cast(sender())); } void Node::InputConnectionChanged(NodeEdgePtr edge) { InvalidateCache(TimeRange(RATIONAL_MIN, RATIONAL_MAX), edge->input(), edge->input()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/node.h000066400000000000000000000403271370472574300172250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODE_H #define NODE_H #include #include #include #include #include #include "codec/frame.h" #include "codec/samplebuffer.h" #include "common/rational.h" #include "common/xmlutils.h" #include "node/input.h" #include "node/inputarray.h" #include "node/output.h" #include "node/value.h" #include "render/audioparams.h" #include "render/shaderinfo.h" OLIVE_NAMESPACE_ENTER /** * @brief A single processing unit that can be connected with others to create intricate processing systems * * A cornerstone of "visual programming", a node is a single "function" that takes input and returns an output that can * be connected to other nodes. Inputs can be either user-set or retrieved from the output of another node. By joining * several nodes together, intricate, highly customizable, and infinitely extensible systems can be made for processing * data. It can also all be exposed to the user without forcing them to write code or compile anything. * * A major example in Olive is the entire rendering workflow. To render a frame, Olive will work through a node graph * that can be infinitely customized by the user to create images. * * This is a simple base class designed to contain all the functionality for this kind of processing connective unit. * It is an abstract class intended to be subclassed to create nodes with actual functionality. */ class Node : public QObject { Q_OBJECT public: enum CategoryID { kCategoryUnknown = -1, kCategoryInput, kCategoryOutput, kCategoryGenerator, kCategoryMath, kCategoryFilter, kCategoryColor, kCategoryGeneral, kCategoryTimeline, kCategoryChannels, kCategoryTransition, kCategoryCount }; Node(); virtual ~Node() override; /** * @brief Creates a clone of the Node * * By default, the clone will NOT have the values and connections of the original node. The caller is responsible for * copying that data with functions like CopyInputs() as copies may be done for different reasons. */ virtual Node* copy() const = 0; /** * @brief Clear current node variables and replace them with */ void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled); /** * @brief Save this node into a text/XML format */ void Save(QXmlStreamWriter* writer, const QString& custom_name = QString()) const; /** * @brief Return the name of the node * * This is the node's name shown to the user. This must be overridden by subclasses, and preferably run through the * translator. */ virtual QString Name() const = 0; /** * @brief Returns a shortened name of this node if applicable * * Defaults to returning Name() but can be overridden. */ virtual QString ShortName() const; /** * @brief Return the unique identifier of the node * * This is used in save files and any other times a specific node must be picked out at runtime. This must be an ID * completely unique to this node, and preferably in bundle identifier format (e.g. "org.company.Name"). This string * should NOT be translated. */ virtual QString id() const = 0; /** * @brief Return the category this node is in (optional for subclassing, but recommended) * * In any organized node menus, show the node in this category. If this node should be in a subfolder of a subfolder, * use a "/" to separate categories (e.g. "Distort/Noise"). The string should not start with a "/" as this will be * interpreted as an empty string category. This value should be run through a translator as its largely user * oriented. */ virtual QList Category() const = 0; /** * @brief Return a description of this node's purpose (optional for subclassing, but recommended) * * A short (1-2 sentence) description of what this node should do to help the user understand its purpose. This should * be run through a translator. */ virtual QString Description() const; /** * @brief Function called to retranslate parameter names (should be overridden in derivatives) */ virtual void Retranslate(); /** * @brief Return a list of NodeParams */ const QList& parameters() const; /** * @brief Return the index of a parameter * @return Parameter index or -1 if this parameter is not part of this Node */ int IndexOfParameter(NodeParam* param) const; /** * @brief Return a list of all Nodes that this Node's inputs are connected to (does not include this Node) */ QList GetDependencies() const; /** * @brief Returns a list of Nodes that this Node is dependent on, provided no other Nodes are dependent on them * outside of this hierarchy. * * Similar to GetDependencies(), but excludes any Nodes that are used outside the dependency graph of this Node. */ QList GetExclusiveDependencies() const; /** * @brief Retrieve immediate dependencies (only nodes that are directly connected to the inputs of this one) */ QList GetImmediateDependencies() const; /** * @brief Generate hardware accelerated code for this Node */ virtual ShaderCode GetShaderCode(const QString& shader_id) const; /** * @brief If Value() pushes a ShaderJob, this is the function that will process them. */ virtual void ProcessSamples(NodeValueDatabase &values, const SampleBufferPtr input, SampleBufferPtr output, int index) const; /** * @brief If Value() pushes a GenerateJob, override this function for the image to create * * @param frame * * The destination buffer. It will already be allocated and ready for writing to. */ virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const; /** * @brief Returns the input with the specified ID (or nullptr if it doesn't exist) */ NodeInput* GetInputWithID(const QString& id) const; /** * @brief Returns the output with the specified ID (or nullptr if it doesn't exist) */ NodeOutput* GetOutputWithID(const QString& id) const; /** * @brief Returns whether this Node outputs to `n` * * @param n * * The node instance to check. * * @param recursively * * Whether to keep traversing down outputs to find this node (TRUE) or stick to immediate outputs * (FALSE). */ bool OutputsTo(Node* n, bool recursively) const; /** * @brief Same as OutputsTo(Node*), but for a node ID rather than a specific instance. */ bool OutputsTo(const QString& id, bool recursively) const; /** * @brief Same as OutputsTo(Node*), but for a specific node input rather than just a node. */ bool OutputsTo(NodeInput* input, bool recursively) const; /** * @brief Returns whether this node ever receives an input from a particular node instance */ bool InputsFrom(Node* n, bool recursively) const; /** * @brief Returns whether this node ever receives an input from a node with a particular ID */ bool InputsFrom(const QString& id, bool recursively) const; /** * @brief Determines how many paths go from this node out to another node */ int GetRoutesTo(Node* n) const; /** * @brief Return whether this Node has input parameters */ bool HasInputs() const; /** * @brief Return whether this Node has output parameters */ bool HasOutputs() const; /** * @brief Return whether this Node has input parameters and at least one of them is connected */ bool HasConnectedInputs() const; /** * @brief Return whether this Node has output parameters and at least one of them is connected */ bool HasConnectedOutputs() const; /** * @brief Severs all input and output connections */ void DisconnectAll(); /** * @brief Get the human-readable name for any category */ static QString GetCategoryName(const CategoryID &c); /** * @brief Transforms time from this node through the connections it takes to get to the specified node */ QList TransformTimeTo(const TimeRange& time, Node* target, NodeParam::Type direction); template /** * @brief Find a node of a certain type that this Node outputs to */ T* FindOutputNode(); /** * @brief Convert a pointer to a value that can be sent between NodeParams */ static QVariant PtrToValue(void* ptr); template /** * @brief Convert a NodeParam value to a pointer of any kind */ static T* ValueToPtr(const QVariant& ptr); /** * @brief Signal all dependent Nodes that anything cached between start_range and end_range is now invalid and * requires re-rendering * * Override this if your Node subclass keeps a cache, but call this base function at the end of the subclass function. * Default behavior is to relay this signal to all connected outputs, which will need to be done as to not break * the DAG. Even if the time needs to be transformed somehow (e.g. converting media time to sequence time), you can * call this function with transformed time and relay the signal that way. */ virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput* source); /** * @brief Limits cache invalidation temporarily * * If you intend to do a number of operations in quick succession, you can optimize it by running * this function with EndOperation(). */ virtual void BeginOperation(); /** * @brief Stops limiting cache invalidation and flushes changes */ virtual void EndOperation(); /** * @brief Adjusts time that should be sent to nodes connected to certain inputs. * * If this node modifies the `time` (i.e. a clip converting sequence time to media time), this function should be * overridden to do so. Also make sure to override OutputTimeAdjustment() to provide the inverse function. */ virtual TimeRange InputTimeAdjustment(NodeInput* input, const TimeRange& input_time) const; /** * @brief The inverse of InputTimeAdjustment() */ virtual TimeRange OutputTimeAdjustment(NodeInput* input, const TimeRange& input_time) const; /** * @brief Copies inputs from from Node to another including connections * * Nodes must be of the same types (i.e. have the same ID) */ static void CopyInputs(Node* source, Node* destination, bool include_connections = true); /** * @brief Return whether this Node can be deleted or not */ bool CanBeDeleted() const; /** * @brief Set whether this Node can be deleted in the UI or not */ void SetCanBeDeleted(bool s); /** * @brief Returns whether this Node is a "Block" type or not * * You shouldn't ever need to override this since all derivatives of Block will automatically have this set to true. * It's just a more convenient way of checking than dynamic_casting. */ virtual bool IsBlock() const; /** * @brief Returns whether this Node is a "Track" type or not * * You shouldn't ever need to override this since all derivatives of Track will automatically have this set to true. * It's just a more convenient way of checking than dynamic_casting. */ virtual bool IsTrack() const; /** * @brief The main processing function * * The node's main purpose is to take values from inputs to set values in outputs. For whatever subclass node you * create, this is where the code for that goes. * * Note that as a video editor, the node graph has to work across time. Depending on the purpose of your node, it may * output different values depending on the time, and even if not, it will likely be receiving different input * depending on the time. Most of the difficult work here is handled by NodeInput::get_value() which you should pass * the `time` parameter to. It will return its value (at that time, if it's keyframed), or pass the time to a * corresponding output if it's connected to one. If your node doesn't directly deal with time, the default behavior * of the NodeParam objects will handle everything related to it automatically. */ virtual NodeValueTable Value(NodeValueDatabase& value) const; /** * @brief Return whether a parameter with ID `id` has already been added to this Node */ bool HasParamWithID(const QString& id) const; NodeOutput* output() const; const QPointF& GetPosition() const; void SetPosition(const QPointF& pos); static QString ReadFileAsString(const QString& filename); QList GetInputsIncludingArrays() const; QList GetOutputs() const; virtual bool HasGizmos() const; virtual void DrawGizmos(NodeValueDatabase& db, QPainter* p, const QVector2D &scale, const QSize& viewport) const; virtual bool GizmoPress(NodeValueDatabase& db, const QPointF& p, const QVector2D &scale, const QSize& viewport); virtual void GizmoMove(const QPointF& p, const QVector2D &scale, const rational &time); virtual void GizmoRelease(); const QString& GetLabel() const; void SetLabel(const QString& s); virtual void Hash(QCryptographicHash& hash, const rational &time) const; protected: void AddInput(NodeInput* input); void ClearCachedValuesInParameters(const rational& start_range, const rational& end_range); void SendInvalidateCache(const TimeRange &range, NodeInput *source); virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data); virtual void SaveInternal(QXmlStreamWriter* writer) const; virtual QList GetInputsToHash() const; protected slots: void InputChanged(const OLIVE_NAMESPACE::TimeRange &range); void InputConnectionChanged(NodeEdgePtr edge); signals: /** * @brief Signal emitted when a node is connected to another node (creating an "edge") * * @param edge * * The edge that was added */ void EdgeAdded(NodeEdgePtr edge); /** * @brief Signal emitted when a node is disconnected from another node (removing an "edge") * * @param edge * * The edge that was removed */ void EdgeRemoved(NodeEdgePtr edge); /** * @brief Signal emitted whenever the position is set through SetPosition() */ void PositionChanged(const QPointF& pos); /** * @brief Signal emitted when SetLabel() is called */ void LabelChanged(const QString& s); private: /** * @brief Add a parameter to this node * * The Node takes ownership of this parameter. * * This can be either an output or an input at any time. Parameters will always appear in the order they're added. */ void AddParameter(NodeParam* param); bool HasParamOfType(NodeParam::Type type, bool must_be_connected) const; void ConnectInput(NodeInput* input); void DisconnectInput(NodeInput* input); QList GetDependenciesInternal(bool traverse, bool exclusive_only) const; QList params_; /** * @brief Internal variable for whether this Node can be deleted or not */ bool can_be_deleted_; /** * @brief Primary node output */ NodeOutput* output_; /** * @brief UI position for NodeViews */ QPointF position_; /** * @brief Custom user label for node */ QString label_; }; template T* Node::ValueToPtr(const QVariant &ptr) { return reinterpret_cast(ptr.value()); } template Node* FindOutputNodeInternal(Node* n) { foreach (NodeEdgePtr edge, n->output()->edges()) { Node* connected = edge->input()->parentNode(); T* cast_test = dynamic_cast(connected); if (cast_test) { return cast_test; } else { Node* drill_test = FindOutputNodeInternal(connected); if (drill_test) { return drill_test; } } } return nullptr; } template T* Node::FindOutputNode() { return static_cast(FindOutputNodeInternal(this)); } OLIVE_NAMESPACE_EXIT #endif // NODE_H olive-continuous/app/node/output.cpp000066400000000000000000000032671370472574300201750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "output.h" #include "common/xmlutils.h" #include "node/node.h" OLIVE_NAMESPACE_ENTER NodeOutput::NodeOutput(const QString &id) : NodeParam(id) { } NodeParam::Type NodeOutput::type() { return kOutput; } QString NodeOutput::name() { if (name_.isEmpty()) { return tr("Output"); } return NodeParam::name(); } void NodeOutput::Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { return; } if (attr.name() == "ptr") { quintptr saved_ptr = attr.value().toULongLong(); xml_node_data.output_ptrs.insert(saved_ptr, this); } } reader->skipCurrentElement(); } void NodeOutput::Save(QXmlStreamWriter *writer) const { writer->writeStartElement("output"); writer->writeAttribute("id", id()); writer->writeAttribute("ptr", QString::number(reinterpret_cast(this))); writer->writeEndElement(); // output } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/output.h000066400000000000000000000025531370472574300176370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEOUTPUT_H #define NODEOUTPUT_H #include "common/timerange.h" #include "param.h" OLIVE_NAMESPACE_ENTER /** * @brief A node parameter designed to serve data to the input of another node */ class NodeOutput : public NodeParam { public: /** * @brief NodeOutput Constructor */ NodeOutput(const QString& id); /** * @brief Returns kOutput */ virtual Type type() override; virtual QString name() override; virtual void Load(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; private: }; OLIVE_NAMESPACE_EXIT #endif // NODEOUTPUT_H olive-continuous/app/node/output/000077500000000000000000000000001370472574300174615ustar00rootroot00000000000000olive-continuous/app/node/output/CMakeLists.txt000066400000000000000000000014471370472574300222270ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(track) add_subdirectory(viewer) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/node/output/track/000077500000000000000000000000001370472574300205655ustar00rootroot00000000000000olive-continuous/app/node/output/track/CMakeLists.txt000066400000000000000000000015611370472574300233300ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/output/track/track.h node/output/track/track.cpp node/output/track/tracklist.h node/output/track/tracklist.cpp PARENT_SCOPE ) olive-continuous/app/node/output/track/track.cpp000066400000000000000000000421701370472574300224010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "track.h" #include #include #include #include "node/block/gap/gap.h" #include "node/graph.h" OLIVE_NAMESPACE_ENTER TrackOutput::TrackOutput() : track_type_(Timeline::kTrackTypeNone), index_(-1), locked_(false) { block_input_ = new NodeInputArray("block_in", NodeParam::kAny); block_input_->set_is_keyframable(false); AddInput(block_input_); connect(block_input_, &NodeInputArray::SubParamEdgeAdded, this, &TrackOutput::BlockConnected); connect(block_input_, &NodeInputArray::SubParamEdgeRemoved, this, &TrackOutput::BlockDisconnected); disconnect(block_input_, &NodeInputArray::SubParamEdgeAdded, this, &TrackOutput::InputConnectionChanged); disconnect(block_input_, &NodeInputArray::SubParamEdgeRemoved, this, &TrackOutput::InputConnectionChanged); muted_input_ = new NodeInput("muted_in", NodeParam::kBoolean); muted_input_->set_is_keyframable(false); connect(muted_input_, &NodeInput::ValueChanged, this, &TrackOutput::MutedInputValueChanged); AddInput(muted_input_); // Set default height track_height_ = GetDefaultTrackHeight(); } void TrackOutput::set_track_type(const Timeline::TrackType &track_type) { track_type_ = track_type; } const Timeline::TrackType& TrackOutput::track_type() const { return track_type_; } Node *TrackOutput::copy() const { return new TrackOutput(); } QString TrackOutput::Name() const { return tr("Track"); } QString TrackOutput::id() const { return QStringLiteral("org.olivevideoeditor.Olive.track"); } QList TrackOutput::Category() const { return {kCategoryTimeline}; } QString TrackOutput::Description() const { return tr("Node for representing and processing a single array of Blocks sorted by time. Also represents the end of " "a Sequence."); } QString TrackOutput::GetTrackName() { if (track_name_.isEmpty()) { return GetDefaultTrackName(track_type_, index_); } return track_name_; } const int &TrackOutput::GetTrackHeight() const { return track_height_; } void TrackOutput::SetTrackHeight(const int &height) { track_height_ = height; emit TrackHeightChanged(track_height_); } void TrackOutput::LoadInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data) { if (reader->name() == QStringLiteral("height")) { SetTrackHeight(reader->readElementText().toInt()); } else { Node::LoadInternal(reader, xml_node_data); } } void TrackOutput::SaveInternal(QXmlStreamWriter *writer) const { writer->writeTextElement(QStringLiteral("height"), QString::number(GetTrackHeight())); } void TrackOutput::Retranslate() { Node::Retranslate(); block_input_->set_name(tr("Blocks")); muted_input_->set_name(tr("Muted")); } const int &TrackOutput::Index() { return index_; } void TrackOutput::SetIndex(const int &index) { index_ = index; emit IndexChanged(index); } Block *TrackOutput::BlockContainingTime(const rational &time) const { foreach (Block* block, block_cache_) { if (block->in() < time && block->out() > time) { return block; } else if (block->out() == time) { break; } } return nullptr; } Block *TrackOutput::NearestBlockBefore(const rational &time) const { foreach (Block* block, block_cache_) { // Blocks are sorted by time, so the first Block who's out point is at/after this time is the correct Block if (block->out() >= time) { return block; } } return nullptr; } Block *TrackOutput::NearestBlockBeforeOrAt(const rational &time) const { foreach (Block* block, block_cache_) { // Blocks are sorted by time, so the first Block who's out point is at/after this time is the correct Block if (block->out() > time) { return block; } } return nullptr; } Block *TrackOutput::NearestBlockAfterOrAt(const rational &time) const { foreach (Block* block, block_cache_) { // Blocks are sorted by time, so the first Block after this time is the correct Block if (block->in() >= time) { return block; } } return nullptr; } Block *TrackOutput::NearestBlockAfter(const rational &time) const { foreach (Block* block, block_cache_) { // Blocks are sorted by time, so the first Block after this time is the correct Block if (block->in() > time) { return block; } } return nullptr; } Block *TrackOutput::BlockAtTime(const rational &time) const { if (IsMuted()) { return nullptr; } foreach (Block* block, block_cache_) { if (block && block->in() <= time && block->out() > time) { if (block->is_enabled()) { return block; } else { break; } } } return nullptr; } QList TrackOutput::BlocksAtTimeRange(const TimeRange &range) const { QList list; if (IsMuted()) { return list; } foreach (Block* block, block_cache_) { if (block && block->is_enabled() && block->out() > range.in() && block->in() < range.out()) { list.append(block); } } return list; } const QList &TrackOutput::Blocks() const { return block_cache_; } void TrackOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source) { TimeRange limited; if (block_input_->sub_params().contains(from) && from->get_connected_node() && from->get_connected_node()->IsBlock()) { // Limit the range signal to the corresponding block Block* b = static_cast(from->get_connected_node()); if (range.out() <= b->in() || range.in() >= b->out()) { return; } limited = TimeRange(qMax(range.in(), b->in()), qMin(range.out(), b->out())); } else { limited = TimeRange(qMax(range.in(), rational(0)), qMin(range.out(), track_length())); } Node::InvalidateCache(limited, from, source); } void TrackOutput::InsertBlockBefore(Block* block, Block* after) { InsertBlockAtIndex(block, block_cache_.indexOf(after)); } void TrackOutput::InsertBlockAfter(Block *block, Block *before) { int before_index = block_cache_.indexOf(before); Q_ASSERT(before_index >= 0); if (before_index == block_cache_.size() - 1) { AppendBlock(block); } else { InsertBlockAtIndex(block, before_index + 1); } } void TrackOutput::PrependBlock(Block *block) { BeginOperation(); block_input_->Prepend(); NodeParam::ConnectEdge(block->output(), block_input_->First()); EndOperation(); // Everything has shifted at this point InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_); } void TrackOutput::InsertBlockAtIndex(Block *block, int index) { BeginOperation(); int insert_index = GetInputIndexFromCacheIndex(index); block_input_->InsertAt(insert_index); NodeParam::ConnectEdge(block->output(), block_input_->At(insert_index)); EndOperation(); InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_); } void TrackOutput::AppendBlock(Block *block) { BeginOperation(); block_input_->Append(); NodeParam::ConnectEdge(block->output(), block_input_->Last()); EndOperation(); // Invalidate area that block was added to InvalidateCache(TimeRange(block->in(), track_length()), block_input_, block_input_); } void TrackOutput::RippleRemoveBlock(Block *block) { BeginOperation(); rational remove_in = block->in(); block_input_->RemoveAt(GetInputIndexFromCacheIndex(block)); EndOperation(); InvalidateCache(TimeRange(remove_in, track_length()), block_input_, block_input_); } void TrackOutput::ReplaceBlock(Block *old, Block *replace) { BeginOperation(); int index_of_old_block = GetInputIndexFromCacheIndex(old); NodeParam::DisconnectEdge(old->output(), block_input_->At(index_of_old_block)); NodeParam::ConnectEdge(replace->output(), block_input_->At(index_of_old_block)); EndOperation(); if (old->length() == replace->length()) { InvalidateCache(TimeRange(replace->in(), replace->out()), block_input_, block_input_); } else { InvalidateCache(TimeRange(replace->in(), RATIONAL_MAX), block_input_, block_input_); } } TrackOutput *TrackOutput::TrackFromBlock(const Block *block) { NodeOutput* output = block->output(); foreach (NodeEdgePtr edge, output->edges()) { Node* n = edge->input()->parentNode(); if (n->IsTrack()) { return static_cast(n); } } return nullptr; } const rational &TrackOutput::track_length() const { return track_length_; } bool TrackOutput::IsTrack() const { return true; } int TrackOutput::GetTrackHeightIncrement() { return qApp->fontMetrics().height() / 2; } int TrackOutput::GetDefaultTrackHeight() { return qApp->fontMetrics().height() * 3; } int TrackOutput::GetTrackHeightMinimum() { return qApp->fontMetrics().height() * 3 / 2; } QString TrackOutput::GetDefaultTrackName(Timeline::TrackType type, int index) { // Starts tracks at 1 rather than 0 int user_friendly_index = index+1; switch (type) { case Timeline::kTrackTypeVideo: return tr("Video %1").arg(user_friendly_index); case Timeline::kTrackTypeAudio: return tr("Audio %1").arg(user_friendly_index); case Timeline::kTrackTypeSubtitle: return tr("Subtitle %1").arg(user_friendly_index); case Timeline::kTrackTypeNone: case Timeline::kTrackTypeCount: break; } return tr("Track %1").arg(user_friendly_index); } bool TrackOutput::IsMuted() const { return muted_input_->get_standard_value().toBool(); } bool TrackOutput::IsLocked() const { return locked_; } NodeInputArray *TrackOutput::block_input() const { return block_input_; } void TrackOutput::Hash(QCryptographicHash &hash, const rational &time) const { Block* b = BlockAtTime(time); // Defer to block at this time, don't add any of our own information to the hash if (b) { b->Hash(hash, time); } } void TrackOutput::SetTrackName(const QString &name) { track_name_ = name; } void TrackOutput::SetMuted(bool e) { muted_input_->set_standard_value(e); InvalidateCache(TimeRange(0, track_length()), block_input_, block_input_); } void TrackOutput::SetLocked(bool e) { locked_ = e; } void TrackOutput::UpdateInOutFrom(int index) { // Find block just before this one to find the last out point rational last_out = (index == 0) ? 0 : block_cache_.at(index - 1)->out(); // Iterate through all blocks updating their in/outs for (int i=index; iset_in(last_out); last_out += b->length(); b->set_out(last_out); emit b->Refreshed(); } // Update track length SetLengthInternal(last_out); } int TrackOutput::GetInputIndexFromCacheIndex(int cache_index) { return GetInputIndexFromCacheIndex(block_cache_.at(cache_index)); } int TrackOutput::GetInputIndexFromCacheIndex(Block *block) { for (int i=0; iGetSize(); i++) { if (block_input_->At(i)->get_connected_node() == block) { return i; } } return -1; } void TrackOutput::SetLengthInternal(const rational &r, bool invalidate) { if (r != track_length_) { TimeRange invalidate_range(track_length_, r); track_length_ = r; emit TrackLengthChanged(); if (invalidate) { InvalidateCache(invalidate_range, block_input_, block_input_); } } } void TrackOutput::BlockConnected(NodeEdgePtr edge) { QList new_block_list; foreach (NodeInput* i, block_input_->sub_params()) { Node* connected = i->get_connected_node(); if (connected && connected->IsBlock() && !new_block_list.contains(static_cast(connected))) { Block* b = static_cast(connected); if (!new_block_list.isEmpty()) { new_block_list.last()->set_next(b); b->set_previous(new_block_list.last()); } new_block_list.append(b); if (!block_cache_.contains(b)) { // Make connections to this block connect(b, &Block::LengthChanged, this, &TrackOutput::BlockLengthChanged); emit BlockAdded(b); } } } if (!new_block_list.isEmpty()) { new_block_list.first()->set_previous(nullptr); new_block_list.last()->set_next(nullptr); } int new_index; for (new_index = 0; new_index < block_cache_.size(); new_index++) { if (block_cache_.at(new_index) != new_block_list.at(new_index)) { break; } } block_cache_ = new_block_list; UpdateInOutFrom(new_index); InputConnectionChanged(edge); /* // Determine what node was just connected Node* connected_node = edge->output()->parentNode(); // If this node is a block, we can do something with it if (connected_node->IsBlock()) { Block* connected_block = static_cast(connected_node); // See where this input falls in our internal "block cache" Block* next = nullptr; for (int i=block_input_->IndexOfSubParameter(edge->input())+1; iGetSize(); i++) { Node* that_node = block_input_->At(i)->get_connected_node(); // If we find a block, this is the block that will follow the one just connected if (that_node && that_node->IsBlock()) { next = static_cast(that_node); break; } } int real_block_index; // Either insert or append depending on if we found a "next" block if (next) { // Insert block before this next block real_block_index = block_cache_.indexOf(next); block_cache_.insert(real_block_index, connected_block); // Update values with next next->set_previous(connected_block); connected_block->set_next(next); } else { // No "next", this block must come at the end real_block_index = block_cache_.size(); block_cache_.append(connected_block); // Update next value connected_block->set_next(nullptr); } // For all blocks after the block we inserted (including it), update the "previous" and "next" // fields as well as the in/out values if (real_block_index == 0) { connected_block->set_previous(nullptr); } else { Block* prev = block_cache_.at(real_block_index - 1); connected_block->set_previous(prev); prev->set_next(connected_block); } UpdateInOutFrom(real_block_index); // Make connections to this block connect(connected_block, &Block::LengthChanged, this, &TrackOutput::BlockLengthChanged); emit BlockAdded(connected_block); } InputConnectionChanged(edge); */ } void TrackOutput::BlockDisconnected(NodeEdgePtr edge) { Block* b = static_cast(edge->output()->parentNode()); if (block_cache_.contains(b)) { block_cache_.removeOne(b); Block* previous = b->previous(); Block* next = b->next(); if (previous) { previous->set_next(next); } if (next) { next->set_previous(previous); } b->set_previous(nullptr); b->set_next(nullptr); if (next) { UpdateInOutFrom(block_cache_.indexOf(next)); } else if (block_cache_.isEmpty()) { SetLengthInternal(rational()); } else { SetLengthInternal(block_cache_.last()->out()); } disconnect(b, &Block::LengthChanged, this, &TrackOutput::BlockLengthChanged); emit BlockRemoved(b); } /* // See what kind of node was just connected Node* connected_node = edge->output()->parentNode(); // If this was a block, we would have put it in our block cache in BlockConnected() int index_of_block = block_cache_.indexOf(static_cast(connected_node)); if (index_of_block > -1) { Block* connected_block = static_cast(connected_node); // Determine what index this block was in our cache and remove it block_cache_.removeAt(index_of_block); // If there were blocks following this one, update their ins/outs UpdateInOutFrom(index_of_block); // Join the previous and next blocks together if (connected_block->previous()) { connected_block->previous()->set_next(connected_block->next()); } if (connected_block->next()) { connected_block->next()->set_previous(connected_block->previous()); } disconnect(connected_block, &Block::LengthChanged, this, &TrackOutput::BlockLengthChanged); emit BlockRemoved(connected_block); } */ InputConnectionChanged(edge); } void TrackOutput::BlockLengthChanged() { // Assumes sender is a Block Block* b = static_cast(sender()); rational old_out = b->out(); UpdateInOutFrom(block_cache_.indexOf(b)); rational new_out = b->out(); TimeRange invalidate_region(qMin(old_out, new_out), track_length()); InvalidateCache(invalidate_region, block_input_, block_input_); } void TrackOutput::MutedInputValueChanged() { emit MutedChanged(IsMuted()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/output/track/track.h000066400000000000000000000173641370472574300220550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRACKOUTPUT_H #define TRACKOUTPUT_H #include "audio/audiovisualwaveform.h" #include "node/block/block.h" #include "timeline/timelinecommon.h" OLIVE_NAMESPACE_ENTER /** * @brief A time traversal Node for sorting through one channel/track of Blocks */ class TrackOutput : public Node { Q_OBJECT public: TrackOutput(); const Timeline::TrackType& track_type() const; void set_track_type(const Timeline::TrackType& track_type); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; QString GetTrackName(); const int& GetTrackHeight() const; void SetTrackHeight(const int& height); virtual void Retranslate() override; const int& Index(); void SetIndex(const int& index); /** * @brief Returns the block that starts BEFORE (not AT) and ends AFTER (not AT) a time * * Catches the first block that matches `block.in < time && block.out > time` or nullptr if any * block starts/ends precisely at that time or the time exceeds the track length. */ Block* BlockContainingTime(const rational& time) const; /** * @brief Returns the block that starts BEFORE a given time and ends either AFTER or AT that time * * @return Catches the first block that matches `block.out >= time` or nullptr if this time * exceeds the track length. */ Block* NearestBlockBefore(const rational& time) const; /** * @brief Returns the block that starts BEFORE or AT a given time. * * @return Catches the first block that matches `block.out > time` or nullptr if this time * exceeds the track length. */ Block* NearestBlockBeforeOrAt(const rational& time) const; /** * @brief Returns the block that starts either AT a given time or the soonest block AFTER * * @return Catches the first block that matches `block.in >= time` or nullptr if this time * exceeds the track length. */ Block* NearestBlockAfterOrAt(const rational& time) const; /** * @brief Returns the block that starts AFTER the given time (but never AT the given time) * * @return Catches the first block that matches `block.in > time` or nullptr if this time * exceeds the track length. */ Block* NearestBlockAfter(const rational& time) const; /** * @brief Returns the block that should be rendered/visible at a given time * * Use this for any video rendering or determining which block will actually be active at any * time. * * @return Catches the first block that matches `block.in <= time && block.out > time`. Returns * nullptr if the time exceeds the track length, the block active at this time is disabled, or * if IsMuted() is true. */ Block* BlockAtTime(const rational& time) const; /** * @brief Returns a list of blocks that should be rendered/visible during a given time range * * Use this for audio rendering to determine all blocks that will be active throughout a range * of time. * * @return Similar to BlockAtTime() but will match several blocks where * `block.in < range.out && block.out > range.in`. Returns an empty list if IsMuted() or if * `range.in >= track.length`. Blocks that are not enabled will be omitted from the returned list. */ QList BlocksAtTimeRange(const TimeRange& range) const; const QList &Blocks() const; virtual void InvalidateCache(const TimeRange& range, NodeInput* from, NodeInput *source) override; /** * @brief Adds Block `block` at the very beginning of the Sequence before all other clips */ void PrependBlock(Block* block); /** * @brief Inserts Block `block` at a specific index (0 is the start of the timeline) * * If the index == 0, this function does the same as PrependBlock(). If the index >= the current number of blocks, * this function is the same as AppendBlock(). */ void InsertBlockAtIndex(Block* block, int index); /** * @brief Inserts Block after another Block * * Equivalent to calling InsertBlockBetweenBlocks(block, before, before->next()) */ void InsertBlockAfter(Block* block, Block* before); /** * @brief Inserts Block before another Block */ void InsertBlockBefore(Block* block, Block* after); /** * @brief Adds Block `block` at the very end of the Sequence after all other clips */ void AppendBlock(Block* block); /** * @brief Removes a Block pushing all subsequent Blocks earlier to take up the space */ void RippleRemoveBlock(Block* block); /** * @brief Replaces Block `old` with Block `replace` * * Both blocks must have equal lengths. */ void ReplaceBlock(Block* old, Block* replace); static TrackOutput* TrackFromBlock(const Block *block); const rational& track_length() const; virtual bool IsTrack() const override; static int GetTrackHeightIncrement(); static int GetDefaultTrackHeight(); static int GetTrackHeightMinimum(); static QString GetDefaultTrackName(Timeline::TrackType type, int index); bool IsMuted() const; bool IsLocked() const; NodeInputArray* block_input() const; virtual void Hash(QCryptographicHash& hash, const rational &time) const override; AudioVisualWaveform& waveform() { return waveform_; } QMutex* waveform_lock() { return &waveform_lock_; } public slots: void SetTrackName(const QString& name); void SetMuted(bool e); void SetLocked(bool e); signals: /** * @brief Signal emitted when a Block is added to this Track */ void BlockAdded(Block* block); /** * @brief Signal emitted when a Block is removed from this Track */ void BlockRemoved(Block* block); /** * @brief Signal emitted when the length of the track has changed */ void TrackLengthChanged(); /** * @brief Signal emitted when the height of the track has changed */ void TrackHeightChanged(int height); /** * @brief Signal emitted when the muted setting changes */ void MutedChanged(bool e); /** * @brief Signal emitted when the index has changed */ void IndexChanged(int i); /** * @brief Signal emitted when preview (waveform) has changed and UI should be updated */ void PreviewChanged(); protected: virtual void LoadInternal(QXmlStreamReader* reader, XMLNodeData& xml_node_data) override; virtual void SaveInternal(QXmlStreamWriter* writer) const override; private: void UpdateInOutFrom(int index); int GetInputIndexFromCacheIndex(int cache_index); int GetInputIndexFromCacheIndex(Block* block); void SetLengthInternal(const rational& r, bool invalidate = true); QList block_cache_; NodeInputArray* block_input_; NodeInput* muted_input_; Timeline::TrackType track_type_; rational track_length_; int track_height_; QString track_name_; int index_; bool locked_; AudioVisualWaveform waveform_; QMutex waveform_lock_; private slots: void BlockConnected(NodeEdgePtr edge); void BlockDisconnected(NodeEdgePtr edge); void BlockLengthChanged(); void MutedInputValueChanged(); }; OLIVE_NAMESPACE_EXIT #endif // TRACKOUTPUT_H olive-continuous/app/node/output/track/tracklist.cpp000066400000000000000000000162401370472574300232740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "tracklist.h" #include "node/factory.h" #include "node/math/math/math.h" #include "node/math/merge/merge.h" #include "node/output/viewer/viewer.h" OLIVE_NAMESPACE_ENTER TrackList::TrackList(ViewerOutput *parent, const Timeline::TrackType &type, NodeInputArray *track_input) : QObject(parent), track_input_(track_input), type_(type) { connect(track_input_, &NodeInputArray::SubParamEdgeAdded, this, &TrackList::TrackConnected); connect(track_input_, &NodeInputArray::SubParamEdgeRemoved, this, &TrackList::TrackDisconnected); } const Timeline::TrackType &TrackList::type() const { return type_; } void TrackList::TrackAddedBlock(Block *block) { emit BlockAdded(block, static_cast(sender())->Index()); } void TrackList::TrackRemovedBlock(Block *block) { emit BlockRemoved(block); } const QVector &TrackList::GetTracks() const { return track_cache_; } TrackOutput *TrackList::GetTrackAt(int index) const { if (index < track_cache_.size()) { return track_cache_.at(index); } else { return nullptr; } } const rational &TrackList::GetTotalLength() const { return total_length_; } int TrackList::GetTrackCount() const { return track_cache_.size(); } TrackOutput* TrackList::AddTrack() { TrackOutput* track = new TrackOutput(); GetParentGraph()->AddNode(track); track_input_->Append(); // Connect this track directly to this output NodeParam::ConnectEdge(track->output(), track_input_->At(track_input_->GetSize() - 1)); // Auto-merge with previous track if (track_input_->GetSize() > 1) { TrackOutput* last_track = nullptr; for (int i=track_cache_.size()-1;i>=0;i--) { TrackOutput* test_track = track_cache_.at(i); if (test_track && test_track != track) { last_track = test_track; break; } } if (last_track && last_track->output()->is_connected()) { foreach (NodeEdgePtr edge, last_track->output()->edges()) { if (!track_input_->ContainsSubParameter(edge->input())) { switch (type_) { case Timeline::kTrackTypeVideo: { MergeNode* blend = new MergeNode(); GetParentGraph()->AddNode(blend); NodeParam::ConnectEdge(track->output(), blend->blend_in()); NodeParam::ConnectEdge(last_track->output(), blend->base_in()); NodeParam::ConnectEdge(blend->output(), edge->input()); break; } case Timeline::kTrackTypeAudio: { MathNode* add = new MathNode(); GetParentGraph()->AddNode(add); NodeParam::ConnectEdge(track->output(), add->param_a_in()); NodeParam::ConnectEdge(last_track->output(), add->param_b_in()); NodeParam::ConnectEdge(add->output(), edge->input()); break; } default: break; } } } } } return track; } void TrackList::RemoveTrack() { if (track_cache_.isEmpty()) { return; } TrackOutput* track = track_cache_.last(); GetParentGraph()->TakeNode(track); delete track; track_input_->RemoveLast(); } void TrackList::TrackConnected(NodeEdgePtr edge) { int input_index = track_input_->IndexOfSubParameter(edge->input()); Q_ASSERT(input_index >= 0); Node* connected_node = edge->output()->parentNode(); if (connected_node->IsTrack()) { TrackOutput* connected_track = static_cast(connected_node); { // Find "real" index TrackOutput* next = nullptr; for (int i=input_index+1; iGetSize(); i++) { Node* that_track = track_input_->At(i)->get_connected_node(); if (that_track && that_track->IsTrack()) { next = static_cast(that_track); break; } } int track_index; if (next) { // Insert track before "next" track_index = track_cache_.indexOf(next); track_cache_.insert(track_index, connected_track); } else { // No "next", this track must come at the end track_index = track_cache_.size(); track_cache_.append(connected_track); } connected_track->SetIndex(track_index); } connect(connected_track, &TrackOutput::BlockAdded, this, &TrackList::TrackAddedBlock); connect(connected_track, &TrackOutput::BlockRemoved, this, &TrackList::TrackRemovedBlock); connect(connected_track, &TrackOutput::TrackLengthChanged, this, &TrackList::UpdateTotalLength); connect(connected_track, &TrackOutput::TrackHeightChanged, this, &TrackList::TrackHeightChangedSlot); connected_track->set_track_type(type_); emit TrackListChanged(); // This function must be called after the track is added to track_cache_, since it uses track_cache_ to determine // the track's index emit TrackAdded(connected_track); UpdateTotalLength(); } } void TrackList::TrackDisconnected(NodeEdgePtr edge) { int track_index = track_input_->IndexOfSubParameter(edge->input()); Q_ASSERT(track_index >= 0); Node* connected_node = edge->output()->parentNode(); if (connected_node->IsTrack()) { TrackOutput* track = static_cast(connected_node); int index_of_track = track_cache_.indexOf(track); track_cache_.removeAt(index_of_track); // Update indices for all subsequent tracks for (int i=index_of_track; iSetIndex(i); } // Traverse through Tracks uncaching and disconnecting them emit TrackRemoved(track); track->SetIndex(-1); track->set_track_type(Timeline::kTrackTypeNone); disconnect(track, &TrackOutput::BlockAdded, this, &TrackList::TrackAddedBlock); disconnect(track, &TrackOutput::BlockRemoved, this, &TrackList::TrackRemovedBlock); disconnect(track, &TrackOutput::TrackLengthChanged, this, &TrackList::UpdateTotalLength); disconnect(track, &TrackOutput::TrackHeightChanged, this, &TrackList::TrackHeightChangedSlot); emit TrackListChanged(); UpdateTotalLength(); } } NodeGraph *TrackList::GetParentGraph() const { return static_cast(parent()->parent()); } void TrackList::UpdateTotalLength() { total_length_ = 0; foreach (TrackOutput* track, track_cache_) { if (track) { total_length_ = qMax(total_length_, track->track_length()); } } emit LengthChanged(total_length_); } void TrackList::TrackHeightChangedSlot(int height) { emit TrackHeightChanged(static_cast(sender())->Index(), height); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/output/track/tracklist.h000066400000000000000000000052741370472574300227460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRACKLIST_H #define TRACKLIST_H #include #include "node/graph.h" #include "node/output/track/track.h" #include "timeline/timelinecommon.h" OLIVE_NAMESPACE_ENTER class ViewerOutput; class TrackList : public QObject { Q_OBJECT public: TrackList(ViewerOutput *parent, const Timeline::TrackType& type, NodeInputArray* track_input); const Timeline::TrackType& type() const; const QVector& GetTracks() const; TrackOutput* GetTrackAt(int index) const; TrackOutput *AddTrack(); void RemoveTrack(); const rational& GetTotalLength() const; int GetTrackCount() const; NodeGraph* GetParentGraph() const; signals: void BlockAdded(Block* block, int index); void BlockRemoved(Block* block); void TrackAdded(TrackOutput* track); void TrackRemoved(TrackOutput* track); void TrackListChanged(); void LengthChanged(const rational &length); void TrackHeightChanged(int index, int height); private: /** * @brief A cache of connected Tracks */ QVector track_cache_; NodeInputArray* track_input_; rational total_length_; enum Timeline::TrackType type_; private slots: /** * @brief Slot for when the track connection is added */ void TrackConnected(NodeEdgePtr edge); /** * @brief Slot for when the track connection is removed */ void TrackDisconnected(NodeEdgePtr edge); /** * @brief Slot for when a connected Track has added a Block so we can update the UI */ void TrackAddedBlock(Block* block); /** * @brief Slot for when a connected Track has added a Block so we can update the UI */ void TrackRemovedBlock(Block* block); /** * @brief Slot for when any of the track's length changes so we can update the length of the tracklist */ void UpdateTotalLength(); /** * @brief Slot when a track height changes, transforms to the TrackHeightChanged signal which includes a track index */ void TrackHeightChangedSlot(int height); }; OLIVE_NAMESPACE_EXIT #endif // TRACKLIST_H olive-continuous/app/node/output/viewer/000077500000000000000000000000001370472574300207625ustar00rootroot00000000000000olive-continuous/app/node/output/viewer/CMakeLists.txt000066400000000000000000000014631370472574300235260ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} node/output/viewer/viewer.h node/output/viewer/viewer.cpp PARENT_SCOPE ) olive-continuous/app/node/output/viewer/viewer.cpp000066400000000000000000000176001370472574300227730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewer.h" #include "node/traverser.h" OLIVE_NAMESPACE_ENTER ViewerOutput::ViewerOutput() : video_frame_cache_(this), audio_playback_cache_(this), operation_stack_(0) { texture_input_ = new NodeInput("tex_in", NodeInput::kTexture); AddInput(texture_input_); samples_input_ = new NodeInput("samples_in", NodeInput::kSamples); AddInput(samples_input_); // Create TrackList instances track_inputs_.resize(Timeline::kTrackTypeCount); track_lists_.resize(Timeline::kTrackTypeCount); for (int i=0;i(i), track_input); track_lists_.replace(i, list); connect(list, &TrackList::TrackListChanged, this, &ViewerOutput::UpdateTrackCache); //connect(list, &TrackList::LengthChanged, this, &ViewerOutput::VerifyLength); connect(list, &TrackList::BlockAdded, this, &ViewerOutput::TrackListAddedBlock); connect(list, &TrackList::BlockRemoved, this, &ViewerOutput::BlockRemoved); connect(list, &TrackList::TrackAdded, this, &ViewerOutput::TrackListAddedTrack); connect(list, &TrackList::TrackRemoved, this, &ViewerOutput::TrackRemoved); connect(list, &TrackList::TrackHeightChanged, this, &ViewerOutput::TrackHeightChangedSlot); } // Create UUID for this node uuid_ = QUuid::createUuid(); } Node *ViewerOutput::copy() const { return new ViewerOutput(); } QString ViewerOutput::Name() const { return tr("Viewer"); } QString ViewerOutput::id() const { return QStringLiteral("org.olivevideoeditor.Olive.vieweroutput"); } QList ViewerOutput::Category() const { return {kCategoryOutput}; } QString ViewerOutput::Description() const { return tr("Interface between a Viewer panel and the node system."); } void ViewerOutput::ShiftVideoCache(const rational &from, const rational &to) { video_frame_cache_.Shift(from, to); } void ViewerOutput::ShiftAudioCache(const rational &from, const rational &to) { audio_playback_cache_.Shift(from, to); foreach (TrackOutput* track, track_lists_.at(Timeline::kTrackTypeAudio)->GetTracks()) { QMutexLocker locker(track->waveform_lock()); track->waveform().Shift(from, to); } } void ViewerOutput::ShiftCache(const rational &from, const rational &to) { ShiftVideoCache(from, to); ShiftAudioCache(from, to); } void ViewerOutput::InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput *source) { emit GraphChangedFrom(source); if (operation_stack_ == 0) { if (from == texture_input_ || from == samples_input_) { TimeRange invalidated_range(qMax(rational(), range.in()), qMin(GetLength(), range.out())); if (invalidated_range.in() != invalidated_range.out()) { if (from == texture_input_) { video_frame_cache_.Invalidate(invalidated_range); } else { audio_playback_cache_.Invalidate(invalidated_range); } } } VerifyLength(); } Node::InvalidateCache(range, from, source); } void ViewerOutput::set_video_params(const VideoParams &video) { bool size_changed = video_params_.width() != video.width() || video_params_.height() != video.height(); bool timebase_changed = video_params_.time_base() != video.time_base(); video_params_ = video; if (size_changed) { emit SizeChanged(video_params_.width(), video_params_.height()); } if (timebase_changed) { video_frame_cache_.SetTimebase(video_params_.time_base()); emit TimebaseChanged(video_params_.time_base()); } emit ParamsChanged(); } void ViewerOutput::set_audio_params(const AudioParams &audio) { audio_params_ = audio; emit ParamsChanged(); } rational ViewerOutput::GetLength() { return last_length_; } QVector ViewerOutput::GetUnlockedTracks() const { QVector tracks = GetTracks(); for (int i=0;iIsLocked()) { tracks.removeAt(i); i--; } } return tracks; } void ViewerOutput::UpdateTrackCache() { track_cache_.clear(); foreach (TrackList* list, track_lists_) { foreach (TrackOutput* track, list->GetTracks()) { track_cache_.append(track); } } } void ViewerOutput::VerifyLength() { NodeTraverser traverser; rational video_length; if (texture_input_->is_connected()) { NodeValueTable t = traverser.GenerateTable(texture_input_->get_connected_node(), 0, 0); video_length = t.Get(NodeParam::kNumber, "length").value(); } rational audio_length; if (samples_input_->is_connected()) { NodeValueTable t = traverser.GenerateTable(samples_input_->get_connected_node(), 0, 0); audio_length = t.Get(NodeParam::kNumber, "length").value(); } video_length = qMax(video_length, track_lists_.at(Timeline::kTrackTypeVideo)->GetTotalLength()); audio_length = qMax(audio_length, track_lists_.at(Timeline::kTrackTypeAudio)->GetTotalLength()); rational subtitle_length = track_lists_.at(Timeline::kTrackTypeSubtitle)->GetTotalLength(); video_frame_cache_.SetLength(video_length); audio_playback_cache_.SetLength(audio_length); rational real_length = qMax(subtitle_length, qMax(video_length, audio_length)); if (real_length != last_length_) { last_length_ = real_length; emit LengthChanged(last_length_); } } void ViewerOutput::Retranslate() { Node::Retranslate(); texture_input_->set_name(tr("Texture")); samples_input_->set_name(tr("Samples")); for (int i=0;i(i)) { case Timeline::kTrackTypeVideo: input_name = tr("Video Tracks"); break; case Timeline::kTrackTypeAudio: input_name = tr("Audio Tracks"); break; case Timeline::kTrackTypeSubtitle: input_name = tr("Subtitle Tracks"); break; case Timeline::kTrackTypeNone: case Timeline::kTrackTypeCount: break; } if (!input_name.isEmpty()) { track_inputs_.at(i)->set_name(input_name); } } } void ViewerOutput::set_media_name(const QString &name) { media_name_ = name; emit MediaNameChanged(media_name_); } void ViewerOutput::BeginOperation() { operation_stack_++; Node::BeginOperation(); } void ViewerOutput::EndOperation() { operation_stack_--; Node::EndOperation(); } void ViewerOutput::TrackListAddedBlock(Block *block, int index) { Timeline::TrackType type = static_cast(sender())->type(); emit BlockAdded(block, TrackReference(type, index)); } void ViewerOutput::TrackListAddedTrack(TrackOutput *track) { Timeline::TrackType type = static_cast(sender())->type(); emit TrackAdded(track, type); } void ViewerOutput::TrackHeightChangedSlot(int index, int height) { emit TrackHeightChanged(static_cast(sender())->type(), index, height); } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/output/viewer/viewer.h000066400000000000000000000104641370472574300224410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWER_H #define VIEWER_H #include #include "node/block/block.h" #include "node/output/track/track.h" #include "node/output/track/tracklist.h" #include "node/node.h" #include "render/audioparams.h" #include "render/audioplaybackcache.h" #include "render/framehashcache.h" #include "render/videoparams.h" #include "timeline/timelinecommon.h" #include "timeline/trackreference.h" OLIVE_NAMESPACE_ENTER /** * @brief A bridge between a node system and a ViewerPanel * * Receives update/time change signals from ViewerPanels and responds by sending them a texture of that frame */ class ViewerOutput : public Node { Q_OBJECT public: ViewerOutput(); virtual Node* copy() const override; virtual QString Name() const override; virtual QString id() const override; virtual QList Category() const override; virtual QString Description() const override; void ShiftVideoCache(const rational& from, const rational& to); void ShiftAudioCache(const rational& from, const rational& to); void ShiftCache(const rational& from, const rational& to); NodeInput* texture_input() const { return texture_input_; } NodeInput* samples_input() const { return samples_input_; } virtual void InvalidateCache(const TimeRange &range, NodeInput *from, NodeInput* source) override; const VideoParams& video_params() const { return video_params_; } const AudioParams& audio_params() const { return audio_params_; } void set_video_params(const VideoParams &video); void set_audio_params(const AudioParams &audio); rational GetLength(); const QUuid& uuid() const { return uuid_; } const QVector &GetTracks() const { return track_cache_; } /** * @brief Same as GetTracks() but omits tracks that are locked. */ QVector GetUnlockedTracks() const; NodeInput* track_input(Timeline::TrackType type) const { return track_inputs_.at(type); } TrackList* track_list(Timeline::TrackType type) const { return track_lists_.at(type); } virtual void Retranslate() override; const QString& media_name() const { return media_name_; } void set_media_name(const QString& name); FrameHashCache* video_frame_cache() { return &video_frame_cache_; } AudioPlaybackCache* audio_playback_cache() { return &audio_playback_cache_; } virtual void BeginOperation() override; virtual void EndOperation() override; signals: void TimebaseChanged(const rational&); void GraphChangedFrom(NodeInput* source); void LengthChanged(const rational& length); void SizeChanged(int width, int height); void ParamsChanged(); void BlockAdded(Block* block, TrackReference track); void BlockRemoved(Block* block); void TrackAdded(TrackOutput* track, Timeline::TrackType type); void TrackRemoved(TrackOutput* track); void TrackHeightChanged(Timeline::TrackType type, int index, int height); void MediaNameChanged(const QString& name); private: QUuid uuid_; NodeInput* texture_input_; NodeInput* samples_input_; VideoParams video_params_; AudioParams audio_params_; QVector track_inputs_; QVector track_lists_; QVector track_cache_; rational last_length_; QString media_name_; FrameHashCache video_frame_cache_; AudioPlaybackCache audio_playback_cache_; int operation_stack_; private slots: void UpdateTrackCache(); void VerifyLength(); void TrackListAddedBlock(Block* block, int index); void TrackListAddedTrack(TrackOutput* track); void TrackHeightChangedSlot(int index, int height); }; OLIVE_NAMESPACE_EXIT #endif // VIEWER_H olive-continuous/app/node/param.cpp000066400000000000000000000144051370472574300177310ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "param.h" #include #include #include #include #include #include "node/node.h" #include "node/input.h" #include "node/output.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER NodeParam::NodeParam(const QString &id) : id_(id), connectable_(true) { Q_ASSERT(!id_.isEmpty()); } NodeParam::~NodeParam() { // Clear all connected edges while (!edges_.isEmpty()) { DisconnectEdge(edges_.last()); } } const QString NodeParam::id() const { return id_; } QString NodeParam::name() { if (name_.isEmpty()) { return tr("Value"); } return name_; } void NodeParam::set_name(const QString &name) { name_ = name; } Node *NodeParam::parentNode() const { QObject* p = parent(); while (p) { Node* cast_test = dynamic_cast(p); if (cast_test) { return cast_test; } else { p = p->parent(); } } return nullptr; } int NodeParam::index() { return parentNode()->IndexOfParameter(this); } bool NodeParam::is_connected() const { return !edges_.isEmpty(); } bool NodeParam::is_connectable() const { return connectable_; } void NodeParam::set_connectable(bool connectable) { connectable_ = connectable; } const QVector &NodeParam::edges() { return edges_; } void NodeParam::DisconnectAll() { while (!edges_.isEmpty()) { DisconnectEdge(edges_.first()); } } NodeEdgePtr NodeParam::ConnectEdge(NodeOutput *output, NodeInput *input) { if (!input->is_connectable()) { return nullptr; } // If the input can only accept one input (the default) and has one already, disconnect it DisconnectForNewOutput(input); // Make sure it's not a duplicate of an edge that already exists foreach (NodeEdgePtr existing, input->edges()) { if (existing->output() == output) { return nullptr; } } // Ensure both nodes are in the same graph Q_ASSERT(output->parentNode()->parent() == input->parentNode()->parent()); NodeEdgePtr edge = std::make_shared(output, input); // The nodes should never be the same, and since we lock both nodes here, this can lead to a entire program freeze // that's difficult to diagnose. This makes that issue very clear. Q_ASSERT(output->parentNode() != input->parentNode()); output->edges_.append(edge); input->edges_.append(edge); // Emit a signal than an edge was added (only one signal needs emitting) emit input->EdgeAdded(edge); return edge; } void NodeParam::DisconnectEdge(NodeEdgePtr edge) { NodeOutput* output = edge->output(); NodeInput* input = edge->input(); output->edges_.removeOne(edge); input->edges_.removeOne(edge); emit input->EdgeRemoved(edge); } void NodeParam::DisconnectEdge(NodeOutput *output, NodeInput *input) { for (int i=0;iedges_.size();i++) { NodeEdgePtr edge = output->edges_.at(i); if (edge->input() == input) { DisconnectEdge(edge); break; } } } NodeEdgePtr NodeParam::DisconnectForNewOutput(NodeInput *input) { // If the input can only accept one input (the default) and has one already, disconnect it if (!input->edges_.isEmpty()) { NodeEdgePtr edge = input->edges_.first(); DisconnectEdge(edge); return edge; } return nullptr; } QString NodeParam::GetPrettyDataTypeName(const NodeParam::DataType &type) { switch (type) { case kNone: return tr("None"); case kInt: case kCombo: return tr("Integer"); case kFloat: return tr("Float"); case kRational: return tr("Rational"); case kBoolean: return tr("Boolean"); case kColor: return tr("Color"); case kMatrix: return tr("Matrix"); case kText: return tr("Text"); case kFont: return tr("Font"); case kFile: return tr("File"); case kTexture: return tr("Texture"); case kSamples: return tr("Samples"); case kFootage: return tr("Footage"); case kVec2: return tr("Vector 2D"); case kVec3: return tr("Vector 3D"); case kVec4: return tr("Vector 4D"); case kDecimal: case kNumber: case kString: case kBuffer: case kVector: case kShaderJob: case kSampleJob: case kGenerateJob: case kAny: break; } return tr("Unknown"); } QByteArray NodeParam::ValueToBytes(const NodeParam::DataType &type, const QVariant &value) { switch (type) { case kInt: return ValueToBytesInternal(value); case kFloat: return ValueToBytesInternal(value); case kColor: return ValueToBytesInternal(value); case kText: return value.toString().toUtf8(); case kBoolean: return ValueToBytesInternal(value); case kFont: return value.toString().toUtf8(); case kFile: return value.toString().toUtf8(); case kMatrix: return ValueToBytesInternal(value); case kRational: return ValueToBytesInternal(value); case kVec2: return ValueToBytesInternal(value); case kVec3: return ValueToBytesInternal(value); case kVec4: return ValueToBytesInternal(value); case kCombo: return ValueToBytesInternal(value); // These types have no persistent input case kNone: case kFootage: case kTexture: case kSamples: case kDecimal: case kNumber: case kString: case kBuffer: case kVector: case kShaderJob: case kSampleJob: case kGenerateJob: case kAny: break; } return QByteArray(); } template QByteArray NodeParam::ValueToBytesInternal(const QVariant &v) { QByteArray bytes; int size_of_type = sizeof(T); bytes.resize(size_of_type); T raw_val = v.value(); memcpy(bytes.data(), &raw_val, static_cast(size_of_type)); return bytes; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/param.h000066400000000000000000000247341370472574300174040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAM_H #define NODEPARAM_H #include #include #include #include #include "common/rational.h" #include "common/xmlutils.h" #include "node/edge.h" OLIVE_NAMESPACE_ENTER class Node; /** * @brief A base parameter of a Node * * The main data points of a Node. NodeParams are added to Nodes so that Node::Process() can use data acquired either * directly as a value set by the user, or through the output of another NodeParam. * * This is an abstract base class. In most cases you'll want NodeInput or NodeOutput. */ class NodeParam : public QObject { Q_OBJECT public: /** * @brief The type of parameter this is */ enum Type { kInput, kOutput }; /** * @brief The types of data that can be passed between Nodes */ enum DataType { kNone = 0x0, /** ****************************** SPECIFIC IDENTIFIERS ****************************** */ /** * Integer type * * Resolves to `int` (may resolve to `long` in the future). */ kInt = 0x1, /** * Decimal (floating-point) type * * Resolves to `double`. */ kFloat = 0x2, /** * Decimal (rational) type * * Resolves to `double`. */ kRational = 0x4, /** * Boolean type * * Resolves to `bool`. */ kBoolean = 0x8, /** * Floating-point type * * Resolves to `Color`. * * Colors passed around the nodes should always be in reference space and preferably use */ kColor = 0x10, /** * Matrix type * * Resolves to `QMatrix4x4`. */ kMatrix = 0x20, /** * Text type * * Resolves to `QString`. */ kText = 0x40, /** * Font type * * Resolves to `QFont`. */ kFont = 0x80, /** * File type * * Resolves to a `QString` containing an absolute file path. */ kFile = 0x100, /** * Image buffer type * * True value type depends on the render engine used. */ kTexture = 0x200, /** * Audio samples type * * Resolves to `SampleBufferPtr`. */ kSamples = 0x400, /** * Footage stream identifier type * * Resolves to `StreamPtr`. */ kFootage = 0x800, /** * Two-dimensional vector (XY) type * * Resolves to `QVector2D`. */ kVec2 = 0x1000, /** * Three-dimensional vector (XYZ) type * * Resolves to `QVector3D`. */ kVec3 = 0x2000, /** * Four-dimensional vector (XYZW) type * * Resolves to `QVector4D`. */ kVec4 = 0x4000, /** * ComboBox type * * Resolves to `int` - the index currently selected */ kCombo = 0x8000, /** * Job type * * An internal type used to indicate to the renderer that an accelerated shader job needs to * run. This value will usually be taken from a table and a kTexture value will be pushed to * take its place. */ kShaderJob = 0x10000, /** * Job type * * An internal type used to indicate to the renderer that an accelerated sample job needs to * take place. This value will usually be taken from a table and a kSamples value will be * pushed to take its place. */ kSampleJob = 0x20000, /** * Job type * * An internal type used to indicate to the renderer that an accelerated sample job needs to * take place. This value will usually be taken from a table and a kSamples value will be * pushed to take its place. */ kGenerateJob = 0x40000, /** ****************************** BROAD IDENTIFIERS ****************************** */ /** * Identifier for type that contains a decimal number * * Includes kFloat and kRational. */ kDecimal = 0x6, /** * Identifier for type that contains a number of any kind (whole or decimal) * * Includes kInt, kFloat, and kRational. */ kNumber = 0x7, /** * Identifier for type that contains a text string of any kind. * * Includes kText and kFile. */ kString = 0x140, /** * Identifier for type that contains a either an image or audio buffer * * Includes kTexture and kSamples. */ kBuffer = 0x600, /** * Identifier for type that contains a vector (two- to four-dimensional) * * Includes kVec2, kVec3, kVec4, and kColor. */ kVector = 0x7010, /** * Identifier for any type * * Matches with all types except for kNone */ kAny = 0xFFFFFFFF }; /** * @brief NodeParam Constructor */ NodeParam(const QString& id); virtual ~NodeParam() override; /** * @brief Load function */ virtual void Load(QXmlStreamReader* reader, XMLNodeData& xml_node_data, const QAtomicInt* cancelled) = 0; /** * @brief Save function */ virtual void Save(QXmlStreamWriter* writer) const = 0; /** * @brief Return ID of this parameter */ const QString id() const; /** * @brief The type of node parameter this is * * This must be set in subclasses, but most of the time you should probably subclass from NodeInput and NodeOutput * anyway. */ virtual Type type() = 0; /** * @brief Name of this parameter to be shown to the user */ virtual QString name(); void set_name(const QString& name); /** * @brief Node parent object * * Nodes and NodeParams use the QObject parent-child system. This function is a convenience function for * static_cast(QObject::parent()) */ Node* parentNode() const; /** * @brief Return the row index of this parameter in the parent node (primarily used for UI drawing functions) */ int index(); /** * @brief Returns whether anything is connected to this parameter or not */ bool is_connected() const; bool is_connectable() const; void set_connectable(bool connectable); /** * @brief Return a list of edges (aka connections to other nodes) * * This list can't be modified directly. Use ConnectEdge() and DisconnectEdge() instead for that. */ const QVector& edges(); /** * @brief Disconnect any edges connecting this parameter to other parameters */ void DisconnectAll(); /** * @brief Connect an output parameter to an input parameter * * This function makes no attempt to check whether the two NodeParams have compatible data types. This should be done * beforehand or behavior is undefined. * * If the input already has an edge connected and can't accept multiple edges, that edge is disconnected before an * attempt at a new connection is made. This function returns the new NodeEdge created by this connection. * * If the input *can* accept multiple edges but is already connected to this output, no new connection is made (since * the connection already exists). In this situation, nullptr is returned. * * This function emits EdgeAdded(). */ static NodeEdgePtr ConnectEdge(NodeOutput *output, NodeInput *input); /** * @brief Disconnect an edge * * This function emits EdgeRemoved(NodeEdgePtr edge). * * @param edge * * Edge to disconnect. */ static void DisconnectEdge(NodeEdgePtr edge); /** * @brief Disconnect an edge * * Sometimes this function is preferable if you don't know what the edge object is (or with undo commands where the * edge object may change despite the connection being between the same parameters). * * This function emits EdgeRemoved(NodeEdgePtr edge). * * @param edge * * Edge to disconnect. */ static void DisconnectEdge(NodeOutput* output, NodeInput* input); /** * @brief If an input has an edge and can't take multiple, this function disconnects them and returns the edge object * * This is used just before a connection is about to be made. If an input is already connected to an output, but * can't take multiple inputs, that connection will need to be removed before the new connection can be made. * This function check if it's necessary to remove the edge from an input before connecting a new edge, and removes * and returns it if so. * * If the input does NOT have anything connected, or it does but the input CAN accept multiple connections, nothing * is disconnected and nullptr is returned. */ static NodeEdgePtr DisconnectForNewOutput(NodeInput* input); /** * @brief Get a human-readable translated name for a certain data type */ static QString GetPrettyDataTypeName(const DataType &type); /** * @brief Convert a value from a NodeParam into bytes */ static QByteArray ValueToBytes(const DataType &type, const QVariant& value); signals: /** * @brief Signal emitted when an edge is added to this parameter * * See ConnectEdge() for usage. Only one of the two parameters needs to emit this signal when a connection is made, * because otherwise two of exactly the same signal will be emitted. */ void EdgeAdded(NodeEdgePtr edge); /** * @brief Signal emitted when an edge is removed from this parameter * * See DisconnectEdge() for usage. Only one of the two parameters needs to emit this signal when a connection is * removed, because otherwise two of exactly the same signal will be emitted. */ void EdgeRemoved(NodeEdgePtr edge); protected: /** * @brief Internal list of edges */ QVector edges_; /** * @brief Internal name string */ QString name_; private: /** * @brief Internal function for returning a value in the form of bytes */ template static QByteArray ValueToBytesInternal(const QVariant& v); /** * @brief Internal ID string */ QString id_; /** * @brief Internal connectable value */ bool connectable_; }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAM_H olive-continuous/app/node/traverser.cpp000066400000000000000000000163511370472574300206500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "traverser.h" #include "node.h" OLIVE_NAMESPACE_ENTER NodeValueDatabase NodeTraverser::GenerateDatabase(const Node* node, const TimeRange &range) { NodeValueDatabase database; // We need to insert tables into the database for each input QList inputs = node->GetInputsIncludingArrays(); foreach (NodeInput* input, inputs) { if (IsCancelled()) { return NodeValueDatabase(); } TimeRange input_time = node->InputTimeAdjustment(input, range); database.Insert(input, ProcessInput(input, input_time)); } AddGlobalsToDatabase(database, range); return database; } NodeValueTable NodeTraverser::ProcessInput(NodeInput* input, const TimeRange& range) { if (input->is_connected()) { // Value will equal something from the connected node, follow it return GenerateTable(input->get_connected_node(), range); } else if (!input->IsArray()) { // Push onto the table the value at this time from the input QVariant input_value = input->get_value_at_time(range.in()); NodeValueTable table; table.Push(input->data_type(), input_value, input->parentNode()); return table; } return NodeValueTable(); } NodeValueTable NodeTraverser::GenerateTable(const Node *n, const TimeRange& range) { if (n->IsTrack()) { // If the range is not wholly contained in this Block, we'll need to do some extra processing return GenerateBlockTable(static_cast(n), range); } // FIXME: Cache certain values here if we've already processed them before // Generate database of input values of node NodeValueDatabase database = GenerateDatabase(n, range); // By this point, the node should have all the inputs it needs to render correctly NodeValueTable table = n->Value(database); PostProcessTable(n, range, table); return table; } NodeValueTable NodeTraverser::GenerateTable(const Node *n, const rational &in, const rational &out) { return GenerateTable(n, TimeRange(in, out)); } NodeValueTable NodeTraverser::GenerateBlockTable(const TrackOutput *track, const TimeRange &range) { // By default, just follow the in point Block* active_block = track->BlockAtTime(range.in()); NodeValueTable table; if (active_block) { table = GenerateTable(active_block, range); } return table; } QVariant NodeTraverser::ProcessVideoFootage(StreamPtr stream, const rational &input_time) { Q_UNUSED(stream) Q_UNUSED(input_time) return QVariant(); } QVariant NodeTraverser::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) { Q_UNUSED(stream) Q_UNUSED(input_time) return QVariant(); } QVariant NodeTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { Q_UNUSED(node) Q_UNUSED(range) Q_UNUSED(job) return QVariant(); } QVariant NodeTraverser::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) { Q_UNUSED(node) Q_UNUSED(range) Q_UNUSED(job) return QVariant(); } QVariant NodeTraverser::ProcessFrameGeneration(const Node *node, const GenerateJob &job) { Q_UNUSED(node) Q_UNUSED(job) return QVariant(); } QVariant NodeTraverser::GetCachedFrame(const Node *node, const rational &time) { Q_UNUSED(node) Q_UNUSED(time) return QVariant(); } void NodeTraverser::AddGlobalsToDatabase(NodeValueDatabase &db, const TimeRange& range) { // Insert global variables NodeValueTable global; global.Push(NodeParam::kFloat, range.in().toDouble(), nullptr, QStringLiteral("time_in")); global.Push(NodeParam::kFloat, range.out().toDouble(), nullptr, QStringLiteral("time_out")); db.Insert(QStringLiteral("global"), global); } void NodeTraverser::PostProcessTable(const Node *node, const TimeRange &range, NodeValueTable &output_params) { bool got_cached_frame = false; // Convert footage to image/sample buffers QVariant cached_frame = GetCachedFrame(node, range.in()); if (!cached_frame.isNull()) { output_params.Push(NodeParam::kTexture, cached_frame, node); // No more to do here got_cached_frame = true; } // Strip out any jobs or footage QList video_footage_to_retrieve; QList audio_footage_to_retrieve; QList shader_jobs_to_run; QList sample_jobs_to_run; QList generate_jobs_to_run; for (int i=0; i* take_this_value_list = nullptr; if (v.type() == NodeParam::kFootage) { StreamPtr s = v.data().value(); if (s) { if (s->type() == Stream::kVideo || s->type() == Stream::kImage) { take_this_value_list = &video_footage_to_retrieve; } else if (s->type() == Stream::kAudio) { take_this_value_list = &audio_footage_to_retrieve; } } } else if (v.type() == NodeParam::kShaderJob) { take_this_value_list = &shader_jobs_to_run; } else if (v.type() == NodeParam::kSampleJob) { take_this_value_list = &sample_jobs_to_run; } else if (v.type() == NodeParam::kGenerateJob) { take_this_value_list = &generate_jobs_to_run; } if (take_this_value_list) { take_this_value_list->append(output_params.TakeAt(i)); i--; } } if (!got_cached_frame) { // Retrieve video frames foreach (const NodeValue& v, video_footage_to_retrieve) { QVariant value = ProcessVideoFootage(v.data().value(), range.in()); if (!value.isNull()) { output_params.Push(NodeParam::kTexture, value, node); } } // Run shaders foreach (const NodeValue& v, shader_jobs_to_run) { QVariant value = ProcessShader(node, range, v.data().value()); if (!value.isNull()) { output_params.Push(NodeParam::kTexture, value, node); } } // Run generate jobs foreach (const NodeValue& v, generate_jobs_to_run) { QVariant value = ProcessFrameGeneration(node, v.data().value()); if (!value.isNull()) { output_params.Push(NodeParam::kTexture, value, node); } } } // Retrieve audio samples foreach (const NodeValue& v, audio_footage_to_retrieve) { QVariant value = ProcessAudioFootage(v.data().value(), range); if (!value.isNull()) { output_params.Push(NodeParam::kSamples, value, node); } } // Run any accelerated shader jobs foreach (const NodeValue& v, sample_jobs_to_run) { QVariant value = ProcessSamples(node, range, v.data().value()); if (!value.isNull()) { output_params.Push(NodeParam::kSamples, value, node); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/traverser.h000066400000000000000000000042721370472574300203140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODETRAVERSER_H #define NODETRAVERSER_H #include "codec/decoder.h" #include "common/cancelableobject.h" #include "node/output/track/track.h" #include "project/item/footage/stream.h" #include "value.h" OLIVE_NAMESPACE_ENTER class NodeTraverser : public CancelableObject { public: NodeTraverser() = default; NodeValueTable GenerateTable(const Node *n, const TimeRange &range); NodeValueTable GenerateTable(const Node *n, const rational &in, const rational& out); NodeValueDatabase GenerateDatabase(const Node *node, const TimeRange &range); protected: NodeValueTable ProcessInput(NodeInput *input, const TimeRange &range); virtual NodeValueTable GenerateBlockTable(const TrackOutput *track, const TimeRange& range); virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time); virtual QVariant ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time); virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job); virtual QVariant ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job); virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job); virtual QVariant GetCachedFrame(const Node *node, const rational &time); static void AddGlobalsToDatabase(NodeValueDatabase& db, const TimeRange &range); private: void PostProcessTable(const Node *node, const TimeRange &range, NodeValueTable &output_params); }; OLIVE_NAMESPACE_EXIT #endif // NODETRAVERSER_H olive-continuous/app/node/value.cpp000066400000000000000000000110031370472574300177340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "value.h" OLIVE_NAMESPACE_ENTER NodeValueTable& NodeValueDatabase::operator[](const QString &input_id) { return tables_[input_id]; } NodeValueTable& NodeValueDatabase::operator[](const NodeInput *input) { return tables_[input->id()]; } void NodeValueDatabase::Insert(const QString &key, const NodeValueTable &value) { tables_.insert(key, value); } void NodeValueDatabase::Insert(const NodeInput *key, const NodeValueTable &value) { tables_.insert(key->id(), value); } NodeValueTable NodeValueDatabase::Merge() const { QHash copy = tables_; // Kinda hacky, but we don't need this table to slipstream copy.remove(QStringLiteral("global")); return NodeValueTable::Merge(copy.values()); } NodeValue::NodeValue() : type_(NodeParam::kNone), from_(nullptr) { } NodeValue::NodeValue(const NodeParam::DataType &type, const QVariant &data, const Node *from, const QString &tag) : type_(type), data_(data), from_(from), tag_(tag) { } bool NodeValue::operator==(const NodeValue &rhs) const { return type_ == rhs.type_ && tag_ == rhs.tag_ && data_ == rhs.data_; } QVariant NodeValueTable::Get(const NodeParam::DataType &type, const QString &tag) const { return GetWithMeta(type, tag).data(); } NodeValue NodeValueTable::GetWithMeta(const NodeParam::DataType &type, const QString &tag) const { int value_index = GetInternal(type, tag); if (value_index >= 0) { return values_.at(value_index); } return NodeValue(); } QVariant NodeValueTable::Take(const NodeParam::DataType &type, const QString &tag) { return TakeWithMeta(type, tag).data(); } NodeValue NodeValueTable::TakeWithMeta(const NodeParam::DataType &type, const QString &tag) { int value_index = GetInternal(type, tag); if (value_index >= 0) { return values_.takeAt(value_index); } return NodeValue(); } void NodeValueTable::Push(const NodeValue &value) { values_.append(value); } void NodeValueTable::Push(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag) { Push(NodeValue(type, data, from, tag)); } void NodeValueTable::Prepend(const NodeValue &value) { values_.prepend(value); } void NodeValueTable::Prepend(const NodeParam::DataType &type, const QVariant &data, const Node* from, const QString &tag) { Prepend(NodeValue(type, data, from, tag)); } const NodeValue &NodeValueTable::at(int index) const { return values_.at(index); } NodeValue NodeValueTable::TakeAt(int index) { return values_.takeAt(index); } int NodeValueTable::Count() const { return values_.size(); } bool NodeValueTable::Has(const NodeParam::DataType &type) const { for (int i=values_.size() - 1;i>=0;i--) { const NodeValue& v = values_.at(i); if (v.type() & type) { return true; } } return false; } void NodeValueTable::Remove(const NodeValue &v) { for (int i=values_.size() - 1;i>=0;i--) { const NodeValue& compare = values_.at(i); if (compare == v) { values_.removeAt(i); return; } } } bool NodeValueTable::isEmpty() const { return values_.isEmpty(); } NodeValueTable NodeValueTable::Merge(QList tables) { if (tables.size() == 1) { return tables.first(); } int row = 0; NodeValueTable merged_table; // Slipstreams all tables together foreach (const NodeValueTable& t, tables) { if (row >= t.Count()) { continue; } int row_index = t.Count() - 1 - row; merged_table.Prepend(t.at(row_index)); } return merged_table; } int NodeValueTable::GetInternal(const NodeParam::DataType &type, const QString &tag) const { int index = -1; for (int i=values_.size() - 1;i>=0;i--) { const NodeValue& v = values_.at(i); if (v.type() & type) { index = i; if (tag.isEmpty() || tag == v.tag()) { break; } } } return index; } OLIVE_NAMESPACE_EXIT olive-continuous/app/node/value.h000066400000000000000000000065601370472574300174150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VALUE_H #define VALUE_H #include #include "input.h" OLIVE_NAMESPACE_ENTER class NodeValue { public: NodeValue(); NodeValue(const NodeParam::DataType& type, const QVariant& data, const Node* from, const QString& tag = QString()); const NodeParam::DataType& type() const { return type_; } const QVariant& data() const { return data_; } const QString& tag() const { return tag_; } const Node* source() const { return from_; } bool operator==(const NodeValue& rhs) const; private: NodeParam::DataType type_; QVariant data_; const Node* from_; QString tag_; }; class NodeValueTable { public: NodeValueTable() = default; QVariant Get(const NodeParam::DataType& type, const QString& tag = QString()) const; NodeValue GetWithMeta(const NodeParam::DataType& type, const QString& tag = QString()) const; QVariant Take(const NodeParam::DataType& type, const QString& tag = QString()); NodeValue TakeWithMeta(const NodeParam::DataType& type, const QString& tag = QString()); void Push(const NodeValue& value); void Push(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()); void Prepend(const NodeValue& value); void Prepend(const NodeParam::DataType& type, const QVariant& data, const Node *from, const QString& tag = QString()); const NodeValue& at(int index) const; NodeValue TakeAt(int index); int Count() const; bool Has(const NodeParam::DataType& type) const; void Remove(const NodeValue& v); bool isEmpty() const; static NodeValueTable Merge(QList tables); private: int GetInternal(const NodeParam::DataType& type, const QString& tag) const; QList values_; }; class NodeValueDatabase { public: NodeValueDatabase() = default; NodeValueTable& operator[](const QString& input_id); NodeValueTable& operator[](const NodeInput* input); void Insert(const QString& key, const NodeValueTable &value); void Insert(const NodeInput* key, const NodeValueTable& value); NodeValueTable Merge() const; using const_iterator = QHash::const_iterator; inline QHash::const_iterator begin() const { return tables_.cbegin(); } inline QHash::const_iterator end() const { return tables_.cend(); } inline bool contains(const QString& s) const { return tables_.contains(s); } private: QHash tables_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeValue) Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeValueTable) Q_DECLARE_METATYPE(OLIVE_NAMESPACE::NodeValueDatabase) #endif // VALUE_H olive-continuous/app/packaging/000077500000000000000000000000001370472574300171205ustar00rootroot00000000000000olive-continuous/app/packaging/CMakeLists.txt000066400000000000000000000013701370472574300216610ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . if(UNIX AND NOT APPLE) add_subdirectory(linux) endif() olive-continuous/app/packaging/linux/000077500000000000000000000000001370472574300202575ustar00rootroot00000000000000olive-continuous/app/packaging/linux/CMakeLists.txt000066400000000000000000000034531370472574300230240ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . if(GIT_FOUND) set(APPDATA_RELEASE_VERSION ${PROJECT_VERSION}-${GIT_HASH}) execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --pretty=%cd --date=short WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE APPDATA_RELEASE_DATE OUTPUT_STRIP_TRAILING_WHITESPACE ) else() set(APPDATA_RELEASE_VERSION ${PROJECT_VERSION}) file(TIMESTAMP "${CMAKE_SOURCE_DIR}/CMakeLists.txt" APPDATA_RELEASE_DATE "%Y-%m-%d") endif() configure_file( org.olivevideoeditor.Olive.appdata.xml.in org.olivevideoeditor.Olive.appdata.xml ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.olivevideoeditor.Olive.appdata.xml DESTINATION share/metainfo) install(FILES org.olivevideoeditor.Olive.desktop DESTINATION share/applications) install(FILES org.olivevideoeditor.Olive.xml DESTINATION share/mime/packages) foreach(size 16 32 48 64 128 256 512) install( FILES icons/${size}x${size}/org.olivevideoeditor.Olive.png DESTINATION share/icons/hicolor/${size}x${size}/apps ) install( FILES icons/${size}x${size}/application-vnd.olive-project.png DESTINATION share/icons/hicolor/${size}x${size}/mimetypes ) endforeach() olive-continuous/app/packaging/linux/icons/000077500000000000000000000000001370472574300213725ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/128x128/000077500000000000000000000000001370472574300223275ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/128x128/application-vnd.olive-project.png000066400000000000000000000240521370472574300307110ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î< IDATxœíyœ\U™÷¿çÜ­öÞ÷$½d'!!a û2, ¢‚ ŠŠ#êȼ*î:ã;Ž~ÆÑqq™ÍgÔWD„¶²‘t:étzI§—êꪺ÷žóþQ}+ÕNètzÅüò9ŸêÔ­{ï¹÷ùç<ÏsžsœÄIœÄIœÄIœÄŸ"Ä,½öL…žî /&CHbDùS‚â0 fÌ ¼V p Ȇd6‹tÝ  µ~]’A¡,«Síßøäˆ³€%”@øÆœ9˜©T©»–ë*S©°¡µ¯g!´a¤½LÆÌ:NÛÞŽËa"ÌhL”P$`ÔÖb%“‰eYáo¼qåªU«þ"¯1 £LaLнf$„úàÁƒ_ùâïú¦ï‡;;;³€GŽ3–!” å[X–ÿ«¿úØŸ¯Zµê‡Žã,•RF…rî3Ó!Âáðù¥¥oÞül{4Z¢áÏXL„ ™J•Z@øÚk¯]ÕÔ´àK Ì °páBb±BÌ®Àó<|ßV<ÏCk}ıçž{.8Mœy暟®]ûÈššÕœ9¨}û˜Ñ$8Ñ–)ÑЀ …\Û0¼ðgœñ^!„5þ|V¯^M<ŸuÂ×Zç묵Ηàÿ£} „@JYôáô?´6£Éd±C®‘If¨G4ªY V®«L) '°pá ¸ôô¡P¸…Mè‚gŽD"k>ö±Ï½ß4ÍHii©M®«‘nñ„ôÍJ)¡TÈPJ[¦i•Äb±‰¸ô´`4Áíw…d(//§ºº€ºººO_sÍ5§ZV6TU…ÅaÌ(LˆÐZ ÇÑRkSÖþlSû#1RÅö<#¿BÐÔÔD8F!/¿üòŸ•”T§RñМ93³+˜0 Zh­_—Ö~a+?„xžÇ²eË0 Ã0Ê>þñODz¬ÈLµ&L`¯×@Ïñ@JI6›Å¶mæÏŸ@<ž¸ü“Ÿ¼ë&Ó4Ãååå…]ÁŒx_ÓÞb•RøÊG)uDKÓZçŽûG?î+Ï÷ð•Ÿ?®”zÍ2YR’N§©¬¬¤¼¼€††¦/½ño\déð=0c´ÀDŽŒZkúúúxîùçhÙÓÂÀÀÑh”úúzV¯^MQQmmmÜwß}@îžãï ‘Hä¯ÓÛÛËo~ó›¼à¯¼òJjkk¹÷Þ{I¥RGXëAŸ]__ÏÙgŸ”cãÿXí)%RJ”Rd2,X@2™$N›W^yåÏÖ®}ðžé͙ӧöíÃeĦ…üú׿¦¯¯/ïs§R)ºººØºu+o{ÛÛ¨ªª¢¨¨×uI¥R!سgË—/GRŠ––z{{ÑZFI%ð<®®.úûûÃÂBäïOÄQJ½&ÒŒ´öŒö]pMß÷‘R²hÑ"6n܈eYuŸûÜß~ýSŸúÔ_ ”øp('˜Öñ‚)ï|ßçþûï§»»Ïó°,‹’’ ÃÀu]z{{¹÷Þ{Éf³X–E"‘ªëº´µµåÕ·Öš¶¶6\×Åu]âñ8!'@6›Åó<<Ï#‰F‰D"ùb[ö1ëX(ø×úM¡v å‹ëºD"æÍ›@QQÑ[?ò‘¼Ù4ÍpEEÅŒp §Th­Ù±s{÷îE)E$áŠ+® ²²’ƒòàCÒß×OGGÛ¶mcéÒ¥TVVÒÜ܌֚öööa×;pà®ë"„ ¢¢"¯~³nŽ_|1ñx|Øy‘HdÌ­?¨wáw…Údä9#¯ëyÕÕÕôööÒÓÓÃ’%K¾±fÍéëׯ¢¹¶µ~èxò “c`J5€RŠíÛ¶ãyJ)Y´hÌŸ?Ÿ¦Æ¦¼Ñ·}ûvó`GG¾òœ&éììÌÿ¾¾¾>ÿò•¯ò÷(..¦¢¢‚ÊÊÊ|‰ÅbÇ$@aë?šÐG³ ´ÖÃ4@¾>JÑÔÔ„mÛ!ìë¯çÝ`F“ÉD¨¡az]Ã)ï:::òÖýœ9s0M)%–e1oÞ¼œeïûtttPWW‡rPJ‘L&éìÈ ½½½T*…R Çq˜3gN^(®ëæ‰aÆBy­Ö4ã±ðs´.àh÷ÒZcšfÞ5´m»é _øò-Ë ÷ö–8亂i!Á”k€@hÀ°"!‰D"ïò æ_\yYyž4---h­iiiÉ»t˜¦™¿Vð½ïûìܹ“mÛ¶ñÊ+¯°uëÖüùÇÂhÙ%-28‚®)‹Q[[ @yyùÍ·ß~ûå–• ÙÓB€)·‚!U­u óÇmû°qæº.kUsçÍ¥¹¹€ÖÖV|ß§µµ5ß5ÔÕÕa‡S|ßÏßã¾ûîË·B€êêjÞ÷¾÷aš¯ýè# Á ®RJ|ß“ P¥555ô÷÷Óßß/N;í´^²dÅÙ;wnj²¦|èxÊ»! Ü2Ž|¹£}.\°0ÿÿöŽö|¸r .&ŒÀM ´F`e¬¡ÝÂz‚Y¿BK–ÆÆÆ@c…o¿ýŽŸimDŠœé°¦œ†ÌµT­5‚#[PþXÁ‹®®®Î[ò»’N§9xð u¬®®>‚ëêꨛs¸ÔÔÔŒ)°#¥5†+ü,¼ïHa ä‹”ÇqhhhÀ¶S?÷¹¿ý„i𑾾©:žò@eYy•ìºnþÅj­Éd3ùÿ;Ž“ïwMÓ¤¶¶–ÞÞ^\×eó–Íy\[[;¬ÿ‡á­ôª«®¢¸¸8]Ó4‡uGÃȾ?èÇõ_x,€aGØG ;—””PYYIGGåå•wÜrË-þä'ß{¼¢¢BuvvjrI¥“ÞL©BFB`ýýýÃ2l’ù–FóǤ”444ä_öæM›óÇŽh‰ çóÇb1‰ñx<ªs} ½†B¦Æ¢þ ˼yóˆF£âôÓOÿ÷ªªºÛN;S9t<å&´ÖùOðÿ]»vå[UU•o©Á8{ =Z[[󭹩©iTc,ø TùhnÛXP(úh×;^†Á‚ ‚î!þÑ~ê?§:•lJ ¥dñâÅykëÖ­¬[·Žææfžzê)^~ùeLÓdñâÅÃZ[III~t-xñUÕU”””Œª!µ´´°cÇŽ¼+¸mÛ¶|Œa,õ-vá½G /¤”„B!ˆD¢g⟿Ã4ÍÈT O© ¥¤ººšå§.gà PJ±nÝ:Ö­[7¬¿\ºt)sçÎörMÓ¤º¦zX8¸¶¦vTw. „Öš{î¹'ÿ7ä¶jÕ*®¾úê×´Fj¥Ô0ß¼ïñ¢¬¬Œ¾¾>:::¨®®ýÄu×]÷è=÷üüŪ*T{;ŠI0šr/À²,.¼àBV®\‰ã8y])…eYœ²ì.ºè¢¼@Aý¼úaך3wÎkªôBׯ0¿àx²|Fa´c0> ”úúz"‘ByñÅß‹'†RÉ&5H4å^€”’¢¢".»ì2-ZÄÞ½{I¥R„B!êêêhhh5V‚çœsNÞo¨?ÒB°üÔå ¦:\[[[;f[ ðXF¶ü€P#I:^-`š& .dãÆ%ŸùÌ¿w×]wÝšLûÐ3iCÇÓ’ ¥$‹±xñâaéã…}÷H!())áÒK/Í7Òý ¾»ð‚ ÙÂÇ20òÞ…]ÀÈ¿Gûíx‰Dhlld×®]Äb±?ûÔ§>qóW¿úµÿ(//÷»ºº&%J8m)aoÛv¾ºo£AJ9ì÷£½h!–e ûÝÈ2qŽUÏÑþ>‰Æ­TVVRQQ@}}ã/¿üòù¦™¤’M¨Ì¦='p6 fàºt/GÃñ’ 0ZØÔÔD(0¯¾úêÿvœhlp01)¡â“#Fs_«+I‚‘aá‘!â X–Å’%K‚¿«?ÿù¿û–iš‘É:>I€1"hñ…±±ØAÔóh¹G+±X,?^ǯ¹óÎ;¯-H%{ýÀÇcýàÓdÈLwUFÅH/àx#‹ã±jkk)++`ñâÅ_[³æô¹–•ÕÖNœk8#0¨ùØÖrǺ[øÀ 7³eðåé®Ò¨­ÿT;Îa8ÆC‚E‹1ûúëßùß=t<íÐZóË®³nÏ£øÚãÅŽøÍþÿBéiÉ‘|MŒÖCÕ#“Vvþñ”ÀB`Ûvý¾ð•¿eèxüÏs"'O”Vôfå“CªÃ5\[vÃq'nLF,I)©««àÅ_$™L¾æ5Ž—EEEy{ ¬¬ì]úЇ.-˜u|BZ`ZA‚ÐÎj#DÆO³¦ò|*TJ©|òÈLBa$0èÿçÍ›G[[ÝÝÝ<ðÀTWWnÜ11rá‰Ñ£(,C(±téÒ‘Ò\68Xœ…ˆN+ ÷KÄr$±ùÐËY%˜†9îhÚT`d^€išœuÖYlÚ´‰ÖÖVöïß?©÷—RF£Ñò˜RkkÉ-O7®(á´@J‰iX\TvÛ{·Ò’zÛ²Ç5v?•¶m›+V°hÑ"<˜ÏvK˾ 0ÚwZZZ†þrß™J…%tŽû9¦•ÁËs,‡Kœ+x²d-Ïw®gwãN–‰ÓYµ×DàßPJaš&¡PˆÚÚÚa£#? G& g40$DÐöîÝt¦m+#>1`Úõ¬ —ÿ‹Äxcå5xÚã'ûþmF€£¡ÐÆ7 ÝÃÂ㣄 ÿ´€Qáw´6¥ÖJ¬Ë0.L?„À”'ÂÙÖ\Pw1ï[˃=˜$9F`¤ð‚ï ]ÈÑ„´ðð‘¶ Ç,ÖB ¥c;DÂÞ“ø -äGÛ@¿êîê £‘`d°h4­0ÚÿGY o;uŸvÀá¡áˆ¡Ø.æí57Ð>x€¯5ÿ¾ö§»zcÂhþ­Uæ>Œö›ñÌi¦Ý  EnÂDذÚ?‡Ëæ¼ûvßCC´‰[«>0£=‚…É …9Ž@~.A ôBîÐ<š!8Y˜1^^Ø ãy7©[é¨jã¯ü„…ÑÅœ»dÖÀ0Œü ! Ã8Âòém£¹#ÿžŒçŸ]@)rÆR$!l‡y_ÙG¨‰ÔðO›¿ÎÎ̶é®Þqa´¾|4õ f,Ë8œŒ.`Fr$°-›H(J©QÊmuÂó=¾¸é3´¹aSZ1 “ùâãMÈuf ¹Ð[8–‘8™˜1]@€ U„Ca”ò™ŸZÈusoä?wŸ¿ÙüIþþÔoSl”œÐ=Uе‡þÈóÏÒ’l¡mpJ+´V”:[ÅT…k˜¯§!ÚÀŠÄjJÌÒqßo,ê?èó„ñÏ;8f`ˆÒ Šà+Å…úRZçìãþ½¿å¯·~’¯œò "2z\×ìS½lL¾Àú®gx¶ý¶õmAâaìl^%N +ŠWsNåy¼±ú-ÄÄçå™D0 #N>ÖÿOf$àð K4Áó=Þ®þœý¥{ÙбžÏòQþïÒ8ª 4šæÌ.žéyŠ}É=4÷ïfwïNÚÓŽÛ­Ôhº3Ý<Öþ0µ?Ìvþ[ÞÁu57 sŒÀˆ üùB¡ßúd3–ع0±ï{ÜPüÚÚx¾s=ŸÕ9›‡»ƒN¯ƒ{ÚųždKÏ&Ü×›?^ìÜÏ—_þ»ûwñÑ…Ÿ>¡!ëBõh…B!m)š‰ÄŒ&@ððŽåĨóê8·üîÝÿk^êÚÀ'7ÞÉGOù }nhûOµ>A{zl†¢@` mc¤Ð£v5V%v)ÝÙnºUžrQZñ‹Ý?b~|!×Ö\BB*V0‚0£ F¡Æ »\á^ÍËÑØ“ÚͶÞ-üŸõï'å¥I{(åëG£2ʪ’3)%„E„tˆÈ&A„BK|á“Rôù‡èt;èôÚiÉî&é%9/vç—âG}\‘¥Gvãš.–c±2z:¾ò1‰}Sï˜ñ€Ã$ˆ„Â$²E¬I\H[º—´7J³¤h=©C´eZññðµ"¥RlïÛÊ)ñS©‰Ô²L® ª†V&ÓפQR¡ 2}\Ï%OÓKV%Åf1¯º Ó0ˆ:1ÊDé¨sgf ÀǸ(u ¢ÏòêÀNÊ ºÒLwquɵ„UˆÝî.Z2{ØÙI§ÛÁcݳîÐ#”[,/^ÉÒÄ2N‹ŸEµ¨FŠ\?ì+…ï{x¾GÖuñ}Z9—h8B8Áç{À4,lË™µ‚0k „@¹ñ‚x4Áî¥ìlÅÒg–œË†žgù]ÏqEù5\)ß‚2}úâ=l“[Ø•ÞÁK½/Бm瑎y¤ãAv«ŠÏàÔ²•œVr í%˜ÚÄW>¾ïáYè¶ec[vÎâ 3Ö¤”òØóg:f  g¸Ù¦M$åŒôþ7ü({÷°XDyCÙ56t?Ïÿ´ÝÇ `a|1!ž”g+&š3n4p,B`&Ží°)µŒŸ%£2¬ëZËóò)ªŒZÞVt#F¯{ˆnÿ._ÚñY6¸Ï“H$(+.cµ}&·UÞÁêøYù€ÐÑГíæۿíOÝȺîGgE®âX1«ŒÀaðTfÏu=ƒÐ 1Ñ:ÉoüšªúêT=ÕN }~”~¯‡ç>Csr7ócó©,àŒâ³YÜw •±ÎŽžËÖôfv¥wЖ݇«FŸäÙ<°‹»žû0Yòqnš{ˬ7a@kÍö¾­d¼tÎGW¦k°»[Â]uM•]Í@:Éå¥WóxÏ#Ìv±Ü\A¥UÎ/ÛLH†X_ΊÌé,ã4Òö íòü6úÜC è$ûÜ^ImF£©vj9½ä,„–xÊÔc_jf¦bV [ä¡Ph4Jƒ–šýÛ¹/ùkêÃMlH®o)ºž“÷òxç£d¼ wÖßÅÖÌÖv<Ä𠼈&k>i/E¿ß‹4 K¸Ì¹ŠçBO³ßmá-E7Pk 4Q†Vz–v Ã1+ ¹Lž3¢çr·ü i5ˆ«=´Ðhm µâÙΧùHÝ]üßòjf;„/¥$QÂï~ó‡ž$­2üEÍ_òÁÚ³9óèø÷øžrñT.+H ¨uæpaÑ¥Üy/ 'c;3xÞâñbÖ>‰@Ð(Y]z&Z+\åâ*¬ï²/ÕB»>@•SÃÎÁí´E÷Ñh.䦸-œ_ÁÆÞ üsë×èð°ÄXƇ«?Ί¢•ÂÈ©vrû´förwÇù~ï7ð.%‰R"áè˜VŸ ˜µÈ-ž`scñ{¨ ÍËï+O¹¤ý4‡ünjBspXŸ|šâxÕv7ÄÞͲĩlíßÂ÷Z¿ÅÚJ°<º ˰1 37Cy(¨Ñ¼Üÿ"_Úñ9Ræ@nÑj1úz†³ ³’…)äuÎn«¼ƒy¡Æüq¥1c\DƒÓ„¯|^ê~Ž~§—¢x1eV9oÝ@SGóÀ.þeï7Ùk6sQø2ÎH¬Á¦01¤‰!ÌüÆ»’ÛùQóóux=`ÖÚAöpQ¼˜S¼å|¤ì<œ¹ŸÖL Žq^É…Ôs±L‹öÌîþn­~N½'5+ã«©p+Ø’ÜÌ›¿Ã»ªnåí‘›ZðBòYPY||„(itOÿ«¹Í*Œ™=}}¬˜µ‚AÑH_•!¼]ÞDÆÌb‰P‚°¢Ô+'.ôeûx¦ã n¬¹™X4†ÒŠåj]^'o({u?ÀOü+7–¿‡ëÕÍÔõ<9ðíÙøZ€òÑBpzâl\7›K÷žû?Ÿfe@ÊœHÄT–UQYVEUY•¥•”•‹ÄѶ"é%ñ|m}¯ðØ¡‡°L‹h8Jcx!Ù*¨âŠâ«Hªwwý„îpÙ—r[üÃ\¿’Fgsœ¹¼µä.Š^6½»=O0f­tAh88~J±UmÂ×~~qË"«˜Å«9³ì,.®¸œÚðœk0N¢ 0½ÐZá+oÔ×þJÿfö¤wq^Ñ…¼Ð³Wg@+¼$‘pPœ9‡_ þ%5[¹®ìFlÇÁ‹yôø‡x%»‰õýO³ið%\\С||åÓëöðxç#<ÞùßÜöUN-ZÉ›j¯å 5o"bß”¶ÉƤ٣-‘6ÕE)Ÿ˜?¢ni·ƒr5o®ºOùÌs±ÜÌä„U„¯<„Ñ<ø*?ïý …‚˜Ž³RœÎ»#·skñ¨0«0¥•+†‰(È!TZñRÏþnËxÓºKùÇm_aOj÷¸Ÿi¢'ˆ¾n»€à…•:GËeõ G¹Ò{3EUÅtø¸ r1RJBvˆÉÉú2nšÕÑ5<×÷ ÑÞRüŽ¡Ôñ,©ÁNMŸFM¬ŽÿNý”mî–Ü|íã+ŽXï¸×íág{þ“_´ü˜sË.àMw²(¾ä¸J|šä*9ÝÞr.u»n¨ÿÕ#ê“V)ÂN„­8àb„$¬"LC²-ó ëþ‘¬pÙ’ÜD­3±•Ü{àÿ±(±˜3ãçàù±p„äàvÒâãþ8x?>D– ÂÈM$QÊ?âÞJ+žèZË“ŸàºÚ·s×’Ïy¢é¬ ^Àô’@ É"g a#BÊvÌõ<ÛÆ²ŠqœhM؉ ¥ÁÎävú½þ\ ¸Ð<Òý?ÜVý~ú³}|o×?1wY=µö,ÃÂ2-,3‡¸R¼‰¹r÷¥K»ßÂGHð H` ›Zk¡&–$NἊ Q¾9=ã “HÅ´FJ4HCR'çÒnbsrã°Ãžv‘BàØaËA£1 ¥uÖ\Laæ“M|­øMçÝ|°îÿðóƒ?âk;¾Â——~° cÛ i`JË´XÑ:涺›iu÷âk0Êd¥²’ £œ!d‡‰‡c‹b\ÏŶì×~$­'<}Ò«ãtj Y ‘ùGÀ×^î7†Ä ææÅæŠy¬Œ¯âù¾õ¹é`Êef?vßÏ{+ïàÛûÿ‘ïíù6w6|)$–i‹Fs» Y¡›èàY¬ôV£Q!‡‚UCëŽm …†–‰[—)Ĭ릹-w-Ãb~d RÃ"‚JƒÖ]0I47aTbI›ó㳡ÿ…ü9žòx¢w-Æ/áýUâÛmÿ@C¤·V^C ÂNnMŸ&Mãzn~ˆ\Ž‘û”RšX¦iZH™Û÷a,ïl`Ú0”7`rzè ÃMìJí8| PjȽÑú,Ób•u§GÏf}òÉü÷Y?ÓýóÞŠ;¸½æ¾Ûü-¼××Ü„%ìü\BSšX!åú „ÐHÃ@ ™Ÿc˜Ÿ]4ôolïk–¬’›£Óm¢Á0$1eYìÔa‡ýë‚z D~´ðêø›yep3ýþá%kw ¾‚0$§ˆ•Ü\}?hþ/õn 1:Ÿ¦ÈBêBµ<Ðñ{6'7!VÉÕï$j„ò­wd+kcb⊚T#púó%4¦49!ÎŒ¬aõ(=î! ÐF>È"ئE,¡)=Ÿ+oä7‡~™'IKf/i3EB±†óé«ì¡Kup^ü¾Ñü÷tz˜ÂÀ&)9Àƒ]÷ñä¡Ç¹±æ]\^þ†ÉÖ–›IDAT!wo| c2´ê¤E…ÈÙÓ ÌUl˦ÉXÈ™‰5ùwobÇ8ÇÎ-KsYä ¬ ¯Î?—R­™½„ì¦apIô B:Ê¿çmå7¢•ç»xÊÅõ=„ øI~°÷»|ëÕ¯’õ³'ô<­&ùþuš‹ Xr.ÌáK© Í :“?Ú9¦a Ç(Žs]ìÊͪÜïÑ´föa&8ð¹–1®_O{ºJQCÖwÉú.®Êâù¹YF†4x²÷q>½í£tf;Çÿ<¬V'…9„˜ê±ò#‹9; ì„h´¹¼ô*é5£ÇÆÞÁæ¡XÉñ>Ï, äl€éný…-Ú2m¢áçò†Êk¨5点)eGS·B²#Ä£ V„Wr]ì$’¯ß÷èËö¹Ðîü+¦e‘Ri©NN5Oc…^­,¼¼FðHzý^þf×çiKï?b™c—‰—Ó$‹< f CqÂG\ã_K‘,>œ‚™0¹©ø=(Oáù%”’!„ø¾Â¯]­õ¤¬>i ‘+cÏó Œµ~Až€i(•;§Xåæ ím”ö3,4Oá~~?ìÜGú$jG¸µêh¥Q:·+jhh¢éXë0k¼€ã±r§Â+Êx¼ ˲°m Ó4q¤C“³ ÿ¼Qc±€Ö¢#ÞŽ]¿åáþûIÄbÇ$¢1ÇFJ1æºÌ*äê)ŽÃÂùÈÇó¥Cš,q–柹ƬÅ1n¿ŸåÆiG$‚~¿å;¬ï}&w¾”‡'ŸÇýg ”:r§Ì×K\›4 ÉÊð*äÐk\9“°¡Â©äÝ‘÷r³sóå¢<||¾¼ë‹ìI5ë¾£í)p¢˜4#PJðý@}½þ X†A­SÇJgYí²$¼˜X$J8ä Éê3Xš]F»€ê%v¨mìó[øæžàëK¾…!Žïõù³Â T*×oÓë„0Ù!n)z?  ÙaÛFCš8–C*=@8¡6;—7ÊkðCÍòUz3ý;EÓ>ÃxRÝÀB•ùz„”‚¢,ZŠÖq¹ÕE¤ 2°-‹ˆ&ãfHgÒdÜ,RÎ _@¥U¾û ‚.`"1‰ù¯_Á"W0â9WβìÃCJ-m,Ã"¬Âx×uñ•!¡, ãÃd,Q;©³ƒ_ª‘¹„ÎÀØË[ì„ùýlÓ"è¥Ì-w«ÃFšŒw9)Íj~=£ÐÝ;ÚóæÈ` FûûÌŠ”0­µÒZZë¡M‘fV8xº1\{ý½Á«l6‹ÖZê‰X¨l rƒÿxžwHJYžJ ‹Å‡bþIœrý¾çù àºÙß÷ýC)¥¥…ðTww÷‹UUU—57·°tébLÓB)ߟ˜-YÿÔËlÎÍ'صk7Ùl–ƒ»_´B‹ÃY7ãÂD@ !t&#””B=öØC¿ºþúw^¼o_› šyóæ‰D1MkÚ}ÞÙ­ét–½{[Ù³g/J)oíÚGÿKÏO§ •k|¹ŸŽçú¨R¾”¶»víºóæÕwÍšó?´oß³µµ=?„y’Çá¡`ßöÙg¾ÿè£ÜfšÒé†1®}œ¨D °\7ÍfE‰f…RºlÍš³N¹ä’ËßRQQyŠmÛ !ŽsŸÕ“ 3™LoWWç–Ç{øž'Ÿ|z«”â Rn—mÓ-eÿÀ¾}dç†Ñ$%`–––†„qÓT%JQ¢5 !TXJiiœ {ý)BçÒ+”«µB÷K)¹®8ôuww§`ÇãÆ„Ø€J$º³‡¥GBíº" :Ê$h¡õI„@ƒÐ€ÒZ¸ZË´a¨)u¿çù©D¢Ïíî_ËÏßc‚ê*9gVQȲ¬°a¸!Ï3mÓTfNè“„åyÒ3M/ëûVÚuÝÁh´7³^õ«õÃÄ SIÀ¬¨¨0³Ù¬û¦RZ*¥%D&ò~*ÐR*)…4<˲¼X¬Ëmn¦p£¨iׅדÖR)„ïWü À0Úµ”è}ûò­}d®Ý¸1‚ŸbÄw'1>úú'ä÷Äd æ¤à''ãé'q'q'1QøÿÈͨÝÀNIEND®B`‚olive-continuous/app/packaging/linux/icons/128x128/org.olivevideoeditor.Olive.png000066400000000000000000000376221370472574300302660ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aË pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF4½IDATxÚìw˜UÚö:LOÎ3L˜!#Šˆ"ˆº¢ ¬(‹ ¢«"* Ⱥ®î¾¾~¦}ÕuE]1 0®¢’ €¢(”<¤a˜œ:VïªÎ=‰ä ž¹ÎU=ª«ÏsŸ'ÜÏsNIB~k¿Þ&ÿ6¿à·ö~k¿à·ö~k¿à·ö+kj¬'%Ijõ -ZtÄ/jôèÑÒßÿþ÷Ä^½zSe¨$I=eYÎ%I²šÀ•Úáx @Bx€:]×÷ !6jš¶tÆ ¯Ýÿýu‹-Gx¬Úva¿‹8Ö=z´(óæÍ»Âb±ŒWåTI’R³²²¤äädV«EQ$©M×wÌ B4MÃãñÐØØHMM åååhšV©iÚ×^¯wþ¥—^:ÐÇ-L¡Ë³gÏÿ€,ËgdeeY222HHHÀb±üâÔ­×륾¾žòòrÊÊʼº®ÙÐÐpï•W^ù  Ž;Œ=Z4hå–[nù«Íf»5)))%''‡ŒŒŒv=³†¦(//§´´”ÚÚÚj·ÛýäSO=õÐçŸîm ŽøÕüüùóÿŸÍf»5777.??«Õú«wÄ<{öìaÿþýN·ÛýäøñãÿÖZóÐîàüìÙ³Ç&&&ÎÈÉÉI*((h•ŠßS»‡=µ{¨¨¯ ÆUC½«σ×çŧûÐ…v½G3¯!ͨ„„*«¨ªŠ]µo‹').‰Œ„ “ )H.h•‰Ø½{7¥¥¥µ555×_uÕU¯·„v €Ñ£GËýë_3ûõë÷Nfffÿœœ’““›=ß÷¾gcéFJkJÑ„EUY‘‘ Y’dɈ¤èk=ÖÉ-áô!ŒïÖ5]7Žš¦¡û44Ÿ†ŒB^J½;ô¦onßfÏY]]Í(++ûê›o¾õÐC\´h‘~ÜÀ?ëgÍšuiJJÊ‹ùùùÖÂÂÂ&ϱ«f;ªvðíÎoÀ"¡ZTdUFµª(ª)|Õôþ%dÿ%J’dÌN)F@v´µT]„®#t.ºWC×u| ¯Ç‹æ5Žx§u>âôb:¥vjò{JJJسg§ººúÚ«¯¾z^,mÐî` ß:þü™ò:\–“Ýô¬ß\±™U;WQ^_ŽÅnÁb³ XCðÙ¾¬ÊH²9óY–’hÕu ޾FÓºt]7ºOÇçóG¯Ç‹ÏåÃãòàqzÈNÈfp—ÁôÎêóÜ555”(eßÞ}sÇ à A»ÀèÑ£åóÎ;/ñºë®û2//¯G§N±Ñ½½z;K·.¥ÊY…ÕaÅb3…oSP,Š¡,†àeÙèÈ„h Dë¯óX€Àï³?†)Ðñy}øÜ>n/^§˃»ÑM†=ƒ z]@qZqÌóïØ±ƒ½{÷nzþùçÏøè£êü&áp AFJ¾ýöÛ; <øÛ:dtìØ1æû–íZÆW;¿Âê°ŸoÌ|»1ó«EUÂ÷ ^’ƒ&)¨ÇBÀ-KrÀ,a€@è„®£k:ŠOAµ«ø¼>T·ŠÅnAu©¨v•ê†jþ³ú? î2˜óŠÏ‹ú®N:!IRn¸ak¯^½úŽ=z_S~ÁaSÁ‡ |å®»îê<`À€¯óóó“ ¢=Þ5;ù`ó8u'q©qXã¬ÆØU,V ²U ^1„PûþYËé#†)ÇFøRÌïB ¡‹0M k2šUCöɆ¶³)È69~«Âç;?ç»ÝßqñIS”VvÞŽ;¢(JÆYgµÁjµž:zôèí€v8¿ã°M L™2¥`èÐ¡ë “óòòbÎúÕ;Wc‹·a·† _µ©A•¯…&|IBHáŽ×±Î´FË„Ž¥ èø}ƒPm i>a|.^§w£OƒwƒW‹!݆0¼xxÔ÷ìÝ»—’’’š¥K—ž<}úôÝmÁ‘6ò€R† ²&???¹C‡Q_0Ã|vWíÆžlÇê°ÝnEµ©›/«2Ь€b8x~5ïº0#—Ÿ±œ±9@„¾&†Ãj‚ÙoÖü]RL ›ýá. ,ß²œ=U{¸æÔkÂÎß¡Ct]O2dÈš5kÖôXµjU k q .ü¦   ë 'œõ†ÙßÍæ@ãì vlñ6, Ö8CøªUE²H(ŠSÕû0â55èâçqø'Ã/Â8j&O y´ cØhhwg“‚Ä&Ÿ19:|Þµ‹Ý»wÿ4vìØSgk@p¤¢ °¿òÊ+ÿ)**Ëá{yÝËtÄ–`Åž`ÇïWû‹Œ¬*(¦ÊÌÕ9Qÿ·ƒjæ¶€-ô½ºÐƒ@ÐBø¼>4¯a ¨wãªuáªwÓ!¾7¼9Ú·Ú¹“mÛ¶-œ0aŸWKzñH@¬Ó§O¿ò¤“Oz¾Kq—há÷2œ°'Ù á;¬Xâ,†Ú·^¾_íùKR"=úÈc,¦=„‡rþÿu¡4кO7È"Sx½¸ê]¸ê\¸j\ä'æsóÑ Ø²u ß­ûîº)S¦Ì<ÍБð”1cÆä<•õâ+ë_aã~â’â°Æ[Q*JœáíÊV²ÚwÝðâýKð‘~@{ì¡€-Ê?"Àd Y~UF ºÐ±‹á8 ]5»xnõs\úõaçÌÎʦ  àé1cÆ|òÆo”¾£åÈ@ü¼yó>)**꟟Ÿöâ'»>aÕîUØ“ìØmØ »¯ÚÔ@|¢G"Ô}“G!ÚåÌ>Rš  ü¼O7ü·†Çé1"ƒ:ÓÔºV<Œ]G„kÏž=lß¾ý»ñãÇšòGH€åÁüCvvvÿ¼¼¼°“m«ÙÆç»>ÇždÇoÁoA±+ÈV“ÇW$tYGB ÄÐôûgC‚oÖ<Ž[äïÔÑš@R$°€¢+¨š`5Mã£ÍQ”VD·ônsåååÑèl<éÑG?mÚ´9€»5Ʋ-P€„îÝ»?••õâÛ?¾Åa1f¼Ãñb _:’$¡´FèÇ#¤â¢I‡V2ýÉ Ɉ”lŠŸŠÅgAóiÌýv.ÿ{îÿ†'+3‹Î;?¼ešM܆Ùo›1cÆ}¹¹¹)©©©a/.Ùµ„Ñ€§³Þ&#Y$°°Ñe]Òñ :Æ1´{…7ê9Mh1ûÿ?Þzk¯_÷ÿÉzÀ'ÀŠ»bŒqœB­VËâ‡É!99™ÜÜÜÄ3fü °µ†.k­P’’’’³²²&åææ†©þµ;Y¹s%q)qÈq2²]F²êKH]2M‘NÔ ûkÁ ü%¨ÿæ´€Ÿ5 õàø Y€$]BöÊÈÅ£ðá¦é’Ö…=§ÉÍÍeÿþý×›fÀw¸@â~øá?çääØ"+yÿ´Å¡ Û ~[²J ‚®³^Ü‘Ÿ)grmÒµ\p5 5 8œx5oØl5{ŽÇ™ß- cŒ—ÿ¨ Íø_Òª$«¡ d»ŒêPycýaò°X,äää8ž|òÉÛ{KZ@n­íÏÉɹ:'''ì…u×Qî*$5$«a³PƒTn@¥ =ðC/J¼ˆlk6yöÕl¡´¡”¸”¸€Í÷«~Y’T¨ŽúC>ýÎýä;òip6ðøë“Ò3ÉnD ¡¡á¯ª…–—EøB@ÇÓ1´JÈv™;ø±òGº¥ÃÂÌÌLúôés;°Ä¤ˆµC€Åáp$ÇÇÇwOJJ sþ6Ul2˜=SðB:tº®²`¡NžÿomåZòù”U—!â ù X“¬F¤ýŠw,‰‚€CèO%£˜CI• XeÖí_G×Ô®S¥¤¤˜˜x2Ô4¹¥„ÏÝwß=>==]‰dWìZa_1Î".!ž†f„vº/нº7ÐWÖ­Ä£yÈIÏÁæ°¡Ä+EàÕÃ?ó[鿏jB3ÂjÙÔ UðÉ–O¢ØÜôôtåþû↓9gPmÁù‹ËÏÏ÷¯Ü·Ò¾„E]A¦OD‡x~õ/¸-nÞßõ>£;fH!¬w®Çãó «¿òÅÊM™0Y'È„úÞF/Kw-eè C§KMM¥  `$ð’IûÚ¢T !!!¡‡Ãás2Ö•­C¶,_hrÇ/`hÏ=àÔ ø æÊê˸úì«qU¸ð4x~Þ~¤çßÂÿn@2I"Õ,$±È¬Þ½:LN‡ƒ„„„ž¦PÛª,ÅÅÅY6›-QUÃßVRS‚œ(T.éh’†ŒVø@l„ôxçzž{N¹‡Q£ø ì’â’~Ó"#¡¡kY°YÙÌÛ?½Í•g\Ivc6•F(h~æ·ÒEøc=,·8†Z *áÙQ! 4Ét³«:?VüHô 5œ˜˜HNNÎé&”H? 9ÄÅÇÇw¶Ûía/ìoØ $üjÝ_í¯Û¸Ÿ 5aœ¢àÿ6þ÷œ;úÜÁC"¾0Ŧüò嬇;{ó9àâM7Â@!@3ÿ7Ÿ×=:š[Ã×`”‘ù\>v•ï‚`4ˆÝn'>>¾3àh ¬@œÅbISU5,þ¯pUÒ•º¬# 9jöGF¡³?@ö¨P•XŃ_?Èg<ÀøªñÌ?0G®ã¸ö )ôðÇó¡³¹Y  =•"à"Ay}yعUUÅjµ¦ú‹™ j °X,vYBµ»] z£šd˜€XÙ¼Hé ›ÄÞytÍ£Ü}ÆÝøüK.Åži7 #Ú³ª6ëùB <3úpMÚ!Ôø'•¬² ²¡2ÜÉ“eTU3M€Ú@•eY,#jô6"]hèBB€ÈB&ø6n^µþcSi]9Nâ‹êÏyþ›ç¹}àíÔ.«å늯°¥ÚÚ„"èu> dÖûËÉ­¨@CBèÆctê=õQÚÅ”£%VbHm& P$£…½àò¹L t] ét¡3?4 „-ðüJ‚Ê[•o‘µ)‹¿ý7î[~k+×bM±ËƱeZ29Åq ÝâºQ`/ ÖCq`Sl4ú©rWQå©¢Ú[M¥»’Jw%{÷°½a;ûÝû…²tÌ4KS5Æ*#¦ëhæZD—ÇÅšBTÚHfˆU4êÖݨ¨øL_B`Ì~IHÑå]‘,`K‰”…ïù7S:rÿûy資X^¹ÜÁ!h‚“âObLÆú&÷ +ÈmÕCuŸóu§ÏÉöêí|_ù=ßT~Ã÷õß#,âè"†ˆ<È")˜>öø<±ü‹€<µ"(Ð|Âg>fÑ‚ÿ‚üpSЄֺªä4™ië¦ñZòkÜsæ=8¾tðnå»XS[AŠ’Â‰Ž)²1$}ÙöìÖEœG¯Œ^ôÊèÅ¥\Jec%on}“·Kߦ^©7œUé( Æ1”Ž,%ó _›¾Fm!ÕtÝ s¡–AG GÆýÍ9€M@J—˜úÅTfž;“;ÞAšæ–ÍÅšn5(è–¤$qNÊ9œ“vÅ ÅMÎô#ÕÒi\ÛçZ.í~)O~õ$T~€êP¬¯«D,†I,.K+åÙ¢ˆªÉ—‚3ZÒ¥"ýƒ™:$`¸,%q%|°íÎíx.×vy›óxlûcÈiF!D’’ĸ¬q\˜}!6ÙvÌÃxk<ôWøÞ­~KŠåˆ‚ Vet,3àY¤ðúÊÃÕ1›?¡##£ - pIÄ6‡ @Ø3÷Îäw~GU}#º 7!—»¿»›þú3µx*©ÖÔÏãñz¨¬­¤¢¶‚ªº*TU%ÎGJB 9i9Ø,Mƒçæ'n&#=ƒ¢¼"rSsIOL'Ñ‘Hœ5Ž„¸Eaòé“™ÿÂ|â-ñ¨‰ê×M™ƒP3H¸µq‘p›5€®ëõî’tÉxÜÄB@`ÛÚªycË\ÚýRÖï\Ï)OáõÌ×±[ì(’a†Ü^7®FªêªØYº“vüÀê-«ÙSµ‡ŠÆ ½F½jdÍüΛÐ’.Ñ!±ÅYÅgÓ1³#Ù)Ùä¦å’›–KZzs×ÏE-Q>îÑѽ:Â$w$Ežk7ž?R¡a,†0âV0*U  ›ê_7âQI—y€(-p˜@Ù{gsaç éYØ“9ÏaÂ9¨sÖñô»O“–ư>Ãèšß•´¤4ŠòŠ8§ß9!ØY¾“ÿnþ/ó7ΧZ®6ª(RСZ«fk «ö¬BûICwëF÷èÈ6{¡k¦á€úù€`,nü^Ù*ƒ 4];bˆd£º¿‹£­BòÓ’07k![¥Ä ‚ @¥TÉ+_ẓ¯£·þÜòÜ-<>ñqþ2ö/<ºèQÎü|òSóÚm(Ãz c`÷XT 2;19s2“O¦ÆUÃÚ²µ,Ú¹ˆµµkñ(žà~ƒÂ$z|ƺ<áAK’„ì‘ãäí{h´sD¹€fÌAd½…ß)<Š@C2ºÐ ÐT£‘ 9\M ¼ÝkD³·ÿ‡qÝ.¡{AwRSÿÌ8ž»úyîºè.N,:‘{>ù+¯í}y[çb™oåÌ‚3¹ Ï ?e8q¶8’íÉ +ưÂaèBgkÕV>Üõ!Ÿø”]žÈ¬ [¥˜³@Gè»Ö„ˆŠÌYo5ô6j ¹5 ¬ÁD&tt!ÐB‡þH]×ñº}xê¼xê½xÝ>ƒåB§ÞÒÀ ß½À çO懲 \4ó"Öï^Ïïûüžù—¾FaV!ÖBRW‰bÓVL£×}½¸uÖ­x5oðGK2]ÓºrKß[xëü·xë¬E\Ÿwå¢àwŠã£ûÇ\7‹2;,ÄâtݨÞÕ4Í@¡¦V×ܾzžj¾c§ŒÈ÷óKæSVWF^zçw=Ÿ2ʸlÑe¼³îºåtãõ1¯3(iXÀ’mÁÞÙŽ½‡]rÓ‚›Â@ÚNH9I}&±à¼,´ ™Hu§¢¹Œýý÷÷‰.4ÿ6´±_ ]b~T5@(éàw©þMÓñ¹}x뽆Ð=Z“ßå7)n«›ûoÆôƒÖ¨¡%kLûrÿøï?H°'0ã3¸¾àzôz, ¦ªXr-|¦}ÆÔw¦âÓ›gʺftejÿ©,ùÃ;ñ1ú¨}МZ˜×ýs÷Èò°ß$5@,Á4ûáGÝ«£53^w™èmå2¼¹ÿMvUíbp¯ÁÄ»âÑ55KeæÞ™¼õÝ[Ô4ÖpË™·ðô€§±×ÚÑ=:È 'Ê,©_¤“¨i¨i9øÎ+>9ÌáÅÓ_¤³ÞÍ¥EW<·ƒ¿XDÑÓ±<ÝÀ,Ö[ß5·†·.8ÛÛòÙÐçüŽçcU­(²Âs—?‡£Á¦i(© ÿ-ý/ËZλ~`H—!¼7ú=®É½† _ºWGrH|áù‚‘/dùÆå­þÍ ðú^çÖnE©SŒë×ôCû G°‡:Z¸& íTpˆ „8JBŠŠÿ…h- ÞõÃt£/.¸˜û=ø`÷ÌO™Ïï^AuB5_i_ñô¹O3þ©ñ\vÚeŒ4–ɧN¦ûÖîÄÇdz¾r=ï–¼Ë6mWý÷*~6«O»š³zŸ…Umþƪ¬rÝi×1ä„!Lúh¥–Rc=¤t”£€â’X¡` *(´tüh†ÐÏ Y—Ã@a0f¡‚*=„vMñ5Ñ6;§+/ÿþeƼ9††Ô¾Þÿ5Óþ01OáûÒïùûè¿óûž¿çù¥Ï³­rÿø44^ßü:oo|›«ß¾Û<ýsúÓ#§y©y$Æ%’ŸL÷‚îœÜÿpWé.víßÅY‰gñê¾WQÓ½EúûåághÛº}Þ!Aþ™F™¥y4ƒH‰Q t¸h*_ߣCþ÷´ÿåÎUw²¬d÷ º‡ÁÝ3kÓ,6VndƸ\7ô:–o\θãè’ß…‰&2íši,øa³¾ÉpÉK(Î,¦º¾šu;Öñä{OÒ½CwÆ Çï>Ì K^@IQPÓU,,Èš•™å%ËÑt »ÕÎðÎÃñÕúÐ|BÈÉ2››ùó리ºŒ›Îº‰ø'U5UŒm¼±²¦‰V˜Qˆ÷ ­A;ö±~h¼ÁøÁÐVðЩ`Úæ˜IGG²K<óã3\8ãB>ùþêëpy\¼ÿåûLž>9Q¦^©gí¾µºê#vÖî¤Wn/²â³Ð…N«fÜìÀ£y(­+ewín6•obsåf¾=ø-›ë6»wH‡©bÑÁ¡@'ftpT©àÐ/mÄvNŽUKKz.9>™¡yC™·zþçÀó]òº Õh83Lxk§|L·Ün4ºyþ£çé‘׃^y½(Ê)¢·Êµ*V S )L)dPá ÀóUÎ*>ßõ9íøˆ%{–P­U7±0ë šðÅÁh³Є†‚–ôç"+‚!JH ùX5«;»wjÇSyô¿2²÷Hzæõ4JÏ«¢»…îd7Ò:ðù¦ÏÔcÛ÷oçʧ¯DW»wtÏîNÜŒ:m#NaÜí,¢¥Æ¥2²ûHFv‰O÷±rûJlZÀ{»ßÃ-»Ãn–Ñ*ˆØÄS,³ØÖÂÛ6ûa³¾÷ŠÆŠØèr* \ôÒE|ñÓ¸½n¦/œØßX’%â,q|¹åK–¬]¨ÓGñè•¢¤+Ð6Ù7ñFéüiþŸöÀ0öUìk1<´x(ÏŽz– ×lào}þF.¹±ãÇ!ÿFãqD–ð¨U…¦£ÂA!bîŠq¬ûΪ1¯¿(·Ý¥S®—3röH²&gñì—Ï¢d;÷Í4ní~í9×rÝ3×ññwsí¹×2eДÀÂU%WA-TÙ o`èô¡|ùã—­»D{"7¼™µ“Ö2kØ,ŠÕâ`UTKá]¬çCYX!ŽMàG˜®é‡FY£þ}é÷1OJB Âm¨K9]Fí¬Þ}ŽVxdð#¨²JJ| _<ö¼ý+7®ä.üÎË8Ï l %KT$Vpᜠ™þþôVÛ^EVÑs+&®à?¿ûÅJ3@КC¿Ý<â¨'ƒüê&òÐzþö`¾(ù"æå;ì#™£™,&ÈÈÉ2’Ý0ʽ3ƒ·qÏMËeñ´Å<óßgøjËW¼xõ‹ôTz"Lõ-Œ;yè):÷­º‹þu%e%­ó¥tÍ»6s°ô ERz­nlßã·´4¦¡kÚªim ,äÀÒ0uPäûCK“Z‹Æ#Ù––,Å«yüv¯ÏÉD´}5û(L- üogæM3¹äÿ.áË`îĹ yrÕR5’Í\Y¤|ÄŠºœö§1eÀ.|99i98]NʪÊ(9PÂæ]›ÙT²‰M»7±a÷| HqrŠŒœ!£kzðŽmÍ„ÚÿHáö(:jL ù%aNˆñzä #]y¨­Z«fÅÖœÓ휰ç]áƒÑÞ\ÿ&·u[¸Ö°9xnòsŒ|`$¯Üñ Ï]òã_HÁŠ äx¯êåѯå‘AÔ ÃÙ37h‘¬ÆîÞ’MBÊ—°X-­ö%«±¾2pM­IýFj#ïÄô ©F%¼X$,æ°Gm­g?¬. mZuý Îc}Ÿ{jÍSTÔGGyyÜxþüáÑ?Ð)³ÓMC¯1W G²“i2j¡ŠÚEEí®bénÁÒÕ‚Z¤¢tTP ä\9SFJ‘Œl®KoÃ:€[óU'Pr˜­Šå´Å~µ.àŸÞ¡ÁÝö{<^9a¥˜Ÿ«öVsãk7Æ‹ C'àqyù¯‘\>ðr~_ð{D½·Ý 'í’AS§)È©²¡æed‡ykY ÷©ÚÒµ>€ù|`™þ¢‚E$ea‘-xð‰ ݼ°÷ÈŒ±PäXµZ­–ùkç3qàÄÀsõÎúÀ¾†1G†%{–°|órÎî~vØKq¶8†÷΂m õì(^¾òeòÖäaM°Ò+§{jö°dë† eâ©Is¤±ùÀf^ýæU^^÷²Aµ†Œ0a>€A ‡ú€M±5wƶia´04Y‹±]©Føº@s ¿`¡]¤H<÷ÕsaköngM…­Á„ùذ{CÔ˜ ê6áloÜÎíoÞN¿‚~T¬fÊËSXúÝRžõ w¹›¬„,TY¥wnoñ0Ÿ]û§$œÒª¸¿Å°ZD„Ø!ûZk,SqHº®k‘ŸMT áûxMuÒ…f†H¾Ç?W×á§êŸ˜·z^P+Ô×gLSŸP'ÕñÇÿȾÊp¦¯ç f(à›ÊoØx`#^·—»~w_ïøšÜ¤ÜØTvÜø“{N†zbŽÜÂŽþÇMõˆÏ'XbwÚ!iÇãÖ´ðE›©q©Á™nî¶]I;+’”d‰>}€ªú*#:¨IÌ´ð¹ýb?cžCƒ+èGf"\†ÝØy Θ@½»ž…kòȘG˜ñéŒ&ÇÓ¢XxxìÃ̾x6 Ao…—ßÂë¡laZ|Z˜¼4MÃãñ4ya¹9º§±±±N×Ãc¥ŒøŒ€ê÷›˜³© &tk™cå –ºK¹uþ­! H­p¾„AmjÜÄø$²v‡ÚùàσÿL—Ì.Œè=W£‹Gß”â¬bnq+¥¥MaT¿Q,½i)´wHN@k‚äiÅïô¿/+!+Š·ill¬kŠ&jZeee©×¾¦¾0¥0àÙl¿/ºF.àˆæsǤTJ†Å[sï‚{»jX‚iÖ–ì-*¬([Ásî@AR|RÀÔõËëÀ¥g]ŠCw°§z Ž›ôï¬z‡¿‘ß® rç³rÚJú8úý‚¶æRüû›Ì¦Ð'¤ŸN|y½TVV–6Å4h€oÛ¶m?žtÒI}ãââ‚60»'ºÏ¤-CUJ²„¤IQÞmÔmà#ŽÇ´Yà©ÕO¡×êH‰’Q°¡·þ³3¿›IçŒÎ\3ô#ªÑ‰vãf’$1qèDn{ó6Îìr&Ť“ø±ÏŒ¸wn¯›sûœË žƒèÛµ/:t"-) UV™Ø"7½~ršyÃíäY Ký› _÷îÐ;l|Ýn7[·nÝâu´®… ~~ÁŒOII ¼Ð'¯qrNŸÓ`Á4ã¦Q²$ÇÔ'¡ØOøgº5 glÆ=÷Úr’]âž±)Þ»Óë$ÎbLŽ!' AÌaõÝ º±âñ ÿÃY¸y! 6,0ü5’MBΔW#S½éZ€€Úׂ@p(úö »n§ÓÉ‚ >£‰I7e<€³¢¢â ÓétF:‚]3» ˜/\ …ýïßNMî©ð„ôóC¦àôm?+;d^þ0Jš‚d‘(¯+ XAvzƒÎþªðõ‹2:ðñ}“—–‡’ª æl ÚYEí¬¬`’¹w¡Ö4ÙÓl´cF]sºF9€N§ÓYUUU8M-Ð*hæjËÊÊöFúgi¬ éºOo2My¼‘´R’q“ìí·U©ª‚ÖlY5˜Ù©Ù|r÷'¤‘fÔ˜H9E6„o¤Á¢jÍ€!"dÚsh”ý/++Û Ô±L@spuß~ûí7N§3ìÅ û\h¬òwÍÔ}!;h†h‚g µ^àHt3DDÀÖÁÛ´•W–ƒÏ~ølL'?3Ÿ§}ˆ½În˜VÌèæ^>#ñO@• O¾0Jýûí·k:Óhm‰Ü@ÃìÙ³—566ê‘^þ¸~ã‚ ð…tsëM îôé½¶º˜¤÷;¶~ëz`õÎÕÜñŸ;p{ÝQƒÚ­ oMy ½ZGx"¼y=ÜtÆHk¢ûÂÍîèSFGEb ú¬Y³–aPOî¶„˜ö¢^Ӵʲ²².WøªÜÓN8Íx‡àÑœíQ?"4¤Ñ~9&aË-ñxåûFZ×"ñâªpçæ<ߨ?¥’{≱O @šáb>‹!ô€.¾Çår±wïÞ=@%Æmc½me}&r*Þ}÷Ý%aè:©à$ÃôŠ : nHùrdÛ/¥½ëk„4ºy}ÙëHqfnß&±Õ½•‰³&R|U1·?y;_mø*0°Wœ{£ºŒ22‰1Š<[ò›¦ÕÔÝr»Ñ·°oäìgñâŦ}m€ß¬~çwV×ÖÖº5-Ü„Œë?.löG1â—Ý6äµïpÏs÷pÐy9ÞÜOX2@ ¤*TÆUòÂW/pö½gStY“žÄ¢e‹P4€49Í`C+z„ˆªò <ŽŒ̱Ÿpæ„pÁiuuu®?þø ª)°¥t°0Ájàà_|±fäÈ‘ƒCï$:¤Ûæ~1—mÕÛŒE›f.ZR¤‰d~‘w½lÆeèU:RºqFQG€`’8sÍb¼ÌÏæ~?—W×¼jäîã$¤$ɘ@R3å_ÄßùÃ2;1¨ë ð¢—†–-[öpÀ”Ÿ«­¹€P? 8ðÌ3ϼW[[ë‹än:÷&ƒ÷ì¡^lS±ì/Ä,’q“TsèX÷IŽ`ýŸœ.#%HF   õQRˆÏ%<‚ëϹ>*ö¯©©ñΘ1ãà`sê¿5ÐM¢\Ó´}ŸþùÚ††ð ›>ù}¸âŒ+ ¯ÖL’øÃ¾¨p¦9bãx_¸Í‘KfQR̺@դϛ¾ç|-Ÿ1Ö—œy ý‹úGÍþ/¿ür-°(7å§*üá`°ï‰'žX\YYév»ÃCœ«_EŽ#¼D;„M1¶Tàx¼û±~‹;•Óé1?_°#+1‹ι!2}OUU•ç‰'žXl º©ð¯-E¡š©FJ=³fÍz¯¡±!*æœzÁTC¸M"ÙCL'±…†Ö@´‹ÞÜuF>ªÂ5ÑªÏ Ÿ0ÆÔkŽ«W0uÔÔ(4:Y°`Á`¯iÿë›rþÚaFÀî>úèËíÛ¶ˆ4};öåò—¦ÀtP!RÍ·¦Ä¹µš¢=ôæ®MDÇõe\-C ‰dýÆŸ9žS;Ÿ¥úwîØyðÍ7ß\øãgK…â­- ×L:q?°ëþûïŸWWW§Gæ®>ûjúwêoä<´pKKÅšÛáxéM]wH _«ë%C?ÍØe]xý:÷cÒ¹“¢8ÿºº:ýoûÛ\`—)§Ú–f[à÷Ê’òòò-sæÌù8–)xhÜCœ˜{¢1ûÍè ` šsúZ¨íkw½õˆ‘µ’¿H‹á6Ç÷›ãØ+¯ÿ¸âÑ”oc³gÏþ¤¢¢â' Ä”“»5ËDÚ²0Äï ì¶/Z´hùêU«·Õ××G½ñŸWþ“^¹½ö* ±¢‚¶®€iOj¿™ëŒb@[c"´pÕï¿zðäµOFu}}=_­ùjûâÅ‹—;€}­±ýÁ™«È;†G&(NN~á…&&ÇÇÇG½yêì©|¿û{ƒU$ãþÕþ»pû7Iø…Caë­{Zý¹à6$ìë]Л]û¯¨ïlhh ¤¤¤fÒ¤IÏë€õÀîæB¿Hy·~ö0è œd³ÙN~饗&fffÚGÔ›ï{/k¶¯5þ™‡.’ŽK©·îµ¦ë„qBˆ( Я¨ü鑨Ó766rðàA×ĉ_r»Ýë€ï€í@MsÄÏ‘€Xt 8)++ë”éÓ§_ž––f ­ô·—?}™WW¾jÔª1@Àq„æÀKøMì÷ˆÌ™éK™ø»‰Q§t:TVVz§L™òjYYÙ7¦ð·š‘š§9h øÅd²€®@Ÿ¼¼¼¾?þø%©©©–Xš`ÝŽu<¶ø1Ô0@ ì¡Ú@:ŒÜh§`±…æ„?+)‹;/¾“SŠN‰9󫪪¼S§N]°wïÞoïŸLڷŰïH $ÕA6Ð 8133óÄýë_cÓÓÓm±|€—–¼Äü•ó CªÌøîP0ˆv¬D D:1c¯%?<î¬qL:RÌÓ544PQQá¾í¶Û’u s€.@o›ÍÖuúôéc “šÁÚmkyþÃçÙQ¶¡Ã)”#´€d®à•Ú‘‰­|ˆVùQ¥Ý¡¹ :fwäúó¯çÔ.§6)ü’’’º)S¦,p»Ý??[L†¶V¹i`Îc‡ ‚b 'P|ï½÷þ~À ãìqX,–˜\öÃ2|¶€-û¶³ßÌ¥‡ùR¸ð¥öª "îÜ”½ÝÉÝX rÉY—0´ÏÐØéX¯§Ëɪ/W•<ðÀï›¶~£y,m.×L°hÑ"FíA&PtŠGŒqê5×\3 !!AŽå†ú_oùš×V¼4²sçí"¶ÚÜSiìÙcéßµ?};÷mòtN§“úúz}æÌ™«Þ{ッM¡o¶™6¿MÂ?jü °À ¦sX”žžÞù¾ûîû]çÎSív{“ÚÀßÞYýŸmüŒM»7áô:Ã@fÚ³ÐCxS1Û-vºçwçÌÞgrဠ›=×ëÅår±}ûöª¿ÿýïUUUí0…þ“Iõ–®E‹i£G¦]À Ø€T Ïä Š€Â#Fœ|ÅWôKNNVãââZõëw®gcÉFv•íâ`ÍA*j+¨wÖãÖÜ8]ÎcºÙDK>„Dœ=«b%Áž@zR:Y)YdЫ°}:õi•pœN'555¾9sæ¬}ï½÷Ö™Ôî63Æß‹‘šw/Z´H7ǼýÀ¼ ?O`F'ÌcÎäÉ“O6lXqBB‚b·Û‘e™_{Óu—ËE}}½öé§Ÿn}öÙgW›ö}—Iïî"˜Þõ,Z´H„Œwû@3LL:…&:ȲœyÍ5לrÎ9ç%&%Zì¶–MÃ/±y½^\nuµuÞO>ùdÛÌ™3¿Ñuý Ÿ¿Ëœýû¦vµPá·[D˜¿6Èr1òyfÔ:xðࢱcÇöÌÏÏO¶Ûí’ÕjEUÕ¶F"ÇY(>ŸǃËå{öì©Y¸páÆ•+Wn3U{©©æw,éòÏz½‰1n¿ˆÐ6 ÉÔ9¦VÈ5#‡Y–“FU|Æg&;â«Åƒ¢(H’èǃ C‹4}>¯‡Æ†FoIIIͪU«JÞ~ûí­º®×bV]›ßg‚ #ŸïŽ5ë+4aLG1Ãô2ÍÇ)ækŽ„„„„áÇwìÙ³gFnnnRRR’Íf³©ªªJÆ%JíRð€ðù|ÂívûjkkÝ¥¥¥u6l8øá‡î¬7rçæ¬®6gøAÓ¾—›Z ¾)uß.p-T#ĉ&R0L©ÙÆD“[p˜á¥%„4þ¹9ÁV‚èU|.SèUU5¦ +LT™Ï7\À)Ž2HV„A6kÑ !ÀH2{¼  m¿÷ÆÏÿ*>—)ØZ³û]2Ó]&PtŽ½ÕžK+¨¦m! ˆ ¾r@ 3DØnÂÔS2£½ )@(fZAp<„~Ø_äå!l‡ŸÝOi¿µ_Oû†û•·ÿ?5Þ ¼>k|KIEND®B`‚olive-continuous/app/packaging/linux/icons/16x16/000077500000000000000000000000001370472574300221575ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/16x16/application-vnd.olive-project.png000066400000000000000000000012411370472574300305340ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<IDAT8u“MOSA†Ÿ™Û{¹´¥JiCI„01º«!&jt㈠*ÄÿÆA­ q[Ý©èÆ6µD ÃGHÔP¨3sï…RÚú&“œÉÉûÌœ3gÇZYY©(¥J µ×u£ î,--½êΉ“ \.‡¥RI !Θ14 jµa*!ÄØÂÂÂÑI^vÃzÍQE®ë’Ë冴Ö/»ó²ÏÑ#!Žã „ X,âûþíJ¥Ò)õ ˆ _ö?žxž‡çyH)‘R2??/|ߺ¼¼<Úp„ƒLçÚí2<ìsR^&“!ŸÏ{ñxü@¬ µf*>ÅÚÞ'.¦/±×Úau÷ g„‰TžjµJEXk‘RÞHˆ$ë¿ê<ùú˜Fs‹Ë£W($ dG'¸06C«Õ"Bêõõþ£1Fq3{‹¦nRÌ\e«¹ÉûÝw¤ýÉd’T*E:}nð+h­ÐZ¾ðñðÈzüç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÀIDATxÚt“ÁOg‡Ÿo˜] K]—nKk‹SÔ±§1ñØ“\ˆø Lô† ±´iÚ 1z™Æ&“M–&°@14Ž h‚‚ìº3̸ßÌ÷}­)ý%ïñ÷ä}“÷ìÄuÝ#À¯@/`³wbàðƒã8ób§<Üèììmmm!ölcX__Çó< \rg\¸®û-0Û××'æ^Ì1³8C¥VAf§ˆûZöq¢ÿƒ_²¸¸h€Ã6ðSGG‡¸¿rŸÐ„$_&ä÷ç±ÒÖvq›€JÁfÀ­ù[$&a૱²²ò‹ôf³YJ«%ž7?§±½‘z¾NüYLüùδǨ/©îÍ=ÍL?™&—˱[kÍËôK|˧¿¥Ÿåh™Wòç ç8™=ÉF´Á½÷(­—ÐhüÈGk ²”R¼±ÞêrPælëYŽŽÓ ˜]žeâÏ ¼Ð£ñÓF¬f‹ˆ¥Ö. Ö¨nV)¯•ɘ W~¿ÂwHÇi†º†Â?öñ¥Ï–Üú/ ¬†µ¯â1<5ŒT’îB7¹–Wÿ¸JÝÔ‰’ˆ0 ‰Þ~Øàý õ­:Æ7(­PFQ5zÛ{YZ]bô»QÒŸ¤9vèM0¹0‰”òc€ÞÒ¨&E¢ oÓc¬4ÆÁôAnNݤ!ÛÀ³ê3Ð "ñ QJÙyò”7ËÛ¿i`M¯1þtœó=çY­®R¼\ä@ËŠ‹\Ÿ¼NÇÒA€Óå 6º¢ÑU®iŒ4Üž½MBBůÐs¡‡‘k#œê8…ïû ÂuÝ£ÀƒÖÖV«øw‘»ïâ½öZ¾ÿB4¤’«ÀéoNsæè¤”ƶí¾]™.?f2ÑÔÔ´·†qŒ”­5RJ \pç7ñ/?@út–Àð½ã8ÿ¼XsГHË•IEND®B`‚olive-continuous/app/packaging/linux/icons/256x256/000077500000000000000000000000001370472574300223335ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/256x256/application-vnd.olive-project.png000066400000000000000000000665561370472574300307340ustar00rootroot00000000000000‰PNG  IHDR\r¨fsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î< IDATxœì½wœ$Wu/þ½¡B§éÉyfgÃlÒi•%„$°™²@Ø€ ïl†gaØ~ü~öó³Í'0äg‚ #´HHByµ«MÒ®6ÌNÎ3=Ý]U÷ÞßÕÕS]S=awvb}÷SÛÝÕ·ªnM×ùÞsÎ=ç\ B„"Dˆ!B„"Dˆ!B„"Dˆ!B„"Dˆ!B„«d¹;pžX­ýް0¨åîÀZ_î,¤Ìû°ÏV'føˆ .Vºà„ =)³?Âê‡ y¯Êì°XÉÂø°Ï¤£pœ}æΡN*~ô„^>ûI!Â"`¥ )³ÑÖV)Al»Ž*¥H)‰÷>Âê!DQJ•û: 4 ²««H \¬D¡™!ôhs3¨m×Q!•RR)%M¥Q DJ÷5"Õ Bˆ"ŠR¢&& c‚R*cÒ0DWW x¯@DŒ•&0Aág­­ ù|s‡ !X<.™”ŠJcRJ €†¤ ÔÌû‰Hae‚¢¦ßCBT.G¤«äcDd³ÌaŒ MÓD__ŸÀ´6‘À"a% GبÏ,«–Ù¶Íc1ÁÇäRJ®i‚ßrËëZ¯¸âª_I§«nÔ4ÞN)«eŒ¥–÷",”RVWW×oþóŸþ¦QgjŠ9š¦9‰Ä€sêJ5ˆ.+…¼~ÐÂ{ÖÜ –ËUsÛ¶µXLrÇ1tMÚ5×¼¢ñõ¯ÇÒéÊ;±º¦1#,J)ñè£?¿å›ßüÖqMË[¹·$戰@°åî@%#k+X>_Ë-ËÒMSjœk& Œ·¼åí—¾öµ·-_Sha‚B[ZÚ^ûâ‹/|kp0ㆠ˔J«L&³ÜÝ[3X Tý™aÔy¯s®¶ÍÍ»ï¾ûŠë®»á«Œ±Êåín„¥¥4¹gÏÞ<ðãûGWPÕÕ951 Ô°R´ÙU…•ðG+þæf°©©JÝ01ݰ,;vÙeW4½ë]ïù'MÓý¦R)lÙ²õõõˆÇãÐ4mYn`½@))eñUJwš^¥TÉþ`[ÿ«¿wާžzªìu_zéøÇþò/ÿôûŽÃó¦iå²Y͎LJí®.øƒ‘)pX)õ6è屘­Ù¶©+嘔2ó}ïûàÇR©ÔÕþƒvî܉뮻5550MŒ­„[YÛPJ•¼zï½Íÿ9¬}ðUJ BÜ1¨»»»ìu«ªªo¶mû_OŸ~q¶ueÛ¶R*…úú)5: ý…`%ØÑÅ¿æfP!uÅ4ÍÑ8çÚ¾}W4×ÔÔ¼ÑÀŽ;°k×®âÃá⣜ð{¯Þoá½÷·›ë|sµ%„h·Ýö†¯¤Ru1MstÓšã8,“©ãp1Ïy ¬ ­vÕ`¹  $¼W)%ÂdR*&„Ô®¿þÆWBtï€D"]»v-Oo#1!”kïÇl®ëzÉgMÓ6|ìcý´ãHÝq Ý4ÍqÖÜ\Ôƒáâæå&?ˆ”u$™”T)E…\JÅëëëJTÿ-[¶D#ÿ2À?ª…¹Üˆl?ÍÀCkkëŒß¹ªªú-ïÿ‡^͹ÐmÛÐãq‡çrÕ¼µuÚ„D$ü ÂJ €bR‚ ¡¨aH¦ë:UJ1ÓŒmô7®¯¯_–NF˜†_Ý÷¿ú1ß}åÐÐЀ͛7ÏØÉ%»ÿ÷õ׿²‰sGÏç ÝqžÏ×±ŽŽ- ˜1¡ Vp3ú”šŽé—R1¥eŒUùÛ%‰åêb„90›f0_SÁl}}=êêê‚ûcozÓ›ÿž±„áùlÛæÙlƒëˆL`¥‘²¹@q"¥¢î{N9ç1CΣ࿕„…Úû iOÁæÍ›ašfÉw†alÿä'?ù±‚?@3MG³,‹ü ,+…Š($ï„ó•׿á˜ÀÃ|}„pαcÇŽþ€ÚÚÚwÿú¯¿÷ZÎ…á8¦;ܲjYäXV¬€…eöEXùð;üÊ}7BŠCÉd›6mšÑä²Ë®øâ¥—î«åÜÑ-ËÔ,ËÒòù:ÿ´`ä˜+!àj®ð«Âa%a©f`¼ëd³Y@ss3jkkKÚ0Æoû»þÚq„¡iŽ‹InÛ6ohh’‘@(Våî¯Ì6ÚÏW „ÀqX–B¶lÙÃ0JÚÄb±Ëî½÷³ï³m¡Û¶®Çã‚üa$!€EV.¢¾/&!ÈårRBÓ4lß¾}F›–––ß¹ë®w\ªiB·,wj°àðH "‚2ˆ Š¥´¸B055¨¨¨ÀƃÍɵ׾âïÚÚ:Óœ;ºiJͶmùæFDæ…刾ôò <‡`>ŸàúªªJÂCÀ«úÀþÛ_8ŽÐG/Æ44„š °n ÀŸ’*„€Žp ¤(Ii]ÈñÞ6×±¤šy}üÓhå®5ßm¾}Z,ÌFó%ÆX‘!°, ¶mƒRŠ­[·ÎHÿŽÇ7|âðÎ…î8† nÛÕ,ò”Ǻ‹ªñ²Ï²¹,Ξ=‹3gÎ`xh™LRJ$SITUU¡­­ Ú7 ƒR:ãRJñ8Ž>RÜïÍo3ÆpóÍ7#™LÎ8Öƒ”™L>ø „ÅvJ)PJ±¥s ¶mÝJ)„xö¹gÑß×_¼Î|îÑ{ﵿîºëPYYY¶OóÁ|Id¾É?óÈ,ùœÏçÁƒ¦ièììÄ‘#GJÎÑÞÞqïí·ÿÚ?úÑ÷[–!m;¯(­UƒòÔ©…CÖ}*ñº"OpOž<‰‡ö?„ɉÉâ~“““èíéÅÑ#Gaš&®ºú*ìÞµŒ±ÁB€€àܹsÅ¢(¥èëëC</Ž^aýèîéÆÙ³gCe¶nÝ !À²,ôöôâÌ™3ÅïƒíË}ö¿÷œia}Z,„ù̶o¶  r»\.‡X,†ªª*477ãܹsþ&ì–[nùÒc=vËØX¯ TÊ|Þ–™L¼6þl]“Àº1”Rpû÷ïÇøCŒŽŒÂqœ’Ͷmض]|ŸÉd°ÿ¡ý¸ÿþûaYV‰ +¥N§a˜FɱB8Žƒþþþ¢‡AÁÁ’c½k뺎d2YÉÇe[3Ôz¿ƒ÷¼')%lÛ¾hf@¡”ÛFåÚùM¿?À²,À† PQQQr,c¬ácûèÿ´ma¸©Ã‘? Ö(¥`Û6{ì1<õÔSpg†=í/[å0Û¶qøða<ðÀp§øðRJ¡ë:ª*«ŠÇK)‹ç*iÖŸb{¿_U]Ó4‹‚á×ë—ŸlÂ6Oø½~ù÷/6ÌWðç{¬ÿ»Ù6ïþ7E>H^?‚û<ä|3çCž†C)ņ 0>>^ MÓÚï½÷ÞO}êSÿ”†0MKæóD57Cvw+ ¬SXó`Û6Ž=V"lÞCµyóftvv"•Jç”-Ë‚išÈd2xæ™gJÎÇŽÃÞ½{‹`ªkª111Q2BSJ100!8ç%€CCC3œ„„TUUÁ0Œâ¬ƒ×Æ3]”A<GMM 4M›UX8ç3ÌŠ…b®Q}!…AçCóí«mÛÅ¿qgg':Tò·­¬¬|ë>ðÛ?ÿâÿò?mÛPñ¸%³ÙjÕÚ:¬ +¥ë ®¬i€§þ¿üòË3l|/®¿0M‡ Æ ”×8’É$’É$‰DÙÍ4MhšvA1@øcØè?ßsÍ5Ê{$0׿8(¥ˆÅbèèè˜qmÛvþÙ•W^Ý iB³,S‹J‰¹X³PÂd³Ù‘uUUUÅ5¼ÑÜ 01Mét5µ5PB¶m£···x.MÓÐÔØTrMÏkßßß?cêÍ?àoï†MÅÑÌ/aÎJOðbæ½{Û.däÂß/¼ó9÷\äá‡çÿ˜ðûI@)…ššš©Ã”Ró®»Þù”23¤”غ\³LÛÚÁQ³8‡o%ê¹ι«ÚWU—<ìÞÖÛÛ[tÞ1ÆÐØØ3f–'!Ùlƒƒƒ34ƒÞÞÞRò„Ù0 4Ô7Uõà½g(”RE¥õböø&À~ÌÐÔæ"ûùnþ•†:::ÇKΩëú¶{ïýìG ñþRbaõ×Ö,xB266VòÙ{°R©T¨Mì=LŒ1$SÉ«”ÂÔÔTñAcŒA×uÔÖÔ–÷0öôô”˜RÊ¢Ñkjj ëzè*Gå¦(ý÷»T˜kô.7Òû÷ÍGs˜¯ú$B(¥Ø¸qãŒó×ÕÕ½çž{Þ}•¦ }ŽRbë‚Ö,(f§ÏwîØ?Í¥136sÄ…;UèwÄqÎÑØØXüíýÂë™Á„#Bêëê‹öðÁõ4€àqåÖÛ Æ,AøGï°ýAÁöÛøå´‡rý &-dó´³x<Žööö·qå•WÿÍöí—Ôx¥ÄÖsêðšžÜøwþ‡-ÌÎöà \ã3öûIÅ;缸Elúúúà8N±’”²h–øûEA[[[¨IâµñÎí7gž}öY?~¼¨5„©Ø›7oÆÖ­[K¾¿P”› ˜k*088Ÿó/´ÏÞL ¥uuu˜˜˜Àðð°ïº4ùîw¿ïKýèߢëDR*d>o«††Õ××çM ë`jpM€7â÷óÎxÉèé,~ÕÛs¾ÕÕÕ!‹Á¿v½R £££ÅäÀ­q722R²0&àj$õõõÅ‘/¿oÁ/lÇŸ¡NgŒaÓ¦M¼zrPxýË`ŒÅ|¦ÃúöÝù–÷»QJÑÑÑL&SŒÓ4÷|ò“ø[ŸûܧÿZJC¸Sƒ–jn†*ÄH¬qáÖ¸ ”>aŽ¥¹Ž öÙ›=hhh(ùÞóøûƒ~º»»KFrOPššš iÚ¬«}åBýÉ@þ<‚Å2Ê©üa;ÿ¾ræÀ\¿ÃùnÞ߉1êhnnþ;ï¼{çŽRJŒ`øÖ4x#À\Žªr(7‚£ô(¥Ð4 ---Å}~¡§§§(ˆþ)DÿkKKKYûß»†×6Ø'¿S0˜àß.³Ùøþ¾„|KðÏǶy}J$%¿w™n¸á+MM+4ÍѼªÂ€V`Í’Àš&€r>´e1Ÿ&…ópÎÑÞÞêð²þ„(ùΡZ[[ËÚÿa}ñkžàû÷ùÛ,–Ý_Òßû6‡};>xþ %ï”R466¢²²²ä:Œ±ÊßþíÿåzM^óàœaÆ\˜m† ƪªªPUU5cô,ªä^ ¿M:Fuuõ¬ê?%3¯éÇ ô þx¯ä‡ÿ¾‚ûÃÔ{ÿk¹ó•3ºù ‰ú76lØ0#)*OÜðñòîõ˜:¼¦€ÂF™ù%3Ç{ÐÂöiš†ÆÆF –|ï•B`bbb†–àÙÿs%ôxðû2.¿ârúÌ)MO³Ð4 ÍÍÍE ö-èc Æúû÷yŸËi(þs†ýañ³ù8¼óhš†M›6áØ±c%íÛÛ;>yë­¿úØý÷ÿë1Ë2¤ãX2—«Uƒj-—[Ó@)z߃˜ÏS®¢Opq ¼éÀÇ—œÛ þñÛè(¥Eõ.#±Ö–VÔÕÕÍðKøM/`1H 8åvÎr*}pf œú ˜åÛ|}>H&“3J‰BØë^÷º¯>öØc¯žš*N ®õÔá5o躪þ{µÊR2…èØË ç---¡y÷ýýýEõßÿ†¦¦¦9W=Ó ‹¡²²UUU¨®®.nÞçt:],lºf×ûäáÃÌ‚°= þ؆ÅÞg”ãœ×âŸøÏ‹ î8+¬:¼&M5MžöúsƃðFÿ©©©PÁ (B܈Àd2‰úúúçÂÐÐPQ[ðúT___ KžM@Ã|žoFè¦ëzÑ´¸Ð,@?æk·û÷û_ƒmg»ÆbÍ„ù Âb#Òéôë~÷w?þ«œ ݶ =wx.WÍ×j¨ðš'Ï)”z”GFGB+éÓæ—G|ƒžd]×ÑÐØ0ã|}}}èëë›qLccãœö¿×6ø½gçÏGP.6æéJASáblž? xýÍ›;ÿ?¯”X>ïÆ¬ÕPá5K„by­0?@÷¹nä²¹²6¥”]]]Åsy çµµµ¡{ïšÍMÍ%±ì066VŒôBžú?—–ÁÕ2˜¢Aõ?L¸Ë…òúp6[Þûû\, ÀÛ***Šy¾kko|ã_¥4^’:\Xu8˜5¸ªI`Íà išhnn.Ù¯”[[þرc¡¡ÂBœ8y"?î>0µµµ¨ªª ± qÍ€¦¦&$‰²j¬×6™L¢¡¡a^º0A ”kÿ-F”ß|¼¿@÷ÛxÆ”»ÆRl---H¥R%××4­ý¾ûîûŒãH=:L±†R‡×,x¢i:::B§Éyäœ9s¦X7ß‹¦Àþ‡ö‡z«;::ŠuÂÀƒišhjnšñ]0¡¹¥±Xl~ö9™)HÞû°*Áå² ³ ­ÿ½ÿoFsk)6J)6oÞ<ã7­®®~Ëý¯~çÂðük-uxÍOjš†ÖÖVÔÕס¯wÚWJ!ŸÏã[ßúvíÞ…ö67mtppÏ<óLI±÷'SIttt”Ì,¯ç‘NC}^<þâ¬}óŠÎÇCFJ)@iÚ­”RìÙ½gΜ„¸~O¸ËÕã§”¢±¡qÞóóa#¦”˜!TåŽ÷  –S»Š0ÂñÏõ…<¨ „%•;÷R ²² %ÎZBˆñÖ·Þý•ÇÿÅÑu" ʲl¹VR‡×¬ L€W(rÏî=%œ_m.ºœ×Þºu+:;;Çg³÷®YWW‡t:]¶]uM5jjjʦÿQ.Ø#1ÿ=„­ ì%#-FR‡…˜am‚&Âlm–jkooG2™,é‹®ëÛî»ï|̶EаêW^Ó¸’·ÖÞîÝ»‹%½ý˜-ÊŒRŠmÛ¶áÒK/-ÖœkõÊ„5·”Ámnj†®ësMßHø½¶`ÑÅÂ\‚íõ+ø³…/Çæù‚³< ï¹çžw_í• ¤¯ZÀº J)âñ8Òé4vïÞk¯½emaïa¨©©ÁUW]…}ûö¡®®‰DbÎÛïðꆵ©­­5ý7ˆ¥ôò/å„Þ/P~ÿ„ÿ^gKTZ. Ä]DeÓ¦M3ºtÅWÿm[[gšsG7M¹&J‰­i€/N?™L#ç000€ÁÁAd2™âL€a0M³XZº¦¦©T ñxº®ÏÛæMnÞ²J–:Ä(¥hhh˜×ü¿RnMƒÚÚÚâò`ó! ?¼kΖmx¾ð/^æô Ûü~¶~/ª««Q__þþþâ>JiâÃþà—>ò‘½M]š¦](%ÕׇUéXLíðÈÀ4MTUU¡£££(ü^dG¦i"‹+õÎWø½kÕÕÕá¦o*®3 8Â$“Éy©ÿ„¸>…K÷^ZÌ(\(qC¢½%Äž)Ôüß{ûýíƒïË{¹°aÃLNN–„Flß§>õ‡ÿíÿøÓ_p·”X.W-››‡We)±uC@麮#—,Ïlã•èZh"'´‰Dº®ÏZïúaõÿÃúl***ÇÏÛàœ5˜Å*¿úìi(a©À~¢#ˆÙο`Œ¡³³,ñŸ444}èÍo~ÇÏÿùŸ¿ùœeÒ¶óŠÒZÕÚ:è-5Fá°Â‰`]€o„öF๼Ðç{ /g>Å3æ:—·ÊðùÀ¯z_ a áýi¼ÞwAšó¹ÆRÛA:yò¤¿/ô†nøÒXWPÓ4lÛ¶m†Ï¦¹¹õ÷o½õ¶Mî*C†æ8ÏåjyÇ*Yu8"€‹†0Að08Ÿk] AŸ-9‘H`Æ Á~°×½îöoF:î¥;ŽÃ2™:”˜À $ˆ",‚‚TN8ßë] AŸmkjjšáàœ×ßwß}ZHÖMÓÑVK)±ˆ",*üBå!LØË½_(.– Ï¶mÞ¼yFaØT*õÚßýÝ¿iµ•‹ ¢â|´€ Nò þRø8çØ¶mÛŒ{Ý´iË_ý+[½U‡WC)±ˆ",:ÊiÁ©Hïóbå9,…ð{[*• óhwÞy××K!¥ÄVäÔ`Då?/0[=€ ¹öRm---¨®®.¹>ç¼í¾ûîûl!> ˜:¼âJ‰E‚q9†¯~ _úsœqN/wwV%ü£½'èÁ¥ºÂ4…ÅÀR’À–-[f¬Q]]ýæ÷½ï7y©Ã+¹”XD>(¥ð\þI¼çðÛðÅ'ÿ¾òÔßâƒÏ¾_û{µð$œõ ¿„©þÁ¶ÁĨ¹nYÈõ/æ¦ëú €RŠìÞ½÷¯öîÝWçùVjêpD(¥pÂ9Žû~/Ÿ;KZJàÜp¾òÌßá÷Î}Y9µbóòW"‚#{Ð4ð¿GÑÙnYÈõ—bK§Óhmm ^Ýxç;ßý Ç+Ú ¥Á”ÄŸžûº‡ÎA* ©$¤·ÆñıÇðxþ‘EY›n=!¨„}¦”Î(Ë\DåB¯±·ööö%àt]ßòéOî÷¼Rbn¨°ÍVR)±uOJ)((dÅzGΪ:ÌðªT56Ò-˲Çj…'Ü@©Àõý¦@MMMɱ/½ôÒªšðJÇ—«¯¯÷=÷üæÕœ;†*lYµl¥„ G ”[±§L¹Û·oüñ’Q?›ÍâèÑ£8zôè²ô{±ÐÐÐô!!´¿•’9‰„íärB´¶‚vu-_ÁumQ`îmj;*«+á)ÿgq0ÊÀ(¡Ô] ƒDÃÿB¦þû÷{ï+++qíµ×†®è¼ÚAÑš›ë’š&¸mK.¥¤¶½¼f@D(Ôp&D1\Ÿ¾3Šå˜5 Î5p®Ñù­â¡<ü޾àT ÷>Nã¯xEè«B.¥âRšLÁ¤¬[Ö©Àuo(¸ê'%hmT IDATŒ2Ü,_‹ŸWÿ ]ç(d&3®@¯rkìQæêœŸ‡ã83±aÅWƒ×«_³á|k*NNN–œ[ɤԘa(ªiŠZ–ðÑ#‚%5Ö=âªû”2pÆ¢)\Y}ú¿[9˜Ä~õStÒíõÿÂò××;ð0r$ þ"!äõÞû—`ó^ËEÛ”3-‚þûrõæ[ը܄”’)¥¨”Š*'J)"¥Œ–ÅÑŸPPF¡1ë¨ä•xmÕÔÜUbÏõÃw§¾¹Ì½]{ *PJå<è8 &¸³Å „í/wüB Á9ˆ;òƒJ)Ãä/r.9¦5ÍÕ^)_–Æyiáþ³?Æ€ê¦ÿþÑØsøÍg”E¹‘z¡U‚üÇùÏ{¾Õ†‚PJ@ÿg!IJ%EµÆt®A×tÜÄÝ¿ê„[²gðþªÿO ¥ŠBåf¼­œ9¬/Ôæ+¼af@ðœÁsÍUoÐß·ˆgû£Tà#`9PüÑ(ñi:8ãØ&w㊶+¡G <}òI<œ{ þE„_ ýû‚£¨E¥àh=»}6•?¡&ðþsÍE )tR ‚eú'„¸ÀƒÆ8tMg o§ïA{ã#ÙaüÝ©¿Â¸‹´€ED9›?(ìaªÿl#|9¿B9?‚_`çðù˜aÀr |`Úèù4M‡®à\CœÄñ–º{P¯pªçeüÍà_@EIA‹Šr$à½Î6â{ÇÍæÔ žg6ažKÓ3ÊÄJGDx$àiœsh\§ûÄU¸¼ý*èTƒ#<|âAÌÆޮ崄ÙÌ‚r#|˜à¿ [ µÜ¶Ò€~_€Æ8tî.ïM Å;ø{ÑÑ´ „ dúñ…Óÿ 1‘À"#è dÚ èßçµñ ¶÷ý|¦ø‚×óÞÏFç³­tDàƒ§PJÁ‡¦iàÌ͈«8~³êƒh¨h%ÇÎÇÿüC7=8¢"(ÐÁ}AM LU÷ÚÎå¥/'´a×8Ÿ)Á•ŽˆB@ˆÏ!¨iàŒƒ1Žj nn½ = ‰Ç?ŠN~Ç­i‹Š0M ÌF÷¾ Óæc,t´›%(gÿ—™\QXù=\bxZ¡œqè\ƒ¡ëÐ8c ÿoÆŽÖ]ÐÇ„5ޝû2ŽäE¦ÀE€'Àž àx |h°ä Æ„µ™K3¶ öc¶ïV:"!…ð`Ïà:4®ƒQN4| ölhè% ý£½øÜ‹÷¡×îŽ*_„ ;05¼SnŸ‡°yþr$Pnn65?2Ö[]ØŠ6æFp4ž¯÷?Lí÷Ÿ3x|عüÇFNÀ5ަ€¦»SƒœƒRŠW«×àêöëã&låàÑŽ¿ü<„šY°"Ââ`6G Ÿæ"‚0í!xþ°ö q® `Ý™H!@H1É%¤”nR°qÿMŒ´ ãÀ™g‘u,ÜìǨ`•øÍêjõ8ƒ‚ðíX©ðÍ_ìú`a?Êí÷Ÿ×;G9§ÞjøûÌÌâL¦\€·t˜T\¿û0þ´î³8Ñwk?8ú]ÔìªÆo[ñ$  0%3ȈI8Äq×H   ˜Ô„ILpâ–â^I¾_8½Ê>€ÛGÆXI™±…AðתðÌ „W)w«K—,K!)SxÍGðçöçÐ3Úñܾzä˨ÚU›¯YQ$ ¥Ä¸ÃñÜaLJÏ  ”[Ôí8Û~Oœø,XèíÁÿ8òøìÎ?Á&ÞYzžE†R 9•EèÆ¡Éçðüè³85ò2NŒ¾ˆ¼“ƒ£8JÀµü>Káv”î.1ØÒÆ‘‘C86zÿJ¾­W7]‡×4¿—&¯€cÉ…b6ûßû'ƒ0­ )Ìvý•ŽˆO¸âPÚt‰0)%¤¸›¼M=x±÷EgGÎâ3Gÿ;>»ãóØÄ;MÌ©úENç^ÆÑÉp&sƒ™tua$?¡¤…WyÑ–6wï_IŠÞ|/þíôðŸg„k®ÇÛ7ÞƒKW‚béóäg3‚m<øg¼Ïa³«œœ‚ž&KÁp€wTü¾0ù'˜€Pg‡Îà3G>Ïlÿ<6içG޲qÚ~Ïd~‰g†ŸÆàÄ §ú18Õ[:At]úÞ/5<‚RB ìïþžî¿¶émøößB‚&—€Ù‰ ˜ë?×TálX ± œ'‚NACƒ»Ð¨tãšìÜÜt þíå`Jd …ÂÙ¡ÓøÌÑÿŽßßúYì0vÍ‹éàEç(~6üc¼0|]ÃgÐ?ÕïŠxÁ~/¸§dÏ/ü&Ä3ޝ¿ø%teÎâ÷·4½,2Áyý`åf ‚ç:ýǯtDp p Vx«ØH%!¤»Ýì¼/4ÄÑî* %pvè þèð½øèÎ{q¹qM( (¥0 û°ü§x¨ïg8Ùÿ†rƒ5X‰Â>¼”éŸû0¿¿ã‘T©eU¥ƒ$PÎó?ßóxðk+\Š?°8sÿ”RJ) „kw¿Å|¾ÿ3 M AQP@÷X>èðîíïíñÛ]Mîˆù¢sßîûvÀ™±SpŠªý… <Ô >˜¾e³p wV€‚ RpІj%JĽ?©$~rî?ÐoÅû7|ÕV„ ” ü)7¢Ïg`%Ü×\ˆàŒœÖ¤hpš±¯þrì?ý,(H"©009€¿>ð—8Þyï¬~/ŽÛGñÝîoàXßQôgú!”€*D–½¶oZŽø>{Ÿüý£˜ÞO [T‰'üÓf…çCJ–õ'BgqÜPu3ƬqLˆQŒÙc±‡‘G¾xŽ µüëéïáímïB5­YQR~û´ûx¡ˆ`t *^p J G Ü⼇«^@ïHˆ$u…bÂÇ¿ý>ž®ø%†Æ0fO@(w!Iâž*„(¡à„ƒJ( b Á“0y 1ƒNMèTGŒÇÀ‰è``ˆ‘84hD‡q@PrÈ#'sȉ,&œ1 å‡0b¹qÊP ²hŠ0BQÃëðJú+ˆ‰8#°¹‘pà0ãÈƨ†Eòp àÀ§vVï‚. ()RZëo5`5õu6D°H(u 2èZAÀ ‘À«’¯Á&¿ƒ)'H@( [:8=zP Dâ ¸’î>…™ê9As²;êva«Ü‰JQ*94Á¡+\i€ˆ¦ò  Ó^ÄUãAKË#oä0É&ѧzÐïô`ØÄ@®öe Hðt¢»Z%0`B  ‚T¢n¡w‹¬º˜G"– ’)P¢Š&J„¥ED‹ BÜRb šp—³—[×àÑŠý83|ŠTJ€7¯0ÀsÂÁ¹†œÌ¹qT‚* A„KÓÖ5º'»1‘Gw²›ã[°‹íE¥¨r§& Š¿®ò©ØåF®é°X÷½!MÂDJT¢ -€$“˜Jea“Å0Æä(êyâ* Æi1¸èðÛÉ J¹›®‰¤\-i5¤Í®UD°ˆðLET¡ˆˆ¡ ØŽG8x•ùZ|—“b   J0¸°RA[u;6&6a8;Šž©sÌ "'§@¥I•»_°«meaÄÅÄèA;ŒG´‡Ð–Ü€¶x;.1.E³lCB$QXódº!˜Ú‚ÇÞ‹p”ª(¨ * 'fÒê.£F ë'p Ôç‘R’p”Ï+NÁ9¥lͨЫ,2‚¦€Æ5èºÛ±qIv/~VñdGÏ`PT”HOðNœðVý×aÄ œMœÆQ¼€sù3šĈ5\°ÇE!üXÂVq`å1’Áᑃø9{Ð%ƒŠ Ø¿|;*eUh¢N1¼WÉ „„ôÖ^îƒ[$…A× ºk`…"®6â1Þ,ƒ›±çþM4ÆÁVIÙ¬µŒˆ.™®'hH¶fÃvlÜJo÷ù×1åd ˆB’§L%Ñ3ÜGZJáÌè)|-þw¸#ñVlÊubƒÜ‰ÑÊ!œ$/â¤sS}èÍöÂ’$DÑc/!¤KZ˜™Àñ±#x˜>ˆ–X:ª7bGÅnìMìCš ­˜*ëÍx® Â+¤,ªìBºÄ   ñîè¯k:tMw«÷t Ul«Ti¼=¥œº¥Öé*™/_«ˆà" dV€qH.aèlÇÆ6k'jSu87šƒPSNmt*kkp|ðr*)ú¦zðùMÜ^y¶äv@)‰:»µªW‘ë‘Mep¶ú4ŽˆCè›ìA×ääTR 8R¸¤GXÒÂK“Çðræ%€·ä߉ššZìýÆr#³Fñ}ÿŠÉ¦qÜfÞiËRu\)Äì:ÅNlã»0ØÜg_âÀès85q–ÌOG²ö,dÅFúñdÿãøûgl¬ØŒí5;q}íØnî@’¤”_ ožRê†ÑéP£Ò?‚ûRZ_/|m¾K¥¯ÖP ·21I&“ÌqÆã„H :@ôÛn»ý×á«^¼sçÎUóÐø+é€x‰B®:c1Ÿ: U˜çÏÙY4%›°×¾M©fœUgurKZèÊœÅXr{—Ãd1hÌ2dÔwÿ” q'ÍØ†]ɽ ‰áì le‡Fz¡¹ny‘Ã@®ÇFŽàážñüÄ38+Î i$QÁÓàD ¯ï‹,\è¶ÖqäÈ‘’éÐüÙ×r¹lPÀl!„£išÈd2ž·ÔÛ–,<§0íOÛÕ8ÈžÂD~Žèeç°W¿ͲÛ’;p†¼ŒŒ5 ¥¡œ›8‹3üö¤/CZ«ç8c`œƒ1WA¤Ð„Ž­ØDu ýSÝnlʧ»á¿²0Ãà’AO¶‡†àÁÞŸâ…Ì È~¤Íj¤Hʵß}*üjûM– ÌŽ5OÓ±ùÓžqϹƩŽãS‡áÀqUr+Lj»° ™ÄîøeèÑÏb47îÚòœÀQûtVv¢AovW,â¼`‡SßT ¤B“ÝŠŠŠJôYçÜ€³€‡R2È9Yœ<ƒgŸÄþÞûqÊ>‰¤™@µV¾ª~¥FD³cÍ€‡0- ZÖá9ò4&ópKéùQ´Un@µ¬ƒ. ìÑ/ÃP|#ÙáBÂx~‡Æ"Q‘ÀÖØ6hLwƒq£|z1M¸sò ² 55èË÷ +¦ æAþ~ËBü¿£dìI¼4zõüG2¡4‰z£qYJ~­D0;Ö„j…MÓ(ŽN†P6”Rp”@7鱫ÁÁA%Ç%l²©I f =‰);ƒcc‡1dôcWòRÄX œñ¢I@)+Ù@)TÙuhJ5¡ßéCFLºÙ† |ΦÉ@À’ÎNžÁ#=áéÑ'0JFÐ߀‰­ºßçb""€Ù±.ÀÃL-@ Ú©Ãsxã¹q×!¨rÎÍA\¦](¢(¶‘KÀÓýù^X" ‰¼ÌãÔè)Ì=‡M•¨ãõ`Œ¹S”‚PZÏu5 »-ñV “AL:ʹ {‘³d ׇgžÄ/öcŠMbs¢:ôUû;-&"˜놊3 E€nÑÖ“'_1±Ü(•1l¤[Š¡µr3**RèΟCVd ~…‘ìžyV,‹-ñm0¨é†ê´oî])…¤¨@»¹£lãöÄ•®òˆ@Bb4?‚§ŸÄ±§Q—ªC“Þ ² E@W"˜놃—ÕKHÆ“H³*èTŸ®t«šìVlï@U² Œräd¤P6Œ^@¥Ï4Èõáá¾aÆLl‹ï%ë+x¥@ ¼LPPxp৘t2J¨,ŒŸT‚€œ—GNá+úßàÕ€B­ªGOæåh­hÅPfãölb»e¶”®š]¨Òêp¨ïy<ÕýZ’­ØX±W˜× ’Ö€årùªœZ\+nÂeÆÕèKöâeñ"Îåºpvê4&Äli¹FB n gÌÌV·PAaÔÁ_ú3`7ðæú»—eqáˆ`‰¡Üt; Ë! O¸sû €"…Œ\D¢à(%£ý‡ðo±Æ›ô·A‰­Úa!¤Å͵·àÃbØ‚¶rðüÀ\Óx>¼ý÷ð‹Ñý8:tžý žÔņôf\–¸í|#x^ƒeçAE{®m؇9˜¬G?éG¯Ó…!1€Qk‘AFL #2°•G H2½úP¡÷źÞ¨Ntœ=§ÎF´[t½!"€%„?ç>#'‘·sR„B¹•„ˆ‚®lPP €8È©,~Ñó0öv\V¶åf$IÇp~uñ:¼¾òMøÉøÐŸë…%rÈÉ<ë}Y1‰ßlþ0n¯z›|†ŸÆ±á£8€%†R BLÚøéà1–u«þ7çp¤Ø¾ð¿‚›×?€^\›|% ÛÀsâiŒæG¡ `q×Ú7¢#¹ ¤Y‘…P¦†ðRþ(ö$/ťƸ2}-:Ò%9tOžÆ‘ÑÃ8š?ˆ~½©x iV ƒ›àÜ,”L kf0Ŧ@(ޤª@Ú©B«lÇN}xŒ¡+w i^…·Ô߃[õ×£‘4#ÅRˆÓtf¸q „«ù·œ"@„"<õ_H”L#n&€qâN I E!ÅQR ÅÿØ’àÔðI<_ùv²KÑh6âìäi8J ?߇Œ9Ú\î0ÞŽÿà?ĉ‰ãȉ,™Ãñ±£ø‚øsüzÛo¡ƒnÆ.m¶×ïÁ©Úxhø§82|O=ާÔ/ÑkCK¼ –@VMáLæ4ÎN„3 *µ*ÔõØdnÂmÒù¼ ¯CS}+NÙ'°G» ²Jº5 Ýxá~–ŠEU€W " ` á9ÏÇã88,àå‘îwÞ?·„oÁà…{'L’ \{$“x~âYiÖ6j+ëÑ,ZaHt;¦âSËB([Y˜°'pbê8ê“ ¨%õ€ªI-öÄöa{åNäyC¹tg»ðâÄ?ˆcã‡q.w“Î8ò2¼ÌaLŒ¢7ßcSGðLæ ƒ¨Ž× SnǺU¤/-¦é:8ç®VAÖO% •®D—þx¼×›b·"­W–.?wÔTJ¸Ùx…$ áæí =Ý`½h'Hk•Ê >4õ,4ݲ˜Jàõê\[{=Òz%4ªÃVº¦Îàëg¾ŒÇ󸡼J h#øê÷ãý›[Á(‡%mØÒ‚#-8Ò)&ÙÒ†%-X2Qg=Œ/vÿo|Ïþ˜Še3bˆqÄc ÄÍ8 Ä¡¹ K”ü‘pE "€%†?h‹ÜŽMu…(= (U,ý%¥;·/<€ƒáìžÍ= U…´ž†T ¶´Ð3ÙÞXLÝ„¦ià`¸Y¾7Õ¼5z-t¢Ã–6úr=øÞÙÿ‡G쟃‹„€PØNwâƒíÃΊÝШB¼¢lFÞ¿G ¶´0îŒãá¡ñ…¾?Å ü≒±âf4³­ÈÜ€¤HøW"X"¿0òÑ¢šwÄÞ†ºx}I™,÷OÀ ™ƒ8–²qÎêE{¼D)8R`ÂÇcÙŸÃ4L˜† ]×AAqµ¸¯©ýU40˜ƒÖ~Øõ=ÜŸû÷âS ”kžÄ­$Ú’ SÍÍ'+¹S{¥}õ´[Z8;u óòŸãþü¿C34ÄŒ˜[6\s‹—PF×…ê¿ZÀ¢X ‹NÓlW¸©áÕˆ±X™šýÒ­ï[(ì)ˆ)Æ­ )°Í¼”p(8ÒÆ©Ñ“˜ÔÆaê&LÝ„®é „as^_óFÔš0‰K£Ö~Üõ/ø·©ïÊŠyÚ‡Àvc'Z œº ~PJ š€%8³ ‚‚P1…ÿûâßá»ÃÿÅ8å…¤¤HøW"XjÖýskês蚆_‘·c_Ëånþ™…;¼’ÜR¸Ñx1Ð(šQkÖAIÀ’ús½xÂ~ †n¸¶·îj [ÅNÜRý:T›µ0¨¡Œ9x ûÇøçñ„ÒF) 6ÉmØS±&‹3 ”0PL÷•ÎfOÈK _{ñËøÉØ¿—8ü"á_Yˆ`‰áUÒåŒA㮇Üä&Þ¬îÁÞæË¡­Xd3 Uˆ hÐÜäš”¬@•YíÎ.Hy‘dzƒOÂá6LÍ@ÌŒ5`—Ø‹k+oD’ÅÁ ‡„ƒIgõ>€o}BàLƒŽ[b·£Ýì€IM0 ý*-˜eûªò2¯ÿ2zíž J0ŠpñÀ ‹¥õ_Ó¼µ ¤hwã=¸¶ù$X²hs{Âå%è004ÇZq5¿€»ÒN³Ù À]ZÌN½Œç¬'Á¹C7¦}š(‚+åÕèHuºÕ…© …¬ÈàÑž‡ñဥåÀ¹†jUƒ_­¸Mf LfUù¢?€H€²P"PJ¢+sÝ%KKŠGXˆ`@q× dFÁV7 ¼¿æ¼oi~'6Wv 1pÊÝUƒ)‡N ´%7àM oF-êÁ˜«’wh›@¤[hDHSb?z½†f®aºµ¡ã•±W!­W¡=¶Ù5'ädO <ޝ þ=òZš¦¡]mÀí©;ÐowÍZXÓϧP¿Ià{¤ ©C8XÄ- IDAT5qB.¼Y„‹(p‰á_+€s zÁé¦ s*¥°Ïº;Œ]8Úü^G1)'Àˆ†vÞŽ«è+Фš £.ƒ¢¤ )=\®$liãøÐq¼Ôx—h—BóM»¹#°B£hAc¬ ŒploÇ##aªàsh価¾Œ»Òï‚æhؘۂ_3ߎ§ßÇÉÌKÈ‹8pÍJ\íƒ* Ed¡™ç&L± á€ê.ˆŠ(`¥ "€e»l˜Æ5ß‚œžpP0‡áRë ì—ò4¢Ã`F1¢NcBJTÚ5HëiôçºÝzÒÂh~?úwìlÙëνkÓEI½õýZµv˜xWT] ^ÏñÈÀC˜°•#£/àŸÄÿÅ›Óï„.uÔåq¿ §Äs“OaÒž„£,7^ˆ»Ü¹"Pnx3!1ÇÕ©ëáÆäŒ˜‡Ë‹ÈX”N2èºS73㈛q$bqĘQgÆ`h®únh†oÓ¡i:4Îa2œrHåf:ÒA^äq¤ï ºìS%+{>MÓ±EÛGÙx6û®7âµ7#­U€ ޲ptò0¾=þuȘ€¡¨ •øõz¼!õkØlnÉbЙF50¸kÒÂ+§8nmz=šÑVÐr"`¥!Ò– ž)@ôé!/ŽÞvl8Â]•—RZ˜6Ô ¡µ(!°`QË­¬$”$°`¡;ÛŸŒþÞ[÷—”‚ÔMH!Ñ€&$Y §&Oà嚸^ÝVMñðÐCwÆÜ²^‡ñòMÜ™|;Lby`»³íÆfŒ?ƒ“O£×î†M µ”„U WT^‹Ûw€(R,xae!"€e„Ÿ4¢M{úƒ¦ép à-¬É™»È¨·$7àŽøƒd½™^Wø ‚& S‚Ïõ<¡šÔÓÆ‚çÞ5;t]GR¥ãÎfÇðÈäh·ãZu#d5ðèÈ~Œ9£p¤#ã‡ð]òMÜUq4\>bS\å\=±}8?cÎA [#˜cH² ìM\†«µC!ÀÉaå "€eF1D˜ÂU£)ã B! öº+?„Rp6='•¡/ä`JL–Œ°ž/àäø‹xtâçxCån•à‚ž:ÓÐÅÑŸÄ”3…“'ðdò1Ü _…Wà&ðŽýƒ÷cLC(cc‡ñü#îªxb$Æ8lǵ)vÊ]؆pt6s`(qš€A 7ˆˆM—(°²ý"+^|€'$ãÅ¥ÄM3Ó4Ý×B@Æ´’šÿ'&ÃQ3ml!äD¿ì–Ê=ó”PœSçðÕž¿EWö rÎ&Å$~1ð ÿ W‰ëñÊêW!É“`„ÃQ^?ˆN}z\C2ž@̈#fÆÝ¨CÝDŒ'PAÒHh è\‡i®ÏëîÔa”´âi+ž`PÐbu âˆ©Ü±ÝkCq J`#Èô#lå_[Ù8:tÇÛcWì2PJaÿÔ÷59‚)™…·ZA_¾ôý'Œ×áf\­^ «ÊÁ#Ã?s+ IÏ ?…8OàŽÔ]и˱ õ ¦— g”¹Žº‰˜ƒ®é`Œ—¬&ae`ÕÀº‰&ó)8ó¢ê¤’8k¿Œ®ñ³e+ó %0’ÆC?ÁŽæ=PJá„u ‡žÅ”œ‚!° Õ{ ž} {j.GÂNázr¬j =ˆœÌÆ…G~Ž8MàöÔÐ BJá@zÓ˜ Œé Š+ØÔ† ˆpgÜ CN¢•…—«ŽÖ f — ¤”x~ò9äd¶¬‡]* ¾€ú~ÔÐZôæz‘q¦` º+ä*çTÝÙn<%žÀ«ù­plà&ö+˜ªÇ“£O@H6±ð`ÿbLŒ‚‚"ëdá(Û59œ,léÀQŽkvHB l‘GÞ±]&5aR 1ƒÉc¨ÔkÐh6 ÙlEs¬uzÌÿ¿½3²ã,ïüï]ªê.½¨µËZmÉ‹lƒ±/€}Á@K„`&'“9gÎ|È,ùÀa2“ „`†„€ƒ `b6 6³Ø˲d˲–ÖÒÚZ½Ý{«Þ÷™oUÝnIí«Õ÷¢û?çU/ê[U·n=Ïû¬ÿGUˆUrÂæ¨NºPœRƤŽC`Ê‹y¼gOc7.þφ̧lÛÆ/'àeµ—³Ä. ©G´âJ2HFS5y|ì®]tÆ+”·¼*þm÷fëØf2ñL¹)î¹;t("à Z³@R )qê}>óÀå± Á#^ÂlB@¼Ãúj¶Îº¾³X×gÕ×sÞà…œ×·‘~3€¥g5œLtå²ó}ó‘Pvë}` šlSˆÞ¬¯Ahº&þœ+¢+Yà–°¶¾ŽÑ#‡!0*J£ó2áÔ7ybüqF—f±_Jš¥XsSõfnmþ#­}d¹»PD.ãAú£&ÓI§‡È| O†V …ÖÐD+*E…Öh4^$ŒH(#žÊ&Ùtä—l:òËò=TM•ó<ç ]Ä¥C—sáÀEÔu_`îá×F×)€ÓÝ(‡†‰ÇyñiÆx;vŒnçÈà!Wåù /aóè&Ò@EQyàЧLúI†ýVD+)î÷"·„^Å×÷ßNŠƒÂj͹çñ{‹ßE¦2&Ý;šóDsû¦vs°u€½S»9š£D¡ÄãU(}ÂùWåÁ¿g†U3妸ÙÁŸð³ƒ?áø;ú¢~.[x/]z5W/~9fA íYÏ ]¨z(«ê|`Ûy&ðâxâè6vº'9Ó¯ç2{?­ÿˆGÆ~nÿ×,½WŸñZ.¼tÞ3 EßG§f®º*Ī >éÓ|‰xxÏ;øŒ"å!(—q(;”…—Èå\±øJê¶,‰¼™H ô©V›5( ‘1eaRd DƒaU¼M°FÓ#|ùðW£íêEEyÍÎg8ïP-X™®áõÉ›yçÂ÷qfeCÈDäìÃÏ„zl6LdãÜ1|;ïûéÛyë}7ó¹ŸæHz8¤8çåóêlt•èiÔZdÐ.Ä(=ý?NˆbèÈD:º%ÖWëë¸dÁeÔM±I°ÊbtÄC²P–Î`/ MJ1Gýa2Ÿ‘JÊ’d1õ]‚V†ÌgìmsÛÑÏ£bˆlBlâ(!‰CU`dm¦ Z4ë²õ¼£ò^®©_Uq›rìR=¶oåã~„›ïyµõÃìšÚYöKœ*tzL¢k\€¢!¦ Èìô;W( ¡ ßx¥]‰UZ5pOó\ BÓ7ÑJc­Á9K=íçÕñëXº€ÿœÃÙA–ÄK¹zà† Xòòa£BÑ^;Ìc[É|†~5úK^¿ø-ø>áñŸ.‰‡ùFõv~gðmhTÈZ8‡óçÃT¤Vš¶IB³ ×™9£o%wL|•Q´@nú‹ÊÝ­râ”g×Y8–åŸü,_Üñy®]ö ~oÍ;8·ÿüSV•8“Œ¥³Ð5 `úuº ?’¿ÿ\x–±‚%•¥LNL„ ÜÓ •6ð*%ŠqÞ#Í>®Ënä’…—±“¬×±Ú¯ lÎ[ ”wŽ}½SÃ8ÉÀÁGùî‘ã­‹þ€–OÙ4þ©J¹{ä{œQ_ÅõµQ¹µâ}ž¹È2’8¥ÙjÑJ[Ý¢•jÎÏ.bIm9_mÝÆ­ÇP*¤Ed¨âeðÊÍÈVáSþõYÀÂê¢\|³A€Ô¥8Õ*ÉA*qðíc±Ä/åR+ýª²Ù(4ñ(”‚~;?Þ÷Cš®IêSœ8Z®ÅÎÆîû:¯é¿™3ëg!^hø)nßõE¶úÍÄqD%I¨$ µ¤J­Z¥V©ÓW«Ó_¯S¯V©U/â2³‚7'ÀeÉK09Mzé äÍDÁ%øõwo/ž»ö‹ß¿ï |â±Òp“söLu:zW) ÌœÎ+ ï $f¨²èùÈ"¡ÏkÉv’¤J-g"ªÄ}(Ž"[Ìò3 ï…»}“ƒ­ƒ¹ðûrXIÓ7yhìîkþˆ7 ¾3ª«ñ"iæÓÛÿ–#r£,‘ ,FIT¡'T“•¸N½ÚG­ÚG%®Q‰+ôéAn²¯å·ª¯£Oµ’K&b5-`¨~ýÃÔ§|îÉOóG?{ ×È3,sñYu.ºÆhC¦eNGÿW(0F³&^—Áhä©Ü)¢Ó‘Ý&!q.Â(!²m½ö’²{b©KÉphÑ ÿOh0Å¿ü6k–¯â÷½ƒOíû¤ûØ9ù$·ìøkþtí¦bª9-ºÁq£5ÖèÜÚP4Zùn¯—fW°²¶†;š·³#{"¯ QÊ!h¤(,š¥fàD¨›>ÎíÛÈE—påâkˆˆ‚K!'wÇîäݺRômú0ζgÓgúiºÆÓzÅ¡vß…@ 1` Zb‘¹ <Œ19ûP0ÁEÂìÁ"ˆ®  mËÎÃhz„ÛG¾Äû–ÿGÞ´üí|vÏ'9šŽrÿñåúyÓÒ·a´¡Œ+h­Ñ¹ÐÚ”Ëh…n)Vf«y[åÝÜïîåÞæ8ê¡G/”¡†âðm{sPJ±P/f¥]Íêd k“u¬¯ŸÍÊduηX%‰c2—•5EÀùd~VŠ®S"ª+L«¹Bxï òTkÃR9ƒõ38œÉžâµBæ3\^z«TA*b0ÆåmÆYiás;ŸÓ,­, ¿sjZ$^¢ñÂpc·þï\ðG¼~Ù›ùÇáÏÒp|u×m¬¯màE}/-WˆÂƒÕ**vþb© ×§š¨LóR¹†çW/åaÿ ¶æ€aT#Z0Þ‘0 úé׃,T‹Y¬³T/g©]AMU±*šk,Qfié4¯5(¦k´0rRY‹;¹ºH”Lºùh¬ÓÕPyJ,¨ÁhMMUY^_Á££›ž¶"PðxŸBHÔJ¡­1í×å·X+•ûÅçÖ.æNõuR•–®Fhä 5ü(hý9?Hîâºê+™Xv”Û†ÿ‰±l‚OmûVŸ·†3’Õ¥i¥J™üzò•»ÖjLSÓTŠ~Ëå%\_Ž#ÅãÃù!oiVh1%¡Rí‰Jå`Òâ>HÞ‘(.wØ=íÞ„“‡ÂšèTEÐuAÀ e8 ¢Ïóª†ôiª3Ÿ!ÓÿDµ•kÁXpR˜®¹°¬Wë9»~.6¯Ò+ ∣Ìg4²&ß>ð ö³—›«¹qùo¡€á©aþúÉ1é&Ka˜ÎT¡&IÖª!@X¯Ö©Uë$q5LRŠ*TMš®S×ujºNÕTIL%d4â8¯\ ÃQ­z5ÏDTJª2k¢œ©(W'}^êx´®± zš°Í‚°{å&t.¬ë8‹%ÉRîɼìõÄȼ#ËRÄPxì=m…•ø /|Žo"SnFÀQ.€  #é~¾~ä+¼}Á»¹>¾‰±…£|wäÛóu £Thû=®håD2¦ýúèãŃWòäÔ¶œ‰èøóBæ2&¥Áw|“³n$ö–·-þCÆÜQ6=Ì-ÿ-ýë\^»2Œ.+…2aŒFë(dœ&²Iœå%Åi†+Qót{ÇŠaÚ÷šòû¶«STU´›—NÚ×Ô¹.@×Åæ»§SV¬Ê›e”2<ϼ€ÅñÌS|¬JÄ«gu/ۃѩ²±~!3«ß\XŽþ‚zH²„?\öǬ®­c,=ÌÇù÷Oü8LšV„Sd9B[r˜…EIé×W¢µ¤Z¥zµŸzµŸZ¥jÒG5©S‰j9…z +£8‰Û£-ÆX´6åyŠsžüÏ©³Ñu àøë4^Åîl4‘5,sËY·àÌàCÏÐ’¢`æé_”k¥°FGqd©«×÷¿ŠÑ‚§lE„)7ÅC“?+ÿnÀ-àý+>Ȳd9‡ÓÃ|ø‘ÿÁ­{?Í9„Ϲ§Ÿ;ìÊ ­Ö´"¶BGÄQDÇùŠÂJ¢|ÅZƒµy@q…¼”Êßµwþ“½:]åhwÎ÷•Ì/Úq›¶"ί>ŸôÏhùÖ ›ƒ¬6ÏŠG/˜Í¡æÀ›+˜uSë¹bÁ•|ëà7/³Ò’ƒðÄÔã¨>UÊÃRVðG«?ÈǶ˜#Ùa¾°ýVîÚû-.^x ×-¹skçS¡2£¿aÒOðå‘/ñ«#2šŽR55ÖV×rÕ«¹°ïb"•÷$?íqUh”SˆN6ÿ¡ €¥ðŸÞ @åq€ðm1Úp®ÛÈÊÚj¶ŽmÉuμIJò½iº©úg)Lr­ ZY¬‰±6%²)/ãZM6±mê1„Ù[twOî"Õ)Uªaœ¸Öé ¼gÍùøö0å'Ð(†ìBnÙþ7L´ÆÙÐ.gõm`y²œ‘æ~¾à.¶†ÏA²ìšÚÎ݇þµ•u¼nŹ|à¥D:šqŽ/§è*0ó&v‡‰5—P9‰§ÑcBMýÂt!çndÇä“d’¤Ó:ÌïÌ~ް›‚1ŠÈZ’8"M#²A^>x{ZÃL¸‰EØÝÜISOѧúPZá²ÂÛ¨.à]«ÞË'ŸüƒÑoXøÞ°äM|qäŸø×=·ñ“C÷bÒd7ù×÷¥Ðxv4žäcO|˜ ûŸÏ{×ü +¢•+p†.Œô0ÓÝk#´¶\a¯byrF¨mŸ¶ ­´Jž½iRr!‡žä ?Ió|y/¼«ì¬ñ€¦o±7ۇц(Ͻk,˜KÌå¼yåÛÙrô>·÷ïØÕØÅ‡ÞÊÛV¾‘À#àœÓ‡$ùy´R|{á᱇øóGþwúJ9`þÐ ¨«,€€¢èô.*Ü€¼€Æ7`qk ‡.`osø8+Àä5ö3Š|ž‰%%„Ô\>¡8Ž"Ò4&6×ùÙ]ÝÉ£“ç ‹{š;¸(¹mBÊÏ{_2]¿œ£Kòõ½_áß|÷®ý®­ßÀö¡'øÞ¡o¡”ÉÛ•Ò’R”ù¢óâ0Í”Ÿâ3;ná‘ÑM¼o퇨ëú¼ZlþCW*€¦£ð‰u¾CÇ‘%Í,/rWòpô;ÝÒ< PD:ÂøgO™­”BI8‡7ž8ŠÉâ ç3Ü 7õÿ6û[û8˜<+ 7‡K+B+ 1¨´‰#äôo¬¿†Š©°®¶ŽÛ÷|‘‰ÅãÜ4ðî;r/“~—ïø(•w!Š$Ïëk|þ¯ˆâÇGîaÇÔvþô¬ÿºʺò=œ*ãÛ:]t•  TÁ çŸq*ëtX*/š1y¤ÞËr¿”‹]BÕTËÒXÄ&Æ*ûkŸGé`D&¤ßâ(!Ž"Ö¸u\¿àUD*>¡+0Ò ŒCêMÙPîûG>ÃÿÜý_ùEë>®©]ÇâýËÿ”{ÿ€‡'ÉÆäBœwR,5VЋyqa9‡—‚ã Ýϰ§5Ì_lùs¿FŠñT}&,÷%ºJõämtãʷIJ²-Ô¶GD:â%r úΡb*eÓMdb¬~­ûWž+¯¬‹lÑtX~.ã .íaˆ3Ìh4FhúÊî<Ãn·‹¯ïûW¶LlæOþoîü!Kå úüïz['6³À æ‚ïBA²iÊÀf"Úÿ/äµyÀpÂOñáÇÿ’oü· <æ€õçÄ+œ§“wèBPøÿ½uÌR¡¨ÅjCY¢È2àû¹ºÿZ–DK‰u‚RŠzTC—íÔmŽÁg³äM5†$ީĒ$¦¢kܘü6k“3³ŽfGiJƒ0LÐ ~1þS ŸTRnÝý)žð[ÑZQ¡ÂÍõ7Ò¯éÓAè –€óŠÌçB,— ¸‡Ü(²™8>µû“|iïçñ’K ¸¯íçÎT]§z@Ç£ØÝµÒhè»#Eg·6rÅâ+é7ýÄ:¡núç›._—÷ Ä6 (´Ù.R ¹yà Ù…3Æs»1RZaOcxƱ'Ý¿ûj­-‰Ix±½’—T®b­9“sÍù·•@éä‰}èP,vúPåWt¿ìýŸßóÙÐ=ÇQ›=©³Ö®SÞ =óÿÄ ”€ÕA„I>1/u×ð¢ÅWÐgúY¯‚çzžiuúZÛò\•¸‚5 kå,^=x3‰NJK`ÒMz×Né9ÇhóÈqŸï–‰ÍüÛÑ;ò=ƒ·ðóÆý<Öz”íéãܼ’—DW³€¡\w@|Û%ð¹…PTBj¥Ñ9óÏ×Fþ•¿ß}K°æÐ(Ò€½ àIDA„ÓS€¿ž‰ö›¶Š*W­±FEDQLETT…¢›X?¸Uvun?÷úw˜â|6"Žõwd,q ×ÞP¦(3qŒ¹Ñ2—ù”–kðsþîÈLê ¬µx“±¯µ/ŽQw”¯M}%ðvû^gÞÄzµyp0w ¦Ç òŽÁ% =ß9ôM>·çp§ÀPªsÍèâ4`§R,Í7ŠúÈZáã€ÈYnê  … ™n׿ÿº®@øFc$Šñ!"ï‚çZ÷ ôíçþñŸp¤u‰ssnÖóîoíãûcwqcýÕŒs”¦4ószRŸrWã›Hð^Ï9æ<¦Ì[Ô¶¹­ì’´¤…Ñåñ|´`‚VÂïà…—±±~AÞM97BÚéÏi×(€öœÉRS>Å=9ÍWˆÒ;v¸Ôe¬f-FræÛ"(ðœpòó™<+ľ$ì×Ö—q?ÎæÉMd¤e¤>ËFf¯GøÁ¡ïq]ýL1Ù>•x<¡àÁæOIã¯3o¢îú¹Ø_ÂE\L“&{ôv˓약Tûi¨" i× (¥ØßØÏ¹•`@d:ðp½0}¤]'¢k»NpÚ7w¾¯ªó V€K'¡T8 lÁaÀg”Õ<÷›W”£É]çòh¼‚…Ùïz7ÿW>AEUÜoï³ý³÷ñ‰­òhúæŒßO§{¸õ)MÞZ{'I&[‰8KÖs&ëñˆRÕä¨cL¢´fa²súÎcEmÎûg5}øÙ¢àìT7 «„]@DSøW= `&Úϙ ØÜWÏ»M{ä×É»íx@P:B”ÐRŠ…²˜-ûO Ù¡p>>Ç=0ë=žÍ›2 g9£à½cKk3·ªOóž÷QõÕœ/P‚¥‘û÷±ÄôùA"½–Ä$Tm•UœK±6” þ¸öáçŠNúéè*PXäæk‡ZUU~1:˜ÙZ[Šr`£t°Ü%XÏý>Nc'R`mL,y! ï=]%"&’„.²‹Ÿò¨;›;XU]3ëÿ%ày¬±™Ïè[xï‚R§WN"ÙÉ]“3!x!p(A›ðû“-´½và“Œ`ÀÌhkÇ¢äÖÓ”c¾C ,ÿuù'÷|Ú(¬Ò@„è»ó®lVÒ&t¬´«Ÿò˜£Ù(U_§ªkLùÉþä1¡M¿âïõßò¥FU*í!çÂS’ûâZ…–fcB@ )õØÉCç7¬uUpúèŽZëùÄô!UÑTen~Nv; 6ß(¦ÇQDdCŸ‚΂Û%ô™Ùã­¬Iä-kâuO{nAxpüÜ2òqLb¨WëôÕúèë§¿ÞG_­N½Z£^­“$b›`mUÔ\åëCб“ÑU@Qèó¤]tÑÃìh¤;ónnî]Q$F)ȹùg^C`2J|Â2»‚q76ûá2ÅÅ•Ky´±éiÏ,"ÜwôÇ|6þï[ù! ¡íÙ‹o¿Ù¢XÊ´¶¥rœc£9 ÇIDAT«{q²ç žltÁ?ÍÌž€ž NUÐT)ëÉSš×Þ hÖŠD'¬©®åñæ–§¦ë „KìeÜmïbO¶ûÿÎw°8^Ì[WüÓ6ó H¨ƒÐ*ðÎ,Š:yú¯³-€Î¾ºcÐÖ¦=¡ïtî€Ñ¦œþ[úÐ!X¨”fCrάÇXd¡PT¥Êú—ªª>ãó~øV¾uè!&¡M{™À®G—.ËÉGçîúÓÑu€÷cf2ÚôÐá(¬oŸ)´‚³ãsHTRVûMÇ»¥4F gº ¼¥ï|aìV&§þzû_±"YÅ%—!NH—>7ÏäeÈì* :¿´²‡ã13pÛcdˆõ•ã­€fˆ3Ôê0õ(§"ߨÏç=}dƒ™Ýj˜ŽTR>¼í¿³/Ý;Ã?U©¹cßw'¢«ÀL៻ŽÞ𛼷b¤Y 0‰•å‚Ú‹s«é³u¬µ9q˜ês†>ƒßOÞÅ«oa™^~ÜëŽÅÁÖAþrë_Ðp „SÍ"Õ¹‚_ «\€¶WŒ+=c ÛP å„Úò¼è|U}%' fúåÕ—”mÍa6aŠÄá¥"pqöB΋/d«<ÂýÙOxÜm¥hÿ9›ÆÅgvßÂ{W½­Ì)ëЛ>·°SÑU  àÔº¸¡mMÛC·@(Gši…Õš¥z)—Ô^È&~Àù•ç±AŸG"‹Va´WÑ®54[ i.tqž½CÑrðpöûeßqgýʾÛxÙеœßwþŒ‰Csù>ˆɞ8yèźÅ_kL0ñuÌ5Õëxpêˆ7õýUS CAM„1ïmIbLP ÖZÒ4ŸŒe~9×™WpMt#ì翉ÍÙÃìÎv/àO~”oü$‘¶sÚ\`zÜ¡SŸÙ®S’·mÎd_é¡{—K`ê1:T®Òkùã¡°VfäËZ‹ˆ`Œ nC΀ÜJ[¤&¥•¦d.Œ ·âY)«YeÖòÊä&ÆÍQñóXk [›[xtb3Ô/Ä«¹%ë(:VÛ?w¦ÐU  pÀä7¸çt#TN/®EcŒ A¾(æLÙQ”sšP³ªõÀ+JÀdšÈ„à`šµˆ¢ˆ4Íp>%˲¼PÐh±˜ë*¯à¦×P­V¨Ø/¾16wh—­wªðC—)蹿)(Ý€¼gÀy_VÍYc‰ãkƒ©_Ä| ­¢0ÿÀiŒ±Ä.&ÊR²(#sA¤Y õâËnH…ä„ĺÜDæÓÉ@:U t l¯Þ‡B‹ºþ1Æ`}°JÎmˆL¸ Šº­=t˜<08÷tO=ôäÜÿí\ñs!ü"â¾ùÍ;?ºiÓÃûÂóœ9¥¬WJåJ@ ìš·ëŸo))Âö°K–,±qÜH¸¢uZ]WJÕÁ×AÕ^úÒ«Ï{ík_÷g•JeÑqš&ð=áïa®q"¾¿c­Í,KÇ¿óoþŸ;îøÚÏÀOŠ˜ 7á}4Y­¦SÍfÒ:pà@ d0ƒ·ü”`¾%eº0Ë–aÁ8޳Dk[]Ï2]WÊÕ@Õ´ö•µkÏZú;¿ó»oX³fÝË”RcÁôÐCq»ví¼ç_þ埿ôØc[÷Šè†ˆŸ;a­Ÿñ“ÞG“iš6âx4!§¡€ ü 0«Va&&†â$Iãf3ª“U•25¥T |Í{]QÊ'ZëxÆs–^uÕË^¸jÕÚçõ÷÷ŸÇq¿Ö:™ï7ÓÃéç\+MÓ±ñññá]»v<|ï½?¸óæGözïS­USD"zRÄOŠØÉ8vSÞgS­VÔ¬V§ÃÃdpÊI.:A€"wšÍfÇqbLZUÊT³ÌU•ÒU¥|Õ{h-‘ˆDZk#‚ÑùÀ™âx=ôpªg°ÊȾóÞ;¥È¼×-­}SD5¼7SÖú)?å}4•$Íæ4ó¿ØýÛÍ.§bB Ap}ø,rÖ6²V+n“icŒÎ2­´ïD$Ñ™ˆ 5m…ŠôAs†c*øÊæTÀk­2ï}fŒoy¯ZÞ›†1¾é½k:g[QÔÈ&&¬«ÕÌË®?¤áaü’%Ö5’ÆqS[ë4uÊZÄ9ï1Î{Ÿ‰ˆ ˆ1…QÐĨž!ÐÃ\"g¥*„6ßýñà<¨,lP:q-k}Ó¹¬Ƕ©T³ÕhØ4Ž£lxxÆ®Ú*€b÷/n‚O’'²X5›Ò‚Î%¢”óQds.‰DŒ%0™ ðAôvþN¤°¦-ãÒT9­]>µÖ¤Îe-çl+ËZÍFäqeI2r¢ ß)W$,Ó3zÕ*L£±Ø¦ij+eYE‘‹œó‘µ‘õÞ›à EDS 4ýx=ô0WÈ…5¡´VN)åµÖY–¥™1:MS“ÓÈ‚ðÇipÃÃ8Ú¿yã·ë$!QÇ,½j¦Ù\bÒ4µõº3iê­sÇÎz/Æ{)…?Žc5-X¢gôp2q¢î=¥V«U½ÖÊk­\«e2­.Št69i²( ;ÿ®]xŽúÏ‹ ÐiÂqœX·=5µÌ¤ij¼÷º^w&Ë á¯jQ"¢*Tî =Áïan1S(i4 ”ù*QjÊk­¼µÊkoŒqQ¹juŸÛ¾ý8¿^¹í;QHŽU…5 Ót™vÎiçœå½×ýýAÐEPÞ÷„¾‡S­U™ S¢µöy“7Æø(Úçó]ÿD‚?¯Í**0Ósú3 V­B¥)Úû%¹ðÁ÷Þwêûéá7y3Oih="Q„ßµk†+ü0Ï«`¦(¾ªÙ~^·îT^Z=ÌÄöíå·Ç ølB?ï­ œHLÿ:Ûß÷ÐéÀl‚<›Àw„àè&a9öZ»éÚ{8ýp¬ w”àèv!êöëïá7)ì=ôÐC=ôÐC=ôÐC=ôÐC=ôÐC=ôÐC=ôÐÃiÿ—»\¹¤gIEND®B`‚olive-continuous/app/packaging/linux/icons/256x256/org.olivevideoeditor.Olive.png000066400000000000000000001065501370472574300302670ustar00rootroot00000000000000‰PNG  IHDR\r¨f pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF‚“IDATxÚì}w|Õúþs¦ìn6½'$!t0‚ QA,دb¹–û»z¿Ø{¿(XQ®ríŠ^P@ì4‘"„@BêîfÛÌùý1egfgwgÓ°'ŸóÙÍîl›9ïsÞ÷y¡”"1#1ŽÎÁ$NAb$F#1#‰‘‰‘€ÄHŒÄH@b$Fb$ 1#1‰‘ HŒÄHŒ$Fb$F#1ã0\¬!‰³åôîÃc0ù?1¬jò?5<žˆetò,„ùs‰ÓÔ"A'²E4Úc h¾ðk…^”5ÿÓ0´¡kÌŸ?ÿˆ;)ãÆ#3I+ìÚÉ <òÈ€‚‚‚A‡£/Ïó݆Ég&•’ÀNá4‘ƒØB/RJƒ|”Ò&QEQܶy½Þ •••¿Ü{ï½käã´Ó˜?þ ãÆkÙÎKMˆe) zã®Î*³oß¾Ž¿ýíoc233ÏåyþX–e;BR’““Ijj*’““‘””›Í–eÁ0 †!$aJÅ©ºRJ!Š"DQ„ ðûýhjj‚ÛíFcc#Ün7¥”ºA¨ÔÖÖ.œ5kÖ6lðÊ  hÀA«-Q` ¬˜G5˜½"ð ®sçÎŽ{ï½wRffæ$žçË!™999$++ ÉÉɰÛí`Y6!±‡h‚ŸÏ·ÛššTWWSJim ØX[[ûÁ#<òÁîÝ»½‚2-á°ƒ´žÐ³¸ë®»®è´ÓN»#))i˲òòò˜ÜÜ\$''ƒçù„Ôuðàv»QUU…ˆ‚ T455-^±bÅ3¯¾új¹ ‘ ˆ_ðµ6<€»ì²ËòGõ§Ó9Úî°ç"77v»=!Q‡ùðù|¨ªªÂ¾Ê}ðy}û=Ï‚E‹=ñÎ;ïì—Á hà+ H@óv{?{öìKsssoå8®Gqq1)((€ÍfKHÍ:ü~?*++±wï^ ÿªªªzáÆo|@@£VZA¬ ¾¢âógŸ}vÆ´iÓMJJŸ———TPP€ÔÔÔ„te£±±•••8pà@SSSÓ§sæÌ¹gÉ’%u2 Ä  °&ø¶éÓ§w;ù䓟v8§±%%%`˜D äÑ>DQÄž={P^^.x½Þ+W®¼sæÌ™Ûø H€^øÃÿÚk¯-=ûì³_¶Ûí'–––’N:%\r‰a*,صkõù|?.Y²ä†×^{m—t$8ê@³ë«î;üĉó'NœøŠÃá8½sçΤ¸¸8±ÊÃÒØ»w/vïÞM½^ïŠ>úèº>úh¿†'P܉B8jÀ„ÕçðŽ™3g>‘’’2µ¤¤„íܹs›—j¼5¨kªC­·.Ÿ Þ€Þ€¾ þ€@A € Í>ßvµy«[kTKžãA)KXØx윛I\Rì)ÈLÊDfR&²ÙH³§µùoÚ½{7öìÙ#¸\®·§OŸþºº:¯¹×à¨uŸ`Ÿ9sæ…ÅÅÅϦtíÚµM„é€çvÖíD•» 5®Ô6Õ" „¢ýHÜ‚üÑ ÃH‹œÎ%i™0u`$ˆ0´kRª¾‡ ”T Eò,grRr›’‹nYÝïÌoÓ`ÇŽØ·oŸ{ïÞ½wNŸ>ýC>„ÈÂCjU`Øõwžmüøñù—^zé»………Ç ==½U?wSÍ&l;¸ {k÷Âåua†Ha¾ QïƒH;™zΡפ©Ï);_$ GA.‹ Õ—~³HÕsC)…HEõÀvÊ)§dßrË-•”” (,,DRRR‹?«Ú[5•¿c{Õv4¼`9„%²ð³¡û„€0 †# ¾Nø™Ðù#„HÂnr*‰…äÀÃ_ –¨*ô²Àë@s+ŠT¥[A„@eP$m@ˆ‚! ÂÉ%¡WA/ ê4¹ÎÜÿ¯×‹ŠŠ ìÙ³gÍ¿ÿýï‰ßÿýAíÍ Ñ``øU[ÿ©§žÓ£G—‹ŠŠ¥¥¥-þœ?þuûÖa}%XŽ•…RFǪ»=Ëɪ?Ë„H‚ÏH`BU-@lƒ& ¬žïÃÝ,°¤ hL…PžE”T”4A% 5!(ÝbP€ B0!( SFÄqyǵø÷ìÚµ åååÞ¿þú놻îºë 7Ð.ž‚# *?'«ü޹sç>™žž~yŸ>}Hfff‹>ãÇ}?â} Þ[ŽãÀpŒ NžŒV ÐØüDcÈ­%ÿ 0Sÿ[ªòi ]%¡6!åQÕÇ ¤ ˆ©¨òÊÎ/Ê@ e@žb@D0DFRŽ/>'—œÜ¢ï^[[‹M›6Ñúúúÿ\qÅwðj¸67 ŽHп²ëÛúöí›1cÆŒ%%%e-eøWW¬ÆúòõpÜàx„%`yVÚñy À Û_Ñ´;¼ÑöWîSÐ`ÜúÉÑEøÅ²̼Fs@«¨*J·² r2ƒA@‚Á „€ N1(AŠ-ƒ:Â)Oi ïØ±{öìÙøàƒŽÞ°aCÆ$ÚŽ8…_Ëò;n¸á†cÎ9眅EEE©]ºtiö{ÿTù6Tl@ƒ·AxNxù>a‰¤ ° '1û €‘„˜aUèv_çö#LHÀ-V<š æo¥á‹Xk(Çh5Q €(†´) ƒA ¤$0Pn…€€tG:– l‘F°sçNTTT4~õÕWç¾üòËÊÚ€ê%h 8bÀ@öqнÿàƒŽèׯßÛ]ºtá:uêÔ¬÷þóàŸXS¹•õ•`xFrà³|dµ_ÙÝ00ºúŒn?m@ã¹3=—äèÓt¿—Æà”]T# 5€(Å (nB¥šâ)‚¡ÝßA‚_@IV F¿¼~ÍúmعsgpýúõSg̘±Xà Û‚<"À„ì³pÌœ9óš’’’‡{õêÅdgg7ë½ïZŒu{×ã%Ÿã9UÍgy6d÷s¡Ý^ÝõåÝ]re×Wïmý(ö>%‰•–ù ~¬™{På´^‘†81Ü= C¼€_6 äûA¿DýA é2£{ŽnÖo'«û66LðÅ߯ñd$?¾¢ú+¾-h…ÝèÞ3~‰Ý¿\.¬zdP«„™²& šÁ—@rŠ!rÐ/A0DÐTÍ‚A¥ƒ0¶×ظ¯ßïÇÞò½ØøÇÆW®¹æšûxd“ Õ@à°€HÂ?gΜǎ9æ˜+KJJÀqñU-ßV¿ K¶.'èÇsÒÎocõê?ÇH&k|Ó¯e÷ ! „êwwcÅÁ¦ÕxBß|SÁŒ7 TÒtÿËZ " ¹ O¬(¦AÐ2_H#HáSp~ßóÑ+«W\¿CìÞ½›6mš{ÕUWý¿ÖÃ"òk¯½v_ß¾}¯/--»XÇò=ËñË®ŸÁÈ;>'ß2 –—„_UýeÂOqé…v}¢aõµê~˜}OÂfØÎ‹âN{Üïm FÎÀªY`È0P¸€€ 3 ¾ _§õ< #ºŸ7˜íܹ6lxõÚk¯½€»µ@ ¥p(;évþÙ³gßylßc¯oN¥žÿü»kwƒµsàì’ s6ŒMbü»Ÿ°$ÙÇj\zvŸ* €*þ|=cO »;,­%Gs¼€ÙoW5h´0Åc@dHf ¨(‚`( R`ˆú`¤kN ù1Â2ês×°bÛwØ[_Ž«N¸Êòw'„ sçΠ ×Íž=Û}ã7>)?åS…Cu^Û½&–ÁÏoà|î¹ç®ê׿ßß‹‹ŠãRûý¢o­} »ëwƒµ³à’8ð\Ö!kÉ`l 8»ä < ¹ü8`%²ŒLú±’Ê Œ|KdÒI¶÷)‘o• •"DÐ8þÄ(ô(ý‹ôÛµ ØÔGåë¦ð8”Põšª×—#`xÉTLBe}°vVZKi3᜴®’BëjÛÁmxqÕ‹ð‹~ë»Ë¢¸¨ýú÷»ý¹çž» €S^ÿ,ÆÐêÈð+¡½I3fÌ8§k×®æÆEøôÄ[kÞÂAÏAp6IðyÖÆ‚·ñ²À©î>%ªÕÄökmzÕÖ×øšw©®û%Ÿ³.KÍ0E*†ÔP‹Ê8UW•(êÔÔÄ ·ß£MãõQ®– T®±nÊf B³«š‹¬•@@^K¼—Ö™Gec%f®œ‰*O•å5k³ÙP˜_ˆ®]»>éQ;•sé›íù°k(sR£@ªÚö”QL@"Ýç¤u£š < F^_¬¼Þ$‡+èÆÛ¿¾muÛ,¯á¬¬,téÒ…5jÔ'eee92Æ `ÚIø•Ïâ8¤Ì˜1ã㢢¢”‚‚ËïõWý_øbÓðQX‡l«Év›‚ÖÊdlšÐ^m<¿œÁ§íd´ïu6e [4¢}®E~Ûþh³á­üÅû¾F’0âqx…‰" Qy5TqÛäu¦½†WbWÐ$6áýßÞǦƒ›,¯å‚‚¥Ì˜1ãc)²\ðŠL¶´—€ÕØýÎ×_ýÑÒÒÒ>ñTðÙÕ° ‹¶,‚úB6™ƒ—;§&ö0œœÈ£IßUI!ÍBP\vZW‰Â˜-®æ0óñ¦íÒDKûV÷„]Km4¡âZ”AB ë¦TZ eN“• ÖÆªä¯6öÃísã£5á’— GFKß¹sçÎE±Ï믿þè5×\óhЉ´—g M5Æ?éþûï?¯{î“ã)äQî.Çç›?‡—zU––u°›o—U}Q~ÂU¡RX|‘ˆ‰(íö …HD¤‡H»‚ˆÐcÊŸñíãfÏ TPg´×™ý‰‰¿¸ÿ¢;ããÊî¯\kòš`¨º.(CCëFvTžHkÍ&¯3#­;Æ!MÎÁÁC=x÷·w±»a·åµ]ZZŠî=ºO¾ÿþûÏÓ‚íæ`ÚXø‰Võïׯ_^ÿþýÿ]_`9:®Æ[ƒOþüM´IUíY‡œÆk—þW„žðDº`ѹð´Â/’Ðâ0 ¾!4;.–Ð'þÚFè[š: 0¬­ðƒ‘Ö“²¾´`ÀÚYÕD`ìÒÿуÿüúT7U[Ž(È/@ÿþýÿݯ_¿<ƒ)Ðæ|×Ã+Á>÷ÜsϼN:ÙÓÓÓ-©Ç~Á÷þxž ¼ƒùjå˜~Õ½§øóµÉ;L(„W Q£Æ”žhᦱ̀h)­‰ <! (, I “Øai]Q)~Xʆ¹•ÙØÔˆ×z· » v.v‡éôôttêÔÉ~Ï=÷Ì»ôÒKÇ@ߎL8ì43ÕÿÙgŸ½¡´´ôØ’’Ëï3wÃ\Ôûê¥_Ùñµê>GtH-q¨Ð¡»!&"Ä´+>~í¨ñ¾öujý÷†c#¾Æä+3²Ç 1£c«ÇSh¼2Šv ¾òZR}XŠY kŒQ§vl:ˆY?β¼ÖKJJPZZzìóÏ?c{šL ?Ñ¿cèСE]»v½#ÆÞÆy¨vWK„ŸÂðó¡ > Ϩ!½„%aqûZâF—5èt´;‘îG ðÑ-$ n¾X~â„‹q»æœc³©+ÑF©ª9j3=UÍRñ()åŠ6*ÒJðPEC^ùù•¸<¥¥¥:th‘l ØÚÚ5ȵ!°¨¬ÿôéÓ_/**⇥/Ù½»kwup²½Oä€)Hƒá¥@pR Q]zrØ®¢âªËÓ7º¬ªüÚøÿxTË„ßÚ*}˜Äà­!¥!Í‘0ráRœ®( % ”€%¯KPÊ@YˆTÄÖª-X°õ Œî9&æws8(**â¦OŸþúªU«.€¾ûÐáÀLõøá‡/*.)îkµ9çæºÍX½kµäkUvz †geF–‘Êp«ñÝJ†>qG[iÖ̽Ià£C­¹›{ƒi‡j)4VÍ®ü4¹êš#,#‚ÈHëRÁˆ¬|Ë€Xˆ¢ˆ%.E—Ì®–ºÃëóö}øá‡/ú׿þ5¡ŒA:nܸV¯+Ø€Jü9Ž´²²²ûòó¬÷lûrË—!•J¶©”ÉÚä8~™íW’;_ƒª¶‘PÐŽâ÷h¢uioµÇëlE“À+-ms4 5÷\Yz 1Màü¿ZŽ%jáå|«òSZΊµ³ø`í–e ?/eee÷9Ž4™@çÛŠ¯cZy÷WC}8gΜùpAAARJJŠ%;ìÛÿwÀ­z¥b¯Lº¨‚Ï]=>…ð3+if7o)9äjÅÙ(v¾Û´9vib¶WÒ,^úlÏ0N€!úHBލ EºÊS6ÞF¼ÿÇû–>7%%I3gÎ|RÖ *ÜÚ\ӊ¯õùÛ‡ Vœ““sÕh¿µ×â÷òßC»¾Q{ÀA-àA¸ £|¢HÄðð]Žþ‘vû°çLv|³*Ú.FGÄŸ.ŒX£ H^úPz±ZFžÓ¤›+Þ~Øþ~®üÙr”`NNÎÆ +6h­Jr­ &êîà 7‰P£YÉleÄPùyQÁ|ÿ×÷è–Õ ƒ Yrùå—?¶xñâÉз:„ýœwÞy=RSS/,,´î»zïj€—.dß¾T l(Aƒ0"‘Ô}é$G ç ¨õà ùAF0ÐU2lj98Må„"–‚²TZÏÁÇðí¶o10`̯UXXˆòòòÎ;ï¼_~ùå„z ˆrAÐ-¾Ö u~ÿI“&Ý[\\li÷_^¾û÷…ªôr$¬NŸ6W…è#ü´îºH,¿Ù­®‰„áq³ÿc–ýJÌ#b½GÚÿu‚¯-!†-‘ ­_µ¡¦定]øzû×–¬¸¸˜Lš4é^B„;Š îþ=zôÈIOOj5ä÷׊_’$££R¼Qù‰”PˆŒ¨#º—BW 6¬™ôîžð8)é$ôµ÷…“8ñMý7ø±áG5{P锨õn ÀLý×EXc$”V ¡Ü1ä#A¢z´¾ÛñÎé»ÄxAAöìÙ3´G9ýõ—¶Ãx(5cÔŸãÎ;ï¼»°°ÐÒîÿMù7¨ó×I„Gô&«ñó³ÐW%zŸêÊ£‘?Dˆ°;¦eLÙÉg"ËC ›‚ó³ÎÇå™—ƒ©gàsù¤öP¢`)`%á ;Âþˆ…Ç#Ü×V‰6­4Ąַ’ÄÆØÔ4Õ`á¶…–„­°°ÜyçwCŸ#À … çZª(~g^^ÞH«|Ùû‹Î‡ª-ݬÝýÁ!ªv¿ºÓÜ}¦|{jò©(àÂ5“Þé½q»ívÌúcö{÷ÞfgãB¦Gb×Oh- ¤ÄŽh#RÕõ,h¢5kþ»mßáÜîçÆüj:uBEEÅ(÷Aê.Ä#Ôz¼Ý5íîÏCªô3)//Ïn¥©Ç²Šeh 4J~JV/ÙýÚN=jénè{ò{ñÅ~8Ö9;3)×ö¾® šj›ôÈÁ„ð'Fhñ½$hî+ëU­ª–§ãôý(–A·‹v,Š-¨ ƒ¼¼<Ûý÷ß? úJÂ-Ò¸‚‡øãèÓ§Ïe¹¹¹–˜ÿ_ÊQÕ}ÅþV¢ªÖ_)Ó¤ Âþ‹T4ôÑ4& ÁfDü>붯Ã}Þš)±¶¬U‰›„à'4+Þµ#‘Ñ|Ьe5zUáäõ¿rÛJŒì22æ×ËÍÍEŸ>}¦xW–;BÁA‡Dà؇ Räp8ŠNglá¯úµÞZ5¼W‰ùW;·0úä£`¥J¯Ù­Kp™~Ÿ­{¶búsÓq`ÿøÝ~¼©QdÂÖ?êy€HÕ¡£65››R^LW¶ž%¨rUá‡òbÊŽÓé„Ãá(2dH Aí©»ûاNzµUòouÅjõD(_]dD°,«ÖñSŠv0`LÃ|Íì0íŽoÔ"…M û>÷½~Ü~7œiNpÉ8'Â)¹(±ù'´€X<€Q3и•ŠBj}Jy÷§AÊd•Iïå;–cXÑ0KdàÔ©S¯ùé§ŸþO–?Ÿ,´9®šƒŽüüü3sssc¾h¯{/ÊÊ¥¨?9Êœ´ëS6”`¡ê%$¼½v¤ø}3µ_ [=[QêÐW"Þ¹o'6íÝG¦ɹÉH)L=Ó6‰U ‹$ÆÑޱ ŘÑjʺ–]‚jR›âä vTïÀ®†](M+iäç矡ñpE¶› Æý:´8999‹çù˜/\Y¾R%ót'È€¸ÊdDF²( ±ªQ€À(üÚçmøgg ÇÀ–bƒ3׉¤ì$ØRmA)¨€„¾Ãë7h5AC"tfaRdƒ%Û–àê㯎úÕxžGrrrÖСC‹W­Zå’åÐ/sm®ÙÛ”)S¦åääX"ÿ6UmÒåM«n?!) o·­Vó!á•[c€Úç˃åØåÚ…Ò”Â:N°6¶dìévð)Råá°2Q‰‘€(`Ì0j¥aZ¼æ ’¬/_: öºËÉÉÁ”)S¦­Zµê_o@Üf@s4úŸ““3,;;;æ‹~¯þ® Kj±Ì°R-vFÃ0 ¬íG ÚÿŒ\|MMõ5QÃb¹ÿt÷YŠÅÕ‹qMÊ5êû烲ÄF;@yé³#1"šÄDÀ¼Ñh¤êZWn)+i—"êA@YŠFo#~Ú÷†‰ú}²³³‘““3Ì`0Í1š£¨m¾’“““ív{®•¶Þ¿íÿM×—OÙýCyÕ² iÙEHd·Ÿ™úi÷W¾ù¯ž_1Ö3ùN©DY§œN(Ì*„}lwbóO ƒ4>NV‰Jw –/&XµgUL°Ùl°Ûí¹ÉÉÉÉn·»¡Æ¢q›LœÂ¯Sÿo¿ýö±999–Øÿõ;tþOm¦ŸÎ_Êhºµªõh;Á(÷¥5”¶SAyŠOÊ?Ñ}¯s !  Bµ6|â/ñ§í"¤]“ºîB±ê*ë˜1YïJ¶ ¦¯Å–[, cNN¹ýöÛÇÊ@³ƒ‚˜fj<[=FXiíýË_ÐäoÒÕïW#ý !·º jÒi×,{‹Â4ÓÏØ¡—°¿z~ÅÖº­êçMˆóoê:1ÓL€ŒíýÀ$•àù?ŸÇÓ'> 'ïÄYegá·òß°¬j™,—wN€@bþ@w ¨¨)L+Ú–îʆʘ_eY°,ëÐܱÍ€qãÆ“””óCª½Õð >p6NRó cj‰T2D*™fì¿ñ6bü?¥1ÁCû«ˆ Ú_™kgâƒþ¸íÌÛ°ýÓíØ{p/À| oZ",1Ž,vŒ.¡ÇDÐÃTù1Q”7:%IH¤ƒ¢t+÷ž‚Bè¾(Ú~¯ûÝû‘Ÿ½±®Óé$'NìûÑGU·h=,¾¬¬¬,999æ ÷7í×1œ"‘"øÒC!ýŠ÷7¶‰ŽÔÈÃø¸®9¨•Ý_Ck2N«ëVã“ÍŸ`Bï àYŽ|7üï4Ùš@9 ÎÁ%ø€#D°Íš€D|^^Ý.i7שøZ0hês"@D) (B¤)‚‰ª€€(¢¼±Ü  OŸ>}¬ÔÈ(±jXÕ´Íl^^^7‡Ãa Œõüuö?•S}i(ößj£³L‘ÔÿXyý„#àSyügïÐ-½ @nj.fœ6ÿXñ©¢k&cgB1 ‰Ñá<š`‡uù1)÷–ob`Ýûˆ&iÀQb¨HU3€ ÒÿBP@@U0PÒÐ)¥£Â¾Ãá@NNNWèã,ñ˜j$jjj‘ÝnIRðÐÅL«*¿¡„¡²ýO"·é2##%ÿÄÝ݇H‰Ø4O¬ÿNý7r“sÑ¿¸?®/»³6ÏXÀ–nkc¦À¡p ­ì‚í=#u ŠØ/ÀH š™²Ö@E Qõ!Ô¨FyßýõûcʘÝnGjjjQs9Æ¢ðk]€œÃá°T¤Ö[«î˜ZŸ¿Z=Õàòkq‹®æ¿ò#ÖÉ›êŃ??oÐ ?`<ÆuoµWb0Q*¬Õ„Ä05™ 4(«ÎAb@3ý†Û€þ^Kƒ¡÷1ô9ÚP[1<×$lš|wÓc"I”V²´†¶fV»«cž>žçáp8²î ´V9h€ã8§•òßî€[Ýñ?¿â UTé™Ðcˆ½û…]µÿ[Ê/d,vvá‘Õà“CÜxòسh~?ø;À\2§vJŒæíèoFI­5ÝYcÙïñ}¾¿i¥`3ÍÃP98ŒH¤&4”êòZ´G Þ†ØK–aÀ²l²Á° Ø €å8ÎaÅèò»Ô$µ{Šü‰"‘St#t߉ú?êþZyKÉÀ¥røÍÿ^ýýUõ$ß?â~tºÀ{Ћ`S0Tê)ñ§ÿ3öO”Ùm•åVÈ.AÚ¡…  ¥cûƒüÒ}uÊÏ©;¾L–©ï§„ÛjÞ?j–^L8ÒuR´aù¯Ñ×SÆX–Ïóöæ@¼n@Ë0 måá x¤=˜JâP*ªßB(U{ü‘¨ ~¼ö³Šz€pŸÆá³êù(ØT€q}ÆÁÁ;ðÄ9OදnEeM%Ä! ÍîAÿŽnZF+L;@ŒÝo ×4ß/¦iýë\†" ˇôUWµÇç±TšŽÂ5Gýˆb¿è‡òsDPP"( Ræ(ˆ$ÈÚ 6ì ¸t³·ÏFar!N,9Î I}ðh·G;´ð‡í4 ‡a…ÃðøÇ1wè\œ‘z·Á/„rŽÀ"¡ZÿÄÇDóZÍþ¸¡”ksÄTlÑäÇÃ&It.A§ ˜x"™­¥ ž€Kå°¼n9ÖT®Aÿüþ „ #)3GÎÄ=ß܃ßkOùVsæð98!õôMî‹c’A±£‡û(N-ƽƒïÅE/“¿?‰¿\Iæ×5‹@Ôÿ5¼€Œ›¥¶&f[s[«KFUGQýÕÒHòq$¯” Íh³¦žŒ”>Ì¥qxqó‹x­à5)•™0Hâ“ðÔÙOá`yírØ2mÍl>ggžÓ2NCwgw©£Wv/¼|æËxîÇçðYÅgàœ\ˆGé fA¼&@T.‹ jI±vÑÌÚ’С›vץ⇄jÉ‹ÓÛ[ÐhŒÁöÀv,ß»ˇC° ŽåðàðñüªçñÉO¤8$VíúõBƒS㼜ó0(mÔí(ÃᮡwÁ¾ÒŽww¾ >W«1u80”ùŠ˜dö¿dü‡e†õ¾Ø‹ð°ÓŒ )gš(€$œiíp €€ƒÁ[;ßÂiE§eXø>Øy;!¸}Øíè´¾^Üú"¸,l±ªG8œ›}.&åOB¾=Gë˜>l:Ö•¯Ãúšõ’ö”Ô1A Ù¬G+@zØ›"D•åצkU~­À”Eµ`(IF픣Ø؉¥{—bDÉØy;=Hu¦.îw1 R pÿšû`¬dãjÜ„ÃÒ‡áúâëQd/:lwÑêEp:œ(Ê-BI^ l¼­y§”Ü0èLûx(Cac%訣9j¿ÙšÖ6¹Ñæ·H ƒØ¡ n,E,XñgZ5%Rîu´h@C6`[ÄÄD} ¥Q„2Í Üz =N5ïIÛ@loí~#;ÇpÈNËÆ–½[Pï®ÇÀ^ù©ùxcÔØY·½súDôxhGPÂåq¡º¾åUå’PËÂ{ îjkÕÿ«ªÑØÔj,A 6bU›N0¡vÔ$‰ÀžbK¶ú¶bëö­X¸e¡Z¯Ž£JsJÑ9«3ŠsŠ¥™[ŒÂìBd§I»{AV6…=ß.i9,‘ oDµ‡4ñïTÐd’íïšc´'ÞÖ&@4s6’ÛÌX€ŽÃˆ  rQ›#H?È)PDN“$& É}¢=NmüIÑönÀZÀ>Z‰ÿíüÆwZ6Oø4jݵ8ûø³Î>9ÇÀô‚%,x6zE%Žå‘šŒÔ t/êŽw¶–oÅ›~ÄŠ+ðGùªŠLRìivµóaH(ÒN; ©š”ó«TÜñ‹êÜã߃]•»@÷È‚,È嬨,l* .…ŸÉƒÏäÁðL¨ö@CÇRí¢%Šš~ ,ë`Á8©{NGJj`Ö/@k½í5ÚÅЪ;Z×_ØI3$?˜‚™ºH@zkç[]:6V"Án+ÆÞ?5®L:u’z¸ƒsà‹ß¿ÀÛËÞÆ.C0¼ïp è>,ÃF%ÈÒSÒ1¨÷ ê=7]pQ@e}%~ÛóVî\‰?«þÄŽÆR¯EÐ#h`C )uÙãT¡r ®€\Æ: ?æ—ÿ×ì쌗ÉMfÁ:Y©ŸÂ…Þ¸&Œ‚E) i)9¬ Zjt4˜±,Ùáí æ•bÂrÇ#f A‡ d¨BæoŸI=%aç9O^ý$Æ?6åµå¸mìm*Ñ6æø1è–Õ ×<{ žÿäy¤§¤cXŸa~ÜpœqÜ(Ì.Œù‘,â(³E™E{ÜX€OðaCÕ¬©Zƒu5ë°®v\Ô¥¢éA§¥4å®UÕœ†ÁlB”ž',ã`À8å];TëMÝÕõ§‹X”7Ú±ê/6”×E\h¹³ÃžÐÄñë2 (CåF šÂ ±>£Ã€ö‚qoîxt½vÎ8®ëq¸~äõxá«°·~/¿ôqðœ¤ú—•–aÁ# pÓk7aÕÎUX²s o[ ñ}½r{áô²Ó1¼ßpœØçDõ5±†µc`Á@ ,¨2ýÛë·ã·êßðóÁŸñkí¯p‰.©5»P³Cd…„PÊX¡WãµYlò®Mzøæü·,׈ ¦»Þ€JyÔÔóc(#Å(åÀiŒ“mò{¨ÀØçMaµ Ê_…w7½‹+û^©~Ûù·áËõ_âÓµŸ¢Ò]‰Y—ÏBºSòd¦dâí[߯ã Ç[¿½¥ÚÎ;|;°í×mxmåkHB†u†á}‡ãŒþg $¯Ä:=AôÈè=0©Ç$ˆTÄÿÀOU?aeÕJ¬oX/õfdIl B¤\{-ŽZ0 <« ‹¢¨çLêˆu¤`›)¯±†ÂH @§ùóçÏ/++‹ùæ—,¼$‰H‘p6FŠóæ‰ä3æH(0Ƭ«¹Iä”™Íßn`¼ ÁW=@‘âKÁ—£¿„“UâY¶a®š{ØdݲºáÕK_E—Ü.º·ÿ|Ý瘱l|@R£ƒ¢W„Ð$@ð="D¯ˆnYÝ0¼l8ÎèwN*; vÞÞìŸTç«ÃÊ}+±bÿ ¬>¸.Ñ%ñ$Ñ­Í@ñ†øiˆk‘‰Wê£|¨—â«k¿Šùµ6n܈qãÆP  @7¥4fA6çÒ/bP¬ê0ïl¬ôÚ&`¼¸bø­1K¬žÖcÞÆy¸¶ÿµêÛ ï;§v=?Tý€]¾]˜øŸ‰x~ìó8¥×)ê1çw>zäõÀôEÓq@R‰ *¢O„à 6‰ØãÙƒ¹kçbÎê9°‹vœÔý$œvÌi8£ÿjìÕ‘aÏÀè.£1ºËhÄ~Ü÷#–î[Šo÷‹±!­ 7ŒyÚ×´‡)Õ¦À¤/'I’¢ºbiÆ…©@›€‰Š¯Ú½ZÁG„J¸AŠd2ŽYˆT{j¥÷lÄØ—Æ‚Ëã$–¼ øÃþ®8ù ÝÇ׸kpûW·ãWׯRø0K¤"(í¢_ÒB“t+zE”f”bî­sѽ°e„°zßj,Ú³ßønêN€A3@w, ‹ƒ " 5,Q¼,>ùûDÐ&Н¯ÿºM5€f‡YY*ˆ«~|¬g¯Ö™—ëÖ‹AQªMÐt§1/Ñ 42˜ûÇ\Ýù*+)ÃÙÝφÐ$6€d<òÓ#¸gþ= Aõ¸¬ä,¼1î Lé<A—T\„ؘdl .›ŸÏÃ^l‡½³ŽR]ptq ÂV ^¼›Ê7µh³„ÅÉNÆC'>„oÎûOõ §¦Ÿ ÆÏH‹´#×Ú?ŒþÂx-³ÿ­iÁ`Ú1ÕSS ØXõMÅ¥¥´‹’[H‰>QEaµ­”¡›kÄ÷¤¼ó×;¨÷ÖëNÇÍ#nF .Ñ+ 5ŸÅããÝcÊ[SP㪠Ùe ‡ÿ'žò$øz‚[ R¹gìrK–*ó9<ø|¶Bì%vò¸òÃ+±íÀ¶V¹„6Ö†³KÏÆ¿Où7–ž»w÷º=Ø’æáCçPLÌ°ÝÆ>Öì5aiÄm8ÚŒ‰ a6Ï¡šJÏ9íN/÷”ü¡N4ªÐÇê:cRBÌ͸ñúº×uç£_—~\0Á† Ä€â à²9¬ñ­Áø7ÆcS…~ç]6ïy‚tIsTsˆÀKJØdl: .‹ŸË£>µS?žŠÍ•›[õz¦ÛÓ1¹Ïd|8òC¼sê;™=h‚tîŽà²^­>¹DXXÜÀa Fu¿#¾@ÕvÌjØ«¦É¤îªìj1@Fh I8‚w·¿‹j¾Á㔡S¬BtKL0ë`ÁgòØoß‹æ]„¯×ëm¾žy=ññEãÔÔS!Ô ½ÒwÔ€lÃØ°É,¸tuŽ:Lþ`2Vo[Ý&×ö¸¼ãðä)ObÁȘX0œ‡“4íw;&Zx¢<Ö£M9€X6N»öª3îøJçØH]b[jß1€—ó†i£Ž‚#à@°QÞÑ I"à29²¸iáMxfÑ3:pŠ=³ÏŸ›zß±^öDêMH¨Ä¤2ð¤z0íói˜·z^›- ¢´"Ì6 Ç,Äù¹çƒ6Q‰3IôNŒkÝG<æpæL A£ãGª]SꢫU:5߬´FÍ×õhoÍÆðÁΰߵ_='Iö$œsÌ9’Jï‘*â‚àØ4l.‹ÙgcÚÜihhjÐzcpÓ°›0ûŒÙHö$CpK¦J,3EÜ·ò>Ü8ïF)c°F~J>9í¼Öûà ý¶a@˜Å½€YÜs»Ø÷J‹ÆÆWY„ö)'îe½xyÍ˺óòüµÏãýiïãÌü3%AöËMx€IeÀåpø¾þ{Œyy \^—îµ§u? _]òÎË9ÔE%m hbƒJ.×éýW-Æ9/žƒÅë·é‚*Ë+Ã󣧮½ÇÞ ›Ç¦‚\‚°Î ´g=€#£ò¤±ïš ñ¯j²ÖŒvsÛGY6› ý ûéÝl ‹“zœ„—'¼Œ§Nz ¼‡‡è•8ÂI¤ŸÃcŸ}f­œö¶™ÎL<~öãXxþB¼6ì5\Yz%zØ{¨Qeêù Ã3êûU;«qí'×bÊì)øqómø³ ¦7Ÿý }¸>\’6`%è+1Úw´m@{³ùŠz/“QêŽ/ÐC¶=1è Lè>!âyÛg,æœ9ŽF‡äî Hü ,«^&çˆQ¹ Y3:£¡¡½“zãƒ`é¹Kqßû1ÃpÙàË0ª÷(œQrü‚ßîùmû+÷¯µS° ’DÀ¤1\VÖ¬Äwß|ñK)*Ï™‡ÒœRd¥d!'-™)™Hw¦ƒc9¤'§ãÔþ§¢4¿Ôô·Ô6ÖbÃö رovTíÀ–ª-ø³þOAiÅ1Ro…ÃÒÔlC0#ËkP:þh»PK…‰Z"Q£öë\wíÙÀâè—Ù/®ãOîq2f ›{¿¿‘*ì–`yårLê-ùÛØÁ“×=‰ËκL}maf!>žþ1þõÑ¿0ï·yø~Ë÷ÈMËŤ&aÊÀ)Ùe$Fv‰ýîýøtë§xoÛ{Ø‹½R~F “ÁH9MR z¯ë‚Vkb"ÄP ?û»vÌ#õ´ªTGÒþªÿ ÙŽì¸_—Ÿ‘«]çy^Ú=S,+_¦À ÝOÀiÇœ†ï÷}µuk1êÅQ˜}ñl ëj4r|çãñÅõ_àÚ¯ÅÚÚµ N"TûªñÜwÏá…o_À™½ÎÄÔ¡Sqfï3ñèiâv÷íøß¶ÿaBï Ȱgè¾S¦#™ŽLôÍë‹Ë\¿àÇâí‹ñÞú÷°lË2‘\™`¬Dö¥2j×_0(ExØ£Å0[«‡²A(Óˆ©SÓÍòä]] ÓÕ¹ð”L=ñðs-+_ÖìS7mø4z"å øD¬¨X¡{þö1·K.C¨ákpé»—âµe¯éŽ)H+ÀG—„ó»ÊP)¥8‹›ÃéÀ’K0õ­©8ñ±ñÂÒ "¦7-LøMÙ}Ö†Ñ=Gãí ocÁ pò1'ƒËáÀðàò9°Ù¬¤ò'ID¦BþÅâz¤N³NY‡BýosÐîÔa?ZCàé’s”¤#Ùw^è¯ö|ÕlÏNÍÆé¥§Kþs€?þƒMC„aÙÉ8¾ðx ìͤ¸åý¸yÞÍð|êqvÞŽ™ãgâîw¨Ñ†lŽvÌåp¨Và‰oŸÀàÇ# âþ®Ç‡÷/}žõ ìv;ÀKŸ£6÷8Z…<ÆóÑŽi¯ ©¶MŠdó(Uväˆ= NäçöYe;];±xGóCo/x„¢[*J²b^ ¸ê´« ¸ (¹Õ¸,óËçcü+ãQYW©GÁͧ܌WG¼Š$o Êǧsà²8p¹¸lbŠ¿àoÖw%„àªAWaþ…ó‘Oó%oBà(Ë llÂ(nôÃ/Èh—+ÝäÈ=¤¡¤­6@Å##̓¡xö·g›]ÝõøîÇKÂ/'þ|[þ­îùq'C2¤çEQŠöËb±Î¿ç¾r.~ßù»îøsŽ9ŸLüÄN¼‚tM’$ÆžÉbÀæ²ø±¼e!ÂÇ‹&~„,o–ìOdÆJjpx˜&6> †v|µûŒØÂüû: !ØÔ¸ oþþf³Î_Qv‘”ÿï‘ê~_þ½L켓Oœ ¡Qª 0\‡jG5&üg>þùcÝ{Sp ¾˜ò% ’´‡€ägìR•¡·6½Õâë^’Y‚—F½zBp  ¾„&`UhOõ¿íI@MAMU½—ÛOA€«þw¶Ø×9þsçŸjô J«aÙ^½g¡s^g - ¡Qª¬Ö´I©Àl‹Ùëg㪷®Òi<Ëã™óŸÁýî€P'WDPBq×ò»°ù@Ëˉ]6ø2«ƒR 4ÿQšŒx÷‚ )¨\I¢ÜXm«)@[Àê¡™„jÙZŒÿ︸JtÍY0G¶%ä+ÅP|·oE8Y8èÉÞö U b˜.‡Åâ_cù–åaõn~+žþ<ØF´I(…‹4â²O§à¯µèò÷+í¡.±A.e&ˆGÙ–Ä×¾QmmË¥‰ @Eyªì¦üó#œª=šÿ 4òsbJ9ˆ ÞÖ€‹Þ»þ0Ü^wtáÿb>\þ! GÏÀüVý;| ºcÏ?é|°^‚[„è£úl–€8°™ìX;odžÝt¯¿ðø ñÎùóàt'Cðˆ *ÅýÿÎøÕôú½<"—(@¿VqND¹æñ¬M3¬ Ý hÕLÚ&*¾€•rüi:ÅKk_ ž€ïÍÀª«PÛX A°¿f?ü°“þon{ñ6‡¤Æ3ÉR<=%A sf§e㔞§HÞ™/Ð&Ià–U-Çrøy×ÏXøËBÝ{ ë> Ÿ\ü r9›¤2eµ\-.úïExfá3ðãw®ÙºFmf¢t%*Y(gghtÓ–£í“C"ˆ«€1’PaØÁ’ÌÎ6q0„ACC^þõe¼ôíKÝ"¨W¶ó©ËL:6EŠÚcÒÀ.Ã5–—/ǘcto}íˆkñí«ßBð ÉRì½ÞQìîdžpéI—bàÝQ^]ŽkF]òƒÏ/û—¾{)vxw€ØÄ4Oýô>[ûžÿ$Nê}’åŸûÒÇ/©!¿Úä—Ãv˜äè’š¢$ÿ˜µ‹™Ü‘K‚%¼™š€™ Ø\'Nš…œB›Ç‚+þg % ©àCšT“Ðv=Îxúd÷è–šëÊ\ÂÒÝKáà¸á¼p×;wá±Ó»ð²JðÙŸ¡¯£/¯ Ef0Ø"lÁØWÇbÜÓã°|ýò˜ëcî—s±ä·%jM°Rüb´ÑÜaI@DáDpXñx­ëd;#5óãçùb|g¶Rø|/õL“ÔB¤$kÃï0ÄûàŽàð9$— šj[Kö,\~Êåp¦9ñÔ¢§p×;wéÊe§dã“+?Á°ôa›D©Q.ŸÃµ?àÂW.Ä »á¾wîÃ’_— ¼º^¿5 5øö·oqÅCWàæçoVS€FÕö.ÀÈî>‹ s  %ê¸Yá £¿Z‡2©'5ô@@¢ò%DÿÇo^¡K$rðÌ2£òGAtI.&‰›É‚Ë“L¾˜×™0\ž|[ ÏL #%%¢ýâ_ó‡;`$P¢8Ä٥ôk§Ù7³/º¤u‰®\‚Æ=¡FB„}¡×_ØíB,º`.èuàÄn'bòÉR `é¾¥˜ºú#ä¦åª ðÊäW`{φ`RúCY^JRKnOG2Ÿ ðš°%ïÌ·®Ú^ýéU0i ê¼uÈqæD<>Å‘‚‰e1gí°< &‰Á&ï&\ðÊøäÚOPQ -–Ãì)³£~¶“wÂÉ;‘”.éæœEš- nOGiºy€À¦ƒ›°±z#~Ûÿ~­ú›ë6C€ph@Á Äãê¶ '‡wQP#  "¼Ö,"Ðõ×Qû´öprθŽ=h4f;Œ‡ÁÖê­Èéœõøá}†ãµå¯IDípyþ˜—Çà×ÿOWy8(ñÎÊwÀp zæ÷Dï‚ÞÈJÎjÕß˳<úåõC¿¼~¸¸ìb€ËïÂå?bUù*|_ñ=Ö\ÊÐö„B1âÕì8j~߬óu{ ®#.ôÃ:\´ ‡³Çuü‰e'ž–l^‚¡‡F=¾o—¾RX²›‚¦RÉ%™B°Û½‹6/Âeƒ/Ïòª&0éÄIûàXü²ã@Njútêƒù=л¨7z—ôF¯¢^(É-iµsbKÁY]ÏÂY]ÏT¹«°tÇR|³ç,Û³ Á†PÛ1’X3‡D*‚ˆ e@©à¢ô$4TžP@h4ú‘fO³|¼³¡qüxðGÌûeî~¼#âñ9é9}"„&Ä/&žÉÀÀ.Á³<*ë*UsÀiwâÓ{>Å9÷žƒû7¢ª© UÛªðÝÖï¤ P9ÁÉ;Ñ«°zõFŸ’>(+-éNJTgj‹ÏInr..é{ .é{ ‚b?îý_üõìX€Jo¥KÑZ`ÐB ÀlÇ7kª%Ðk/@b´îh 6Åýš~ûz)ÔÀ[?¿[ó ÊZ5Q}„'è–Õ ðëŽ_±£rGÈ–ONÃÇÿ÷1ºuQÃ…¹"l±”çÀæ³ð¦z±®n>Xóœÿ .~æb]V„½õ/]r‹w3†ÃÉOÆcg>†5ÓÖàÓ±Ÿbr·ÉH¥©úŠD‰Ñrˆ§*pÔ Á‰iyV¸*â¾NeË?@ƒ}ûöÖíxlEU…$$A„JµÉvuŠ-0¢ßLy| vì @Qvæß9¹)¹R4c:.‡ %;˳DêÄ)`0óû™óèì¯Ûßú ›08¹óÉxîœç°áê xáÔ0$sˆД¤;Ô×5†'à°ŠUÞ¨¹¾ü£-€RŠò†ò¸Ïi~©T|5@ÑèoÄ•\©‹ôÓŽUVEôÛ+Ú‡³áÌgbÔ?Faû¾íêk»tû׾ {Ð.™`€¤4 ˜,L&OÊ‚d Y°X¬nXÓ? Ë6,k³5èà¸ô¸Kñ¿‹ÿ‡•“WbZ¯iH &é‹Ò¶G< £™lȽ0Œ\$À–¿jã/ÑÕ)»“Tˆ5(ý\S½“Þš¤ òQÎû럿.å&pr2’Æn®öT«÷§œ†Šº Œ~`´ÎÔ}^¿øuFŠä¥â `œr‚P*&#Ô¥¨ÚQ oLÀ=ЬÆ$ñŒž9=ñøˆÇ±öšµ˜1x Ø©˜ªptšm_X ©:ºÄ1Â4S‘DÃëÒi¬ledH*½_>°ªjNyæ¼õí[¨i¬A]c¦?;¿nýUJJRxés³íÙHµ…»n…Ý0¼ÿpì­ß‹óž<Û÷‡4óœ‡ûϸb­\Î< .c/w Nc@²žÿñyŒ||$vîßÙæ ?Ý‘Žé'MÇo×þ†Ÿþo³Å MRÉzÕüiɤq<'ÓÞ?œ9­jQMBûT[=fsÀasèû.IÀ>ìÃmŸß†.Ó» øŠb¼ùí›ÒΜʀ8å"Djì:gäd82tï{˸[$ÞÀSÑ/ŒÆÎ!¡½ùœ›qYÙe¡\„Hj6¨”æÌKæ“Éàw÷ïúØP¼úõ«í Ëp¸tÀ¥øéºŸðÆÈ7ÐÍÖM s¾³ØºkQõ zgDŠ8|“ nµó/`RTOiBZ:wÔïÀ׸N½ÓáTMeG! 5 ÍeÁæ³`ó¤ûL’FÔ:ãºÃÐNáñ#ŽÀôQÓØç݇óg½5!‚ñéÉOã”ÜS@¨Ô´$’†'“Œ„#Rg£t¾4î^p7F?®71ÚÎ?ö|,½r).ívi¨ÏBKûV͇?üÝ€Q~¤ñžk dÅ®ÍÒÖtˆÀ1Y Ø|ÙeWÀJ]}rKo Lê=)âû>zÅ£˜5uxÂcgÎé|”×”«dáÜk梔+…Ø(Æî©RqHÕ‡Øl«jVaØ#ÃðÔ'OE$.[:ÔÀâŸã™÷ŸÁåO_Ža÷ ÃÛKÞuQ}ƶÎIF`û%EøQQŽÄH AGI.¬Ü³Øüë v]†€Údá”f´…HäˆúÖSN‚¢œ"LýÏTìhØq/÷|üô|d¥fáÃ>ęϞ ã’Ì m…¢C >bX>|óÞüîMÜ?þ~L6ÎEå zðÂ÷/Äõ§Ý‰ç¦<ê–ñ²ÝËpÕëWAô.êY“gAllxÕÍ× @ˆ¹·Ë¡ÆIšé ¡—ly5´™´õžÚzÃÎÚ­Ñö€øÜOòÎ#Šb\vh"(²JüÑÆ,¥Òê8€æ¨´˜óÛì:¸+®KZßÓpF×3$¢Žl[€çÞJ)ÆŸ8ö7Éh’Rq$u-Þ¹¡ý ífµè›pðŽ0BCE­6LÇŒèm8‚`Ÿg–lYó(>šË€^Üòé-q»¤®?ûzˆ"ˆàƒ??ÀïJmͺø! Ì(Üø:Pznk?¬K÷¡|¢oiŽ<¶šJ#¦/šgy)¹&n­°’8\€µBrT™ „!xíç×0²ÏÈèît† ©¾ÍQeþ»òïðÌ’gpçˆ;-¿tÔQèäè„}ž}`,HÁœ5sáÌÀŒq3ðÉíŸ`ÉÆ%èWÚ;jw`Cլع?Uü„€mOòw>µó©˜zÜT -мä<„ÊÊñãž±`ó,Þ¾Xòõ3Í3wšk˜Æ Äñ>Ú­§LéßCÛ(ˆ¢”­ªè¶ ŸêAE©÷aP‘‚™”¡Ê3‘.šN°iìò`Gg@ov,Ŧý›Ð'¿OÄÃT"¨H@E"‰û³(GñÜÊgqÇÙwXBbƒóžÙßÏIâžùþifâÚá×☂cpñ ã¼Aç⊓¯Ä§Ü‰¦@–o[†Ïÿü ¶.Ã0ø÷˜™Û{¬~ñ2zd÷@ì˜2` vÕì“˞Ļëÿ ÊÑÖ© h!ú4¬E¸™»í@Én5Þ0õ>Uãfœö$K_Q–ÇfÍ2‚Á O„˜äDŠ=”"4•¬4E €H©þÃÔ=/"ê±GÕ@`ÖÊY±µ0´ü³@Üă¾| ®µ2úÄÑ  ±‰‚Ê$™Áÿ»ï¯~Ç–‹—¯x|û!Ý;g?u6>ùõœÚõ4Ì?›nߌßÿ¶&LøÍFiV)^šð]ñŽMí Ñ+¦ØÖލ¿U×µê?ç)ŽÔ˜2&‚Á ¯­9]¨B h²¢u¤ÚRÍ󡄈Ÿ(SAÂÄŒ0 ðÞº÷¢t ÃD¬¯o~;a^øá¼ÿÓû–Øc†€ °RmÙÖ'œÄÖßôáMXºa)úvî‹·ÿö6º§uÇê?Vã†×n@¯;zá–ÿܷ׌¤Œ¸õ.CðíMßâÎÁw‚xˆ”( uòü­LÁpkF*3¨¹6†ïg¥,¥@  æ ­FeFôxO€’BK>úã#lÚ·)º€Vú<– ÀpÅÜ+t•€¢c;+åÖû5®.9²Ïgóáµï_CrR2¯YŒ¹7ÏÅðc†KZ‚ƒ ²®²ETÉI=NÂÊ;Vbbω=-ÌñaÉÏkZ†P@~MaF¡suuuL¤m€XYY¹×ï÷Ç´OŠÒŠB §I\€• 0Æ4ÆÒ ¬€-ø—¹+Öî'£ZøyÄFPGê0aÖT7TÇ|I¯’^R©qC¹ñ4g¾¸þ L4ãgŽÇØ!cqÏÛ÷àÍëßÄ„&ðÔâ§Zü•S“Rñú•¯ãùÑÏÃî³K +ü¶¹ÏE" £Iö}¨HQœQSÆü~?*++÷Fˆ.hUP-œµk×þå÷ûc¾¨sfçP(°2uš€€ØuABa…4–l_‚þÐÔ=Ú¬ê41LØ€M;0õÕ©j¾A¤Ñµ°«äöC§†¿|ÁË8¥Ë)8¥û)xøÂ‡qÉ3—`êð©¸ä©KðâÔqýÉ×cÞêyxrÁ“­‚•Wvß´X­ÿ§VIj‹à«¬ùÿÎYcþ¦@ €?þøc{Ý¢Õ8ªOá›o¾Ùb~HAj’¸$SáUkÔ‰Ö§uËÌ8*zÎsÀŸÝÝwë®ÁŸ;þlÁ7«Þc'øaßøÛ›‹»Ñ)§“t½ƒTí4¤hÎí}®zÌ…ƒ/Ä%C/Á>>E}páSâqàžsîÁCŸ>„ÉÏMÆÁ†ƒ-ã:‡åw.Çi§I-ÐÌL‹  Kä‰'"ÐŒ4¼6‰OBqFqÌßã÷ûé×_½ zšÓ²Ð, ~+ž€‚ô‚oSò„&¥ ¢QAE”ª¬`ؤÍð㊣Ã')¶¢A¨Ç”×§¨ÙwðËÆŸC»vk& ðáà‰Ï¸r2rdÆ›‚tí'ö½0ì¸;&Üü”|l¯ÜŽí•ÛpáÓpËÈ[ðïË^À‚ß ßô~xúƒ§ájrµ²S³ñÉôOpåqW‚ºEP¿¨[“üÑ&·ˆ~¬É95Èä[ù¼Pù{(í×,xüÕ2n3Ð*è·Û]c…ìœÙ¢ íø¢@!ÒÐTd¿¿Ù ‹ €!–9"_Ÿ#rÁºêu¸ø¥P î—«J![,†€’ÖEG€$‚Ǿyïÿ`îLOI—4EéZ*lzì‹7¿ˆµ[Ö‚!,¾Ûò=&>?—ž<»_ÞM³7áô§ãñwÇÿ½öضw[³A€c9¼pù ø¿³f@l¤}¡õhº~~‹H`†ÞSz£ÿåýqç¿ïÄ¢U‹â2n>÷f<0êˆ b¨'Ð@4© Zè ŽS£bMúˆCº‰ù½½^/Ö­[·ÎÄ[¨Qø?øàƒß<OlPn/ä$ç„¡¥öÇš58 &‰aÑMÇäPO>’!ÃàÑv àŒä¬¡5?s¼Z &ÕNމœ†’–œ†±ƒÆJ¥Ã¨äÆ‹4.~!VÌZžÝzbKͼôõKÿàxŒ+ÀÀiqÝc×aÖ‡³ðÕª¯°e×Ô6ÔªiÔ¯›vn¼Eó°à»Rz²W㩲`ƒÇtÿ™¹µy†˜J)2S3ѧ OÌÏ÷x<øðÃ3˜B<€Õd - à÷x¿/ÌQßTô¤ÈZÀYμïæúi(•9ÂèQÔËž]†‹Ÿ¸«¶­R×ÙŸõâÏþÄÛ+ÞV½:3Trb& P ¯–©Ìw´ÇÌŽ1k&èMä¾%}c«ä¢ˆ@ àñH»p››FðÕÔÔì b7sÖm˜¹Ÿ_@˜j¤‹Œ2­Ç³aI¨×ŸRà²=x;°bÏ Ü<çf€ÛëUä‘Ûß½%ø€ž¤ÝØKQï©Íì§ecÁý 0nÈ8é÷¦©ÉIžT;P)Êdëˇ1roÂd¹$8kR7!†MÓí©÷Ÿ`ЯåÇOéyŠ%ÿÿÁƒ÷ð)Zy{€"ü~¾5kÖüÒÔÔÓF<«×YHáR å>qŠW@æ´©‘F+1[!h§= \Â…‰ƒàݵïâ™ÏŸ/è“4&ô=v×쎺à:åv’r|@Em…¥EjçíøÏmÿÁŃ/–´¤J™R5a&G® œÇ‚Égt“Í–ª‡Ô,E·ê#ÅïS À`¸¥4Ô,U½¯i~›bKÁÈcGÆ”©¦¦&¬Y³æü/@«L\þ7ß|ó{·ÛméÃú•ô‹ÜÐ@’ÄâÌxD[ñÈC$<°è¼²ä©0§¨9úUGouž–œ&©íŠßwünù£Y†Å«7¼Š+†\!­R v©ú/IÑM×héŒT@Ô)71´FhFÒ(¶4 2˜ Zy(+-³ô;Ýn7Þ|óÍï Â/ ΞÂñ–Wãøü~“Ûí®·’xF¯3BYÆ[Ñ þ šHÁfD&¢;†ö¡¸_úî%IÍN’‰H[lº^š|MêvóÕš¯â–a1óꙸvðµRÉ19h•p’;T5‹´“'úf%-Ùýi›_ fiÃpVÙY1Ÿ p»Ýu~¿¿Ic ¯*Øê&Õ’€ò{·oßþgSSìÆgö>ŽŒ# ,>@1 tå¿#ØþÆçB×Ay^ÞYS%Ïá%- –p°ö *@‹Ö,¾º}ñ)!„àÙiÏâÚ¯ ÕмÔ_«¶¬Ða ©®Y¤%¥aä±#cþ¶¦¦&lß¾ýOH~Ÿl“d @ ¬Àܹs¹ÝnKo0¤ëÉǤR €†P…4î#XJ‰C”òÝœ´Ån­Š®lß»]]Æ~Á>‰¯‘2ž¹ê\ÚÿRk `ņ7Ûýa‘ü3)¢n€0¤çK¿Éívcîܹ‹ Ðæ&4D`P€mÛ¶íw¹\VJ„?~|èkjã 5ÿ«Da0ä úD¡ÃkBNÒ¨Øuðø#Ç‘üþçï!“æý8sWÌŸŽ ³oœ ú\`U¿K~Xêî+ßRŽâ¾ÏîéwŠo~ý&®…nãlxû¶·ÑÕÑ5”lV—2ÚnAKÐ=oÜý Ú®ò8)Îx¾¥ßÑØØˆ9sæ,Œqwl®Ô@Ó®]»ªj¬ê; EéEzõ'ÆB1#Yb %ìþŽ?×î]kºF¾úþ+445HÑ‹œd:BT×âÚªµóÈœxÉxgá;¡HÃXÁBéÙ˜Ï|¤S¥"¥jÌ#óXµý¯€< Ò 0zÀhKÁ? 5»víªàÑ@°=4# ÏŠ+–[1àÜþçJ»s0d½µ]Íô„°‘sÙ–e¦ëã…w^ü÷<lÐõõ#œäU`Òl¨Ù€ë^º]&uÁßžüVü¶Bj?etïÔ3§Ím¤Òê ÆŽè‹ÕÍÚ4Ë$ðG§ (Z€@qî çZ’ǃ+V,—…¿Éb3d¹Y€Ñ hàyã7¾s¹\A+6÷ä!“‘›œ1MX÷If±Û‰qDŒ=µ{°v·^ X°|¾ÿýûPãOÞ˜ÃJùÄI¤ ž, ¶¼õÝ[ù‘è~QwÜôÄMXðÝx¼æÒÄÓ'â’Á—@t‹!S B@ÚôÃJ¬?»ü—]JpNZ.?åò˜2#Š"\.Wð7ÞøN-Rÿ›«h‰@Ÿ<7n\gÕ%8æø1a¯CZÑ$º/îš§‰Ñ¡Ì]bö«jªpÓ#7Iª¿CÓå—!a¯#¼ü|ª r¨ï~ºo.˜ˆ¢±E8÷–sñø›cõºÕ !IôêG‘H–L ¹‡µü²Ð%HWØ“êÝŽºž˜òæwÞÀó,»þ6nܸN‘5Yî|-!€Ä ¡5ÉÊS¨;€T™òeffv3g΃–š1Myy *+U[OiãLØP6–®½S¤6O$!K‡ëà_ßö58Êáš®ÁúMëAšTæY Q¶#%È&I˜ýõSµ9õIBžjKũNJÓO8CûÅ‹Ÿ¾ˆÿXÍP›ÝÅÓî‹FØ ”ï¤m*hÌÝ ›–‹÷o³Öd¥²²’N›6mFmmíåö¨Ð(AX oNsP­à×hîÚÚںݻwoKMM표œóF×—½ÂPAn6Jô‚MEªß(¢Çi'Àà°AÄðG†ƒÖSˆ "˜9!'ŰûG[Ë27 ðÔFAƒ€;àÆÂ ±ð÷…Òêåâ$Pð¡Í.¦ð›ÝŠ&€„p‚6ùmÌ 1–wÿÝ»wo«­­­àÖìþþ–¨ÿÍ33À#1׬Y³æ?þøãwZ€É'MÆw[¾Ãæ}›CÂK '—…þ9`px" "œrΆ²ñÁËMdãYÚJÜ+ååúòîK‚$Ô¡H®“@éIôzšFT€FQ÷• 6y÷ïÙ©'¦ž2ÕÒOjllĬY³æpÉræi õ¿¹€Ñà“ÙH7×æÍ›÷VTTìv¹\–D.xaXD”1jŠõÌ©eFÖBÄÄ¡Ob‰ZƒIg¤¼»>}8îýZ®À&ñL’”÷¯|“Ê€q2Ò1ònaê}»®¤øc¼‹¼®'œ8Á’|¸\.”——ïÞ¼yó^ h#[D7ŒÞ…tp=û쳸\Öj²UvÆž06t¢‚& @ Fh¦`'À ãæ È­ÀH «÷õ5sË)ž„r’äÏ”C”McGDD/úAuj ¡*ÀpÞ ó0ò¸‘–äÃårá¹çž{_‘- Ø"ö¿54E PÜ 4lÛ¶­|Ïž=;¬zny›T$Ò1…]l`'À ã.QÔwÒLá· šå¾.‰,RZ¤.¿fkJ0× R©¸sì–mÿ={öìܶm[€ (î¿;Ç[F2P5¸üñ÷].—edºñìCAZ¶ÔR+J0GÏŒvݬ<-ÃO´‘’Ñ„ª¿Ü0êËær¹èã?þžf÷WÔkìþ­¡P¨Z@EEÅþõëׯµš#0¢ïŒ>at˜ GŒbWa‰¤ ÆúEq·XLŒv±®M¬â°Æj<°ÈôGZ|üºè?5pÎ`-꯱±6lXWQQ±ß°ûk Å+´5ŠDkµ€&ù‹6h|à>ihhXÉ€¿Ÿûwd'g‡ÛN"5Ïù·‘„Í„(:§Á>`h»SSùõñ ¿Yý Í:ÎJÎÂÝÜméçÊ1ÿûï¿ÿcE–d¹j2ìþ8Ô@M´·ŒXõ‚ ÔüñÇ Ý·å´Ñ[Ͻ5,k*lІ^ê±:³¶¶‡ ZâRb¶žZë¼Æ:F4·×Ãì}+D_„ãŒj¤œÿ[ÆÞbYÜ7>ýôÓ…‚ Ô˲Ô`¢þÓùóçw @«ø´f€†÷Þ{oõî]»+­‚Ãzäa“Bî¿`{*¨×º¢µtáµÖâ3EöˆäÖ8ñƒ‰à›nVÊ™€ÎS%¼WJT¢\xÊ…8µÏ©Ö‰¿Ý{*ÿûßÿ®V6RúïkÍÝ¿U@F!c`[V[êÔßwß}ó\.—h¥x(\wæuØu`è$ÊÅÈÕx€`0É»nÖBŒ y´éŽ ÙVçÃʱ&ùø¦y"ÕÍßG›¢õVi3Zúuy|×ãñ·‘³´îåj?âŒ3æ)²#Ë‘ÛøÓ»kjÆÀ öïß_ùõ×_[N€'&?îùÝõ@ACPhÑh­öhÜÉ¥–ÐmÀ¤ùl<˜Í> ]|Š~h´Õ®ù]ñôUO[^óž&/^¼|ÿþý•Pvÿ Z9/¶U@£ˆ-@Qaê^~ùåowíڵߪ)Ï]þ Ó õ%Ä‚†²â‚IÙ¥xÊ4‰mPþJLLK³¥ç5Ry.³†œ4¡&M;i¨|—îy!BsO“u™Ÿ‘_ûoËkÝívc×Î]ûgÏžý-€:Yn »¿Øš»«jò— Z€Kuwß}÷ÛA¿ßoé=v'›ò˜Ô\T[RY aVtÄNK¼ ¶ÿðbÿMÜ‚fÍf#¥ìF\'¢áqù]9ohv|ÍÚÌNÉÆW>§Ýiégúý~466ï¾ûî·5Âo´ýƒ„ÖþÖ6´§NÑtP__`Μ9ŸÇã(Ê,Âÿ]ôÈtdêÔÕ3Æ\G*ÙÔÕ<¡æw\Àp\ÄRpb ³Ðì}sõ_W˜",X)2“2ñÿгŠãbýçÎû¿úúú*YVj5 Ýý[}´*ÈèdP/ÿ¨Ú üþãê×YÍ€c‹ŽÅ?'üI¡L.M^µ® hš“G­]^,Qس}½^±þ£hÁ®â©$¸!¯_YwiŽ4ü㢠_i?ËkÛåráÇÕ?®ûüóÏPc~ß¿µwÿ¶Ò´„ _C*ÈVûÐC}¶gÏžêxø€ºž€;ÇÞ‰ gFxq-)HCՃà 5FªæšØ«X€¨…_­äŒDÓ„ð]?LøM’|Òé¸ë»0¸Çà¸ìþ={öT?ôÐCŸiä£NCüµ¨Þß!ƒ[P Òiên¿ýöÿÔ××û­´SÆI½NÂ=ÞƒÌäLÝE kbÖ(–+Y%1ÚÖ¾r¾*³ ì±hå¼"õ©i']¨º@‘™œ‰^ôO ë3ÌòÏojjB}}½ÿöÛoÿ,ô5ûßÕA?í¦D05?´ÆårxðÁÿÛØØ(ú|>Ëï}B×pÿÅ÷#'%'LÝ×ŘE}Ñ‹¢9‹51›ŸˆØÂµ¬µ(ø±jù™iÆJÀ¢yŠì”lÜ7å> îi}ç÷ù|hll|ðÁÿº\®ŠLhvÿ6WýÛÚ0#S ÀA56lØ6kÖ¬ù 4 ZçŠÅ“SŸDaF¡> à¡yLç.ŒâúIgÛÏh„X›dFãD=¨*¿1ê4¨!eÓ³ £OL{ý:[·ùƒÁ è¬Y³>Û°aÃ6YðÊrÑ}µŸ6¯…Ýf``4¨Y²dɺ>úè[·Ç +ý•Y’S‚—¯Ýòº….N¤°a+D”Ƙ˜m;ã&ã‰ùç1³>&‘…ºx ºæwÅ«Ó_E—Ü.–· p{Üøè£¾]²dÉZƒðkUÿ6ñù·»Å+ ˜ÕjæÍ›·rá— T܃V‡ÓîÄ+7¼‚ݪ]‡Uò¿™`̤֒¥S‹íËßzì< é1!‚à+DŸî=Rµíš(Žïq<^›þše?¿bÚ¸=n,üráOóæÍ[©]ÿ²<´ ëßÞ&Báa^E ¨Póâ‹/.]ºdéïñx”ñøåcÒÉ“ÂC…eUÍø˜v§+3fULÔl@KÀÂx] ^ %ŠOñéëŠyˆ†ÎUòšxÊD<5í©¸×¨ÛíÆ7K¿ùýÅ_\¢~e÷7²þB;Ée³«Ç¥Œ7ŽhL T‰ÕLæ™gžùÊf³q§vZ¿ääd³žǵç\‹c;‹™ÿ›‰ªÆ*©œ4#_x TÓ_@®þ "W%šo¥½o$ U†[ÏЯ‹ƒ ãŒÞ#Qï ÌNÍÆ-ãnÁ)e§Ä÷•)…ÛíÆŠ+Ö?ýôÓ_i6=­ÝoTýÑ»»i× *ì6˜Õª{ì±/—,Y²ÆåvÅìófÃú ûw½‹ÑG‡ñac G´TÑX¬s[ºÄŽ"@\L¿öyc[9˜ûùµÄo¤ŽÀÆuBƒç>ÜóAÜÂ/Š"\n–.]ºæ±ÇûR»Îåu_P¬°­]~‡D0hŠ9 TV@H×ûç™gžùª©©)0zÌèÁÎ$'8.¾¯yû·£o—¾xùË—¥.³¢ô)”‘.P6|l’!µË Wž9S§N6a„SÒÒÒˆÍfkÖ|îóç°àÇ¡c,ôaM!($ÔêïdXü84OõxŒàž°Òqf‚¯x% !EŠóN<wL¸£Y?Íï÷£¡¡ÎŸ?ÿû¹sçþ |EøkÊóW£ýš#üò¦Ñüèp Åö·pHƒÔgP9gžyæ±7ß|óè””Æáp4ë‚,]»Ÿÿø96îÞª@‰ ZA&0Ñ HBàÛ” °’½G |Ílm)/PÓêÀe¥e{ÒXŒ8~D³~’×ë…Ëå_|ñÅß|óÍ&;¿Ñß/ Y~-î^~…éô™ˆz¹¾ùæ›õ{öìixøá‡'¥§§óN§3î:«ÿY8«ÿYxoÅ{XðÓTÖUêÚ‹) GUûI0P™æ1Þªìh"i;¼w„ž‚†«üZÚȤÝ|$Á/È,ÀyCÎÃä3&7ûëz<Ô××f̘ñáæÍ›wj¿*„}Â(/ß!Ñ4ZL4T²&#Ϭ”””ÜgŸ}vRIII–•¾ƒÑÆ;ß¾ƒ?-@ucuøÎÏhTÃî¦DÐT`0.Ú„fÐ,û^'è‘ÀF #„õ*‚Ÿ“šƒóN:—Ÿuy‹¾¶œØSó÷¿ÿýCMx¯–ð«E¨¶¿ÎÝ×»ÿ°4,‚@º†È‘ïgþóŸÿýáS¬Ú´ õõ‘‰A4„h»Bõo9§ š?oZÎhóSŠô”tœtÌI˜pÊt/èÞròJàõz±cÇŽƒ÷ÜsÏguuuUá?¨Qù•š~m"üG @@qò²I¢á25  ýꫯ>iôèу’““™¤¤¤V[‡K×.ŲµËðÇÎ?ÐÐÔN"6æ1ˆu=ÈQ*àQŽ¥ÚˆQøÃNŸêHű]ÅðÃqö€³[íë755Áív‹ ,øå7ÞXPÉ;mbOBn>%ÂO-ìÑš¾þ# @ „ s2/"óŠ6 ‚@NNNîƒ>8º´KiN’#)îÀ¡˜`°f)~øóü±ãT7T‡› ² ÐjQ‚ ˆ}>,~ÙiÙ8¶ë±vÌ0œ}ÂÙ­úµ‚Á š¼Mصs×Á3f|Q]]]e~c9/¥ŸšnÖA>Gh@@‰à ¼@š,ø0Hvá…ö»øâ‹ONMMåZƒ0íû ?mú ;*w`wÕnì«Þ‡¦@“žõ·Â ÄÑ¢D°ù)(’lI(Ì.DI^ ºtŠރл¨w›|=ÇƒÆÆÆàûï¿¿òã?^P¹ûÍŽ_‡P\¿¢ò·y„ß ÐF *Ú@š25€Æ0LêÝwß=|È!½œN'iM³ Ò¨¬­ÄîªÝØ[½•5•¨ª¯Bƒ».¯ î&7š|MR”×çÕ]rZõž‡M ôâYIö$$;’‘’”‚´ä4ä¤ç 0«E9E(Í-EAVA›¿¦¦&x<úÓO?myòÉ'—‰¢Ø( ¹"ðµÁo€¾{¯¢ò·ixï ÈA…HÒpéÈPÀ!;;;ëž{î9»[·n…N§Í"LŒ£ox½^x<lß¾}ߣ>ºäàÁƒ5!¯C¨¨Âð+»¾¶}W«’}G%˜ƒŒÆ$0rÆ™ ¥sçιÿûßÏ(--ÍKAbXü]»vxöÙg¿Ý½{wBnëM¦Ë°ë+é¼í–Ò{Ä@“@qj¹…Ð@šò\—.]roºé¦S{ôèQ””DG\õã5C(…×ëESSý믿*_zé¥ïvîÜ©¾K³ó+Bß yN±õÕ*>h猾£L´Và („É ÐÎTùñäÔÔÔ´[o½uXÿþý»$''³v»½Õ½‰ÑñG0„ÏçƒÛíÖ®]»ó…^ø¡±±QñÛ»dÕ¾Á0•P^%¢OÒÛ®…<ŽJˆ¢ (Ü€¤j4Tù9'€¤ /¼ð˜Q£FõËÉÉIKJJ‚ÝnÃ0 é8B‡(Šðù|hjjBuuuâE‹ÖüñÇÊ;¹¡¶öÊÎßAðµ¶~»ïúG=Dà8~ Yc¤hMùy'GnnnÆ´iÓNèׯ_Ijjj’Ãá€ÍfK€Á"ô~¿^¯Mëׯß3gΜߪªªêdÛ݃P#[—AÅ× ¾Öζ·­Ÿ€Ø@À"<ŠÐ!sf`¢yÖÑ©S§ô©S§(+++JKKsÚívb³ÙÀ²l‚38LlzAà÷ûáóùhCCƒgãÆåo¿ýöšŠŠŠzY½ò®ï6¿Qè›äc}Áµà' ¶Y % ­@zíTsh¦ã8û¸qãzžrÊ)ÝóóóÓ‡Ýf³çy°, †a pˆ…]E‚€@  ìô¾ýû÷ׯZµjûǼ% **»W3Ý•_;=šÝÞk ø¹ºŸëÚ@$ °iv{§A;pjSŽQxo³Ùì#GŽì2hРÎ:uÊHKKsÚl6žã8p†aTMA;£ùnl¬!Š"‚Á ‚Á ü~ ¡¡ÁSQQQ÷Ë/¿ìþꫯvúý~¥À¦_c¯+;~“Fȵ»¼GsŒ?’àw”]?ÍÞÀhÍítjWŽSDyNžì€rËÊÊrKKK3óòòÒRSSv»Ýf³ÙXŽãX†aÔ¬ ÀÊ‚¥¢(Ò`0(øý~Áçóù½hصkWíÆ«Ö¬YS…P•é ¬¢4Âë3¨û 4Ô{­}8¿Ã@F кyè½6ƒ `œö(@ÀjnÍm¤ê‚‘¾çQ%ïž3kñ¡íçIð*¿qj hì{CkÙ˜ßópԣ̄ŒÞsÀ4í´¦Í`Ø4¯ç4 Àj>Ã*$Fdá×6óÒîøAÍέ´V¸µi§V赌¾x¸ }š¯°&€À™ìø6á磀I€@³…ŸFþ€ øM4‚ ‰À GÚnß\à‹L]XF0` ê=¯á8Ãc\ágBßìë$FE` *½¡Yü‘-ôñ.±È"‚iÿBƒGš‘„?ñq‘@ žilövÔ }¬4œ1˜ Zml~&‚êoÅ,9Z=Ú1‘ú ÐŽÔSXŒóóa‹E€yapC'H…Å;+ó€y W³V®‰‘€6QKÍvîXU£åZBBÐ[y+Lab$Fb™#‘î–‰‘€ÄHŒÄH@b$Fb$ 1#1‰‘Gøøÿì%´³ºŠ[†IEND®B`‚olive-continuous/app/packaging/linux/icons/32x32/000077500000000000000000000000001370472574300221535ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/32x32/application-vnd.olive-project.png000066400000000000000000000031601370472574300305320ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<íIDATX…å—]lW†Ÿ33;³ã¿];ë]Ç6þÁŽ3µ²Q“‰cÓÖ$¥¢AIÒ¸”J**E¢\QJ.Ê7D½áÆ`QõÑJm¬"ZúCTP[Ü4ØñÖ®[ÛI×w{g÷ÌáÂö®w½þ£ÜñJGšÙ™ó÷{¿÷;gþß! îõ'…g•RíÓu………ŸŸ>}ú€Ü.­¾¾"|áÂo¦;fX–µédß÷I&“ÌÎÎ’L&Æ0 uõ껟xâÂÐVHh«¯uÝ)¥²‹K)q]€d2‰”’T*…ëºÌÍÍ‘H$˜ŸŸÇ÷}|ß ­­M8Îþ´oß¾XAü¢0V] )ýì½çy\¼x‘’’ZZZgÿþýŒŒŒPVVÆÐЭ­­D£Qš››³A:;;™™™±N:õÒµk×îºqãÆ< ¶¢@âñ8Ñh”þþ~®\¹‚ã8ŒÇq!ìÚµ MÓд¥PBzzz°m»ýܹs¿ljbÃZ®K@JI À4M2™ Žã0::ŠëºD£Q”RLLLJ¥ÐuÃȉiÛ6===Äb±ÇNœøioÒ[#P[[K<çòåË444PUU…뺴´´d3D"yDW£¦¦ÇqD{ûŸ=t¨§зE  ÑßßO4¥¯¯€#GŽÐÕÕÀáÇQJa¦i®!K~¨¬¬4=ùB8./¶Þ†.­©©¡³³3|ÅtìÝ»—¶¶6LÓ¤XÛ !èîîÆ¶íÝçÏŸ*‹Ùì=ëÖàÙ©A¾Qý%zéºï!ƒd2Âá0—.]Â4M”Êß¶mêêê¾øOé-)0±ø¶^²Ñ+X–…mÛìÙ³‡êêj‚Á @]×Ñ4p8L:Æ0¬ºH$\=wC¾³óa^™}™®Ê¯mJ¶m”R466’J¥ð<)%¾ï£iãããá[Rʼ¤7$³vòQj’øÂušìÏoH@Aii)º®H§ÓH)QJ!ÄRÙ•R…gÏÆ:+îdðãl½„˜YC"ý ¯%ÿÊ_æýù÷؈°'ôeNÔ>B…" bYétß÷ó¼P E ø~þr$ú ¼ÓGĬæÅ›ÏÓ9H«í°#PÍŒ7Eبâ­[§»êže5(Ú–[$ 2Ÿ€.4újNòæ­×øõî§¹ý>C‰—¸»ª—Gë§ÉnÄâ9¬Q>‹5] H™Á÷W†DJÉ]å_á÷üË}SXü°î /Ü|ŽûÞ:ÀÙ«?b6õ Rf–‡\6àÊÈlGµ%˜M%vߥÑj¦1ØÌÛî?y(ö=^N^¦Ív°°ÖQ`ýì‹*d3Ée ©7ëy²ùWô†2ú˜ÝÁ;˜\œ ‘¾Éo?z”ÊË>§B棅îÇ'ù±³|©ìN¦¼I¾ZÑÅñê~^O¾J4PCƒÕ€¡Ù9›¡()W/«âÜöçYð˜\œ¤\«`Q.ðïÛW¹ÃnçìÄnÉYzÃ÷ñ@Õ·pìöM ¬S‚œy|?ßX– Ro~Ž 0y,ö8ÓÞïݦJßÁ@ë '"S¡U0¶0JZzÙn‹ÀÒ¢²`亢»ünärw|;tŒ+î|šžãõ¹WàþÐ7¹·üëàç|±m [q¥¥Ìð`è8ÕZ)%mV'w|—yù)3Þ4Ï$~Oÿèqþ6÷jž’ëa&\‚‚°â@élà‡Âý\÷®3˜ø‹r‘ŸÄ~FH+_~þÚpE¾ÕíX¸ÙH)Q¾O³Ñ„c:œ‰ü˜?ÌRFYV±œ©7QÀó<_!=/­›æÊ#Eñó$÷ãÊóT> À»› 鬒ž—ð=Ï[#íj~&£§âñ±g€£…ä>#2##×þ(¥r ÃÈ#‘W ÚZJ2™ÐNß'¬”*úû_B†¾ Dzzjʲ5)tˆŒúz ßßÂ6¶EhêÃñ—ÎSà?þç„0ìÉIEND®B`‚olive-continuous/app/packaging/linux/icons/32x32/org.olivevideoeditor.Olive.png000066400000000000000000000113201370472574300300750ustar00rootroot00000000000000‰PNG  IHDR szzô pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFûIDATxÚ¬—mlÕ†Ÿ™]ï®í$^°Í—í¤¨5‚“&H…Ô‚—T¬P€T4?‚(Pÿ¡5RJÅ—ˆPJ¡ù •͇Vv"ˆÒ|¶ÆˆÄNÛ±íõÎìÎ̽§?&vì8¤âŒŽV3º³ç÷œóÞ{Œt:Í v-ð•JšÌ@诪ª*«¬¬àÝÏßáä`sæÍ&~M1ᘅúî4hÑ(¥(ä ŒŽ2Ø5D]ò'üvõ#ôõõÑÝÝ’©TÊgào•••eˆox‹áð0ó:Ÿø5q¬˜…6Áœôµ3°€€Öš˜ç]#¶ ÎÉo:ØÚº•M¿ØÄܹsq]7100ð.°ÞH§Ó `°¾¾ÞØùïœ eóšÍì<»Ó1äŠôOÇ\ÊUd²ô·÷³Ø\LÓê&>¬r x!™Lš"B×H'ÜTÖUÒawÐÝÛM$!~M1ä{¿„QfPz])mÿi£ó\'5‰’ɤÙ××÷´ÜH$ÐZÓòM E ŠP%ŠýCû¹¾ìzŽäŽàÆ]L˼j¢Ñ‚.ÕDFiþª™¦UM”••Ñ××·Î’–e!"ôx=„KÂØÚfX S.¦"\Ao¶+fa˜ß]„¢‚€¢‘àWûíi º@{;"B8Xd–H°x42JI¸„‚_@™Š/ì/¸%z ùBž»3bb˜©² ³(/*ÇU.ƒÎ §³§94xˆ™H‘\ì XОƷ|ìÖzoؚܿŽé`øhðÅÇ7|>þ„ó6rôÜQPp{ÙíÔ„kÀƒŒ›!jE©ŒVÒÙÓÉòâ娬¢e°…ð¬pbíkl±'âMÑ8¢‚*`*­4JJÚÒì;³ ó60–côÜ(£¥£œÏŸçàWi=Òʉ¡Xq «Ô"\&R!RÁŒ˜D Zi<¼É 0…¼ŸG¼ žòð >Ú׌äGè.í¦w —%s–ðXú1VU­âÅ{_äÉÔ“œ9w†·¾ÍÞνH±àùh¥1Ü‹ ˆxÞËÏÌ€ë¹à€ïúøžÒj¢òªè)îaûÇÛyîîçh=ÑJÓž&jçÔ²rñJ6Þ²‘ŠÒ ¶}µ «ÄÂÐA*§ðß÷§30þ ?–G(´h|™  ˆ/¸ž;€9žA¾ç_Ö·ÙŽeX›ÅÄ̯|þ +«V’þ2Mf,Ã#w<‚F£Cø™þG+=o¾ï+(QÓØñå_øó‡Û¹¹ìfv¬ßÁ«_¼Jû·í”H1Ç;óþ÷ %BhKá+uqo@_ÐO3¥Àw¸FÐZãO€ \kÐîgUõ*ž–§™Åê×Wó¯^`颥Üú£[©KÖ1˜¤õD+;ÚvÐítc„Œ€/øžºB <…ïú(WMw_!–àF]ÏaÙÂetœéÀñ¹çÆ{èêbÓ®M¬}}-¶m³ñæ´Ü׳uÏ2;?ßöÑ…@gL*(ÈäR~9ý?Þœú…õ<øüƒ„æ‡+ŒÑXÛÈÉÓ'9ÖŒZŒ½oÆMÌ9&F±aˆ+33€žëÅ8®b_Û>rùˆÃCï=Dýâz>:ö·-½#ù¾õh+hØûù^p¡áÆš6ckk×ÒX×Àùóç5²€ °'›ÍÞ_RRBÓÏšÊñYÏg½WyC2)ŒðÒÞ—;`kyÕrox!›Íü=•JeÆÏ¹lÛÈårˆ›7sWÍ]è¼F»:èßïá’ÔN|¤ÄˆÜyÃlImADÈår8ŽÓl¸t2Z|Ç£±X €ÓC§Ù}x7í½ídì U¸(¯W°ˆ!OpüX·b5å5ÁÇq°mÛ®K¥R½S¤R)ÒéôàP4-‹Çã?èhfÛ6ù|þ°||*š¢qK¥R@E>Ÿß•Éd´ã8STëjMkã8d2ÏçßæN~él8Â~N§ç8΋Žãü˜÷Žçg€?¤R©ËŽçÿ»_;nÔ4²IEND®B`‚olive-continuous/app/packaging/linux/icons/48x48/000077500000000000000000000000001370472574300221715ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/48x48/application-vnd.olive-project.png000066400000000000000000000047261370472574300305610ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< SIDAThÕš{pTÕÇ?÷±›ÍÝ]6l²YBB“4Jä% XŠ "E¬ˆ-LÅÇ *ÖÚX;b…qÔÁÖiœNGœ)Ó:v&íLcy8c €EÑL%¾"Š(Vb^„„Í.I6Ù½¹÷žþ²dã&ÙM‚Ó~g~³÷î=çw~ßs¾¿ß=÷îÂÿ9¤$ÛHƒŽ'bЧ©áh) P|>Ÿ#Ú…òx¡(Šér¹¢MMMQÀ«#u„k²Çãq¯[·îæòò²ß›¦å“¤‰Z$‰H$R½iÓ¦Û[ZZ"Œ‘ÄpIÓ¦‘ÖÛëÉyþù?}píµ×zsrrƬeYèºN$A×u¢Ñ(µµµH’$~¼}ûƪ/¿Dg rVá°O‡S’¤Éã @ñ±I’„Ãáòóóÿ|Í5wæÊX|K@!iš-îzKK ;wîäàÁƒ†Á¾}û8qâÕÕÕœ:uŠ]»vQUUEUUíííq$†’ÉÎÎFQÛòå+«'Ožì ‰¤Ó4M*++ñz½œMaa!455ár¹ðù|ø|>òòòp¹\q>$IŠ€¦iddd••…Ïçß´ví£s[*$’&Fq8ȲŒ¦iD" imm¥¾¾ž¢¢¢XÛÝ»wSYYx¢cMÓÐ4¼¼<œN§4gNù«ÅÅÅRRÒÒÓÓ ‡Ã†AWWš¦Åf½®®.ŽÀ† ظqc\в,#Ërìx0MÓ(..FQïæÍ›ÿèóùÉÆ–4ÌÌL²³³Ù±cµµµ”––PTTD0Œ#PSSÞ={1ƒ-ÇCII gUEEÅÊiӒˇ‘ndq$‰õë×sôèQfÏž#P^^Ž×ëÅãñ°téR Ãèw®^t?0ûŠ¢ (Jìú`›2e ¡PHþRVvó;õõ{¾ !ýUcÁ‚qßùý~ü~ì|áÂ… ûʲŒ¢(X–[Øíö‰3fðöÛoÛW¯¾sço¾> væp1MäþfD äÀ€%ºîp8p»ÝÌ›7»=íª-[žªÈÍÍMc)¥LàŒÞÌÖ¦§±Æ°uQY–ã¤5ªªâ÷û™>}:¹¹y[n½õûÓ¯¼røÒš2š¶C¼Þvy ‹7 EQÐ4ÖÖÖaÛ–––âõzåë¯_VÝÜœ¡1 ”r`QÆþÚ›j·‹ª*BfΜI]]ápxÄöŠ¢ä¸\Š3¢›;Ö” \æÊe–}.CûYš±<Õî1 ùý~2331 Ó4cfYcBpøðaa³ÙU&JBë§=ÀgÐaÆÒEQ¾VBm6v»»ÝŽÍf‹_ 2qI à´»¸Çw?¿9ý8½Vï˜IØl¶XðƒƒLb4¤,¡\»WòÄ©Gx¶hŠtqûÒmà­ó9رŸ{êBà·çP溚[²Vñ÷5@¿œìv{L:–e!„ˆ“Ñ%#°lêM9þ>ž¸‡_N}œíc_Ç«´­¨¨¨Â†%™èètG»F:Øßñ*·ùÖòXþS@ÿ~ ±$zº$$Iâ‡ùá±XýÙ2òÅ·ˆÐËÊ nñ¬âªô«±cãL¤™/Ÿ³4g9°Ð쮄¾¶©`\<wyÖs(|KµxÔûG²;TŶÐV¹o`EÖ*î+xt9}t‡)"©$ÂÑÖäßÅ9ÑÆ²ô›Ùøs§–ñBÁK”š³8p~'×ñÝf°­y+}çczOÆFCR+0š£Ìz^êÚÎçZ6Ÿúó] X—?Wœ)å¨~„sV;ÛÎ<Çþ@5/OßKºìH0QÉD3n_¥³ç< 8c4Qožd–í*zÃ=¼/×R1“á/L(“æs—÷^lBM©ÒŒ„$$$°,s}}™sµ)¬W#£pNo§¹¯‘_<ÉWÝõ´‰³x"|¢ÄÞè+ˆìA?fB›‰‹TX?ÉsîØ”ó$ÉÃ+¡—©ðoäÃàûx\,+ñˆ ‚=Áa‚½„9 „9è8q‡â`IÞ2ÎYíì¾L™v5 œ¦¨·o†—-곸µIë9ŠOõáSý‰¥ð‚nTBŒžÄƒ;'Úéäÿ1ŽsÔ:‚]²3+m6K&ÝÈrÏ &Éž¤@’J¬Ï¡(«‘€Ku±–Ÿ0+}ª¬",Á\o9[§<Ï©‚43÷"ïð»¶-,;±ßœy‚.£ó›/£CQ ÒÈW„Ín~^ü-F3íR;oR”[Èú¢û˜uv6﨤Gô)û(ì)CÂRGOÞ $ïà:çbþ>DÔŠÆÈ/R—òWóEÂR˜]gÿÁjßÊ|åÌÈš‰Š·"ù gJl×y–ifbÇ«Vký÷Rd~›OõOø‘ëv´UñpãÏXtzšî¡Io¸”e4™¸hnÕÉjÛh’3–NUã¡I [:‡ƒæç—ã´\ëû˜»›×ðYäÓKUF­ ŸÉ´îÇmþÛé5ô¸ æN.g]ÏOiï9ˇÆxÕ,¡p§¸›†H#¯µï¥$§$ùA’%l &h“úŸ¨†ö½õ²1{±‹4ô¾(R'ÿ”«y± ¯œ™rÁ˜ÐiÇ“„‡œN¡YÄMÚ n‹ÞAZ_´U` #åc×/£<êÞL¾+Ÿùîù¬¯äx÷gt])ßÌF$Ð×§©—ÑdPà*ú_äh9äh9Î'HB’$ Ã0LË2C¡P×8B;‚ÁN ÃèÐu}Øvl6›¥ë‘¾×_í·–õ½ÍªªN¾4a&FÿC¾xóÍCOëzÄ`ÝŽô‚-;Ûéµ,uª¢aYbÜÏÏ©@’–%GE:§ë4ƒÁ.R|µhhZø| à6l6[zZš¥1aÿ•’Ô?Û–¥÷E£öžP(ÔÃV`àº|Á¾‘à‡Àº`ãþSÈÿ,þ ‚Ù ¸Ò#ÙIEND®B`‚olive-continuous/app/packaging/linux/icons/48x48/org.olivevideoeditor.Olive.png000066400000000000000000000145411370472574300301230ustar00rootroot00000000000000‰PNG  IHDR00Wù‡ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFŒIDATxÚ¼šyUÕÇ?ç.oí~½„^h¦•Ž¢ â‚"–Æ8j,%´Å$i·h’QÐRÊ¥ŽcEJÕ¨CtˆSeU\I¹dT¢Á AÙhPãÒ´ÐM7½¿¾ïÞ{–ùã¾÷ºAÉÜ®_½×çÞ{Þï{~ßßr±dÉŽà:¸3ÿY$Á7» :€uÀÂüçˆ.g„ÏÝÜQZZZY[[K&“Áu],Ëâ\Bk Ãp\__߸¶¶¶ö÷÷w¿<ìˇ±À àùššš²±cÇ‹Åøÿ¸‚  µµ•ööö^àZ`ùÑX`qEeÅ5µ5µ”——wôí`Û¾m šA+@¡0ÂgŒ)’Ç2®vI’dJÕʈÅbüñTVV–µµ·-ëîê~˜=R XÀÆššš) ÅÆ·Zßb—¿ §Ô!žŽc»6NÌÁ`°, ƒ9â‘VZaŒA’0ñú=¾†xßkø^ñ¹––ÚÛÛÿ œèÃØVSS3¹ üÎþ¬éXƒ,‘¤ÊS¸I;fc9ÂÊû¯8R¯5C–0 µFJIè‡øžÏ@çn¿ËwG—†ò†á >NÞ—ÝÜÜ<üÿjjj.?~<ëÛ×ónϻīã¤F¥pÓ.VÜBØ-42 mô~¢ŒúZÙïÙm®ÀŠY8 ßöÙüåfL`8.såååH)k²ÙìIÀ+ó™ååÍõõõcXÛ¶–‚ÈŒ.Å-u0®&èh 2çh¨TxÏ`ÐBcâšX¹K©(á/»ÿB |¾3î"êëëñ¿¹§»çE`éž­®ªÆCK_ ú7P6¦ «ÄF: PÿtÑVáC6Œ0hWc•Ú$«’¼½ëêJÆÐXÑHuU5=Ý=ÏåÃÜWUUU–Éd0ư²m%‰êVÚBÚ2⩉(£ýo8ê_¥ mk¬‹Ä¨˾XÆü3æ“Éd¨ªª*ëèè¸x°‰î¨««`iËRú})$9cP2'=‡©f*]]d½,9™#'sxÒ+~?VâK_ú:@ )Øçîã…í/×õŽ‚ÎM§Ó•Žã`Œa{ÿvRǥЎ&0ZFŽV"JØøÉF:ú;¨h¨À-qÿq™Ìä­ òtu N©Ãæ]›i6Í8ŽC:®Ìf³ç:À¼ªª*Œ1|ÔýA" æÆðñ£ò‘âÏí&¦b ’ ”Tÿxz„rA,`ëÞ­œZu*UUUd³Ùy0=NcŒaõžÕ˜ƒ²#‡-†I4¿ïù=?™ðÖ÷­Ç|Ç Œ; ­uÂäur +[V2yÔdÒé4Àt¨±mc {ƒ½„Nˆo" idd…¸â·_þ–«'^ͳ;ŸEÅ–k]•)Ž8:Ÿà4h¥Ñ¡FKö5Þ Ç®Þ]c°m ÆBŒ1ôÈ\ËÅ×>@ÑÊDtÙíìfKßfÔÎàµ}¯+‹a9Ö‘)š§…Ñ#ÍP]t(Éèy¥¡ÒåwaŒApQè$«³¤T*B?,SC§mØ0¸Úx-W–_Ék]aqi\l——_Îé%§S¯Â`è úèô:Ù9°“Ïú>cSÿ&ZƒV„#†Ê‘ÃùÖH-ñ”7´p†W‡¾ò±•]tPeÔ~ŒkØîmgZzsFÍá7»CyE9—V]Êé3˜X2‘”›B sŠxñ ˹˜‹Øðå~¹å—ôÆz±bÖWýiX$2*²D ‚0ØÏjû:$ÔhSL\…Úex²ÚæoefÍLÞûl-ÿuêã¤ã% ƒtõícUë*ºzöa)›Òx)é j+j©ÌT²bý >lýQßEy¦œ:4{²»‰UÆŽ8´ò"Mˆ4òÐbK%£RáPŒ1¼ôÅK̨™ÁïÖÿ·^p+J+\£:YÍîöݼµý-¶îÙÅqmСF²±÷Ø`´‰ŠaB°°ihU¬R} €P…ØÒÆ–vd‘|ÒFJ£ ïçÞç¦ãobã®Ì|b& g-dÕ¶U”¤J˜}þl~úO?Å <Þøô –þ});6B ¬¸…åZEG4Ž!4!BÜ(Š4 UH¨ÂýXÅÚä’„*DÊ ô‘2$ ü¹\ŽÀeˆ²¿ÞökfN™I»hçæå73õ”©Ä“q¦=4wÿþ.ÉX’¦Sšxúª§Y9{%sNšƒã8(Gaˆ”Ô’P†‡%J©¢¾_ ´Bi…TŠ0”!~_@˜“H¥Š÷•ŽBëå.熳o`îÔ¹x1M›È‘ãÕÛ_åÅM/òÄ›O rÔ”Ô°àÜ,»d'ê CÔ}N t>©$ïãäú|‚œO(ƒCÊŒñWb ›;/¼“æãšyo×Z2é w½zs/šK2äWà‹¶/È9ZÚZعg'™ÞR¼ŽÁÃö/e}WCßežBûÐZ£µFyŠ0+ ýhÄ'o´¼YäâÜóç²nËû\Òx ;{wòƒ§@cm#¸Ð›ë%KÐPÛ@EIËÖ,GæÔˆ~C*…R:ÏÖ¦¨ïW)¨ÈQ¥‘ܳú–lYB¨B¶}¾ ;`Õg«˜}ÖlºT¯}˜ÇžÈúÿ]Ï¢‹èìëdÀÀˆ()3òßÒJGº©ý)´_RJ!”À’ÖPÕÑçÁ&-}¢[þt á3!º_cWÚô†½Ürþ-<öÎcT”V°à­Ü~æíLªÄ¤»&„ö(íF™uÿ5†Öë Q}”DZé¢4Œj¡E±ÿD]ëƒÏº ˆrs1AÄ—~ûR*R\{òµÜ}ÉÝœSs÷¯¸ŸŸõc^¿çuÖïXÏ´ Ó˜4z¾ôÙÓ¿‡õ»×³øo‹ÙÚ»áŠ(+ €Ìër¨0z$ô)š©)¨/«àºó®CJÉœÓç {%½a/Ïlx†Ñ™Ñ\¶ð2fý÷,z³½4~«‘k&_Êæ¬ûá:îŸ|?݉$e «FóR(F•BJ…¸£n¯€ uXðäZÚZý’Gf<ÂäÑ“ycËüâŠ_°ú‹ÕLx:OþéIrA޶®6Ú;Ú©T•ŒÓãèÞÛ †ôÐ*°‚ Ä’%KL}}4jW¼|ö(‘ŠÊëBÜUZxâ¾ø²Å\öíËH_‘Æec•YìytI7ÉÚ×òÜÚçH”&xîƒç0¡AïÓèÞÈDB`e,¬ +c ÑIÎjT‡âŸ½-sîØ±¿Df˛΄æˆåÿ!*C” ¬J »ÊfáÛ 8ï¤ó¨KÔÑÝÕÍÙµg#’{ŒÛèâLppÆ9X£,DBD“•ï;ˆD(ñ ™Bƒc”TCüVæˆeÙ'ËÈúY¼À‹F/í"<²ö¶íÜÀUç^Åê-«™\=™7o|“¶mcùMË9sÜ™‘à04é‘Cýlj`,À/ð*#2(O¡r íG–P¾²Ê¤ÇëaÑÛ‹†â}˜/…aÖS³X±iõµõ‘ùЦ”oÛ6£SµìîûãÚ»X;G2ÒÅ+¿Z½J»+!¢weôn‡Ü˽¯ßÃÕ;fsÇ÷ï`⸉ÜýÜÝLª›ÄžŽÝ¸nŒ{¯¼—‰Õù—ßý ‘²ò³{0àÆTÖEþ©@›¼—Ëå0Æ0ãäïJB/DJ…” %5Z´¡(àñ˜¿l>¢ÜÂXïŸyŸóÀÊèìïä„Ñ'°î¯ëp—SO££»ƒ±Mc¹éá›P:b‚4èР}ò4M§_…1†\.ðž<žÍf1ÆpÎøsˆûqô`ôr¡´0aäà# VÂB”Šh¦5ìž+mñÑžØÛ½—ήNzù!ýA.˜rËÿc9é’4Â- |Àƒ¤LrÞ çaŒ!›ÍªÁúúð<ï߆/î>èy^oÌûÎ8@üƒ´¡`¢p)RùÚG€Š+:éD” ° J^º_sÛ¥·7=Ïë-ì`ŸI_?ÀÙ grÝÔë0½“5Ñ.npÏÃo( „%¢yq!YiµÙÑȨ3gÚÎ>álŒ1 d®?ØÓ'Zé‰ZëI±XŒÓêOÃÑ›?Þ\\î+¬¨”×#á i¸80&4Ï`ú 7^x#×_é;00€ïû/ÿþu›|$‰I%%%lú|‹V,¢µ¿5ʪ6ÑJœ8þ`†‰Ž¢"ÿS:†Û®¼³Ï**ŸËå>ljjš<\çƒíŸ–Ëå6SÒé4gOÍ}ŠG_{”·ÿö6žñ"Vó @˜¡B­ !\xÊ…üüŸ^\ƒÊf³är¹Â6ëáwꛚšX²dÉ‹Žëü(•LáºC›ë>^Ç+k^¡½§žÁ<ß;ê-&a‰x‚ŠTÕeÕÌ:Ó&N+ÞÃAoÊ—›šš~Th®óáŽÌžÇãeÉdòX8쥵Æó<|ßïÍ;ìÒ£=ì±(÷}ÿ>ß÷ç;ŽSÇq]!Da‰ûØlêC†ø¾”²øÏcqØã`ÇmæçÕ@ü·ñ½ÀûyÅG|Üæÿÿ¹çy¨BLIEND®B`‚olive-continuous/app/packaging/linux/icons/512x512/000077500000000000000000000000001370472574300223215ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/512x512/application-vnd.olive-project.png000066400000000000000000002270041370472574300307050ustar00rootroot00000000000000‰PNG  IHDRôxÔúsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î< IDATxœì½w”,Ç}ßû­êîÉ;›óÞ»áÞ \‘D @Š™Á(’‚DQbNH"P $J²lI|²,›ÊÇ–ígY:¶õŽdI¶ô$ÙÏf²HB$  "Üœwï†é®zôTouMu˜ÙÙÝÙÝßgOŸžé鮪®Ùéß·~õ«*€ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ‚ ö"l» °‡¡º'ˆƒÜîD·!#´ùPÄî„D±£!ã´9dÕ+Õ;Aì<Ò >‰bÇA†¨{$Õe»Ç;͇ ˆ|tb¬m×$¥Cb€Ø1Ù8¶:4e½ïvþA´²Ãl^Ûî{‚è9ÈxtN–áOzçZ‚ ¶—v |ÒkÛ{‚èÈè´Oš1ÏzW DÌ͵S4‚ ÚåÉ'­‡mF½“c¶÷Ñh$ãŸfàõ=Öºï‡ï…hý‚ ßhy ‚HåÀqâFšóð½ë†û¦HÐ ¼iìÓAÒ{‚ØVHä'­õžôž`ssqc¯Œ»"VÿRÊÄïÃ<— ˆÁ9o1ÈŒ1i;ÇqŽIÎ!]Rí Û{‚Ø6Ȩä#«e¯öѦŒ~hðÇ™2àÊÈ !˜zdøÓAÝÁ4úú1ƘäœKõžs. 1 Œ1`¾&ˆm… L6IÆ?Óð7£ ¹2øºÑ×ß×ëabRÆ¿!HÄfÁyÜø3èóçC㯶ð3&ÇJ(!ðÌ31%Ì×±mqI'·ñŸ›ó}°Fcœ+c¯ýæ{^¯‡F^ɤÓ[ùºñW6ùö‚.j-~DÆ^½çœIÆ /\`’s.”(pG(!P(@4»H;Éä1þ›™Yoñ+Ã/„P¯y__Üà‡û2`눉€ryso’ ö2Ë˱.Ãø3 @2¶,›B@pÎäâ"S^±.NHσмJ¨tI= ;iÆßÒêb”AÀ•á¯Õ—,$Br)ËLJÉ›†ž•J2@$š¯é{!ˆ­Dµü4ÝþáûÕU.Ö1ÁùrÓè3±¸È„.ÇžwL]B¥ DA†¦•ÜÆm \µú•ñBðjU}0)Ë\ÁK%ÙôH€I ö²—½rì/¸öÚ¡¡Ñç‹Åy×u÷9Ž3Ä+0Æj[{ÛA$àK)}ß÷ýÆ7¾ñá?þã?~Šóå€s&B!Àç\¨øÏ;!š]$ˆž†@+‰ã÷ÑtùëÆ_7üµšäªÅ/DÉ‘RòbQ(1À¥”ìðáçÕo½õozC¡P¸ôÄŽAJyáž{þþÿñ?þ§ï)€ëò@y\× ”x «;€±-ñ‰cÏŸËøW* ÙBðb1|/%¸¹êªëÞö¶[?400ôvjÝÄÎÅ÷ÿø[¿õ/Þøè£O¯pÎå ¸x‘œ¯{D€M$ˆmÀÙîô©“ùà6ã_­ŽëJ'¤#DÉ-…˹t„®Âõ<Ͻ㎟¹õ¯xÅïU*Õ1Æ [~gAt Αç=ïª/~ñï¾äy`†ÇÅ"°º*cá£CÊ.â…ĤrMN› €uR'öÀ+•VãïûÒB:B”œB!pCÃ/]!<÷yÏ»¬ÿöÛú³ãããæœSÑÀ“á'¶ !™®ÿ™pßçBã8Ò ‚’#„ã‹Â Õê/¸7ÜpýÄOüÄûÿ}¥R¹qËï† ˆMg``ðåRÊÿ÷ÑG¹àyº'`m-ÙÔ‘PHØ ?‰bK!’ÖúçÍá~Ü÷ËN³õïT«ªåï¸Å¢pBã﹮˽ë¯áÄ;Þñ®ÿP(¶ån‚Øtc…¹¹…k¾öµ¯ÿåÊÊ’ô<@÷¬­­Ÿ+eFG—äÙ³ñ$lÉnj¡ Bƒ@Hâp?h®ÿfÀŸS«ÅûüUËßu¹;==S{ßû>üû…BñÐvÝ A[ƒã8W_}•ûùÏÿÿ0xž„ïÀ˜/K%‰€pR¡( Ëð“ ¶úGËhýÏÌ€7ã<îû¾S­N£!\!ÊN¡¸A Ü žëz®Âýå_þçŸíïïmÞÌ]×Åää$ÆÆÆÐßßZ­Çqày^—o“ ¶)%cB@J3_ëÇ„Ñgú>) u~RzYùI)!„@è¢_ÿìÞ{ïíè–ï¿ÿÞþÁüþÿqÞàœkkŽï8+¾ëò`i‰ŽãÆÈ}T $¶òØ ?öýóZ <*<GÑŒø/;B—1á !ݦñ÷>ö±Û^;3³ÿ#y2­T*¸êª«pã7bÿþýB¥RëºpúZˆÝƒÊø&£n»F7ÖúyyË`¾¶]{äÈ‘\é°ÑÑñ—œ?þ¿?õÔ“ËŒ1¨î)(—!×ÖXóêÒ ¤xbÛàÛ]€…¡9ÇŒG‹ùôõ…3ùiü8®ë¹RJgjjºvèÐá;ó$~ðàAÜrË-8pà{bOÐ-£­PCíÚM{}ˆžŒ½Þ(Žã ¾å-?òk•JÕB:A !„#D™û¾tš o4ÀgfZHxO› €󇯀p!D4Ío8Ë_™‡?léH))%B:?þãïÿq×uGR3a ×_=^ð‚ÀuÝÍ»‚è²Züb­|ݨg¥gó ˜¯³ÊÐmÊåòMwÞù3ï =‚Ò)”ÍéÁEsñ(b½›醟D±iìu8üonHný‡Óýº®ç!ÜáááÊøøødeöüç?óóó›s'Ñ#$òvZþYb +½¤þf ‚ñññO¾ó?v­¡g-9BH^«­‹€FcÔô˜2üĦ³×@Ì÷à‚…‹ý¨~ÔVpÂ=ø;Þñî׸®;˜–àüü<<¸5¥'ˆ@·q'éu» Œ1~ýõ/üõ«®º¬_Ï é†" ìø¾pj5­ÚhŒÛºLo,ï ¢+h%æþWðÑÊ~ë‹ûHÞìpfff~0-Áb±ˆk®¹f‹ŠO½Iž@À¨–?`ü(Gr×åCiéÔjµÍ-(Aô0y·íº$ò&½ò1Æ¢óÇÆÆ044”ëúýÒ+_yËœ}~a‹° XöÑ1$Bb?¦ bï¥,7]ÿ`R¢®Œ1§”–0Eÿ{Íäë4f ›A„œspÎ1;;‹R)õ`Œ•o¹å–ÏML •„F<€¤xb[Ø«ÀöÉ[Ÿ ô”JRû!J&¥Ë€1– Dsý{$ÃÛNË;ï´Âí\× Ê ¶B¡€äšÚ»P(\ò“?ù‰;\׋ÅpâS }ª`2üĦ±W€"ï+êû÷<©#Y'îM‚ Bò®t]ÒgÝŽHºÖqôõõazz:W<ÀÈÈØ}èC{• e™tÔÐ@ß÷Fc”OM加Ñ1{]ÆHM ¨À?ÛAj4ýøÂF7¢ü»E^qÑNÌ€ž¦ã8˜˜˜Ààà`žØáÃÏû•o|Ѥ”J®¥hªàpèqÀƒ`œñyˆ.BÀ‚šÀBVŸA¤ÛAƒÝ¦ñWÓ{ž‡ùùù\ñŽãô½ùÍ·þËz½TPñÍ©‚Ö¥ƒ­ñHxOmA s ñ1ýØ¢ ¶rYÞ­‚1!8ç`Œ¡X,b~~>WÜO©TºúöÛïþH¸¢h´t0ψÈš*˜ Ú‚@Êø“»Ÿ ²é•˜˜NƒÛIÛ÷}! ¥ŒârÇŒô½ïýÀMž·>U° †R<±hƒVO@‹g€ ˆ&[Ý׿U(ã.¥Äêê*„`ŒEC§§§Ñßߟ+àÊ+¯ùçW^yͨ”'¤kƬÏHñD÷!@ÄŽa»…ƒÙÿ/„ÀÚÚZT.Î9ÇÁP,3Ósgèíoׯ•ˎל"Ø‘Rrµtp<|n.Ìéñ‘ )Xúþ ‚ÈI¯tÝõFè]RJ4˜`Œ¡T*EñYéW«Õ›>ñ‰O½ÛuÃYõ¥ƒãñ¹—îŠ'zm¢¯°Ýe!b{PÆ_¾ïGŸqÎ188ˆ‰‰‰\Bhß¾}wüð¿í !ÂI‚º°t0=ŸˆLHAäÄœ PB`uuAD纮‹™™™\ñÜ¿ø~óðáƒ*€–&6Aì8¶»{Á6’ ¬­­E#€p-………\k‚pîN¼ï}úg®+\5Eps~^©„ëø¾ïhñ4?±!H±ãè…`@Ý ^û¾ß÷c]Õjóó󙢅1†Z­öêO~ò®·4§ võx}é`# IØ^D ‚ ˆÐ€Ú«QzWc ÃÃùãææ~þ–[Þt‰ëódÄd-LVH±§i§;Á­éf›^0t›Q½NÛ­ËÝ(6#ÿíþ3óOb*N V«avv6×} ½ícûøêK QrlS'ÄPW‘ €=„i‚ €BŠø¾¹"ˆö¢ó7Ú*¶•EÏ×ÜÌkôt:­[zYe0ïÙ¶O:«6=ïÖÓf²†\åÝIÝØ®IRÊH螀ÑÑQŒŒŒäªƒC‡.ýÕ—¾ôÕûâ]­K·@b€ˆÈöE;Ó! !!ÓgNãØÑc8}ú4NŸ>ÕÕU¬®®Ç1‹E appcãcF¡PC|,4ýP×ó_ZZÂw¿û],//Ç>KK§P,àšk®A©X²¶¸òÖ…ÚVVWð­o}+ºß´2«{-•J¸ôÒKQï«ÇòV†÷ĉ8vìXdžW¿ÎV'ÖÏ*àœcvvý-×o%*~;Øì¼õÿ?Õ·íUP`±XŒþ‡ÇÁìì,.^¼ˆ¥¥¥Ô|8çå׿þõ¿}ß}ÿð¶Ó§OJƸBHÆÊÒ÷W¤ 6äœË0à˜xæ™è?B±×Qñ÷Ä…À.Çlµ )pæÌ<ô݇ðï|'š½L«£rÇjœs,,,àŠ+®ÀèØ(\ÇmK¨²¸®‹'Oàé§žN}P뫪9ŽƒùùyxÃ^Ԫʕ·.AàìÙ³xð£ÖYRèõÉ©I\qùBDӼꕣGâž{î‰ÕCR½¦‘WL%¥?84ˆ¾Z_´Tm;õ´zÑãÐM1 §•WA€F£Í âæççñðÃÇ~ƒ6ŠÅâ%?õSŸüø¯þê/ýFø¢P²Ñ`²ZåòâE!ƒ Œ1©- ´zý=‰‚Àn¥Å--Î;‡¸çðØcÅ\ë@ëCL3?Bà‘GÁ£>Šññq¼èE/ÂÄÄD,ÚfllnòÑ‘Q<ùÄ“1bæ©§Bàü¹óŒZRx‚ €ïû8{ö,Fâ¹jX—þ W®[}8U¶ AK׈íÞÒòÌ:ž$(8çRÂq!àû><ÏÛ2ãŸÆfçŸfäóÿˆÿüŸþ3yäk_¾2^Q\€fДÁÔ?‚GŽÁŸýÙŸáË_þ2–W–[ÖG·•K•)TkÕ¨mËÓ,ÇOòÑ[îíÔÊç䉓Ñë¤{Ö?€Z­‹îÖëPÕQRüBžûk÷¸ÊüÄËÝ‹-sÝh­o…Øhw/„@£Ñˆ" ¶±±1 æÊöÊ+¯þõ¾ð¦q)UP -Ll » ½ŸÝ÷}¬¬®àüÏÿ/|þ 1ƒ¦uÝ ¦ÀéÆFß?ðÀøoùß°¸´k'L©tË¥2Êå2|ßO hÓ [8zähôZÝoƒëi¦«úꕲïéõP,Q*–b†]=äU}ÛÄ„^¿¶òšyšÇ³‚õú1…†…Þ+t£,y»HÒÎ뤵Wÿ#zZœsÌÏÏ£\.gæí8Nß[Þò#¿^*9Ñ\:8Ü—Ö¥ƒ­ó á=±G!°‹0 ÜêÚ*þöoþ?ôpÌ@èFFµÓ¢×õã6£æû>Ž=Š¿øó¿À¹óçZ ºYFõP¬T*¨×ëÑq›¡Ó?€³gÏbee¥¥ #/Ê(..-âìÙ³©ßlq÷ÕúP«ÕÄû÷“Ò0sÞ–¾šNVmy<¶òog«?¯qÝHD~»itSéÿÇy÷¢ïSÁ9âÇÉÌ·T*]wçŸ~¿±t0o]:X0±¶t°ùšØCØ%èÆ?¬5ÖðÅ/|1ê_Ô‹Í ™âÁæb6ŠyΙ3gðWõWXZZ²ŠP§ ŽŒŒ¤ŠÝÀ Ž8{îlKºYèF"œ?ËËË-ÝIÆSJ‰‘шëÌÏ¥”ÑÐIÛ=µ{<ÍS 3½$¶zÜN’¾ŸvÊ•7NŒ|'åPñˆ}~•F½^ÇÔÔT®òOMMÝöŽwüصmLLóVHìLcrß}÷áá‡޵à¦+ÚævNò˜bÀ§OÆç?ÿy4üx§Žr}rÎQ©V¢èh=}[ËVíÏ;×vÿ¶Ù ÒÈr¹«cœsÔªµ¨ÜæÈ³nͺÌú¾’@;Çuodoöû·ëج4:9Xoùwbüuº¶¶Ö"`'''óÆðn¸ñ7_ð‚«†ÕÒÁa<@¹%€¦ &Ò ° Ð ŽøxîÈsøÚW¿fíß7[ˆi}Ó:¶ó’ÜæO<ñ|ðÁ˜Wèc¡9ç¨×ë¨T*-ùÛܺêœÇO@H3zyêHµþ%Â4Ìò›y«½”•JÕj5æð*´Ú¼*IuÞ Á ¥„íHv‹nÇ$(1?kÇàw*Žt㯋ÀND€ŠÐÓ›E©TÊ,‡ã8ƒï|ç»E-¬ÅðÖxZ:˜°C`— ŒÛêê*>ÿ¿?ou­}×êÁ“åŽV¤=¯}õk8uú”Õ¥®ZЮë¢Z©b`` ÖzMjíªÏŽ;Èõø…,ñÒbdE8aOš+ÞKµZ õz®ë¦z’î!I4Ù<,i¢ÁvoIB¢ÿòÛnõe¥m+G'Â,W'"@ý^õ @ÇqP,177›ÿ"‰jµú²;ïü™·Ç§ —ŽÇÄ–¦x"‚æØáèÃ÷}<ôðC8qâ„Õøè˜E×uÑ?Ðr© × ÜÚÚÖÖÖ°´¸„‹/¶\§»Cø¤=kkkøú?|¯yÍk¬­%åàœcdd?þxbk^ÏS .àü…ó)„ñy–Àºx9{î,.\¸«Ÿ4ƒ.¥ÄèØh¬Üiyèõ£×±nÄÔV­VóM3ži†K ­4ë}+èF+ܼ·´óÚmÉë×tz½Âìhw¯D¦ú¨²ô÷÷cbbGŽÉ,ß¾}û~öMozË·ÿôOÿüAÆ|Q, ¹¶V’Œ­Hs~€™™ò™gÂÛ0’¡ùö($v0êá  ÛÅ勸æ7¾ÙÒ­ŸoÆÆÆÂ)~ûúúP¯×£>yß÷±¸´ˆ¥Å%œ9sGŽÁÚÚZËCÐ|­òyì±Çðì³Ïbzz:ö€S¨_­Vƒçy±~Q½|æ{uuçÎÃÐàPdh³D€ÞpþÜy¬­­Y?7áœÃó<Ôªµhâ¡,±`ŠÓÓ¢’-,,´Ü_;[Ujó<ÕJ5öY/£Çio#®ûvʆ¢¥èL pÎ# Ê ~'SSSX\\Äùóç³Êí¼ìe/ÿÜ}÷ÝûæÇÿþ P”¥ï/CHƘ¤©‚ $v8zëÿ{~.\ˆŽÛhºQrûöïÃÜìúûûá8NÌÈI)Q­V A¹\Æã?n5žªE£?Ä‚ Àƒ>ˆÉÉɨ¥¬+Î9Ç =årKº*m=•öéÓ§1»¶¥ yêëä©“ÖHýõp"ÿ?00ÐR?êžuÒº%le¬T+Ñ”½¶ÑyQÞ ×uQ(P*•2½[I;]í¶Ð;Mh?PRý_¨46âPû ¢ïOý߸®‹¹¹9<üðÃÖß…ŽãxÓúÐÇ~á3Ÿ¹ûg|_È0ô†I@ÊjUò‹…T] Ž97öä“á-€¦ ÞÓØ¡è†Q €x ~—fHÔ磣£8xà úûûQ(àºnÌh(#<ÏC©TÂÚÚžxâ‰ØƒÓli*! „Àc=†ë®¿ÃCñ´•1u'Š8sæLæ=«´?µžt—wÒuê^„1F=š¨| ¿ÞZmÝ ×6óTÁ‰I]f?0cáCžçeÆ$av­xžÏó¶Udåºá“nRºå=Pâ0ɳÓɽmJàªãår³³³xôÑG3ËÕ×Wãm·ÝþÕßùÏý…ï7D¡vÁª¬T–—™l ”À 4U0A`G£‡=wä9œ:u ÀúÃN7b&åróóóB±XD¡Ph1Êhú¾‰ƒ¹¹9œ9s§OŸN4ºzþFO>ù$£òè.p%†‡‡cs¢Ûº.ô´Oœ8@-†Ö,þ™”F§OnB˜ÔõÀ9ÇðÈpÔBWÆ?o€­\úk×uQ*•P,cÞ…vѽê»ÊÓe±•˜FÏd£FÚÖÂ×óîFžúøsäH§"@•O[Ù/Js``ããã1ÑšÄÁƒ—ü“›o~ýý×ý=Æ|©ÇT«ÂYZŒxŽPĪ ë"€ÄÀ.‡ÀGµþ¿ÿô÷Ñh4R¡þÐÅþýûQ*•"¤"ÜuW¤J_ ƒÑÑðº3gÎ$º¸õãAàñÇÇÕW]k5©ò(Ã:00×u­ã£õûP"ââÒEœ=s¥b)×\å}êÔ)¬¬®$~³¾\×E½?ª—,cš¨÷+aœq‹E‹ÅÈ Ð º¨Ò[’Ûmø³êw#ØŒ·)Íó6*2tQ­ºÚ5ö&ú9úoDýŸÌÌÌ`ii ‹‹‹YÅ+Ü|óÍ¿uï½_}ë±cG%c\ªx€ Xi.#LñÄ:½ÑAH´…þ P}ÙO<ñ€Ö€*Û¹®ëbfz&ê+V P(DB@¹‘=Ï‹ ”Ú&&&P©TbyØßT9Ž=†3gÏDݪœzÀÐÐPlü³Þ22ÓB—éÉS'­Ÿ%ÕW8uúká €YC…( ŠP¦I™€GÿôÀ/×uc›úÚÙÔw¥wãl—Ðï?Éó‘v]RgÐvòìT$ 4]¬¦mæ¹fmsg¸®‹………h%Á4 …ÂüOýÔíw»®çpƒ ±Mœ0?Œ÷Ûï>"6;ÝX;w.rÉç+^©T°oß¾Èðë†Co•«åK•QRÛÈÈFFFbyØ´ª óz]då1òyE€ª•~©TÂþýûs•uhhøùÈO¾:>?@É 騩‚}ßwGhŇ IDATQ®Í`nþ] €ŠjÁA€cÇŽÅfS{Û,|@8ÿ¾jé«Íl1ÚŒ‹ÞÊÒÍ2xRJ;~,š•PG7\ÃÃÃVc™dDÕŒ€fŸ»í:0¨–Öë#­ü###1£¬_gìó´´õ©ˆM·}·¶^¡#t^WM«å2½5þ6O€þÿ444„ááá\e¼ì²+>ûò—¿rF-¬Ö PSK)™±^-¼!°CÑÚ©S§Z ®­@¾Á¡ÁÈͯ»¶Ö¢.Ô˜x×u£YñÌ2%‰€Ó§Ö=úCSoýÂõÜ–þP•¶~\“'Obey%s:c}žå)ѽ 6¯ cáxú¡¡¡˜G$SÈxžY]æû¼®ä^6ö@²ñnçÛën— ho( 9”µ[-Ûÿ•4«¶ýû÷GÝoT^÷º7}®^/„nÒÒÁRJf¬ l‚­k ·þɈ C`‡¢1ݨ%A |¸8ŽÓn¶:“Ð=®ëbll,,˜öUe4[ꦇatdåR¹Å-¬Î7ûìF, ­üR†#tO‰^[ý  Ǧÿͬ‹4/ƒº§½ÊF[ò@ü)ÏùžcÃÌ»›{³Lÿ,,,ä - Ï»ýö»os]OŸ*˜'ÅÀnô»; ³U ?ŸÕï¬"õ¾z‹Û?J08Žƒr¹ Ïó¬žscŒaeeç/œ·vK(aR,#g’¨Ð½Bœ:yªe8 ‰î)I ü3óQ‰6÷|Ië $ÝK;­ÏÂFŒñFÓêf· óû2…êöÞÖe¦æÈÃØØØÞóž÷¿Èu=WuHYæz<€ê ˜š¢x€½ €ˆi\3[’êaÈCµVàe¡=ÝžÓ )ÕÏ..]´zô1öÃÃñü²Œô±cÇ E²B7ÈGމ]k+§¾©Ö¿™ç^Í´’ÒO*Çn!ËÐvÃ8'¹ôó¤™$òæ©Ï  ß O€)š‡††Zq“Š{ÕUÏÿW]uÍH|éàRËÒÁA0Î(`oA`¢?è–——£ñÿI­Zý!R*•Pð -“Ú´ã‚Uâ¡Z­Hvcëå‚KKKV¯„îÞÔ»Ì4l›ZÕ/m¢z}êä©–ü“ °êæÐƒó`kí§ óõnõ (:1ÎæqÛëÉ“fVþYH)c}ÿíN¼‘=þ/ë¢CJ‰ÑÑQœ?>s1-üÆ_ô›ßøÆ×ßøÿøØ™ hHZ:xoC`‡¢?l˜@ ý:etÌ–zZÞF#1]=pjj ÷Þ{oK«ÜÌOqôèÑ––°:GM¨¢VT˜D/3ç“““ÖñÿY¨€DëgFžœs|õ«_Å×¾öµ¨’η¥e–ùŽ;îˆÍͰÝ" ÍhwzN»Ç³Ò×[ÖyêËüŽ¶Êø›"[ÿ-J)±ÿ~\¼x«««åwFÞ÷¾ý_?÷sŸúÉøÒÁeY©¬8ËËëKÀܤeé`SØ¡PÀEýðõqíy†¸é-îNZ@6÷§Ê_O×–¿þÞæâT`dd¤eø™—ž®šØÖ¿4× 8™¼n€Y–B¡€ÑÑѶ[ÿz=˜å´åkºý}ßo™.íûÔë’1]ßÉ÷Úm’êÌ<žÔÚï$/³îmif}ž….Òþ—7so»×u1??Ÿë>jµÚË>ñ‰OÝÚœ*ØÕã* 1ʦ ޲NxMìHìPl.P…n¤õ×@k ¦[Æ"σG?Çæ×gÏ%f¤”X]]­… Ÿ+„À©S§"ïC–qDhg¢$³LêÞ’Œ¶‰^Þ ÚÚÔ=5(Î!)Ÿ­ÆVgyoZ ?+/ÝÐoô\}©lów¶U{ýJÿ=W«ULOOgÞÌÏÏÿÜ-·¼é!¼ØTÁ)ñIB€ ÿ†ÀǶâ›Í°%MÀÓ)¦'¡G‰×u199imIëèÁs¦‹_]§Õgik¨mrr²ãѪ›"©.Láfûžòûé׫V¿Zk!k âí&Éø'bóœv¼Y­ç¤|òœ·{UºG‚sޱ±1 ä¹ïæ›oþݹ¹éŠë“ Qv‚  Së†ß¬0; »³µŸ´éçlV¾&º±J3ަ`rr2d˜fŒ¥”Ñ,6€ ÌãNçœcjjª¥õß.YÞ ›8kÇp›ó0ÆZ†Šm7Y†ÚæÊ{¾yf^툆$Oƒ uÍVL”µ×óWåáœcvv…B!ó^Ç™þð‡ê]W¤.v€–Þ…Øá$õ§Ÿnak¡·ãö¶Ý‹Ú†‡‡Ñ××k餹ϕÀÖj>qòDjþz9kµ†‡‡ceé¤N²„˜ž·Ùu‘t¶÷i^ž^$Ë¥ŸÕ’Ïs\ÿ¿Ì yò¶¡wô‚н_®ëbnn.×ýô÷÷¿é¶ÛncÚÒÁª+€–Þ}Øè­›´Ö8Ðl)t)`×¶2šè³”G„:G_zWïÈÊÃôa½,¯,ã왳ÑyiRÏS/G;^U·YbLß²<7fKÙ*ìXöýmíØNqÒùY¢¡“ül×ÚŽoÕX¨ëëëÃÄÄD®{:xð’_zéK_½/ÞÐ:Upñ$v$vª%§ÅÏ‹Æo<ãä‰zlÆ+S 4Qqj*^ Ùe®^¯¬¬ÄZú*˜îÔÉSð¿¥>låæœc||<êÿÏ*· ‡;©FØÌ3é»Kó¨¨úŠ-O !{keÁ¼­ö´. U?yÒnG`tŠ÷¯§× {sr+Æ&&&Ð××—ç¶Šo|ãx¸^–¥ƒ)`÷B`‡#F΢]—vIùÚDgÉy+# »Þ'&&ày^KkØæyRâôéÓ±Èx)›K7ü—¹yŒ…S«ÚÆÿ·ÓªÎú.’< I?mÆ?³Ï?­~·u¯z=Úúϓ壋¡¤üÌc¶kô2äùžõ¸`kg4÷Iž"½lsssð1ˆÜ$=ÒÝBŸ˜'­|¶×ii*÷{½^ÇàÐ`fKXqüØñ˜wÀ÷}œ8q"3š_¥944„¾¾¾ØÀv1 IVk^¿Î¶™bÄ|ÐG²'·¦WÈ|­Ë:7+ [&õóë×ØÊ’v?ÛmämÆ^Ý«)H …fggsÝÛÐÐÈ»ÞûÞ¾D_/À\:Ø÷}‡–Þ=Øá0äs!GçwQp–=L.«KB/—ÞrѽIx3Ý'Â.å¦ÅI¨×-«ÿµ+œÔƒ8«KD½VbCi›:ǼÎu\pÖ~ÐâV‘U‡y„b'i´sMtCkû]mf‹>Ï^•I*ýýý˼7)%»êªk~㦛^dó'Ó0šË«sÌ”áPÀµµµÈM»´´„óçÏ·œo¦ š|h£ÃÿÔu6±b¾gŒan~žëÅ®O"Éਘ ÛÌŒ½€^z«Üô”$«ž”nÚ±^cž ¬Çè÷’gŸF»iµ³Ÿ™™ÁÒÒSËÀ9¯¾ùÍ·þöý÷óçϯJƸBHÆÊÒ÷W¤šh* ŒC[/€¦ ÞqØ´ÓWA×5¹Þm#j59Ù@pãcã(•JÑ’¿¶üÔñÕÕUœ7—¸b ùžèHìPÔC¨T.EkÀ›-NÛ¶´´´á|¥”àŒceeÅú™ ÎylLV¿«* R­´|nk]Ÿ9sK—páü…(à)Éý®>«ÕjéŠñWcñ“Z£zýpÎá:¡Èñ<…B¡£M ¥$Çv“՚דynšQOú?²u‡™çÙ cÞ:3ÿïvÚžsŽ………(X6r¹|Ó§>õsïŽO.Ÿ ¶t°>D0ª¶Ì̈-‡ÀEý˜=×C±TÌýðZYY±ÆåÁ¼æÂù ±ci-.×sQ*•?×ß›[¡PÀôÔt®{\[[ÃÙ³gqþüyø¾•Û|`ëÛÔÔ …BËÔ¿Qó:ÛýÄD[ŸûÀ6¼/m3‡ö¢ñ×Ñ }ÖçiÞ€¤ï&ëš¼åË:ÇvÛmÔÛÝ—J%ÌÎÎfÞ/LOOêÍoþá+ÚX:ضÁ²'¶;óA5Ð?Ðò¹Íˆ1Æàû~Qßn  jI©íÜùsVgk!•Š%T«ÕÜýëæ¸÷‘‘‘\eBàÜÙsѬ€Y÷ã8FGGcyuj@%$Ï?µ¯*ƒÊS ¬åŠóÔy¯‘f,Í×iÇl´{mR¾íŠbÛÿùNÚ åú]1ÆøK^ò²ß¿ì²CýBxnHW-ìû‚¦ ÞÁØ¡(C„?dý¸í\µA€Å¥ÅXt~»H)±´´„Õ•ÕH$å¯Þ÷õõ¡X,¢”Qäœcph0W¿%œ:} 'NœHLS§T*ahhhÃÁbk,´c¨mÃÑvƒÑ71ešÁµiÛ5ú1[š×&¥k^ŸU®Ý²ß¿®ß•ã¸Ãï}ïûYŨ¥ƒ…(óJ%\/À÷}§Í¥ƒ‰m†ÀF‰€z=×t·jâø‰–à¹<èל9s«««Q9Ô^Èë-ÝÁÁÁ¨¼y¸º`xh}õ¾ÔÖ±â駞ƳÏ>»ï$úú100s©o„<³#*ëÝùû»MRä1̦À´ýÿ$¸¤î„nÜËnØsÎ1??Ÿëÿ¾V«¿ú“Ÿüé·Øâ*áÈæ,m,Lb`›ÙOŸ]ˆzrÎÑWë‹õ¯'=èÔƒôé§ŸŽ½ÏÛ ŸwäÈëX¯÷OŒŽÄÊÖ4òÊ8ÏLϤޟúlqq+++©-fõÀ›™žÙðô¿±üy¾ûÒí%’ŒzÞÏÓŽÙÎIí¤ež»›öårûöíËuÿsss¿øš×¼ñ ¹tp(K<@ÒÒÁнõè1HìPô–ðàà ªµ*€õ•Â4FB?q§OŸŽV™ËB7üj’Ç{,3˜KQ,Q¯×ccÔó  µã8p]###p]7õÁnëgOÂõ\ µô½o†ì²ÅÞï¡ÉÑÌùÔkEÞc¶nÛëNºò$âvò~ttÃÃÃyîÝ}õ«_ý{33ãeµt°Š‚0 0g<€^‰$¶ ; ýá©GÏÌÌ$žo¾üß}è»±ef³r}‘§Ÿ~§OŸ¶ž£ïƒŒyòÞ«~M¬¿2­…oÛLjµáºn×fÐc|ý¡š•žî‰Ø+˜Æ7iŸYwIÃÓŒ¹îMH2ôí ý|›ÙÉûÙÙYëHÏóf~ò'?þó®ë9A \´tðܵþ{•½õôÙe¨çãããð‹Ç{ §OŸ†ïû1·rVyÔ¥¯Þ‡ T*Å¢ìÛiá*è ´ã8€&§²—N+#cáÃúDCz~!mb½¼6A¥»ðóºüÍïE½VÝ8YßÛv yÐÏ3¯µ §´Ï’ÒoWHîÄ}Úf»¦¯¯ÓÓÓ™u"¥dW_ýü߸êªkFô¥ƒõx52 ÆÅô$v(úW¹Û=ÏC_­—^z)úê}’‡æÙŒ¿ùÞÖŸl´=ÇÁåÏ»#Ã#Ñ2µöµëç+o‡šV¸“´ '>©ÖªÝwÿ©­¤<Ìþ{[½çÙô9¤1ñÖk$lÓ›ÇÒ }Öñ¬¼Ú-{/îÛ5òYûÉÉIô÷÷gÖ ç¼ö®wýÄï–ËŽ§–¶Å¨¥ƒsÆØdHìp”Á圣P( X,b||W^q% …BêÃÐlA&µ0Õg¶ëÍt9ç8xè ¦¦§P,#a¢·þÛyèª<Ôõœsô×ûQï¯çNC‡1†ô×ûc¢¤[F2kj_S<©z5þFƒ¥\Ÿ·Á–÷vbþOš.zµÏ2ì¶ï-I0d ‡v½½°ï–‘ÏÊãÀ©·Šb±xå]wýìG\7œ%°9U0·-lĤ~› €ŒþÃW­ìB¡€R±„ééi<ÿùχëÆÃiïº.8«ž&&&>öŽw¼ëù]\:˜ØDHì”ó²ÒyNÔñnÀr>·ºi”Í®ƒfA¢ï²›Žn’Ô*7[ðI­ú¤´’Ž'y:)óVù­6öIûz½ŽÉÉ\¢›ÝxãM¿søðÁ /¬â$-ÜØáè­X}N€R©„z½Žýû÷ãÚk¯E­V³^k3øIÅ$ïçy8|ø0]rc£c‘ñ/ ÿo»Oe´«•**•Jª 1ËÎC­VCµR'»9@;t"^²ÒÒéEƒ¯c™4ãœ$ÔÞ&²Ò±•'ïÿÁNoÑwºŸžžF½žÝõƘ3ð|äs¶¥ƒ}?¾tp£>7GñÛ €]‚®ëFž€r¹Œz½Žééi\{íµ˜››ké0 h’‹Ùv. ãºë®ÃüÂ|düK¥R‹ñß(ê!¯î±^¯£ ßjÒDÍÐÐúúúºü—‚.´’ê¶›ôr«_'o7€b^«®×÷YÇõ<7ÓÐË-úNöœs8p åb£R©¼ðŽ;>ý£Í©‚]sé`= aªà¨Ê^]€À.@ÿ¡ª–m±XD±XD©TBµZÅää$.¹ä\ýõ˜ž™¶õ¤=¬Ìó†G†qõÕWãÊ«®ÄÔÔ†‡†cÆ3ZÿjãœÃõ\LMMY£ÆÓÊ>33Åtkú_=oÀÞúÎ2ÝDÿ­8Á&àôòëÇõ{2ï«“`À–9ËØ'»“÷…B ¹êivvöî[nyÓ%mÄ$ Þþ'ÞÁÐD@»ýÁ¦ºn09çÅÀÀªÕ*æpêô)œ;{gÏžÅÅå‹"9ȯX,¢¯¯ýýý ûøûûûQ­V#w¿*ðOåÝ­ûSé9އ;¡Ç¡\Ц Ijñêå¡¡¡¶×%È[6õZ_”i«Zá¦1RõÞË^Óà§}fîÍs³ÎI:_Ñn0 M€$•c·í111£GfU“sóÍ7ÿ›oûÞ×>õÔsKŒ5d±(äÚZYÁŠBHƘäœË0à˜xæ™ÈØ« Ôë¨ê÷Ä °‹0E€i4]×E£Ñ€ëºð}ƒƒƒ¸°xFÀÚÚ~~Ã8nØR.Š¡Át8Ê¥2jµZÔÕ †úé­~=ïnߟ~/Õj×_w}ñžeH8ç¨V«ð<¯«]* Î9*Õ n¼éÆØÈ‰­0Âú,‹ºÀÑ÷"z7@šñ6[óæ¹61‘dè»ÉvãíÚïß¿‹‹‹X\\L­ÇqÆ>úÑö3ŸùéÛ}_HRˆÖ©‚Ãs!çæÀž|2¬Z$~]‚À.CØé3Ü)ƒ Æåû¾b±ˆZ­Ö²ð2Zæõj¯Œ¼JKmʵÞÍ–¿‰~CCC¨V«X[[ƒïû‰}ÿŒ±¨¼år9êšØhU] !¢rMNLbp`0V&Û ÝFU]?ÊÃÑí‘ݦV}’``,¾–@;^€ÆLl·1ÞŽ=÷/þ«ï7D¡ äÚZIÁªTS@£1*2§ &º €]ˆÞRFÛ÷}pÎáû><ÏCÑê¦0ÓR†DœW"@ óÓÇúo†¡QiJ)áº.„Ñl€®ëFÓÞªsÌzPe/ -€–Wj~ÇqZ–YÞ,ôûp'òÈ(OŒ:§±µÜÍ÷iŸéû¤´Ìn=‘ IDAT¼’ÄÆFïc»òVï‹Å"æççñ½ï}/³~fgçñ¯xÍ7þîïþî)ÆüfW@IúþŠ¬Õ µ^ÀÌÌ ùÌ3±ƒ´^@—!°K1Õº2ÔÊý¯Œ“¾üoZ ZoÙëAtú¶ÆF•AÍ.¨ÄiôóõÕÕÔÄÝþ§— @”ÏVOë¾+uº(ÓÿzvZõêü¤{I;?—a#ô‚QÞêýðð0Ο?ãÇgÕ÷º×½îß}ë[_ñcG%c¼P–¾¿"›ßÅl1$v1úM=L•QPßlùë"@o+7².ôϻђÎs?æ=)o€^n›@mºXéVë@ÌÍnηÙõb~_º8ëÖ}n&I-sý³$#d^—ä°]gæÓ ±Ö Fy«÷³³³X\\ÄÅ‹SëÆó¼éüŽÏüâ/þÜ/´±t0@ñ› €=€i¤¤ Ýè¦ÑL{êÎÖÒßJ£Ê¢Ü€ôòÛÊÜm£¨‹¢íŒÀ7¿ë^ þ³‘&iÆH?ÇL7éünµþóä·[÷ŽãàСCxà2ã]†~øýïÿÐþý¿ÿƒÿåû Š€²Ð—ö}m,Ll€ót 6ŒÞT†Jo-êýúæfºúÍm»îE7ºz,‚¾éçlF™“êÔÖM²Y›~¯[9ÉQ·0p’`3Åœyiÿ›6áºYØÊ¿›÷årsss¹êæŠ+®þõ›nzñ„”'\4(¾t°”’ÑÒÁ[ €=ˆí!™dØÓ¶^»‡í.»Í8m•èÅ晴Œ³ít±t]šÀ<³„Ávå­Þadd$³^8祷¼åGþ ^/²—¶®€„÷D› ¶Ýpn”^+ûFÅI/Š›­À»aºœõÏmç«}Rl–±Ob»òVïçççQ*•2ë¥P(¸ãŽOßi.‰/,héàM„A=i¬“‚ûÌóóó$!a¾î6Ûm”·rï8.¹ä’\±'£££?þc?ö/ô¼õ©‚¥,sÛTÁSSÖi‚Õ—F†¿CHÑSØZïIû4/€2öi^òt_­V1;;›«Z®½ö†ß¾êªç¨¥ƒ …À ‚’«/lʆßüI ´ ‚ z†<ùIÆ'é<óØV ÍL+Ïnاm011‘7 ú£?úã¿W.;žŠRrµtp<€–î6$‚貌ºù™ÙÒ7ÓHò¨Ïm×m&½`¼ÛÝ'ù¬ýŠÅbf‹Å+ï¼óg>hÄ8BHˆ-œ@ä€A=EšAW´ã0c ¶£õ¯Ó FÝÜgµè;Ù«x€<õ=99yÛ­·¾ãÊ6–¶m°ì‰HÑS´Û"Ïò$yò|¾Yôš±ß¬¼jµöíÛ—«J^üâø×—]v¨_Ï é†" ìø~8B@ˆpŽ€„¡¦7–÷„ ‚ zŽ´à>µÏëÐÓ3¯ÕmõÌ;­Eßé~zzƒƒƒ™õÁ¹Óÿ|ä7\W¸B'TW@™W*ÒBpß÷°;lnÎË{"AôI­ò$#߉ ±Yì´}§û P(dÖG¹\~ñwÞýNÏS³®ÇT*ÂQ³6£\‹ ®€!@DO’61zŸæ°¥g3öÛ)lù÷z‹¾“}¡PÀ¡C‡rÕñþýsŸ~íkèaP P­ Ç`±*ÎÌtB€ ˆž¤S/€í›±Ô¯Ù.㯗Cíwª‘ÏÚ÷÷÷cff&Ou8¯~õ«ÿÝôôXE¡‰€²a@`ÎxýK%`A=ËF½iÆ>¯°Ø*v“±OÚÏÌÌ ¿¿?³.ÇùÄ'îúU×õœ ®Š0§ ¦x€A€ ˆž¦[^€¤E„¶Ûð›l·‘ÞÌ=c —\r <Ïˬ‡Z­öšÛn»ý‡âñ%'¤c ¤x€Î @DÏb3èi^ý}’[Ý ÔÓîzÁXoÖÞó<:t(W=8pè—^ùÊWï3ãÌ¥ƒ-ñy2!@DÏ“ÕR7 iäÍa€i]½B/ëÍÚ `jj*Ox¯{Ý›þ ¿¿ì©xÛÒÁ)ñ°¼'š ¢§Iòè{Ûks`›Ç —½@oëÍÚÏÎ΢^¯gÖëºû?ýéÏü‚ëz±¡X:¸÷¾èm‚A;‚$/€Í¸dµîm¡Wéc½{Î9:×u3ë ^¸õCúØ«ÔzÅ¢àR–¹- çÒÁ½û…o!$ˆ¶x2x ßi|äùí.±GHó˜çë]¶þ~ósóÚ^d»õfíK¥8ëþŸ÷¼+~ýºënÓ—Öã,KS<@ÙÒ‹ š|}í«ø‹ÿOžz/Pï¯ãUý·à•Ÿ@õmwñˆ]Žn u1 Œ¹"ÑЛ¯mlõTÀí¢ßënÚŒŒàܹs8zôhÖýßö¶ýƒûïÿæ[——W%c\ !$ceéû+2@ææ<ùddøÕ—«þzûËÞ"È@¤"¥Ä¹à,þå…_Æ/?óÜ÷íûpü‰ã8õý“xâÁÇñ_¾óG¸ýä‡ñÕ•/AJÙóQbg“Ô¢OëÈÈçéDed¶‹ín±oÖ~aaµZ-óþ …¡»ïþù;Œ¥ƒù–ÞÓ^„eÌGñ™swà¿?ô—8ú½#X]]A 2€ΞÇwø~íûÿÿzé7±"—I›†Íý¯qõ>és}3ÓÙ½¶¶Ö•ûØÛm¬7cÏX8?€ã8™÷?66öžw¿û=7ÐÒÁ‡C7Þgƒ3øÅ³wâþ‡îÃÒÙÅÐèCFXk¬âÈGñgÿø'øÌ¹ÛñxãÑ(-‚è6i^óµ~^’á×÷Åb15ïÅÅÅß@è£Ýí}¹\Î ¥d/xÁu¿s啇T<€¾t°Š ¥ƒ³!@Dè[@àw—þ}ìQ¬.­@Ȧé—RÊð½ ß H2À¹Sgñõo¿|úgñ¸¿.HÝ$ɸ›}üºË_}n×Ï•R¢\.§æ}öìÙîÝÈé£Ýíýèè(ÆÆÆ2ïs§ú¾÷}øßØ–öýøÒÁøÜMlƒ`ýa(eغ¿íøÊ±/àâ¹%Íø¯·þ¬ûšŸ )°ºº‚Çy¾ò'Ñ5zúÑ ’¼€Ý寎Û6=½jµššïñãÇ»3 ŒöF÷ævàÀT*•Ì{/‹WÞ}÷ϰ9U°›´t°@]$ˆ¸‘fáþ¯–ÿ Ž.6ÿº0°^‰ƒðõêê*Nû'céD7±µèm­ó}Ò4ÀjLÍ÷èÑ£h4]¹‡nÑ F<ï>I€é{ÇqpøðáÌ€L˜ššúøýÐ[¯´ÇÐTÁY Öië†hà[‹÷cmeʬ·C_—x—A ‰€„Ñ]L#¢Ž™{óó¤Å‚`hhÈz\žx≮”¿›ô‚qWû´-o•Jóóó¹ný¥/}Å¿>xp¶_/À6U0øÜ\x ö¸áWØãD­ÕŠÏÏ`ue9vNRëšC¨Ààp“Ó“øAï á52~=‰¢›´Û`ëÐ) JÍó¡‡ê9/Ð;ƾ[iONNbtt4ó¾ÇøèGoûM׎RÅðÖ©‚3»¢ªÌÌt—@€XÔS}üš‘Î2×Êø«ýÐÔní{Ä „R„é’á'6›1Oë 0¯µ]ŸµHÍêê*î¿ÿþ •{³èÕ}§ûƒ¢T*eÞw¹\yñ]wýì»´©‚)Ëܘ1Kàž1ü {˜È(7ÿí…”B &jண”A(ʵ ®›¸/Å+!¤D ! ²!@liËûfuؼSSS™ëÕ?ñÄxì±Çºu ]¥W[ôì]×Å¥—^š*ä333wß|óëçÌ¡A €õù"»—Öúßb€Àg½õhx_}®¬»A“~|ºëßå.föÏàVñn"cÔ¨Š 6 eÌÕkÖ÷6£fŽã`vv63ßo~ó›xôÑG»z/Ý¢W[ôìëõz®xƘsË-·üáøøPIJÉUW€š%P`,ãõžÀ^Ge- ¸‡á=°æ ,ñ·ÑŒžžÄ-Þ1Œ4¿6t†›L’AË3u°Í8p sR )%î»ï>|å+_Áòòrê¹ÛÁN2òYûéééÌØ pgôŽ;~ú³i£B!0ÎææÂ,°‡½$ö(1c¬µþ…B`AB¡¯Øü¶þôÖ±TÂáñçáÆÕ—!Aèúov'¨þê 6›nu0Æàº..»ì²\ù>óÌ3ø›¿ùÜÿý8¾÷VÈÜnãÝ­ý¥—^ŠB¡y¿ÕjíµwÝu×I)!¤#¥äB”¹ê ½Â „ñzO@«îqb­ó¦Ñ„À•òT*Xÿ[‡Ù`þÿ1_1Ð<×|==='NàÙgŸÍÌÛ÷}<òÈ#xä‘GÐ×ׇ‘‘ôõõ¡R©$v¡u )%|ßÏu^ž÷æq!|ßÏ}}Vz¶÷yÓ¯T*™ë10Æ077÷Ï^þòWÝóÅ/þïg á4L!y_ŸKKÊ 67XV Ü3ØÃÄfÿS[Óm?"ư¿6‹ÓÎI_Œ…ž¬?(€b±€K+—crqÒ•-iÄV’dlm“éSë{ýü+®¸KKKmM|áÂ\¸&œ‰Í†sî½éMoýÝ/|áÿ¼UʆB8Œ•E¬p!„ ‚@26*}ÿ„Þú×Zêý®Ô@hÁyëcö…”x|!*CUp¦˜A,. P+a~í`k’FŸ#AlyºÌc¶x ¼îºër-UKôÅbñÒrÙñÂXÉîÉûúB€Z,¨ ¬w왇 @³eÏsß¿ qú†jÍA~ªÕÿm¸GYTÀÀÁxS(èAXêºæe$ˆÍÆtéÛ>Wû´xµ ÜtÓM™Ó=‡sàÀÁš”¡ñ×c¤”LÁ„Ì÷÷–Ñ×!@$Ò/qEé*E%ZÎ U¾Æ8ãpwÀ›OιµõE›IžÈ÷$OmUÁB¡€n¸!×ð@¢—`®ç¸’‹"ò¨y@ˆ½;# @ó¡höt1àV_…þ‰:8ã‘@gmy Ç Çàp‡sp ÆyóšæVKŸ„±dø$·¿í œ”æòË/Çõ×_Ÿ¹j Ñ4׈ èúëë » Ô.±‰]ûÀ"@ ¶Þñ0œ pií2J…/€„ÄÚòÅCàŽÎæ>4þaoÀz·~b+I2äi)›0¯ÅK^ò\qÅ$zœuPàR¢ùºÌ„c„{v @`Oc>™f°Ã–|Øwÿ+¯D}¼ÞêB ¤À©Å“8á…Ãæ €ÈýÏÈøÛC’!ÏúÜ|m¾çœcÿþýxÉK^‚n¸û÷ïÏ5g=±ùè#„à\JÉ=/lý—J’…"Q  £lff ¼Ð0À=J¬¯Sh¶¾¨OÔ†CþeX8ˆsGÎauu€rH)±|~ÔÂ[ÝþŒƒófZëS ’ ¶ ýÿNö§>K›À¼V‡sŽááa áòË/Çòò2Μ9ƒååe,//£Ñh´ägKÇFÖ9z9ÇÉGßi>Ié·CÖµŽãäNKÿ>Ž=Š ?=á„?Êð7Ë €ð¼˜ë×û3!@@BÆŒ¾2â¡!wÀ™ƒ¯¼=Š“Ïœ“Ñâ¾O/â+Ó_Âò7D-h€¶Ñ±•ØÆø›]Yçèiéè×”Ëe”J¥–Ipt`οa–S5™NÞëÓÎIJÓ¬ ó>²ØŠ¹@Ž?Þ"t\wÝØ#‘ˆÄ0…¹¹çðä“-IìjA@]ĺñoíqÎÖ£ù9ƒãp\Ѹû‡çP(x±X >ž=õ}<Ä¿ Æ×½aÚ à?bÛI‹h7(ÐÖ`ŠÛȃ¤|ÒÊlËS$fæ¨ý½™®í|ó] $ÝWÒ=ØÊŸuÏí'!d³õ¦ÛÝõ_­®ÇA` úÛõ€$ö81=ºî™êÃgQ¿>g~på ˜l¶èבRâÜñ³ø"þg¬ÅÏÀv¯t&vYýý¶~ÿ­IiÚη½6 ¶z$º·N¿>M pÎ[ÒÊkàmõ˜%:McÏÉ€‚vQ%±hÆ~WC`ÿa!æºçŒ…îÿææ8‡ý+pyßU(UËš œ9pumß:}`{̈]@šIÝæ±4ñažcóØDŒíº,!–·)̺0AVºIeèäóddä®ô¼°Å_*©î05+ 4'ÚS šzñnÆyÑïð0€1Ž×¬¼ £3ÃѼh¶ò¥”8õìiüyã¿@6à ¢1 `7üúën‹[úIiéØ\öIi™åÉ+ÔÞô èi™×ëñ¦(HªŸNz;ׇÆÝcë}þE­ßm8àž‚±þÃW#š®Þ4ü\Þ7)gpcá%¨ª5B$$VWWðÝcßÁ=¯@  ˆžÂfÄÕqýµß –VV™’¼zYÍ|Ô{›ëß¶O¶tTyly›×µ»µ+ Ü0Ô=:Ù +‘] €=Nì‡ÎÖ *š? \÷pÎðŠÕ[093Î(?€òœ>z ºúŸ°*W¿ZO‹ z›qVÇÕ~+D@Öký}–7@¹àU~ê½^3Í´ômu¢ç›VNݸÛÒUâ Ó-/IÃþˆDˆŠÔoþq5·¿Ð}¨ãò Œ÷‡?ö( ‰†ßÀSGÇÿZû[ëP(‚èÒD€mx`^`keë¯mç$Åäõd‰ÛgIŸÛZó¶|æ=%å‘ÕòOªGÛùíxšqëïdúû½ €þ#mþ õÖ¿ãÀušÓü6GÜ´öÌ@¡ ¦Ö¼ÇÏà/ÿœ'Ÿ1€ z‹4ÃÙ©0Ó¶½¶¥c~žÕÊN:–eèÍü€ìQ¶kÓòL3êI¤ €n“bô÷Tç% bý¦‚•€10Í  âã(°Þê¿£ûGBQÐüÍH"ÀÓO~²ò‡B’¼Do“dX¥”‘!ë–h'. ©l¶ôô AuÌìPå·å­¿OZÙ3©Ü¶ò™­ù4£ŸÇ…l.þÄ6+ÍÙ÷$ˆˆ$/×F¨!ŒqÌûñÕW o¨/¼®™ŽKçñ¥“ÿßòïmñ z4ÞmO@R:6ƒœ&lÆUíÓ„@R·GšWÀVŽ´¥¾mi' ˜v6¢» ¤{î„ÝŽ-ôÃX8üï–Æ›±°ï n¼+@HãOÇ/ÿ[,Ë@›Á;±•ä1àf^ú¹6Cª_k3æy l’Pï“FBؼyòNQ°l0íf`àÞkñ› bؼш€h¹_å à(ŠÞÜŠá}úÜÍ¥‚kxäûàoÖþ"Š /Ñ«l¦°¬¤‰sÔ^ïz°•!­EmKšòháÏL+©ìY‚@å‘×ÕŸDÒ¹äØ8$ˆ›€3àp›^€pºàðÇx¹5nx1ªõ¾H¨€À3ÇOã¿û¯xÚ2Š ãOô*[!lÇÒfôKó$ ³3¯K:_f9ÒÄ€ùîd$@’Xhgt±1H-D?.¶þ€p¸£yœ(6@÷úµ·bnv<×oþ[ H)ðôãOáÿ^ú=4äZøàP:ƒ„уäyÕë4÷¸)(’ºÌ4Ó<I¯ÓÊ“%lù% [>Ý0à$º "†î`ŒEÃþX´0ÐúðÀp©àð‡Ø'êx-{+†&‡£ã@ °²¼Œo>ó üõÊ_€Ød‰5: mŒVß½‰9‘OšÇ@/‹™~;B ­µoФûH3ìY¿ó´–¿Í@t„Ý Í È‚\Ç™Öïÿ‚Æ ñ‘¡V¯EçGë;…??÷Ÿñ¤x, ¤X¢ÇÉ#’Œ¡ùþÿgïM£$É®û¾ß{‘[Ufí{õ¾Î ÖÁB‚ ’&n€tÄåX”i[¢(cÓG}üÉ%Ñ" ‹’ì#ûEJ†,Ä:œ¥gzzfº{zïêê®®=+÷̈÷ž?¼ˆÈȬÌêêefzyÿ>Õ¹E¼x™÷ÿîýß{o·ôðn¼úÆï~Ÿ½¼ݯ%ѯR÷~»YùßIõ?ç¸7pÀa’^ î =ëúBÄ‚@/ü‹Vü?Ûú%8B6“Eb XOÀÕ‹‹ü«ÊЇw$Àáþƽ ;³“ñ„[{¢qawD yŒäm÷±wSû?‰[Õüïuü~ÛÝŠ<8Ãïà€C_txÂ.qZ`¢6€‘‹ò¦ÀÏñef÷ÍØ×£nš:¯-¾Ê×êêB vC¢ûÉç{­Ü“ÆúV¾[yî–ôòôšÃnÿ½Šò$ß»1꽎åˆÀ[ Gz"¾€DE¢8P´úOô¡V ǃ'ùäÐ1:9jIAdç×—×ù³¯òºÒ ÜŠô»ß‹Ü o@?"m½‰@¿ö¼½nûms»)€·Â[ÑÈawpÀ¡/âwŸ´ÀÎÚáŠÁðãþÅS{Ÿb`0‡G /KÍâÅkü‹òÿƺ^µ?l pxp»$`7Õþv³¢ÝiŸîcv`›Ñï6âÝÇê7ÞN«ÿ[ynµê¿! óÜ;8àpKÄ?8Ùnœ l  ð´Ç/ø¿ÌüyRÒC C€¡é79wáMþeõ÷Q&è`÷Ž8ÜϸÐkÕÜk,èߌ§{ŸîL[…v{Œ~ÞŠ^ï¿ßyéeÔw2üwGî pØ^¬Ç¾£B`P@´Ï´šã§2_`l~OzÑÞa¨•˼°ðÞøjìpÆßáAÀN$ zz¯¼»k¯zýŒ[¿UþND ù¸_ßÛñB$çÑ}7ûífå¿Ï€#÷Ž8ì BØ¢ ^Ô)°S â^†úŸà™é28ú½Çîóµ8ãþöÁ‡[bÛ¥G( {DG•@càç[_汑ÍdÂC@€ÖškWø£â°,;=€Ã‹~Fºû~/CÝ=Æ­¼·K’Ûuï“üíD±Ñç÷2ê3&ƃägÚK$¸“qîõÜ­VÿÉ}z½¶!H£×8½¶OâNVðâ÷à­„#o úéÀŠS"нXh/:^¹ìðùÌ—øê¾ËÍ…@€0¶dp³UãÄù|屯oÿŒÈÑG’DÒu½Êyu–×*§8}ó5ί½IS5 ´2 eThð­á‡(ôÒ1ÞnŒ·{îÀ¾&,#=±^Ã’„P„…ò+ ¼°ôÂf ³>ÂÑÑc¼kìifS{—“ ÉáGê³…»'Ý^îmoGøw+BÐkì~Û=jŸãýGÞ2ô$&¼€CÊK…º€(3”fh4ï ÞÏÆÐ*_›ús6V×Á(tTvÀØ’ÁÏ_xޝû=þîÐ?¤ ‡`ŒaCo°¨®r5¸Äkë'9¿ú&7¶®‡_ŸÀ¨ÐݯIüÛ1ô}ç°Ã±1 uáaxHé>®W®q½²ÈsKß#ëe8>ú8OŒ¿‹÷L¼Ÿ}™L{³ ˆGË3p§DàV!ùün„Ý„ ×x»]Ýßîççâþ÷Ž8¼=è*?Ší&aº`è ÐF£Ð|¢õnLÝà¯kÏR©U1Zaˆ<Іj¥Êsž%},Åo~‹¼Ì?$`§ùF¯µt‹Uu“%sËþ%ÎO³°~•[שµj(TÇj_éÀÖR0ÚŽsŒþí¢û˜½ˆ¥¤ ªhŸ“«/óêÚIþTþ1OŒ¿‹Ï|„÷}˜ÙÔ“ÞTœrú( ØI,m¡Ÿð¯û;x'™Ñø½Ž»vã%x~ÏpxKÑ¡è) ¤ …"À„¢@£BÓa?ëÿ<û—yýâiZ­FèÂVè0P)—øÞ…oá…_€It^d[ºÅª^fI_gYßàRí"KÅë,•np£x_µÐá?¥VÜ)ú 6#ã0ü·B‡â )Ðè˜H!F˜€“«/qjíeÆs_åC3?ÄÌš#™ã̤æ:4;ú‰{¹ô“Ûw?Ÿ$½4;‚äXýÎûNa€$z ?ÝŠÿ­…#o9z‰%¶>€záó 2` RZ‘šÖ†ò|^ÿ Š{ÿ«W¯‚2(ã!…ekcØÚ*ñ ߯…¿s“€îùD¦ÁF°Êª^eݬ²¦WY¨^e­¼ÂJé&+åeê~=6îJ+ ÖKbŒ&Aäæ¿þ­ÐM "B`Ÿ×Ó&+õeþ¿+η®}OîùŸÞóxœ)9ýȽöK¢Ÿf _FA¿qî$ ßÞ8àð¶ [ЯR t’a " Ì{ù±ìçøó‰?aeuiZÐá6¶J[|÷ÂwG%¿^ø{äeá¾#BêºÆM½Ä²Zb]¯²ÜäFu‘ÍÚ&›• ŠõMŠÕMtèº×‘pÏèõ~/1߃høû!ùèGªA…¿XøO<{ãÛüè¾çgö~Ùã 2<:F¤—¿;<½Þ½ªÐBèçHnß-øë7®ÃýGÞ6ì( ”Ä)/Ê/0áÊÖ`ø`뇸4q‰Ô¾G­V­1a‘ K TÚ⻾…8*øÛ…¿{_€†©³\aQ-p]]ãRùêý‡Éè÷ÃNd@Aůð/ý{^Y{‰¿qüWyfè#̧ö¶…‡zy—¢ç{‘~ûö{=¹ÿ­VÿýÈÃýGÞVló[| H¤ÀŒ—²:ˆ€e4ÃsKߣØÚä<ùÛ<ž}WLàÑ54»!Ý÷“Ûö¯×ïi'Ï‚ÃýGÞì&3ÀÐH x¥F`ŒæGZ?ÆåÙóœ½tÆ6 ’c”­ c åJ‰çÞü.­ã5þÎÐo2—Ús×$@ÍÅà<¯¯ðJéW×/±°¼@#hl‹ã' ¾s㿵ˆH–@ …£8½þ¿æŸð[Oý6Ç3O ìk´5ôsÕï†$÷éuûiî8àðŽáV™^ìþ7)ƒ ˆ³Œ¬ÊñYùӬͬÚP€ ¬Á(´01PkTxñÍðþc~}äïq }ø¶I€1†u½Æ)ÿe^i¾À›+gYX¹J±VlÇîM¢•Žq7ˆÊ ÷ž3>Òh!1FñêÚËüá™Æo>ù?p8uÔ‘€ØIØ/½°)èÞ·×Ø÷pxG±Sf€‘¶WQû`©ÑZÚÜÿðÂ~88Î{‡žáÙâ·¨Õm%<[LVc ! m Ö¨râÜ ü#¿Ë¯ŒÿO¦ß}K]È.y>ø>/¬Ÿ««W¹¹¾D ‚mB¾Žt^ÿççÏråâe0% RKŒh;ß6$Ðl5yõü)þàÀ?åóS?ÇgrŸ³¡‡)e§ƒ×x®ù]N®žàÒÒ%Jµ-ŒÑí•~(>뙃lÊnx织Kv—Ç3Ûöß-Iˆš §„‡'¼N@›´w1ªx+r‘ c ÿáÒŸp¨p˜ÏMü,ƒ2ïHÀm ŸðVÛ¼UdÀ}^wGî$/Ä"! ŒÛK-52Ôc@k f„ëO³5ñ§lll µ¡±X""øA‹s—ÎðUþ ×\ãþƒäã JÓ48á¿È÷kßæôÊë,./PmÖˆ ïèе µŽç~7ư—o_Ü+­ûÄÛŹî‰çYÛ¶ßIF”¡Óåíèe€w{¢•¿‡GZfI0žž¤¦ª”ü-ÓLdH„i‘¢3U2ò°t“c ²—±Â ŒâÏ.•gÆ>Ê~q!ñ¿ìtÞv2öws¾¸ðÞÁ‡û½DÂØ†0‘/Šÿk´ôÆ`ŒD«€§[àÌø«”K¯`Z%BGÃÖh™Ðs°¸r¯ÕÿŒ›‡—ø|þ™óöð¢ÿß«~› 7.rs}‘VÐJ¬BÁæj+:ŒÄ†w`ü; ²ˆFŽ_‹IPâ¾H¼Z¾¸0K{‹öùLþ#A’ÇjÏxé+kluG_¨¡ ŸÇÒ¢;"HI‚WàóS¿ÀD0ƒ’-ѤdŠlêMJA‘’_¤lQöKTU…–iƒÙN Do“k•«ÔU5䇉ïœ#÷oÕ¹tŸÑ½ƒ#÷ zê´Í 0Ò†<©Ñaf€1¡&@JL?ÜøQ®M,°¼¼ Z¡… « $ØqâH½E±¼Å³§¿ÃÅ™óäsƒ,­-±¶¹J`T¨à'Žó[co‹ ˆP\`„Õ욘(/Ú*¬è1ì|G§;âÅ!Ü>7 !Èx22'ÓH!I‰4))‘x¤½4I:|ÍÑÏ=9"`š &4¾öñ•ošªACÕiªf§ñ× -¬Æö Ð(­ÚU E§§ —1¶ïM2ž™`BO3њƘvQ'# -ÙÄϵðe _(P£JYoQVeªA…jP¦ª«”U‰†jP×ujª–Nn“´L1›åSó?ÆEg›Dsrpx”à€Ã}…m$@té¼Tìš–Z‡¡‰–†½ÁÞUx/Å­ïÒl40Úºþ¥Q¤5Úáj>2°ÚÍ:¯]@`› E1g®(1„ieá¼L˜´(L¸}5t¯÷'x"EZ¦ÂCÒ.”’ór¤Sr©,ÙôY™%—Ê‘ñ2¤½Lhð³ 2HŽ2&CJ¥Àx¤E ©I kü=#‘&…<Š=Vg!BC­Ñ:œ›„…BK®È}Z4)™-¶ü-*A‰’¿E©U¢ì—P(­12jH’“ðÈ(5²­1H<é‘“„*Q¦Ð‚œ$Ç u¼Ø8Ž=×”Pè”BçJh”§@Zâ€M]'•NaÙŸaj`–|ªÀ¸œ`BO´KH#Òy=8àpß!) DØ•²!%Öø§d ãi´¶ši4Z >RÿoNaiñ:Z›`<„Ô#Â!eÂeL$°^kßÁزÂÂXà M¢½0¡¹ µM3°–f—·]µ{Â#ãe™+Ì228N!]` =È„œ O´Î’Qirz€”ÉQö±×JãiQ%Áâ!¶{"º]ÜÑùí7¿#Êü0Þî{-²Nk°Ac¨ICÖX׫l[l66Øô7Ùl®ÓÒ-ë¡‘n„v/ð„D"IÉTœ–y!¶'ˆ_ˆbʤ&ÐÂ’D_àIOJZ÷>ýΫ}^Û%PhE ì‡jC'%=¤ÖèÐáIŸçØãÔã¼88<¬pÀá¾DO=¡m ÊSHí!¥Æól ø÷7>Äkc'¹Z¹„F#¤]âkcÀH„°aÐ@”Ί=°ýWÚÒ L´ò×HJëØSînõôXM+@¬uέœáêúE&§™šaÿèfš{™mÍ‘÷‡¶‹¶<2x"ö;‡w‚dýk È5/E, ´oÚn˜ ÈéDK µæ 8FÓ«SËÔhäê4R5ÖõÅ`“Š*SókÆg(5Ìûò`¨1ŒðdBü­úCÒD›u«À“Ej’ï8†á­ÃvÊZc<ƒÖösµß³Ä8àpߢ#H!ìÊ< heK‡vc4Jj‚AÞgža­°L¥RA@[—¾±ñ7¡f]´ÿ³Ò€¤…ÇHv„j«JSµð„A‡¢B­µ%$2t¬ ·qpD”†Ø™“®…ÆW-´Ô(°X¾ÆRåoÈטÊÏ03<Çžü>æõ&ZSŒ©I„¶ú„H ×q~Ønì·§í^X÷3¶`âÎzQ]cˆ‰ADRŒ¬  XISpH#ðš©:m«5È ­a<éÅÆ?In›Ob.q `·¸0Ü_ˆPÊ8:öcû~ÝÇspxà€Ã}ަAÉP@$Ô¥uèPh-xºù~NN¼H­Z®@i=‘zl*ahx¢#²m@GFFx|ò)õµ5Ê•-Jµ2Í …»ê•͈ÒáBÏÍ]öùÈð$ÜúÆ(žð„$Ð>×K׸Y¾ÁëòUÆ&˜še¶°‡}b?“þ4Á4i•¶nò°û!ƒvؤ Ø-¶“ 2‘ÑC¡!.¨”0ÌqJ¤$c²dU.ŒùK<í!¥Ý f[# sFÛ @[Çѱî3 ¤”Hé…„`goI4®sý;àˆÕü2µj £FèÐàÛ¡¬­òâìÌ‡ÇÆ“¯­,b€ú2GY™\bÙ»ÁUu™ò¥j‰r}+.¤F„Â7!¬€ÐèÐFF3^’ZAœ Ù Óü¤ððŒÏÍÊ V*7yC¾ÆPf˜ÙáY¦ósÎeFÏ2L3d†ã¶6:ΘкӘÝʰuäí‡nÿ^ K†¹C³fDXW»Ù6N4!ìg&Cƒïy^øØ ø"@·>Al›K{>Û¿7Ä$ÀóR¤ÂcDž[U¬spxà€Ã}~Yqà O£M ¥5)ÏC+…–’wµÞÏ«/s¥v)ð ´‘Qâ>í<6à" Ø•¥Fqmùßñ¿Á‡Gê|¤òqÓï¢aê¬f–X™\æšw…•Æ ›åu¶êEëÞ764 ÁÈÀêСÈ]o3¸`P€FƒQq)<<-Ùh¬Sllr^žã•Ô‹Lf˜-ÌshèófÓz–q3z2ÚçîòØV¼'Iº ®­‚Ø6ÆÖèÛ=cX¡·Cv^IƒèöcÛºW ÙâŽ^nýhµ/…ÇõðR!ш=‰âIÎö;<‚pÀáAGV@¤à:¼À[㯔‡çY2ÕYÞç?Ãrá&•rź©¥@Ó^ùcÅ…:tÝÛ¬m×›1éЬl.óó=üQŸl}‚”N1[ßË´žç)ÞK1½ÁÊðË“7¹,R¬n²YY§êW1ÚÖ)ð"š°Esb“¶K2 „ÄS_ûT6+,l^ádê3…æ†ö°x?û¼ÃLë9¦™&EºóÜ%Üö·ªëžŒ³÷2¸Q!¦6è$Z·{%t¯Ð£•¿”ži?·È3 DÛmŸœÛ6È’è]l($! ˆˆ†!;E‡px Ì ˆÜÁ6àÅ‚@í¥Hy¶J'%ZJžl¾—“£'¸R½X!‡g‹úÐ051…’•µU @ a½±ªß’µÍUþZ}úDmýY•³óÒ†QœÑÖÇÌ“4S V37Y›]溷Èzm…bu“j%´R¶¯±:,¦Û+öÞIV3 „$%<üÀçJ±ÆâÖ5^/2‘Ÿb~x/{†÷pdà3Ì1#æ)˜¡8,‘èqò˜ÛŽßMBƒ­ò㸽66#éHŽßódèþÝó^ )%)/»î{™åNb¶ÿ^^€Hè…â@OzHOÆub.zK\(ÀáQ#bŸ‰Êã†+[á“ÕÏ2ä „@)«üRUì«boí OËg(¦7X]áæÔ –š×Y«¬±QY¥¥[m@\s?*£ Iï@;¥­­ð‘„+i$žLq£¼ÈJå&§–^¦fïÈ^ö íãððQöxû˜f† 1– f©ÚFBâµ=öÞÖD†>*½yìãNoBdt“^€ˆDE|„” 1`;ŒÑ­IÏQ_/-]$À®ü"A!c£ï<px`°“ Ю¨uìæÕÚC©Ð ¼‡WGOp©z¥ F +›3„¡Ñò)5K|Òÿ,Ïïy–Ë7/Óðay\mE|¡q7FSoÖ8uãUZ{Z|²öY&[3H);cß‘ÝH&ZÓŒ5'y\¾›Jj‹•áe–§np½µÀjy…ÕÊ*-¿ú:É€2ªÓøÅÏêŒ0(­ i|Ö3 …G«Þ¢Ô(òæêžßfnhž½#û94v„CÙÃL1ì7O†áàÖ¨'jD·ÝÇ'h»û»Ã„!ù9F1ø8>ïÉø~‡QîQ¼(ºmýv„m0´WùBt güu8àð@¡[(ŒU{k6vñ J+dB ÖiÞ×|†¥üuª•ZX>ŒócÓôV·VØ*lð¥ÏóÝ™opný4•FÕæß 2‘0PÓ œ^xƒ`O“§?ËþÆ¡¸Â\¼Z ¢-{ †B0Ìpm”cõÇi¦ëÜZbmr™…ÖeVÊˬ”–©5Œ´5”Ðh£â0AÔX'éúŽÉ€Õà£L7Úñ„´áq¥x‰k¥«<í9&'Ø?r€½£x¬ð³b޹Ô^òì¸=\ëm>1)éð Ĩ€Îí"ƒn]üÏóÚ¢@!‘žŒ_ëçŠï®HÎyÛw&.,”èœ~ôÝBIçþwx”à€Ã‰øB-‰kÁ›0õ-é°ŠÇ‚wqbäy®V/aŒÄˆÐe²z½Æé±×8R}œÏlýù‰!Þ(¤XÚ£ÑÂÃCÙj‚ ŒÁ˜&goœ£9ãóC…OñTýi0XŸ±Õç¤4„ š»‚\ç°:ÎÑÖã¼Ïû0«ÃK¬L-s¥u‰ë[×X./Ñ ¬g@é€À(KD'è6ÖQJ ‚À$¾m:æÝ§DŠ¥r“ÕÚ 'o¾ÂwÒß`ÿèŒⱑ'™óö0çíaØŒèS´ÍØÆ#m€Ü"ˆ¼ó‹Vö‘' Rä']ÿØVϨ#}£=‡.¯Å¶ïЉ¾3Ñþ‰•¿3þ(pxà°½B l§†^­5^â/£3¼7ø 7—ÐÕº-ë+#ãd]ÁK×ycä$Ï”>Æ'·>ÃÐP—S/°²¹ Z£‘¶t¬¶¡péæ%Z“-š…j| O‡½:bá :"nó IDATúè}D+éœÎqÀ?¡àïM=Ãñg¸\¾ÈÕâe6ªë¤ŒFa‰€ÒmR•åM Û;J~\kÀ¶n ¶ZEN¯¾Á·å7Ø?²ŸCãG8:zœ}éCÌÈYÆÅd¬èŽÇwÜ&]þ]Þ‚ŽÏ0aà£{åO‡‘îúðÛïÓlÏfèkÄc#•“î,”䌿ãGX$Ó£˜n·@)«þVRòDëi^}ž…Ú¢U©ë–2þšÍ&§Í«M?θšä™Ê3œå¹éïp}åº5ºhL(Œ›‹k×øNë›4¦j|¢ùYr:V(T 1\w~|‘ÑÔF“ñ3RÇ9Ô8ÎÓ™÷³¸÷*g›§¹´qžåòM_(‚¶ÑíáïO”ͤ-¤ðHÏ’Ñàôz™77Þ$íý{†öqhô0OL<ÅÁìafÄ<ãr‚8j.ÚÕÿ’aè˜É9lûüb¾è¹¿U\¾WC8pòlÛ>¹3ü2¼wzïDâ¶ãox¡T^j­¥ÖZ¦ÓF“’žg<­'¥ôŒ1ž1Ò“ÒxŸûÜOÿ-!D_"õä“O¶ûÙ;Ü3ÄîØ•ïi»Üu2Fml {%5WõT ây( DfÆ%‡›ÇB2Ì2™™¦:R¤\+·=aÇ:aYaA­Ye¹q“ÆXƒÞarr ®D¥¡E.n)¼Ðåpw‡0ÆØ 95ÈŒ?ÏAq˜ÙÑyò#yªÍ*¾juì×ÛÄöFGØK:” ,±0ö ðµÏfc“«[—yyù¯ožâjp‰Rf -)r"‡ev#·¾Uû˘œmû‹Vþ¢í =ÎGIè! Üözò_}vSØáÁÀÙ³gcM/üàßÿ¿‹ÅbÝ£¤Ê©¤ÔZk©¤TÚó„ö}i<ÏÓžW3å2Q>îíü¤X8àÀdœ8tAˆ€2šQœKÃçÙ*•ì.¤Ý%vÇCÝ«0™f\O"¥d\M0'÷S+R®•PɼR„2Bë…hú-VkK”G¶ØŸ>@AÛø»¯]ŸÞ“m#i+ßÉmD Ræ§u†©`–}db|™l5Š 7x¿uöÎH’m¬ÔP…2Š@(ãE }JÍ-¶®ðòÒKœ+aQ/PI•d@VfÉŠ\G¦FÏ?hàIh’†?:;é¾ãïâÏáá#wGx`±“"%zû )"ðÔ%¥¢mùœÀoú4&jž$c2H!)èap˜êx™R³HöKÛX ?X)-³1´ÆtfŽIo* O´ÔDÞ€vçºp%,Û_MËg’±u›Ñ0çïa6;Gv,ÃVs _ù½wÓÿb¸$É@”’¨L’‚¶‡`³±Á…õs¼´ü"ç+g¹¡®ÓL51—RáO¢Û˜÷Z­ÛŒ…Ý~‡$¸;8àÀž^Óà €mT3ŒsaèMJ•­pµ ¶ ¬5+dF3ìc}Ó†A‘ç°:Fk¬É¦¿IËoÙý´ CmÑ›2š•Ò2«ƒËäÙçíÇaÅ;!mIÚ°NìÉ€u™Gï©ýÞ’:‚bÞìch|ˆª*Sñ«a»ä;õlGùˆë(Ê ±bĵÚ*o®ŸåÄÊ \m\bM® Óaƒ"Dv(ñ»]ôÉÏÑ~‡Û#wGx ¯‰ªÙõöDñ~Œ!E ?pÕ¿„ ‚°qiÇ¢¥4åÌûÓa46X²ŽÁ¨¡$¶¨7j DØíO‹ÌÃ>ë[«ÜÐ×ÑÍï™ ½]Þ€D{ë h{ˆÞ¡º”N1Óš'?R •jR¬o†­ŒÀpwž€nt’Ó&&@¡Ð(ZªÅÊu^]9ÉÉõ—¸ÒºL%UÏ0 I“Ù1~ïàp»pàîà€#vðÕ§·¦lLq~ð ¥J ÐÎxlV@c´Îê)ëÒÇO‘â >J¦f+]¤Ú¨"Œh‡D(&ë Têe–ê‹ÔGkL"/ áÊ¿­ˆA;45źˆÄEv@0Õš!_Ȥ[lÔÖãsaСgãÞ^Ëú“ßÖü* ¥+¼´üçJgY—«Ñxxäe¡í p†ßá.àÀÝÁGxÜÊ ™¬vnº!e2øéW[W‚ ªUc=2ú:ÊÁ¹áö©ƒ¡{?:–dŸ>Èèà¥Á"¥j)Q¤&«-. á×¹^Zd³°Æ\vcr!Dhü½.àů‰¨v},$~¯ñqŒa¼5I~pS¬7Ö:^ㆺÑ7L kõUÞX{k/q#X¤•m ¥dPäÃVN.ÏáÎàÀÝÁG.ôðh &,Ì£c=€f$ã|þ,åÒVÔ˜PÒo•é@à+Š™"û³1c†`ZÏ1•ša«°N©^n‹ðâÐ}Û!ï-n–®³’[fd`˜y¹·#à%4‘hP$nÛ"Áöm¤q÷ÇÉPYÅFc-$5¦ü{Œn2`³ Â2ÆFQj\.^äù¥p¹~Rj /b€2"cO›#·GîŽ8ðPàÖZ€vËÚÈHgL–f¶Æ•Fè°†+w[!Ph6T†K<λH‘ÚV€fÌL°Gî§2R¤Xß²exMìwÀD!ZVŠ+ÜÐ È‚ä€wˆ”L‡uð½ØðÛù²S/ DLÀ CÍ¡0Ú#Ÿ-À f½Ööh£ß¡»Î€6ížöY®Ýäå›/òÆæ)¶d‘t.EVdɉÀ‡ÝÁ€»ƒ#Ž<|è¶‘ òDF1ŒñæÀiÊå-Ú¿ù¨²¥Ců’õ8¢c´N¤ëY"0Ä0Åaj£ŠõM”ÈØ ‚°M…BïC±¶Åbcr¡ÄžÔÞP ãÖÆQ}€Øèwv²kg Øãhc ÆÈg†yÍZÝ’€(¥ð­ ôC/½@ÜåC±YäµSœ\?AQlÊ¥H“f€Áx GúÁ€»ƒ#Ž<4¸-/€Ž¼9êÙ «Ö *ùBïyhÂJ)JÞ&S¹Y¦ÌŒ=N È1Èaq”`´Åzcƒ@µl(ÁDÕI˜C¨7«,¯°š[¦)0#ç¬ñÅž°Ú!žèÌ€¨v~øŽzc`$¡à †ÕÚjÈAÚtä@‡W۵ф}+~‰3oðâÊ_S4ëdóYÄ ¹°Uq¯ºÿŽÜpàá„èºßà  ÃpÀ°ã\î åJÉ©(vÞ•‡ß¨×)æ79–~,l›Ûy0Æ6éc0¢(êM­FB¤Å†lVB ׋‹,©køŸ}Þ~2"{¢šB¶Å€öµP @D|Šú0â0 1â’öX«¯vH"ßnO@Ý^¨¡ÆP÷k¼¹y–«/Pó*äÈËY‘œ7À¡ŽÜpà¡BÏê€ x¢º&nΓ3Ts%kW ?6P" $šÍTë%ªÃ5ž”O!§üÅ™aσæ(™¡[©"õz8}6°+rKJ6ë›\)]¢8°ÁLv–Qo,‘#ßÙ"×}ûŠÛçvÆp>yU`TŒ“ɰ^_‹Ë›ûä×­ˆnëA××_ãåµ(Ëù\!1´­Â Ã£ GîŽ8ðPBtÄÆ±Q·Óãº!)R#¼™³u"1 ¢½n**­)[¤FRáxûXÑ1"âaój?…Á¥t‘J½DT(Àn¢W ~ƒÅ–¼EÒ¹³bž”Hµ‰@T.X´ì´ A¢¡"LY´• ó:ϸ™``l€Æ:ñ#Y±ÞáFwx úlª~™××Oñfé 2…4ƒ©ÃrˆhÒŽ<Úpàîà€#úy¬n{´Ö6#ÀÀ‚¼Ê™æ©¸ã_{…l«üÙ(‚½õ}Ÿ-Ydbp’æHXÓ˜D3zžñÜ8¥Á2¥úÚXñ¡íyÀrPFqsë&Wë—Ù\gÔgTŒ%Vùb»7 Ô˜¸¸Nøö$ £³L©iF)ù[´t“v¡w2 Љn"}Vu^XþjB¾@A ‘“VàHÀ£ GîŽ8ðÐ¢Û Å÷µikŒ1lŠMþ_ñ'\¹q ¥5a_8‰â;ѸP«×ÙÈ­²?{QÆí6"ª‰Ã4A5Étfš¥ôuJµ­ö\°†?Ú¯¢h¨4+\Þ¸Ì"WiåšLÈIÄ`‡7 Iˆ ¿è˜«1 ¤M?ôLŠ)†‘‘Q|Ù¤Ü,!¤—˜Ïý#´ëE”Ñ\.^àÄÚ ˜, 熑£qm†ûeîo¸;8àÀC‰n/@tÛK‰þµÔŸòÊâ š-ÛÍΆÂÒ@¢³7k R+³ž_åhÆŠ£ÚCÛH€1 éQr—¸¹µ„ÝÅyÚ„ÃÓ@¬”—¹P<Çbj‘1Œ‰ ²"N‚8# ÒD⊅BÄi$ã­IFFȲl66‰ ’¾Ü/Æ´C0Ö2¨5^Y~‘‹Õ L O2"GÉ:oÀ# GîŽ8ðP#òt;¹¶™?Ïòí•¿¤¸µcñ‘€0åðEãEé…¶jEJÃ[O=N–ŽUxÇ5Ä@)Säjõ2J-i¨#aÀ’,yhM‹×¸P:Ï¢·€Ÿn1(òäE!vùGÆž€H@ø|8#)#Á£rœüè 5U¥¥}¤ðÂּнªî®€øN U„äi¥¾ÌË«/Ì2’aXŽÆÛ:"ðhÀ€»C_Ãåàð #îžÆÆ­Þ­7ß`o5þ’åõe[ F„ŽjvÖ© sQ(<  2 À©Å“ îä ©_"dã5+Ña˜ôg(äò4«M )-1Ș3(tH:,E0F£¤F*Éry‰Õê o ¼Ê¡É#<>ú$GÒq@b0 tø: ¸@`…ŒÆ(Æ›“| ø“c3œx• [ç¨5|™!Ð>ñ šþ‘B? kØc¼}×ÈøXF£…@ƒ‡a¥¾Â¾öÏxsïüÂÁ¿É±ôãdeÎÕ ppØpxèdëY)$ßÉ•ë—ñ•oEyZ‡.xû§1!1¤0€#Ð",õkÂ(ê­'n¼@a_ŸL”Ÿ²+ùÈX¦¬ÑR3FجÒ³†çÉH "°º­cOÆÌ1F“&ÃFmƒòb‰³Kg˜šfïÈ~žy’}â{¼ƒdDº]I0¶Sa2|¡*ôdMŽ£•ÇÏNpdî8ªç¸\ºH%(£L@þ)…:$¡äm& møúµ¿àjù ¿úäÃûsÏ0,Gâ¹9"ààÐŽ8<ˆ½öõ9^\ÿÕZmaœc×ã‰ÎQ@ô¿A# µ"4”ª%¾ãYç |:ýa]ƒ6ž ëfæX”‹xJCØ®×!Háh%%Ê(„±óÖ2:¶b05‚m¶cX)-³\ºÉkK'™)̲oôåŸb·‡)1‹ mßr’_ ðC£ 4H Í)Æ›“ìIïç©™w³ ®°X¹ÆRí:-Õ$ E€Ò Š»þé8io;!€·ŽÄ›F!æìæþ×—þgþÛ§ÿ>?<ü©8{ÂyzÇGmcôŠ~‘Å•E­0¬%´ke$¶ÐžÁh»’ŽVÖÍnãÿ„÷Ã6Bl”×ùþÚw˜˜šâ½ÞIt`Õý@2§÷KŸ¢¦Œ žð˜*LŠ­fÑÇhTœâ%ì5Tƒîÿ(¾¸Q¼ÎVs ?X(.°°¹À+™Ì Ïspä‡3Ç™ó ‹Ñ¸¨”’ œ>J ÛµOiFüq†›cìKb3¿ÎÆð*‹­EVKܬ-Q×5”Ñ( ŽÛþjÂB>!áIÆë#2ÔÿS¹3’¬Ú¨…£Øh®ó{¯üͧ›|fô'm–€#=á€Ã#k€Â8¾ñ9U{™j­‚6¡Ãt<#¬óßÐaõ>£ãœyŒÄ6v)ìŒ\_[䛹ÿÌÔÐ4{Rû!¼¨ÊbZÏ0˜-ÐhÕÑÆCDÒ Þ=ÿ4×γZ^#0JX†À6 L‹—OðÁå‡?ÍVc“‹¸Q\$0Õf• kç¹°rŽÑÁ˜Ù˱¡ãÈaVÌ‘Y¤H ”@ª‰ÆHÈY¦ýy¦Í‡¼ãT¶Ø*±¤o°ÞZf¥¾Âzs…–n…ÙA˜Y¡QÚ6ú‰HØ÷‘€¶²ß"é9Ø-è•úÑŽJPá_¿ñ/˜}ÿÉÏxŽ88ô€#=bãb¬¡YÒ7Ø(oØb@hŒ6 hAÔßÇ [‹°5p¤þ—„Æ?¼o@c j`àÒÒþjàk|)ýkdMmÏÒ5‚Àíc¤ç«P¦ÎKמCÍ?ÃŒ†å?ƹ¹Óœ^}…ÍËTý(6ŠlÖ79·|šÙáyáhî1fýyL)=OB”Öq$¥HÈê¹ÆÌpÃTRejÃ*^™U½Ì†¿ÁFcMƒ’_DI»¿Ó£Û¨Ö@ÒC Ãî€:Ìö§£TñvD^˜d½ƒösíûÅV‘çWÀÓï£ ‡c!¨#m8àðТó'Žï e]¦á7BaIT ]í¡ PË(‰N„©g&Z š@¢Œ@¢ÆCycš ^_<Åw|Ÿð>§5Æxha(ˆ!æÒ{¹Æ5dH"Cx­²ÀÓòƒ|,Ÿã¥Ôs\ݼ‚ÐV½¨D»1M´×_Àš|fú'ù\ú ¼wöœŸ<Çéò)®l\f½²fãä(®m-pmk×r'Ù?|cCÇ™Ó{oL‘•Ydà¡•ÂW>ÚÈP‚(™P2ì2ì¢Ñ–Q—5ê5ê…:ÍTÕ`…­`‹ª_¦ª*Ô‚:UUÁ×-”ñiêV<žÆŠ µ uX]Aôy%a»MS”¡n¢C܈`À âÈèq>0ñar Äßgü:á€ÃC(0òTt™–ß é@hlB¥¿a¤5ö«µñ‰âñ!K@ ãâ=JGnmM©^âÅõç9<ýG½ÇZÛN~f™'›Ê¡‚©¢2Cšê×Çxªúrƒä¦þ ç×ÎÑR¶``” @ØtABCzòæËÔ‚&õ™:ï÷>Ì\zO¾Ÿ+£y£rŠóç¹YºF€­rXl)6_áÌÚiö Ïshø(¼CLµæô-0Š@hmÐR£•ŠøÑ?aA>(0äãöQñ Y§åµðÓ-Ï'Z(›V(|ªºFÕTØh®³ÔºÁbm¦j „D™À¾¿0õ°íî—xBÚzöårlè1Ž0‘d"7EFfÈyY†Å©I„‘m¬¾#*½ìˆ€ƒà€ÃCŽ8Þ£5uSC¡8Ï`+ÌIÐÈ05O#±Æ n#˜¸b”¶ëŸ 3¤Ö{í4,®-ðìÈ7Ù›ÚOFfÑÒ’€i=Ç@vj«JTcH¨«—ôyŽ›§ØÓØG.ýrS9N¯U³ÞmUï`û @hÃÙÕ×iªõùcDŽò>À…ws%‰‹ÁYN¯½ÁÂÖjAc¾iqyóWŠ—ËMppô‡óG™ ö0ÞšÀS)´V¨@¡=­måD[x¥;n/bO‹6†œ gìs~ûü'0@UVhäk¬ -sªò oTNh €Ž2FžðÂc:3˧§>˃ïfBL0,GÉ&£2x¤HË4žðH™Zk„':«;;ãïà¸J€®àCŠŽütu—Ó(­ÙPk¼Xù[•­(òÜñ\EXD^ÿD(ÛºÎâx&6€ö˜vƒJ³Âðè8v#4dt†óé³lÔÖ㮄Q: šÙô<AžA•g–=˜1ÃV³H ƒD8îæM;‡R£ÄÍú dæÅ^$ɘçHê1ä±wl/étšzP§Ô-qÁPóë,Uop¡tŽU±L}°ŠÌHò"OÆË!‘xžD {ëI)=ëÕ‚TÊ ·ñðÂþB¶ë.غ^<×è|fÈ0ä™ ¦™ØËàÀ‹õ…˜TD5¤ðð„ÇþÜ!¾8÷%žæ}Œªq2&“Ј¸'ƒÖkÏÄ\zL¸J€wçpx¨¥ïé0–­µ¦ÀÙL¶½M´š ]ØaSôL@„â4[PB, Ä´ÁÞe‡B!)V7y±üçßŨGhÈ™û3û¸Äy" œ2 ´¤Ô,q-•YÚòþ­~œüTžW6^b³¾†çy´´u•›0 Ï·n ®—oðWÿõ} >™ú y‘·³3‚y±‡99Ïã#Oqiä"§+§8·ñ&+•›¶à†¦ªsnó çÖO3[˜ãðè1c2˜a$%åÙUµ{hm+(j4%±E9]¢.j´L“¦i’#KʤH™ j€ŒŸePâ°‹­ïo½+“­)ÞŸþLÀ³ëßD˜VØÉë}¹ý|nòólE - B¡µDÏÎOÚ¹Ia?K#ìçêààІ#-ºÕÿÖ=­6#d³DkA“ØÞ&þ/£¥<aH@›¶ËHA»f€±ú)4 ÀHW—/râðs|FüŒ¯IÁ´šc0“g«á‡ÜÂR–jq]_å=òdTm •å}å‘ËqÒ{‰å À” õFáÒ°V[åWþ‚æ?’þQF£-c0ŒÈ1Þk>ȱÂã\É_ä|ë §W_çze£¬›×Ë×Y¬\ãåô ì:ÀÁÂæÒ(¨9 -ZTE™E³ÈBå ׋ l´Öh¨ftR‘Òc$=Âpj”ÉÜ{ö2#ç †öG‘Ê=ó'y&õQF¦G8Q~žÅú5r"ÇSÃOóÌà1ß܇D‚g?Kfccb’g¼„V!!&t•:á€ÃË.õÔ\§`†9P8ÄYñº­¶—¨h⥩aW§Ö»oФ6$`IÜ9@Y÷³¹Œ­¶Wi–y­t’÷>˜CÉŒ˜c([`«±eE}FƒPH#Y«¬r³°ÈÁÆÑظyx¼»ú>rùAN¦_àÊæe„(OÐÒ>Ê ?¬iPlùö•¿¢µ·Æ'²ŸeŠiû>u»ó߀äIñ4ÇróÔü{8¯Þäôš &@‡E}¶[lµNñÆÚ)²^–ñì$ùl´LQ÷k¬××Yo¬¢´B‘èQ+ õ ÆŠXæbå…ÿŸ½7 ’ëºÒõ¾µ÷9™•5Ï…Â $A€gRœDªÕl©o_É·;ܺqþ¶ÃûÑo¿xxp„_ì;ÚC¸o‡»ïuwß¡»¯$ŠI‰”8ˆ“‰$H‚˜ˆ…BÍY•yÎÞË{Ÿ“Y°)àü•••Ã2sý{­ý+dGßNöôßÂ6³‹‘l”Þ¼õÊá.`ÇÐn–G–©Sc b°5\–€²üPžî ú‚«¿!*`… *PáúƆ,€RÃ;¹‰þþ!æg‹jóº¶3yõZ¦‘E}´–˜þ÷ N¿áy:1|øã±œ¾t†·Þäa¾†ˆ0î§íãÌü™à3 ÒùE`ä»[·D#/ܲzý=ýÔÇ_äƒËGh9#d>ÇêƒSš±œ-ñü‰çYÛÚæñ¾'ج[þù®©HÊn¹…éMÜ6};oâÍ‹opbñ΃³žÌç¿¶o±”-¢Ë!£âÄ£®ã ˜iNI¹ºq !`æü,‹ùkƒø0±IÚk" 0qR$atA: *T]UÀõŽØÿ_w8—ÓŸ p¢÷§.ÄÇš÷Ç>I÷;Ê|ÀG=>¦Ûm :[ú·1á'Q…¦ir¼õ>Íö ¾pÊ3Áä&Ï3Ƈ&Ùê·!¦Ëù.D4z}?›e 2sí˱„ e@/D}EVãâÊy–í"ý=ŒêøúáHtêä“ vÕö°yh+==u.µfÈòŒPhðqJ`˜RX”¢Ó¢$]Ǥ»$P\VÁ®ôl»§›rdå0Y£M_o/ý R“kl öNTa IDAT–4IIlJš$$IømmBb-Iîkb7‚±&‚õ屬ð[ª ೡ"¸¾Q€®.€@ªÊ1„¥æâº6ÀĺÀ&å#$*ðc7|4*þ#†vž116ÉÍ~oIÞ×wXX1áDƒíoÒk¸Ùì#¥ÚÚbð/âvMëLëVÒAË|6Gæ² Š“¨Ðïú.S…KÍK,2Oo£—q¦BF¡«PŠ%ãŽ%$LèÛzv0:<Êåöe–³å®¿§01*=”‹##¯¹¿‚ tˆ–_ãØÊQNµ?¤1ÐC_2À€$± ‰MIlI@‡$IÿŸ”­ˆÆ˜ò·)ÉXi\€ßzTೡŠLnXìÍ÷³cbÖ$Ö¯¯†uvÁÚe#ì5Ú×¾÷1@j1,7¤ÈÛy‹+GiÊ #n”ñ¾©ŽR]ƒ¹OWÕgÏòaíhpiSÝ–ÄÚÒ« îêÜÓz‡Æe²w’ÔÖ¨™:‰I1ˆD®9™¶É|‹wgßá©™ïñ ^ “MgŸK5}IòêÒ²óííÄŽÔlÄ$PXñÆ`ZðMi׋||º}]ð“öfäšóáÊqþå‡Î›ßåLãCL*Ôkuji4I©¥uÒ4%MkÔ’iq|L².ø‡,MGG6­ þ*T Â õB²pIµÆƒþQ¶Mn[oóq$ öòwÙ_$²ãí±>®qØÓ`¥;לeÆœÆ?Ʋ#ÝI-IKiWðš““³°:ϼ¤kŠw‚1a…[ä Ÿpçê½<4òU6÷o¡njÔLTR¬^ƒ{`[Ûd¾Íñùãüèü“¼*/ãltìÊZ”=êñÞ¡Îcœá ¿‹‡'¥fRIH$Öå»’hadRq,;Çþ×á "à32Íhû?»øcþâôÿÃ[öMÚi›z­‡z­F­Ö üE6 ±!íßü¥œðô©ß>*\—¨@…ëºnÕ'1\ˆÁöµïàö±;è­÷ÅÀÿ›­ ƒØ-N³§ÐÄÄxtôEù!’¥Ös2_l£Ùƒár[‰ãtÏÉ}Æ©…œµ§ÊúvQû¶6)•ïD¡k÷ðÈÀcìÜIÝÖ©™:©ÔHlø˜{ïãêºÅéÅSüðô÷xYÊš¬–LJâ”ÙÅEE¼a2ÝÌ@Ò²&‚,D}ÆiöŽêß”dÀ|,±êœ­âxyœú@|α¥#üÙÑ?åçùOYJIcàO“´ üA`¸^ÔýÃ>U«ÿ 6¢"®olþ1ôÇrƒÁòàêãìÞr¶Heÿš,@ÎJ¹«$€–¥¢">hrœËYm­²$ eKâ„›d°1‚`BáQC¢‹Óñ.,ÍpÌ-kßI r;Þ2 yåÖöí<Ü÷;칕ºí!µu’`žc ÷9m—“i‹™æž:ñ=^rϱjš¥XŽ®Y´M:çðΑºýõa ©vÁ`ÔFKÄò‰mx¥@:Gó7 ¾Júœ¹ö<þþÿųKOrÙÎÄ㬠ü¦«E°ÈlTÁ¿B…«£"®_Ä”oУb¯t&zÅOùM<<Âæñ­qÌì¯/¬{™.[wÝßûâöŽQ;oÑ–VùØ!f²wD1{ Ô•Y€–_ãÈòÛ,¤—KÕ{!vKlZ¶¿•A§ìjÝÄ#é׸mt=¦‡ºí¡fÒàd(‚ÓœLsÚnùµË<}ú)žËŸfÑ,¬#ÝÆ:ªžÜ;FüÛ¶a‹•‹ÅØÐÛoâ6˜’fu—âj\ ‚ÆO P C‚sŸ±êVùWGþœgçžb–™uéþ✮ üUð¯Pá#Q€ ×-Ê/|%£‘ŽYŒ‘h(þ¾wíAÁ¾á?1 l#”<ê‹U¬vH€@æ2ZÚ.gIJÕn§a{‚q àb!×58»p–cöhhm³v]û[Y÷6a›‹ýÝ’mãû7ÝJ¦Fjjq…2 Ž6-[ ®Ø•ØGðj.ºHÀR¶È¿8ü§¼×z§ôøÈ÷@… ®@E*\ß(tEJßH ü…Kœjö ˜Î·ðDöìÛ¶ŸÔ¦zö'%ZXw©ÐÐß`Ø–· ú!&êñ5´L·;Nsœæ\X¼Àaÿ6^] -…#^á„gcדï<;³ÝÜ;ð¦S¤’’š”î§ æ±å®¥k¼rö%~8ÿ}>´ÇIlR–ŠÚ½ª²3ÛÃýãÓgûB‰[dTŠ ô˜H¤ŒtD±$ ÆÄ¦Œßl¥Þ!!Ërzå4Oý.3îbùÿ *üf¨@…ë°F@(Øè%_(ë‹‹Ãöl¿ã¿É¾û©%=±; «¶ü KVDaÓÀ&¦ÝZwÚà‚ ðÔü‡¼§‡£’¾3 '1WŠ­ rÊ „öå¹ex/©µ!XKëö!¸{GNîÛ´óoœÍ~Ÿ÷å0bL´Û D"€ä ÞÃã÷ÑSøØ 44ñ9ƒô¢#ª„Žg@qÅ:žüÆžÄ2˪[åç3/2ç.—Š*øW¨ðëQ€ ×=:îq†|WËX‘H“(¬3I9]n[¶‹ß_þCØù ƒ±$ˆ@©+ØðSdIHMB-I¹móíÜѾgC[Z¸>ìGl •«åRFÛ欴š¼5÷&3r!<Të[[hºE]å€{ó>öÚÛë™$‘`\3uê±$`$Ü/Ç‘Jo]ú%OÍ|÷íÛXkÊž{c, ŒåãÜÍýÜ1|5S£nz¨™‹A4†2#ýÂT@³ÎF˜Oj#Ü5ïàÐÌë\v³±m°3ˆ¨"*|4ªqÀ®k”SïŠ,@\=«U¬ZÔ{’$Å«b½#I’¸*fÄóùo3=¾…7‡^çÄ…£¬e-Lר[•õ•gÑb•CjjÜzÈï0à‡P£¥²Þƒ* 3Ìp}”Îðž(‰=ð9F,'fòþè;L›-¥é6‚uŸjUEâ½”mí츅¥öI\yg>¤þsm“yMˆÂ`¢¶Þ›{‡Ì¯‘Mæì‘½XkñÞ‘Ø„ÌgLdSÜ“<£phî0,A ÷&Ç«)÷'tÄf4 >ŠÛjÂ-åATOÙ}ðqµ}E¹Ø<Ϫoâ½Ç[’€"#P +T¸¨pC  ÄK©P›„É{IŒ{´«?^¾—{b[}'¿Øù*'rnî ÍV3ôîKg¥Y” —üÑÞ1öOàAý*»Ú7!)Ôxx`°Þ²%ÝFbR2ŸHœr¦…LÁ&–ùÖ"o.¼Ác÷1l†;Ö» û™³þ“ír¼WRvÉM«½Ïr¶ÌPm˜ÉÞM¼7÷Í|‘m׎ƒy\Ø?¯›?Ê“ù¿çë“-n³°>Áy˜£†‰lšûíÃôôòÊÂÏ!_BJf脈†É(Ô‡L‡ L8öRŒTD‰ëû‚4l .„ÛVým×BÓP°j"ç«… …ŠT¸î±. @̈u;”icM|Wàïõ,ÏñªLµ6ó{kßâ\í4G·¾ÇÉü(ó+ ,6hga‚¡‘ö2Ø3Àæá­Üb÷q[û#ŒíãL,!„QÅa›†d„þ´fÞ¤ˆ†!à ¥1P’·96ûïæ~óP§œ`CÀI ‰9¨í˜0CXðÞ1•ofsßVŽÎ¡íÚlíÛÎ@:À3¯!ùâ¡­mr vÄhŽXøpù8?âIü¤g¯¿ÄY|$Pâ=Ãí1î°PnðÊâ‹Ìgsˆo“¹¼4cò>fNDÂj߇ >&/1 (Hm¬Ýç±8¯âƒÉ)5\ž#IJ9š9 -+T¨p%*Pá†Aim‹F·?P£$6‰A&-ýü7 ÉD wQas{Ó­mÜkâRí"sý—hÙNr„à'0 ²uu; ú‚p.é芞yc Þ{Œñä|?z¬Î'Á8L(.áÉ]Nf.6ÏóËæ¸‹½g èþX ÁEª¡ál­mã„éãÂÊYî©=@:‘òêÌË+×~âÉ|† œZ>ÅxôܪH4 ™ŠH6ü··î¤1ÚËKó?efíb ™œËA>f¢šq]IÀÄ’@%ãQß æE6 è.ØÚ¿•í¡Ð$>8=v‡*P¡ÂzT Â 2ÄÖ8 5!ÈEm³i׃ºÚãïܹ¸’õôhƒ-kÛÙ²º£\m"`ÅF³¡c¥ öF$Zì1 ˆ¼£J¿ ¯ÖÒùBY/ÌoruX“‘å–÷/¼Ç‘Þ÷8hï*÷OÔA® 5JZÌ"ˆuqï<£LÒ_`¡=Ï©•“Ü\ÛËÝîì„ååK/°˜-Fƒv!¢às0pvù Oó$nܳWo'Ñ´|þÌ) z¹eù6½¼•¾É»Ëoc¼‰à!÷.hÔwV÷žv—|è“u A¸¿)Ü#88r7no}ü1‹#±:åÙ«û©³'9䬵Œ¶Ç9˜ÝÇèÐo¶^çØÊ{´½%—, }N'ѯáebJ ”LG ˆ‚Drã=‰XÄ&<1ý˜ö[ãØe_jÂõ RW¡B…€ŠT¸¡°±¤f¦tÄHŠå¢íô"ðcÈŹãM´igì/Ðñ(ç DƒžH¬µq‚^Ç @ÇùX*èº9B bbW€1ä>'“Œc—ŽqxêmnJn ío±¬Pè°`»º¼z¼Oʺø¤l¢žô°š7™oÍs´ÿ]¶²Z^ã.¹;iyaæ§,øyв½’£êȼ2³z‘§Ï?‰Ÿ‚}rûz àÅQ×:»Vof0fÛèv~¹ô .¶.`Ôa°xu„Ù„‚Å£„ ¥@0œ.S¶S#<:ö8w5î õ]åñ[ü«R@… ëQ€ 76ê  ¢`!!ŽÂuQµo y^˜9œ18ïqÎzU ‡ EÝbrŸ[Zå«rc,Ö*¹o±–µ€Ð2WØ£ >¬ºÅç8™f4³eÞš=Ľ›îg“Ù²nÿŒ˜ð«X,j<‰MÐØZ˜C:Â`m€ål QáØü1vç¦Ö-˜¶å ÞƒŽÁ‹—~Æb6‡ ´½àBQ§šqií"?¾ø’IË­ì#Õ´,›äNÀ;ð0Þžd8esßVÞk¼ÃûËï0—͇î 5u¡]0Ú+Šúà³ÎS—»¢·ÜÁ׆ž`ÜMâMwG·€³V¨ðQ¨@…W#ÖØàÄ'‚D±"‚¿3xkðõ]céˆñ ¡_°ê  ÐëÛhì|Èxa…Ö²Õõ>øhfãC êÉ|N"G.½Ç»ãï0]ßÚèt]»a)r„&WÅzeDG¬pfù¹*—³KnÿŠI;Í€Àº„ÛõndÜòâìOXh-€…¶Sœ:¸¢ ©˜i^䙋O"ãp«îCòZ§,á‚5ª'õ)[Öv0j&¸ip/Gòw8Ö<Ê¥ì"‡÷.d*Ä;d£å¾‡ö€Ðépçàý|mèlζ¡é•Ö¿U¸¯Pá×£"nX|T&%Àœsò˜ðÞáŠz³ú +NÊ @9cí¿ –@£ˆÏ™Ë̯ÍÇô·F{—Ž Ä|’‘û”¹ÕËüréuîLïa„±0b74ÒÇà÷Ëkùújö÷郵!œ*Ž u†ßgÛøNú»ÁCMSno߇fžc.›C àÛxu¡¢8¿zŽggŸÂŒ[n5û ‰NI"A<™kŽ ×˶æN&Ì$ûpŠ“œX=Æ™µS4}%Çy@‚BTQ‘ú( }•}ö “Ù&lÚ9žÝ—ʸB…_ŠT¸¡qu `L'ø¢‡ß¼&azžsËÞužRΰ¦Cl¤S¸÷Q^˜‘óÌ7/—5ð«ZJy¯žÜ; mŸðÞù÷92ô.÷›‡£ Î.8”Ó Œ`4ŒöêI“ ,¬å5¼æd8ð9ËÙo¯bºw “íMá¾>eû.dÌðÓË?a¾}€Üg8\+ªàpœ[=˳—ž$J¸‰[ʄ̑àþç¼GŃ÷4´—žµ^&˜ææä6–F9Ç.µ.2ŸÏ±æ[¨æ ¤ClKw°;½™É|½ôacVCŠ¡G]ó:)E MD… Ö¡"nx¬#„î]ëÊ”¾zŒ¼±1kê±µnãócb›¡-=$úÿ—¯§®ü»é›o£íÚ!øÄ¶  ­y>çüòÞjâÀà]ôj_4:*½†Ã¼XO÷qÀŠ_`®5K®ŽÌµ)f œ\>Á‘þ÷3ã$>˜#YgÙÏ]Șðüå3¿v™ØLW: άžáé™§H'Rv´÷DSCî²P¿wyÙJYdPPËp>Êp>ÊVvÐ4M²z 'Q¨Q§Wû¨µêØ$‰¤†8½Ñ”¿Öe*T¨ðѨ@… lèˆmhbB [¬ ^P Ãk‚€Ïn¨ÕiúN*H€t·ýu¿¦1ˆ†ŒÃ9{† ‹çP +óèGxÕmUï¹@&m¬O8|ñ0Çz?`z0¤ýKw‰11 àq´ÌoúWù`þ]2Ÿ‡Õ¼’@n94û#c£ÜÞ¾£t$2NØÏȘðÜ¥g™kÍ‚BÛk©…ð8œ‡“+Çù±}š'FS¶ËnŒÉ0.”SòØJ™;)K)¢²ŽHõú^Ä÷'§ôM01‹bmRNrLŠR‹“;–ËÝ]!¨Pa=*P¡BÄ–±Òñ’·&ü@̺à_Øíϯt »½ÂózïKC"ÎrŠ K¢¸.ªÿ?!Øz2ÍI|ƉËðÞÖ·Ø—è"2…¡A£14í Ï­=Íó§ževu–Ì·È4ôø‹íÀÌÚE^[|‰dز¹½•A7Iûôt\ùñÌÓ,´æHMJ.9N}i]¬^xñ0õ¤ÎïÖ™f Æ„þƒ÷.è$¼ vÃ^£’ÿJMEÑŠYh*[+“¤MJ,°îxw[ V¨P¡DE*TèBéÐU¸‚t­ø×õœoxY·-ŸªSZ(D†äm½ÇâÚÂGÖÿ¯UÅùœŒŒ5ÓâíK¿âþͳ•!kÑé5(·§©+<×~†gNü…ÖeZ¾MK[øXŽhk†:@…ãK0Ó¼Èþ±;x8}”¡l4öá {[ñÊO.>Íb¶ývrr¢z?¦îßšû%uSçëƒßd<›Âˆ„VJ—cŒ‚J‡m•!»Ñ•QNöB‚–¢þ‰ítVØHŠLKqÌ× *¬CE*T¸ ®:@&Î¥)Äu!êÅ¡BW!Ýqg±Xgö£œ×³œ/ÒÿøO¤`÷(9!…dæ}ÞŸ|—­vdžŒDçµ¹×ùññ§™_›¥å[aꟺrú Á’™,LésçøÅÌ«465xÐì‹øŒ7f_£‘öñxÏ×e“祗B§£ÂáL >Îè>vE￵_…4IH“´ã²h,&fJ3¤¢œS¥ÿ+T¸¨Pá#°1h¯ÿ'e}ùjÿ/ÿ.çt²]Ÿ58£§¹°t.¤ÿc àGÕÿ»²ŠWG®9ó«s¼µxˆûǤ߆6 z–Wg_ffõ-ßbͯá¼|ÂcpxŒW²8ŠØÛÐŽxèòkLOnaïÚíÓSŸrPî†Iå'žf9[ÆHðpAæúŒ—Î?O}sÇzž`0Ä›„Üçë€O<Îù¨¸ 0Ò±V¶I̤$ñ¶BPÌw¨Vÿ*|<*p±±žYá·ùÎmW 2Nù:± Òñ­Wå¼;Ëìòì'Jÿw?¯Ç‡‰}Æs|ö(Gr ½#l›t pÇxÿÒarŸÑö-rß.'ŠJhÍCð²¹ê[`võ2¿Z~ƒÍm ´K‡>ã-·ëd“mž?÷,+Qȧ!€S-ßæù³ÏÒ³½ÁõÇé7ˆ¼7ïQµ8ç°¦“Xg®»ƒM’Î\¤¼T¶¤§ªýW¨ð±¨@… ŸWú¬»ï{µû ÁÒ÷äê‰_Ûþ÷Q(äæêÈ}Æ©¹“ßq„ýA½(5ˆr|õ(s«—É4#sž Ú3…‚Æ©ƒDáÿÛöV,Ç?àTÿqÚ»É $FÒ¼ÎA¹—Õ±/_zŽ5má%Að&ÿ­ùÏœyŠÆŽ^¾’>Mm¹ãW—üE.­Ì¡žÿirE! Ê-ßâðå·y`òa&í¦rûÖÜ*óksÁÀÈóžàD'ð.0ˆ¯ïÈ dÞ²Ô^äÝ•·Ùݸ™>í¯Ç÷6ò^îIï§5¾Ê«3/•>Z{ïÀÀJ¶Â“'ÿŽÚÎÛ“xmÚ¨ öÆywÜÌWhÒ¤­yèRpm2mã¼§åÖBÆÓŒ\s¼÷´}µ ÁË„ºI,½¶ˆ¥‘ôÐc ¤ôÚ>ëƒ Ùa†k£¤R#?5S'¥F©c«¯É ×)ªwv… _¢O»~fý%–š qøÏOOÓí^='frbü(ãLbLGÌhQQä†âCv Æ•øè€HCì3¬I8±|Œ ýçÙãn‰)þ@dT=Ù÷Ô`u¤É¡Ë¿ÀHðñW¯A+©'°Ð^äßœü+úLm×"× ï=-߯ùœœÆh}”©Æ4“)6÷naS} iP—êR§.=ÔLís{kT¨ðŠ\s(¿®§»Â€ø>(D~±Î½Â2+ùJgð¬Àÿ†Ï¼^ xaéÇÚpWÏ}à-Æ’Á î±e/èÀGð"‚÷¾h0éÉ5'ós«³œÈp“݃ïC&À{ÇXk‚û±4°ÈÑå#à…\¼QÅ ,·Ya Ç ÄGãðÃx݇k^\9êŒ7 ß)Êëe£†ÉHq´4̈ŒÌd.ãb>Ã…µ Î4Ý IDAT!«ÑulR“2Ý»•m}ÛØÚ·m};Ù5°‹­íôÐCiP§"~»P€ ®1Ö{H×ÊÓ³ìXm5Ë öi£…0×GΉ¹£\œ:Ç”l!Ï{¦j›èKûYm­¢áÃZ¸à§Z$¼Ç›à!Á´ç2œ¤œ\>ÎÂðc:Iˆ²9ÞP:nnmãþ‡¹¼6ËeÅ(8Íc`Ô†û…Š; b¤ Ô@%h¨Stÿ޾¯ËŒ‰Îó ‚”¶Éñæ®c«"ˆFP÷5Ü€H‡ŽHÌØd>ãÃåã|¸||Ýq¨ rÓÀÍì¼…Ý·pÛÐmLÕ6Ñ# ¦AJ­Ó’X¡Â— ¸ÆPýä+º ׊à£+åè˯ʊ¬°š­òy´©w—>\8Éé‰ÓŒé$"Bîc:ɦþiæZ—CPR\ U1(^‚U°J ¯Z‚º>cˆÏ.Ÿent–q™ f>ªˆs¨DMÊ®ö˜x„gÎ=:0ø”}‘ñù‹àO˜bXX-G†ç ¶ECËbLÖaL´;R⩈ ˆ ‹§Œä_ü0S à"Šªtȱ“¢JlÀR{‘7g_çÍÙ×ËÛ¶ônã¶áýì¾ýÃØÖ³‹†4è‘©¤•'A…/ *P¡Â+êÿ ÞÓŽŠ|øøŽ‚_‡e€‹Ë3œh}Àô®PWÏ„N²ux;GæÞÇúàœ—û Åæ8|Àqö¡X-+^rœ:Û œsç¹ÅÜŽUEÕÆÖ‡)øÔ§Ü–ßÎÌÈ^›} Å‘[*Š÷& az¡ *ô˜»‡÷Ðgiçk,¹&kù2ó­9V²e¼ å‡ãQ5åµ ÷‚)HAgTr9ÉHÂö j|,(*Å@…èI`L6þúst¦yŠ3ÍS<}öljlâŽÑ{¹cänî½—‘tœ^é¥.=Uv Â?(*P¡Â…®R@Qhûvy[A>ýÓGOu8Ÿqbé8—ÆfÎGðê©ùöÔnåPÏ´WZd´q±eNcý_ŒÄÑÐ~' ^À9p&Ç«çÜêZýk4|/–ØA .)weÀ q0½‹Ó9»z!+Óþ>>\ƒ#€1†‘ž1¾=ù2É4ŽœL22mӤɢ_àdó$³­ó̬Îp¹=ËÜÚeÚÒŠ¥ ÉŒGIPõxãoÑBtÙ9FHl#”È ŠòÑé1d)4Žqþ¤DíüêyΟù.Où.F,·íå+ãðÐÄcìèÝÉ@áÊQ*\KTàš£ÞȸÒý/¬(½wä®ý¹¾^9&Ï…ÅóÌ ŸgH‡PïpαUw°kh³«³¤š‘«ÃkÖ©ŸÇ•rQ–ÇA¨ç¼óx í9Z¦I?}tÆ*`Á¹ºWÏæ|w ÝÃŵàt轋Ê~bP6aÔ²(̵.slí¦ì4ý2vª0UTeÏš=+¬ ®Ò”UšÚäBû,ÖÎr¡u‘Kk¹ÐºÈZ¾‚%/Jèèó2øÇ,@ÑQh й„¦èŠˆBÂn+çO|~ÔqxþmϿ͟}ð°{à&šx”‡&ãæþ[KAa9C¢B…kˆŠT¨ð`]Àˆ× ñ>·×ˆe§ÁðâÊ.éEnқ˱»C~˜ýù`î}òµŒ\3\žwÊêƒñN, „ç%\7Xu«ddÁv—°Šw"@x.Ä£N°jÙæw±¹g'šGé´é© xAUðÆã4çÙs?dtz‚ÛØ³N©ªÔiPӆ̪Ê.ÙM»§ÅjÏ*ÍáZ²ÆÙü §š'ø°y‚3Í3,¹ÅÐ àƒ™h@m‘M„ÄÁOF»J¥â0l¯B)(øtÎ [:ʱ¥£üűÁÖÞ<<ñO>ƾÁôÄ–Ã*3PáZ¡"*\cè†ÔÙÎ&ÐkXcƒPísH©†ô½WÏj¾Ê‰ÕcÜ]¿Tbë!ìlïáöñ¼pæyR©‘[G泎HO‹5pœjxQl‘½ˆ=÷bÑàÑ/F×ÙŽ\ÃcT•É|Š›náÄʱ7µÌ¨¬©¡.Àb¾À3—¾Oc¬Áv·££è"$ª ŽÎ±TCƒ>z´Ue“leÏ4+,-q¼uŒ÷VÞ⃕÷YÊ—¢K¡‰þ EÛchDµ, Š 1à‡.Âèè³d6âtó$uò$uò/™ìÙÄcS¿Ë76ý#ö ì¡®•€ðj¨ŽÇgCE®1ª.€Åù/›Ø¼#U!Õ:©MYs«¥ýgMÅáP<³«3Ì׿Ö‘`ˆã=n€[kû9ÞœÓË'Ã}Õ‡µ»F‚Ø ‚Š ¡Ò XEÔÐc{I|­ôß#ظ¿FÁªâ<µl–íô¥},f Á‹@”+ÆãÉUQ'VóÓ¥gùÆ7÷“ë[)…²_€²Ó¢«äbÔÒÏ ý 2É&ö÷`®Ž·×ÞäÐâœmŸ‰Á–¿ ø“®’€-Åü§¢$:‚±PwÏÀ烋kçù›“Á¿>ù—ì>È7§ÿ1O=Á¢.=U‰  ÝC»*|2Tà¢3еzc޸ЮV7b; uuõ¤ÔHMÏsjMárçÔ³ÔZ¦©+ 1L!~S”­›¸gâ~.¯]Ž:‡wE[ ½õ1ðiÖªÆcôI_hÝ+2Æ–B PE Oû°ƒÌ·:| á7´ÙyÔDQ :Â/~Á€íçáÚ×ôCa›bÁ_5ðëRÐù?@Cúhh/cvœcwónö+^\ø)³‹˜"ñO™Æ6D8)18jQ5(=|ù /<>O(Ê[ó‡xkþÿû‘ÿ…ǧ¾Î76}‹;†ï¤¦uRIñ¯ÈÀçš¹QP€ ¾ ”_N]¢¶ß §Ö@ÖŠ•ôgû+Ö§ž|›Ù «f-¦Ë}y¿š¦ÜÚºÙ©^:÷³@|èJ0b:ƒ‰b>&Ú ‹`6÷n£á¨Q¬µW40¨‚mz(¤Z£në¡°PýcI% Ûj<ÄÒEŽA5G¼tùE§†¹W¾BFÐ(¬ v…ÃßúãÜMJbàÃo‹eœ îã!vÞÌëÍWxeùEÖü*I’î’@‘±P‰¶ÃJäîÚ¡f¾Â÷Ïü=ß?ó÷ììÛÅ77›'¦~Ÿ©ú&j¤•V Â'FÕ„Z¡ÂŒîtvýôÕzcðÿ¼>ŽÑ&W=+íeÖVÃAP'Qx( ç£0wqûèj¦NOÒ fkanž˜režˆa{Sc3Ó²¹þ‡qމµXc1Ö„q½&ÁÁ Sÿ Ô"„‡Gã¦Þ›©™£&hfä5§­küäâÓ¼Ëá@6LBXy[ŒXŒ¬1XkÊý2&n¿Ä€Üu܋̀÷JâkL¶6óhú»üӉΎÆî˜Ñˆû€˜ øOƒ”?F@Ä„àKñÞŸÓ¹¼:N¬çOü¯üÉ‹ßâ¿ç¿áÐÂ/XÓUœºj,R•B> ª À5Bõ¦¬ðqð>¬Æû|?½µÞ2Žn¬Œz¨(+íeVYØ’7Æ Îa$¨ö7¯mã®ÞûYjòÁÂû@HégšáðúÇèZv ïaÂm*³@ ¸‚WÌH ه×mÉKÙJN˜](XõœZ;É}ƒ_a8æÐâëä J  ¨ƒE]âÙ¹'žf·»#a¾AèRƒZƒ÷AëPŒC š k âËlˆªÒçzÙãnf¤o„Ÿ'/òóåðšo(  Á3 ¸ a‡b˜ ~Їù4žŸ™Ïøá¹ïóÃsßçî‘ûø§;þŽ>JÍÔ±Øî{¨*|2Tà B1‘­B«Fúu€ÞZ_¸ísýÞ +Ý\«nF;Æ{¼±ˆ*Æ *®æÍ¸!ÅòÞÂáð-2Íb R“š”Ñú(û{0à:ùø 3Æ„ÀHPxã1VÁçÌÚYfóYœóxu ‚3†“+ÇØÓ{ w&÷‘ޤ¼6÷r\¥{¼(¨ f:Ï^~Šþ‰A¶ømë;*b*Â{lEÁúòï0ö8ŒAé¤ò½cðÞcÔ2Þžäó8S›xfå,ù »âÌé2k ®Â@I–Š“ùY=>)Þ˜{•7æ^eGß.¾³ýŸñ{S¿Ï@2XŽ3¾¿Šc[œÏëq¯%*pÑ­L®Þ 7Ö Ò6^ ×÷2XŠéd…dŸÏkX¥Y¶¢X4ï꣒=®Tw-íÁôúÒ~Þšû%&7¤šââ¸]‹¥nëÜ;ñ¶ç;QFób»_˜r?T|™ž_NæywéWdy›<:  ‚hŽñ†×ç^aÓÈfîÖÈr^_ú9 Á4È(Þçˆ÷–Þá…žŸðÍ¡o1âÆ¢‘P\q«†I€„À_¸z¯aŒ°zļ8¼Jp5jý"û€d¿dtpŒgVžäd~<Ø"CÇF8Î5(‰Ý6¡"#IgŒüæ6ŸN®ç>ü?òð¿ñO¶þ1¸å;Œ×'±j¯»îî}¹žöë‹B¥øQ½A+t àÁ`Ø”l&5)SÜÏ…Ð ㆠé)kæ iš`ãmF„«»yHãw§¿ÁÍC·ÑŸ ЛôÒcz¨Û;í=ôûÁ+vEâj)®¬µ`„£r”_Î"'Ãk†žÜçdšq)ŸáÍÖëÂ}éƒÜ>pW8q2 rŸ“«çåK?åµµ—h'k¤6¡–¤¤IJš¦¤iBšÔHÓµ´/5ji4©m¸“Ø”ÄXf#c¨k[³|«ñÇÜßó0‰Ø²îš „(5&N,,f˜¢I0\Y’/sÙvüÿä_úþ§wÿ;>lžˆSõ ËJ\kT€Ï†*p Q½1+\ å—VŒÃŒ2Ðduyµ\¡}_ÐEæ!Ó6Þ8Œ±š1ჯªø˜*ÇXÔå ·G¹3»-õÌ žçtë«n•ñú$’;Ø”mF“"ç-径à_ˆæ@ã*ù¬9ÅÏ/ÿ”ål‰\ŽÐbhT@ ¹Ï1"¼µô&“£ÓÜç¿ÂC=²æš¼·r8øª‹5õœ¶Sžºð$ãÛ'¹7}€„´s¼Ê@bú?f¢.Áû`Eì¼Ç¹ã-FòR (.lj 8D…ñ|‚G“¯³©oO7HS— 3áNšfpÐ|¤°§ôzø¢²-×âïÏüž<÷÷|kúùvýçL×7c4º8^'ßSUýÿ“£"*|A¸Ú­ˆ0¢# Ö¹´2´]ízŸÝ¥‡,oãꎚÖãÿÂv$VQÒºvÅã2PËdk›²ÍÜœì¥m3Ü}¾µtÔöÅj·‹@ÑãoXe·ÖÞä­Ë¿"''× ÅÇU½`QT ó9h‹—ç~ÊÔÄ$·äûùêÀ×iú&§šÇcSžÇ)¨QVÚ‹üíé¿ah÷ûåÖtD‚¿ZS;dÀy‹w«o-¹s8cÂo—Ç}räÄY ƒnýrCãühåßsÎ žå©ì²fƒg€n°.< Òðûƒd>ãßžùk¾{îïø£-̶ó¿`0&ö^üV*ø:T%€k­.7úE;׋þñbä=(ƒ~˜ÁÆ`Y?‡Ž¹ÎgAaœ“ù6mm—mq"Ë–ÔZÒÄ’ØÐ®—XKbM( 4\£~„_GD±±¥Ï)÷¡“ú/*!dŸ4ðü¹gi»6™Ëâ0 X3Ô;rçÈ4g.Ÿå……Ÿp.9Íölßÿ&ëÓ±=ÒH€’{Ï…µóüÝÙ¿á´9‰#XÚ“¤Ø¯”4IÊK=Mc ” jé•—4M¨¥ ib±6ÁZKö°3ßÅõý ûkw”m~‚ VÈÄ’€Dd, ˜bÌqá”;=Š3ûpÛ¾Åÿwê/ø“—ÿ¾wþoÉ5B¦¤VõÛs©ðYP€ ¾(Äï«¢7½ÆÃ:ÂhÏFÌçÖA®]?mïÈÉC­?~k›”¿C¬…ÛLBb FÆ?Ɔ÷âñ±ÏÞˆA"QØÌViò‹Å×9½|ŠÜg8ŸãÕáb ­{ÑuP‚ ÷Ž#+GxmíEæí;ÖvóÍÉo3œŽÄãÄtžà\øÞü;<}ñI.Ë¥r{¬ >Ö&ØÄ’“$¤6 û™&Ôâ¾—BPKÓx[Ф֒$ᥒ2‘oâµ?àñÞ'H¥öÑž*˜.Ï€BÛa„q0¡ÐyäËÙ,ÿÃ;ÿ-ÿåÿ)gVO•­©¿mî÷ÞoÓvP€k€õoÈêr£_@6ܦåm¨`Ô2l¥fjQ÷ù|,‹2€÷yü¤‡à‚¥Å˜H’ZÃ%)IWL’4˜ùˆÅš4f ’`Âs…ûœú®ýUáŒ?Å¡‹¿À©#÷ÚiÄCHÑÇÂÐû §9¯Ì½Â!ý-ÖØ“ÝÂïoú}¶·ü@)ZÞüôâsü|ùg4µVàbâ¶FA6loAzLØÇ$Iâ~Ñ`šÔKBÐ9)‰I¢@0ÁJÂåyo÷}‡!;‚SšNްÒ#¦øEæ@(σÄÊ? xsþ þ“Wÿ„W.¿,–ãy,æU|™/‰g% üd¨À5FÅH+讕w¯üDaŒ FzG±òùµjOá¼Ã“—·¬kB@´IPÎ'y­ÖY!§1=ž$ᾉ-kèýߨpW”ózŽOkŽ/ÌÔƒúrš JèðJN=N32¿Æó—žæ=sqÂ>€ß›ú5j…¯àÔÑvmþöä¿ãíö!9ÝYa‰Ù‹u³]4ürßÓõ´ÖÉ$i§$`,ýÚÏ­~ßéý¹9ÙÛ•æ7ñ˜Ä¿MwÀ·õ)t]¡ÿóõi°Íó_ÿê¿âÌê)ºµ _Öï¯/ëvý¶¡^CTl´B!NZ'R*sbp0˜c¨1̹¥³Qøù8†Õ¶#×<¤¤»SШ{$Ž™ ‚¾âwÞ—Û[hŒ étkSÒíæ*Á¿M‹£KGhk;¨îc탨âð!Mî%È!ó€ÉYl-ðÌì“ r“ÛËéÝ´§Wùþùïââ>¹¨¦[Ìæù›ÿC»GÙ›ì»úªŽú^âkŠŒ38 Έ¹ %<7eËdƒy»œ‰AÛ ›ó­üãž?â{מcMVÁƒ–^CÀ 6zˆ(=(†D™/Ö3`kc;wÝÏïNýÓõ-t&.~y¿»6N¬&~:Tà¡ó%¤üƒÑú _„÷€âËÀP òBa˜Qg¸w$Ô±1ä|¶wKªä.G/¿ÎM±r¼b<Æ`¬Á;S:èAØN#&øû›„$¦ÿ­‰þ÷Pšâ¨zÖ|“ŵ…®DQ[â`]1†óˆãvEKÅ|æ5ÊÙæ)ž[|–ÞÁ>6g[¹»öËãM~<ó4Å„N@½ãøòQ¾wîoÚ2È´l¹*ù.šò¬ C~ÄÇŒˆç$Ç!Öë‰ûU7ÆÅãè@< º!î•ÙÔ·™g›?༜C´ßÁ\¨Gƒ0^"/è²–Ø`¨a‘pm‚Y" ;»ÙÛ¿Ÿƒwp`ð¦z¦1ƘU·ªSšø²º˜ÛÕM®«n€O†ŠT¨ð¡;P®¸ãO]{ØœnÆJjÙŸS"äÎ… v*âAA@ F ^9ñÞâÄ•Á¼X J)²+„€Q¸¡\¡Þƒ›®ß–XûL¡\)4$”|˜ÎFxkáM¦êSôÕúÉFy¨ñ(«£K¼8û"xçñbÀ+/ÏüŒ­ýÛøýáo3d‡Š.·/ˆ/µXwæt;'®<6ÆLnJ”å!+Ï_îÂï^×Ënw3cqÞp¯òúÚK¬±V®ü‹í`g@ø×Gzègf©ÔØZÛÊöúnv5v³»¾‡]}7Ñc¤&drR›+ä8bm‰ùò¶VÖÏŽŠ\s|yt…/ÅB¯¨ú–Á!®®aR¦iŒÐZ^ _ÈøÏ¶š‘¢ëðÚYKY ˆ+)f8çB­Z;Y„¢†-FbÚ?¬ü‹Zªbo:CéPGëÐÈ:H)KÅ! Ù€"W—¡žŸù #ÓÜgîg<›à±Á'XΗùåü!€03Gî•¿ÿðß1]ÛÄCý‘R»²Pl &d±ñ‘”¹Xœ?€¤K·!c„<žÝ$@œ0êÇyÄ<Î-}{y-{™wZo‘“•ç"Рè ñ/5W÷ x„éãJðaÒlbS:Í”ÝÌŽÆ.¦ífjRZ“Ø›ÛÐaMéy ’â3$‘’H§¯³ú»NQ€kŒnx…÷@GUÐéûWUÆÝ£}c\\¹ð™tÅZ2¾,¹÷ä>\UP&‰Ï/1m 0±ÔßÅŠ½ØÒX@YƒÁ?ªÆ½*â õiRIiÓ¾"›Qîkà¸B|, €âÅ šÓt+üxæ)6mžbwv S­Í<1ú-–ò&ÇVŽ€†`éDYÉ–ùëÿ’ñ[¦Ø›Ü;®¶Šíœx&‚&ÁJ„â ;ßP"‹¹öÁ¹ïhø^¶ùŒÙ î|€_®½Îáüš~ÕñP‰)vÕ²$`ˆeø†Q "±$·¿‡£fŒq;ɘ™`ÜL0žL0%Ó$’bÄJ‚•ãMéC  ¹QÐ|]§‰-ćIܧp 0)¬‚þõŒŠ\#tóFEízÑJ…Å9§ˆ+]©õŽ2<Ÿd¬1†áóÑ”¯{í;ÏÞ‡…‘˜–5á}ktÝŠ½x¯vý2¨Ç÷´ ïpÞ1)“lé߯ÑÅ#ˆ7ˆ\™Í%‰â8AÅ (ÞB0"ç|û?›ÿ ÃLúI¶´·òí©?ä¯Îþ¿œ[=‹Ç#êñ §›§ù·gþо}íì€ø¨™N6 ?LYûç¨cÜÈDñw, ø@œ„€éôiö&“)I¿Æýù füòyViÒ4Ͳ$PÃ’Ð/} H?f˜dÐ 1,ÃŒš e0´ªÁbÃÔF픋‰ûàcö‡@ÈÂ?ÃÔBç0¼¼Ïñ"Á"Yb)(Å"WULƒü2~_¥JøéQ€k„NÝ1ü]¥Ðn\¬¯åviŠ ëê=ÒÖú6›’i¦êmX‰B<5%ïº@ß–&®‹úÆ tHKYJPÖ‘…pUu£ìÜͱ…°Æ†©‚WÉf¨jLxƒ¨yy%ˆ&ãM¸Œ7æ^c[ïN6Ñã{ØÖÚÉ?™ú}ö/˜i_ ÿDpâyíâ+L÷lå&¿Ãˆ]§j¿BAA\wo( tÚø$‰š‰¼0AÊQŒ3d1›“;V0êq8ôRw e˜=f/¹Ípµ‚Åò !xH¤*!¸«·Á0êpÝyP‚vðj­ÚWhI¤#íöe PGt}_}qú² ü}vTࢠø®@¬é"3q.®µBªyÌM2Ò;Jkq-…¤ÿS óEïCÛ[·hªhMCCê›a•bù¸ÎH;l–«Ä†øÂ}°ßýÿì½yœ\ÉU&ú÷fÖ^¥µ´oÝíV«W»ÛÝÞÝÆ6‹ÌbŒÇÆ,3ó†yÇoޛ߼ßÀÀ0ìÆÆ6ÛxƒÛKnÜØÆk{íMÝjµ¶Ö®R©ª¤ªÊ{ãœ÷GDÜ{3+K*•”ª->ýRY¹TfDVdœç|ç;ØÙs=RóYX›ÃÃÎâÌ(B\šo-rÁøD –œú'lÚ´7Ú=HÔàzy^½ùGðׇއñìœs/T!üÃÑO`kïv¼¸÷^t›î ¨1Ãç ¥RI2%q¶4ªÈÄÈ)#·˜¹%çŒ \‹'Òæ”dæp·¹Ï”÷» IqIýëV/Lþ9œx½×ËÀ°ñÏ}L¡ëàú:ðŒ¿k»ýj1íaMNR¬˜7bà"0ª#V&ZO(Ì.O”DX—¯Ã†¾xòäãÎÙü bª %gXMÛ'ø µ5Z<Ûb¥–ëYN]kóa܆„<û|c%øn{>ÿ Vß3€@šã[ç¾…›únÁ¯BºP·Ý¸ÝÜ…Ææ =ü!4tÚå‰q|ê$Þð=¼nvš]M¥mÕmëíYS ŸÎ@‘°Ö¸´Û"`|—Aë*:DÁ,e¸]ÛGCZ [(lŽÞ”Q‰Âa!W¥RKå)ßU.8͆Ð+ÁÿÄË#—ªŽÔ”*qÑ¡«Õâê£Ýß/âò€£™ø‰*+3HpþººÁM±ÍlGOÚƒÆt㪔ª*¬WâC5ÿ{4—÷ PÞ¬þ IDAT¡ûæ×óZÿVh‚æ:lìތÂɸâ6•¶‰Ö×E Ñ `AH°Pdvÿ|ê3زq'¶eÛ¡zЇ;̘Ø0Oû;WÓ®"Æ£çÅ}Ç?†Ûð:¬7Ã>R1ûgUH¥J 4¶Æ‹()€´ˆœR @d!êR:" ñ} B[â‚+Ñf?(y ³D&*aþb\-{}®DmBô!8'lJyä Êß³Œo1!žú¯Ñ¸æð5Ðqñ®X§·â´æ6o€À†°.ÆÚþõkŒÉÚž@7(U+ЖàÕzú¼øk¢É@Î|1@D°^6á–U·ãèäǹW6špÌt«† W‹#â“_ÁêÚjôë ¬ ê*<¯ûE[3†OÆÜœrßgŽÝ-Ý[ñŠ¡ïE÷Ïà´Î»¸ßB0`ÔKŸ6ÁŠ“4ΉA”ûœ{îNþÌk¼¬²49ÅXù<Ëq4‡ágsœAouÊ€S{ \*€À]0Ì@pˆÀÆT8•!.Ê­jQjÉ!:F8ÍØX"V&´dЇ6if%¬·±¾oÏ< CHñ—ÿVÞ°H(Ó»JË®5ÜZ&P1FÌŒnÛ=µ›ñîoáÈ…ƒ0,PÍ/(æŸP@`]I;õ¾ÏŸúgìÞv3vÛ7OÖæëð]C¯Äx~ýjqŠÍl<ø~lèÚ„»ºïA‚dV' :ÇK¦, Zþ ­±`Ë+0b!ÆÂŠ7þ^¾ØuÙ+#ƒMïãy!Í•"•ü|Åàs“cyâç¦ß/ €åïGÀÿ>—„Æ ›På…„Ïc±a¶ÖbŽZ,6D ChòÞgÿ¸@W*Š Ê/fr¥f@ú°µ¾ ß2!³ ›YCöóÄUí† ƒ‹!Ï0ë§7âŽUÏÁñÉ#°Ä¥Ëâ5TS¢R p.ÃWÆ¿„M}›1(«ÜsU±ÑnÆÿ¶îÕ˜°ãØ;ö8×üg<Å_x'V_?„ÒÝ€gDÌ0öUcRäÅ+U…a.ÿêCìÖ8=±≑ª!€&Bbóa»yßh=á79Xá¾ÊgÎEÂò9Îk‡çVˆÕßÃÌ¿ábF˜g4úóCt:Žf€kŒ#+RÙ“Ç ¬ä™çŒÜæØ”oƺþ ˜=€«ÒPáE]ªáç+Ù4µi>Åœ𠹦;–€.íÂéx¸w;Lì‡%™`Æ;úMÞª‚I@Jøú™¯àž»1 CnŽDPlɶâ5_‹÷ÚwáÀùî]DñôØ~¼çà;ñó»~ÛÌŸz)_¦P} M)R®40'°Ö‚ˆË®‚A-¢˜Õ¡›ö¯"ZRÍ?{‡í#/EÛß-£ aÎXŽiñØêŸ*:óC,ì Z7“ÖÚÕvωX!hâ„Ó?û°Á†| 6öoBB 2¾$pþh·-^Í2‡jØŸ=㜜J ˆÃMxöà]H(hØÑ¼Ö¾+´Pq×ù¾<úŒó9q™r°-߉Ûø“XÛµ^¤ Å7F¾Ž~ŽæGšNâ—žgsê&ü ÙŸú]¹ #I R“ºÎ‰IŠZ’¢žÖQKë¨×ºP¯Õg½ÔÒZùs­†šÿ½ZZG=­£žÖPKR$&E®MŠ$©!IÜc©1H’æK(tåˆ%е‡.çRÌ­eÞ‹Ñà_b ÃРq ð«ãš]±ë¡þ'{g(]I– Wú±­{¾“| Æ•UPx+m™B @N^å|Ü<Ü|˜5[Çõt#žÕ3û¶Ë‹‡’¿yœ.E-@‹oû:¾kè•Äj7.Ÿg'eìâÝøÉÍoÄ»¾ãùXá =pü30œàG6½[̶¢Üíâ¹j…D… èÈLÆqØwWT A‘@}Ô¢PÞ»Ô_9(øó}Óm÷£6ñÊç6§?£8ɇè#PF@´:¿*òÒ‹…Q››gh9qyˆ€ˆˆkŒæÜmæ…J»^ôL„MùV¬ïö'5~ã²Þ§È_ì÷®äW„\2Pml¸T Î6àΡ»Ñkz]$ÀçÑç÷¶^áгÓgp0ÛeU“D@Š»éfüÄÖŸBë!R`qÿ3ŸÂ_~'اiÖV$¨š÷żC‡Ä2"`8œ¼Ù_ vÑÄÔŠS{ÓŸKjRÿÜĉ%et!I0Q뉾Ýé¾( §üjÞŸ¸;ÎÒR@““qÙˆÀ †­V.š7¬2/[°¸}é–aƒv 6ôo€¡ÄkÄÏo“#êÜzk*=ã2äïŒO‹;±ƒÛ;pûª;aØ Ð\¦SS…ªz•CÁ¾‰'pžÇ›ŒY¨½ïÒ<;¹ ?±å§PãRÑ,øÜ‰ñ{{ÿ¾1õŒêY§€Ùsô­s/>ƒð/8ÌMƸ0ÐA/áŠcP¹$ì½ÿÜ‚ÑÆÀ—n2ôå¥ÙØ_Ìà/5ÃUI±+1ÐqÌ,÷Y¬¤šˆk…@›àÉeLN1ž‰` ÊE¯íÅ®îëðhúrÉk>Ï4@0±:Ëe~$À0—@T"°aqÄ c«ó5¸­ëì«?SG¡äûÞ_&!°„3ûÎïÅù5ç1Äe5€#…"=Ô‹»ºïÁø¦1|ôȇ|ã €D±oüIüö#¿{7¾¯\ÿ}ؘlÂ'ã$Ý$Áâ@TР2†øÈ„1 £)8§næë…l¹] kø×÷Ïþ;¨@®9_8ˆë»aØU?'QÅ»/|&²sxàÄ?¹38 T]»¢sÓ£øÌ±À?ÿ'ìèÛ‰[†nÃs†îƶîíè¥^ôP/R¤³ŽgR'q0ÛùVs?¸ÀªP%üÓÉûÑÅuì¸/]órÜÜz´5®U&7‹!Ÿá¬¼}¤ºŸ¶Þ1wD ¨.ÄÀT ¿õ±ˆ•‡*ƒÞ݆¯ z ‘A¢5l×XÓ½Ç/…áVdnÆRË25¯h®V@Ë\´t6 êòàjÀ¬`NÀìjäaÐúé ¸«ïù8tþ Îfg X”¥z— UÅѩØîžF¯öci9>U(¹&E¯ZóCË'ðµ3_*ˆüwï5=ØÞ·£ÙY|üÈÇðÉ#uÝëq]ßõ¸±ÿfÜ6x;ÍÔ)EJ5Mk†ó¸€/œ}죘Ì']$ÄG"ˆvs#W¦8%ÓxèìCxhôkØÒ½¯\û*¼hÍKч>$”úyU>éY ÜJÝGZ[W%•cD`nˆ@ÇQåT{ĺ²¬¯ˆ “Ü0!‡3[²mØ:´§&OÂxM€K+é•!k&‚!sÀ•Ï¥LC{NÄRщ.pÃP5P¶5vâyk^„ûO܆WÉ›/À3Žàš ôIoaœcBMâ;ªÀ†|¯Yÿã8Ÿã±±‡bæÇv¼/x2ÊððÄ·ðéãŸÀþ‰}81u_:ó¯H)ÅÚú0ÖÖ×b}÷zôrÆòsØ?ñŽOŸpÑHL À—’:ñ â\”D¹pï>ü6üã©Oâ5›^‹;úïD/õ‚}è?ò†f¢¢µ£ñŸ;¢Ð!”†>œîr4‹­¹LøÓzHÃe æC¸¾çYx"ÙëÈ€œ@DçFœóõéä gm÷ÆPÏ~…óC ä96µ†­c²‹ëJ袂޼»“=8п?:/B`àÀ±é£˜¢IÇ~÷ß9'ìtàÇé¢qŒÍv ^»éßâÏó·áÐ…ý€wº¹«t˜ Öõ®Ã-7ÜŽOŸ¼Ÿzæï‘«E¦9ŽO>ƒãSGAc®WyRƒ A¹‘Ç1Ðâ±0pre‹‚Â9G&ãžúŸ¸cð9xãÖŸÅÆtRªE¾Ð,ß‘+똹R˯â⌨¢©ÐóœN;û€Ò!/¨³uj'v¬Þ‰„Ó9+Ê€ÑÎÒ‘AÙ\†ÊÖ³‰aWÓnŒW 4nlÂÝ}/D2XD7BéÚ\Ò)#Óg0‰¢.?”â•oZ¸8BØ.;ñÆ-oÂp}£K‘ˆbßøS·ã°¹€Ô`ƒnįýqüÒ ÿݦÇIûúòâÁOhó @àZKH;Àµ@T Ñÿ7W.ÿþÜvìfþÍsá??öá“§îÃÆ ¡¸4£öÒå#:Æl_ØøEŽ0³e5€aw›™1œ¯ÇÎÞëÑ•t!¡´PÚkg([ïsaäÎ~Õg”¢U*˜œÑr´Ìi’8‡;òð’5÷ÂPÃÉe1î«P›:ê jYûnŒñšìÏø‚ %l×ëð†m?ƒ¡tJ‚=õ ö5öâ¤Ãy™€XEŸöã¹Ý÷à—®ûwH|$ðÌ Ÿjpº*€ ‚*DS ¢NƒÀ—{‚Ü_…á;õ…Ï‘isÒNà/޼¿õįcc¦eºyì+­äêˆËGt:ŒêI¯\£1œá0C…Ë4{ÃE N°3¿[¶!á)'—Œ‡‚}Kák1—¦(UÊ !ö"@A䯠Ozp£Þ‚[ûo‡ÃÌCõ0àäô dh•BÏGÜu% …± ®Çn¼aëÏ¢ÛôâÌôü'~¿µÿ×qÿ¹ã˜<ƒÜf¨InOï›¶ÿj”ÂW]Hñz ×tIÔEëS$âÒê~‡½±'öäIß©ˆ ¨øØÄÃø/ý*8û¸€óM¤·•løª{hŒÌf¡°@hNÐW. k{YDXD8M•U6Fˆf6ªjTÙ0«yÕ«¾ÿõDÔÄ¥‹‘™±s玖…9S bå¢ØÌ«!^…k%ëõòC¹î¼ã}£8Žu¿ÿaçB®‚·üSìoìC#ϰ™¶aOÿ-þ|ï ¾ÀuÑf ë@è*Ä;ðÆ_šŒXQ%PùçÕ¬pA&ðÖ¿{/&qÁUx,÷=¦Ýþ#óCt:Œàý‡‹[§:ãþxYÙ—°.\èùÆ@•îr¡]ðpcv÷Ü„þÚj\CBI%ÔÞ Hxæ‹Z¾_§çTÌ¥ÒæØÈÆ’$A’$ž©ïÄ‚6NoÅK¾ ƒÉ‹\FU@fÉO—ß/U¸B}7}ã£ÆGN$Gñ±sÄŸ >uþãx†ÀRŽUºÏë{!ÎËyLê$nÀn¼yË/C!xçÑ?Å!û4êY ·õ>Û‘+"C%· |ÞÁ!´H „RÁP¿.…# êSþó*‚ð¢Î>% ªøû“‹?~ú÷1aǼìpxïå¿¿¨ïÜXu–»ósµ€#„vKe2-îˆf×Õ®v>ñ• C„ë'÷àÆÕ{rŠ×ahf*  r‚Ióšëð>YÌ©b¼™Ë(€ñs sKãªØE9¶7váÞÕ/GJç p}€“Ó' þ0íq=™1Ác¸ä¸ïØßᛣ_ÇŸy/ÞzäñÆMa­¬ÃŽäzÔµ RìÄuø¹-¿á¯N¼ Çé(v$»0@°¡€Ä÷=p)ªf€j0ð¡'€{>0‹f@ÐChÕ ð)ÏÀWÎ}¿±ï¿àd~6T`yÃVíÿVÃ÷ÕËCt: UxâOXœäO ñ/-g%wñg>BEÔ"ƒA» »“›°¡oR®!å2PT¡x‡ å)Êêµ¹k]Ð4»ð~Áo¨¦œ#У½Ø›q×À=e á©€°÷ŸÁ4>Ô^~¦Î˜–ýŽêQüã‰O7½ÆÓç÷ãOžþ}<*c SXe× Gû  °l×xÓ¦ŸAñÁ“ïÇT>‰Ý={€‚Á¯\‹' ÍñQxç¡E3@µš¡€fÍaÿäSøÿžøÏxêÂ>dš{N¸^.—êþY˜˜¢ÐA´_q‘F´G«’q`®{y`2£v]¸{VÝ‚nÓƒ:ב )‰d•²zÒDM±QЙc¸óâÀ ¨j˜Æ“]¾ž±º±ww?;»w6¥.æ(€‘Ʀuºòþåã¡ö~ЦðѯaÚNÍxsÙ(Þñôã û82dMïÇj°I¶â ë~ýÜþ-žÕµªZœâÕr4g„›4´Bœ¡àS"¾ëc‹f€”)ŽÑ™ÆiüÆ“ÿû22,ÿ hø¯Ñ¸ÆX®_ƈ+C+q®Z@ÇEI`H8™ †›·âæu·¢Æ5ÔL §¾4°Œ ™!—7f†b¦cÚÉ ´5àæÓ>&‰›W’‚ÈÀÂðÔ¼xðåJV]´4°ª0–C£É¶Œ…€ 4'&öÎ:î‘lùÌ;pŒ$åø‰``°N6à‡~;ê×ãk_DŠšÓk(NýRøjÞ_CJ à´È‡Jg§ü$ˆ\(€Ô}† @tÕ äþààïà3#÷£Fñ¹,§}'h´»?:—‡è\{»J…|®ã%^ÊK Α'ÎQAZ#_3_)g#ÂÚÆzÜ’Þ†­;Pç:ê\w¹tO«q½Ú‡EA SuQ€PéàÉx‰aÏ0Hçउk`”’ÁŽéëðŠÕ߃:×.ZŒÜD>Ž ÓpM…Ú͘Â$Ÿ?8ã5ª8tá þæÄ0Âg@¤^€Æ þVÙUxIí¥xYï+°§ëfô&=i€PþR9ñc_¨*Pu wAƒf€´× fj0CañîgÞü¦eºø ŸâK’B¨S¢V+±`‡Ð¼K’—HXÈq±F4#EÝò @^/ô [¤Iñ„/`ÇÄu878‚sS£™: °;I2ô$=è¦.g(°0$©0¯‚°uI¡Ä0&…V~NÆâBâ½¶7ʼxè,>3r? ©k‡uɱÿëÈçqSÿ-xYï+P—.€½ÙU“ [{°Co@_ÿ 6N}dç³q<‘íÅ8&@ê:Q({ö>\ƒb&‚Š‚Y¡A† @ìö »Ž‚L€¸Ïͽ¹ç»×,T PÅGŽãù^¿ñgPc§¸\NÉ­Ú–U”ãZ!:D;Šr±.Ĉ"–Š šÌìrÀ¬E­¼q¡ó4f R`ÏÔm_?/û<(?"¡½i/êÚí DØøg.¾N… õx~nᦨ 1Æv%° IRw?€|wÔîÄ™ÓøÆØ×ÀP‘ ,´Ìg"›@¦.ü­ª`ÒàSùœ¼àdã„Ë»Ï{ìÃØ}ÃÍØÉ;ÁB0˜¤ì/ 9NÉq|âÜß@ XÏÃxY×wcSøvã[8!Ï@ (y‚'Ä;V ÎöD`õ²@̼À2ƒ½ÀkP0t‘%m’&¸6Äpÿ©Oa,Ã/ný?ÐÅõ “¥†v"@Kq> ètͬwò÷‡‘èD̪„…s¬uO$³;Ý3 ˆ\¿û®F7n¡;paýy|ãäCPU2êZ~;ëlŒ[—ÅÚ\ ¹BLÝ5V$¬PSæÈM¡ 0)ÖN ãÝ/Áé©S8Ü8€Pö×ì(ÎËyLé´‹(HhÁ[>."8×›ó¨Ggð‰Ã뇓XA✪5ðØôð*`'å8>6ù!ܔނï¯ÿ Få¾?„§tD­ÓùøÜ Ÿ¹1ŠBˆÝi^ÅE. `Ä'>”¼³àÿvœT ÊV…ª‹|iô üïÛþ#êÜåÖ-Õh5]ÇÓÿ•!r:„æÙœ¿ZøAC2Ü?}>—YšaÈ®Â]x~4y^[{#žÍÏÅ †ÊT¡Ù`çDhq»ì7*Âs‚ö@)#\öA¨Ê?xö<0òO±KÚ @óØ—Ú<‘ÐaT7&U-nÁøŽˆhƒjE@ÐPrLr5R (T@s(5ªcÏôíȆ3ôI? 6¥¡¬v\è9ÎàÊür‹’` +†þä;`qGí.œ8¯}¶(±u˜ÖIW%´0t¡4O¬øôÁåATð…3âú ÏB/ú@¢0Æ`túlñœ@t8ÒŸ/Ú‡¨àKÙç1гø¾ú¿Á`>„Ħ؊l  x±y)NÈ <©ãiÝsz¶Œ’øS¨ (yªŸ’ã ¨2”)0Ýn=ýõ‰÷ຮp]ï.€¸XcKÐî俔ƿ#BÕ;m=ýÇE1WÌTÑk•“Àpêêç“ÔÍ+¤ IDATõ BŸôáÆÆMè“^ø_/Ò ‹)àô¸ˆT$&AZ_ ¢Æ8)ßõÙz¼¤÷^lïÚYˆ…èÆ´4`µ9—.œ&øç_>¾<úEŒÈ@]@¡hh³š ¢Ô($ýIýñÆÃø»©à\: %à®]è•~ìÔ]¸¯Äë“7áµéq¿úÑçôË”@e”Éú•¢œ²vA'#Ì„LøðÉ÷9UB`¡B—…êÉ¿¼/:óEŒtUÕ±pòѦ#—BÓZñëÈ¥B®t.t“óOÔ ÅlM0^¦”ÐÕ‚KUj,Øôš¿>´®Öͼ$°E#®ÑÈåñ!ŠMS[ð}kþ >tòý8Ó8…BùN<PÕæ|éµ,óÛúÎçøúØW0Ü¿ÑÉ+0-ÓmŸ[Uá áx‚â©ìI|X߇îþI¬¶«ÀÊþ9ueÔl ]Ú ´wóó1…)¦8¢GpÏ`DFò'~_ÉAî&Íå hÒ ÅáéÃÈmRÇÃ(¢LK$ ÐzÀZ c^ŒˆÀ56•ýUSqáF\ ÕúyWKî‰^¦*7Æ?—KYY_$€C^ç ,ÂSR À #1Iqzv:‰ûY÷²ä´ùwf×ã‡Öÿ>x콘°€„G°Ó–GAÝÜ=ï¡><þ¼´ÿåÀ ” mïeJÀMO8ƒ{ć&߃ëý)¬³`´$ +\ØÞ¨jŠºva€nÇnº9¦hGèNâNë)Œà4Ôðï%EJ@Ñ^3 ¥¯XõÝþcwé‚à¬,ºu1 Úþ¥2öÅ„ètÕP©[Mþô/1qÙ(Ö ,ìÂØ $&)·Â°Ö"œ=C;á !\4 õç—è®w-Ðä+ Tò„ œ““úØ}“ð‹Ía­ ÝØm÷à6ü>rô¯ÑІK°ÏpÜG*ˆsC<;BÝebïÄ£˜Ðq `"Y".÷®EÝ¿«Þ#×£xßùwáµýoİÝ#á°P¦Ê*†àtQ7un‚@Y!¤˜ä œÖS8‹LÐ<…†f`btquîªd¶umÇž¾[0”¬všP©4¡9m¹¡êE¤PÝcQÜŽ˜;¢pPÝèbè?ârÐ$ gG˜ " à %[hìkõyþäÏÌžrî‹çä4›T0 »H€cƧpŽK5lA¤èEnç;‘mÌñwÇ>ŒÁt Âô§ “Þå?¤èMú0žÏ](à‚½€'&Çp×FÓÚ˜Óï…ÀB@ìOç§ñ—cïÄë~ÛÌ6I}‡}­¿ÿDªÕ >ªÀà"Ó¥k°šÖ:ž¹ˆk¬” ái­†§¨¥5¤ZsÆŸ}Ä@ÃfÑGª§þhô¯¢Ð!T9áÄU=ý—¢sHwJ†Óü†1îð&¾®¾8)•Q€P Æá ·ðùÿ* ® àópákë!©1îTlƒHÖÏ[ÿaHñÂÚK°fû*ìL¯óD¿ª€ Škƒýf`^™:„©Ú$H†™óï,~BJàœ=‹÷œûs¼iÕÏb»Ù…š¸^jØk R¡¨:MŸ!| _$žóa}µG.ÐT bamÃë>[P¹7-’õÐnët‹6Úü«ƒXÐa´;íÇ@Äåb†âYaÜýY0´æ ä*ŒïXô’jq‹85£2U}öºÌN T>N Qž~íÇÝül±Û*éæï›ªÂ¨AÒ?ï±™<ŒiLAH‘^ÖïU('d ï>û<ÇÀ #MS¤I µ4E-IPK¤‰›·1)˜°ÿ[»‘¦Hó”½$ÊùÕA£À‹"âHÐ&Û¿ø÷¨æïCŒ¬Î1ÐA!¿"$~.5Ñ#"æŽ*§$œ&Ì ¸šnræÊzÐ\Ë”âÅeÿ øN„ï …ªz2®”‰©>Ïìu ,•,¤qA^R¿Ò‡@Dô'ó籩£˜´S¨i7ºi~„Â&ÍÆí8ÞuúíøÅõÿ[xȺ?ˆÆZØI —dOmù[R8!k¹ßT÷!÷šÞø»ÆPDÜZ:h_¹cIý¹—‚Á/ä"Üq#–ÚÕÏPD8DÈT4Ü}Õ“ÿb%¢ÎŒt¸¹291#wöš&u§âÄÝç¢ìÉ\FHÚÔ‰×PÇêtͼÇ9šÂ"¬b(š÷ëÑ‚Q9‹·~ Žê3àÔ MR¤Iê"©Ëᇋ{ÌE R“ aã.Æ8=9i:%W>ƒ¶ãYRƳý^lkz1#F:ŒêfÛ\»º£ŠXá|…çš(b]òÂó(ü‡ŠÀâEµô±àˆ?«0T¶-K…á*›?èôû™NSÉÇ©£Žõéð¼Ç8%“˜’iˆV™µH(A®ù¼_O}@U1’Á;Nÿ þý†ÿ›’-H5õý|Ê@Jq!Ç ÚrªP6…s*‚VÒR2ž‘ xåˆ@ÐÚü'4ê•d–j¨6"bn¨²à‹•SìåíË@ ,€(×çbÄÅHÌ„.À¾Ò!èÇ¥àDn@e)žÿþl¬mš÷øŠsrÃØ€.©cS} M¸¢9WõN4Žã­Çÿ¿²åW±!ÙŒÄ눸}C|…@H¨H³ã§(¸"ÆGØwTtQ!ß&™´XD‹s-´ÂýË2Àp½´¢‹1ДùFá¡ÆpUÄÕ@k¿éµ\*÷WÉ ²¯¤G逯p!Z$3‡Î‰.-ࢠ͟ÁaÀÌŸа9D5I±=Ýq,Q%mÁý]œ¡Ó`c\¸¿æBþõZ­¼¤utÕ»ÐUïB=­£–”i‚ºO$‰#M%û¦KU•È¥b>«û+ÐzàŠ¸D Ch͵D/5âj¢Õ¨ÏpÚþ¥²QÎppˆ Nƒ«|p'Û4I}Ïã+’²‹q%îs"¨ikkëç=>'*$H¥†µë®Ò¬ýk{Ý‚#“‡ðGG~ãæ’Ä –Ô&u©¡–ÖÀsšï,„Š‚ÄÔ}î¾y¿^;îÂ7Ç¿†wýSüâ¶^ísVêü[5,Þ*xž#_=JpÞá"µ£7òÿáöb¯jYìˆ)€£•hµ˜‰W‹MåçÀ4£Ô±¸0•%€ê,~Їÿý:êØÙµk^FƒÀèç¾ÂÐÖ¥ wt=}<q¡‹AUñÏg>ƒÿ¦x l¸`øcŠRÈ4q‚A¡l0­”HÏ`2ÅçE¼, #ZT#10?D ChWú®£`EDÄå£'áDKg zÍ•¢¢BzsßÃ5´k“u—=–^î…ÑfÀÕùZ¼¼ÿ{®Ê\ÛA¡øÐ±¿ÆgFþçþoŠ‹ñê€Ì ˆ ˆœÁ7Áèûü?û@Ëg‰Åmü«hUÿ[JÜ–Å„è\cT×h\°—‡¶•átô*×UU<¢ *T¶HîA¶vm¿ìq $ƒ0bš h]»ðìôNÜR¿ýªÎ¹ …âmÿ_ýWä”»\¸'G/‚.‰'I† SÕiâ%lüË@$Y_¢ÐÌæ•V»Æ…1?̨j˜í_“P–V/ÝÚƒmõm—=†ádM çÃ`ÐáU}?€é®«8ãfXµø½ý¿…Ç.<‹¼H‡x_i½ÝdôÑ,µŒÿ¥JªÃýsG$víŒ|øÙ±†›ï‹ˆˆ˜.öRßè¦á6èß×´Žíõ]¥XÐ1œnD5÷ZpRÌG2\›¯Ãkú^‡Lü5žÎæWap)LÚIüæ“ÿ¿»ç-ØZÛ^óªº_“1l™ZkíüRً¾Êì:0ÆÐÿ•!F:„ÙrTq±FD\=Ì=ja„7•lx:"ÂZ¬ÅpmÃe½ï¦Úf¤ZQh>ä[.#åkí:¼¦÷'±§vóÕžr‘lÿó©ßĘkRmÝgfûŒ–ê^Ôê´,å¹,4¢ÐATCþ‹¶¾&"b¢0á4\ {{ò[pú0€guïžók÷š>lO¶lzת¸ÔÛ7lÁš| ~¨ëÇñý=¯F×<;^ O<Š??ü§˜Öé­øÔ"‹ Ñè Zóÿ1÷qmÑLp#OšcG „ÚéÑìî¾iί¹«~=ºÑã¿{e½$10&!1 N0(CxîÁë{ß„mfGGæø©S÷áþÓŸB¦™Wœ)´œÐ.}±ÜN!r:„²ìO|IN©`%EM€ˆˆN¡úsß7õ§:ÌCŒMf3Ö§ëq2;yÉ×½¾ëtiWñûQ%À(T]~:1N ¨G»°ÍîÀOv¿{åQ|~êAœ’K¿ÏåàmÿÛ»¶ãÖ¾ÛaØ h,/¸ýÒEUÕ†@+!ÚÑ Ä@‡0[N²èXkDĵCkþùÜ=1£Oð¬9Dz¹7×nEºÀl@ $Æ%w‰âqíˆ$Ì0&AÊ)úóÜ¡wâ§{~ß[ÿ~ ñÐU›^¦ üöþÿŽ“ù)¨Ø¢]ðrT‰Öí8sCŒt"®Í¦[°@Ð6,䈈ˆÎ!|ÏŠ¯š’×`¸S2û4@žÕ½Ÿ{ð¢¯wsÏmÀP©FèwœÑ@,ŒñßmÆAÙoµèÏq7ž[»ïÀãùcøfö5–ƒW<×S“ø§~ÿíúßB/z&¨éãåaËTyšM âÒˆ€£u‘Ë77±1ƒè£ö¥b KlM¶cC:{oãÙ=w¢GzÝ Ÿœ o ¦‰AbRN$®#ab ’$EjÊN…† jTÇ@6ˆgã.¼®þÓxC×ÏâÖä¤Hg}ÿ¹àÛãßÀÇN~r·ÏTú,\¬Ša¹ÌñZ"F:€Vò_å”9¬¸X#":jÚ ¤îôÏ þg_ºÇÄÈpGï³ñéÑ£m_kO×lãíHàÉ«ìƒ2Íç:fyÕHQq ' 8_…E )›`Ý€Íf^™~/öÉ“x$ÿž¶û ¶c¹Þwô/pÇàspS÷M®^Þ‹!-×Sòr(m\(D Ãp 2䦂CP&‰Ž@DDgá¿oÔ¬ÌTfFwÞƒÛºnÇçùALÈDÓ+0/x)dl‚ônµ ‘3ôlÂD@–Ã÷?ÃÁŠìQ£[{Ðm»q â–ÚíѳxL¾…Góïà”̽Íp¦Þzàñ;»ÿ=Ò&ºlœ€@TÀ+Et:„™Q€’¨ÒÜh!F±ÂPè”ýà ¿aËÆ¬Óa¼ ÿÅø‡sŸjúõ{ú^ˆm؃lŒ2†] ´¨U,Íz@"FÎʳ`D`™aEXU…¨"Õ©¤Ø¨]6ëñâôe8K#x2ß‹ÇòGp$?tIÕÂ'/ìÅgþß»öû‘jR<9ÊvsXŽÍB :F0þDiS»#FS*@ƒ¹ŽzL 'ïÃs{žýÓOaßÔ€íõ¸·÷»0 ƒ0Ih7ì ?³)ZòÂûùR¨(q¯›Y§ÙÏ”#· k-ˆ,˜,ŒwD wÆj4AjlÄ&là xaÏK1гx<gâ@¾Ötâû޾/[ór$ÔW8$Àò0–N˜‹ŸÛɯG\Ñè JcO•Só%""¢Ó(Õ8ƒþ†V*\E{6¿ÅºÆz¼zðGñ¥ô %ÜÓýB¬Ë6À$ ¡³ƒà* B9 Ø}߃$pQe@9|ÜÁwä3`ÊA–¡l`EÀdaI\Õ¨Ê ñ0Vƒ$'¬§ N6âÞú+0‘Œã±éGðHãÛxbêqXØbÖg²3øòÙ/ã%C/ƒ! —n*À»4þ@³ØÓRœÓB":BYšÒ,H"Ø3³IIDDD'à=nr柉 p]òXœ¯0!1 Å–|+^Uÿõ¼©IÊ“~¥±ar)vÝõÙPÂÀ@0àÔñ¬%Y&c`m…jˆXXKu͉D¤w˜°0 1ÖäkñÒ®{ñ’Þ—aš§°/Û‹½SãÑ©‡q²qN|/Zõb0R*ÀK·ð+œúÝ>ÄÔ"®ÑèZ›ÍB1TqmQœ|½¡f&°°Óô7,ÌVA¢ ú¤À‰‹oðc` N±‹¸ï¼‹ø1j¤`ÿ[_uƒXAnóJøŸÁþÚ°ÀŠ‹«O À9a.ÅO XF‚ÝÔ…çu½Ïï}’Ô`“¨¥5À*” *ÂŽKñ¤Ü¾ÁQ$^ ¢Ða”á6  EFDD\KTÃÞŽEîËYÀ⌺X õÛ"Qh9 oôºŸkúã9ž]OžC" ‚Â@=Ÿ‰`CÅ „­«°¹µ> . l€ÀŠ-¤Ã Q)zZ«? ‹T50šb•éF‚ÔG ÁõYê\€jZd)Ž1!:D«ÇDÄCáJâ|$€ÉåðY&¨â!”Cˆ™` ;/ûËà+ ãOÞ¤ %„ÃY01„VØ9^LHDŠ€ˆÀ÷3 Ãe ¢âJ$€|EC¥ÊHD "PVˆºCþTýø–®áŒ"@WÑ語ÀpÄ¿¸P#" 3ª˜aˆ25€ õ‚ð§n'd¼ª_♋¼YßO^nÀ9¡ø×0ATaØ9$Ô䨄F"ÖZ°+ k­;á«ÀZG‚ksc¤p€;ó£²) fæüREà„a)Ïe!€¡ä47®ª!¬X¶q-Q|½@©3àL%vÄ>8*ê»ÍNò׸пKp¡òW¼®6Ë“O„÷r¡xÇ#@B¤ÁñØŸÚ™Ƨ˜ÔE¼á¹"}˜¼Ò_¡8ˆæHˆ °q¯C¼4%Qè­B>jR«£0?D ÃhM” ‚BÈ—é±>GÏ)<ÙËÂ?^°zú9ù*Šû®óŠ:9bG<ä"LÏDPŸ b(‰»­k8§ ó£9¢È”èEŽÚg©£J®®’ÿbC ù!:@+ó?,Ì ËW""…>¤Î¸‡Î}!°2\ÀŸì¹¬ÿgÃE l/LM¯Ðj”ˆC%%()H]ôA}ŸæÈ÷‹ ‰+ ¬8A5°”àq‘Œ¢Ba2ä[ç´çx-€ u!¶»Cÿ×M¥€áT.¥@°¹¾ßßGؘ2rP&Û1Ûa{¦ògx äå—©¸¨€:§À°B„¡FKg€ƒñ÷×â4ª•ÌΉ$G*ƱüŒdÜF¯ ÑèJu* ¹P¸ÝÚ(""âÚÀçüé™(„å]>>4ði2•žmºRÑ\¨,Æ»˜´wA Ðæ¼µú× W.*@ uw2ï®Ì\8P…÷ÞÕ²8çÜ8'€‰ 0³²(ä¸2Å฾ÂÒ´þYÊòÆ ‰ètaÓaDWà A è­FD,Êþ(®|n\|g”§sÿƒ†ßA¨ù§y8õ¥¡ªŽ#´ì­” øg€\[bø2@—ûH«³ÒÄM`Y@t\Âv²ù³ž™b‰ûêÜ€ÃÕ«6ߎ’À §F'ŸÑ¦»Ùû/rµÜï*# :ž2EPäKÅçýƒÃÀLg T1#?¼rÌ•½&üNa(—òÑߣZù8Qx~ˆ@1#ßW!ÕŽ€ …æïå,iò&2o‹¥íð¸F?¼¿;ý£RÐ:ÖòG—Mh&)^Œ°¸ÀŒ²?B4üóFt:„v9þVRQŒDD,,f2[š wÇÅo)#”b¶Ó5ˆNÀå!:@«wÉü—‚ñãzˆˆ˜?ænÔ—Ç^Ó~¾Qb}~ˆ@áehúãh) \ýB.‹ofDDDDGšªÁ¥²Ëjyà‘X^}™àK?%ârÑîô_]{Q 0XnœKåžI3rþ3»¬FÌÑèÊ&@(Nÿ®gwÕ›-x½ 6ΈˆˆˆÅfãl|ØOE¤8ý‡ëˆ¹!:WÉZï«F¬ui€ÿ§Jñòúš;"""bI h§!‚ê€aXkÛòFGÏN_ÓÁ.1DÀBU¦Ó7ó~çæycSJã_’Ë߉ˆˆˆˆph>ñsqÛü<Ï›€j@UíÈÈHÆϹ³!:— "Òp€,ËÏ%Iº¶õyÁ˜ššB­Vƒ`Œñ¯á$:­Ígt ‹N@DDDD0þfS48 ×eÂø· ÿ[›/ÐЗ ¢kt…˜šš<Þz_50>~¾X°å­èt¤ö÷Å|@DDÄÊFØéßEM]è?ìŸ.LùÿàT#ÓÓ£³¼¼‹½R,¿ŠÀENùÃÄÄÄáÙœ;7Ö↗t šÙ ê„ô@t"""VªD?òmŒ*²ù011<Ï‹4@kôôÂ…óÏ,À–b àŠ@zôè3nݺmÆ#a1ž9syž#I’âþ*(I-" À"ðšµÀV½€˜.ˆˆˆXJ˜y°i%AWCýÁðsñ˜ƒBDqæÌ²,k›ÿ€Ó§OŠááu>  `v‹Ü5´¨.pöãÉ/ÕˆBµ¥yDDDÄDØÀOYç_ŒVOþŽõ¯>çoñÌ3'fÿª0==}äsŸûì¹h¬Ì%Õ»\€YP]- ¤êI*=tèà¿ìÙsË p }jjO?}7ܰªâOöêe«­¸ rÏ }®Dì#Tq """"–‚j8…ûJÃOEZ´”R/>vìÆÆÆfÍýÀ±cÏ|®¼Õ\¹µ’ ~+¢bNIÍ2Vkm»…2ƒ=šçÀG?úÁn¼ñ¦7Ó^€ˆpôè ôaxx„Q i9/·¼JEÊ¿13[FDDD,%„í+ÔçWkû«uÿakv"jNPmtt ‡=sÑÓ¿ªæŸúÔ'?é^€4Ï к§¯tg :Íhr€ÂØdeÁhàœ½cÇÎ×´¾`U³zïÞýPqÖZÿEoM•/‚ëy]]ÜÑöGDD,7¸H@8ÜháUUÅèè9ìÝû²þ˜I†>qâă<òÈih…Øç¯§AÄ­{ùŠÅJwfüK¡Ñ€CJ”+`Ô¯ôýïïG~õWí•I’¶}#_ øøãOall»vm…1 ˆÖŠw‚#”|€hô#""–;ª5üÎpUQÎ8|øŽ9Vœü[ˆÈôßü͇ßçöçbã •m ~D¤ìˆY+f¡°€h׉‡††@ªƒ$"¤ªT«)‹¤œeÊÆ(‹°1FYU w 36vÎnÚ´ybÓ¦Í÷\êÇÇ'pòä˜ ==Ý…ºUkW«ò¾rÝV# KÕ–¾@hë+þçòœ>}{÷îÇ©SgŠœÐüo·>ùäÞ~üãÿ ,@–™sÕÜ2“Ís¶Ìjak-[cr9ž…™Õ£õúyu/}M>„E€•¸$œçx@ݧ $þçæË{ÞóçlÙ²í®áááÌözaÑNMMáÉ'àé§`ÍšU@__/ººº$Æ Ì„Ðã¢l)¼bÖgDDÄ2Du/ aÿ<·˜žžÆùó“=‡‘‘QEMe\ IDATdYÖÔíïb-ÇÆÎ=ògöÖ¿¬äÂî½ÄÝn(À˜š"e˜]  åôßJòn½Y!:mqDëÆÆ€înTsFÅÏyNê‘wW}Ç;Þú¿~åW~mKOOÏLu  Â"β 'NœÂÉ“§ ö+3ÃcLE ³¹î?:K­$fkí B_Èï·iðÓö5§§§O¿ûÝïø£,kØ–ƒ™ÀÖ¤ùö¤Ž3ŒqN€1fÙûvˆ@3ôÀè–-¥XDsùÔy“ÅB"ˆµ¤ÌªÖ’œ8qâÂÛßþÖßü…_øw¿ÞÕÕµî¢oÖÌ\-ÂbÖZäyM€S¬ˆˆˆX²¨îuÕûZOøÁø_*í™çÙø>ðÞßÜ·ïÉ3"$D<‡0—‡´ÖÃ[…à+fk°¼•lEª€ê…·lgÙ0gYf¬µ¦»Û&yÞ•Ôj6ÍsI­MRc¤&"5fS‘”Ykªœ2kªªÉ®]7®{ó›áÿîééÝ1çµúv?GDDD,7´:í~n‡©©©SøÀûûk_ûÒ!"ÊD(c–L„Ì”YË clƒ™3kóF’pÖh˜>ãÔ¿"H+9\„°chrrØ@o¯˜,“ÄÚzÒI’¦ÖJ*bRc4‘š1šˆhªjfMT5QUcŒaU5«W¯éùÁ|õ‹®»î†»‡n@üDDDDÌŠññ±ƒO?ýôWî»ïãÿrìØá1€¬,‘XwúG."9å"”9.gÌÖóLfL–e™É˜9¯†ÿ1²Róÿ@4>³EoÚβuœeYÒÛk½ЕÔj6±Vk“4I$pfIUµà¨r £ª€af£ ”UAÛ¶mzîsŸÿ¬íÛ·_?00¸©§§g]š¦ýišö,ć±P°ÖN6‰ÉÉÉÓccçŽ9rdß׿þÕ'žxbï)ÇÚ'_ue%„ýñ§œHrk‘3s挾͘)7Æ4ò<ËŒá<ËLfÌTž¦œŸ?ïÈÆœ–înØt¢°ÂÐú÷@[¶€§§×k-‡jkÕ´DIE4e6©ª¤"šú7†Y  FF•Ù°w©Îj]]=1U±¬‘ç|dddÚßlêµßÐÇ~(‘XâÂþ°D’ÁZK³ ý»Ÿmf gyžåÆpÓéÿ¶ýŸ¦§äèQ´#¢Íõ²CÔphí  èÈè¦M§Du-‰ˆC"¢ÌÌÂ,¢Ê6Ï™ŒQ&YKd ³ÀZ…1ÀªˆQc«*÷„ÊE '`||lr||lòš~  € èoJ«ÔZ«DîôïuX$äü‰ÈŸü ãŸå–™mÈÿ3“%"ažcX˜ùC³ v=–½ñ¢ЊVâ1;ñf–‰ ¥Þ^Ø,›¤é麭ՄTdLJ€`ÉZCÆ0˜e7*«"FT!þôoˆ@"š^“ª’çd’ï£3+ ÖB׊]Õfæ åëTÂø[ka+Æßå¹3úœgYf™I¦§Y˜'…™e|œ|37RcNè‘#í­üÿíÝKoÛ:à3CÊiÐ$«[tÓEþÿ?+ºkÓ&±È™» iѶäGÛ{‘ØçÉŽ»q3>Ä`2×𳩠ðô$v{+æ®y½† ƒË8Žã ¥ƒ”‘³¹{ô¼mfe!XÜÌ‚ÖB`3Ô€²×”;_AÌöŸÅ]š½«îz+ô¶—ëXÎ¥)ãÿ%ìÅJøK®Wþ5ü%ã:‡ Ý4‡ ‡®þïxÉX,ߨQ¶Æ—/ð‚™™@ŒžÝŸ¸Í!¸†”FÄ8  ÷ìfÑB°v'`s‡†`*âÙ )sJP—¢Î ØÅB€ˆÞ»™[òN-÷r€¾ÈÖ¶a¯aoªeù_J’kË?‰hV•TÇýSš^_5‡ðœCP{zR Aí„«ÿ«hÿ ”FvÎ÷–¶mBàÇR²`vʪ f͆£EwfÝcp÷c¹…pÙ<È5FtáïýDÀúY¦-Š"¢wm þÜžêÆÿ§¹)•ñÿr–©IID6ãýõÊ?©J^¯CR}ÉàééI¬Ÿø·ZÁfþcæx±Ø(æº[óV+ð À'¸»üü |ü¤ôŒ××rs”ÿK£ç¼òÍw÷œÝ=䃻çK`V––÷qw‰±_ `›à?p+DôÖ Òö›×¦´¹IO»ñš«Ê¦HIL$Y™ÜW&û£dÕ±µýÓë«fÕ—‚ä§§ýÖ ÿ«ü×0@&K] [8ŽÐœÿÙtîî\['ÀÌÂjeÁ̃™…aX…öÁ½tˆ{Üt°×ð­ï„WÿDt©ºÖ{f¯ÚÝüL$Y·" «jǵ•!XšûðÿõK³ªZYól¾Zmý[óÏà ÉÌq÷N2ŽŸ[°[¨™…› fSð¯V«¾Pwˆ»w+âVÁQVÃÀ€ˆ.—|Û¹ôáë"©›Pö¨óLDl×µS•üjªÏ9FÝ\ùdzˆx·æÿXë÷üb1\¶ÍuúóÙ"ÀÌôîÎ4%¯Áÿ!¸»ÞÜXkõ«™àF†¡ý&@›°Y8û™ˆˆ.É&hû u¦aq±õ.²¶º - ž­ÍöŸ ÿ™qÿöþW³÷ÿ.†Ë¾CCý.2ŽŸÕÌ$¥Ü]rÎáþRº®î·Ú vÕ?]€Y­Jø·‚ ½ñN°û¹ˆˆÞ³­íÂÀ¦åq^w X[ßߺe¿X ÿi³ŸòóÕg®üÛg¸ÊÖÃP™·4П×NÔì“´N€»ËÝiÎÓD?÷[m›þtÅ@¿ 0ú`¹À» Ñ%h;ÿÎwÚã¶`;y+Ÿ[ÀBûñ£lØ6MøûæÃë–û ÿÝó‹Ç`Þ\ÏÀz]–º»˜™ô…€;$g¯¿»UÔ ü|«åßùÏtˆˆ.JõßO ¬aßRw|¶VôÁ_Ö÷k-U8Ãÿ0̲S‹y|„¤4 ìî.÷÷¥Õߊ „½ûíÒ•?–ž#"º;íÿ¹Ïý|€Mèÿ´Ðïƒ_U}¾ZŒ{Kýþ3.‡-í¸57àñ(…@h…@+úŸ‡Ôm§b øDtZø·ÐWÝ àÇÙtÚªÖã7¡Ü{¥»êgøÁ°9îXÐŽ}G)•=ýsþ,}W`ºúŸ?¶ó‡‡ÿìßCDô¦|ÿ^ŽS°}lç}è@ þ:Ã8mm?ÿbpš¥ey²ðx¯€V Sà·ÇýsK‰ˆ.Í!¨êV! ªÂ×z¯­~àpè/þU‡?ÀàKËòví|o¨`· JQlDD׬?ôµÅ,·÷ÃWýs¯Cç|ç‹ÇÇÇé…)í3·&"º(-ØwÅXž¯WøÀy-ýCWú ÿŠó{mÒsh¿¹"aîñ©¿#"zÏ…ñ¡à>÷üØ{]%†ËŸ™ûûZ {þÜ×½'§òÒkÎ zÿËßq¬8÷9"":­Xzƒÿ†Ïßõ»­|~DDÛÎ8õwÔaðüwNýÛò; "Zö'CtÃçÿÿ5ÑßÁÀÿ Jo ¿""<½Iÿ¸¸=JÂIEND®B`‚olive-continuous/app/packaging/linux/icons/512x512/org.olivevideoeditor.Olive.png000066400000000000000000002432771370472574300302650ustar00rootroot00000000000000‰PNG  IHDRôxÔú pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF;êIDATxÚì]wœUòÿ¾×=aó.l$ H0€#fÄtêéyz˜õ §þ¼3bN§ç™=ÏœõÌŠˆ@”œ3»Ë.lÞ™î÷û£Óëžî »3_ͧwgzºgzº_¿ªúVÕ·c B„"Dˆž%Tœ!B„"DB„"Dˆa"Dˆ!B„ Dˆ!B„€!B„"DB„"Dˆa"Dˆ!B„ Dˆ!B„€!B„"DB„"Dˆa"Dˆ!B„ Dˆ!B„€!B„"DB„"Dˆa"Dˆ!B„ Dˆ!B„€!B„"DB„"Dˆ0„"Dˆ!Â"Dˆ!B„tS‘Û²3!DœA!í!b  éJÂÄ)’öAÆÚ>Ìdq…tåN’|-DH{*x–‚Ï"¤k!B„¤HÑ—ç^Jž´Bé AHº4óøëYŒ1) !ÂÒ-•},%Nb¼ORlÒVà –Âg1¶eq>‹£@ˆ0„t'eï¦èI‚¯½¶h€Îæõ3%ÏblkaéÞÀ;ï¼#®B’iÓ¦ÅRøñ7õPô^ ?ÿùÏÅ&L˜™™9  –$©”RZ(IR!$‹’ @Ò „I(~!m4T¦e[Eô¥…1ÖÄkP¥FUÕ튢lknn^ÓØØ¸~þüùóŸyæ™ ïµÛ©IÄ1 ƒ kΧë½µ%“0UÂè6 ßí5u(~çB`øðáÁóÏ?RïÞ½÷ »É²‰á½;•¼Sñ›ÿo¼ñÆQC‡=: î%Ëò`BH!!$ëx|>rrr‘‘¿ßŸÏY–!I(¥ ”šcÒ—¢LUH 4¹ùŸ1UU¡ª*EA$A8F(BSSZZZPWW‡p8ï3›cÛ#‘Èšæææ׬YóñÍ7ßü§ðUCÀ %ðÊ1Æ€0„ ¤ÍJ?žWOÝþ_zé¥ý÷ØcS222öóù|#!p!Ÿ"„ 77¹¹¹ÈÌÌD0„ßï‡,˦b"¤+‰ªªˆD"…BhiiACCjkkQ[[ë5q«Œ±ápxYSSÓÜ ¼ùàƒ®s1˜‡A &‚c@Â’ŒÒwƒïuÿzæÌ™ã‡ rZ0Ü—R:P‡ïm’™™‰¼¼<ôêÕ ðù|BÉ éqÆA8FSSª««Q[[‹††· >¤ªêºæææïW¯^ýÒ7Þ¸PWô†²W\ ‚XH0„ ¡ô“RúnÞ=@/ºè¢~“'O>'33ó0JéPBˆ-©4 77ÅÅÅÈÊÊ‚,Ë–"Äc2D"hhh@ee%jkkÑÜÜìÜ&¢ªêêÆÆÆÙßÿý}ôÑMœAJ Œa@(ý¤”¾my衇¦–––þÉçóíEÉá?0;;ÛTø³"¤HAss3ÊËËQ[[‹úúz§¨ ‡Ã?nÛ¶í…Ë.»ì#‡1  c@Š?–Òéáë‹ôøãŸRXXx®,Ë£Á•Žúý~äåå¡´´999»"$Í(A]]¶mÛ†šš„B!þíH$ù½ªªê¹óÏ?ÿehá5„ÀÓ†€0„Ðý¼}g,ßm‘~øáJJJÎóù|cy¥Ÿ››‹^½z¡¤¤²,x¤„é(‰D"(//7óø·Âáð¢òòò'/¹ä’·=ŒÞeˆ€0º™·Oc(~ }ðÁèÓ§Ï¥>ŸozfYYÙ „ùäEEE×B‚PTT„ÁƒC’¤.yêÂuØ\·åuå¨j¬Âކ¨i¨¢*æx"”ØÇ—‡â'„ăü{„V+s?a0t„%Òíã~>Œš¹—*S£Œã9S™ýµn$0Æ Q ùYùè•Ý …Y…(Í)E¿Ü~ÈõçvÉË£( Ö¬YƒÊÊJã·6WVVÞ}Þyç=®NCÀ«%q4„Ð €^?÷¿ ½oì^{íõ¼$Ie——‡Áƒw9ºÞ­ [±¦z 6ìØ€êÚj4†MÅM(qõìmŠ]?S®Æ¢¯``žH€çX%í{³ édÈKì:»yþªªÚßgDÀñš_ 〩ֺL&Šr‹0 ÷ í5}rút©óÚÔÔ„5kÖ ¦¦Æ8?[çÍ›wÖÝwß½HWþX!˜ažd  $ùEÁý999þÇ{ìŸÙÙÙ' ]­¤¯EiÁÚk±ªj6VmD}s½MÙ›JžêÿA¢?§ð׌±(ÀŒ°˜ÞR%i÷(¤k  £Ì0CNÅïDômT¦Ú•¿±^Umë˜Ê **r2s0°p † Â!H]ƒ¹ÓQ:ÈÞºà‚ .¯«« !~X Ç%  ›Ixý¦ò¿ãŽ;¦ì¶Ûne}¥¥¥D uÚìþÂÚšµXZ±kËׂ¦)pp Ÿ:¼^áS.ÎÎ0ПJÙ5 àTÚ.ñþD•¿±mJ }èZh@ŠŒg^oØuŠµÎøL¦D#ŠªDç¨v@Q0•€`×’]1ºl4†äwÞ0ÁÆQYY‰––0ƚׯ_ùå—_þ.€pOG„ÐM åo4î‘ܼþììlÿ“O>ùtffæá€•ä ;Ýo«h,Ç’íK±tó4…›@(¥”ð>¡!DïJA(´÷´×œ²‡©ä £€XÏá pUüÄM±kŸ+Dm5Þ e5á2£€ÙѾ2€1f2 ±½®à¡­SUÅÚΘªj¯Í÷´|¦¨ÈôgbÌ.c1ºd4ʲÊ:ݵinn¶% 666Î>ï¼óέ¯¯y Šq º³ €.n$P×åõ_}õÕc&Ožü¥´Àï÷£OŸ>(+ë\7­ñÿ¶õ7l©Ú¢)m PB£½}cáÓë'Ú>¦GOá™ôG`AüFˆÀ<“ncޏÇúyE*˜?Ñω‚ÀHqhÀµ2ÌæŸòÛ¨Lµ<£ZÀi¨ÌÜÎða>A ˜Ï ã@q *Ã.…»`B¿ œ?ÙþìNum¶nÝŠ-[¶  AUÕóæÍûÃÝwßý«Ðíy„Ð… €8”×À÷ßÿþ÷º^½z]€±þÎTÚWÞXŽß+~Dz-KŠ„@$MIS‰ê œ˜ž¿õkHˆ¶ÞPðÎR?Ëë7`| ìH€õsÊÝ‘ñoSú.¡€˜@;!Âèúƒñç:8”¼îÕëo˜ž¿f¨P €1›×Ï<þ«*cªößPø ³½VE3A9ˆ1»ŒÅîe»£4«´Óœo£dPÏ P«««=çœsîÔQ€0¼sº €.jx@þ.¥}äc=¶ä¬³ÎzËçó €’’’N•῱n#æo™ÕÛV[Þ¾¤Aý¶¤>N¡›IÜs#Gl5ÿœBçóÜjýmy ®H€W}¢ ¸=…1ÐZ=¹ësŒÁà ¯yÀYh ŒÙQge÷ƒÁ̈…ðÿUÅ2Fô½ûï¹:Í%Z³f ÊËËápxÕóÏ?âûï¿_w!×Á®n  åï¬í—Êßw÷Ýw>lذ'!œœôïß¹¹£”gYõ2Ìß2[«¶‚JÔRüÔO%j*y˜1~bËú7ÖG)}p°?ûìt# [‡„ÐE €ÊŸÏò7býòˆ#²o½õÖ÷|>ßH s@þ á,©Z‚Ÿ×ýŒ¦P“Ý»—,ØÞ¦ø%ò××Ûüœµÿ Vy q¯ûCÄ;ë?ªÌxÇøI¢~â=ù éÙAB(àÙ((*4à°å 0pã°•º”B…ÿ7’9ø_U,À7TU«Øoè~[2¶Ã9!¥7Üpñ˖-«‡ˆÀ^%Ðåat Áx¿™èwÉ%—Œ8äCÞ&„äåää`àÀÈÎî¸lÜ¢ŠE˜·nZB-QŠŸ‡ô­d?Ø '`Sþp°ý9žŠÙ/Ô>~b5ÿñJâ3Æ­-híØ@wÖï‰7JØPðêèæõsž?`˜Jßa$DeýyŠÈY`ËP¸Åp¾Îðg`ÿ]÷ÇÄÒ‰ðK×θ¡¡k×®5BµŸ}öÙ´‡~x‡8Ñ€. €NnÄQþ¶ò>¾ûï¿úàÁƒ$„H¡¶iõR|µò+4´4˜ ß©Øy#Àß—ˆ• à’hKôãB6ŽDÇøù@”¢·ésw &‹_+‡d,%!» ÒO0¶ß” –çˈZï’è4 %Ïçð%‚|R “5ÐðþÝBªªšˆ*È æâ aaBé„»vS¡ÐÐ ¿Ó;OÅgª,©ï2·ç{¸U x!.‹>à¸ÜÂ<à†8=çkà Ø{ÈÞØ§ÿ>(´û5¬©©ÁŠ+‰DÐÒÒòû%—\r|eee#ìy*ÜÙ;5 €Nd$éoKö;ôÐC‹/¼ðÂO$I*ÉÎÎÆ!C:¤ƒßÏå?cˆ¨SÁÛ¼}ò—íŠßØ®™ÿ¶D?GÜŸoÜêwC<³ýI|8>»Ÿðæ…¤c²ôBÜò ¼ yU $j¸­s­0š )Š=qPGE±¡LeP#v¥oò èë}Ô‡CGŠÉ}'·ûõkllÄêÕ«Q__EQÊ{ì±#æÌ™S÷äÀ.S! €Nb$ üepÉ~^xán‡~ø{„ÌŽ¢ô]_·Ÿ­˜ƒêÆj݃§ º—O$ jÄõ%¦WSò† Ó÷J¼wo¬çúð±~óš½Ñ¼½~ãD:ù±ƒã?–Çï6ölTÀ‚pGHš BËË7Wx—Wà ØÙùíã’98Usx£stºaSÉsôÁº²·52rfxÿªö\3TÝh(Î)ÆÑ£Áà¼ö sòÂŒ±ÆÙ³g÷Øc-…=90Ò•Œat ‰L?ßW\1þ€ø!ÄWPP€AƒÁïo¿Ò™‹à« _aþúùdÉ‚ú9hßæå»Aýœâ7×9 ~¾~ŸOüsËæw&ÿ™™ú$Zá»¶ð%ö 4©D?áý iÏ1Á/-ôB\» 2÷ç^F@Tƒ9 6¨ßÆ D‡<Ã*Sµ\=?@‰(Øgè>8lÈaðÑö#6 …BX»v-vìØÆXøë¯¿žþÀ,Ð €ºX…€0:ØHPùÌ~þ믿~¿‰'¾H‘Š‹‹1hРv¯Ü¹Ÿ­ü õÍõÜ/Q÷¸¿G½?_æÇ+~3ÉÏ«¡_Öǰ×ô»*ÿ8ž¿ñ?jbM˜Û‡¤n¢¡ÿî§üSˆÅçûlJ.Šßà °qxÌ­;k ÕHHu5ÌÄ@½œP‰(öÜ=,›™‹cG‹½G´ß5e k×®EEEcÊ/¿üòÇÛn»m®n8)„;µ €4’Uþ·ß~ûá£Fz€d”ùµ›å«†ðÉšO°ló2PÙŠóSÙRøn¥~¦1 ¹+~'Ï¿Ñò׋Ê×Éëo°3õÙ¶I¤‰¯¹‹­¤…ç/¤=Ñ D½zÀF¼¦B¼1` fx@µñ•6Ä€Sü|ˆÀ0f|ìß¶Nõ6ŒçãŒÃñ#ŽoW!®LPY¼xñyÿøÇ?fw5#@d$¨üÍÿ{ï½wÚ®»îú/´½•ÿŠ+ðÙŠÏPßb÷ú©¤ÔÏ'ó9 £ÆßÆÀ•öŠÜÖЇØ!7¸ß-‘Ï©ôIÜódõc©ŸìE†¿Pü©šDc~,ö@x— º<@¢I‚`ZÂpóøù^P`…X´òB 4 #ÇŒ># Gv„ ®\¹ò¯W_}õ;pç è”F€0:ÀHBùûø|ðÁÓx'RRR‚AƒµÛ±~¸úC,Þ¸ØæõK²H€$IÑð¿KÝ¿Éá¯{÷|ˆÀµ‰ƒÞ7ÊËw{íåý{(|ç{1'm{ì ï_H{ƒX@Üãðh"äe08slëTGˆ@uÐ CÏüçªTU5ûؼ}G8€ç0‰ƒ8ž#'Ài L4'Ž<±Ý®ÅÚµk ®¶nݺë.¿üò—9$ SÂhg ÊÿÌÞÖÞÊ¿ª¹ ,ÿ•5•ÑÊ^¶àä/×ÓûwüØbýÔ"ô‰JôsÔûg.^f<¥ŸÈ„«ÁPüB:ãH†y0Vƒ!7®€¨¼.©Ð­JÀLú3ª8Øß“<ˆçPôò@7ÆÀ°öß(5䂲‚2œ4ö$”d–t„pÃå—_þ|W0„ÐŽ@²Êÿþûï?uÈ!÷´·òŸ_ñ ¾ZùUѼ}J ÉziŸä„û EïîõÉ*å³?ÑÖ™Š_S³–â7ŒD•ú9=o0°¤I|œx¢ýX ·"”}ºÓ“E±ù¼Pƒ¨öÂ`m…µr@ `Ì£ÿZe`;1ë:}Q"ªV:V  GŽ> “úMjw#`õêÕÿwÕUW½ÒÙ€Ž6ä:—ÄUþ÷ÜsÏôŽPþ¯þ¿múMSæ>ISú”‚ÈÄæõóÿv¶?NñS÷V¾|f¿ òçcý¥ÖÙ²1ú93÷í¨Ôq¡R;œŸÝ-СÜ;×ïpç©`ÞÞ•;€a&¢­'–á̬wµ{OUõ[•*¨~§ª‘ˆ¶N¿{)ÑÚxk_¥½V‰ ¨6Q¢9 ƒ ÃQÐXÿ}RU"*Þûõ=l©Ý‚é#§§ýÜstyy92dÈ]÷Þ{oøê«¯~ÓcsU?Lµ'{ =páö§^ÊÿÆoI3xCA¦Ñ•`” {© ñ\ÈÀ0 „ÁvèuqØû¢òR¤üõ)­Ã'ÿDB„ð÷DÜFVŽŽ›nëù{Ôíþ5î}³Û'O æhf:ŽÅ6s•l½6·á¶—|ÖT¬ÁÃß?Œš–švAJJJ€Ž7îÉ+¯¼rOè$núbÌûÔ9s9ÂÄÝ^º}ÀCùóì~fÿŒ3vÛÿý_%„Pƒä'ݲ©~f­š…õ;l \’%{ó™Ø 7Æ?£N߆ðI~v¨ŸÚ•¸ 5*›ß„ù sET¢&4ÉÅUÒ­Ô‰í­L…ò’ʱaÛ‡$àÙ9*fÌmɸ&R@`z÷ avÂ,ˆ……ªzø€Z¾1%T«" Ösƒ'DU´ùB"TªæsF%PˆªO4[k¶â™ŸŸÁ cNÀ€Üi7c¨¨¨ ûï¿ÿkuuuG?õÔSK=f…¿$Ó¦M#]¡•°0Wþ€wcßÁ\zÔQG½MñµWÿüòù˜½t¶–áï¢ü%*ÙÙ°Â|(€×n:¤[J·Lô(÷sÒûúåõ×_ÿÄï÷ÍÍÍÅСCáó¥·¹Å{«ÞÃÒ-K£=ŸdKü3có ñÛÚôrñ}þ¦çý\¹û]Êú\;ô%@»ÛM{%XéI BH×¾®IÀ|7ÁxÛ¸0 F•ªî½lÔÁŠ£Ó ×fØxßFáȃ"Ök%̽¯' Ž0§Ž>5­×(cÕªU¨­­E(ZuÊ)§-)ÐXœ´ÁíV(ÊÓlàpÊŸ÷þͤ¿—^zéY¿ß?4''ƒ J»òséXS¹²,™m{%Ÿ°§Ãÿ²Ñº7ÁŽ~”Ú÷˜ @ ̳E¯Ñ¹/ÅoL<¤  Uª”¢}Ò HÙ§ âáî©üÛûºÚJo½€KˆÏìÒ©àrÕBfÈP)Uõ0Õ01•€B%*˜^Z¨å iÿu& A¨¢•j!Em½JuZÕàÂõ ÑjŸ&œ¶sæóù0hÐ ¬Y³uuuC_zé¥çÏ8㌳\pBþy(ìv!GÒŸ³Ö_æ ÿO·HD'ÓIÉdɶªq—P=$@dcǶܼFeŠe[—ã韟NëÜ 1hÐ deeíûÄO\Ã…dDWÿ»u(€vcåïVïo*ÿ;ï¼sZIIÉù€–,’‘‘‘Öc{ù÷—±¾j½ 3âgüsgŽIÕ«¯7šùðM}œ<þƒ0ÛüÀÀÀ¨µÎÖ\ŸŒÕ(56jüMO_æ c~â¼{~ÓP‰dHç:YWµ|ÿHb ‰­”’’‚"tÒI¯—••eñ:¡;ºue@wËð¢ù5.làþûï^’¤üÜÜÜ´–û©LÅs¿=‡­5[íÊÞgøæã³JþˆD 6–.Ã80!7Þ8 ™‡QÎgSò°+y7Ö>WÅï2‘$2I&;‘&<ùÅQúBáwÝÖGO9^÷¯›!`[Ë10 ÓàB’Æ,K$bSøNƒÀXÏÏqæ:~.ôYsä†ê xä‡GQ#i›Ÿ „ÜÜ\H’”ÿý÷? à‘@Û†  =ãþnõþôxì±Ç®ÈÌÌœ˜‘‘AƒYxä¹EÏ¡|g¹ sIFv¿Ä•úq‹$IQÄ?übÀý”èõý•'ìD?”põýv ù? 6g\6¹ ‹Þ†ÅɺKd›6íëô”\â¢í±ˆ¸xzcÛ=yIÕ9 z¯Ûýl{ Ç6†b V¨€nÌ+¶¹È9GñüºcÌoFˆ€ç0æDs½L±©j›÷Xú¥4h222™™9ññÇÿ›nð9N~€n—@»‰òwóþmÿ×]wÝ”²²² Œ¸:3þŸ]ô,ÊkÊÍØ¡¡YÀüå€Â%¦ulK²‘¬€a™Ðo­›ïÃóÛ¼¸ßðŠby éðú[ ÿÛ²:Èû~ºx¤ ýèD€haÛ6±Ð#QPGÌ0¤¦4ç,.tióüebƒý‰¬¡&ê©#›ª6áßßÿ;mót04óJKKg\wÝuS€ì…t#€våïÖÚ׬÷ßÿýKöÚk¯Gâââ´&ý=÷Ûsغs«wéŠ]òI¶ÌH°+|ý9ñû›q}rãMB‰ífå½[ÀMù·vRjRLV™¦Ré Å.=Mù'•àœ3Œ|Ýá03ÿù0%Qó‘-CÀ UÊVXÀTüz(–Ã$YFÁƪxdÞ#iM ,..²×^{=²ÿþû—Àâ‰ñ*ì6F@wÈð*÷3ãþ—^zé „AAAZãþ/.~[vl±²^©•ùJ(±!NÚL3ÖïÒ¡ËÖà‡ËÚ·ñü{úxD¯œÍ~Z“©œ_x¿5"ºð é ÒãÒVä1›ºµýæ+‹œs³:ÀÖyT²S ó9Q<͹1G¡ÃqZ_¹ÿ”¾ê€Aƒ¡  „ÿ¥—^ú¢#@îÎù]’ 0Ù­½ïc=ö7¿ß?Ä`úK—¼²ôl¨Ú`y÷†W¯[·&üO-ë×LæÓ‡£ÌTøŒrÙýÆkÞÜáà:[ÒàÙÁÏ©ü½&žÖ(öT © ¶LÅñ ÒÆ_"Ÿ“2˜°Øl‚”ËÍ!ÑŸiÌ/nC<Ï4:aèsttSÏ' L€B + >bæ%0Æ@ÁªòUxêç§0ci3"‘êêê?öØc»ð ïÅè\Œ~‰]¾s`—C\âþ€ÙÏ_þò—1eeeç@¿~ýÒFóû¿ÿÃÚʵv"=ÖEˆ•Ksjð¥7<‡¿-ææøÕæ‹ÔÇôžáM ãô°c%bµ…°'òOx?…ä-‚èG,M ”êñ—ªÏ±!nn•6Î9Ž^NÃÀ…4ÈœÛx3Âå8Êœm$iÜ{˶.Ë¿¾˜–9Üçó¡_¿~€²²²sg̘1Þ$A¶_Þ•C]9À·÷ŠûƒÁà‘Gù Z\\Œœœœ´Ü䟬û˶.³e·í|ÍF>²ž1k$¿PG?b‡Í¨DÍ¾ÜÆÍbdÜÚxüAlÆAB„>)ò0â½—h­³ce«¸{Ô/¤µÐ{GÕúwºÉ43$@ˆÕúל£`oQÎwäÉÌl•N7GR{X€'F“$mn]°~Þ]önZæòœœ#€N:õé –)î– u—P@— ¸@ÿ^qÿ“O>ùoI’òrrrÌLÏTË÷[¿ÇÏë¶×º:¬V*s ^²ShÊŸ·Œá$3vímð=s Ìýæöz/ÕŠ?éÏm…²ïŠp­!1&ãÞ“.!ç:Ï×úÜc„ls ?ÓÜÐá~¦hð¿0½ÄP¦ôoÌ¡L{M™Ö˜è«_!/˜‡˜òs;pà@455¡®®.ïÉ'Ÿü÷Ygu!¬ªÃUAWtÀ£ä¸Aÿ3gÎ<&77÷`ŸÏ—6å¿¡~>_ñ¹'&ÏóO$­ Ð,ç“4² '™Ÿbb+Ë!örW¦>RŸ¨ðAïÇ+9V¦|¢Yô6¸1§šÈ}qŒxˆj³ f¹  ¹˜snŠJËæÜ4~®3ó¥$U%`cä,ª!©ïþú.Öì\“–¹}àÀðù|ÈÍÍ=xæÌ™Çx„¢èÔºb( +†Ü’þL®ÿ]vÙ%g̘1w豜´4ùÙÙ²¯üØq9a}~±‘øPø‚Ïž5Ÿ;³kaü˜ÿ™eƒ:_»‘ú$C4âõ^¬õÉ—Deõ'@´“j¢ÑÒN,]• ¨=ǯÛÜkîq›«œóš±˜$A„˜ä@6â3n>u]ôíÞ\ô&ª›«S>¿gdd ¬¬ 0f̘;vÙe—D÷ p- @ú¡¯F—¿B¹¹¹(--MËñ¼±ô TÕWiä>’ƒæÒA|afý;¸ümÝ œ&úU‰òüú~æÎãÏ{N+¾5|¼}Z]óïðþ[ëuwE¯]v}tZäŽàà=ú˜ýˆ½·ˆ9w9Ý5n±!|ù lçE±‘té: P^SŽg~~&-s|ii)rssA Üyçÿæ €X» @»òýËüW_}õþÙÙÙû´Aÿ/.yu–§/G7ô1±AèÃ6>mþ†àšùx*8”‚Œ~±&Ö*øDB ®JŸµ’ (“»PH¢·€0^¢ <‰G¸ Ž`ä>ñFO,d,¶÷]º}ˆL°yÇæ´q 8@ÙÙÙû^}õÕûëF€ÜB]) x@ÿ20 Nš4é~(,,L ÕïW›¾Äºíë É”³P*Ê߬Úb PB@LÆ,k :_#i†@[§¿gBmükG¢–©ËÚ”´×æÚb·ÌþV$0µg­´!ÝWXJ¶!ă§ƒ8Þ£Qõ¤e¦Ó”ë•óLe ”@µ5(´uÙ)cÚT¯ÂzMeUÕæZÆ`ò Ë·.Çì5ŸàðÁG¤ỗAbóæÍ˜4iÒýÁ`pßææfZâŸñŸÂ kM8H ëß„þ}ôÑÛ%IÊÉÉÉAß¾}S~,ëêÖáëUßèYû|Ü_¡`4Å0môÿDsõ³Þ_ˇeÆÆeòé*] ½1mq¾f P³Þcîï¹­w{ÏkûxûÅ|Ö{‰~~¼íbíç\’ù±ˆE,Þ‹ÛÃ7W9_;þƒhÏ ÑçAs.$ „ÚçJÉš?µ<*m$Ê5T3æÙ}ŒÕ;W§|ÞïÛ·/rrr IRΣ>zGœP@—kÔU’bBÿþóŸG÷êÕë¶IyÒ_h'>Zñ‘òçø®m™¬’ÕÃÆm´ìå[ú:úm;[õÚšù 6ìŸ h?¬ßªê€øû;S(@ÀÏ&y$N>€#L`Ë €=GÀ6·Q{s!çœÈ·6ç ñs,ß'…¯x}áë¨j®JK(zõêuô¹çž;&ÑP€0RŸøýðuÔQÿ†Þè'Yÿo,yU UV9—Ðç,S1ãü4:¦eSüÜ a»¹øGÿõŒ±”(ÿÖ(ùdiÜ“ÌÞ¾PN"ÆßÝ®i‡$º4r-¤†v¦@íÊÞÖAU²ç”×–ãÙŸŸMùüŸ‘‘a6 š:uª‘èG49P—K¤]Dù;YÿLèÿŸÿüçŸ}>_iºÞ^õ6¶Öl5“NlìURtã×&\¹ ê—Ú›ù˜Œ[ü¯gÑ6¥=æŸ\ÌÛ+îïÅȶâ6îI†!-•ljݱMHGGÔ;?`{|wÂÌÄ1·ÁA¬«L[³3n•dɦäÍÒjÙ‘¨ÏǪ6àåß^N ““ŸÏWòÀüÅ p²v# ³'Æêôç8p`î Aƒ.–’¿ÅÕ‹ñëÆ_Mj_wµƒÁϦÐ`þ\…j«õ7§Éð‹±bgÜr93ñnº×ÇŸŠÉ(UÊ^ˆÎd,ÄžÜH»§ç~,1–N/VÀ¨ýç8úðM‚Ìc®s¦­¯€ªÏ½*‰bd*•(˜ÊðÃê0²x$v/Ù=¥ç¶´´uuu8pàÅ|eݺu ´d@EÿÅÆæ}ÐèŸÂ…ïæÌ™÷B|yyyÈÏÏO)/ts¤³V̲ÅümdËOPaX«&Ç?géÚš`Äðücuê3ÏL%ÞĬ×ßZ?]ž¾ðä…tw4¡5Ÿ“r÷+Îû¶yÌeß($€F#^Ž”Y•#20gKu xë×·ÐnJ©NÈÏÏG^^!¾™3gÞ÷>]Š 3'ºAÿ&üòÉ'ïš››» 0 å_þÞê÷PßRoƒüm±}êhìÃóûS;BŒòw£îMFù'²>¯ßKù·Vñ§Jé ÒÓ „TÞ ž~[öÕWSBíF‰m!Sg8Àé€ÙŒ=)Ûx]ÓTƒ×~-å×ÄÐ5¹¹¹ûzê©Ãp†ÐFïß°ªle'žxâ}Haa!@Jc鎥X²u‰-ÖdD™Ø3ùe]y:ý˜Q×ï´]þŒä™¸ä;¤í |^Û%“àך~­M¢Iuâ!çá5Å" rí5§w€­Uº£ÈÎVi¥Wˆ¬á‹S‰bþúùXT¹(¥º! ¨¨È 'œp¢ËyÕéQ€Îš«ìÏwõÕW ‡fgg§<ñ/¬†ññŠ-OŸXŒ~6+U¢Q¬~6ïž׎~f|ßóêò爥B 25aÏ?Ñ0@¢p²¨C¢ï§j!B„´qðºÏYœíø9JUÞϘólû Ú&Tó3fu Ôç`£k i¨VnTàÍ…obÄÁ#à—ü)Eššš`èµ×^;åî»ïþ@ö|•ûvBë4@|ÿfÙß^{íu#“Ò㘽þÔ5×jì}zÇ*­ •ÅêG‰ÅìGˆÎæG‰Éìg°ü0µé¬~<ßq‡h~®±ÞÑ€¶-3I§ì‹ÛúDÖ%¼óþ^¯cJäýTí#±ˆ¥ó,ü¼fï.ýžm.$Ü|©/„cKµÍ±úœK$Øçe[ v€J5;ñîòwSë‚üü|À{ìq#ìe2Ü;¼tJ 3æ¸Õý›ðÿÍ7ß|œÏç+ÌÎÎFŸ>}RúÅ«ëVã§õ?ƒÈë•øì "ë£O"vÆ*¡ŠPƒé`&Ë•ù_gÂ2þ3“0gó-ƒQËØÖeÑ™b®Suµšô6“^‚ßë³â-­ÙG,bKÇ,±æ$¯÷mŽãç>~[“UÒØA‰m5çXÉ` Ô·3æbɘ³d@IÛG&øfÅ7X±cEJuEYY²³³áóù gΜy<¼;u.@§0ôþeþ1cÆ\½{÷NùqÌZ9Ë*óãù˜±&gG?¡Ea±ƒèÇÈ0ba*Tׯ>fé AÂq{¯X~«¶iCœ¿5ñ}YñèÄ’üû®óš‘@íl‚f4QÛ\j2§ê!W¾›I$älÂ&¼ñë)×………€Q£F]é@ºL·@¹$NÎ#óßûí·Ÿ,IR~vv¶ÁÌ”2ùnÛw¨¬­ÔZNrå}NÒ3Þä(ï‹•÷éŒ÷ó?æº(„ØjhÛßOús’hâ“lÌ^Äø…éžyÎ÷lÏáÎ!`ä@ÅœYa„Yy¶9šÏPˆª%doݱŸ¯ÿ88e窨¨Û·oG}}}þí·ß~Ê?þñ—ô€ˆ®·]?J@lï.ð¿™ù?bĈKŒŸJ©hªÀœ•sÌlR¾´ÏÆ>E¹„?b¯Y2øº~x°üyÆ@Hë”v”¿­¤ˆy¬wùŒÖÔ+ "¤kK¢¹W±¶se ·Žrs*7Ç:2gY¶“5Ðàryoá{ØÒ°%¥çÁÐE#FŒ¸îì€Ô¡Û: Й7ïßÌü¿ûî»Ï$)7;;Û„^R%_oú*S­Ì~Ž¢Òö\"v¨ßAüèÌä繓åÏÙ<’§÷5ÂéPþq?ƒ¥ÞëJ_ˆî…DmËb¯w«p{Ÿ+láÆ¢‰v ßÚ`ŠÑÛJÌ|¥¨ÌY5g;+eç«°°•••¨¯¯Ï½ûî»ÿxíµ×> ¬ë-¥³£m$âýûø†z”””¤ôÖ֭Ţ͋´¸¾Ä &Þ 1býÔ^ÛϨ®ðM-u®|ÙŸi=è]BéPú¡ÔO B„t%—?í7qPü2Çzââ\8Þ3Ö™¹QF~€a(¨\‘%Íìʬ<ã9·þ‡5?`RÿIV0,e§¦¤¤õõõ:tèù^Ôu PõÅ<;Ó¦M#ï¼óN‡OxpóþŒJß=÷Üó'I’²²³³QPP—>ùlígV\‰ƒ“x¸ß GÙ^8 ~xÏ_¯Q5ùþx,ž^ùdzµ³òO´qPüB„t t€µà×G¡DSö< `›'õù˜©Ì–8hzþ:#«1ÿòü ÀK?À“¯HÙ)+((@vv6êëë³î¹çž?]sÍ5Oë(€¯³£™Ëû7¡¾!C†œïÿ÷¿c}õz+¾ÏÓPÔ¾”Ú©)y~>6Å-ætòdxzþ‰(åΤüSÙ­Oˆ!]HÅ>Î>(¶9ÑslTGU¨ùÛ˜»‰D@ µ±¹®Ü¶óËç§ôTºI×U|I _ÐéräN2ŒÂõ™vÅ&¸ø¿“òׄ÷÷Œœ’¸âK§ò·ÅÛT}#Æ1L„×/DH7WêÌû½„à ÜëÎxTu”ñavW•Ùµ‘˜Â¢çi&# aZ¯¢jÉ‚ï-~J&¤È»ñÆž9sæ;°r"€¡“°Ê8Ì8@ÇÛû=zôÅЫW¯”ÀÂí QU_É'i¢³/udž:Ûüº@ÿü`& Q—Øضw‹9à²6+ÆÐG‘ìŒB¹Ëš—á‹Ú/P©´QyFKTÕBŠ·PüB„trIGÀ…âܵµ0³wåËù¤@×…oºFešòwVj©@yM9~Üú#ö*Û+e§­W¯^¨¯¯‡®³>ÔuXVB ‘ ÀSw(UpgHôlù{î¹çŽ÷ûý%YYY)­ûW™Š9kæØ $8’ [üߋ؇S”&ÑsÒ3þy%·Ä€ÃÍÆ²œc(Ø"©Ggþ¶õc3ÆbTp¾Úñ>«ú !„l]·Œf>^¿!Â6`1ƒD;’º¢NÏß0s­0‘ŽyŸQkûwÎãÆüþþâ÷±GéV·Â6Jqq1ªªª äÜsÏÿôÓOÿ¨£†^3P¤G@Gä8Ê߈Ÿø9ä¿@NNNJà§ÊŸ°³i§­¶Ÿg•²ÕùKijÕYh([¬ŸÀ½ÉO ”¼›ll`,.(¸ Jù" ÷:—ìr ÕB„B7…iŽ@‰(P#*TEëØ–¡*êÿ…é¯þ?™Þ,„’¨ù0*@Ošæs®ÌÄl7^Â1¹ê¥Û¦cC¹\J±½~;¾ÝümJÏ¡«tÝåƒ;/€“"¸Ãr:ð¢ý•È{ï½wIffæpèׯ_ʾ4¬†ñÕš¯ì¤x$€o7©£Œ2Ó²ä‰*LÔpõ“Ä-i/ž„öqyo¨o(¦åNMÀÆ+ –áª]¯Âkk_Ã÷ÕßCòKd¿ â# ŒÚЀd†«PüB„tsÀë}ž“D>ˤ fÑ傿ö|N=Ï `,F³Ê ÍN‚*1C/ù{—í²nýúõömÛ™™9|ï½÷.™7oÞFN·) èÈÞŽjú3cÆŒ+T'þýTñjškLÊ_güÈàÇi«yÕñÆAÿŒ3 œ±.ÂÀ—®x—üñÊŸxÞgÚ{Œ9·‰ýÚ©tÇÇ _ÊoÕ9:°ßÈ÷åã‰%C GàËðŒ0½52h\#ÀâC"Dˆ´‚CRbgNåû¨˜S>?3•iÛSèm TÊôø?ƒ$Q(L‘$FAÀ¦U€© /þ{÷ÙY¾¬”üœ]vÙ;vì@ïÞ½€F ‚½K OWÔ¡É€´/¹W×?ßÌ™3O"„²³³á÷ûSö¥ó+ç£>T¯·òµZIší$‰ÕŠR;2G_î5ŒR?}ÌÅk‘ɨ„¹´Éä`/$Ö:7fk^ ÷oÓyW2všk[ÐÒB¨1ŒpKJD…¢ªPU–T‹b±ˆE,=»pÜmI‚ÛN…ðs±Ñ>ÖkBùçÔ|Ít·“ès}]s~ØüCÊôŒßïGvv6!þ™3gžwN€NÑ*Xng¥ïüO]¼ßðáÃÏRÛôGa ¾]ÿ­ÅôgÄù‰£Þ_âBÎJgÝ?gB¹eýÇ‚é=¡rG̬5}|}Úˆþ1Ô7Ô#\†ªªV.Õ!ë 8°— È_ˆž!H° ™<ç¶U ‡ uô  ÆGé¡W±ùôJO—Šû™¦F%¡¾¾#FŒ8Àëœ~ãÃÄqöÚèˆ^ñG!x`ß@ Pæ÷ûÑ«W¯”Ñþ.¨\ Åþeêã'œRwÉÏ4›ú0{S[LßAõËf׆ °ó¹±’³iv«ÏSu]5îzû.,ªX„`nA´L<ã–PüB„tk-ïýV[óZAl¾æÖ»Rª;1nÕ>¿»qºìhØ·þˆÉ}&§äÔõêÕ [¶l€²Ã?¼ÿìÙ³Wº :˜¨½Cnýœø¸ˆÿüã¥Ò/þfÃ7 Ô( ÑÛER"A[odÿ¨µÐ$fmC÷˜¶?ŒÀ¸b UÂcjôþÜÏïàö—Iëìº5[Öàì»ÏÆ÷¿}‡pCH/ !Ò†Š@(`ªª#cqK,bK÷\¼æ»Dß÷œIüÏÔ~}…mnaV~uÌíÆk  ’ÆúJÍ2p`öòÙ)Õ9†;ùä“/‚– Àë:êá~vË@¼Ú#û_îÝ»÷>зoß”}ù²ËPQ_aÜ€ØãCæB`å˜õ¦\oEÂXg@ÿà ÿÄø³ýðeù!gú d@ÖãiIÔùŠE,béA I!ßu˜ Îù–8ølë`Ïï¢v¾#îO$ªÿ×u!˜·z*+S£ô18¤ë¯¿~:ì}œF@»§UuD`”ò >ü(,,LÙ—.Û¹ !5¤5àOhL{ļ@1 [>î¤Â¢•äjOe6È*Qè+Ö¿ q0†M-›P®Až//î9Z¸r¡Õ4ÃO!dø2|ðgùáËòÁ—郔Aüz³$bZ6vO!B„ô4'ßš=¶wC\s‘€ ㋊Ïcž«1ƒGë¿_ø©CÛâFENbK]Hç;s~r¼vtl7ßsÎ÷à¸` [ |·á»”饼<­*kìØ±ÇÁ»Ð…¶ë…âÁÿæ’››; H]ëßíÍÛ±¼b¹•øG¬úNp4šWO¸&~DÇ\T}À¨€1J‹7%e%Y]­Zý³èÓoð|Z9‡–†LÙÆÞr2sÑÂZ ~ 0—EÄý…éáÂbOùÞ™ünyÄ•þ×uNcÜ:æµNï  ¿¶¹Wf¨Öú¯éfyzf®˜õðۆ߰mÌ6”f•¶ùôbóæÍÈÍÍé¦ ;" Ðe€^ €ò¾ûîÛG’¤LŸÏI’Rò…Ëw.T¨Ë‘8cû°bû¶~—X¿§¹ƒ$kÿ£”≀nu¬Î÷‰DÐDš0{ëlLÛeš;D({>þícã_UÍr•©¶2!B„IÈÑq¨­Xó§[ßÏy3Æç:+œå¶)â\|F0SS-Þ¾8%€$Iðù|¹ï¾ûöùöÛo×À ¨ÝÂé ÄBdòôéÓ§©mý» |ö¥&óŸUîáiðI Æ€¢ˆ.û‹QúçZÖ'/ Ñœ¯ÏõÊP¡Zq-Á'ŸÄ̘ºçTSù«ª UQMC@eªeˆ‡xˆGÏ}¤©ô·-9FÎ’@þó EÎÏÛñrÀ 2 -d¬=ÿqÃ)ÓO†®›>}út¸ç´k ÝU^õÿ¹¬¬lrªáÿ5Û×€JÔ½nŸïì®4„³"mLw\IŸ¹sù• °øÅóþcAýÉxÿn°ši3þ·þøÓÐ?¹ž·=‡í‰¾½ú¢"T5¬B +ÚQ ©’@„7 4!PŒn€žáç\Ëbt d.I‚¼À͓滌Eùà˶.öÆm(Íl; PTT„;v ¬¬loØ«$¸ót¹*âø|Ï<€ŒŒŒ~•••’/^¶c™Íã7k=)±µ‚4ØŸxÈßä à'!$ÊóªTHDù' ¡µú·+Õþ¨LñeÕ—ØÚ°Õ};Bpê¾§BU,å¯FT0…AUT½ÿ¶ ý"DHŒù†öÿ,·yšŸÏ‰õy¶×\)·¹8u…ND(Áï¿§äwºN×}±zPÚåB®Êÿ”SNÙ"eff¦là,¬Xh1þØz@Ûú@óFOpKé³øŠ;žòçý·Ý8gÑ7nÀ¼°æÏ}Ÿt< ‚PÃ*Ô¾„U°St®m!B„ôp-Ÿ¦mÓe8ðs:åˆÞøõ'× †:þyóÏ);>]çI§œrÊn1Œ€v9ƒ4ÍÄ·flðÿ~ûí7Õ°ˆLç6,M‘&¬®\mà ª½°ñðI!Qq)fJ¸å¸ÅùJ9™|€ÖÆþ½>ߨi%>‚ß~ÇOîÁ_gìw”°‚HK‘¾„#Z>˜ÈñÔÅùIŠ?Ÿ°h>Õ°×¼ÏóÅ89–mY†ºP]Jt•ì·ß~GÆP´C2`:Ë ¹ raaáx@£HL…,Ù± LcöãÂVög5ú1þ3Æìñ}‚˜±ªd`þ„ØýX+àǾ1E¿T¢ ~Š×¾ˆ1½Ç (£6=qò‰xwỨh©@¤)‚HFRP‚RôvÁ´}H "¤óIkó\æ­¨˜Œ¼€¨ùÒ­c«KATs g£ ã3ÜØø™†«‹*aŸ¾û´ùôõîÝ•••(,,ÜöD@‰Ó“ Ú! ÕÓ¹Wï½( àŒŒŒR)ùâE•‹¬–¿è_#¹!vøpoìã »%X2´¿ sù'P*“”òç`'"k ¼šUãÕo¸nç—ý¸øÐ‹¡´(ˆ4GiŽ@iár˜È"D„º@ˆx„¸ pæÛ-ز %?ÑÐyºô"ré]ØuÞÀˆÊ˜4iR!Äçóùì{dMÕ;u-avEo¼v”š•ŽÚ·‹Œ§Ý½ÿD‘.„øH€`Vù,ìS²k£‹ýwÛçOįU¿j¡€f  >ªõ ”@ˆ!îóM,n’dœ7~€˜ŸÅyíΰƒíøÀQ3DÓ®%ƒË¶-KR¤@---¾)S¦ìòÅ_¬@t@»L²rz†@T Ãf{챇©«ÿ_[·5Í5|RÜò?ó5ìå€<ÛŸ !¸*êx L¼$@7 ©@Ixÿ¶ï¡ T¦Pü _ú8îÜëNÈ4z\rØ%8ï…ónC H j6 ’ˆªk²¤!Bzˆ$ðš«\Ùÿ(d±?Ë,t •Î0€m½[OݦxgãN¬Ú± C †¶ùôeee¡¥¥‡vØ”/¾øbµ‹ò7ô¦Š4†ÒixñÿK}ûö¤®ûß’ê%\ãfvp ˜ý ÏÞÉøgPÿêÆƒ 5Áû"yåï9 Ûêý;¬^ã P?ÅÆ†xcÕ8mØiQ›.ŒÓö8 /þú"¤F R@[¨OË ” @ˆîé'”‡Ý¯µA¬œ'“Y•pó&Ÿ$HÝMItB Mõ¤j„`aÅ”¨®®FŸ>}Æ#šØ¿6-@ºxbrVVÖ@à J…¬ª^ecñ³ÕvGÙw„¶RA®°UJ6%Fuí‚Yë‹ÀG!$¼·å=¬Þ¹ÚuÛ³ö; ý³û#ÒA¸)ŒHSJHÑJ²@‘ Dˆ„i¯/òü~37ŒË 3æF¾,ÜM€KË—¦ä333 $` ÜÛ»åtj€¸®9²,çHÿÿÖÚ­V™WžGµÂO;äϽ6ÿsP“±ÞÖŠ¡5–o<ž%çO…Å PŸ xè÷‡pïä{á—ü¶}|’ÿ8ê¸èµ‹n CòK ~- Ù–4#BB„ô@ñš“©ˆ•õ+<—ïàBN¸ßVÒ G€³—‹£œ×-›ª6¥äÔºO×…n<ny)GÒY7àøãß•B222RBTªFC¨!º¹q@;ž5©®|Ò,zp8•j«yÿYb<QëXòßµÑBD& Š-Ê<·ô9×ß8¬tÎÜãL„Ã7…n #Ò1«L>Á â!z´†ÛŸ¤¾÷€³ñ7@”²çÈmýaˆµm}K=¶7oo»¢$º$Çü®ˆß¸ËTÏŸ {ï½÷d … €µkí%.§Ê ±1*T¨ Œ@‚d… $Àéõ³hû+™X|ì6¾¬}½þwH0CŸlûã ÇcÒ=¢6=sò™˜¿i>×.6 ªeJ¨fLP"P  \® ˆ h~ãò<ú¦D%:·#°qB°¢z û¶ùÔegg£©© “&MÚçÝwßýÍ©+]Œ”K:'€ (--¹¹¹)aUZW³.*Zbƒ¥]xþ×Q~Ñ–V'âŃɾ€D”?!Ä$ö‘ühâ‘%`góÎèB)n8êd±,D#AP — ¸„ÒÎ’4zL¢ŸÇëàìc,««V§DwåææJJJFÁ; AÍÔ9â˜F@fff u@Ûê·Ek™7h¢JH¸@Ƭü€DzZ·¶¶5ž÷…° 1Ëü#>) ¡.R‡<€›'ß•¬S˜Sˆk¹×r½†H 1 ’_ÒxD>€!ˆÄz? Þ~¦SÂìó«3 Š1ÐmvÌi[j·¤äÔ:033³ Þ9i¥N•@0$’ßïÏYNÍWW6TF+žþ—XÆ€›Btkl–‚ØbIÉzã‰vòk+PÒ(ß©AˆŸ€F(Õ/›ËßÄÉÃOŽÚeŸ!û`únÓñöª·5R ÑF~u©L…ò"¤Ç¹â Þ£0•ÎTÔ{ü÷»qhŽ‚(Èéƒëyd[k·¦Fùê:P׉^]“HCïXÀÙˆ_$Rnn®ŸRê'„¤ŒpGS5ˆY9É¢›}D!„hÏõVP Æb~‚Njc#ƒ¶ÿ$ïø¾÷÷}˜ÇžÌe{–à¾I*ðð@%í#¥S(^YûFöÚ £ŠFGírþçcYåR,oX"T(e Tøò!B„hÀkúqe d­ü<c=³=·¾—@ׄ`†Þ` DK¡6Þ7Bªúª”œ!J)t]èÏÍÍõ×ÖÖz5¢°z¤4Øš®€3öOÐéÓ§RWÿ¿¥q ÂjD#¦cD»Ì`„hÔ=  VTãZêzJ…n3¡–ø ŽííÇPÿÌͳ÷Ò¼Ûö[Ͼ!À(d À"*î]xþµÿ¿̳mî“|¸ù¨[0㵨o¨‘)˜D࣌PP  "¤Çëz’@ÀþcÞþS½¿—1w}Ϙõžù\Õ>‹ëôת¹=ʘöÚhn{(‘6ÖmÄ.9»´ùÔeee¡¾¾Ó§Oûì³ÏÎõ@ºD@¬@€îºë®#Sj4l±C5ÄðéU[º"pã{6Ÿ’Øõ’0ý»¬MðR ‰fCd¢jù;";pÇOwàÎýîŒbü+Ì.ÄÍGÜŒ+?¼!9dUèW™ú¨•ƒ!Œ!Bz¬Qp@¬n~Ž8¾«qàÆ ¿ªªÖñèfŒéÿUîµ¾¨ªjÿ¯¨æÂTm½ª¨ØP³!¥€®¿ƒw -Œ€í˜-{÷î=222RòeÛš´@³V“Z1¾~“bÆðùjgóžò7ÖªDh*Jô‹³MÊ #€($UÂ’ú%xê×§pþîçGí2®ß8œ·Çyx|þãZB LLœ‡få0#@ˆnçÝ»(òx‰{.¤>N%o÷ø™çç›ï9zØJ Yô¶ª¢)u¨‹èJß0 ÑDWüaÕZ§rÆSS–`èB]7:ûЮ†Ñ<Æfãììì”VT6VÀÆèhKØÔFcªý0¢i(äԔ¼Ží0ÆaIIØYÉ(ûàÓ^— üßjÊb¦ý¡“¤‹Hxoó{^0 8(j—S'žŠåËðåÖ/õª-¬"i×À¨"DH—Qèñ¼ö¨mx…ëPòQŠÛå3õÊ=J™{±ÆY¯* :”¾ñœ3T…ET}½¦ø¡0­:·Ý–©­Ðu£©+ÝTé0RaxUÒGY3~¿¿H]@USµŽh áþƒhùš÷od÷#Ê-%ÄZÃâýºî§X±ÿXí9“Åu_Öö{;ÎÔ©‘}š¡Dƒ$EŃ‹DÿÜþ\08j·k½þ·këׂH0ªµ &|­!BÚ]©·¦/&´b25Á²>ÞcUö— e°ÛoQF¬>s>‡5ÿi/Œü+À郗ו§äÒù|>€ßïïå¸|{êB©.ŒÙ X–åL@Ë~ôêŒÔ4×D™Q<ÿÜÿ¨#æ ¼¸Zëq'[Ò×Vø¿Í ‹xò ‰€ú)$EBX ãÖoÅ¿§üÙ~;{cÐÄGÝsß<M M¶0€ Y#Ö ¢2@ˆT+÷dã붘<¿.Ek}¢Æ/j Ež*ÑŸcã î¶ŽŽ¼-¾<°¦±&%:ÌI˲œ÷ø¿[.@§-ôêH5½¯5ŸOU `mS­íbñ~¿³‹r$ŒØá)`c™bñi~c½‹8žÐ.ð¿ó&&eåõå¸sÞ¸u¿[£’‹sŠqëa·âª¯B˜†5Ø_¿ú´‚$HˆÄ|,åžb¢ç·XŸ›,Å8kÅïpÙ6&úÃHÊHì½]˜ƒ$ˆK4ö³mh† ;Rrù ]¨ëF/ ´å¤’ ˜Ä2FÕIü߬4£9Ü «¾Soãhþ0í9%Äq0ÚÑë]ΰY/ê¶ ‹±Œ÷‹»M²KÊ>‹Xÿ%™BòQÈA ¾  jçã…ß^p½»÷Û—O¾‘ú0" a¨M Ô,¬‚ET˜… )ûÍbK—XXôU¯GV˜õ\ÕcΊª­WÑãÑaÇrüw]´¤6-ž­.÷]&Î?gÌõx£–XsG;,^g}ú@0LÉ—U5WÙÛ5ê‹ Uƒ© *_~†£ìÑ4Àq¡+$‹O´°-ñ–Ž»ÝÉÀ$EËb¸wá½(Í*ŰÞâv»`ß °~çzüXõ£mèJDÒ’A¬!]XÑÇTòNxžÅx¯«*÷„OKÍ{ Ò Ç›‡mÝÿ˜=|Õ2˜8Úsj˜¡²¡2%@0D]]úöíÛ?üߥ[-cnnn`e=¶UjCµÑ7 ³<F\c>n5§6² »ÓT› €ÇÿYºg=)ø ¨JQ"¸éû›ðД‡P”UdÛ”Š[ޏ—¾{)VÕ¯²10­‡ˆÈÒe•¼«ïA^¥ôã9¬{?Ïß/'!Þ6‰æ8¯w½x]áL†´å0ï9yGSjòü~? 77·Þi ¤#.?€fggñ?¶­Rª‰úÖ˜ŠÛié¹5‚hƒ5›Ðý‘$¥o§@ñ¨Þ:ØG!$Hv¸å»[Ði޶f}AÜsÔ=(‘J®#ÜF¤95¤‘jõ·¢}°UTÜbc…ÓUQ-r˜ˆF c.!ÇëˆEÃ"F=¹Åg&šéŸåŒ0ˆû¡Ý'¶$Þwlkè™êÆê”Šáë:Ò­‚.Ñ£î0 ®! sÔqÔ†j£ì#g€q±xvÀÖžÂd „Ö°&hoïLƒIZë`Ê4¦À•u+qÏ÷à†ýnˆbM,È,À}GÞ‡ ß¿ õ æf„A‚¤…Dy Žðè“ñæ=bõžÞ­PâIÍQ©,µNt.¶•:BÂféAt«`#À…êZêR£„urÛKñ§Êpã*æ­c½äóù²@’¤”xC¸ÁçðeÌ v°Êý Ö?[rŸ÷Û&†$cMIÌÛˆZÇ:à¼Ò’Nì§2$|³ý<5ÿ)œ7ἨÍûôÃ=G܃+f]P}È6Œ)(¨,Ê…¤QÑsë½âò±âõBɧøZxl‹,(jÿT…ï¼ÿ6]Â8n~¼ðNhsmJN™¡u)!vg]Þ hóhLe€SùÛH dY©ãh 5ÚkmÀ+nD~ôhåpK01ŸÛ~­QþÞׯ…ê7f]€÷5noåo”ÂP™ªÑ'«^_÷Š3‹1mÄ´¨Ýv+Ù ÷v7®š}"4 Bk¥õ ¦²h$¤õ ÆUÑ»xôNÊYOŠZÏBRf$½]j´r.{ëa³¼ÛÒŽd0bŸ{ T³i 7¤ä :Qבž:iHLG3 W£€RÔN&I ƒRƒÒȱüY¥DΣį5õ­¾Éyÿ.û'äýw€èe|D¦ ~‰ÉPU†‡…™…دÿ~Q»Œí3w|'®ýâZ„6i›%ýz # <1–¢;.y7$Çïæá%¡èNÆ’^õ¦\ý»Ï¯ŽöŒ8rÁ ×Bع¯^5fìÓØÒ”R6@Ji±iR.©®ðD$I’]'ŒVJK¤Å–ño(Ì(J_fåF¬Ø6¢›Q$®Ämøã²>üï\ßéà;ˆboœ!) ·Í» ÿ þ#‹GFí¶gÿ=1sÿ™¸ñë&á¨sL$½Z@tlÓ +CF™¿ ¥þR”úKQè+D®”‹\9ùr>2h2¤ HD‚Ld5› JUA“Ú„F¥õJ=ê#õhPP¯Ô£N©Cm¸5‘ÔFjQ«Ôbgd'šÔ¦(ZmWd-–¡ Wo&ЮŒnBÑwrÃ3†fö µ´™-Ð¥ñíÏQU—¼ý­ÆPcj”§~oH’äKÀëït@"$L”’R 9Ôl+å0Ú<ªª ¢³Î“¨zòŸªŸVVoCéïAG%Ò0J©; ˜€Ç¶ªüaŸx %¶|€°Æu__‡G{ýòúEí¶ßàýð÷Èßqë··ÚbmÓè‚ ß=Pq'Ø bxÆp É‚ÁÁÁ”1e²¤ÚX[7,A¶” H@ò’Ú7¤†PªDU¨ Û[¶kÏÃUØÖžWGªQ©³åzDñrÀž¯cûª‹gŸ»^H÷5¼¶‰e¨Üx┿Y¥¡2sîç+•øê Ã5æ®–pKJ Bˆ„Ä8:e3 ¯d…´õ26&ލ±Å8 owrÿÇß=|’!–e”2•AVe4¨ ¸ú‹«ñØ!?#?j×C‡Š¥wÿpwÔ5¡ºF(H€ËdI ÅðÌá˜=c²Æ`hæPHDêðCóS?úû¢o°¯7Z§¶`[ó6lnÚŒÍÍ›±¹i366mÄææÍ¨ÔÛÑ%‡‡GG¿F„²’¼¥©â”]šq$¶ËŠ„RmÐ:4AmÖ1€`§`Ö~\Ê€°¶y†Ò7knÁ 2„i¥k¶ÁᬠH"¨÷ïåÝó“[ܲÀΈ8¯¶Ó  EyC9®þìjY àNað…*²–[!AêºUøûgÇ?ø'd=ÄN{"þ5ÿ_Úïá(7)z¸À€~~˜Ú{*È?yr^·þ¹yþ<ŒñÁ˜‚1æ:…)ØP¿Ëk–ceíJ¬¨ÕŒ‚ ™TÒÂ(è*Ùµi»¶p$ÌÀÑýšÀpqÔˆ8. !€x:³S%Ò )倢F¸’>Fh¬'Ņõ¡–dž*Kª%PôûÞû7¯ŽèéýRª„Eõ¿âæ/o­ßæjh4ö$ÈTÂý?ßo–qÊÝ@3#Ø#wO_x<ÆdéÑJC"å  œA˜Š©€ˆÁâ‹ñkõ¯˜_=Ëë–C¢ÔѪ§óÆ@Ϥë„kÜ`’ »›G:íh€œÆ·­ã¬œ”|YX‰€#€€9Ê7WÒÉó}æÑ Þvç³H¬L9!«êß‚¡’17:ú¦!zeeSIeø¦b.^\ø"ÎÜýL×]§>”J¸÷Ç{ÍŽ¤2d0PFAdt{#€0‚ýò÷ÃJþ€]‚»á5QQãzøÞãpÎB³ÒŒßª~ÃÂê…ø¾ò{llØh%’:¨È„1ÐAJ4‘uÉР°V|†×ç$³pûð=fUI—ò÷âþïrTÀi»íŒ€ €–D¦B5“É 8Y… bþ7ظï¡z%&ëÇ‚ñcAÿ]þw^]¦M¶f3¥ –wAÅKŸÀÀ€ü®»7ò8ø%?nûá6óšJ’Æ®: » Ø=gwœ[v.e ‚ä$(±gñžØ³xOÌ1ëëÖãë­_ãëò¯±¦~fê},øp0Úi>HrÎJÔK_¸Í¿ÎçÎP€ñàõ±.¤„ÒuÛ oÛiH˜Mªà P$⳺Mqr™êž°T¢±)ÖºV²@¼¼€Nkp7=#LË hF€¬Ê¸}Þíxòˆ'=wŸ:|*r7ͽ a„5#@Ï' àÚw# P.Äy}Ïþyû …‘"3g有3‡‰Íõ›ñù–ÏñáÆQÑRm èå¿Âh/[·ã Ϲ– n“¸˜ô„7ÚmD¦ËHk Cóâé5Â$ŠÎÉêAlh')H«55]„ʰ— Ë–ãûÍßcrßÉžûN29€|õDXÄv¨š Ù]¶w€~=§LÁEý.B¦”)4Cš¤ov_œ9ìLœ±ë˜·mÞ[÷~¬ú*U5#@"6ºa¤g¬ÇœË:*ÀÍ+6î‰ë¸ÿûqí×¢Ífy ‰H¤kÐë—I&2``p úûãÀ‚Qì/ ¢„ŠÉe“1¹l2¶5lÃë«^LJ?DK¸Å4ø¼wˆ.ƒ$ûÎùÙ­%¼Ûz'rÐN‰€i‘rw\Æ…Q™–`¶iµÒLڀàL+çc$H°¢q¾ÛòöíöžÐwú(.Ÿs9jj 2UK Ó;¡ _–²@FeŽÂˆ¬‘92@&]þëRšUŠËÆ]†3‡Ÿ‰ç—>w׿ ER´1* îm06Àq½óýxósW¹Œ.;M¨ªõ®Oòb…²µ NÑO6êâã‹@£`&•)àž]ù,öé³O\þ…] wÅSG=…¿~òWl©ß0@Ve  èèV ( °{Î;ã²Ç¡Ð_(fûN.Áüuü_qâÐñàü1oû<‹€ÊˆÐ@J â˜sY{†b…ã…„Y‚ëÚÝÅê\@¼ÌÅôäðІóöŒ#,&­c=ÿd¼üD€®ÂЈ %k2‚•+1wË\ìßgÿ¸»÷Éíƒ'yW|rVÔ¯0%&ú)%ÊОHúúbßü}±OÞ>ž5¼UÜûB:^úåôÃ}Þ‡O×~Š.ø'êÂu¦!@eÝȤL°Rvñ>|É'šëˆ{¨ Í >í£.Ýéè— CX* åß+À9ÑŒ½qг«ŸÅ~}ö³ò4óä†(È(À#G=‚k>½ jXš@üš—v#@÷ô(8S ¦`DÖqQ»‘6è0Œ-‹k¿¼+êW@òK€_7Zy4@´«î¢P+ɇÛ¹ ÓLG¸>ŒHCJ“5¤B¨®-c[+Ù4'ŸˆÿŽú/nzöÎÛ[(ÿ ~É[¦Ü‚£ú…H}‘¦ÔfUcŠ (Ž6ÄB„tiw •Ä ±23ùRÀxÕ|7YeHwÀX„?®@W­ˆuž£QÐÚ¦µørË—8¸ïÁæû™LlÛ± ¥¥î–*¡¸z¿«Q–]†G~DË `ZNcÌJâjeÌ6OÊÃôâé8¾èxQ£ßcmU‚ë§\ÆY˜³i˜¢UžHLók¥¨ è8')9nsm¬X¿Ûƒß¯«·¥¦]xTygc&›ýë³b}®X>Ÿšr¦•)žYõŒ €Ò‚R,^¿8æeÿãîÄm“oƒÔ A©W4$ E 3mQ˜I@”ȱåÑ<œßç|¼0úœVzšPþ=\(¡¸ùЛÑOî‡H}J£¥E 1ô<ËE Ùªäi€^~k=f¯¬îDâò‰Æÿã¡ÝàQâ#X߸s6ÍÁá»nÛfdÿ‘øtþ§8lÂažŸsÈCPœUŒ¿}ñ7ÔÕ×™9ÔO­q·$€ã‹ŽÇie§![Ê“S‚¾ ®;è:œ÷Öy¶,q#ÄÓ $ µh@ÂHKþ3b¶fHØów"è ³‘C<è&¾1D{ì×¥„Yô«’–Åÿìêg£PBö½^˜óBÌë?¦t ž>êiô¡}n#ÒA¤9%¬@UT0Æ 25šç›1LΛŒÿŽú/fô›!”ÊÏË~Æu]‡¯|…°îTǶ÷ ½1¡p‚™siŠ@iÑÆ–ªªÚØ.ùàçœD ÿXDAÂèLpM"1BDÀõí¨D±)´ ³7ÎŽº”þ ì;z_Ü÷ú}1clýòúáé£ŸÆØÌ±ˆÔip­‘¸Å"LƒkU­ *P$á–Á·`時’·È„áðÕ‚¯púͧcô™£qÚͧáþWïÇ ¾@u]u‡ß´1Ó©‹˜¡µEÕÂMúØJ&Ô$–.<_Å"!€Ò÷Œ¹&ï%Ô ß•Ô7ÐÝi€ã áÌN €xvõ³8l—à {ààÒÁÒw®æzÜöçÛ<¹ò‚yxøÈ‡1ó뙘½u¶P%0U 5e‚‡ŽKû_Š,)«gC°1xÚÝû œúGÜþÂí¨o©Ç7‹¿ÁÜesMJÞÞ¹½1¤lú÷GßÞ}Ñ·w_å¡wnoå¡WN/d2Òv|{Ú‘†ˆIfÖbt$"Ð!!€V¼o æJ앜í…"  ’Ê,Æ?Cù§ã¢$Ú†R žOÂLr MM›0kÃ,=àè¨íNØ÷Ìý}.þöäßpÏŒ{<¹ü’·N¹}ê‹g–iÉ…F…@–”…k_‹zÐ-'ÔºÆ:lß¹UµU¨®­Fu]5¶×lÇöšíØQ»ÕõÕ¨ª©Bem%ªk«ÑjF¯Ü^3h F1ƒµÿKvˆ2;iÊI¸ëå»´N}2±1ñíTvâ—¿àç ?k¥ž:„Éñ¡2d2‘›™‹œ`ò²ò›•‹¬@r2rÈ@ÐDNf2ü‚ÈÍÈEF ~ŸA_@3$³òøe?2ƒZ"h¯ì^PÚׯ´(  5¢‚(PʨÈèª@¾7Æ@çatìHJÂkñèõ]©:æTn×e¸‰jþ3«žÁÔþS£P¸õì[qôõGãâ_Œ‡.~~Ùïù™îy!å­ón…¢(–5 wŒ»ee]æÜT×V£º¶ÚTèÛk¶£ª¦ Õuúúº*m]­¶. Û9ë§1’¾h‰kR†„šH 殜‹¹+çšã-;˜»ŒÀˆ¾#°[ÿݰkß]1¢ÿägç§õ÷c∉øyÕÏOD€jÉœzY§q|LÕ*<ŒŽAðÕÂZPÙT‰ÊÆJ°*+9Œ'p±õ c½óžÓóTˆ¤1WJ’ö½km‘ €dç¯d{°s?’üŒd þDß@ÇZ’¦×ÏÒã%ÇŠA  5(ÀÖ¦­øp݇8nÐqQÛe2ñÈ¥àø›ÇY÷ž…ÿ\þdgx'îMÝu*úåöÃûkÞÇU{]¿äï°ß¨¨ŠM¡G)s}ñºº® S,£†Wâ.¯!’O²”<φH4ˆÐ±ž›ŸÅñ&µ ó7ÍÇü óÁ¾e¦Ç]œ[Œáý†chÙP í3ƒËcHŸ!(íUš²ó´ï˜}ñóÚŸ5æ½ÍÐ ³C8@±ŽÍ† f<Þ$…B4AT”aÀ) ã=#Ëßè `43’HUUMÚ(€Ô«ÅšŸ­}=+ˆ7_Kw.LÄ\Lwf=õt?\¿ñ¸[KËËbk²æp7ƒt=Å‘µøê³kžÁ‘Ž„ú¢6Ù$n8ãÜðÂõ8ù®“ñü•Ï£(¯ÈóãG—ŒÆè’Ñ)?ìˆÁÎú¨ÜQ‰Šš2¯uQæuš§¾£n‡m<ÆUè~h(H¢ ݱ¹ÎPò”[O¹ò5þ1†§L™b%PV…«ðíêoñíÊo-e«j̓Ëc`ñ@ (€Åп¤?@Yﲤ KZ-yýRP‚”!™T¼ Üñ) XH€°Ñ€ó†ì†¯ðmD9ã‹ÈDË#ñS[oó:éÙA—'êÂ퀉eÄëfL…UŸë\ŒI—ŒÙm¯kÛûOÔ<á,K– úgÝZýs?HWPÁ¶¦r¼¿î}L<Ýuó³9 s—ÌÅì…³qâ='â…¿¾€ÅÚ÷f‘dæ¢ §M¨k¬ÃÒõK±pÕB”ï,׺â¥>jAʆ‰Rà6åÍ)zãslÛ¸|–¹¿ñÚí?‡ðÊÒP¬,ÂyÛŠCñêÛ4«ÍX\¾‹·,ŽRÂ>Ù‡²ü2”õ*Ó’÷ û¢¤ ÅùÅ(Ì+DQ~ò³ò‘Ì„$IXS¾Æ4¨š(€ÉÉïD e¯0[¿ã?¿Î¼Õˆ€â5%©ÕÄJ HÚ±Qj7žÜäØ!ç~‰Àú±Ú³î3)w " '—*x.QjÉXïÇ" J44 ìÕ•P&=0ñ<·ú9;ðXWî<ûNürÓ/ØXµ'ýó$ü÷¢ÿbLÿ1í~è•0¸Ï` î3GN>Ò\_^]Žù«æcÞ²yøqÅXºy)T¨Z¨C7 Õ»#º)j8ŒÿN…Î N…e8ðëx#WuQôÇk‚W˜–7%½Jpä^GâȽ4£ ¾©߯øß.Ÿ‹¯— Õ¬ž’)ð=@´×64€-ŠE©Ü]ö·ŸþÜD¿¸{ÉW7¼îi+Ñ(‹00Ý€¹÷ZÕ>Ûf 0X뙑³¼lMáS?õm ¨\KÁÛïm¾Û§IgËàîAç-Ç\îQ¢Ÿ3‰²’Œs,(“GX/%ˆ°Øï»~–—Îà cÜâ|íX„Ð9Ƙ›Zmk#Àø–jbû¶&Yµ‡¨ Å3«ŸÅ±óLÞ;|ü˜>éD¼ýËÛhPqîÎÅý§ß£v?*æWågæcɆ%xóÛ71~Ðx4ö ädæ¤õçegdã°q‡á°q­ñæ›ñåò/1gÅü´ù'+’3 å…Ä ð ~<2ÿ—`z·×™\LJl^¿êŽ@ñ؆Ëpfñ0cÿ4 iÉ~â§ >}‘-€pžœmû,aÒvÀH¸">‚çW?iƒ¦! \wÉËÌÃ'ÞˆKŸ»T¢P™ŠÛ?¼«7âÇýÓ0 ó ñúM¯ãƧoij³žÅ÷‹¿Çm/Þ†]Jv1}Gí‹ ?˜ÖŸí—üS:cJÇà²É—¡!Ü€Õ+ðåÆ/± rVÖ®Da÷|74Ày>áòžç% QFµWÌž‡òyOž7\×+Ö$ëÌÚwÆÚͬ{ÙQ%áòS<7Ÿˆ!ϼǨë¹ÝŽèÒe ƒPeªÆÈ¥OR*´õ„ÙÃK0Ÿsëø–µmõþÛŒ°øŸÓ]QF˜ÄPªÄ[kÞÂ點î¹ËÑŽÆÛ?¾Ï—}®AÆÁó?<Í;7ãÓ@¦ß»­¯OòáÎóîĘÁcð÷ÿþ!%„M;6á¹/žÃó_< ?ˆÉ»MÆáãÇAãÂ.E»¤ýdù²0¾d<Æ—Œ %ҭر¿VýŠ…U ±°z!¶‡¶Û‘a0âBïKZ9n<”-Ÿ`Ç#jÆs)0‘n½ Ià3òÏ$VÞ‘4#>=A4ÝÞ6I\¡30¡DÒŒxyï­AœŸåZêD`yûÆ>ÎÅl2Ö  Ò–A´YGÒ €€ € Y²äÈ{çw^€‘#G¦äÀOûè4ÓK0;ˆDL:Q[\Uâ&Þ›r–R™ÑD1i0¦%–©Í*ò"yxïð÷”½=ñ­;¶âÐÛEšlåbcËÆâñ³GQNQܯýeå/8ï¡óPQ[aÂïN¥7¬l¦Œ™‚Cw?{ Û²Ô1vóæúÍXPµ «â×ê_±®aK K:Iߤn&å¹L¬Qµöª>ŽÕèÉÙä2 Ññv׆ži°sp<@u ZŠ#¬¥8JMœ–ˆ½"F «æºYçÍJÉ)[²d `Ú´i§¨P @€&ÍZ„D(,H—gLT9ò¥ñÊ[£lã*}ˆ2ÀDP@óüª#ÕxmåkøÓnòÜ¥¬  —q9îøèm_YS‹*áä'NÆÎü†– ùµwˆoýç?v>毟¯ÁÎFÜYWZ«v¬ÂÊ/Wâ‰9O 'ƒGˆCÆ‚)㦠wnïv;E}³û¢ov_3àÀŽ–XTµó·ÏÇÂê…XR»D'4 ×>oezÀÈpððƒñÅš/@üÄÜ—ÈФàš¯ÁÚªµ¸üËã*Ó'ŸŽáeÃqé—¢²¥RKH“`¶œæ3f aŠj¥¯þô*^ùáȱ÷нqÈØCpèøC1¸lp»Ÿò>Y}pÂàpÂà 2Ëv,Ãwåßá«­_Yá©Ñ!±IÕv,ùÏŒÕâ—%ø@'P* 17ï¹ñx³(Y–¢mY·ºÛ-oß¡ìy¥oxØ&o¬¦65¡¼¼äeÌ7#æW]sÌ5øâ¾/ úT{óP%ýøVW®Æ}'݇ /v‰ßÄñöùoã¢7.ÂïÛ¡Äâõ'°àBP#ªö}ŽŽÚë¨vç Ý{ F÷ƒ+w¿Kª–àÓMŸâÓMŸjU2ÀQô d@HâDÔÝnsp¬Ïd.ÿy}~?ݰp‡©bO2’m0Pƒ2­‚ã%èÅ ÄH>Iô3:…ÒwBü¦7OÆ®Ä4‘&: P©Çs‹ŸÃ%.‰¹Û‡]€—xJH iMf$¿d†ƒ(ÕJüB!\úÎ¥¸¬â2\zð¥q“÷ê¿Þ:í-\üþÅXZ·ÔjÅk„›-D #fs6¤ºQ`„h˜j†AÄ ÔFjñîÂwñÎ/ï`Àÿ`Ö-³›™Ûa—{dï‘Ù{$þ:î¯X¾c9>Ùð >Üø!¶6oåŒ iÝÜÙÖí’Ù>V{_·ù8VB ¹¾‹³R1$Ó3€»¥E¯+x³^Ö÷V¬R>£©FJF¨¤)×W¼ˆÚ–Ú˜›÷ëÝÓvŸµY…ÚÂô^šA!eKr$<ôÃCøëkEs¸9î¡”å–á•S_ÁôÁÓ¡4)`!=È8c@ç²—‚’ÖÏ>“jùú÷I9äÈúkã½\›6bÆ3Ž„;Å^0—» ³Ž™…gxÓûNGËrä:¨,ºù–!B2}¤23Á *¬ç\¹IîC™Š”jy°¼·’@`¬¤¾„èLI€^ô®|w :©/Ç@€z¥Ïþö,.Û㲘»\<õb¼ùË›Pš=  UPI§ öëe}úøhÍGX÷ä:mÂóºæ½q–Épý'×ã†wn@D‰Ä=¬^™½ð̉Ïàœ‘ç€5j= XÈ”ðè7qô¬pCtCÀDtCàî¹wãÙžíêov_œ?ö||pìxù—1½ßt#A×|* nI!B„_o±¸ýZCíØ#œ×oxñj$z1¼Ø”%ôµV F:½¥sšâ¢”PüaŸ?Xa^ñpFõqÊ7Ë‚ã_úí%œñô¨ª¯Š{x•píA×âÁÃD0„Ò¨X ˆ†Å¢óMŒÆT¡•Í hÆ€”©/Yš!pû7·ãÕ_^íR÷êØ¢±¸eò-øjúW¸yüÍ‘9¬…‰!Âhƒçêü﬋}Qaïym4µ 3 l%¥AѶ3büæø‰åA¿¼âeloÜsˆœ¼ÏÉ a¢\U"\Òш€œ-ã犟qücÇcÉæ% ɩçâ“ßÀÿ¨ zø¡EC±’'y ä(t€rO?®€¸á³ðÂ/t¹[6Ó—‰“†„7Ž~ÏMy‡ ÒBÌsÄ'EšçI÷m·^Ò1_#EÛ!ã@Ç!³OÂãWTÆyûa‡Ç¯¨öxlg{-vÏ$­M3iÆ~ýOÌ1RÖ« û‰˜1hã·BË+`Óˆ¬ýÉ ŸC±5¼'=}Þ[ð^BãrháP¼uÚ[8¤Ï!Z^€ž`„Œü×\b-FÞ“µc#~+W€dÜòå-xàóºìÄ3±t"œò f7 §<¾°ÏºN.OÀë\‰‡xx4åií¾n¯c½×BÈín¤*¡CH ƒ-¹Ï€¤ o”Ïäï2-GÀóÚÊ×PÙXsó'Ÿ¨ÅäCj,o”™ž·îu›\™ìÞhÁ_ßù+f¾75~^@v ÷0®Úã*Fb"f%R‰ÅbÍ!ħ# xø§‡qí;×BQ•.;LûäôÁ “oÀ§Ó?Ź»ž‹@$`«°Gž€!ešíâú¬K‡Ü2ücftºlõºµÙ¥n1v—LS•©®ÛE}V³ù Oß(Ý3=þ°#¾ß•<+' @›ñäÂ'cÃò§B†¬!ËÃ4¼qÓËÔÑHaHÙhÅ3 žÁO%–@Áù“ÎÇÓÇ>%‘F 0«œh@Œßlþv½å–a Ð,Š7—¿‰ ^¹ !"£Î,½3zãÊ=¯Äœçàì¡gÃ×âƒÒb¡'öBÜrǼÞ€Nã훿¢{ùf÷x•nâAéq{"¼¾êu”7”{nš“‘ƒw;ÐB8ÏÒ¤,æ?Zo|CdÍÛ¶±ùåHø±òGóð1øuï ê>÷Á»§½‹QÙ£L¾“APÝ»cPÄO¬œ€,ŠÏ7}Ž“þs6íØÔå/mA°×ì} >=ñSœÐÿ žIœ"Dæ7<¾ñLÄAØÓ]&JGE@ˆ†ðÄÂ'bîrôÄ£5åÑÂÌìs±eŸ»ħ+[#?[B¹ZŽ“ÿ{2^›÷Zb0w^¼ú‡Wqâà5®€&­J€Gbb*4â0¤h#`iÝR÷ÄqøvÕ·Ýâ2eáŽîÀ«G½Š±Ùc£Ã(Â"¤ÍÒu©€Á’ËøŒÕÙ)Ùï³Î-¦ãñ”À±>#ê;yúK¯f<ÝyBÔ+ ÈþÕoà¼qç¡4»ÔuóSö?SÆMÁæ›ñåª/ñþê÷±±y#@µrAê£ZX8:Ûä=œ¦„ˆÐ®ùà /ŽÝûï÷rwN½»ÿº;nùúD”¨JÍØ>‘ˆÕYÁ.׸îµµ Œ€2ÍŽßÙ¸g¾x&.˜t®<üJÈTîò—zlñX¼:íU|¸âCÜõã]ØÞ´ÝäPк<ëºy7!sº­öÊ}ñ˜›¥óÐ Îù’Ù'g›r·²nF4A™@„´«·ßc`þ8(€1z‰D&a<¶à1ïÍ Aq^1Æ+½sΛƒ{¦Üƒ¹ÄVŽHt#£,Ï,̰3õ½0?¹r¼SÇŠWN|E´Èâ H4$À#‡pa ’Eðè¼GqÒc'a]åºnr¹ Žv fŸ:g >¬™Yç»n "DÝRñ÷(˜?QÅ +gÙ'£0»0a«œŠFž€OùÇírœÉ`äØ1¸€Ï‘-áûmß'í Œë3ïŸñ>öêµ—/ ìb°8F€lU˜TÂÙV-ÄáŽÇ>{,¡Ê…® ™¾LÜpÀ x~êóè+÷Õr*ZìÕ‰æT"¤+‡th†0bï;ÏyÊ„‘(؇0 +%¥Û) r”£•­“U7Ž ‚xèÀ‡0¡pBÒ»çrpÏ!÷`üoã1ó‡™P$Ô§uõ3•+!V§Hj}/¨lªÄŠí+0¼pxRßÝ+³^<åEÌß2Ï-zßW|ÚæZ‹Ð0:Œïw\—DH–§LAÍã 5†pçgwâùïà¦ãoÂ>Ãöé—}¯~{áýSÞǽßÞ‹—–¾¤Uløõó&0‰iç9#!íë¸ÄX5GÆ Ï&:p›ƒ=ºšò¯£þó=àÑ£¤Ì¿ínˆþÄng«J[ Jq ¹¾\üwÿÿbXî°6}ÎicNÃÀ¼¸àã ÐiÔZûút"ÁìC`¶¶õÁT²ßlüÆflݱYúƒ± B0±ïDLì;*Sñ{åïøvË·øvÛ·XP½@#,¢,ªÅ°íú+n¼¦„Z%Á²Úe8åÉSpİ#pý´ë1¨xP·@n:è&Ðÿ\ýÙÕ¨mª5[?¦Oú5¹B„>s—.ðªÓt«ñìôÜüz§B³ÇÒg²×‰úgóœÝ:áÖ6+C&÷ŸŒŽ{¹‘\( ŠU³QM^³Ÿkó‹0·b®í³Ê Êðø¬Ç±±rcâ7"¡[<î~!^œú"~:ù'<8ùAßïxä!Ï„º &C³ £1¾‰uL<‡ÍÖ ¥ ³×ÌÆAw„ËŸ»«¶­êð”ÁSðÞ©ïadÖH-§¢™cTÔĸÄCÌqó ÞpÛ2µÏTZvhJ‡Ôز±xî„çÎrÍ+×äÍß>Í;Ï鞎ãn9_þúeÂߊ„PÛ\kz¸G 8wísæž8/üÎz.jåŒ!ÝH‡Áä 0{drs$°,†7½‰ƒn;§ÿët|ôóG+á.=‰õÉíƒ×O}' : Jƒb¶€víÁ z ô܉ê$¡;D ã¬ ’VË,¡ÄÉÐßV™jµâÕa~UU­7²4SkµR\>êò´|öè²ÑxþäçqÆ«g Qm4KìÓàe’7Ìg hQZðã¶q@¿ÌÏ)Î+ÆiSNéwœŠëN¹þW{‰¡‹øe?|’/þÙ˜4`@"&–LÄÄ’‰¸zâÕX³s >\÷!>Þð1VÕ­2Cæqw¶² •¨É$ 6«øjÝWøbÙèì…&ž€#'‰I#&A¢R—~É»¦Þ…ypß¼û@¦2íº1bÏç!N7o·×ö^su¬ÿ^(r÷˜K»ö(J•×N?Â0=~;ðRb.{õÞ ý³ú§mXë;Ïüü-~Ë£4ºú9ã.úvk4ÏEG_„^y½pÛK·áÏ÷ü Í q¿›‚#G‰ÆÆFûð±øï÷ÿE]Km›Áùƒqéî—â£ã>ÂûG¾ †_ u tö:Ì>Fõ‚Áh(çÈrµç;Ø<ýíÓ˜~ÿtŒ¼d$.~ìb¼öÕkØP±¡ËM N¾÷|/Ш*X³~…Õ2âK²]ÝÐ I4\aÖ˜«°wÞ¥KIËKLû×Lì?û.øßP @‚*(¨ 0<ì¹ÛæF}Fv0=᯸á™ðÁO`Åÿ­Àó×<¡}†Æýþƒw;{Ä9ÿ9w¾w'¦í1 gM> cúŒ±m7¼×p ï5WL¸¿Uþ†·W¿÷×½šp-q‘É ”j„GD&`>¦%Íù h …Ú¢‚¶PÔ†jñÖü·ðæo‚…úôÃÄ!1vàXŒ4»õß %%zˆL;Má&\ÿùõÐZ<”ˆ&{"¤ iK#Ñî$ ¸ @6€yï¼óÎ+0|øð”ø ï`–ýÀ«lKæXÕ$ý¹ÄÕrSŽq8&.“:hÉ•©c²2¿b‡øMXÉîÉØÃ €—x '¶Ë×=ÿÃóøÇ§ÿ€”¥uà£Aj–œ°;S4ó›iß 4ËÎFØjÆžW۷r³rñèÅbê„© }CK.{ö2|øÛ‡ ~ŠñƒÇãÌÉgbÚ¸iÊîU!%„9ëçൕ¯áûòï¡Õ>6UØrNÔjæ¨!Õž_áp'ÓŸ‰ÁŃѿ¨?úôü”ö*E~v> ² Ÿ ?ˆœÌÈ’Œ¼¬¼´^£ŠXºi)–lZ‚ß6ÿ†ßËÇÚúµ@&´ë–Á]7ƒu‘@„ÚÁéñt†â•z¬Oz?Øy5lL©<ƒªQb­è!YŽ˜Ë@fM® ã~_\ôEJN×òåËÓ¦M; @ €:õ4hÐ @a)(A»ô‹•˜h’I‹1 v´Õò#(Iè|Ïó[’Ñ~èY“ÎÂâ-‹ñòâ—ÍuTK”‰5!Qà›Íßàäa'Ûöúƒ¸júU¸úé«ÔGêñ§‡ÿ„˹מp­V²C²YøÏyÿÁ¿>üîýð^Ì_6 Ö,ÀÌ÷fâä=OÆY“ÎÂÂ!¶}ü’G > G > [ê·à+þ‡7W½‰M ›,"!™Øš*1¿¦ðIˆØÃRa.AU'jVš±¸|1o]l/WuÔXóãX¦2²2²Ð¯°þ0åøËÑ_ö'u-ªk«ñÑ÷aõ–ÕØ\¹*6`ÕæU¨nª¶Xýš²§YT¢`23£,’fÏ—Òî@¢õüI¯GŒ9>ÙdC$ñ¾@Úx÷­ì‰ã·¡]j» <Ù§ìx±ªªžž}¢ë„hçwÁñ %gµÛW¶„[pÌcÇ`YÍ2­¬Îð(œ7Žìs$:ð¡h<¤«'acõFk¼àQ‡à‘sAAVABÇñÙ¢ÏpÑ/Òà}Ÿ…ví;l_œµ÷Y˜ºÛTÈ’»M¯2_løÏ-~NËW0ƾáé¹ LáòQŒJ”°nÚð‚ ÂŠ«óÿÜÅ0gŒaTÿQxúò§±kß]úíŸÿò9fÜ=UuUVuÜã²f€Ö(ÉdFÔQäƒ @Ø] ˆ×ðŒÕó!Xáù«ÌDLZpÕª$±!aúÿ®Ž´{`«ûÜ;–N‡D0û 1'P• Ÿ mçaððÈ)@n‘í‰ezy TíNú®ü;­²Ã!~ÙK½Ô¤.6: ~±ú L½o*oZœÐq2öÌúû,Œ(aBójDÅÜåsqÞ‹çaÏ»öÄÝŸÞ-5[¢Ï¡8dÀ!xþ¨ç1kú,œ¾ëéÈ `Œbo3¬÷: 9TKÌ“ èK¾9_†œ/CÊ“ çiÿ¥<ÉL*4x¤½gB¶¤NYUñ²íËpøÌÃñÁÏÄýÝO½÷N¹ñT×W›çø‰©èIPWøÌo@ý¼¢"D賎7R®x[í¤¢@µ"5m³0¬v¥"«?åK]¸®Ý‡Û°Òa¸xß‹5~€F#€µè×]¿¾;C;ñÛöß\÷?ã€3Pš_jÞu†ÂÝØ°Ç>|,Þúé­„ŽcPñ |øâ˜±ÇØ«FT ¼¶ÿšó/Lº{Î~îl|±â Wƒdׂ]qëþ·â»Ó¾Ãu¯C¿`?0…€XÍüÔê{Å5@Ê•L£ÀTþ¹–ò·-œò7×qÛ5ùšð—ÿþ7¿q3B‘PÔqÖ5Öá/wÿ×ù€W}ikÖ ÑÎ{ESŠ3ŠÛý«/;ì2¼³ð¬mX«µæh‚ Õ*¾Ùü ÆsE.>òbÜðæ We ~·¿EmÁ%o\‚…â¦i7Åmã›ÈÂS3žÂƒ³Ä=ŸÜ£U$À iEÔf/ÙKfc@¯øã¤?â{ü½³zÛ>'7‹»ÏÀ¹ãÎÅœµsðôïOãÇò-êa£Ç#¦‘±[Án8´ÿ¡˜P2r (³9DÔB ØÑ¸wnĆðÛÖßðë¦_±¤| "J$ê:Ý+Ÿøþ |¾âs\{äµ8pähhnÀœùspßk÷aÝÖu€ßÑI‡ù˜¿Ù˜K6Û,ûààÓÛ(SÛ¤!¤“ÌßéÞ/‘¹Õ‹ Öó®.íž0lXj¨[Í=«×hàbNÔ%öïÌ ÖD7À ïѳøm™£ŽfD®ƒŠÅPö" qQ»&Þ…ŸØ!_ÿɯŸàìçÎ6anš¥yÉDÖÍÄÞñú‘¯»îÛjƸ«Ça§²Óª(ðY9jHÅÞ}÷Æ“g>‰¢Ü¢„ŽgÖ¢Y¸ô•KÑ 6XãÛ7ªzòS?Ž}ÎÞçlì5p/ÏÏ[°mÿõqÌÙ8ÇT˜„ìU²®x-v/Ü=ésÖjÀ·ë¾Å—k¾Ä¬³PÙPi^K¦Zì—j‹†ª8[$˜Ì¿ù“1û6˜F—@¤hÃÀvŽ„^„6ÆúŽÊ°%b«\€Êå¨9| öç¬X±@ÈHiì.qæxöîN|7'·ÏˆZôA`òñG˜ÉÉÎ":w¿ªÚëúÅ’¶EUUüVý[‡»#ÆÝKw‡Ú¨ZÜó-z[fư°r!êBî!Š ?ˆs§œkå‰0]Áúˆ¦Ô2)æm›‡Ãÿu8~YûKBÇ3uìT|pÙP0@þ„iæ¸aû4¥b!¼ýëÛ8þÑã1åþ)xöûgQ×}œãKÇã‰#žÀìgã¤A'AR$\2ú¼tøK­RþåÏÂáÃÇSïÀO—þ„—O{'= ÁŒ ¯r½ ø%ƒ‚dêïeY} Ü’­mC²´Ï!ÄLú3Ê„å:lŠ¥Ç-Qº¹wùsvüsÛ¿»„(„x[ªŒ³U;7??(„ƒÞŽ!˜»un‡Ãe‡]¦å43“sÞˆÇGX?lýÁsßs9°r {«MqIY*” LÿÏt<ÿíó Ïð²áøø²qÀàÌ»ÚÈ10’åø–¹Ë*—ặ¯ÃøÛÆãê·®Æâ-ÑIˆC †àž)÷`Á™ pÅ„+â–+&*‘°ÿÀýñÀÑà§‹~Âu]‡¢Ü¢è&FºÂ7ûd; É…ºÁ`dûÓ€K%Âë"D)RüB:DÖÖ®ÅúÚõöý‡= }²úhÊ¿™YÍytˆñëÍ_{îÛ;§7N›tš­¶ÐvÀêà§ü߇ÿ‡+_½Ò5AÎ)ù™ùxñœ1cÒ Í°0jüýV†¼M9ú •F¼øã‹8ôÁCqÌÃÇà_Þ@K¤Åö¹Ùþì´Çü`>.Úû"|wþw¸ù°›QœWlVHØšå: ³%Ké­²?¾ÀýSGÙŸ "¤†²‹òÈmÂñ‚}T«/S4V45¬šñUU]3ú¼ÖŽ‹Þ’÷ÍUovذ“%ÚïOü߬š­ƒYX#_oú:æþq!H˜hûèa$#?4è:K[^ýýUœðÈ ØV³-þqQ·} þyÜ?áƒOƒ*õÖÅÆçÒ G¦²üeÓ/¸ôµK1î¶q¸åƒ[°fûšv;Ÿ¾ üeÏ¿`î…sqÙ~—Áç÷Y¡LÚÏÖω A+¹ÏàÄ)wЏ­·ÅÒ5aü¶Î¹±t„W(À0Õhœ¼Îîlu“N_ATc³–_H§‘·V¿…ˆé°ï?vÏc­ø¿£™ÓúÚõ1ŠA%ƒpðn[MjŒpÑÝ 8Kƒ¸T-ÀÔMM8/àÔ §âͳÞD‘¿ÈLx"21avšáˆµëÞ3õSÔ4×àñ¹cß{÷ÅÚªµízN³üY¸öàkñÙùŸaÏ]öŒ.û 8(}ŒáÝ é(Tðt¬÷o{žH''gg>ž´‡'w1˜ÑT&jf;a ïÖÆ­ø`õ6ü†”ÁðâáZÀÈ0ƾޘqè m¼á#ã\?=¦M³)*Ô œðÔ xå‡W:¾‰»LÄç|€‘ù#íŸmþ¬˜¹a îuë5βÁv;·…CðÖŸÞÂÿø‰l±u¬‹Ô¡ä;ª»§Xzv‡@‘Ø‘úß»O³×:ʱAýajÄÊäWU*SÝ÷Ž Ú~ä×G\‰nÚK¦Œš¢…‰ŒÅGŒÅ L3{ ´ï«‡ÌL~?4\7"Á®x÷ üý­¿'„~ôÍï‹·Ï~‡õ?L e©Ìjpz†·gê™÷Ò¡çV¢.ÝïR¼ú‡WÑËßË •ðÕ;â!)xðp~,}âÔ?" +æ üüêï²bp6¬¬Y‰×–¼ÖaÇ1að„èÆ9:bôÝ–ïb*iBfâ@8P‹ž—dXF€”-á™ùÏà”Ç4jÜD`õ§O}Œ¿@C+"Vûi“0G/A4ØV¿­Ã¯õ¤“ðÞßC¿Œ~s„ëE Zi ÒCCHúwú†€ú»2ÇÞ{~º5Í52wí³«¦ŒøX¾N RªÇüòù1÷?u¿Sá‡_3Z‚×3 ö&>²×Kä¾ßö=ÿ×á õ „âúîÇý‡ß¹EÖi8Ú j•áeP,ݾ´SÜê àí3ÞÆŒ!®½Œ†[‚r[,)ƒ÷Y' €Îp¥kä3< ß `Q™¸GH×¹D"¨Wã_þ£C¡(¯Èb Û=S ~@^VŽ›pœÅ„§W˜©ñ;q{½¡Î–Ð÷øqø`ab¹§Ž?¯úò‘o)Q£ QGLšÝ Áœs:Íå.Í)Å+§½‚Zb7 DHDb!nŠŸãë7=!]VÌ–°Á{kÞÃ;Kßi÷cÈÏÎ׌HYŠÀêÄÍ€³:K+ EW˜¿•‹ÙÏâϦhò5aÆk3p߬û2f÷°><ûC ͪ‘…ìhO¹;gËT7Wwšk^–W†gOyþ¿ÖÉAÂ$Œ!Bz’à„ú Ž~޳˜ýžMhU,Ý# @,$àÿ>ÿ?,«XÖ®ÃOQ{‰C˜À€ß¶ÿ†Í;b~Ƥ“0¸÷`+ …Ùˆ§Œßk<Îr>çþ¯ïÇùÏæpsÜãî_Ðïýö/Ùjƒ Ö¤/W-´°<¾ðñNuËé;×ì Ôz¬Ù»2Šp€X’éî×–P0:Z÷s¼ÞFf°ÂÌÌ~sá9úctq¹°]0{—kEÕ€üù?£ª¡ªÝÆ`ùŽò¨žüXS à›MßÄE2Nßÿtpö™`*÷{©ÎgÏû ‹4轕ïáøGŽOˆ4('˜ƒçO§ ;Åêi²*cŒï{fÉ3ØP³¡SÝûçpÆ׎»Iãb°Uòˆ*ñH0ûߦKÌüµ0â)îT'pP¾Ù©É€û OFõðRiŠ¥c­|#QN&ØÔ¸ §¼| v6îl—±¼dÝ{XI‰1%8yß“AÂÄL4aíHô&D§¶Õ³AŽc-ªZ„#ÿu$ÖTÄgòóI>üsÚ?qÍ$Í£6cëa«Z ¤„põçWwªÉŽŠ޼jƒª- `„`lá>qŸô O?ÕõýñÿRÌ+€Ö:sŸ­uc7ËÒâå:; q1nyírœöÒií‚Ìúa–iÔº7BH̾†ô-ì‹I»N²J Ãv%lNÄnô˜|÷‹=fQlS¶áȇL˜)ñ¯ýý¤Éô¨ùfEßoù|÷@§ºü“v„±EcµãÕ{2¨! ½°å"¤ ¦ª€Ê´Åœˆ“5õ’ >´Í”Xâ.ÄèY@À¢‹pìŽÁšÊôñÙ×Ô×àß¼€PhÇAœÇÅPÞ¼ Ë«—Çý¼“ö9I¯Ð+Â*˜Âmèã›û¢óü¿›dTçί“jñåŠÄ{•Ÿ¸û‰xåÔW£fƒ5©`-ªv ª †~|Ÿ®ü´SMÇ;Nóþ›T¨-ŠŽœèF€¸7z€ëŽϵ^ó}ªt‡0R&j„AUX`ªµh·è¯ÁÜ׳$Çs[œ›±ä°ä÷ wm À$2ñielë×ã觎ƧKÒ£´n}æVÔ75„hÓ%``æ:ãu"a€i“§Á?Ô°PC , íµ 0Åû·ƒ@"€€èµü$“â˵_BJŠªÄ=†}ïƒwÏz}}ý 61¨ÍÚ10`„áÂ÷/ÄÏî4sÀ~#öÓ€&¦--ªvÞ"L;_Ƽ î•N· ÙyîsvÒß wÀÄV h¶ V=ŽˆußÍóÌÝ:à—üø`ÁhliŒ{ÃJ†áýsÞÇØü±V³#=³¾ImÂ_ý#~ßú{§¸ôÃû ×øZT3wa˜a"¤»F`¼V¿ñZËŠ›Ý¦M°Ù(Æ­Õm€Aàù…Ïc¯Ûö‹s_DDi[Á>~gÞz¦ö}z‚Q£Yÿ~ªyÌÆòCùhŽÄ/Ï;fÏc,N€½* ¢Zå…Œ«2pŽa£J@bÚï÷«êWaKíÀA#ÂþýT쬈{Å9Åxëì·pPŸƒ4;dUÔDjpâ³'â»ÕßuøÌÔÎQ‹½‹hÕ@fo±ˆ%‘ùq懾̀„éD(€éyËǽ^+¿“ìÄo^I7MÂcŸ<†ªºä’®\ˆÿ~".úçE³°öùzâ! èÿõ¬ŽuhQ[0o뼸ß1u©™¬)ü0×¥Ráª^bý~¢“IiÁF˜—‘‡=‡í‰#n?Ë6ÅçKÈôgâ¹3žÃôaÓ5ž€3{Ô*µøÃ Àû¿¾ß¡—½)Ôd0±°îýëÆ’@„€hðô¹¦©ÑçnhÚ€Þ½£®…î<¾ó ¾üõKlªÜ„P$¨ª­ÂÊM+ñÑ÷ᦧoÂþí.9ŸÎÿÔ®ôƒzö}Po¥Ð3óõõF4±<€üì|ì3b+v„b‰u #20wË\s“ó:åå8êÖ£ðÍïßÄ=ŸäÃÃ'?Œ¿Lø‹³‡tÅJ0 cÆë3pû·'”_Y·uÉÄh+ÿU !B¹«¸%ŒØË°@@LÈ&^ ¹±O²ßk?QGµ™tyO;Ô¶’ÈÒ’ ³‚ΊÓS™"ÒÁ×ë¾ÆWË¿²êî{ü˜¿įçH0cí&O†þÜHZÀ_Œ0|µé+Ü€âþ “NÀW˾‚RAÂjX"P Y`ÜØq@o¶|•© „¢$·Çîy,Þøú œtÏIxxÆÃ8yÿ“cÛU„àÖcnEQVîøâ0³Â2ÿæþ 6,À¿Oÿ7ÊòËÚõRÏ[2Ïêâé þRU”QÓ`Ò÷a¬õ,zŒµ]¼õ6ã8Ö>ü}Í¿v<·Í¿Ž?_  ÙqÑʼn„t $€PÝ ×=v¾“ͦr$Ðl š£/Ù$Së„g(u¾=®Ù%û šeQññé†!¶cZ¶sÊÊãþiSNC†”¡ÁÙ!«ÇSã„<Ðêp5–l_b¾5cÊ A˜†qþãçãÑMè´^6å2ÜÌý aª³P–¯×ï>ÿûéíz©ßþúí(17ú¬' Üoxü64€!êµk9¨1a&x еn”]1ëð8õQ«•/—}OT¢y–<@‰¶?ÇÅo„Løß§{ÿ”ÙÇ”~,‹·/FIVIÌÃöË~¼õ÷·0ížiˆ„" !„´cU%Õ -$„0 }]4°Ç€=°Ç®{à§e?1†¼òlÙ±·žq«Ýhq‘3ö:½³zcÆk3RCÚy”´dË¡8ï¥óðƼ7pÇ)w`Pñ ´^Þ¥ë–âËù_~ë÷׋±è¹@ˆ@b"ˆƒ°h*`‘(DH'GŒÄ@×nzYK!åIò%Ð\ýu®)G‚”+™ïÓ<í=5 Yœ÷/;¼.9/'ƒ ¥:ôÉ#&ãÎÓï4ÛÛšñ(‹óûõDDgþÁùŸoKb|dÎ#¸ð© ª˜:j*^ûÓkÈ¥¹ÝÐK/?]ý)ö»m?Üþ¿ÛSZzé”럼*TëwRë÷šÿ…ÒM €Tè¥ò³ÄÒyÈÆ˜åÁ›!ÞÈàBº1 åjJßPøRžnäqÛéÐ? P-À©üžçõ{^ü@~ÂÃûœCÏÁ™“Ï´úp=Ìp@‚çàÇòmeˆG=9š¡·þ}ý§×qÖ#g¡9¿\qŸ!ûàçþrÝÐÏiÈŸ?€ñÿ7¼ÿêšêRzëÿç½ÿ`ö³­ªžAGjl€¸zæ}ßû  £­€ÖôqwI¢ 6(z©AŸË,úÜ @ƒ$ YDÏ Ú’M åØ_Ó,}É Úþ~Š‘`}G <¢`8þ0üIî{þx7F×hyC5/ ˆ00ff*ÆüýÿÏÞu†IQeí÷V‡ÉCÎI$YÌ‹Qd1*bÎq]Yue°îª¨˜1î§‚ baAP—(* 9g†8©SÕý~Tèªê[ÕÕÝÕ==Ã=óܧ§»«+×=ïyO"K!üoÏÿ´õæxs0ôŒ¡òÓïà„‚¹æàÊׯp¤°»6·ÏD}} ¢lË#ŸS¹1Áqrÿšõº<Ðÿøh4¶ìK½4ó”ÿNÁƒ¯= dz ZƒÁ§\¯rSif>N­Ÿ,âÉ©ý«;àêŸǃD_!È¥s©€Ÿ9r ]¨ýyH¾näEò”esà' >e}‰Ýdýü@á!ž„ïï_.&Þü6|¢R€BRJKJ©[I¢ÑÒ¤vÇ- ¦-ñ5g_¥Í=|òñü´óg\òÚ%()-‰»wÀ—w|‰&yMå’Ü€\’ØOäóTH@ ”yÊ1qÑÛ8}ôé¸ðÉ ñîœw±çО„ÎžCûp÷ wã¶q·A$’\Œuà—Ë!ÃK¢¥™ù½‚u \ý' ^ÔDàÄUÀò¡&‘hëžpúMp\\BH4UOÇ,ïb„ÌÚoõ÷ ãþi_«=.lyaÒûعEghñä†'cæ31ôí¡ØY±S¶Æ=Q— õPPŸ2‚Ëö,ÃÒIKñàD‡ÆЧStnÙZuBˆ-Q§¨¼/Ž•ðë¦_1gé|ûó·F‚²«E9È¢Á˜J†z †óÃ¥ê\´v®[»åi’Ÿ³Þ[µõO×pÀ…KuÕþº[P”ë×/KlÖc1ÙÝÐñ†Øu'(÷]t>]ö)6•n<€à4EG *:›Í¬?²Ê aACí³á§Çškä¨y%;‚xe:}Ãñ òæ|vÇgh^·¹íþµª× _Þù%†¿3›K7˼ъ„ð+± ~9žaÑ X¿`}´Ú¡C|ƒ‘­-’CØEžò”@L¿ð@@.\² ¸–óhhÓ¤Ÿ° ›%pžHl×~Rj Y™ßé?³—Ì' ÄæÒøˆCN’ò®ø<><=üi\ñÆpPÜùPí:¨¥À lÐ,¿®ípz79µsk¾»µÏ­Ø¼ofþ2eb™<… ðl+ÛŠ!o Áçw}Ž“êŸd»Íê4ÃÌ;gbèÄ˱áø$Ê(À‚úêh !¢e8 ¢tõŒDéâ É@×(ûC¦Gä6È9Ä@aHäTIšPŠ/— 21ó¸[LµgÌÛÔûê û_ÿªéjZ¶úפªûýŃùùÈÖÑ·Y?ÔÍ­ëÊýÞ¿KœÛº·Ö¦W QHa I¤Ñ–·¦ùìž®÷bá°ð—îA†§ÂïñÖ™ïÏÇ+×¾ŠUOýŠ[þt+ y=jp Ÿ`W`þüúŸ±q߯¸ûذ¸!fÞõ%:×í"·1q$WީТ©–B-¤Xù¬HQ‹2B¤@r€&)äÏÕQ ÄfäFýÿT÷ÿó‘Ö¤‚šb–Uï4@Ö•àw,Ù0$à‚¸zË?rÙ#rw¾€È‘új…|¥Ž‚¾cQ4ÍÒSä1¦fê>7Ô`ЕaV©­PŸø : h{»x¸páÂ’s›žëêúÎjú·ï/wç (þôpl÷»“ŠN§>ðúu„I×O‚OòÉë„’_ŸCp(r—¿u9~Ùþ‹#@1ãöèR·‹ÜD(,Eî+¥—µ‚L # \Rk0èÞ«š´: y‚æûWƒ¹páÂ.U&ò¡UQ+××{ßÅ÷1‹©Mqàº×Á'ø’Zïv½ñÔEOÉëŽAÀQé(†½= ÿÛü?G `úmÓÑ©v'¬„¨* ÚU1×Ôc¡@Ç ˜z5hV¿Ú³Aø§)»€M.™cg¹T ©ÞÝÕzÿV}Ì Ø®ƒDºR÷zè—Ñê˜ó^5BºÕë––õöéÜíê·ÃÆcåÞ>@ð IKMüS“?¥´›{ÝŒ™«fâÇ?Êùõ^E¹úã¡ã¸âÝ+ðñ£o‡¾¶ë©WX3nŸË&\†õÇ×Ënªäì« Õî†DËKòók~´ÔKAIÛˆÜuºçÝJ q@À"ˆ/f^L1]ÙÀ¼-nÐë Vo€˜~5¤éOäÂ% `‡ÚÒ²jBné žúp4¥ÎOe+XaN*>)åí<}éÓèûB_9EJ¥=¯¬€áFþg$þsÍpAû8‡ú…õñùŸãÒ —bci40¿ ÝwC÷†ÝѦV4+l†ÆQ;§6ŠüE¨•S˰žòp9"R¥¡R ÅñÐq ÁÞò½Ø_±ûÊ÷awùnl?¾{Ë÷jÀ@‰’äw\¸pa”¯ cùÓ$·ëއl¹TË{óäZ'§mõW÷½ON}Á`PÔKeœû‹SÞFçæqa» 1{ýlЧøˆBá®ÿèz¼}õÛÒÃ>Õ±AQ|qçøë´¿¢GëÔy:5ì¯à|ú)ðjåÔBó¢æqN?…(‰  ˆ`¨ÂX©DH ¡4TŠŠpއŽãpà0UÂÁʃ(©(ÁβØS¶{Ê÷ ¤²$ÚbZW8Êppà^ …~@½hO€2Gs€ —4HóÂæi[wq~1u„ÏW}meì§ ¢\(çxè¸+ àú^×cÖªYr{cZ2 DÁmSnÃëá×1üŒá¶ëjXÜSn’‘sO@,ÁEž7yÞ¼†ÁJ*#•Ørt‹66Ý„G7bÝáuŠÁXp@90à€5t­ÃaUˆ$Žäœì{Œ¿Þ©eÏ€e5Êo”ÖM ;g>[ú™ìÈQ@€O.|³§tŠë¥úwí"¡¥•¥<¨‡ÊQüºr»"qϧ÷ 2\‰ëþt]»”yÞ ‚Oƒ=ÑöÇ"1ê‹Q†ƒ¸µï­q×[,Ǿcûв^Kø<¾jy}½‚íê¶C»ºípyû˵çtÓáMX¹o%Vî_‰åû–cÝ‘u!²AgÒ6ÇÙ­Ïj¶ûßÉ<Î@¦Q¦_`Ÿ ˆµà5g¢CΜ @º[ž?çu9³~Ÿ%% àç?ã²—¹²'õÀ¬_fú(ˆ_®ë¯ÕùW ï@Añð×£Š&EMR³X kÉ¿(³ RD’·!yP™ žhÅ´^m{%´‹ÏºoÝ÷nýv¹›·30X¿’¼]=# ŽJ©¿îü¿nÿ5ZÕM<ăV [á”§à²s/Ãð>ÃáófgàaŽ7Ú À€6ðžÃ/{ÁìM³1sÓLÙU À>v€dÏýïø»x•Í ºÖ¾1:€š–1/ϪæZC¦dÞ  wsT?© Wfd;§µ;MVÎ:zžJ!1„W~z%åõ‹’(Ox ë×7Òèj¯\,¨k“®†u,Ù´$îvFôçoy^Î,ðšúéš©Cé @ Iôÿ|"· Î äʽ$Ÿ„­‡·â›_¾Ám¯Þ†sþz6ìÚP-žùžMzâÑÞbéMKñ݈ïð×EëüÖ@—Œv-XÝë¸dØpPÅl.Y$A1˜‘íô8¹‡¬"ˆÒóŠø¿_þK6¦´þŠÊ YùS“ÕmV4:pr]cĶÛâ™ÏÄÝÖƒîÀß.ù›<+y¡’G´&A¤ˆÈ`@×Ð0°@ŠtÀ €hÝ7Ú€~ôÃ?Q­î§®ºâÑÞbÉMK0wÄ\ÜÞåv4ð5ˆ‚‘ƒ.ÕPJ] ¥Æ[ÎÁÐhG>øp0ŽŽdäyêÒº‹¬ôU B5–Âx`Ö¨”ôúwØC·3ßÓ¨åZ/¯žaõ ëaÃÞ ;ilÜí=yÕ“¸òÌ+ ™1•®¤DÙ"SPdjGARHP.”ㆠ7à‘ADŒT»I»GãøWÿá·ÛÃ'—~‚a'CN$Âb{­øH® °I§¸¦Ï8ÀY.5Gö•ïËÈvÔn€:u¢,€~¢'ÀO»~„Ÿ'$½þ ;7ØO†:@}Í÷åǬçúó®Ç Ÿ½€±ÚƒBÞ¸õ ônÛ;hH ¹HŽŽÈ“­zú×»XnƒZÑWRHðÆÂ70dÜì;º¯ZÞcâAÿÖý1að¬¹s ž?ïyt«Ý 4$ß *0¸k8+À¥FJå¡ý¯û,¡‘ìïh ÛCl—LŽýåû3ö(thÖXó +mr ðÏùcñ݆ï’Z÷’5Ktõíµ)öP¾ó ±Av};õE«†­ðü´çðÄûOØnÓïõcÚ_¦á´f=ee¦¡€@A|‡ 9€«€äBOd`$: u¯…~Þý3ú<Õ?®û±ZOäÅ9Ÿ¡Ç ˜wý<,¸æ{ÜÐñzÐ| DAChXHòy¤ÊùTGV<3.ω1÷ª~ý*Jp}êïkª¶€ÅÈH àÓ“Nf U°]>2;vÛ‘±g¡Eƒ ¦ =mžÑ#áÖ·bíÞµ »ëfÿo¶fÝSÂŒc/ •ÆN4DÀõ®ÁøéãñÄö ÏŸ‡OÖÅ­!)¤•QÝŽ ^^êƒ\‹ ‡~"¿jLäyä+ï ˆâB …ĸäÕKðò¬—kDŸ÷κàù _Àïw­Æ¸~Ï¡CqGH! ¤°î\šíŸ*fÜ‘¡õ«÷v²º‚3ÜÀ…‹­l;¶-cÛjÕ¨•Ñß+"¦Zßqé8®üèJlØï<~Þ²yؾo»FÃB ©h̶®éw <^ ãgŒÇãÿyÜvûõ‹êcúÝÓQÏS4 —;F8êâP÷‡xä6ÅÄKd7nÀ¯æ(#ÈyJ<S åIóÍ\õêU8\v¸F܃…þBÜÔó&,ºy>ö.lq!H˜áhà á^áîîà¶„2-„ðÔ¿ê,›ŽnÊØ¶šÖk£üµ{–È€x öVîÅà‰ƒ±hâ¸ë GÂøÇ›ÿˆ¢QËþ Jõ?p4p”¹Îfõšá‚žÈëð¼ôåKxì£Çl÷£MÃ6øäöOÉ…T)É=ÂJ]Éô\êŠæhûËðÃK@òäR@0wó\ôúg/ü´þ§u?öiÝÿKnY‚;݈\škh"¥Vwä@€€êdî3#]c …Pľ—v¼Ä±÷ËÆÃ‘2aÞ°vCC±-@ŒZÊÄ#+¿CáC¸üÝËñØŒÇP(·¼¼úÖn[«){­:ŸGž5ˆògxDàêW£C½–ûzÃ7DÁ+ß¼‚Ç>¶§·9ï^û.P Ð ZeT0 «çÑW€èk9‚T˜'`op/†¼4ãfŽƒ(‰5jÂo]§5ž¿èyüq÷ó§1(’Š@TÎ Q-€P»DÝyMuˆî<[IÍ»V:ÀêÕ.ƒBàÂ…‹µ„Ä6Ùœ‘mÕ¯]?šªªÂ&>Ùò•|Þøñ t~¤3ž˜ú–¬_‚#¥G ±ô¥úèP¼ûõ»rP5ú^MÅó*ÊS©Ò§gªîîq7^9ÿäyó,÷uЃШN#ÍJ'>‚W羊G&?b{ŒƒOŒ'=!³YQ˜'NZ=[Atì€_—]/»¤| Ï|û †<7;KvÖ¸û³0§÷žs/6Þ¿ß\ý Îo~>„`p0YÎ Ô(Éx)`×èô8Q$T¢òä¤ÿžÕ ˜ØßÔ¶}¥ã …óïi¿ç’½Ì€ß÷ÿnk »%u ë­‘a¥( ¾èwÇ*Žá•ù¯àåo^–©õbU‹rë_Õu@r%©Rè  )S \Üúb<ÙëÉøŽÇ‹kû_‹ñ_Œ×2ñ¼1ÿ x<íbu¯Æ(ŒŸ7Ï|e]6ØïõcÒ]“ЩN'ÐJÙw<ôUW½ƒ yŒ•IÑ Mýe*Î~ìl,X½ ÆâÖœBŒS ¥ôð»?¾‹39ó~W£ql§&0åº)¸±ÛZö…!ø²:õˆÇ8°ô‹çñÕP¼8DElñ|7UaÉBj¢ä¢³* ðãÎÑ«e¯´nÊïó;s‰éü¶ª/—‚jV¯êÿ×À¯å¯äÓ«¾z}°Ýy-ÏK~¿½~¼u×[8é‹“0nî¸( Œ1ߌßãÇÝîfþþ̶gâ¥+_Â=Sî@„¨ÿžÈq@ÄCóUëã@‰L¬fRèÆîÀn }y(®>ójükä¿Ð VƒjÛB¬Ý±«¶®ÂŠ­+°rÇJ¬?´’OÉ%±q®ÅTéüGÓ¼<UÀöd¨J H"ŠßÑÍJüžÖÌ›ì„åÚý°íü½×ß37YÕ©°±t)¡Q«WRž jšà“òWÖÑ£a”ï?.ÿZ7jû¦Þ‡°Ž Á£_> ¯àÅíýogþþÚÞ×bõ®Õxkñ[%NüD7I)(SÜõRõ „€ TŠOV|‚Y«fá±ËÃ-ܯ§zL«ÇÊá× ¿â·Í¿á·M¿aÕ–UX¿s="$"3=>„CA(õ^ D—=oÞr:ßQ—g×6l@¼ßqPÝçh®a¹¤—ÕY¾o9Ž£8'}‘ãP@› (¥òd ¥ F×—~q½%F6¡IaWŽaÄŸF A­¸æÝkŒµLPàáÏF®?ן{=ó·ÿ¾êßX·wlY`¨PhHëK4bÿ'DDZlÀñàq<ôÉCøháGøçˆ¢÷þYu/î9¸¿mú ¿nü¿nú¿nüÛön‹f>¨Ï£3ŠTegUÀ§š*C Ê«j •'ÜÖ¤,C”›WHÑʦ’Z)µÔ1)Uæ*ÊØ¿c«#‘ÂX¼m.î08m› †ƒ6]&X.zF€Ä1ÝLÌZ2þ+9¿óù˜të$„/0jêýð{üqΈ˜ßy>¼óCôýWl-Ý A‡q¨à¤ÆÈÊž‚Êÿñ(͉<ÀïÃeÏ_оúb̈±8­Ýi½í>€5[×àm`í–µX»u-þؾÇÊŽé¢]Ê”¾rž‰|,Ze/t5¨8Æ‹˜OŠ ©1N, ¶«_Œ>±s ‰`ØràToºsÖ$å"DŸiÐÓ4µX&Þóï•«ÿêhþ+׳6ÎN+0×Ä×c€„­Ý¥<\Ž_« àýÞǵï] ’fa‹TÂÝ“ïFŽ/—Ÿ~yÌïŠó‹1õÞiè?NÎc—Y±iñHè"@ ••¿ w\„Ñʉ^‚…[~@¿'û¡oû¾¸sиøÌ‹å8ähéQlÚ¹ ›woÆÆ±i×&lÞ#ÿ¯WôZìÜ%QWàÈÜØI‹—ðèXåXˆOIÿôÀK<(ËÿŸÂD•É9ŽšþIvÎå…€ªÒÂ2EíkµÉcО…vM¸0ÂcNà¿›ÿ QáMÓ²d¡õÏ`ܴعõÏG2ƒ€`ÓáMØX²1-B `G/¹ÄzÙe»—á@Ù´=æù9ùøÏÿAòd+^Uà \*ǰ7†aÍ®51¿+Î/Ƥ{&!æE+Ø…¢õìîàÄÊTÀH´²„<ÁÀhe—õ•õýXï•åÕRÍ1J]gÝ[YõB®ííK äQE¯”‡†WQö>™ÙІ]M…d«ðÅ[Þ­Jƒ°Y,¶ËsP°B‚Ý©£oý\¸Ø0_þñeZV_¨`[b$ÍÖ"4‚é«§§õôµoÚ/Ž|1Zó_×;àXä.yålÞ¿9æwZt›7¼)7 R]Šò70„Ô¥k¬g….÷Ã@á ù:Ë_¥ä•AŠIÌУ߫V½™Î×ú5˜Üy «^oÙûåýÓ”½jÝ+Š_? $t¥ú_¦¦LšÅûÆ@*6šëL yÏúüçè{I’@©ÄX.þ 4 »Xäh;$…ßò‘ƒPÌH“¢ GÂÆûr=‰Œ(þ³òHTJëã>²÷H =u¨(¹ø^àP¨~ùÏØuhgÌ5w÷½4 •–€°ÚÕÎÝs¡]Èלsë}Äeä‚Fõ¤ „|Ý(ˆ~G  Ñô‚2H.Œ#‡@ÈU>÷ë†OÞ>|T PT†GZž*s\j#ʮڜӴ D{h¨Ï bçmÊÐ+T®òùüö±}”Z0@hLM"N…:ê*ÉÇ 0ˆRƒŠ¬;´k÷¯uýÁ*«(3lGý_­è›ÖGB°éÈfÌZ7+íÈó×?º9uAC4¢Ì¿ÁžŠ=øóËC°ÿØþ˜ß½j,Îly¤…¤ !@RÚÚæt—¯¹ö¿9wÞK@}sòýÐú —y6Cˆ\ÝÈÑ€úåó?‘_ÕÜ}-_Þu¿ ÷Jª÷ uÇ“REqº±ÞeÊV^5©"pƪ ©T‡â®SÓŸÕwNއ G±|úû§®¯ÚÖú&™9¶~x!í,@ƒZ ðÄÐ'4>•gOio¼µt+.{õ2.;løßëÇw}€ºþº@ömmÓàúa¹ˆOW`'öÑÿJüІú{mx£¾z-EÏŽ¾'5ðK¥Qó¸×ëuMŸÕxàöAz«EQú\¸$ fþ1ÓõgáXù1{¥OÒ\¿íÿ ŸüòIÚOãõç] :D•¸ª¼•Ö½k­Åð7†ãxåqÃïš×kŽwo}$Ddankëf<€07Wò ª¸½F``ðÉë—±Sò5]Ñ'Z(-ÕÂjq~ï%Þtab¨›@@;ùúhQ‘Q§YÑÉ9i>ªc$ Øvt–ï\îêƒ%Š¢‡™¹ãþõÝ¿P,Oë$âõxñËÿ![òjd¿¤Dß{ekyÅÞñæT„* ¿Ðm¸èh@ ú{·ê$Ã7[„D9Î\¹6T¤ì, ®œÙ"B:”|&Ð q­ù¬`5¨q¿¸p`òªÉ®®¶¼²œ­L¡šJu¹½e{1fö˜´oî²s.Cë:­e7€Zà‡R­…0ñü¸óG\7ñ:„"!Ãoúú´í£CZ`º\\ÒkéW‘½í÷ùÝÖ'5— Ô]¡ßã_µÉÕÈ8ª ÎmòQ˜ÌX3å!÷,åÊ`¥uo‹L°ÊqÁ{ËßÛLë\â<¸ãÂ;d„Fåk•ù0oÓ<ÜúÞ­%ÑðÛ÷îx rÈ¿U‹…ëÏ­ú|$>§Æ›;Ýf;`šËgý”W¯Çë–n̸)3¶-œ¸_ŸKÖXÿJùÔ²p>ÿýsw#ç?#=1ôç€z(îšvŽVMëf¯é r‘+³j<²jàÜ̵3qï‡÷غFµáí[ß–•¾òûŒÅœ(V{"=MÃö]ôÿºmêôßã: eTwºhœÏ¨$É0Ü-–#×—oLô»[—<òŸKJ Ó|ôËG®­²¼²Dù3ƒ€Lñì,Û‰»¦Ü•Öç¤vam î94,+oQŠüP]¤½&¯œŒG>}Äðû󻞿ü«!Àq<—ª4ëv¸Ž« ¥TD†»ÀgÌ IRØMå™çËs†ðH0Y ïwn3 fÿ-©‘¹;'&°l÷2¬Û¿Î•U–U–­qÌG«,€Ò oöÆÙxoñ{iÝäðÞÃeË=¤sHÑ™M+Å›Kðæâ7ñâ·/~?æŠ18ðælø÷,¾1>ñ!žè÷†u†6Åm¢i‚êzSVån̓ŽÌ3‰VˆU^óýù®QÃ)r- KÆÚG"‘°ßïw˜}FÄTÅÂPîSRàŽîáÓzyû`)§ûÌA€úuªŸkHÐb¹t€ .U4ÿŠ ?OÀ+—½’òº*ƒ•Ñ.eÔt?eŠÎ¦ÑãRÛÆ.Úº·ö¾5m›xÆ@x P*‡ ù$^!ÚöWPf8弌ùf Šs‹qk?yŸ"àHÙLýy*®êuº4ëbXIy –ì\‚ÅÛã»Íßaã‘Î@‰ž“võÚáâvãìfg£Cý¨“[…9…( –boé^l:´ +v¯Àâ틱rïJùÚéç#óú«cÓ‡ô<³d;uÈÄ[Îì÷5‚.è¨~Ög:}¢¾æûÜ‘H$œéËæÍÀ­@•ƒ«T˜W@@¿T’B¢%@`*i%hl ”þ† Ôø€Ú¡Æ]Niœå2 qI÷DIŠi¿MÅöð(²rúì!Ô-¬‹¡§4©ÓštÀ)ëˆ=â†Þ7âÂ.Â+xQ¿ >wŒÁ¶Þ‚ÿn˜‹¯Ö}…Ÿwü ‰HQe­8½ééx¬ïãèÓªsßkçÖFíÜÚ8¥Á)Òq`Ïñ=˜þÛt|°â}l;ºÍØv—d1H5ŸÚôkqòžÆ±î™ À˜.­öNõ%õ­€)EAn+ºL’$µk"¤ñ–0œîp8\©?ØT¥0·Ðº‘ƒª·,]éRÐ~2%ƒù8Ë @¥ÀûKÞOùY8VvÌ 2Y ØpLÊ+ê¶߆k>¼Æ…ï¶ èy¨%ò•çZ-wëVWô‰¸ý£Û±pÝBmƒN„¿ z³–ÍÆˆ×F Ó£0æ«1ØZ²Õ°­6uÛàŽ³ïÄ×7~ƒµ£þÀó¾€³›œ‘K K"Em¼wéû˜{ý-•¿•4-nŠûν+î[‰‡„Sêt’ˇåuK…ÖÎÄåù«Zšä²ÔÇk¨ÿ¼(¯È•{XÕ‰áp¸ÂbÓ¨n F÷27@‘¿ÈºÝ¤Bí¨í€µÈÞ4â©|$šz¤RÈ,ÿ)’¨´¥?I¦€~ÛŠþöðÐg¥mréÝ­7¼§"ÍoO¨ÒÆV­ºç'yB¸râ•X¾%ZéñaãòS/ PìÙ·ã¿îwÇW‡`ÚòiF‚†í6*j„[ϼ³o™•÷®ÄCz}›õÅ‚›àòS.OmR&†t‚ïùï}sAh±1q Ùœ²(%ø>™–Âp0¯Ãf}`œK šj±ýZ¹µ\•••¥™¦y…4)ü)++;0ª–%)uòë$ÇIpá’ ¢ÚSºÓW¥Ö%°2T[w¾*)b]Z ñ¼·ä=LX0!-›êت#êÕ*~%ŠßΧÔ(€W Ì!¨$•¸â­+°v÷ZÅuAð÷ýu$+Ú …”°à÷¸å[Ðîávøû´¿cÍž51ûк^k<:àQ̼i&ZÖnéÞi$Ã{ ÇŠ¿­À}gß!,ÈéŽaÝ1JU<¿Õ„95ÉchPØÀ•Í«:±´´ô0âgÔe-°J¢ pøðáCn€úùõÙQ´"¬£l©ªx¨A«xþ»çS¢ÉË+Êcƒa%“U“ÁãR•AÔÿÈW`Ö¯ééxF»34@U¢)}(Qêê ÂÐׇb×á]šåýÉŸàг¯¯Ô @8rô&Ì€³Ÿ8ç=}þ³è?i/{¬JANþùçâÛÛ¾E›‚6 eLŒ‡Óy«Z 1Ée©é3j±.ªûÎlå³Öczžêæ×u=zô0Î¥5-PHƒâg’3;wîÜ«ø9\ÙñFEìwÊ.8Ã\ ‰óÊ qIÉúWŸ>Ø|t3f¬š‘ôêŽW]7©B&Àt|ÄK y$Ü>év¬ÙµÆõÍÖá4y’¶JÛÓ"(L€_vì©ØƒÁ/ F™ì¡!ïÝûî¸àŽ(x7¹ø–o^Ž¿üç/8ùþ“qïîi<”.9³õ™XüÀbŒì6RîgŠ–2®6€ºµšøúhŠÛ‹§^iüŒ«FÅ\9~U'îܹsŸS}ší @ÌÎ/]ºt „B!W6Ö¼VóhN¿Îדú¤L”Ú÷ˆiÏg¹¤|U|ðazœU«ôùùÏ'ÝN÷xÙqgp¼ xJ#¥þæp<~ÐU=Ôé¤N2%.F ùêû›KëÜÄG°õèVÌ\9e2D@E ãoG.„YòX8åÁrCÁ´e9°$ߟ ×LÀÛW½|)_fÌ¥Œ¥8IHO¼Š„ØX. ¶ñêr-ê´p¬X±b+ì«@d%àˆ Ø´iÓ1È]ÙPž/9¾ËV…BÎÔ @GIï-ߋ׾-)úÐÒúΖCÐùÞ•(ü¿ÍÀS_<åÊf|^NnzrÔg/n ÏŸ‰y¹öôk±ä%(È-@ß}1mÅ4<6í1D€ÇãÁæ}›qU¯«0ù/“£åÇu @8óÅÛ ’ëËÅ‹W¿ˆÿ»áÿPLŠl€”El@¼¹1•J‚©š¬NLYÓ¶ëÖqåøU](Šb¥èã:Žf@–X.W)³Ï=™Ñ°¸aü*P{ª‘ú”Æ¢¾dO3 ä’¬¢TÊ+?¼‚=G÷8zdGÿWaJ Ëâ&~‚ñóÆcêÏS]ÙL›¦mägYOÿKÓ§²Owœu^¿ôuthÐÏ]öÎm{.AÀ«s_Åø¯Æ£UƒVøßúÿaûÁítê |>êsçº.ݶ4+n¡ËO» ZˆÎõ:G[$§Ë%Íó\œÀL¥.ÙüÞ€4©ÕĦfTVVäåìg,€tìØ±‰D\ÙX³ÚÍâ#:'7nª5—x.)*I•(Ëñ÷Ïþž°a«àIv£Þ÷¿<î™|–nJ]‰¶hÔ"±¯O½µH¨:§å9ø÷ÀG-io.òüy¸µ¯Ü'`Ì´1˜ºx*Fö‰1SÆ`èÕ¡f?8[ÎÿVÖ5i餬¹Ú4lƒyÎÃÐ.CYUQ3 ¿|&²œìµžã›×mîÊiRuáÑ£GdRñ§ƒ`Yý†ú|Ø ¸— ؼvsƒ?&#@R|a¬JvQ¡ñºs™ë TŸd´Î+«ž'_­ý ßüöMêj6£ø€°ƈ·F`Ëþ-)ÍMë5µ4=§ðÌÀgà!ž˜õ<;üYœÊù "ÅoÞ‰¹¿ÌÅãW>Ž«ž» ‡J¡[Ën˜ûà\´,n ˆÀŒå3ðóæŸ³äçäãƒ[?À¿ÿüox‚©{YéðÍK.-›ŽL‰­;ZÔu7@ÑRšu1ñ -ªŸ‹¤?þøcà^*`ë:­MŽz€ÀÂS¶Ñýñn.\Üd<²rüÛô¿ápùáÔ’=ǧ§®4/ü@I¨#'Œ4Ö3HP×mlý¼šä’S.A÷&Ý™ëñ ^|x÷‡hÛ°-B¡®}áZ*=„aç ðg‡áxÅqœÜèdÌ}h.:Öï)"áîîÎX-§ò—ÁÌ{f¢ž·žЦHfK\€£¬ªT˜ê`›V~¼8­“ëŸìÊ9Pu¡¢õ¥ìÇTuåÊ¥»°?}ûí·Ý'Õ= >Ág¿ÉÊáMýâÕ”NUò>’²=À¾Š}¸wÒ½ñ`A0ü^ ÍòãÔÀŽ’‹¿¶d-®›p]Òë×®¿‚œò<_{êµ¶ë*Î/ÆŒ‡g Ø_ŒŠÊ ÿ÷p :m‘0†=7 åÁr4­Óß>ø-Nk~6íÞ„+_½R+&”-Ò»co,úÇ"t­×ÕȨY‰2n-—n+>ÑíK0´Ó¶[¥^mê·q(ºÑÌ-§•þwX*~õ}EEEHÅ0etëKVê×¶xR#ü©Ö=ú¿Vý)úžJ(UÛ»;¨Å]H)¯ć¥_„(ˆøfí×xwá»ö¢Hf AV£ÂÃ<Ä?ðý–ùxpÒÉ­Í› ðuï•í×Ê-FŸ“âwé;¹ÉÉxý®×‘¢äØA z8ÆŽ‹e—bøóÃPª@ݺøú¯q^û~øñŸèßaÛmYšÕm†9ÍÁEí/ H A S@‹ Ð÷¾MÓ N‚ÚSYã;jõ°#é>—ô}â£÷ŽÚB°A-wzèÃ!+½™N àv€—\ ƒÁRu™ê ^«©õÖ¬|õ1ßQ­’˜¡‰H‚÷g¦-P3YÕ:†ýÙhüoÓÿ,ïÿ Û7°©LT“cŒLÀ{?¾‡‰ó&&<ÇÆðˆ±Ïþ¹­Î…Ïãs´Îa½‡ax¯+ ؼo3þ=í_¸éü›±hí"Œxqá r 0}Ô \ÚóR¬Úü z=ü'|µä«¬¹˜rÏÜÛç^  AáêHiÂMS`ž»µ{‚Z;ªí:ê²ô›ÕiêÊuQu ¢YÝ;ì¸Â¬dìBå$ÒñãÇK÷2ZÔi©ÝP’‚¨$mHògêÎPꨇ´dXM€y¢@ÝŸ/ á:òDD×Ã^à% !Œ|{¤eÜŠu+ éêzå@¼¨€9Ïxs~“Ðý!vØóG¾ý¨Ê«ª2¨Ç |yÿ—¨%ÔŠVT3ÌJ/-ŸúB­µˆ†I§Ãš¡jõ}(¥èÞ¼»+ºK \´hÑ* XÇ ®6.€D³pá”RêV-€†E åê\N3(ãtLæ÷<#€´ Õ:öÊ9óÛoGÿ§ûãçõrÞùî’ݨ+e¥éQ”(!±Ê¿š°PŽwGé\ñêŽú#x#q½üz Ï1ù9ù¸kð]@ĨÕž_­ú ¿nÿÕÊë×G¿nýðï[þy/΃HE ¼ ^™úJV¸Îjwæ<4MršD3”>¬Ø‰¬ï`^Vdè'Lltˆ$»š7vå„ÃaPJéÂ… w8°þ«• @²¡Ü Ì­@ÀõZXc%Óg1í‚aD£éèüG«ŠbàR½Y¢XÅjœŸàHø„Ç'=ŽÅkƒäÈŸŸEÚ))Û]VVT£@øÐ€(¨‡j-u#Þ^œó"n~ãf ZY]Õ] ÄÔȺïÔSñôO;šàõǪ±{ºÊ É¢zµêaÈÙC@úZ"ʾ^~ÚåŽÖ‘ëÏÅ?®ûæ¿9«6¬Bß;ú¢Ç5=ðÂÇ/`ûÞíUÚ6n‹ÙÏFÓ¼¦¤ ¦"’¡fJ̵’’¼Æ¦®¬n®3Þ{ÃýÆçö¥GË®Yÿ èBsÿJs `Ö7²"P¨îÀ´Ü´iÓ:À½@À3[K±Ãž`ÝŽ'˜8 £e¨{@ŽÇœ L€Ú¿>‡€ä<å5Wþ ~YaªÕ5& º/£{à³³ŸÅÔŸ¬i„ÒXánxŸá2EÑQÌhU?1«°C˘?a>îºâ.¬Û¾½õ:^Ù½oï—§¼Œ-»·dô”·iÔ³ž…z¾zî2ñæSJ[ü)ZÿŒ)Þ’ +lS¢àœ¶ç¸rìªîÛ¶mÛFÄ&®Š°CÌJëtY2³fÍZî&Щq'Ô-¬kÛ¼Á¶Ú¯9šßáDB-þ¸pÉ(È‹‚â# Pm»F›×'ƒ›{>ºË6-cþ¤¬¢ÌÑñ–‡Ê“Þ­óO?^êE‰4®•¸O8Ç—ƒ—î “žš„ÂÂBPbÙ†e=q4:섞7öĘwÇ`Éê%IWGLDNn|2>ÿÛçȧù1„"¡“¥ê©KߥR07NöAíâÚèÚ¬«+ç; fÏž½,Öâóé¬ýÿ"qÍš5%IЍmÝ.M»Än‘"¶ä/£4hLÀž]¹`7ë$È‹þà„O 4·Ô…Q  ÄÀ§(N¢c†ªs:¤®PPqÅkW`ûÁí¸ÄÎ>¦g?,&|\˜Wˆ'÷ݪ•Ô-Ê)JzÃΆï^ÿÍ73Dúc×xvʳè{__4»¤®~üj¼÷å{X¿}}Ú@@Ï“{bâ-£Å‚¬@@ºƒúÒQ*Ø*HÜL´ë™“®èÚÂ寶–$I\µjÕ~0+ ˃-6 –••Ü+Ô«m/íâüî`û™! Dà ¤“öâÂ%ŽU¬ï¤§1úW_´¡H 9^%+>àPè®|õʘÆA¡pHKͳ“’ò’”vëOþ$Ï`hY…¹…)­³{ÛîXüæbôìÐS‹{Ð_ßc‘cøbɸ÷Õ{Ñý¦îhqY Œxl^œü"¬X€ceÇ\™—¾]ú-Þœù&B´>€hRŠ.XÿVÙR¶þí–³c1,Èv½ž8·ý¹®ÜÚªÎSt è¤ðº¬üÁ°­%ÓŠÄ;wnêܹs£ŠŠ ÔªU+åŸÕê,T€QÞ AôUPt8d+D÷ÜàO§ºß‘Xå¨ï=!åO/ ' ‘''Æ´AV* ­þÇ«J)ÖX‹'܈OG}*§ÿ(­,•zì„m’ì>º=›÷LIYS‘‚DH¸ Mê5ÁÜñsqÅØ+°põB#˜1US)©,ÁÌ%3ñÅÏ_¢üì·lÐZvÀ)'‚V[¡U“VhT·Š ŠQW€‚¼Ô.ª²Š2„#aì?´»ìÆúíë±bÝ Ì[1ûËöË #7Z‚xˆ•æâó~Žëž»ß,ÿÆÈäÄÔ´7ÚŒ;ŽîÀöÃÛ1wå\k×&+õNu+ ó`å*M¢õnʆ۱v)~’î1ÖÝé¤N¨•_Ë•[Zõÿ÷ÝwKÍzÑÁ™ÏÚJ€VŠŸ .\¸R*†Ãa9-Ï…4¢>mûØgSÚ 2}§OIÔ÷”®Ø>øˆyüuT93芽GV”"ñ¼³è¼3ïÀÑŠ£Ñ ÈJ1mî9º'¥ ®Yýfò\‰Ž²J÷Úçús1åS0¢ÏˆèuUª#‚>ó „|$?ú™+DãAÔ×äÈQ\ æáSÜI>¢Å[0Ù ©æIÄ7ŸìúXÍ|Ä8Ü4,tŒÇÜ·C_Wt”$Ij qþüù[ã¸`Uî`a,jň;v¬¤víÚÂá0ü~Ê?½åéÚ–%I’' I7Aê.:VJ€ѱ&7%‰1‰0nýsI‘ 8QŽUP\]Pòù)ðà'¢uÃÖ(-/•ƒ U³ÆcDÊë¶ÃÛRÚ:µêÄ87•Bí‚ÚîMÊ/Þ¹ÿøý~|´ø£h5H5=R7³‰DƒôDÓl«KÄdlfŒ”s¦/¤¯.i>‡ [ÿ4ÃÖ?e̱ ÝІ˜õégµ9Ë•k«æÿ+ €"6 @ÚÓÁÖÁúÿ#ÄÍ›7¯€ŠŠ W6ܬv3tiÖ…QoeÄ~ˆ§°ÝJùãÊŸ —A€¹qOÂõ¯Çüµóe«×Ϩˆ¨“-‡R˱/Ì+Œ²|ÊŒ¶W®kæªxÞ¸û \×纨òÒ±$Ggùç ¤@(  …ò{R ¡@Ðþ'ùÄø¿:f!&¥” ±´ÒdRÿÒÑÀI<ƒz[vF‹º-\¹®ª®Û¼yóZ½.´Ð•z0I‡ ÀüjÉL›6m1à^=èסŸ³²À€årúêañnÄdAºŠñ‚@\N&@W# T,Å?~¥»ý ¥í‰ Øzx«;³œ®˜ØÆ=Ór¨Áƒ7ïz×õ¾.ªˆb™«Y¹ÈC´ T¾É=PB¡Ðb¨!ÏXXJc¬æcR²þYí:R‡ßS _§~®]SU×M:uƒ`)ý4–¶r? €˜.U @€¸~ýú’p8C)uEÖê4íA¡”‚HÄ0qX¹´lI¦üÕ}Ñ@q¦`]±êiý– —jà•ïyÅêu¦ /.SçÇ*ŽáHÅÔɯ“ÔfË+Ë£óŠ2M¯ß•¾Ü|xóÎ7A@ðÑÏÉs“ã Xåê±éM.J©uívELÚúãe•$@Ç[¦þ%ùoµ¼…º´j¯¹,’Öõ±_nÑÿjþ8®_¿¾Äİ2¤tÏîér°N«^ù«CÐ/GoècJJ“*¶þþFг #à#AÓÛžŽ–u[ºrUú_Ñy,åÏ*œ6ÿ&€ý¯… þDS#ܧ 0øèâFŠê‘¡®ùE¼U}“‘tUäƒ>73@ë ¨o4¢ÝÔ»¥$ù8€#ÇÄÌr+6¯@y <í à­»ÞÂÐS‡‚”Ö½áhë^BˆÆ |üúa>°ß«`Ê]3¹Û**_r8·9ü§¶ËZ`Ê(Y,gÁ\Ðí×®a üøãÿÓ)ÿ°öªÚ«–À&`Ú´i¿QJÅP(äšU}fë3åòœJì2#AUkßÊ¿OÙ–{*Ì/âÃ…Krn"è¾W7X °©dSÒ›Ü}`wÌgÁpßýþ]Ú×#xðî_ÞÅŸ»þ4¨’ÑU©QùžèлÇLïµ4@}Z©ϬÙêÔág,ê±.€˜9•5ç[…ƒ¹®5ÿ¡”BÑqâäÉ“a(~Và_ZSÓÌdŒÏ pøðáýz„”ªå¡OÇ>±¹ý¢Ò XßæR¤Æ2—Ô1”|KÞ<â-Ë­:>øH’ Ðeh0Ë‚U”À¦ƒÉ€ûv2§ãO~ú$#˜ÇïõãÃQb@‡Q& D£e{ãÙÄbØñ¸)Öãwlý'bí'S÷_ÿ™Îúר^Ó2½;÷Fqn±«Ö¿¢ëbt H»¤3 €U’AdP‘åË—ÿOï#qC.êt‘vóI¢d­d¡SÄz¿DÙRû7ÁÈ‹ÂÎN*g¸p±eôV«Ùz5)¹Í%›“ÞÔÆcàÛ_¿MK: ˜üàdœÞâôw€àVê\2Vº“À¿D·Hî?+¥ˆíÁÊÅÝ/víš©ºmùòåKL:Ю€ÓŒYÇèw^ŒÃ„ß{ï½ÿQJ©êpctjÒ m´1†U˜_•¡Å ˜.itD¨eeƒ¥oUË)É‘È:µ‚ |ðq¢ «öß &oÓþä€?¶üÁœžCb/Íz)c˜'?'ÓžŽ6µÛ€VR Ù-Öň žCÑ…ë &xÍ’Yû3ÖºE“µÏ ¹Ó½?©ÑIèÚ¬«kúHÑmô½÷Þû@XV,€ˆ øÿ3X bèP(:zô¨«nÜ}0íCÄ :Ñ#IKflf€ âÂ¥ Y 98Ž¥’Z튵+¢iqjüòþý…ïcË-;Äúµêã«Ç¿BÓ¦Zë^µCaÂÞcšä2©tüK¦!߬·þÍ)~€e)Ó `ðiƒ]»NªN;zôè\ÀÊÀj”V%àMãºYý•X ¼lÙ²%¼´¢¢¹¹¹®ìÀ­Î@®'•be´; ”f=©  Ö°„EºJÚͧ>€Y‰;-%œŒòç„\¸8›•Öí[‡†E úéîý»±ÿÐ~¹Z'„P-W> p÷îÆ7~£u)L·´jØ Ÿþ ž€Ò@)%rÃ$µOáK‡ò§qæ£d:Zí›dÁ7ƒ‘Ò§³§ ñ^ºØ.í‰"Ï›‡³ZŸåÚ5RéÿeË–-aXÿV…€ÒFû§› ¦ËD€€Èĉ¤”JnVlV»t`ƒ˜?K­"± êð+.\ÒÇ ü±÷„:é|cL^¹*Ñö‹7-Ƙc2zH]Nê‚Oø>Ñ¢² ¢s RVtªì@¢óQ¢ ?Þz¨2ï“  o·¾hQ¯…k×G¡ÿ¥‰'.Žcù³BÓ Ò™`È¢.))Ù ¸W.îz±Ñ—nå?b9-ô~x‡‘©n×àõøà®g¬Û·.á¹dæ÷3@‚è@ÍÅiîK˜0wBFA@¿ný0éþIð„< AÍ ©‘XN!šßi„>s>’àNŠX¹¾ž¿ôX³yÞaЗô¼Äµë¢ê²’’’Ý¢(†2ñÿgÀ‚Ð+íÿÿþ÷¿ w‹ulܧµ>-&ðD¬‚œ§—$È•?|dÇøuׯ Í#ÁPó—Ì—u¿ 6&RA€®üðCSÂSŸ>‰JƒÏŒ±WÕµ @‘Z:É´õ—ž‡€ØV¼?VŠßœþ§[W“{ SÓN®]U—)ºÍø§v}ª%€Í%ˆÉ€\è×H$…BEѵ¸âŒ+¬[+°ºAY rèû²£ÅÜ*#œÎrÄ\¸ÔtY½{5"RÄñò –-@ye¹¡V¾¡Ù~(…ˆÆ}5—üëì8°#cÇ5jè(\{îµ@†ŒƒÁ“J``\f?Iêßé\j—rj49)cn7Íùæ×+Ϲҵk!Š"B¡"‘HxÚ´i¿™ŒÞ°òψõŸN`gý›‡á„lÛ¶m”••¹¶3gµ> ­ê·2ºÌ!4 ¥He9(ä¤`/Ä©»áþØã<àéï©‹zš;@éVøýºïÑóþž7u*ƒ•¯ÝóÎn}¶±Pj±=õO©ó92fAt`ýÛÕ Õ}§í«ŽþoÑ þÔöO®]U‡):-lÒu,]˜q  €X)ÿ0€ðûï¿ÿ-àn‹`¸úì«)fPK)^9`WNX ƒ¸páâ\~Þü³£åvî݉Y?ÌŠUþ»ò©Ê_Ð5)òTÒJŒ:=îì÷g½P8”Öãò{ýøøï£A^Í  r­Ž 9 L0X:)Íád[úy[;-ÐlW3Ȉ^#\½ªStZ8È8ýŸ X7Š˜•?€ÈÚµk”••E••î!æþû£aQCcaQ$cU((^…æX>øà£jX°~£¹ãÍOÞ„(‰ÑrÞh¹a­u®®Û ¾U1ñE»òí<¶÷¾q/ºÞÔo~ö&J+JÓ6é6©×?ø1„°`ˆˆ!Zþñ‚Ÿã”GO)NÀ®yÄX,ækÕú©€T¢¨_\tq¯ñOee%DQDYYÙѵk×`éº8WÕÄsD@  üÃ?üÈù“nUbò ^ ?s¸µ·Å¢øùFd¥ráÂ¥š nXˆ`Ä>àxoÉ^Lüt¢!Õ/f˜Ë 3àE´%¯Òrwç±x`âh{e[üýõ¿cýöõi9Äs»ž‹¿_þwÐ5¦J4õXÃ×ÔÞúO”)pÂ@˜}ÿf0 `b†ž3>Ï5}£æþ/^¼ø½n;ú¿Æš/ŸUI`ƒ+àí·ßþYÅH8v5ðÂ΢Na˜›ÂªT¼nS–• .Y/ÇÇ1oÍ<Ûe{å1”U”h5ÈO ô3 È…ƒrt O¥´¯}ùºßÔ}ïê‹·f¼…ÃÇ»zŒ£¯ž­zÊ ¤”4·r8 ÊK•úODù[oÃfž¶I!dÍýµ k»Z÷_E(º+òÖ[oýÌ þ#6 @F%Ó.+7@D‡ÂÂ[¶lùJKݣɊr‹0òœ‘Îb(µ¿‰ì\¸d=@ÁG?}d¹Èo~ä¯'E©~së\¯®Ý°»~õ7*h >äÂH+`鿥õÆ(´¾¼5®yü|ûÓ·²Û!Eñy}øà¡P@ ä6¤t )ÄI(ÿ„¢þã§Êß\ÀÍ"ý/®a§¼qîÔʯåÚ­¥ê¬-[¶èƒÿTÀNù×(€ù’IqÉzíµ×¾¡”ºZwŒ†Å ScœPU pá’õ `öêÙX·'¶(ÐÁ£qÛØÛ´R¿Ýï‹2ð Ê ¨Jß tqð)1&&€äGÿyCøì§ÏpÙ#—¡Å%-pû¿oÇ׋¾F ”|”vÍÛáÉkŸÔX-ü,ÑÆ³VÊ?Ùª~Ô…ïÌËIÖó0kίW\Czqõ¶ ƒ ”âµ×^ûÚlØ‚í¨ú?S °2 ,ÀŽ;Ž”””ìq›ÈõåbäŸF:.äc˰è&«›”.\²Jùƒ$Œýb¬á«£¥G1ô¡¡Xµi•¦øÕˆ~m¨,€ £ÿm¶£±^Dhq  þ$x}÷†?6Í.n†k»ŸÌùÇÊŽ%|¸w]zNirŠ `(LᜊOEù»ÑðǪ‘^ù[ÍÝŒ¹øšÞ× ßŸïºõ_RR²gÇŽG,¬V@•8‘«*€ô'* 4iÒ¤o »º#CºAãZcZíÆ´ÞµªÀ‰d8Däƒ>‘Œ€¯ýï|÷J+K1wÅ\œû—s±lÃ2£ÒW(ƒõo¦þí²Ìl€ Ô,=0¹H.A*0ãǸñß7¢ÙÅÍ0à®xîÿžÃªõ«¥ {&Ü?AJ©`C¹àx•Päòý|oµ=«åXÔ¼rî4v®oX»!.9íWu‹ª«Ý2é´0¬Óÿª$€¤’cn×ÏkDš@€Iì0  I"'”f\¸dÚ$¡EZIå¨ù Õ£FßçF#ù‰_ùLßq/Q.”Æö(ѧ%SQQÐÆgR´Æ£:0ðÌxö@ô;­Ôm`¹ùKF_‚y¿Ï‹GŽr^bß5:´ü}ï´ÛŸéU³ðõØÊ>æ3Q~?zØh\ØíB×n§ŠŠ ”––¢¼¼üø5×\ó €RÇ•Q¦¼/P©Œ ˜;6Ä¿•\¨“i@yYõBf&`Ö¬Yÿ¢=•Ý’ EÝLdÈl$Ù°ù¦œàƒT‹šš! §è=r”(~… Ð âÀú·sÿÙ0Ú6Íl€.pPUàJà£ÿ~„ëÆ^‡–n‰Ó¯9ÿ7|µð+-=jØäˆþ#4Ðh@ ]•@ÉÆòOµ‰ë܉°®À*Y(j=WÇÌñ hZ·©«Ê_¯£ÅÔg`ƃCioÕ`n`´¶p¬2dÈÅò‚Á rrr\Û™›ûÝŒ±ŸeߤØþ}Â~Ó —83À…KøOù9#õPÍÒ(¡²U Dcü:kÙÇ÷ï”íS÷y»‚Â:PÛ½”U<–ÑOnõ®ÕX½}5ÞüìMЩu'ôêÑ çt;ZwŠÄR×Ïb¨‹ï“©ýÏZžeù'Dn¹àWo¥`0ˆp8Œ`0X9iÒ¤•ô?«0­*ú?“€êT§U=€°‰ PGxñâÅ‹ 0°¼¼ÜUзC_ôlÝ+·®ŒÏ“H`WûR' u2Ð)1½`€.\ÜŸ :'F€J4Êxê•AäçI‡§FTñDçmî‘”ÏÕÿ#‘ˆæ2 "‰º,tÿK’„Õ;d@0ñˉ²KÓG¢V±:ë =ïÄPΉú9UþvÔ¿d*Õ.Y°’ +@îmº£§þ®Þ?jÛßÅ‹/fé0Ä6b¥fœ2ýœ1lm=~ ±Æë¯¿¾( Ãá°ë®€›ûÜ7]ÄQà µ¹qݾ¬<£€ ÷Xbth¼â'GNÔ%.÷Ÿ¤a_ô±GjÝÑ¢¦4×D®nÍ™ùB¾ (T}ý~],«RþHPù;XÖvÞÖ­ïæónvõ²„Ãa„B¡àk¯½öƒ•;ò¿JgsolS¯øX÷0œ¼ï¿ÿ~Á…^xaEE…«,À)MNÁžCðÕʯì÷XŸï«§Ë”A •i;s  ÀàAÜ>›œàÂ%uý+(–± ¨I1«ŸÇS„nݾ©,%Ts]ÄÄIF– æ31ã$•¿Õg‰ýâ÷`ÅO12º.>ýbtmÑÕÕkjÙßï¿ÿ~CéÛÕþ7§f\ª"Ъ&€-˜0aÂÁ`0àÊ3¯D®77.r´íÀªd¾Åg¸pIŠPÛøjAyº¡}Në? Ì€WfàוVõi…:¦@Ï$0Ù€ªRþp¨ü€Å0÷ZÌ×¹¾\×;þ©Ö0 L˜0áG‡À*÷¿F–¶SSñºNæÜ¹s¿àj—@hZ§)nêw“5’–Àn/jŸ• "sÑþ<«€>‹Î7åëk]ÿÌŠ?Sû%Y죎‘Ð﫾찾ƀæÆðGSÿ ý Ø)ŠñŠé$’ÿï¤ëŸ”ør†L,j=w_þõh^·¹«ºCÕEŠn²RþñºÿU™TE €ù,€þ$ª¹’¡÷Þ{oi ¨‡Ã®ƒ€ág GË-­YÉÙ$ÂB¢¶(9S;g¸pqÆQk¨ ’I÷š“gÕ¼*; T)Ôb|ƶÄÚÿÞ(`Îh°¤ÈS ò£4c½1UW“èåÒ¼AsŒ8Ç]뿲² #]ñÞ{ï-eé,+êuEÿe@› f © €Ð×_–ºp÷ùwÇÔ*4êÐã°ò9é‹{PkAªB‹]âì|8b2½ÍdžIý\ÃèH¨º 4Ê_­dèQ¾7h~›èñ Éÿ§6Ö>›óoaáæZýg¢ñ³»Ýíº¾Pu¢“XŠßì`¥þP €7€˜Uðã?^YQQQ‡µÔ ·äŒ6gà¢(^‹Ó-ÐÅ'Ú‹³\¸œ’ìóG²¦+׆ew¿T¬ýx–?Ì› €À Ô—ÖQÞ_pÚ8»íÙ®^®òòr„ÃaTTT”üñÇ+õ: ±ézÝ–5ôU+O’U_€ Y}üñÇ_@(r5šîpêÖ5„jÄT—2ûªï (:ÙÊ€UÍp+>²ÏâOæwfv€ñÞV¡¦âçÇ‚Z¬ßœ¿oÙ§ÅfÞ­SX¹è/î*0J …“&Mú’ÁTa]ÿ_Êú¿ªÀ¾Mp˜ÁgÍšµþàÁƒûÂá°« 0§÷ ¼'öfÔ×`QeŒËÈÌ p‚޳Åbç] ¹pÉ>‹Ÿ¦¸,e+µ„¬úT—±›©Mö9@ˆ-U¬§þßÂÜBW/]ii)Âá0<¸ï›o¾Y§×M°§þ«´ñO6;€•4Q,ÁgŸ}öSJ) EÑÕëwJ?ôêØ+>rEœÜT0‚ÝU¡¤9àÂ¥jžŸDG­ƒRšÊ å¯;ìY³;ó»œïê%E@”RúÜsÏMgé&ØçÿgõŸ € „6oÞ|pݺukUDæ¶<<äaÔ+¨gM/9¥öa‘Ãê&àì.5Oé'«øS±ú«JùSÊßFÙ‚)P·°.ö¨ë—SÕ5ëÖ­[»qãÆ°§þY©YcýW5°+ d•  §Z‚cÇŽ)Šb$ ! ººs9¸ç¢{ØèÓäcÞ´¬‡1ÞÃL³lòIpPÀ…+ýÔ×á†âwjõÃá|•ªò·V±`Óü1,¬Üóç{PSàêe ƒ…BE12vìØ/Íúìúÿfë_;;_|ñÅ ÈɆˆX€P ¨œ7oÞB@.Ç¨ÞØn>ú`@·öå6Y-ƒ.–5)”QÝRÿ$ð”C>Nœ@¾Tïñd×!9ÿÜÒÂvìçt¾’X·Uœ•ù•Xm”}^óЯS?×õZòwÞ¼y? –N‚1ï?̰þ¥lªÙhň0µÖð€zÂ'L˜ðSYYYi8FYY™ë;8zÈh´oÒÞ¨ì-”9³ažÞ‚ƒ Àt0UÍÄc 8[À¥:Z÷nÜ»éˆ `YýÊŸ£ù†:d(“±ü­‚þ@Ù–ÊPPÚ6m‹Ç†=æúe/++ƒ’z^ª+ùkü;ò?«¬ÿlbⱬ8€€ Þxã”RTVVº}Íë7µøm …+=¼cŠTdš ÈÖÂ@qniò‘÷b6¤ÚJ°/$f×ÉÔÉ<$—rhµný ÏH4¸Uç;fN5iS¾kV¿ž¸ê ×çQQYY J)^ýõ:#4Àv¾ÿ¬²þ³è `Åþùçí›6mZ¤' °Ií&uñ¨˜›Û2 ÎNAãæÀfŒ È„•“NæÀI}w.\ªú¾q+СÅïÈêw²®dÙÊ0ïâYþVs)`‹¥ûnÔ%£Ð¬n3×/ªS6mÚ´þçŸÞÎ0DYéYoýUÓ8 È¥)Dð@ka¡vÇÖ†ïñÇÿâã?þ_ee%òòò\ݱî-»ãº¾×á£É{)˜nJ}¥ÖÖÖÞ¢GG •KpšÛ›ÿ׿ϦV¿¼í0.ö ;Ý뱌㣉ÑôN•x²ÊŸ2fxí/™˜ÄRü¬ØPàšó¯Á©­Ouý2ªõþ#‘HøñÇÿÂdñÀvˆÕÁúÏ €Á˜{°‚Cf&TLž<ùõ¢¥ÃpCŸpZÛÓlÓO,ÙÄ¢Ù„c²ÉÂåV7.ÖÏB:Ùê@ùS$‰ŸÍÊßfn=µí©¸¹ÿÍ®_V•ú€É“'£þ™éVÓ˲¿Ùdýg °¸Mí*šÑW@à³Ï>û}×®];EQLK@ Œ9m·±Î°Ë `PþL„›H´m¶ùʹŸ-6 SeíÜŠjjŸÝ:çYH`98˜³DØ·ïµ+lÀÖ½?©ñIxá¦Ò2×—••AEìÚµkçgŸ}ö»…Þaåþ³Êþf¥d °`ÌÁ€ætÀ$6zôèijm·[«2öʱhÑ û†e¨ˆó¹š­9÷Ùs©®Ö|UÇıø-ýüN¬÷T;¶ÁÎò·aN¬z˜3š7hާ®}*-—¥²²RËù=zô4½ÃJÿ«Ö?}1¬ÇB<:À§œ|?¢±Þ²²²²)S¦ÌºöÚk/©¨¨€ßï‡ÇãquçšÔn‚QƒGaÔû£¢Ýž«ñV7̃ÂèS§¦õY}çôLê%›}÷É><‹›÷S6î“Íïâ6DK%ÀɲN”?`_‡ £ÉÔÝÏœ pÿ%÷£i¦®_"Qµœÿ)S¦Ì*“éä€JXûýã•üå @’,@¼Az4œ>}úï›6mÚ,IRZ² [Ën¸ãÂ;ìÓUX7´ÓžéªP-oNOó‘Í÷ušzØVôsÃêOEùS—”?e+ÿ[/¾§¶95-—«´´’$aóæÍ›§OŸþ;bÿ¬"ÿ#0$…g·õŸuÀ  O Z\˜J‡~xF ¤£c *Wžs%.?çrG¾À¬ñ(.\ªîy¢.)þDiüDB¼`åT”¿M Ä¥½.ÅÈÞ#ÓréÔ‚?@ ð÷¿ÿ}†N§˜­u˜ÓþÄê4›fˆ ÀbôÔŒvDQ ¼ð ÓÔŽáp8-û{ï…÷â¼®çY—«t$Ò[€³\¸dž}Ju]Hƒâ§ .Ÿ8¡iPþ}º÷Á_ÿü×´\Êp8¬üyá…¦‰¢`˜êˆ×ò7ë­ {cTQ3î%Dkȱ!åU­@´F€€wùòå»/^¼¬wïÞg–——£¨¨‚à>æytè£(­,ÅòMË•{Z© ßsehßÙÄPª[F}Hìâ Hvrb ÷¿s9Q}¬7®Â·žd›9-8dÇRJ­{M`€™ ÿ½¢R{¶ë‰'¯zÒù9IDÑHÊËË‹/^º|ùò] ¥ŸHàŸTnë¬t˜“ZUÔ_ =]S9~üøï9r8]½TyöšgÑ­u·Øt•xѬv=¯qdSÕ@Îp©)Ö|:îcëudí'ª¬«±òïÒ¦ ž¿éù´]z•ú?räÈáñãǯ×!02ÌXWý‹¹²Ùlýg-08V€Þ²¡i‚£Gž"Š¢ …Ò ^¼þEtjÞÉ2gÕ1@5©¸œ÷ŸÃí$¬ø¡û“U¬ü;¶ìˆWn}%­Ê_Iù}ôÑO` *·²þÍÔµ ü«Àæñ‘€4Ô¶ÿþ#o¿ýöLJ)Ò¯Þò*:6ë"i¯€¡Q†Ú’Õ E0•¨6R.d|’)2$%°µIÞ¸Ùç„9÷ÑØïÚ5k‡7î|#móµðJ)Þ~ûí™{öì9ÌÒ!°Ný«ViÕ ˜X'͈M‹Üœ3gΆŋ/€òòò´” Våõ[_G‡¦´›ŸÈjsÉzÈ$S >¼¸eÍ…KU1 ñ×õ™Oxé`ìÖcàgÛòÜ®‘ЧûµkÖî™¶K&Š¢æ÷ÿñÇ—Ï™3gƒNTZ0ñ:þUë¿:1€}…@3¨dŒÀøñã¿ß½{÷ÞH$‚²²²´“¨òòÍ/£}Óöl&€ÕBØÎb¢VBBå‚%–5Ï烌´ÐNØÒO„ÕKÄ‚Oæ{»¹FŸ¬÷°,1vm޶MÛâµ;_“¦¥C™Pв²2D"ìÞ½{ï /¼0ßNw8PþÕÒÜÊz`(9p°.dð˜ªÖHg<€Ïã“™€fìËëãâĨ7nÂqNÓz¸?ž WŸ¤,ýD,~'|"ë¶²ü­¶ÇJó³éW`´“Á,¢Ö¾y{¼y÷›ðy|i»¬åååZ¾ÿ<0ÕNgÀžúQþÕÅú¯6 €ƒ>V‚b²@Å“O>9…R*ƒAô\AÀ·½N-:Åï `œa9§JŸº4ñq€ÀåDQòÉèlÂOIé'Ò÷ >ëNRiœy„5Ù4Š ø³Pþ[uÄ„{&À#xÒv¹€ê÷—ÆŽ;EéòÇŠö×ð§ZåüW[`=qdÎ `•6¤¨\¿~ýþ)S¦Ì¢éé”WoyÝNêæ XÅ ˜"i-ãRaÜ$pÉV¥îâ}š²ÂOæÙtb½§bõÇ‹#`±‘6®…×¥…òïÒ¦KZþ9èOe~§L™2÷?þØÏÒ`—üµŠú—ªëcRm€Mm°XKŸÎ´iÓ~[´hÑr¤3(^¼ñEôlÓ3n߀˜V˜"lÓ¹ª*]°¦Ôvç>oÞÀm…$ö7YÅï–Õo5ïÄSþßëçÀm{à•Û^Iëc¬o¿hÑ¢åÓ¦Mû ö~–õoõ_ݬÿjǤ`¸`Û¶m;Ô#Ý à¹ëŸÃ™íÎÔðcLŠ ŽT2€€8|–ËÆëí]Ý‚O´T2>ªl˜½¥ÂOå>vkùxû"9X'+WŸ1§Ø¦.[õ±æ,‘jóÝéNÇø[ÆgDù‹¢ˆmÛ¶í?~ü‚•ˆú¯ .óíÎ*äÜÿýÓ:¤U ”¤ô²9O_û´Ü;ÀÝÏBÏ ÖÁ`”åµ?ýgúÏaZ†r¾žË‰è%°þsÌ¥ËÚOÄ-3à´¨ÙêÃê·0, E&„Jš÷éÖãn—Öë,I’æê=tèÐáû^°²üÍôpt’T&BROÑøâ‹/þÍe—]¦n˜( FíàU†_¹òä+£@¡2 Ô‘““SôÁÜ’ŸŸŸï÷ûQTT”öÿÖÜ·0cñŒèÞ€¦úïÀèÆÿ¬W«Ï˜ÕáµçM¸d¡BwÕ¼¨ªuÐ4,oYÉ ØÆ±‚ýûe =w(î|wÚï‹ÒÒR„B!TTTTÜtÓMïƒÁRåºQ¦ŒrÊPÁ«æ?uËú¿ì²Ë’¿½\0ܪ%ÀpXµ ¶bôQŸ•Á`°|Ô¨Q“Âáp8Ýå‚U¹sà¸wȽ"É.Ïß®[V¼ÔA&ROqR¡)þUWËÿeï_Ò¢[1nµvKù;}ÞYYìf«ßkÁ²ëŸ;Ýsé=Qþj™ßp85jÔ¤`0Xn²ø+àÌïoú«ÖÔ¿*^TÑߎjÇ@Ü:[ZÓ{€°ÿþÃcÆŒ™úÔSO ƒ!iÝñKϸm¶ÁË_½Œv@ ¡$ºçºn‚ê$Çì&¨g¨ @uËXYü416 Ê­5.\Ü´Ü3¹4ëuô© V?¬­~szsˆ-ñ×ËþŠî­»§ý”——# B’$i̘1S÷ïߨ¡ò¢†ü©Q y±X«x« rÍš5{Ç7RJ€V&2ÒµUWN˜è×­ÿtÆH°ú7¥âé?׬~‡÷¸Vú—QÜ̬üÛ4mƒgn|&cÊ_Éõ§Ï?ÿüŒ5kÖìµ›ûßï“òWÝ­ÿj À|ûÅ+\¡{Õn†%K–ìxë­·¾Î$hX»!&Ü9=Úôphx°te8c‚ot¸F“Æ©åòäà —&ú·?Tü’ñ»ºßQ@AÙŠŸÆÎ_]ÛtÅÛyê4ʨòŸ8qâ7?ÿüóvÓ¼_aÁ°¢þ«}µ¿ L‚U:Ç ÔWóÍ`@ƒsæÌÙ0iÒ¤yj÷ÀL€xþÆç1°ç@vŠŸžßÐ¥ÒÄí(h~0)µ·ô0<5Ž^û?yÐèfª žóŒ·†â™câõQF)N ³nN€—n{)#s¨NùcòäÉó¾ýöÛõ Ëßè4éˆ0Cù׿¿^¼¨YbŽ€òA4@ýLg¯ ÈôéÓ÷x<ˆ#ÎW˧;&ºì!œÜèd¼;ç]„E¹B!%Töû«{h>BýÑÓçúÏ”ÿUŠO‹ä×Çñc€ŒÄ páRe³HU­Óm?k*+(Ñø …); ^P > Àëñâ–A·àŠs¯È¸òŸ:uêüO?ýô÷8–ÀX´î«Z#À_|Au©’¢ÌÕ`@Q§ªXA¦„»èÿS§NýÍçóy‡ Ö7“ `è9CqêɧbÜôqØ´gSt¯ôÁ}‚ñb\&^j .¨Ð2PЉ¢ç@€ Wòîo‡&ù¹ƒCú˜¹u/ è–Ñh0ØDã—Ú4kƒ‡¯xm›´Í¸òŸ1cÆÂO>ùä×8–¿í¯¯ö'¢úýõ"Ô”±‰ЧZõ Ðßåú›äã?^ùé§Ÿ.È´; uÃÖxëî·0àÔìþ&rJ£åmû‰8Ÿ%bqpÿ8—lPìUÃáv* Ýúâ¹tÿŠ~1”·Ý<`Ùî—š èß³?Þ¹ï*QþŸ~úé‚?þx¥Iñ—ƒMý›ký³Rþjœß¿Æ1 &À ¦›!X|ŽÉ“'ÿRYY¾þúë’)&F?uüÞüæM””–ÈE(£`r´”Py5U: š¬{0¾·úŒ0, Î d¯åÉ¥z]ÓD»ú9éhgñÛ¥÷™@ƒ­± [¦nQ]Ü}ÉÝr¥Ó ‰>àïÃ?œ÷ù矯¶°úãåû[¥ûÕ8¿  º$J²`¼|þùç«+++ÃwÜqÇ Lƒ€>ûàŒvg`üã±à·rL€ÌáóþuC‹`U ÔO„áP?ÒWzdUtêÈ4àJ–Ku¹Ç’iÔ%ÅWúŽãòïݵ7þ r 2v LÑþ³Må PGù×Èb?'`<úÇE4©$b bT×·ß~»¾¢¢"†>]ú`Â×pðøÁh‰`õHM16ˆ ´UÊú`ABì© 8°šØ8;ÀåDenhëuZÃ?]Š_YPPPÇ“Ñyjå–•xíË×°óÀN£ß?@Àô¿%pK¡sPÀ¥º*z0¬f·Ø;ÅOI*þ [àžKïÁíÎÈèåEååå‡Ã‡Ãá'Ÿ|rÆÚµk÷ÆQþz h²þYþ2ñÏ@€ èÕ ˜™€\'  ~ýúµ^~ùå………ù^¯·J@Lÿi:>œ÷!*C•±€ãè“ɰÔF‘§zëp€À%_þ믿>¬Q£Fõ !(,,„ÏçËø²÷È^L]4ßüï›øl€îLPP£ qB«?¦¸SÅ-  ®ÄÓ¹žDƒš_ÊLÅGùš÷ÀÚâ×+ÿ‹Îº#ω¦u›fü‡Ã(++¥û÷ï/¹÷Þ{g„Ãas)w+¿?Ëògƒòç CÀè»:*ÈÓ½æÈ}úé§uêÔ©5äääd,CÀ,«·¯Æ‡ó?Ä/›~‰^#0R†# €$À@*ŠŸ+d.Ù $’eü.fn–l”¾«ŸÂÕ¯gz´ëÜ€®'u­’˦vô€µk×n}ä‘GfÃØÓ¥ì¨'Ê?¦Ò_¦#þ9È`€s` È…100ÏÄh à¾ûîûÓyçw*!¤JA,þc1Þýö]ì.ÙUîŠ;@͈QäN@ª` žbOæ¶â@+ôªÞ.Mý7̆],«ß)àTñÃhñ7©×· ¾ }:÷©²K¬*J)¾ÿþû_^}õÕŸÛЭ‚ôÁ~vÊ¿ÊÓýªxOàéÃ\#Àé£k‰_}õÕ÷ìÙstäÈ‘ý‚Á ‘$ ùùùUpî)çâÜSÎÅWK¿ÂÇó?ÆáÒÃÆþæÚº"Ajm­à¹Þ€•– ™‚Yv˜P@ï¾&Y¤²eû\ªîºÓäïƒrf-c5;I÷]ŠŠ¿nQ]Œ0—}Y•R5Ò?C’$:yòäÓ§O_c¡üYÅ~X¹þ¶ÊÿD•Š0±N™€Ýf—@ pÊ)§43fÌe999~¯×‹üü|x½U‡µÊåøjéWøtѧ8^qܾô‘ +@°ñR­X‚tX÷NowÎ(p¦ ÙuR«©µÒv*¨ (0ööE|LŠ¿¸ Ãû Ç¥g_šÑb>fÑûƒÁИ1c¾øã?ö;PþúºÿÁD•Uûá.€ €A€Þgòäåååå¿úê«C4hP@•»àpéaÌýe.¦/šŽcåÇbc¨0Ðý¯À2+ %0`ñðâB\²DP†’÷;‡E}œFøk®ƒKüÊŠÿÂÓ.D½¢zUzšõþþƒ¾ÿþû?/—›¯T¾±™ö¯ÊŸ€* ‚/Œ)‚¬àÀ< ÷á‡î}öÙgw&„Àï÷#???£EƒXr´ü(þ»ê¿˜ùÓLì?²ßºþaœ4AK0@].)sÂQ—¤t>¯ô“úOTùÇSúˆ£ø£ºpi¯KqÁ© Na*=×’$¡¢¢¡P”R,]ºtí3Ï<óŒ ÛX-}YÁ~ªòd»òç  @ @_,ˆ•!`ÇäÈ8p`»;î¸ã|ÇãÉ—€^æÿ6ŸýøÖï\ï<Ð 3à&prëq¿<—t34Å婃ïœ(ý8Ê_ý]‡æpyïË1 Ç€¬8¥‘HˆD"EQœ8qâwsçÎݨSèñZúš#ýÕ÷ÏåÏ@€@€¾`äY€€Ü ÔzöÙg‡Ô«W¯6.½¬Ü¼ÓODzuËìóÿËô?'ÀÀ©’ç¹T…ÂO8Qô¦ÿ-+õÙ)ÓïÎèx†÷ŽÓÚž–5§WOù:tèØèÑ£¿}út%„ª¬h%ölÀ×K¾Æ¿þ€ò`9[É;©à¤@¼B®à¹d+0p!ÏßXFðÇSþˆÒü9èÓ£Ÿ9[tÌšÓ§ô£”ÒE‹ýþâ‹/þ¬³äõ ÂFù›ýý! üdµòç K€ÐW m ä‹X,€æÛ£G&£G”›››#rss‘›››Us\Éñ,߸³—ÍÆÚíkÙgpÜDÈÒH!.ɲiòûÇdÐ8Û•¬­ýSZ‚Ag ÂíÎ@ƒZ ²ê4H’„@ |öÙgg¯Zµj/Œyû•Ö¿òWýýåìÄTøË6åÏ@‡ @u8‰ °9rAÈyæ™gvèС%ø|¾*«OÖïZÿþò_|¿ê{9ñ-[0`úŒyqF€K6€d€µ™¸©ÃuY0꺊 ŠÑ¯G? ì90«¬}½Õ_QQp8 ذaÃÎÑ£GÏ‘$I¼Wé`Xùûõýª…òç Ë@ ˜Ø5;À§(uäZ0¹fÀÉ%—´¿þúëûz½^ ÈÉÉA^^^VÎ¥¥Xºa)¾[õ–þ±ÔYj U€x™,¶  @9˜àâP©»ñ;‰‘IO±Û ‹”¿Ó;žŽ=àÌg¢8¿8+Osee%‚Á $IB$?üðÃ…_~ùåEë•ÀÆâèQÊ?b²ú¥ê¢ü9ÈBÀfÀJTA€Þ%kÁäÂèÈÉËËËû׿þ5ðä“OnÙ`–]‡vaùÆåX°jVo]¥øÍ“Itò^ôßsúŸK@ƒeš äì÷q­›€¾Î­;£o¾8½ÝéhÙ eÖž*½¯¶lÙ²çÑGSYY©/Ö0)ÿJ åÔ Õê·«ë_eå}9¨€Áè صXY¹@Ïäð÷ïßÿ¤;î¸ã¼œœ? g äççgýœ¸çÐ,Û¸ ?®ù«6®2”ýu\8( HÆjwƒ%à‚T–u!ÇŸ€ [Ûn8·Ë¹8£ÃhV¯YÖŸºŠŠ -Â? †&Nœ¸`þüù[u¼™öØXýú(VŽ¿>ÐOÊv«Ÿ€j À.C@h.!œk²üóLŸçª¿!ç‰'žè×½{÷“ !ðz½ÈÉÉßï¯sfYe–¬_‚ÿ­û~Ûü›Üƒ@§Œ™€€eÁ»‘*È…Kº_¢)~q¿9°nQ]tiÓçt:gw8…ù…Õ┆B!ƒA5¿ýöÛæ±cÇ.P|ýzåoNõ ˜¿¹¤¯U+߬ôç  €ÈʰcôL@·nÝ=ôÐC‹ŠŠòÙ-­A‚v²vÇZ,Y¿¿mþ ;öïÀñÊØ B X5JµR`UƒÎ,œX–Ÿ>«'@q^1Z4nn'wÃYÏBç–«Õ)SƒüTº¿´´´büøñÿ]µjÕ>â×[þv¿U”¿•¿¿Z*ª °æ }p ]á °ãô@@ýÿ¦›nê>xðàž^¯×@+'ìÆ¹¯ Ùt?Vo[{6bÇþØ]²Ž@DŒØ+z§…8#À%“¿SË_¯àEú Ñ´^S´lÔíšµC§VдnÓêyJ)ÕÊø@$¿ù曕|ðÁ¯:Å2)þ€…ÕoWØG¯ü«U¤?5ă ðY°9 ÅŸkÁøø½^oîO<ѧk×®­ÕB^¯7k³’‘­û·bÛ¾mØU² »Kvcÿ‘ý8\z‡F Ȭ¥ÏAWúVër°¾\.êÕAÝâºhT§šÕo† Z eÖ8¹ÉÉ5æÔVVV"‰h}Ö¬Y³}̘1 "‘ˆ>Meõ›]A«__ÙO‚E°_uTþT3À@ÔÀŠ 0»â¹ô ß N:é¤:?üðyMš4© ÚÅ$+Á ì<¸GÊŽàÀÑ8RvÇÊŽáxåqT*P^YŽŠ`B‘‚¡ Âbሜo ‡ J"W„\‹GðÀ)ŸÏ¯Ç‹\_.|^òróP˜[ˆ‚Üå¡vAmÔ.¬†u¢na]´hÐù9ù5úüèýü°wïÞCãÆû~Û¶mGŠ?dRòv?‹ògùû Á~ÕUùsP € ÀŠ °*dî.˜k3ô ÁÀß·oß–·Ýv[ïÂÂÂ<äææÂçóñÙ› .i‘p8Œ@  )þ²²²À;ï¼óÃÂ… w š—¯·â6ÃܽϪ°9ůÚúû9¨AÀÄs °€€™ög¹ L€2|W_}u§K/½ô´ÜÜ\?\¸pÉ„â¡/¿ürÅäÉ“ÿ0)o寷üÍŸ±¦ü9¨A `¹ìêX¹Ìz àà»ýöÛ{ 0 «ßï÷©@àDp páÂ%sŠ? …çÍ›÷ûÛo¿½ Qš>d²üÍJžÙ/¯ŸEù×8åÏ@ 6@@Pþ÷€.hçð'T à½óÎ;Oíß¿=ðù|Y×hˆ .Ù+@ápØ øçÏŸ¿ú­·ÞúE§¬C (}€Ýo¶úÕÀEùsPC@6À\=ÐŽ `1f`H„±M±÷¦›nêzÁtÉÏÏÏÇ£ÕàÂ… –¨yü¢(ªïóæÍ[ýþûïÿ®(èÃꙬ{3ýϲøC ÅϪêW#­~j(`€€ hŘ³XÁ‚~Ð/«_‡÷ /<骫®:½nݺEêΨ]Aà3.'¸H’dèÒ‡.:uêò9sæl3)þ°Iñë•~ìྠ 8ØYýÌ@¿šªü9¨À6À*mж+ÀÊ% o·nÝÜ~ûíç4kÖ¬¾zͼ^/ü~?rrrø,È…Ë &Á`¡PH£ù)¥Ø½{wÉÛo¿ýóo¿ývQªßìë7SþA°*ákåë?¡¬~N`Á˜kØ¥ š€ßBñç0€‚xø4hß}÷ݱcÇ>ŸO«)ì÷û‘››[íÊ sáÂŹˆ¢ˆ@  Uí€p8,®[·nç믿¾dÿþýå&EÍRüv€åã7—ñaá_#rû9à Y6@-'lŽ`¿0»b€ï°aÃÚ4¨K½zõjéY4È…KÍsP¥‡:6{öìÕ3fÌØcú^ñ³(ÿC᳿]tÿ mõsp‚ 6À@,Ø/¬ƒý6 +@ÐgZŸ·qãÆ…·ß~{Ï.]º´òûý^uçx*!.ÕWÌÕú”Ï"«W¯ÞþöÛo¯Ü·o_™Î*×+«@¿P¥oNé‹XXý' ¯Ÿ€8`â¹Ì®x¬ ,˜¯_·wРA' <¸sÓ¦Më ‚@8àÂ¥z+}I’èÞ½{}ýõ×kfÏž½Í¤˜Í~þ°…Rgí³¨þxtÿ kõsp6€å0–kÀ*{ à7³ê6Að]}õÕúõë×¾~ýúµˆîB«n¿ß_m;ráR„RŠP(d ÷•ÏiIIɱ… nœÂ°úC,ó{3`ÐSýfÅoK÷ŸÈÊŸ€ØXÕÍ¥…­X»Áb|: áàñz½Þ+¯¼²CïÞ½Û6jÔ¨ŽžAË&ðz½|FæÂ%͉D´è}I’ –þþýû,Z´hÓ´iÓÖGdD WÈ,?¿ÕÏ,kŸÕ´‡E÷ŸA~p(°s X¹¼&En¶øYïÍÿ{퀀:.ºè¢VçŸ~»–-[6ÈÉÉ14P ùý~‚À.\R´ð%IÒ¾Z G•P(Þ¾}{Éwß}·áÛo¿ÝnRÀVŠß\ÉÏêóûØ4¿ÕÏé~8H H°R YÊßÊ%à3­ÏÃBË–-‹† Ö±S§NÍêÕ«W$˜ª éÇÃ.q&tQ™¾båK‡*]»víî3f¬Û±cG)¢4»™~×+j½â6SþVJßÊÒOZñsåÏ©VËa±1X»XÊßü¿Ù-`f—„Àsê©§Ö8p`Û¶mÛ6ª[·n¡Çã‰)7¨²>ŸOc 80àr¢)zÕºWý÷fëDQ”>\¶eË–ýß~ûí¦_~ù¥FߺÙâ×+f;ºŸ•ê†5Å/"ÖÇ/ÁºU/Wüp  *T«Ò em¬”?+6@¿Ný«Œx­[·.ºð ÛtìØ±qÆ kåååù‰ÅMãõzáõzáñx À€ƒ.ÕYÉ«Š^ED"C°žiyZYY:pàÀ±uëÖí›3gΖ­[·–š­ÞâfùøYi}á8 ÀNé[Õëg•îxZd0 zJÝXð˜À€þÀÓ£Gº½zõjÙ¦M›úõë×/.((Èñz½žx÷™×ë… ÚÐý}È—t)t–rW¼:"‘H܉9‰ˆåååÁ’’’ã[¶l)ùé§ŸvþòË/‡`Œ˜7wÆcQý°Óú씿Þq`ésÅÏÕ m3ÀŠ!°[Æ‘k±ñ ‚~Ÿý~¿çì³ÏnܹsçÍ›7¯]¿~ý¢¢¢¢ÜœœŸ ®Ô¹T7° I’ Ã¥¥¥’’’Ò]»výã?þôÓOûB¡9Jž5œRýVA~°}øN|úV4?Wüp…@€,H–¸9˜Ïë€!° à”ÀEç FåuïÞ½~“&M 7n\\«V­¼ÂÂÂܼ¼<Ÿßï÷ù|>×ëõ‚@A Š›pF€‹ “+¥”RI’¨$ITE1 ‰¡P(\YY.++ ;v¬rß¾}Ç÷îÝ[ö믿–ìß¿¿±p¬*x,…ïÄâV»•rgÑúaÆzY–¾hÚWÜÇ€»€Kò§ß°Ë`¹ ¼ ÀÎÏ%ÀbÞ¬øÅ$@¼÷v ÁjýV>}ÉÐp¥Ï—„ º÷Vˆ¬†•÷X|ï„öÇxÀväÊŸK¦AËz`ìÜ,e.ÆYÞÎÂO„â犟.'+]v`À)(HDÁÛÖ°Pü,Wl\’}^̰úsâåþ;}ïÄÂçJŸ \ý{ ŠYpì¨}ÖïYÊÞ©òçJŸ‹ÛÖ" €¥üí²â)v1ÎïYûcúœâçÂK0`ž(ÌÌ€ª€EÝ«]þ¾€‚wùŸl \’±þÍŸ9 ì3œ„x¯VUù¸¥Ï….®1@ldRÀf·`ÅïÄ·Sþ€ó@®ü¹¤œ¤Ú€x ]ŸÎ· TäJŸ \\,å+1”s<ëÝé÷¬`?ÂØ®ð¹¤ûy ï)ײñ¾:œ2\¸pÀ%%kÈ) `}fUÀ'µÏêçþ.™x¨ p¢¨írîãëq…Ï….Õ ˜­s1ïFÀ\¹·N·KÞ.p+|.pÉêI“XL`vŠ;ž‚·òës«ŸK¶°VÊÛÊGo]\Ùsá€K, >\ª‚ €ÍçÔ…írá—j?¡“#òç’Í÷r2ùõ\ÑsဠŸL3ô.\²ùžæÂ%ãB(å÷*.\¸pár¢‰ÀO.\¸páÂ.\¸páÂ….\¸páÂ… \¸páÂ… ¸páÂ… .páÂ… .\8àÂ… .\¸pÀ… .\¸pဠ.\¸páÂ.\¸páÂ%ƒòÿ•36|ü¶óIEND®B`‚olive-continuous/app/packaging/linux/icons/64x64/000077500000000000000000000000001370472574300221655ustar00rootroot00000000000000olive-continuous/app/packaging/linux/icons/64x64/application-vnd.olive-project.png000066400000000000000000000073411370472574300305510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<^IDATxœíš{pÜÕuÇ?÷÷Ü—–]íKZIÖÃkÉXbâ`j'˜§vqq(4@‚ÓÒq †Ðt S(…R: ˜ÁmœB 8”¤Nm06„‡Á/Û²dY¶õ~¬«ý=ú‡¼[É’¬•´òd¦|gÎüÞçüÎ÷wϹçÞß…/ðÿb‚÷¦ä\Ã"YE¦ÎH%%h~Ýå2Ó´¥l¿ÈXeaõõ©É¶¶¶~ I–IP2¸GD£QÇÂ…‹Ê««W?¥iÚBÛ¶µl¾Äx$)ñòËÏÏݲå?È2 ™´%r{ìé-óæÍ»¨ªªJV”Lx›8’É$‰D‚´Ô××sâÄ LÓÁ`P,\¸øU]/Êe ¡WUUE$I;ŽQõ%áLÆB,cÏž=¾xôçßÿþÝ7¶··Ç3?ÆK"'\¾•+¯Z?oÞ¼au]'ãóù†elI’ˆD"x½Þô9ÇC^^^Z‚ÁàèOëI•Âííí¨ªJ8N'ÝÑžñz½tttÌš3gα½{»¯§“ Fçl\Ÿ)R-@–åt zíÌd˜¯×Kii)±Xì–/_;‹ Kå)`añ\ÝSìîÜ9UUi¤e9]ÅXù   ¿ß/]{íµ¿.(ÈñA×8e>ìÞÍÓþž7ŽýrÄ‹N©V ( >ŸÆÆF cxÉ? èºyðÁÇŸÊdè<¥Á½mÛ”I³ð©~.t/:ëhn¢eÛ¶‰D"455ñúë¯ãv»‡Ù>s;Ô¾ßï_£ëú=@?0æ—™Bzƒ1â”§wEaMÁ-üM݃¬ž±–ÿ¡ êp»Ý躎a†‘&!åüÐðK‘¡(Š20pö˜r„ÄÌÜWªyâÐßf5 àÿ†ÂC“¢ªªhš†¦ié²8u>µ°m{ú{!š¢qeøKesã SU9ª3ÇCeèùÔ~¦ÈJ In—‡ÛÂßewË;ü®õ7?kb`£†!Õ4M欪ªèº>ì8SdmŠWUT"þ|¾•\ÇG~†Gõ°À»xÔ{öზìhúÅ?lœ²›|G”ÙÞ¹T¾Ìů"Ò§r‚$IÃr0©n8«sܪ¢R˜Kuï <ºï!î›÷ ¼KHÚ¼Ýò{Z>d_ç§|ÞuÃJŽxþHüï¶l‡#P‘3—ŸœÿwÌtÇFµ•ªÏœAžhÊ*BºƒË"+ø0¾›‡>½%¯òû¶Ýí>Œ,f:gq¾ëBœ Ö(²è2;i3[9i4r©{šÐéÝìlÚAYÉÌ1»×Ñæ'Ьÿå„„ÇåauèFö÷Æ;­ÛÈW »ò8”8H{²ž.ÈYÄ—•hB#™LÒ?ÐO·'z^>š¢cÙ^·˶Ť&{2´üæ‘e…òÀl.h^ÀÉd#fs¼sù¦t+¬½|’ø€Çê&ÏeIè+,.e‘o á@–d?ª²4}ÎÃ4…躃o䯡ÕnæRïeÔ™uüVzƒË ¯â/C÷°:°–ÖD3¿<ö ?øøNþôÝ+xüÐO9Ü_ƒ,Ÿî÷§Ùy˜Æá°$$fúbxñ³­ûmÖøo¢} ƒ×ÞGƒ§Žo~‹Ûƒwâ—shhâßë_âÏw®âá½éLvN׫ ôýéBp0¹Ÿ}Ý{Pÿè~™¹ŽJ>êÙÍ?þáq¾–¾@»÷q$^CÝ@-­VGjy³ñW8d÷Ì~ ëã‹31m-À¶m$S¢ßHЛìá÷­»ª‰,©¬Ìù»[v4»NÒ¬¢_îÅ-çp­o5÷„ÄŸùþ"ëeõh˜Ö¡˜VÁ‚œÅ$Í$½F/õñcÄ“ÝÌôÏäJO5¯œ|¨\À|WŸô~Èûñlný9»­„‚Á1§À²‰i³ „@×tÖG7°ÔsyJ!1½œ<)ŸwÚÇŠü•,p\Â˧^À¡¹¹ì¼¯ãT]ÈBáí¦­üwsæåôT0}«,[Ë *¸K¹—îžn"0MÆ)¶¶üŠ[Ëî`eø*ZO5±µí5¾’sùð^ßv‚R¥ ˶Äô¶‚i%@WuJ¢ÅX§ãùXmüæÔVŠ<3ØÝù.7obGÏ6® ]ÃÒ¾‡@Ø”ä”"ÎÁ‚´ `Û“›ó“$ 0Lƒc}ul?¹‹ÓÖßÊg=s½w /6=‡OÍEBpòãFú~tá È5ƒROŒEÁ%,ð_„"²÷Ý& Éžò¤§iš(§Mˆïåæè· Éa:â\˜»€_·¿Fs¢‰µ¾[ êaö'öðV÷¼×þÛ[¶ñ|í?“£xùzä V­eVNض2í>'`CG^“•°<8efØ9¾roDÒ‡ûáÆÃ›=¯RPeeÁ5lÜÏW+p(NdI¦ÛèbËñWX»ë:îüèvêãGGµ“)ç$†(`†«”]ñw /Û¦Ñj ±¯–f® ¯æŸŽ>ÁÆŠ‡ð¸fs›s³N–óþÀ.zÌn|ÂOT+d¾^EŽƒe™c®.`Û`YS[­jc³À¿_4oƲ-ú’½hª6„ùÌÖçq ±—÷Ú¶s}h ÏÕ=ͺ⿢0RÈU®j.ê¸Ã0PU§ÃÉyn/NÍ5ê¬ð´„XØöäE•Þ (ÖJmÛ²4Eåzÿ4¡Ó¨G–$Ü–›Çÿ„Ïú>ᘨã#õ}y e¥DCùx\dIÝÖtš‡Ÿ¬Ø¶®è,õ.@•´ô5`IÞ%¬ð¬àhÿQ–{V2óø¤å#~ôùøÅÉÍl¬¹‡çÿ˸ï”)&˜§ž%IâŠ@5Î9hB?­w0iyœnÖ„ÖR¦Æ¨ë9‚p ¶u¼Íy>!+¾d/v?ÿÕö&}¾‘>£o ;d\FŸÓ°m IBÞ 7n¡P+vM–e¢ÁBÖåÞ…ŒÂ©¾“|Þ»Ÿ÷âÛ±,“»ŒyÉ*œ†“šþ<^û(–eް™‡À„zËšz- È2…£«úˆ¦Ê _ŠÎÃÝúœÖ` ÙÙ¶ƒû¸Ü{%ë• ô™ýäª~ ÃH/ÒJa"s…0¨ÐžzWxM?½p¤>§îdV8†a&9Oøè7û¨tœÏáäx«ëM‚ù!nŽÞŠBŒÖ=‹ŒC`‚uÀÈîf*8›.õôÑru6 ú©ö¯"™àäv6ŸØD‰«ŒåÁ¯ªg ¡ì„À r¥ï,, QÖJ7siÇ &÷óIûG,õ]Š*ü $&0‚œ`°²™@¸0üe`pµx4”O87DYÏàjTa^ ‘y/0Jp° <×8õÁÕd’„&iäz}§»ÔÑsH?…Ó—I¶,l!Ä€eYZ¶ó@¦jS ÒKoG‡Doo!„÷kK€¢`ÇãÂêêêÜ{ð`MUEE¹,Ët‹ËÒ0M‹£Gë¬ÖÖÖ}½½†épœ}ð’I[Ñ¢ÑÜHqqéâ›o¾íþÜÜÀ\ÎÁLÒ`tt´íß´é_Z[{è½ÆÆö“ÀÀX7gB€ìóùrt]Ú¶• öôÿ²™4„ v¯Ò‰DÂ>ÖÑÑÑÍYVfB€¿ßï’$É£(†fÛ| ,SË0”˲âííí½0ö)˜ØÊjiˆLôÙs…”£Öù_à,ø_rK•+#€îIEND®B`‚olive-continuous/app/packaging/linux/icons/64x64/org.olivevideoeditor.Olive.png000066400000000000000000000202421370472574300301120ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFÍIDATxÚÌ›{œÕ•Ç¿·ªú5Ó=o†y P‰â|fÍD0D.1KŒovýhØl0Ýõ±Á²Y7›]³&Q£èâ\AÅ@XÑtx Â Ì óîî鮪{ïþQÝÕ=ÃD†‡1÷ó9zª¨ª{~÷œß=çÜ{ÅË/¿Ì ¶™ÀMÀ  ( @pr›[€§WNä¥Öq>w>ð(0­¬¬,PQQA4%`BœlÝZkS)s'–H$Æ´¶¶^ÛÞÞîïë?k.þ5‹ªªª¢¢¢â³Rv`„À4MLÓ$S^^ŽÖ:ÐÖÖvÑÁCßîéîÙ Ü üÏÉ XQT\4£jhååå9»ÔšÏ»•——S^^N[[Û¨C͇^ïîê~ ¸è<\üWMMMäÔSO=âfGoõëiìh¤3ÙI"•À•.Žëä@úø<>ó˜Ò ˲° ‹ÂP!¥…¥Ô”ÖpfÍ™””Ä'Ÿ|2½±±±)šOµª£à=ÀãcÇŽeee}nìnßÍ{ûßcwën¬ E À ™˜–‰0Âýô9~KÑZ£¤BJ‰t$NÚ!Lc§lj+k™:b*c‡ŒíóL{{;;vìÐÀBàGÇÀâÊ¡•ßV=Œp8ì_<?È[»Þboû^B±‘X„@$€¶0&†å‘ Ã0N J*Ð •DºÇvpRéDšdW’dW’1c¸|Üå /î?—N§ilj¤¥¹åqà¾càÞÊ¡•?:õ”S1MÓ¿¸~ßzÖïZO¸(L¤$B8&XÄ ™XAËy!|‚<‘ÑϺڳ©$ÊU¸Ž‹´I%R$»’$Ú$;“|iü—¸tÌ¥¹g•bß'ûhin¹x|0pðXuUuåW6¬dkóV¢C£”І<åÃ+ S€?úYÖFƒ8Î œ¡ ß„h¥1¤60 L̰I À ›¬Ù±†öd;s&Íñž5 ª«ªiiny ؼúi¯Œ=Z„B!Ÿá_Øþ»:w«ŽyÊÇBÞ&˜ é‡=ÙNk­á$OZhï;(SfÀ$ ¢CÔèfÓÁM$ìóΙ@(b̘1bçÎËaù³CVTWWGò oEà vvî$Z%R! b…-°À5\¯cJçÇS\sò§ÇþïÔh”¡ V¡E@((¥¨?TÏóï?ÏÜIs(--eذa‘¦¦¦W€‹à’XQlÆðáÃý‘sß›¼ßò>EUE„ËÂbŒ°2UNQ­Q(Ôó;ùY€0( °"A$,øÊåwûG,ãʱWPSSCO¼çžîžË²ÁR>OU©ô•?Ðs€u{×QXYH $€µ èzVÑ#þý#+? 5„ÀŠY„Üv«¶¯¢¶¢–¥#¨RIOwÏ“ÀÈ|Î/ŒŽ(--õ_øÆ¾70‹LÅŒBT8Âák_£Ô(åWûE<Ç Yhñù*Ÿ œ4%:¤1 ¬b 3i²ªawœw‡ï ÑXôôxO|:ðV€GòGÿÃöÙѹƒØ°¢P ƒW¸ aLx m‰6v¿¿›Ài¢UQ ËøüÏ@yÖ˜µ£Ð P ¾±žš?`båD†T !Þÿ!0Í·€’’€MM›0£&FÄ€(¡J¢ÑlëÜFSc©®ª&¬Â)>_å³èŒ;ª9š&VÔâÍ=o2aÈJJJ¦†|¥¸¸8 ZZ{[ÙÞ¾ÂêtHáZ.JKï¥Z±ªy%7 ÿsŒB2%¶NƒäóoY”FkÐZ!-‰)D`óÍ4õ42,Vƒ‚ââb³««k¦Ì+--õGÿÝCï¢ÃÐH-‘ڋƤ–|¬÷òQ÷G\~ÆlJoÂr¦ÁŸDËAi…B¡ ÂQ Øxà÷\3îÊÊÊèêêºÉ¦D"€}Ý{!¨Ñ–B ­ZzSÒ pyæÐRþºö»|øÞv] ‚EÁ“_ÿ9PÚë³V¸H”¥!ØÕ¶Ë×3“ßL±€ª@ à¿£5}S8¦‹^ª´òUZ! %?ÝõSîž¼€·<ˆc¹^p$þø„‡Êû­½ÄIKv5ÊUH[â$ì´CSO“ÿŠŒÎC- Pá#Óawx¡&ñI<òSZ!‘^bb@s°™¥»—²pÂBÞö0²Bb†Ì“«§Ì¦ÿï§…Øù<µ•8¡èèíðõÌp^ùU¤J!”Rþô&µô-@£![í­5qÿîçm`–™Ÿ ‚@0µp*Ä.`LÁÊ‚eŒéN:íN§³?±Ÿ=={¨ï®§U¶zS¬86ÈZ…R ­¼)\ IZ¦ûW°„Õ¿¬•V)„¡@)¥2Áfž øqH³¶û &$¿À#aáÿ-ĨÁ\§ÇGÆsnô<ÆŽgtt4!#tD¿KC¥”†J9=v:S‡Lõ¯7´5ðü®çY×±3œÉ8€¬å¸ÒÅU½Nêèx¬/q¥ë" çûÈ#â}Q X²ç'Έá#(‰•P-ÆŠX$Z’¨ˆÆ*´eúªP¸ÂØ "ù¨¸ÊÅ•.B ¤Ìø²¯ê+;VróØ›ylÕc,¸l ³5ï¯adÉHfŸ=›+§\ÉÙcÎ&ÞgͶ5¬lXɦÖMlÜ¿µ[¡z²W‚³Ä¤ËêBØÝì}Ë*¶J=èÒ}É•)¥IéE³Y@PG9 AH¯¢ói. ]t$¿iø —árnúùM<õ­§_=žù¿aɶ%,yw ×q‹®ZÄÜsç2ó¬™8ÊaíÞµ<µõ)ö&öú…T#èU{ž)£AiIß-Òû-¥ôÝàèH¯ð(\áþè€å(´£ýN.ûx«¯ZM\ǹö××ò³9?câ©YøÖB’eIžk~ŽîÝ<~Íã øê¸¯réˆKù¤ë^ýäU–ï_NÒLz˜ô)´àÞPÞoå*ŸÓú`ø…ŒŒH%=7øâØvÜ&ÝÆéup]Y©%t°bÇ ê&×ÑI'7ÿ÷ÍìïØÏŠÙ+…Qd°ºg5w-¿‹”ÊÕáÂEL:SðȤG8Ë:‹ˆÁu\ßtI´D)ÕçšVÚ·€¬øä7©ò–Ò·7íât;8q×vü°2-N ß¿òû¼üõ—©ŽUóà†Ù|`3¿žùkîy7Wœr›â›øò¿}™—6½D¼7î;h¹xÔÅ,¹d ™ˆÝeç>QÑ™ îh$¨”ÂU^ÕÇÊVH'£ î ÔæO˜eXL¨žÀs×<ÇÕK¯æ…/Ðo§ntEQyZ%ÕEÕ¬hXÁ‚g0"6‚¡…CW3Ž»®º‹_®ù%ئM 8¶õGã¬d9©ÁJ)”« ™WþÒÚGðhè>À¸òqTÄ*ø›sÿ†{×ÜËâ+S÷£:Ï]Ìi%§qÇò;˜tÚ$ݰˆ‹G\Lme-ÍÝͼöÞk¬þ`5;O "¥$hK””à'ê˜d]ËZn~ölýd+‰ÞK__ŠJIÖí^ÇMçÝ„4]þ~ýß±aïïxé/–sÞóø‹ç¿IKwKÎ, ‹\ùœf•’Ç܇œh/W ² R?Žp­J¥üR—ŸÂ0a]×:ÖüûÜmƒUiÒÐõ#ÊG0kÜÕü÷¡WXÖð,-]­übî/¸gù_1ýÇӹ틷qõYWSSQòחᴸ˜&„8.ðCb¥Q:3˜G …•Ò©¼@ÈÈ  @Ìa¢Äð‚˜ `öDo©êfÿ+YÉ=ÓîáÜáç²ø¿³äk?áÞïåá·æ¡×BöHP`UZ(¡áhÁÏ` 5À^†#IP*„àfÐÇhyoE9òº`ø^)*ZƬ³¨-«Å2,fOÍu‹¯ãÙï<ˤá“U5Š©Ã§b[ÚTÆ*I:IödóÁÍlhÚÀúƒë9dx'Rf'‘–:¹9;ê,à²Lš]ôP}Œcme‘ÜrÛÌÉ3Yþûå|û²o3²j$>ÜÀœžÃKw¿Ä¼'ç1oï<ŠÂEŒªÅ̉3¹uÆ­ÔVÔR[QË o`OÛ–m]Æ3 ÏÐ&Û¼TYäŸçË`"A3Bž tíX¤-Ñætʨ)<ðô¬Ýº–õÛÖ£ Í{ïÑ™ê䉟`|Ùxºèbs×fxý¦ü` o|ðFŸŽ,É¢‹Ø2 ¿ºäWÔjq{]¤Û¯ßÙYD)ütÌÄΆk ~Ë_êø- þP=—¾ÌÛÊRTNw¼›k~~ ÚÕ˜å&OÌ}‚¢p=÷O~óIæüzÍf3CKº…9ÏÌáúÿ½žûêîã”!§ÐÖÕÆÖ446°ýÐvÂaTÂ(ÊK¢TÆ\Ï ³Eåªdë'Àú½ë}VÀ#ÙBó¢ñYãg EùÞìï1ïÇóxâÚ'¸þÙëq£.",À‚g÷=ËÒ¿_ŠêTè”öö#"$0Š ŒÃSt 2zõoG¸€Ï˜Óɯ¬œˆ¼²#·ŸÑqïºÐˆˆ@D;Zwx\+ãùáK?äþ÷£z¼ŒDL`3±FYÆŒ `²0O31†fàþfÁèW,K[~™Í§³Hžˆ|Üõ1?Þ˜Ûò’ÇØ(xlÝc>@6õÏ(2ŠX»u- Î]À“îd^í;–‡Ê}ÒЮö>å§Í7Ÿþ&vl@„…oÚõü´Cvpã/n¤§·‡š!5¨¤â+¿Â¬3gñî¶wù[ÿƒ-{¶pçïdé«K9Ôvˆ Ç_È’¯,Aµ+´y—“'yWV÷©|-°Ù¶íÑÙaµCjy§éDP MݧdâO‡'°=¶ÑnäÖçnE”zÌ®•îCÉÛ{¶sË/naÙ]Ëüšþä“Ù¿o?3@Ý9uL:mW-ºŠ[þù´Òˆ€À(7 " üz g€W=Îï»mÛ› à?{{{}ŦšŽ°EÎòGßÕ'ì ÂÈW±áÕø¸¿jÏ*¾»ô»ƒ}­û0„NkÖÖ¯õöú ©áµ¾ÆcÏÀ¬21«MŒ¨Ð^“#?OtZ3cÌ _ÏÞÞ^€¥ðJ*•òKʇqþ)ç#{%nÊE¦½rX–û˜×ñŠÎÍÕGÜs5˜ð³ßý Q,ØÝ²›†ý  áŽ'ïàé7žÆvl*K+yõo_¥&V/¢ÑR£ì¼>¦µGiÅ#/`DÅߨR©”Vd |C¾|yü—½c ) !–¼NfIå3陲Q`ðöŽ·ùùªŸ#B‚§ƒÛŸ¾Óo>;¿“- [xøš‡ÑíR^±s£Ž‘Ìœ4³ÿè¿ ¨ìVÙ@`]þþÀW>ÈÛÞö6D߬ë¸@§5º'³¢Kx×’3mR.¥ÕnE{÷òcmk´­™6|Íy(·‘º£Çv.ÖfCá7ÇÙ—N§O …¼êÃ×Ïù:ïìzÇ Z}SOqIJïg×P˜· §4@D2(9ìö &2W õÉ/­Ñ)ÍÜ/Îí³Ú±½ÀÚþeñùñDÜ7“Ñ•£™?m>:塘?ŸŸ”¸`°’Y†èûm7â!Ï]¼¹-çFÚö8`þôùL org.olivevideoeditor.Olive Olive CC0-1.0 GPL-3.0 Olive Team Non-linear video editor Nicht-lineares Videoschnittprogramm Editor de vídeo não-linear Editor de video no lineal Editor video non lineare Ðелинейный видеоредактор Ðелінійний відеоредактор Ðелінійний відеоредактор Aplikasi edit video non-linier Éditeur vidéo non-linéaire

Olive is a free non-linear video editor aiming to provide a fully-featured alternative to high-end professional video editing software.

Olive ist ein freies nicht-lineares Videoschnittprogramm, welches eine vollwertige Alternative zu High-End Videoschnittprogrammen darstellen soll.

Olive é um editor de vídeo não-linear com o objetivo de fornecer uma alternativa completa para softwares profissionais de edição de vídeo.

Olive es un editor de video no lineal libre que apunta a brindar una alternativa completa al software de edición de video profesional.

Olive è un programma di montaggio video che mira a fornire una alternativa di alta qualità ai software professionali

Olive — Ñвободный нелинейный видеоредактор, задуманный как Ð¿Ð¾Ð»Ð½Ð¾Ñ†ÐµÐ½Ð½Ð°Ñ Ð·Ð°Ð¼ÐµÐ½Ð° закрытым коммерчеÑким продуктам.

Olive — вільний нелінійний відеоредактор, задуманий Ñк повноцінна заміна закритим комерційним продуктам.

Olive — вільний нелінійний відеоредактор, задуманий Ñк повноцінна заміна закритим комерційним продуктам.

Olive adalah aplikasi edit video bersifat non-linier yang bebas dan gratis, bertujuan untuk memberikan alternatif yang lengkap untuk aplikasi edit video profesional.

Olive est un éditeur vidéo non linéaire libre visant à fournir une alternative complète aux logiciels de montage vidéo professionnels haut de gamme.

https://www.olivevideoeditor.org https://www.patreon.com/olivevideoeditor https://github.com/olive-editor/olive/issues https://olivevideoeditor.org/img/screenshot.1600.jpg
olive-continuous/app/packaging/linux/org.olivevideoeditor.Olive.desktop000066400000000000000000000007411370472574300270730ustar00rootroot00000000000000[Desktop Entry] Name=Olive Comment=Professional open-source non-linear video editor Comment[fr]=Éditeur vidéo non-linéaire open-source professionnel Comment[it]=Programma di montaggio video professionale open-source Comment[id]=Aplikasi edit video yang non-linier, profesional serta sumbernya terbuka. Exec=olive-editor %f Icon=org.olivevideoeditor.Olive Terminal=false Type=Application Categories=AudioVideo;Recorder; MimeType=application/vnd.olive-project; StartupNotify=true olive-continuous/app/packaging/linux/org.olivevideoeditor.Olive.xml000066400000000000000000000003601370472574300262170ustar00rootroot00000000000000 Olive project olive-continuous/app/packaging/macos/000077500000000000000000000000001370472574300202225ustar00rootroot00000000000000olive-continuous/app/packaging/macos/olive.icns000066400000000000000000023352661370472574300222370ustar00rootroot00000000000000icns º¶TOC hic08«­ic10qTic13«­ic09±…ic12"Þic07G³il32 -l8mkic11 is32·s8mkic14±…ic08«­‰PNG  IHDR\r¨f AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs  šœ@IDATxì}`•U²ÿ¤5¡Wl R”ÅÁ®`ë>uWß®úÞºÛ®]W¬Ø…Už½÷¥(R”" ¢ôZé!=ÿùÍwæË¹7·%ä"$÷ÜœœÞæÌÌ™S¿¨êêjЍ"hšˆnšÍŽ´:ˆàAMЄ;?Òô" ‚4aD@îüHÓ#ˆ0€D Є!aM¸ó#M@ Â"8@†@„4áÎ4=ˆà@M±ÁÚ,JS·»j&vÛ?bïsêp«ÖÔÞqÔ¿É›¡óÊš<ØD¬D®&¤(ØUšR·†#Ø#ªnPÂV‚‡Ye²€©n;vU¶]ý"¦˜|ðÁ^YþÎqãÆÙk4ì¶ŽawÔ½÷Þ{lFFÆ ÄÄÄþqqq=£££ÓY§²ô”Äá lÎHeçíøDþ+”h«xôª`ÏR6÷WUU°Þ]^^¾¡¤¤dõ®]»~¸ýöÛWp8âW²C°5ü¡•aã©æÍÞG1®Pc¢‚‰ Á¦…XDU¢‡ "Ý¿ÿÄÿú¯ÿ:·eË–g3¡Óá“Ò¬Y³¨ÔÔTb“’’’(>>ž8Œ˜ ˆ ƒÁñ€z±‘%NB3Ñ‹®¬¬¤²²2Ú¿?QAALŽR]Èa;˜1ü”““óù3Ï<óÉêÕ«K` ª½¥…FÅ 1À0˜jÒ ÀÑ+ÁÃŒíÒ¥K"4˜à'0Á÷c"nÙ¦M›¨V­Z ±'$$¡r$<<c(--¦°oß>ÊÎÎSÈa†°†Â[,™½µuëV0H`¶´ Ôq¸KPGÜ @ôåc¯¹æšŽÃ‡ÿ ä#1·k×.ºmÛ¶BðÌêXZ$úÁ†¿0„¬¬,Ú³gO$–fÍŸ?ÿÑçŸ>“ëf`K*!–’A„„ˆaáctW¹yì%—\’~ÖYgÝ–œœ<:!1!½}F{Ñc„¨ÃÀ vîÚI¥%¥»‹‹‹?ýâ‹/|íµ×vsËÀ T:#€>¬A„ Çü(‹èu^¯">?nÚ´i3¡ÿ966¶W§N¢x!Oæï~²‹xæÀ:/ ÒöíÛ«+**Ö3cxüüãëܬrÖ*(#8,¦à)}¾.äÅqÆiS¦L¹Eüñ,Þ'è±€QM XH3àiÏö¿ÿòË/ÿmöìÙ¹ 0{ŠpH3‚°ð6áÇßxã=† öoÕ ïØ±cLçÎe…ÞJ±6A`§aÛ¶m”™™YÉ[Œó,Xð×'Ÿ|r#ƒ¢Œõ!Ï" À ­!~õuÄ¿úê«»ò¨ÿ,ÏçOêÚµkT‡"[rMЃ5[f;vì -[¶TóºÁb–®{á…¶pºZŒàPÚ9hò ÀõAô²}ÇfÜ…^˜Îú9ñÇÛyQ<dž‘ð¼F@¼}X ‰àwÞ¹†5 uk ‰ÅÂ&Ë,·WôãÒÒÒY„{0%%åRóc˜øÑWaUùeù´¯dåîÏ¥œ’*,-¤’òÑ¥¥TV^F•Õ•"y”W”Se•àÏ:®†øèŽÏöØžS4º1£¢£(.6NÅDÅP|\<%Ä&Pb|"%Å&QJB µLj)ºubkjžÐÜÎ:,vf˜T¾ÊSÈÛrssq¦Àf`¿)#h’ À¿-îcƒ> ÿémß¾}J÷îÝÃ"êï)ÞC›s7SVQí+ÜG9ûsDížöcv„€zàWì@r®­q£ö~T(Ää'éoï­„¤&vmÆ v“‡Ë(Ù]UYEÕU5'Á,Z%·¢6)m¨mJ[êѪ¥'§)µîÁ¨Ï¦M›hçÎE,ü•ÁÛœK)k],¨þ­¦MŠxúrp‡?~üøô‹/¾øu&ü㰪ߢE ön8µvßZÚ°wmÏÙN…%…M±@Ü0Õ.D·Þ T¢±‚wà ’slŸµ Äg„FàÉ}=ZůªšÃՋð`7ƒ0ø1c€eE%¥&¦R×Ö]©W›^tT›£<ò>PG~~¾œ%عcçò×_ýâ÷ßÓ¬ØÛ‡]h2 ÀǨÏÀçÓ]×ó^þÿã‘Gw´ŸÝôksÖÒ/{~¡ÌœL*«*¢áˈŽQÞ0e d±ƒøñg˜€˜ÞÄRØO‰\㺅7"‹=ºÛÍòð7DŽp!zX +:â‹Ñã§Ae f†À:.:N˜A¿ô~Ô¯u?dÓ Ó–*ø Á½|jôIÎL@ ÁѪ4Ðè€×¨ù>Äýø“O>¹õŸþô§wxž,ür ‡ýHe—dÓŠ]ËicÖFÚÏsø˜Xácx¤áóå׎Ë=2ú3Ë…vÃÏ&~Ô”•ú ±Fà„8ÿ9•íôi·èÃgø¡ïé»LÀ4Bý”àá­¢¿mV)Èe!6™à+YZ¦;K¸'wey%óBïŒÞ4¨Ã Ô6¹íƒ‹eÇ€×V<ñÄ~ûí·{9S0L À Š4Ш€Eüº­'sý‡~øÜ^½z=Ëûù‰¼µXúiïO´rçJÚ·‹‰žoñ ±ó@Üè·#ê C€èÏ )›¥0h¸«!ˆ•]þÀàfÓæŸ0ÛòKzË}¸Y•¸½ëíí¯Sñ·$ˆú€ BüˆW ?0&vqW8va`å`¯¢BC‡´Ž4°Ó@:ºÝÑÞÕ¨³›· q~ dýúõ×ÝrË-ŸpöÚÀAÙ)h´ À?¨c)ŽîBäOœ1cÆC<Ç¿¬oß¾Q|K½ê¯ï\L?íü‰òJòˆ3±GÀ#>ÛEc¤w¥kÎUcWâ¶ÿÀD©aü¹“(ðo‚ ûÐuˆºFJpÛg¼dîÏÍ€¿®À‚‡Ó±cÄ7#•a0E"3`]ÅAEy¥%¥ÑqŽ£a‡€øÖ!­]»¶://ïß—_~ù­œv tm ìS‚FÉ,âÇÈ/"?ßÅO»ãŽ;>e‘¿_÷î݈ˆíXD«2WQQyÅÆÅ ÇÄÅ8#~œÃÀviâ?kŒòè`ðÞs!p&| ¶»Ä·QÍ0x!^“VÑ-(°M!xúF‚‡Ÿ?L#C`»2>ó/»ö0! ¨F8AJ| ê2ˆNîrr½»õÀNO ÖÜsÏ=£ùM)Ö)$°­ 4:`ˆ£¾®ò'^wÝuGŽ5êsùS»uëÆAõSKv-¡Õ;VS~I> ÁC¼ÁƒøÙŽ‘^$,ðÅ:«üÎüß?Ëôpƒ¨e„³¶Gþh– D™0šÂχ²‘ßGp£ò ÚV/^è>CA%ð [€]˜_¦C5HFÁWWT áƒÀ­ ¡Eb ØyàI›7oÆÚ@Á—_~yö³Ï>û3WYß"¨ ÇVa£a†ðì  ¹­ÇfsÔ‘ x• ?Çxë£~Þû3/î­ ]<ÇÁ ‘[„ „îCì×ÑDŽ82¯Ç¼ßˆô.õ²‰žíGëìíÖ4A‰B3h$¦G{}¼ÝL6iÔŽp!x&veÆN!z³Mf€)AµÙ)©Ö0-ðbeÌ Ê*©s«ÎtB§h@»v5B¶ã813‚ŠU«V]Êë,N¨ëØ.lðÅÁFÁ,â×Å>™ïóÁž«XäÿgïÞ½£[·nr'Øgm™E+·¯Qszˆü2êóˆ/„¯ó~?D}Këè®D®£¾+pAâ‡-â· ]íÕ¼HQá…ƒ•µ‰ìk{P¤×逘XÐ5fˆ¦ £¾0¬ 0Á‹`ìÂØóÄn'Òè#F­ª¯{÷î¥_ýµŠ· ï¸á†žç8º.I A{à‡ø“ž{î¹[úÝÿ¯í2ä5_€ä·fïš·q•V–RL¼#âÇÆÇ:â>F|3Ú àÑSL:d¤·G{žÁcÄÇŸŽþÖ?Õܸ^•d“hâJáä Ÿ´ã~6Cb·¤ ×u&zqcä7Ûƒ.#0‹‚")0ðØ âW“Hgyv½v øáÚ¹{'­^¹ú‘k¯½öanï~ÖXhP&pX3Ä'x’_|ñÅ;ûÕïºN;ÕëŽÿlþÌõenÏÄ/„šÝ ~›ðá–•~>kÕ!í3Ñ»ó{ã–ݲ» ªEÜÞ ~‘ÑŸ{••MÐŽO€ÿFì×6ñCì‡Ò@q ¾a"°&…mÊN€Y$Äè/Œ€M‘ÀXB]ê0H ƒº¢1½ÇH1uù‡H¶gn§5?­y®º‹Ó³Æ” Á˜ÀaËü??Ìpÿ‘Gy‹þ2Wg`…¬6äm ÙëfSqE±ˆú2òƒ@ìg"WS¦²Ço>D&~]éâ6£=ì b%x©¼·iS+ ¤Gº¦ªêDô<žý=ò10‚7°ÝfÍ@™ƒÍ`w· u§ÀH:5¨`“é@iD—Bcû¥Þ­z[µ nEy8=È[…3&Ožü?œ¢A™ÀaÉü3¾}'o÷]‹Ã=BŒÁáëÆ˜·mý°å{Š6#~¬1q' Ìtί ~éÅîŽú÷kVõmq_æø\šK̆¦mĬ5ò»µS‹wPïFbÚ°hè&iÞ>ƒÅ¤\vÛ iT †`v twÀ]°× XS‚r0ÖÃN#{ŽªSóP>vx{ðy~Ÿâ.N\ĺA$eXmÿ­”.ø‰ØÏïóýõ¨þG]‹‘¿®ÄÿöÏoÓÖœ­“K±¬Aèû£ã™ °ŸˆùÌ@ôz¸GFuvÛóûje Ø|BÜÆ.c$ÝÛ0y}…Õů¡ò©K™‡J\_mw%­$÷¤ÄE¿¡SÑÏ8)…íÙhá Âä£Xnϱ†ƒ¾Eãœ`Ñìç„Íßð mÏˤÉÇOF!)àî©p­®aNˆ&$wñG=Õ§¦Š÷*Ò‹$No抈‘XYfÍTìjqc aʼL¤uÅP„™|¼Mˆ¦¶öoên[t ïþ‘¸èK(tÛµ=L3 ¼`fS§‹8„ \ŠK`ž±¹«`=¹àIÊ*ÎrÊá?¾<¾ï9 >&zøM˜ÀAc†øÁ³Áñp¼7‰¯SsÜqǽtÄGDó›ü~‰É›È2 3éÍ•oPaYpè8åÖ̽a—ŽÃ–w` svèXaŽèÃâ4¤B~|†§\-Yäc‘Ñg6€4ìD­m c;Ï*kù!üÝ0  jöu§懜=•Ï»¼¦èváh`* jõ÷§\ÜB?ÂÎý ¾Ç/অ°cíHÖŒ ñ;LÀÁ«8–DCÒd‰ —_ziñ‹"zã¨?7ðø¼þsÀ@ ‹¨ƒ- àEüàv ýúõkÃãx¯Ÿðç¶BU[ ¶ÐûkÞ§ý•|]"ë%v¶G3¡Û¢]w*æsÕh©ÌéT;ºãÒe‚å/Sº(»­qíT®ž†âϹØyJ¾È[Ò:‚J 5¦gyvÙÝ®°U3X{}õƒFY©ëÆ‹¾gT@¿€³‹[ÀZìÀÖî48Æ\3ø&S– +ŠèÕ¥¯Ò†Ü ¡¢0ß÷ÀÐ'Ä:èâ 3°3‹£¡,pºDÖ),½ËgûSð‚O¨j}Þzúdí'üÉX>ÜÃs|™«I§8¢š3âcÔwæüî<ßpx™r'ëün_ó{™ãY¼~¾æ¢ðóåï1p>OMï¼³[Û̬+ l¼ ”Öß:ô?“œLÍ:ì _ œÂú¦4)þXgb¿ýUûéÍeoÒÚ½kí*´ïÿ Ž˜Âtúš´è†½Â§Àu†gCY²èÇ}îã­¾¾uyÁgKþúâ×/„øu~ù˜¬øƒ `u‹9½Íöw¤»˜"b0«ú\!ª*Ì …p9ÜVˆïO ³òö—Þö”—/b¯ °óö·û[ÃÄdÜᬇ‡ Þ4`Zd¬Õ4ˆ—} |‚bkQi½³âúÃÀ?P¯´^ŽÿÀ^ãè zàƒB·qtÌ+¡¡Ê΀p§¼†ÿo¸Êñ'Ýu×]çôìÕsb]òÈ,ʤ~ùˆJª!ö;#?$YÍOpDµ¨xge~¸É§•®âWEñøÃZVóyevÞéuFoÌùYc„R?­¼Ý¶¿¯0¼þ«ZãÚ&ÒøûÙñ"öÐ  °ôa¶?Xúßôµ„'/_[Õæ Naçˆ×’ÏØŒÞÁLt4$âêbz}Ùë´5kÈÄ:=€.@†N@/eQ0l Àš÷£ ýùV_»cŽ9扌ô Y‘eÿ  Ïm¿÷ó{´¿z¿+Úƒø1ÚƒH§¢GGI‡p©¾ˆ_!t!’D¾â)ÁôãFìá€ö7×¥4»ïíÁA lý‚… ™0>‰ž ¼“ÁHÖ™!À]\ULÿ^úoÊÞŸ·R'ètú`/{*öEÁpO”øå°Ïßþö·™|¥7¯öªXJe•eôÆOoÈÑ^ˆûº,úát¯Û{˜¯±†H†=|ÙæÁ\"=s{(vÿ‹¸SÅ}»| 7¶^ÝNvVb÷NS+Bˆ •OˆÅ5šh¾àæÓâ¼Õ‡¸Â*! å‚Wlb¯éG°P¸ú ÷öÁ»~Lw‚?ðS;Æ!×çT*i¦°ølðtïþ½ôÌâgýBùº}L:õÿ MœX¢?HóþÄ!C†tìÞ½û_ê²â?sÍLÊ.ÊvV]eëÅñÀºÕ‡E>³z+ÜšG|é(0puVÚ¹ê†:[¹µv<Üþì×;Ží¶óôö×|½ãØùªÝޱ{»ÂÈ6}ÁÈÕ.xä`%iŒäüÑ0W²Ô#yºÒ(ã¥b|ÅBõŽüôÜ÷Ï9™†ðôÁLà¿A/SÐè(lSpMÀX·¬úó×T^ä-XþN{W³·Îæ³ý[x«W÷e¾ÅÜÕá°8¤Íó09¼Ã%à0‡ÞA‰zl—;MÅé@·°‡1 æm÷v»ñLR׈FùòÓ0˜ÁÂí¸»oÔôœïðP|kõƒ5XHzq›…xŒ'ŒWödsŽÅ}9<ÆU(ˆæiA5¦U¬y× †u5몪PÖeýJŸ®û„dX>@' —… žÇ±ñ̸NÂ2hPàKôÿç?ÿyQ§Îú‡úqÎ_r¡E[Éþ*æø²µ'¢S:ˆS\Û5\¸æÂ::ß'‡Òù¾Ýù¶qÔ­¦í;”æç¸jÒ¨[M;õ ŬoºPò>Ôã Ï­üÁ×íW—Á›¾¶Ý†âcŠsraL¡ŠqxÉŒ"š ß1™T2`¿Ù?EÝZvékE “’Ò’þ ›¿ÿýï3¹4>t5ÓWƒ¿+ˆq³¡òĪs´æ|ÒéÎôv¡³í³_?«Yà3s*a˜[Á ±ß¬öƒ+c ¸Ãv]ðƒ)ó7&k„¡ãÕ »ýƒ¿†Ù¦Ú%­Y»‰ïnùÙþ¾ÊA¸¿Ÿ¿©ÙýÁÄŸ]áƒ|‚¦a¼ÁOð xcÜ‚WÆ­çIï0 a ‰ÔÁO]ŸÒµ5ßúñ­é ôºý€Ž =…ƒVSG!×,@D3ú3HDô—U~ÓïŸ<¯Iâ/õ:ó*‘e~åÇüxãÇòT·¼Ï¬ô뢋̈@øz¢uâÎACIbäWîí£,‹Û¦m×:êBÜ:×Ô0~®ñÕTÿˆB…Â5T3Ô|íx‚OŠ?¡\Á À€‹`¼(]J“Á vH±<}-() 7z3 þkÙ Р臋Á­A÷¨°¡3T­ATƒpS)&Ca(2ú:´S›6mÎ õ´ß{¤å™ËÀaž•UˆUíy¢"'ühìɪøoJÄÞ­ŽôÂÀ”{³]¹¿Ž&ˆcû©Ûõó1âk¾š‡ÆU;_av¼ˆýð€+ œ‘“~¸qE£˜ È¢ŠÌ¯ØÎÜþrö‚­²ØÇf%Žqr'TqÈ/fb‡ÉÚôõiÖ Ã¨o¥ÓpÍÇvû‹§þÓÿáÁ!Ó÷þêì‡ñMñ‹Ñ° n‚g!½b½Ê hÀgàwQe½µ&´õÐÓщ 'ÎY¥”Ò`R@CI`$¨˜Œþ—]vÙ\yáìPAô_º}©¬úëœ_nd`Lø"b±è/ ~*MàüƒÓplãQã¯áLD¶óÐ|]X¼”Ç+(â[ÍQõÛU,}#¥©M€Laä>P¥£?@Ò„ nç½L0… j^æ<ÚY°S¶öd´‡øÅˆü @wôGnš£1t¬»`¹Õ?˜‰´Xé—<`×üЩ>ÜOMÄ÷N£aÓáá ®]oÛ-v¼Áà¡(?agVü•B#Ñ*~oÙ·…þ³ñ?NÚ ÿAO +ŽæqD8H²‚BpGÿ^½zµá‹ CB=ò»tÇR”¬öË܉GuHÊRØÄbKU´³£ Š.Ð{›MñSÓ4~f\T NLýúSrT2}÷5-Î_,; (Sä§iA0”8ÒGÂ1:ÖZÀE©·ÚÕÂ€Š ²ó„õœHÊ‚2 aNó YT…3ÈA¢ýfÓ74ªÇ(¬@Oüåá! ¯õë×Û_BΦVóðŠjÕW>'Mñÿ¯ýë­,²À?¨ú:ókÊ-Ëuüxä÷˜`ôÇ–æþ r4Ú² zfX¾G¶~öVì Q 4%m Öì4jÛŽRbøC­ÆÒe-/£è¼h*-,u¾‹Kø!/;ï@q#a‡@¸¾~¶¿» &8 Š‚VÆÀ\fу› vtyqpßþ}ôù†Ï9rpº}qLûŽJ ‰Þü•p *€•0€ävíÚê|Øþƒ#"ø¡(£¿>ˆ‹+"0¬ÑYføŸtžáÚÆ²ÍSšB±µŸëÓ¢Ý3=óÓ3´»d7%4O‹Â|¼@«ùqÖÕ!`pI›æO °ñÀÉd:¬3`%¦a˜÷ ~ƒ1X8ÿ gàìžgKü@ÿ@Wüåá³8άñu!жh1Õ«ihÓP¼ô3@B(õ˜»c.”ȉ)ኘ÷ó \SvÌ—z„sòÊ¿ü°`R:À"N¸µ#$Œ+äm•pûúV-“ZÒÕ}®¦Â…´?g?áóPšRHþü?¢"€®²¬ðÆ%áŒÎ‚¿<ú NcK#¿Yã“ýrKré‹M_¸Ùù³€®˜¾âAgk ;ÈÇ C»ì ]ˆ€‚‘[‰}ûö½¤mÛ¶„ã¯?d:£?R(Ú0]õS9)ŸVÞ à…7i®¡G—ЭÑßõ3D wZLš¿êÐÊ+éηï¤ê–“Wmñ²‹t3%ÍËoâH@〷 ’ë†]<œ¦«¦ÇS³‹i@$*ÈÚàÿ‚ èÌng:™øúb:»”£¼Ît‡/ éá ¶Ö]ˆë£Ð ¤J8ñÄ;òÅ…Nxó<˜ú!ëÊá÷ÔÑxá‚Xe-Àá]Ñ›í:ß‚ç½çÞÞn_ý¼ÍÂÊBŸU[·mÝøØ´g÷*+*£ò’rY @zÍãS=»8âjLÁZ?àí®e÷_qÕ5A%œ‹ß€óFê…Va}—ùOü´=A_LgAoì Rè±^ #x] C³sÿ„K/½ôÊPÿíà}:F~pA6°ÊO'Á_9¦îù3¨¤øŸ£Pºr`㥜ew”º÷–ï•…?‰`ý»óÅ;©¨¬ˆ’›'Sl3~È!9Vl@ün™Vüˆµ‘C@ñÌ4SqKqAÜ6þÁn¤OÄ]ñPfŠ×ÂÍ«+?a  "ö›·i í84(pAgLoW-Y²äÿqdФÐ#gªµd[ˆª> YÛ 1==ý4ˆ'ÁÔö¢í”™Ÿéœúc¨À¨Ñ[rUö‚ÌØ`êö¼¸®i‰þÞሣñÖ¯£®‰]ÅU›wn¦µÛ×RbËDjÖ¶¥´O¡„– “d˜§Ž¨¦ Å…‚íV»šGñV^ñ&£ÆYàÐÝä‚MÙ›OßwmnžÆ:cz;•ºÖÓÞуºëô)"þóóEš5kÖ*.ÎÀjA懘9r‚¶”pPpQÖÑ|ŒRæN8lÍJVUM\ºkZœ~®¿!â¥ùKéŒVg˜ÔŽQ,>%ž’Û&SRë$ŠOÆ$õ¨Œ0€5‡W·D±áÚÙCì¶¢Ap4ø »}ÐÌÉÄü7¸/xjì³7̦+»Ò#š·tzÝñ«A˜×‚ðp:k¦¢l QÕ• ªýÁËPpü¤I“¦ðµEÀ°¿Oµ6k­—®†ê¼HG~!v=ïÀò£¿¢”Õ<‡Äí?I]žY‘I[ ™Ã¦tuë–œ˜,×ã›ÅSB‹ŠKq^®îÆŽXš ,ÝÍ#øÜ4æþØÞ€ø/§ý$^5EX´y| «ÿ8+{u ÁBµýUÂÆÎeÌÊžEW¥\åæÔ©]')¯¸`I¥:Î)Û±D ÀPÜ`G½pN¤X&=7ž‰#n¶+®«)wXºÎßA¾ðã!Kv.¡ÛŸî 7ÐG²§ Ë:Ÿ ¨+àæ·À¢H³„„„¶øìq0µl÷2w_T¸s<˜"Ö#WV"4ÙÎ@ÆèïoÛOâ+s\ý©¿v†v²]Z¼”Æ¡ôd牲m:PûVíùTE±”‡¸’.8F1Õ˜!`ဋCÆOÝj r˜¸ýŬ ž‹ÉvY `)À¥¶.ܶ0(½î@EEEùœ3èR@§à¡*Tñ]ñÿæ›oÜþAÕ¦¼MNJ¤æê ´öHuõ_$ž< ·d‰ÕTüì/Á¨]Þ€çc›sݸ©Å#ü{™ïyÔõìAgSey%UTTPe%ÇÇŸÈ/ ˜' µZ?øÛøi‡¹v“ÆÆoIÜçQZ(ÊPÖ¯{~õÀOÐèÃ1úÚÓ€èQó­ @dî2¾œ02”O{ÿ°çÚ_¶ß™ë0Ç“ÓR0v9#g€â U~0hÄ—c˜GÍZñ9æYÖå®s àÿ»P–PÊ‹xÿ¿„™@ßPV$,p_4yøc €»ªl»Œø81hÑ€Ø?‹K‹iaæBMæ×Ýþ8‚ÍêDüȼ® ñ!n@'°Òƒ&%˜UÙ«„øPšŽüR2ª‹a²Îâ³~à¤êæXbW?!vöQ·Æî‹«½æ§á(+:)š^ÝúªÛImZ´¡súŸC%y%rÒ€ ±›Zs‰˜M ftoÐ6c!Ûàº÷â‡a´À&nÉc¤ ;~<´§àÕ+—&‘C9Teª'@<ŸJJæ-‰”ØØàYlÎÙì2,êÛ‰bD¬@Á¡(:¸(¢Õ0Q—$%’‰‡p»“¦n Óø0!l«ÞFŸmùŒFw-ASNBó¦Ï£ÒüRŠoÁÛ€¼/+Wƒí„{Óƒ€{fTNAÇÄaê¯vñrü%®“Ìä s/Æqý-‰`Ýž Õ$«e€îX§¤¥¥¥ä²â`!ÊFB^ •c€¡Q(>þÚk¯= ‡_@µµh«|ߣ;è[æB4æAÖOFnca.ni™ÏcTgÃ_Üü˜‡¬`®oâºnS?ÛD¹Q‰QôîžwiwÑn©{«ÔVtÅIWPñÞb*É/‘Ë@ò$¸U¾GÄø†‹à8ðÖ’fÅøoÑ‚ÒGNqmÊß®ú› ‹çÂÛâX¢)ûùTxóO9ž˜†¾YÏ@3€]‰_ü d] šÜáV?-[ýÔDRcWÊö§ÅÅŸ7w¾IýZö£Þ­{Sû´öô§“þD/}X>J i%–?P*õ¶3ŠØ›Be†è÷`g%ø «æÁ¦‹ƒHdüƒŸ¡´í¹ÛƒÒètÈ©t'ô :E.Z*[ý«º2pa|{/InðùÏ[B²Š²–ÁUr¥®F}Q¦š"˜3ÿš¥ ,ãa»aWF¡þ® ®ê£ýµü@Û©Q4õç©ôÈIPr\2ÞïtZ–¹ŒæfÍ•g›ÀWq\3´Wš˜i‘‘8‚Z f%z‰kW€IíÈv–p1ú#®½Æ·þ jWþ.Çà?è5NbP]ª’ªàçˆdδì’l*­,•'¶DÌçã½ÚP×Ä”€‚)L0oþ…¸P¶)7~þü%‘ù§ql?)ЧÙeÙôäOÒmƒn“à›N»‰6¾¿‘¶ïÝ.`Å£y¤88¨¸ ^) †ñ«å†¿:q@è¢Ø<À*˜ ÀÄB5²ùì‰kç7)Ae%e²HÞÌ9µêdRû?oÆE]xá…ýßyçl ¡C#sè8þri?>ÀÖÀj÷þÝΨÏs&˜ûãì (Y`I@ìUäÉW”pÕD‰°«[M•(ì0»vÏöÓVE'GÓ¢ÜEôÞ/ïÑù}Χ¸˜8ºçÌ{èºy= ~?UÇVËT@0=2ˆ8Y€Hý(—î#žG8⨰ `⃀%ÜF ›8nÒ#§úã!Õ¸ ÀŒvhœB•“¨``lfdR ¯õåR°VUšEͪP%WHü6™ ˜3‚¸ôìI×@(ò ¬ଌ•p½M*ÿ³H&€F ¥4­ååaÅíĸÔ8ú÷öS=èØŒc©mj[ºcøtÛüÛœ][òÙ€¾¹¥gAm›µ¥c:C×ö»–žùåi= á³Ï.S«•QÄ£Á àt­Gvg…Ôò Yˆ¨n+ïZi5__q4ÉÐ‰èæ‹2Hg´GÞ2RLŒú]ýØø`’=Ûwç±vP CÐ#G-ƒFu°ª&(NâW®‚b™ë„ôÞþÓ„ïV ‡“O^[~vc½‰ÖÛ]Ó„Ò{Çóv×Äö´¡ž1É1T’ZB÷|•T”H„ñÇŽ§qÆQIv •– §–öLqÕ†X¦J$ K«˜,##?§%£%FÌrK—»š³âT—sžœZóƒé–ÜQ­DiÜZ7íõª{-·?˜€¢ ”²Ô·¥³‹0­¬°zäXÞ[ZJÀ B‘4#0a|19”ç¿‹Ê‹Ü_÷ù±À¥¢?ìzXüàÁŠ»Ã±˜ÿpÛ~6±sWK,ÛOÛiÔϯÉ-ØR¾…î]t/Ý=ìny—àÃþHÛ¾ØFË÷.àí@ýŠß¼"žðìΚ‘ÍòGÿI·ÃP;ç"v䆸¦n˜–rãZ~bEÚQ&½GþZÍÛvÃ.•5…š0;=æúpãºplÎ0‚üÜô ¬@‡¼€9Ц-(ÝÌ >@ 3€ÄP¶ Ë ¥Q:ò»RWI®ûò¢ Ýhµƒ Õ³–›¥~jÚñÕ(Lãx˜R˜%ƦÆÒ²²eôüòçxò]#ï¢n•ݨd/Þ_!¢švžG5o‚!fÔذ]W·Õt»°øÅ#4æÁr»Œob–9v¸E›0wÄ7‹ešˆF4æÐFk¹µÌC±_€oL¦BJ®p›_AiA@âE è¥\ªE@9¨ž; `‚tr U\Ž˜ps„Ëa”Æ"Ÿc"H›[Ï~äØÙ×[ P®)ùÕøùò·ãKâPÿqK£¸uqÍcéÃì(cmë;ŽãéÁQÒM_þ™víÛE‰Q‰Îa!, :MQY]åâ‚·ܬ%Ü2µ›Õß_-´ªåaÇ>HvÓ.·(VÚSkÚ)aÎ?§‚&®à¿Øñ `0z  É îj¹ìQž“S­ÿ<•=êè: #ëÂ)´2¶VeUeÜ 4Ršò— 0¾GcѬª íZ#*o;€¢~ŽÍ‰kû#­ÆÑ|B6¹"Q¼âÛ"ަmœF훵§“:ŸDiÉiôÐÓŸgý™r¢r(¾/ â#"¸ßp*L­º'v§î Ý©sBgjßžZǵ¦æ±Íå[‰Íb›qDQI%K5Õ„o'ä—çSAeTP~E>åWæË9‰ìòlÚW±²+²©¬ºÌY¿ØÑè?Øa¨ð°Ýj‡?â[JÒYîCÎjêëQOøÙíR»úK i‰ñ\G<üVpKÿ]8²¯^VY˜(MU‡”¶® @¸ ´€²rf¼‡ŽÊÊ'‹iÑÕ|È,ð€ùiu‘ŸˆB€+%^5½ý´#îþ€|FÙéÔ¯®&¶ýb[ÄÒÝ+㦣2Ž¢v©íèñ‘ÓŸfý‰rø‡gÄ¥íÁ±-hpê`:&åÑÉ1Á?Ö’(‡ÉˆRbS(#!ȾuÝ^¼¶o£ÌÒLÚV´6o¤œrþà‹¢LtGM—øµßÄq8ýS¼´pLÛ綉ãˆ]Û¬n´~F þƒð¡•¼Ó°»¤ÔYˆ&Ð!F@\GÿàÄi2 …hf0µ@urÔ01‡Âhƒëºf?ý €8žM¼Þv×<¼Vç¸ñ¤äzþcp⑊ô¿‹ÿ—þ5ì_Ô«M/aSϘJ7;‰öUï£ø–ñ¿98¶Ù±4ªÕ(:©ÅI+a=ÛB²´ø4‚îŸÖß#vÖþ,Z—¿ŽÖ毥•¹+é×Â_ÝÇ^eÀPLòHu˜8 ºÄŽjÃÏ಴Bí&®w˜$Ñ㓵.þFÔ-~ÇAèÊ›øC‚v( U°3ƒÝvû­"Dù‰!ÀS ±?шcr•x£_Ó¨]Ü.nš*õWw}Mˆ÷ØÀ‘æÛÜF/Œ|Z%·¢Œæôä¨'… ì¡=ŸöÛ0ãSާ‰©wrïú6±ÁÒµå{)ÐCÓqC•»@+²WÐw{¾£…ûRQu‘L—Kf ¨¥&¨¸«~þÜWM+?¥ »ƒ!ÛË+ð½”7M†DŸÈ9TP«J¤µ,Ì+c¢bœã¿ðWgÈɶ ›Ú`˜P¾òUb"¨‚÷²k<ÉÇ„I¦ò«…iLt ɵ*—þ8ûôÚè×ä¸pÛ”¶Â°&™›)¯ E'²Tƒé‘ië(mZlÝØñFÜbp h¿iX³¸f4¬ý0ÑU´d÷úhÛGô}î÷20€¹ X5$lÓ|½ýl·Ø•A˜2Ú3~ênõãýùÁ_ô å6„ ±¡.ªNhÊÛ4©¶ýÕŽ­µ{›®Xä•§w¼p¸…˜™UƦÄRVbýó»º0ƒ4I Gy*Í)¥Šb³Eèu˜¤¡ê•L}“úÒ}=î;¤‰ß±ÄòÆÑÐöCé CfЩ©§Re#;oý¹r~ƒ¾m¨~ñ—à¼W»jù1®@)mH8\œ®ŽªNô‰¼ë-„Z1 ‚pZ&¦4í3ZÜ~ªï¤¬ÊÖ|ÅîäèLÊA@C*®Ž ãŒÀ¼Üy´b× :&ýÁÒ’ÒèÉ3Ÿ¤¿}ý7Zž³œâªãl‹°M\:>õxê߬?ÙìHê”Ø©![õ›äÕ)µÝ~ÂítÑÞ‹è¡åÑúÂõÎ ¾—w¤§z5ÚТà©f`ã.ü‚¹MÁ]‹)ˆ·å|ñû¡Äo(V „«&Äý…HMa×)€wÃ${ú2m?Øm·w> âfy / Åò§~yŠ^ÈxAq𣤸$z˜·ïž7ÍË™' ƒ1‰¼EXsت;£å40Q³Ózû…â–8ÜF˜öùªÛ.#\öz3Nè§vG8š®.‰ó|EG]?t8¼€¥¦Ú5O×ÈŸ•W<ò×Hº±|#ÍÛ>Ft!×7cøsg±1±tψ{hê©ôÞž÷œsü¥a9'¡±rBê tN›shPóAΧѲއh^˜Ü2äJX@¯o~âøì…0Nœ­³ƒÞ$F/·€jF‹_07*‹Í0ä¡xʦⱘpãgÂí¸HUoje´1bšÆÛv4RXL®¦kuŒ*’ú‰›Ãݲ¬¸š¦AM0^웾y: ï8œ@ü¥å¥”À'2!ÂÞ<ôfê°ª=µî)Šm+Ÿ÷÷ªÿìÖgÓ„ô ”žøñ‡mÃ!–ÙCo¤•™+iÕ¾UŽô"ã<ØÍPœ³Ëõöóé®A_`jÀŸÆ°Ë ‡=¬ €Øñ?ØUÙ"¿†kÒ©R»/ÓöÃ"¡*õWwƒ›è ÞØ\¾™¾ÚþìmúrKƒ3éŠJ¾œS\(Ä›™•éµ!Þ=¹{(§ Ç%æìül*ØÏWGQ³ë ‡l`ÇÎ…eÂÅï¹&¤ðz…Æeñ{]é:Z·q}þëçî{u±Õ±ÔµMWêÒª ujÓÉÑm;QûÖ|©ˆÛ‰Ñ#~t<ßIç×”Òä¬Ê–‡7øQ}„C¶•€)`ïðƒbÂ@ý!öãËMŽàèô¶„bÿ¼q,˜Õ×8Þ¦†yOc/:;ÐÔ›„R(ÈÇ™qã &ƒ~(䘳ë/}_«± (-Kâ7±7B$ªšš.¬&ØÎê]ôñæi|ñRÔ~Cè‘·¡œ¢:ã¸3Ä/16‘ú¶9R^ÂéH<<HaG!-•ÏܳîÙ±'åógà×e®£ÅkÓü5óé§ÌŸDä–u…&èæ|%ÄŽÓu r¬7Ànk/?¯õp_ÜÁ«:Fo+ÛF[vm¡êm U¼¨Ã‹ƒ;|\Í!bN“Ê; <½‰k'Ó%x!p‹>RÂwææƒz ¾ØÀõ 7hÛC2ô’¨R/¸_0·´“ñJãOa·ñ·f*±Ãû/¬ Àm4·[joýIÃm W¨i°F}`hÞ~R–â4…Q—çªØÝu4añ êÏãÿLcîCûXÔžpÊ·:`Ÿ,ÿ„^û*ØíDÑÛóXYCp#yY°@Ö"¥ ê3Hôõç]/[»òvѲmËhÁæôsÖÏ´©`“ír‰ßùUQŸ—e„Ip¾ðw*¸9FoØù)-<È!&üÊŒÛ<¯‚†Û’w;šñŠß›€ʃصKØtû]b!¢c¿ÔË0°Ã™>‚à}´[ÛÓ¶kñg¸J˜Â(LfX€4„[%?ÓXm°6¦h1ZNk½`r’ü$½Ø_u#%|ªb:Êâß?  G8ÄG]ù¿£÷|Ÿví¢g.{†Z$;;-SZÒ«~•øôš¾lºl¥¸6•n¢ K7Ð ^ $þ íÉÒON=æTÙkw3bÁå^i½DOè5A`JŽÍy@IDATÿÓÞŸhIÖZµ€V寒;çÁE)Cð•/¼¶å½GríôM£TV»”ˆÝ¶”XÏhÁ]Ë lÃxB—µ,¶+€öp«(·Ò~Jâù'†,¼:šÆÜ>`Åbk`õ‡Ïÿ +ÎXÙżPÎyó|YöŒ±  Qˆ³@3ÊE,v»v ñQ€"‰Ý¤m0õ1e´ _‘óä”ÒúlôgòA-{îê¹4yÆd™#Côþâç©[Ûn,æG+?¢;æÞAåq|œGaYE/á+¡ûyK¬˜oÌ3B°éGôcf0àTÜo°ì«{dTGni.-ع€æïžO‹ö.é}5¾¨Cž:*úÝ(ísÁø7êÂÀ0Ïç5w­Å,¼V—òGCJù*pI5}yõ—Z¤_sÍš5ÄŸëÇv°Îb˺ˆëôA°JFy˜ª]@˜¶f§?%i ¤•¸ÕnñCxÅñ—_Èþ¨òFç¢Ó¼LS¤ãÏQóªóhæš™tõ1WKRüÃè}J÷S軬ïhKéºðßÒÔ1SéäÞ'»qÆ=–zµëE7~q#?/²G>Z*åb®”ïWí¯’g¸fü8ƒ^^ô2%T%Ðàžƒiø‘ÃE:гn¦A,i ir~at·ÑrZqñÎÅôÕίhÎî9”_ÅORG˜'ØWðnõcSüBýá'èO¼”&ò;Ñ%aM~È3L*¬À„Ï&È“Z²@Dðu”˜Ñn »ššõƒ·G}•&Õü …ÁŽy¯Å½G‡›ò0r7+kFŸŸû9¥&8Ç‚´fÛóôŠmÇßÀ*ù~¢ÿú?tù°ËMJÇØW´nþòfZZ¸Ô9>Ì⹌XuÇ f¦_½¿šþsí´H¿æHºäã7shTPÍÐñûó"`¿ñüçа!¦=2ã9š|=_–ÁÛõüN½|…†÷¿E\㸗X5¡DÐŒŸfx€®_ç~tFÏ3„`ñ5÷¨VQtï’{éoüpèGU«f­è¥q/Ѥ.“¨¢Ðy\‡¢›ña›4ÞooÍûíéq”Ð)º$PbW>JÛu·DÚ¿ƒÎ{êS¦2Â,!®¿e¿.e{рЈ©»ôèÞÐËöY°ôáeh(~hœš¿e'A1’ƒ qº #¿!|¤Œö˜k«dÀñ¹Úuל#õë_§ìbϤ¾±}©²™Kn½ª H> z3ë úÛ£=æòf!£=ˆ^E}í½GH?·¡ëÿà éüžçûí¨1}ÇÐ˧½L‰‰Îv3.L t]`nö\I[YÅG‚Y«Â{]ÒºP~~>õIêCo|K¶éîêh9‚*¤ýh¦"QÉÌXZ2ciGßåG¾r!¼w$ýßÜÿ#¼eÕ9­3½1î ßn¼,|Ê¡¥F" €™ù•Pü5Ž2Dé#䇟5ò«=˜y }Ö£À¨˜4Šÿë‘`¶zØáíÕ ¤ƒrM ²Q‘…0%l˜ùÛWžšþ`™#ÒGЙy«,ˆ:¾ÓñòbÐe\Fe)e2bC|Ç¡¥iGÁêÚ~XÿƒÜ!hÓ¢›ãÙýΦ%—ÐYOžE§8&?‘.:â"9Úûmæ·ò\Ù×;¿v®sžXg©ôt]Þ:ºõÓ[éÞþÒu 9bpÄ Ô¿{yÇÏ-ä,ñ±ñtÿ™÷S»ùíè韞–òqŽAî€p+Uƒ‚‚³ÀCQ04ŒMñ·Üæú[q—Aôˆäå0`^`¤@X¬<«Å+'€ `;VY!WQL¢³,2ñ»qÅöÛþ» ë!WàøÎÇÓsg?G“?šLòME~_Ó0ow|KúL A½ÑäG&Óco¤ã{ïæ}biæå3éšé×Ðs_=Gx[à’.¡³úœE§v>•ð‘Ö9ÛæÐ;Þ¡»PuB5ÅÄrþ¼ûÝñŒc Ã;eðOêÍvÁI8à¯aêo¹5ÌÅa+ŽÒ†°Ã\»2)0<ÿÂÊÐÌa2Zq¿;;ü¡ì8vá¯áb5@ÂgBwG3â#¾vˆ¦µóû-ìZzÎýƒÕaX¯a²¥vû··Ë'¾1wÇþþ¼]ó„ ý÷_tîßÏ¥‡®yˆ.9ý7Ëö-ÛÓ»7¾Kçï4sÙLúö×o©mó¶4áø 4ià$:³Û™¢wí¦÷×½Oolxƒ¶óOnhò“bÑi|Ìw Xã ú¾Ò}´7o/Ug34dF ;TÂë tß%÷Ñe§_æÖ–æ@7L½ŠË‹'˰%ÉÒ†<Ƈž¢Ê¸ç«¸ï‘Íá&x´ÔÁ]//×éÕß6a· u»†É^ £¶ƒ35£8ÜÞÚ«€óÇ6ŒìˆÏS`9†Ëù `Oåª0Ã1%­W~¿…35®æ2P¨å_2øšÿë|ú2‹¯2à•Ü"Ä×uqD"ú©ƒN¥›^¹‰–o]N÷_r¿û?Äí‡þðÛõXºýÓÛ)«0‹žþæizfÞ34¼ÇpºäÄKhä‘#éºc¯£k޹†¾Þò5ý{í¿é»Ýß â¾,˜bÕÖf×Ä}Ïåoûô6š¿q>Ý6ú6‘}óQzá“d”‡d†úã´"˜v$pFA 1ý*\‰xÀAU@I¡á¯aÆ.8èÃÉuÔ·íêçm"N8U½€Ûø`µS 3í|—•;ŸgÂW&àú™8.à%$;dþWSRlRëó±ÿ ùÍ—ƒD˜+ÆÒŠ=+hPÆ Éë/çÿ…f­™E3—ΤŸ÷þL/]ùAP5qÈD:²ã‘tõ›WÓî2ç Âü­óiîú¹"ÚO:aMž, R€ùn˜<@¢ý§•>L»Î°«».vk›h»Ÿ¼B¦³zÂ¯Þ ”òt$Öi€º}¦Uë1êCä4£¿ø1”\ »ù!?o»Ï2²çú¼õÔ:±uKMOK§+]IS˜êŒž|6`næ\—ßóxyàÛßÒ¹?ÒYOEÓ~?†öê–u\—ãè“k?¡«ß¾š~ÌùQv¢*£(»4›ûæ1z|ÎãtZïÓèÒ!—Òi}N£û†ßG7ÝLoø˜Îïs>á­[µLlIÐýÛõ§ËŽåÅJ^W˜µq½±ê šûë\¹×€cÊZð0(q¦A¦XËÀìµ,þ±' wœó§‚…i¸â­m"OuûË¿¡üûcà#\ŒíÚ(1Y|rM<Äzl噃:î¶óࣥ&žËÇ!¬A´õUSFL¡¨¼(çÞ/ÊÍß1ß#«›Ï½YÄtÚ·.~ýbza.‹ß–ÊhžAï\öíÁGtùc¬r¥¸g¾®È¯’áÂK§_J'Ý=þÕãç)GO©EüV–®·G1š^=ÿUúôòOiØ‘ÃäÀQ\FŦóèßšD~^hÄB¦.þ™^?¤û-Ü8¾áâ~üuFKX€Ò}­Fƒ˜•ð™¸=GHMøáHøŠ@_nûRZ_ŸþÃgµ~×õwÎþ9Æ[~{÷ïu³Öo×þ8‡ ð¤Õ-«é®wÑ 3o•jD|öëÉñOÒ­o%ÂQæ´!˜Žã”àŽŠôàœé„N òJDª›:ºýÑôæÅoÒ=§ßC \.C4ó™P]áÕ˜LÁ÷@ÄÁŒÀO„‰®[WÔ9v½€¿ŠÛþn#´1j²¤(7'ö€˜ºè„…&ˆþ®©iCssáfšµiV;Eœ7ð<ªÌçSt|slæoó”&Ÿ,[xÄ»kµqøƒÌhüsãiWî.ÍFÞø»áäèù‘ÏSR ¯I0|%>ÏÓ‘&¶-k^¡¯Jáï²h_…» “M¦.ø€Ò«ÓÝj2}íÃ~mжØ6 l೿MOþìv’ºÚëÍB)HÅ=Ä…]þ˜ãaT—Õ|ˆ÷8§oe—0óD²¦?lM»ÿµì_7ûB›Æ9®çqñóƒ €ÑœÌ9$æ¸Áãø¥Ö4ç>ÃTNû±ˆ¿²l%ýÜÙ´|órø¸„ôÞ…ïQ‡ªr‡@ú„ù,ܵâU{–g.öHSWÇQGÑ;¾C­JZ9G€Í=‡Ã¶sÃWû@ð•þ ¡ÂÂÏ â¨¨c Lô:âcž¯{Ìj‚I4QqmÁZzeù+õꪎ­;:÷ÿ‹†ü NöÙOEC¼Çj~eó‚,à†Sv±i±”˜Mçÿû|z÷ûw=Ê>2ãHúdÒ'4(i#=@âÇKX#˜¾vºGüú8:·ìLOŸõ4UïåËJ|ïÜE$†d0ÜF¦7^}€_Ç4aeÚé B¼Ç–“@4l$¢¾ÛaÞÌMÄi¾û¸Ÿ–m_VÇ®!™ËËmF<ÂðÃÀª¬UùL>}2_¬*ä8Ì$@ÌòJ¯ÂW¶ª¤?}þ'úÇGÿpˤĻƒo\ü]Ôñ"Ù¾¢OÀ°¾Ùó }¶î32êãÒsé<†*÷±ôÂÛƒ¨¿âƒ_xyï±¹ÈPÛ¤qëü:¤©7ð7ñðÇÈy¾šŒz3Ïe 4~E×8ØúÂ[ÿ“?žLëö¬«C×ý¼ùg!!$'Vs·ÏSÿui×EÎñC S|ˆ&€½w^…Çbß´UÓhòôÉÒ>NúèØGé/þB•¹NZ™–ñöÜ-ón¡_öøsb8Ž\‘]á<†©€‘×¾¬W½™âë’ ‚S8iÔ BŠ õ1ëÍB*LŸ;^F|¡tFhi!'gÓÕ¾r³ÃÙ‘6Pøo†O«äÄäÐøÿW§'º^þôe§mLÐÎ>z5}³s>ì¡ÎÄ‹…¸r˻ոv xðúCo¿Eó1ßXf³öü‡æý:¯Öûñgš:b*Åð)@>̘G…QtÉû“hýžõåÔÕ1 ëf.üü2!ÅððP﫺Õ „_ÁÂ5-ây+„…_…•Tóê44V©ñ•#Ñh·Íê( ¼L G<'ºn/íæååïï7s£½,ZC,ϋϧ‹Þ¸ˆþùÑ?©¨¤!~ÕËŸ¼LoÏ{›·Óœ´xi˜øTà²ìå”_ZóR2;x,Å”°ÈÏ»UxWRà@¾KÅë1ü䨧›>•/ ­Þº!®ºà¸ èµ±3)¹ˆ_‚¸Î!»ªvӸׯ׉a¹KIY‰äWÉÓ‡Ôî¿ß¬__üâ·íòîU¶ÓQN|±›p×ßÀ3Fx ÂÇíMV£'™€q(¦ºE5=ýãÓtü=ÇÓoÜA ×,$ÜžÃ]ÿÝûvÓ§ß}Jþߺé)þš0¿ 1‹s` 8=WUQk;°uóÖtò';»f½À·MÙÄOŽÍÍš+·ù¾ßò=}þÃçø„ï¾÷û÷¨My™J@âȉ͡‹þï"zôóG©¬¢îÛƒ+Ö­p?f"ï3`¸)ã¶Ý›|¸Ñm ›p«ð€ÒvÀôÖo5qÒÆ»¦É nù˜H(5~H.þšÑ¡d2´±U‡vâ!g—>KOÏyZ¶úð8Ù!,˜ø¢[ð¨ÍW‚1‡‡ø|L^ó2çѹ½ÎõhÙÕ#¯¦9ÏÏ‘'¸¢š9gï="pºÝ»iõžÕtñà‹ià­)3;“®:ë*7Ú‘í¤.ùHNn*Ù$ëUÍ«èá%Ó‡?~Hˆ÷ìÆfyú]Þ 0G~AøPjK{H†;Mpª;kÅAñ4~Þvi³¦Õt€þ,vùY¦SXøþ×[Ê¢¢: ÐãÊZ2gðI¼|º=k¡mÇ~Ž;¦½Ã¢R™zyA‘c%WÌK8Šú¶î+Ì÷ùí³ŠXXüjëW”—H×sÝòÚ-tÿÛ÷{äÔ¹Ugúðò©b9+ 'ùªð¯•¿Ò˜çÇиGÆÑ¼Uó<ÒørÌølÍ^6Û}Ó˜A_¾àª_½@¨ç]Dêög×ðÆjr»q!ûî¸-‡£¸8?׉uþÂO×xŠëÌöŽ|¦ßäÛurƒŽ× pÿ/ÿ"vû¶ðÞúË[”Xšèl bï݆œÅìm³%Ùe'_FÉÍ“éá/F`?7Ö:¥5½wÅ{4´ÅP™`+õƒú.ç;ºà¹ hЭƒèÎ×î¤ÙKg‹$ùþ¾ü}4gÙºü—Ë›zX§0`@µêä]ÇÆêÔ}µMýaBÙqŸ°þëÀiZTw…ÑÊ— ?ýio·$>TÿdQ™/ÒŸÆÃM=]/ÁíIpŽ®¢ô¥½/¥î-ºûlYÇ6 W‰ÿúå_K86ð´ÿ‰bóÇ}?ÊÇJÚ$·¡ †^@3¿›I/ÿ²<2íòi„7 š%4£™—ΤÉÿ7™ædÍq®õ²$“À”ðcKÁzjÑSôÄWOÈg¬õ3×Òm\‘õ‹ÖlòLL¤‰ E4ŠÀ»P”wAîàeû¼ò¨Šª¢¹[çJx7 e}´á#ºü•Ë=.aª0cÒ :+ý,‘*^^÷áÇE!`êÉވ?K 2ÁT†%0¹ÔØúï@ÛàËq¨êÍB˹uGCYé|Ôgz††û um)B{˜Çëß²?ukÞMàèï¦w»[NàÉaœò3í¾ ÇôÅy_Ðy½Ï“ä'õ8‰&ž8Q˜Fè¯v~E_žHûËjÖ ¼8éEÛi¬9ÆÚˆëxeXnbý¢#ëά»“™Ö30uL¤oó>PXŠ ÷‚…+,L<ï>õ(Kãú0½ÓÕÅ]or!Á8\$<ø(``tJ‡SB;ž û]çß9¯ôà?>8±×Dzü”Çi@ëûºLÄÌ,ž¼âIz輇ä¨.¤o³¾¥‹^¸Èã+BxŠlڦѸNãäÓdr¶é™i`~"3ÀÍB¼ &Ê\çþ(GT¤¯kà[0x8±Ãú?¬ ÀƒƒyqC4Þ#Üg Þy+ãP ñ†ª®=íZarBw®éߤWޏ’®:ö*çã$Ì–ä,¡ñϧœ¢7 >fòÌÅÏйÎu®(ã¼Nz¢°’„¥>k€é Lqcå_õèßC öþê‚æû ³ýýÅ«åxY°r; Lt]øT0g‡{×a¶ äÖ05ítÈÞ«E¯[3òø‘”—AYYT\MÝ›w˜ööso§7¾ƒŠ¢ŠdqeáJ÷ü8zçÊwäua$xnâsÿFÞ,®™”÷Wì§‚²ÚS¼‡RãS©Sj'yÔÒ$Šü²|AôÜ’\Ú]¼›²Š³hgÑNÑó6Ò†¼ ´¹`³<‘n/blD¸müR;LvÔÇW¸ú:­ia†QÕ›€KUEìíFæ™Æõço‡«]Mï4ÄžœrKpØè¼ãΣç—}׌RáÆâ€vDÿ¾ßï%ë²By´daæBù`Êʽ+å½C—(chÈŠh^6Z©MÅEíf…KrgÂ$eW7L—µèp™aeõ­´ ÐúfÐHÓ%Äâº}­Ù½†²ögQÖ†,úfÝ7Î P¹΂Oz·ï-L¡oç¾Ô¯k?:åèS(59Õ_UBöoÛ¬-ý¡ÿDãã)‹·/¦OÖ"7w•ìrÎR€43ÐQµS;›.¾Z~v¸4aF#¾¤±ÜóÀa#‰Ã÷/¬»á«vÓÌ kuUº “z{röÐôï§L.H‰«Ûx¸Ä eÂèѪ‡¤]ºi)mÚµÉͧy³æôîÿ{—ºuìæÆ™€˜N¼ˆ³é1T’ZB+sWÒ[+Þ¢{>¸‡~ÿèï©ã%éïÓÿîñÅc7ÓzZ°¸8¬Ë0ºÿ´ûiÅ”ôþ˜÷ib‰”Zêù"Q=óoŒÉêÍ”‹2mާöˆÉhª‡ÞQ¸£Î8دK?"¾É‹³÷ϹŸ¶çn÷›ÇŽ,Î+ÓxÃ×ÙÄŽØÌ zC0’&=0I>ü)üo~ðרmJ[ç4#ýÅ @÷²S'>ƒB80ÄŒ!:#šžüöI:÷¾siwînͪÁL,‚‚<6ê1Z}åj9qbËå}B÷y²@«ðõèŸúô©ÀØ_Y @ô¥a´z3€P U±Æ5hãVž¯öº˜v]â7†¸ø4W]¾à+¯ò¨Žm¹+ÞºÂ㤟ßÂÕ ¬æçÕO*}`ZqÚ±§ÑY·Ewnt“÷ÈèA¯_ý:%T$Hr&€×¢šóB4¿:݆u;ç¤ÜtìC‹òÑð†ÓÜÕsݼÚ‚#Í}1}üûiÁÄ4¥÷JªHrà‚ÇSð©²qa¸"¾¤1n¸Â~z¾¢¡á#¿°3- E €B‰Øã¬ÏY_çVwhÝÁyˆ•%œÈ[‘½‚&LŸàqÈ™î/~ô¢s7ŸòÂe%kÞœ]œí–=åÌ)´#w¾{´Çt`PÏAôâï_¤¨~¼·‘î4àn7áoÊ!|2Œ/ Ř¯É Æ/Ow¿sw½>LâV,ËmŽ F>@?^õ#Ýq”“á<¦ ‰'4 ¡”Ã'JxD,³Øô¸˜¢aÞ¦áŽÒ°[ánzËÏoìvïCA³ŒÖ¼‘ÓÌëyÙwaÖB:ùÑ“iúœé´¯`åäÒÿº‘–®[ê\Jâ-@¹ˆÀ°nÐZóhy=Ú÷ ÇŒ íyÛ震Ρ»7jsì9tשwQUŸÄsæ,yÈtBû1ëä3¹2Œ+Ï­¢hêâ©tægÒæÝ›ÝüÂei‘Ø‚n|#-»z=ñ»'¨SL'ù,º|=I§?‚g^¸ë›ÞaÊ|´<;<\0ùÖ›„$RCœ1¢ Zí¦ÇÃ_E"f}ÓùËï0ð¯HŒOtDJ#êʨÎ×ùÌÝôÑMÔíÆnÔéòNôÊœWœyòèŒW‹ä(/Ì èå3_¦´DÏ…þiÜŸ…v³$ðøhÚ¼g³‹ª7Œº.éwIÍ]b6ú/ñÎ"¶£ù‘”åEËiÈýCèùÿ<ïˆËn®á±`áðâc/¦%×,¡—Î|‰zÄ÷pÞ/d‰ÉcjhšP\”Ö€&4­ÉŸN»ÙT{0º8ÈÔ›Ô©PÓ¤ rcE©¿ÕX4Z5âª=bmÊÛD{ ÷8° ñr"ŸæáFžÃÃJøàK<"‚ó×€°R›{¸Ù‡¹:æí²ýÇ `\Ïq4¤Cíó#ޤϺQ$„%;iì3ciû¾šÆG&>B'·=™ªóÅù¹3w´úWúT*äÔI¾lĤ”6/¥[?½•F?à9ÅʇéÁØ£ÆÒWW|E÷¸¸æ; * x×;T7ê[—¸Vû@øáVáe¾nZ¤ÜÀQ2 |åÛüvó·Ì¯3N"Ùâ%ç& ï2ÁƒÈ–?Q&_õå¹:ÂÑúLð[Þ}—ßGÏ\ú ?\GÛŠ·ÑاÇRæ>g¡‹…3®šA]cy²€§X@üõêÄ/%ÉZnò­Â…ûÒÐ{‡ÒÃï=ìwáÒoåB Àöè¬%³èÑ7¥Ë¹Œ†þm(½:ûUª.t—ûN£¿z7„¿ÖÕW^&óÿ·÷pV×ÿ²ÀîRiÒ¤XEšÁ‚&T£,+ŠIò‘Ä‚ ¢ ±þ bCE( €"é JWŠôvéüÏwîýÞw÷Þ÷îÛ²¼Ù3sæL¹gÎ9SîÜyÅz(¦³ñ×ÊÞdó‚]´)×!dJ‰…Ÿ¯ý\z7ïÜóÙ|wgX # Jw¨œ¯8ƒÇ-E®kY³%ƒ°_Ç~‚›ˆúÿ«¿¬Ì^)—ŽºT>ôÔ̬)ÕÒ«ÉøÇK§';ÉÎÒ;̓3‹ÀÂ\¤¡ÑÃG¥Ë”–=9{ä¡éÉK³^’û.»Ozwìm.U—?(-wO®,[½L¯\,‹W-–E+ÉüåóeÝV}õ©ž†¸”Eon.­Ë ,óe#–](å8†ÉcââáIë‡ìâí:‹)\`WqÝÆšß±Ó‡Ñ=ßåÇÉ?¬} óð°!ŽuZ¥ Š# xB…pIu­üÈ<¯÷}‚5wýÕXcZëL/怾y Ç?ÍÇ÷ÿ}@àüSΗׯy]z?×[¾Ûþ\òÔ%ÆdedI“ÚMdìÕc¥çó=å`i=ª×‰™ÙEž (QQPJUFlZ–.[Zpâ¯üA†½;L®=ïZétF'©]­¶TI¯b~c!ww®lß©_nÙ(?üôƒ¬Û¼NV®[)Ë×-—å?.7÷â6$cäP6ŒœB¼@4¸¼ÄÔ‹S׊7¼ð‹ã„Jj–«xâ‚ pð®Q¡<›lîó34Åá l"5Æe‚axÏã¿da@aqÜ-—ÌÊÊ+)¨ »6ȼõó¤eø#3ŸwgÎN‡ç±„Nl]ö:iTµQPR îœfçȸ«ÆIŸçû˜/ø`þ}Û¿¥Zåjr^óóäþ.÷Ë_'ÿÕ½u[Â{ËSŠ/¢:jfª£øB¬Ü¹R†¼7D¾ªË ½òÌüÐ,ÞnP&P„Òc9Ae7ñLÙuFaê…Âë³ùˆ×” »¯?7F t(Ç.å3îBOV÷¥ÅÄ™Â8Àñ,'V,}¶¿ˆëÀ¸Ö0£â1"•æ€ù?\ýÇ;wïÙש( ÎWf¼øÒÍK<þv:­“<Ôã!óêoѦEÒóéž’ãüŠÑÀÎå’¦—èÏ„©  IQ6×P'ôw&âÎè%£fÏBï,]CãúÛ Ø30aü–‚:2›Øß­^±nö9êæíw˜kرñ‰2õF#s`I÷ÌMF8»ƒ ÿK‚g¡üDAa}àÔ’×7Ôâ‹ &cØô‚7EKˆ™†ò!}Ì53ŽL—Fš •ûï}û^ä>à/ú¨8;yBøƳIË&E® „×_t½\qúFÁçnœ+}F÷‘œ=9¦ŒÑFKÓ Mc7Cd ¦=È ]Ô‘™çð¶Âü†‚ÞGXFO–QŦ‡¢ãwp9æ ]™‹qS±Þkh®4æ'Î>`J­(JÅã¹>»ÉÃ¥BÿAm‘]2 r¡$Äh…´•žqìàŸ‰»ëƒS<Ö]üœMCÁ°q £^†K,T`=÷ǹds\¸cç“ÎkÅ“åË„¥dÓÎMqëð'ޏj„4®ÜØôûë¾¾ÿìk~Z¬R…JòÊM¯H…ÝúÛøCüb°Û÷‘ ¤BôÔLÝuÀ¼®ÄÔ^Ïx^×ô¥ªh¼¦AÉqÆo<Ìù¬íáõìöPž÷/™¶X´I¯ý(ÍJ‹65¯»?ƒ¨Aq¯†FHÑÅå jô¹?(^ñ¡ÂÀc¾! £B1I¶ð‚J@ Ö¥Oˆô${÷é@…‰0Rn‘œý92ò³‘©2|&<¢ß9¤÷  ^\C~Íóט/ÿpOÀè¾£ÍRÀ\[®n’îZ<6òt´6#7¦ë0ôˆsDÇú;]Jç©Ñþ!Ñ+_F¿«ˆ gúnaA @tƹMÃ<ˆ9›0?æ§ûaüQÖ½µø­HŸÒÆì€õae†áU^üß‹²zËjäŽìÎ=í\¹ ÑÎF*ßÄå妗o2}ÙY—ÉÍíov–ØÈÃQeNƒÃÚq4áù,‰ Ÿ \E˜G‚,fW `†ÿ ÃWXæÁÈÍC‹f:œx2¢ˆ`èÛ†"*?i%*êz•ësÖËÔeSöž}{ މm²mÑ\»õß  ƒLß%¬Ð"¸á¢Œ’c§ëë7—¼)w¾æü¬Ù}ÖY­7<$TLòpXû Ï…ÏJk¾Ï =¡Ë£?À%pQõ1¨LŽ’v¨Pùº,^fs}”v¾çÀuÈKeueÓIuÓ‰!àÇÒ2Ë€çþóœt>¹s\á&_oê >ûx73•»ð³~œ%ç—Á¿œ0 º´ë"u*Ô1ƪL}§Sôçêw«È=—Þ#ïÜñŽL]?èì°UDÉ * ¦ë]xK7.•“kžú|Þ&*8­×³¡/TKBéÀóãɈϟ”;/º3¡ág¸”ã·­+Ï|öŒR}.§tz`øgOHí*µåºó¯“Sj"}Fö‘nmºÊUç\-ƒ; –Ü}¹2cù§òþ’÷eâw¥´ÊÍ?z<%Ÿt1‹6ç÷›Tob|¿–ýdõÖÕòاÉk ^5íõÎ$ù¸1•8¢–‡bÜ‚F>­¸!¶ã ƒ÷p¦”§ª FöMœa- xÅU,¯_mEp®>‚’5EÈåÐÆFÎÂýû÷ï9pà€Q6£„ŽÊ¯\^¯bÂsÑcw_†!®åÔ?^:é,“®L‰G{L¥Ú{£?. u¼Ä³P¼Aéjµw•Ê‘¡ ­+(¡ûYÝÍgÁñ;…:lÒ!§”~ˆ4øßƒå9oHózÍeÌUcäÍOÆK›¿¶‘‹¿HÞùï;ұѹ2ú²gdéßÊ77ÏͧüAu5¨Ö@Fõ%“¯š"ÍÓõ‚SýÉÔ ¹9Ò²Ãú]èÉ5òÎtʾ¢+W€þ@?Â=ôúÄ(¸¨@›å¹CûöíËåHëaøAZ»ˆÍnüèƒÇ¤YqZ°ôc¯#Ûëó_»A‡ÑÓ±¶Êgô¢Åߤš#êÈÙ#å¯ÞЂ¢¹v§´“2ûÊ8w¸k}³{¯ËãÊ´…Óä´ú§ÉØ›ÇJãŒÆ2gѹñ¹¥ÙÍdп™c¾UÒb?ENTs»†í䓟Èà¶ú+É9:ëÁ׈9>*(¢æc=„ÈGÞ²,èpð6½¦G¹z}tKP`J‹ä¢ÆfÌÉÉÙË“È_ùx31£>F Cú`¢4—1ˆy1¬9ó„ÅåÅÞR{åáí ³`ñºÀøÈ®7±GIÇQŸnî+»O®zùª˜›€P|˜k^¿¹sí–Ið^uÁè;ú=åöÈsŸ='•Ò*ÉÇs?–—oyYðq‘™%èû|\C^wv“³åó;õ ʦ½å ö£ö*8Ò&Ë¿ B¦1¨E)‡yY7ãx8„Õy†À-û$‰ôú¨t(…¥¢„H.Y€‚nذᇽ{÷ŽÚöH^7£®óPl ¥qC§œÃ¿„Î"‰DŸ°ÀD Št ÌùÛÄ¿>T…òø¥NuïDÿº£÷öRÛ¥çèž²9;ï®À°›Õkæ\5î»n<£b†|pÃÒ³MO¹ì©Ëäâv˱Cä¥^’ž­zš<üxX±‘ñéiéòüÕÏËß»ÿ]ÊïÑÃ50T•°R,™ËG/Ĥ!$Þ†Hcº¯=0'TÑkÊBfÇÄC¡ZK°Kµk 'cPüyóæ}йúUuê…ÀÈO/·ØTB4Ù+Ý ÇG² ±–VÜðc §ìÂÚ|ꊩ2þ?ãóuIÌì©…åÊP#€+ÃVæ®”þÏö7Ç|sj72_íá^BoïGÛ1æ’1Ò¡aéиƒ<ØëA¹bøÒÿüþrÅãWÈÓýŸ–ιAÆÍ'M|,¬è¤ðל{|<ðcïþ?ï–¤Âòù)Ë„þ2£â-ºúÕê'|>]ÿË¢E‹V(aÐÜ"aþ(€‚¦¡’Ó§O_¡×ÕJ¯%iÇé« –àBc Ü{â<Æ¡$?câÇùã1Ÿ <Þ£6ÞéîúïÝ)k¶¬AÌsKV.qÂEÉ -FÇmg¯Ÿ-7¿t³1ô^¥¾@¬:ÎÛûÕ•#ö„ÚÕm']OêêQöjÛK®øÕòèøGåäº'K¯Ç{ÉÐK‡Êß ‘&< }Gô•-Ù[<ú‚°1cð 9·Ö¹æ¨rà’ÀRÂx2aä1-Óü}aã¶ú(M_¡cÈé@|è£>Z®tF7­’QZBW  ¥îW°×0 Aµ2kéÃ:3•FÜx3;ÐBèÚL 2/©5Í(z,4iø Zâpß$Ã%ª”âlEöÒïù~Þ×w蚯ÿÇé!ŒÚIò/.=êÄ#]aŒ_ô¦<úþ#N=³ªè’BÈaÌ ðô>­W>Ê;{Þ)5+×”V¨_.½žè)ƒ:’ü¿‘2ñ›‰ÒâÖòÄ›OÈÎ\ßùJЍž^]Þ¹õ¹úô«Õ¨ÜéGI¶L>7dü‹ZOOIãOƒ5Qœ3{uËô._LšÆùókñžú=T·+V€îƒG%¨lß®]»¶FÙÄ2à F{õ€xÿIÏwŸ._\þ楓Î{gêðÏä× ²yy6£ò>ÁýpŽ~΋#[ð:j›;YŠŠZ$ê}¥7lú#òÆìà׃™•3€JÏAnôA›ºm‘;Ÿ{ú–§eÞ²yÚÔ22kÙgÒûï½å÷çô•5cÖÈÒg–Êy-Ï“G^{Dî~înYþÃò|ù£"ðã¦#¯)w_xWV™ÓW””G#KZäâ[ÐÈ-ã¤óÑxò:Õ ÄM>Ð!®œ€tG‘A<´Ya>zâíòì|hÒ U Eô@aããõsêºýS=Ä wWXJä¢4ME%û.\8o÷îÝ +iU¿•ù †¯1Ý·=ðÆëÚtШ zxàí4ÐÑÙ84ÐŽ—ô°1éú½û¼-ó¤ûðîÎwñú=¼èV €r»èùáÞí¿·Ü^¹âÙ+d¹Nßmg®&w¥‡üÇs„¹›~{“¤—N7r‚½:Uëä#Å/½g¬ ê3H†½:LNêw’œqå2øƒeò““Z&ÜÒõÚe¨ùDùàn•)ü&”²I%d˜PñЈ:+ÍËgçg: %—ݙԺ´–´ÐZ®v½Œ?Z¦|1ÅÜ ¼-{›÷uÎîYºj©Œ›ð‰pA4¬›jЏ†!pÓN«wrÆu˜ýê@ÕЌžÀ£ºMõ¬Íž­[·®Ç:$‘kb{'7Kp”n¦Cjùæg>•m*»¼¨²š½Àï0tnÞ9PlÝ‚ÞAÿ´…0ÐGî°FE%vì’Ä”±c8*ÛûÒK/}¦¯ñ¸ ]‹z-<áõÚæÁ8ÒƒA®SS‘ï’l¬Gkå#.TøÅßÐÉCåŸSÿé\̉{ú \úÿûÍßÇmö0ׄøfå7qiíD|üôìÏÊUí®rTÓ{­×\õËAñ»‡¸HT•ÝŒþz‰(ÂæQ\Š%“æñŒ& ÏKbyfŒé„ÄÛª :—ÖÖ‡Sœj’ýQ½èŸÒÙÊOs’(»—žŒ@sQ”~îäjCvDù2ð‚f8#?3ºÊoâZBÒxŒrf3ËŸ×nÍc8Ÿ‚Å˾5k”Y_cm6"5í»Ÿ¾Ó¿á?åe”E%nÊÜ)á„)0O]û”\×ö:çÊ1÷Ъ1Jú:Ô[Á Ñé¿þ7òÁ±”²âÆŽþ¤gÈÍC˜žêjÁ O½ÐÅû}S½ÛýS:. “( µFvQ  ``– w¯X±b ¦#‰\§“:™Ÿ˜†b³c 3]†pI`+¹1œ(ô+9ÓýøT\{„½v¤ ô Š…‘×sãgÁ×Y@¢À–m[œö«lLž;YÖoÇr7ºÃ&ò“ž”ëÎrî" zñ2„.(ÍÆÙá°2ïɾÒ{FÄU~Ä3Ò2Ìô?ÑSBß wJ‡÷$\@/í'LTŒIj@ŒÇDðžxùå—'c:ÅáݦyǪïYÍñ_w/€£½aËpoY€©½ÅT*<¡†°m<˜æ1Û*‡i)¨=Wœ|¡ÀH‹õ56#Õá€R<·â‡N»”hï½2ô¡ñÈCÓ†_3\~Æïó.µU$ÞsS©}0F–˜†ÚQㄬ qzÒ¹qSÂJÛ®iâwÿJ‰Ñ_ w´ jƒGi‘]2…¢pXxXžÝË—/߸sçΟ1-1J« /;ó²<ÂæÒn¹qo£‡1ÜÙ•Ðc¦ËDÆ=fúðLOAí±#Á­Ö|ÙÙàè¯Sçc w_Àšîã¡Í©Aœ´NýñD ’I6´óÙøT8ÜP otˆôþ¡_õTç†JËœ…z¤ÒI¯çn}õVþîp“74c@ö^¼íEéX¯cÞ/Aþ0XAÞÂ-¦Ñ1ÐO<=Ò´^o©‹6 Ma³ºŽn4?=ûî»ï)ën蟽 ýLÊ%c8yñ€ÝœüóÏz˜:‚ûí¿uFv-ÅXTZAk&`¬%lÒhe‚žÞƇ…MùVþ0º>–χ…*Ms×ÿ¼M=Õý¹#¯בÝûÞ½ÒñOeú§G¶<’rÇ•“±·•Få}ìŸ @V(s>èÉ$å‰éŒû!Ò]“aKÆ‘F< nOŽâ g/¾øâ$¥ 2hERF €ö¡p> gý¦®Z òIDAT¹«W¯Þ”½5Ê¡ .§u‘º™uRP¼ŸyvœfÐò`Z"oӧ±üû%ðcÞó´QùݔϦHv®þª0N/êž9W SyÖ7 ó6Í“õ³nÕŽÍïF¾¢¿E¨#>ÞàëFï½¼Fз xw¿pëB¹~ÔõÒðò†róc7ËÌÿÍ4Óëü%æa×i,O xJé'ÀF} ~9ó)4–ùhâÉ#ªsË0y-å7rm)?ä¾k«¼‹QòZš?ý‚ži ”ßžà)PcÒ.Y@VḀ†ä¼ð ³tsb”5wßv}¥F¥¦É†!h:=j€cMÄèñœ¢R™X»m­Ì[; ˜8c¢|öÍgŽ¢ãÍŒ—x o†À!ý™ðìrÙò³þO:ÿ¥³4þ]cøè@óq>ö r½Ïë-W´½Â옠>t¶ü)Nç Ž,úðF>‘'YÞï-Y6†AãYYre‡+Ã÷!Ü=èô z¦%ÓØëÖªÉÑ]²%ã±h0÷2@aÎâÅ‹çG}%ØãÌÎÈÏ”îâ “4ê9>"hRîèç€JßËŸ¿ì=Ǧ­›dàC©?^ÂÃðh.)5Ÿ9O€t=_` {Ôwã¡æ:ñÞC{KÝ‹ëJ×A]å‘—‘9óçÈþyšþðµK¥}•œ¥n*‚LQ®\è)?ëeº?N< ÃbæÀÑ_ƒTzO¾uÛ­u7–B¯ _Jå§€þa f-LΕʧd¾ü_å©I66Y?ù|§YU}Mõu«V­ÚH7(î¯U«hº~cúɆŸ7xk=þŒ³9‘Ó„ŽvŽz¯„‚JÂ%¬=EðKàÀqŽ“nÿHŽÓŸ úÃÐ?È‚¥ Œâ{Ÿ2ãø.fa}ì*YBª~›‹>u\ÄÈnFw„qÛ*9~¨¦ãéå¼VçÉ¯Îø•<=áiyû›·£ÀjLŒTƒ)PVçÃ"ÔgC;ì¤:ð®7mBX.o‰‹6ê´Kß5äÛƒoQb‘„zóï¡ܳm›þˆ¢Èêñ5Õ6õØ}‡!Ègé¶æ1*˜ŒsÉTˆ)g»´qÛ׬Y³<==½I¥J•–‰ç?}Þ(9˜bŒÝÑÆ!f@í6 jŽÎŸF| þ"9°_»ëü‡Î—C;ôõXöA)]Ùý ŠoþvûŸDûÜ0r÷ •S™ÑߢôŒ6ûtœÜµo—LZ8I&}3ÉQ½K c(v?AO¨ü¨Ÿí!ÄìqõFɪéB.y{´éŠ„£?ô ú¥Ä8u‡Y7ôúÇÒÙEEwºÏZ ‡ÊP1¦h¦$hØÎÑ£G¿ûÈ# ŽbúžÝWï}›%ß®ÿV³ªƒòÂóQ±þƒcÓƒó"-Œ&(_ wd8€>ÂE%¸»¦ŠÂ5>ð‡pÛݧ‰ZéÎÍ^¾A8TV´ê¨‹oýÍM¹ª‡J»u@I•Ô9ízf<2Ý…ù¦ûõµ|ŽþMë4•þúk¡‰^ýA¯”·¡BÏ oлBMÿ5¿9fXvh^Gðí·ßþ°nݺ5ºa‘pcLêÕZo‡EçXÞXIÄQƒBcÉ­tÓHó1=_4¶ODŸJOÌÓ¢æ‘v‘yÍç^Èa¾ÌÃw:ú{Ò™lès8î`ÓP§ø¥Óœïþqñ‡Yb¤+¬¨8|ŸÍWgdõÙòE jéH£Ð(9ã_(¿-¿šÖ󬞑ôzôã?®^i«h oÐ;èj*°ƒ½,ˆ#‹ðX°BÜDw>ùä“o¢áQ¾~º¸ÕÅŽ¢»k#£ô:E2LÃãi0¦cP+ì¦çS~´Ðï ’Ç_F*žŸ¯…å‰êžy½‡M=5æ“\Jf2e³ýy(ˆîÁ(<–¨ uºG”=³óûˤ¼‚–ò¨a¯ ¤+ÞS~Ó0tkÓM:ŸÞ™­Š ¡G#FŒÀFÑ-…ÜäèÏ–Ä-',‘lKO„GåhÖ"h™­ç”\»víʨonï|»˜K"É0Ø52•5ñQÙAŒ3q¦ÇƒÉ¯¼TZÁ ƒv­€!ðÎ`œ\ya}Ï~¶ûåó. ›);iXaÞ_6ã€>¹¥ò§ëO~¾x°$vÐÕ£UªO¸EOFý‚žAß w¨©P®0lᣢAÞ2@Ã;uà µ^ ‰änºè&gBCåWèYO—™ÆºÚLf ØAŒ“ÆÆÇ “0]*í—ÅŸxýÆ4ŸÙx·¿½Q´..²<–cAO>!¯êcä×ÅÝØåÆHú"èêÑëºËlžþsµÂH¬¢ æ cP#؆Ðx³Ýظ`Á‚yQ¿øõi¿–î­ô8¤2Ôc¤/lÒx*‹µÛaÛ±³í´°0i ÃèRø#ÇD}ƒô G¼•ßÛð½'Žù-ú|›~XÂ"Ý’á.­»H×–]QJB½Ñ«÷çC”ØýmÀ$,/Œ °åÂÒ`/Ö ï&:tè;zvY0c¶’Øý±ë¥z¥ê±Ö“ Ä£ºÞ›®¡H²€0^5VñÈbÒì< Ǥ"ÅÎò0¨B¦úÓ€wÓ!Cù”?€Žô¦H¦ºåyòèâ½…jgÕ*U“?_ògSL¢?î™ÿ}÷ÝwßÛJktI!ô ú…Á–£¿ ç kÈ .`±pUØŽ·ß~{Ò®œ]‘v<ÁÈÛºÞæ,Pb˜§Q€éA ü­Š‘Çöñhýiv>;ì§KÅþI†6?ËÏtÀ ¦#Í Ç(,ñv Úù}8o¶jË*h츆]<(²@_&L˜0 ú£%A—àýÓÿCï¾û.ZV(WXÀÊùÈx5á-4œýúë¯ÏY³z͆¨‚í›¶—ËÛ_îÌpDÓÝ %õkï°v@x°%Yϼ„Éæ=ó¤Î_jžââ]nس“Æî Cñ=…eš¿ ä ÂÙx·|SõiØÃA>!¿šÖ«C/éxrG%LìÌÆßšµ^}õU½Á(>ŒFèô‹5j°ð®ÐÀµB`†¹> k…© ¿ãÞ{ï§q›Iw}§ë¥u£ÖFù a´dï<€k`<ÀN@ñðLgœ” d^&“¿ ´v]G{¸ ÏïÏÄ? ã6-pŒkJé)¦/Í(/h‰´ÃV9¦L7ÍÈå ² `XóžÙèL¹¹óÍŠLìÜÛ~ÞsÏ=ã”ÚèŽBèô z…ÒÑ¢"ýµï¨Â…u` XÁY€g6nܸAÃ<òçÂhÈ£}•Æ5›Çµß ³Ó´VÓ¹¨fȉž¸‚xæO Rö±˜§°|´ó“ÄiÜŒøØ4¶p1ýnã¶Ëð‡™®rçÉp®zéîÁŸF5É×<¡DÑ\NnŽ|üñÇ3 /šÃ6ý¡_¨µÈ\¡gh‰5 @ãìY€Ù PÜö1cÆ|¢lŒº@¹#®!µ3k†‚©Æë´Ê@Xuâ\ Nà4/º>CçÏã§)LÜ.;öFàBóÝÏK!ÝÆ‘ž8;nÓ2l§#ä év8Æ}rY³JMùÇuÿ€GrЋիVo|æ™g>Ñ 8óÀµ?Gc†ŠbíÏF‰@an£`íYÖ.x<Ðö?ÿùÏcõõÆ~½Ï\£‰]ÅòeX¿a΋*“iÉÁxg"¤e€%êÑQžGÑ5ŽÐÐù@âò°qÀß'a“ÎM§ˆ! œ6TN WpÌçÆa ’ÇŸr¨²Y½ruyôêGòÅA Ð¥§òCoìµ?ôê@Q*?ÚVd…¹¬à, Æìرã'ý\øýdÞ Ô­ZWîþÝÝRµBÕ¼=2"ÔHœÛ¦“FÚ8 @È|A0JþMžÂñ"ˆ¯6.(q>:{vaúÜO‡8òá‰# ”›a še0]åÏŒ : ¨šVUîîs·œPí„ØÙg!ú ×|ÿ[õW}Áà3_{ôWtѺ"5®u"‹0Ìó\µmâĉß|9çËù8ãÕ5¯Û\îêy—TI«’÷%™#Nq;áhu¤'ÀÔÛ˜ çÙdx‘ ïýåºy©øùú‘ô¬ñ 0pL³!ó»0Fù!k¶ü¹r—Q!Cþò»¿H‹-” šƒ@Þÿ}üÌ÷Võ¶òǼ÷/êÑ-,R€]¶A-a° AZ¶m<ðÀ{zÆys2û­µ2g¨«TT#À%;ÁU~v$Ò Ý¹ A«í¦`¤`ž’I^Ø}ðÕ*½7·ÒL#‡¸¿,;Î<Ò*ôd é”3…ž *áÌŠ™ò§^’¶MÚ*a4g^ù©@4õú½þ@P{±¸"7®• Á.<q)`fß~ÇwüK§<{£ü¬˜Òwv³³eH¯!Rµ’.`ÜN¡@ø;8F@PZȰ'ÞA“rEË?í¸¯&®é }ÉN”ùíD‡°í·i¨f.Γà]ï—5È!äñ®ßÝ%íOno×7 ¹‡üC”JÑSÿ˜#¿Å1úk]Å3Y p€ݪSŸŸî¿ÿþWuóãàž=XæDs˜ Ü×ç>ɪœ³'sc[eÓaÚ‘1›ƒìl@8B'þ×Η ;|+,B¸M%·ail;l"¶ 8;Làà©à¤UèÉ Ò€Wh †5à oºæÇ†ß½ýî•¶M£üwÈ=äz ¥PÈѿاþZ—qE>`Á.«¸!È¥f[ÔoÕ–ã¦ý^àÐþý˜éDsÍOh.õLjWq^Æì`f€¢ÐQ®‡a0Þ~ÍÃW;6Î~“` ƒ'D)œ£ …䃭ÜþpB^C¢èýíÓŽé„À# çâ(+”±ÔTe÷&㈫LÕªRK𨴨}Í9‡¼«Ü¿ùך¡üÐè^ûñ?ô†­Ó`ñ¸b3ÖR‡ñ/Œ˜:uêü·Þzëì„â$”_ Ââõ²êɘÆÈ‰ÇŸ˜×9®â£sb:Ðí\vr ô GX})¼Ñ€ì‚àbøïïö‡ mÏ0ÓŒ‚  ›žùˆWèásù<{ë³Ò°FÃÈ||CÎ!ï*÷ó´4[ùí©?•¿ÈNüi]®Ø j Y `?€kžÍÞ:nܸÏ'}8éK¾DÞ(ïYÿyã?¥õ‰­ð¬´ÛI&îv$-»YÃÙÂ5žÀ°ã)Q¡-|¶FÍ,Ñùy/¾¥Ûü²Ó‰÷ãЯĆý¬8#x¿Oœ )3fä§L©ìœÙäLyîÖç"¿ç‡,ÃPB¾Uο‚¼+ Êoä_!ôzqئþZ—qÅjX‰B°ªf¿àRÀ0áé§Ÿž6mê´o’y3Àò¹ò¹üœË=ëìu$:M;Ì6œÆqä2BA´…ÄŽAkû0º>ÇA¼°y˜ ÿQ–ŸqHñv\ÃF0 /¤“éšÇŒúÀ¹ž2Ô»Coy|Àãšœƒ\OŸ6ý•ó©š“ÊÏ©¿×­>,® ·Gnf—^z).`{1µã…L¸ó—¾ôðáç”+Wî¸sÏ=·næ5Í&G‚?×ýæ:i^¿¹<õï§dÓÏ›œ«ÄaÞй KÒ*Q+[â†Í­³Ã1a@ä§#ã)X0ØÔõÑÜ»v&ü7?kðæµ?½&Ý[w7#¿7€E‡¥GíèÔoFL)„ :W@ò Ó ír…p2|²ù”éìO„éüx¥1Ë?ìc°Ÿ™r 'ù»¶í*oy3iå7?ç¥rãüÊ,:Zk1÷¿k?4¢bP³Òàz4?4âáL“-õ§°°•8¬,ÐÑg§kØŒö(‹xB6@£@¼kÒÓÒåÆ7JçVÑnðEtÜðÓ5ÿ×XÞ*žÊã¾ý¡ü˜úC ‡]ùµNc*Ç%š†«bÇÉ?É]@é¡Õøí×JêÓÕWS_]} ×gõïß¿}Ïž=;ddd”Ò¥¢“w#Þ!¿œè,  ¼XpÒì H†§^ÃÞóGH¶1î¤ÿBœ³äbÉ¿°' K·ñvå0¨Þ›æ3ÍÅ:*>äa8£‚šOA·³ºÉ=ïtðIþÅÇ=xÕ§ºñ™žñŸ­Ù¡üP|*?F(?Fï´Ÿ;SVTt§úJœH·‘ñ°Tê®ýñƒøl*C}Uõ4YÎêÔ©Só[n¹¥{åÊ•KW¨PAQÉ»ió¦Éû_¾/‹×,Î3˜@%c¼U‘õù<#À¿‚ûã¤KÁX@!£8›ŽaBæ×¸éOàmt;ް*¼¡u—}PüSœ*Ÿ}±üúÌ_#gÒn÷îݸÍ÷ Žú§OŸ¾H ðüþ÷ý0;þʯ° ¹¹uÒ숛Çc€¶Úx]¦L\ ß d?øàƒ—gff–­X1Ú'–NÑÎß Ï¸Pà_ŸùºLüj¢lØ®÷- ·F Ž7íÞïQ”æ1´L3d±Ê™‰›€þmIvxöâr,›õ¸qÓÀ!NŽæÀSÁFzůUµ–tk×Mú^ÐÔr9998Þ»Ooô¯¿ä³J á†F~ŒúP~Œü<ìc”_ãGÌ‘žÖ èŸ `9PE=ff °šÎjè/]^¯^½jQ~wPó„ºW>yÅ‚Í?«qöünÜ3,ÅRzO©©Ü„ uÃf¦À¼€@›ÎNK…ó8`+³‹QtRRრ]††½¥ ‚ 1âg¥gI·³»É•^É’ Ý{¶þñoïåèOåÇn¿=í7ƒ`A¦þldagGÌàL%á¾ ÂUïºë®ß´?§ý)Ø,[V=²nÜ'ãdò'ˆm:#€âÃù BR†ùm%·ÃH³ׯ¥Ây ‘&ÐöŸiT|]÷cÄïܦ³ô¿°^á o\å5ûóÙKt§ÿc-ÊåÇ anøåù £üZ.t Ðýb÷ìÖìö¥©¯¬3î xF k×®§]{íµꬠLA–ZfŒƒø`Îòíß:xŸ0J eV³@'Dn;ì”–ú[P@amGŽa æSx*¾ ‘~Ò 'I÷³»K·¶Ýì’ Æ”_Gû/¼ð´I“&-ÔB0Å·•q*¿}ʯÐ#?|Ô•Ÿ£>âÙê1å/å×rþÎ2P;lNb~7˜ p_€³Ì2u&pv÷îÝÛè¾@é´4LŠÆáÍÁ§ó>•E«™³ÞRÀU|¯*·*AÌl,áõòÛ–aãJZ8ìçUZoý¼mGY,aäQ¥Çp6oÔ\Îoy¾\Ôò"P‰ÃwüºÞ?¨7[}­#ÿ-#üvõù¡üP|Äùš'üpÐÇpôÀ#'ú¸Ö§ò¶‹<´ ÆSÀzhÌìÙÏ (?Œ Â0x­˜¦o NéÒ¥K }˜ÍBÝDÔ¤”+‰ÀPzlîék¼ìÉ“'/Ð]ý%ú¬É¡ÔPn®é¡ô4~Å·×ú‡}Ô×vyî˜4xzßlZËÃCöÛÎÌ2@ih‡€¯P£F* hÕ¢E‹z:CHÃò÷¤Œrç(wPz|Ÿi¾Žð¹ ,X«¿Où¿M›6a3ï顸ðPrx(>ö⃖ë|ê9lk}­;г€Ü° –¶!Àl…xcE÷àAÚ uêÔÉÔ‹HZžzê©uõ"’Š:+0—‘à¨qjÏ@9ô wXÓã¨.”^GûCz1GÎâÅ‹;vìÜuëÖaŠ QŸÓy[ám¥ h9âSñ˿֛Ðó€r ½,€AàF¡QnsÔ‡ÒÛž‚t€åõ*²òZnÓ:4®Y³f¦Î Êcf€¯a0CHåÔrPvŒðPx|•çŽô{6nܸã‹/¾X¡ÓûeºÖ‡òÂSñ©ø€¶çl€´ñ¹ÁÇuþaÝäÓú㺔°Øã` ß@Á¡ôöì€Æ8Î0‹€ÇCYUþò;wnئM›ú:S¨‚‚âÊâÎBxÎ`è5oÊ€PpÛCÑ¡ðØÀƒW…߇^Göí_ýõš)S¦¬R”#5×V~Œæ\ës½H”a*}>Å״þɇ:ã¹”àNC`Y³pŸÀ^&Pñi`$lCÀÙËÀž|™–-[ÖÐ%C =kPõøãÏÐ}„ ºtPÛP®Œ†2j¸i™š1(ÔÝu‡TÑñsqT¡èT~¯®ßwÿôÓOÙúŽ~›Né7Í;w“ÒbT†²Ãã<<Øõ©ä€¶‡Ò“ùXÊõF| ÿâm‚;âÀiÆ/ö/Ž3ž!à†¡ýö€FÁ^Øa΂ _Ir‚ÐS|· ¦1ØÎ€¤‹ò´=à ™Í6*$•žJk+>•šSy?-gÌ#Â:ÌξÆáØ'výµ jh« }#PhÉ¿¼*Œ=GqŽêTnB*=!ð #â4&, ÊO€z¢%M9åÎV~*=G|@ŽÜTh[¹m 顸Èòé5èµá£Ö¥ @p×ÑÒPi©Ä4ˆÓ‡¸_ù™Æü,Ï6v½Á-KaýÊx˜òÛ#7•šiTx [áaHJÔh$:Q öXs~!ã¨â7Pbð‡JŽ0 8ÆI:*?¡¢R. Pù ©´µ³aǾe^@Žô¶(úØtØcÙÙB€0†J e¦GÜVrâýÐÎÏ‘_³šå`Ê…s€} „¡°„¶"G ÛùY6!ê8¦Ý±nìΧP2Œt*³½dŠ< q„ÀÓk0®ݱæl‡=;û#7! ð€Ä2âtÀ¥œ)àcˆµ…f+(•š 0 ãLá”KŽì*3 q;a:;L\ ú82>†„Dma²Ã¶bSámŠóÇCªH¡8`óɈӓÜOC| Fà@Â×€ÊH‘¤8âÀQÊN[Òæ§šâ@Š…á@ʆ{©¼)åH€£¼SÍOq 0H€Âp/•7Å£œ)p”w`ªù)†ÿì%´³W¹ IEND®B`‚ic10qT‰PNG  IHDR+ƒ AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs%%IR$ð@IDATxì½ à]WU.~2´IÚ4I“´i:¤SÒÒK)Z¡2Š€>чS‘IÊXð¢ O†>J™dPQfyÈ«ð•–Rè<¦ÍØfn“&Íð_ߺûÛw}Ͻ¿û›‡ûíäܽöšö>ß9¿söZgšuèСJE! „€B@! „€˜ÙÌžÙ«§µB@! „€B@! €€Ú„€B@! „€B@ J ÀFÖ* ! „€B@! „€P@û€B@! „€B@@@ €ØÈZE! „€B@! „€JhB@! „€B@!0(0Y«(„€B@! „€B@ íB@! „€B@! %`#k…€B@! „€B@( }@! „€B@! „À  Àld­¢B@! „€B@%´! „€B@! „€”€¬UB@! „€B@! €ö! „€B@! „€€€°‘µŠB@! „€B@! ”Ð> „€B@! „€B`P`6²VQ! „€B@! „€Ú„€B@! „€B@ J ÀFÖ* ! „€B@! „€P@û€B@! „€B@@@ €ØÈZE! „€B@! „€JhB@! „€B@!0(0Y«(„€B@! „€B@ íB@! „€B@! %`#k…€B@! „€B@( }@! „€B@! „À  Àld­¢B@! „€B@%´! „€B@! „€”€¬UB@! „€B@! €ö! „€B@! „€€€°‘µŠB@! „€B@! ”Ð> „€B@! „€B`P`6²VQ! „€B@! „€Ú„€B@! „€B@ J ÀFÖ* ! „€B@! „€P@û€B@! „€B@@@ €ØÈZE! „€B@! „€JhB@! „€B@!0(0Y«(„€B@! „€B@ íB@! „€B@! %`#k…€B@! „€B@Ì,fÍš5Y]«_! „ÀD# ÞD#®þ„€˜.š.Õ8…€£AàС©q¸›´ÀhÀ“­B`’˜ ýTÃ$ou/„À#0³×áËÆc  £ºB@LJLöêY©‰Àp'£ý¬E?>ûÑé§/é! Æ á§ú ÖûщëÓφë3ú-„€˜Ñ(0£7¯VN.ô3ìbšÙÝ|tãð—,;1^~G0™!0ÃM0ÝëØD¿M:”•Pvã—zM>©Ó¯ê«B@Ì(”˜Q›S+#„@@ ×0¨u%›ìûå59m²…^7þP²¦>ÄB@L½ë&Ž}M|Œ¿<.R/òÉ‹ëÛÄ‹ò&ßQÞ}Ô-„€˜v(0í6™,„@@œ¢!›¥íPíÒáPú¥¼´g»—^/íU ! &ÎÝŽU½dqÌeðÛðÛ°+û+û)õËvì›té“ü~l©«Z!0¥P`Jo Nn“³B­£YÚÅv¤KÃ(ëF÷k½è£´‹í~ôúщ>E ! F‹@?p?:G©Û »ãJ½nëí£¿hß4Ž&Ñå¥òU ! ¦4JLéÍ£Á F iÂ5 ¥MlG:ú‰ün4õ›ä‘G=Ô‘éRm"]ÚDé~t¨«Z!0ú xG¢m"ÇJ>j÷"M]ê¡iÊQÓtôQê—mèÇý?” õT ! & %& zu,„@@ i"ÄdiÛ‘¦qä‘fMÔä•u/hפWÊé;êFº›¼?ÚŠB@LÝ‚Ýn|Ž)ʻѽt£M©Gêòxe´‹5õ©‡6iê•mòYÓÛ¨‡²‰º¢…€㎀ã±:B ¦IRƒZf•ú±iWÖã%‡_öUöe¥u£yÃÑ¥j! „Àx#Ð+ -ee;Ž2ÖEºlSÆš¾Ø.ë‘Êi‡šÇaúF›4õÊ6ù¬éƒí¡ô©§Z!0. |à‹_üâ¸+§B@´øßørÔ6SQ¿MKÊË:ÊÇCÿ½üvÈ-Z4û…/|á)+­qÄÇÏŸ?Åa‡vìܹs—Κ5ëè9sæ,¶ú(3<Üê¶Ìm ŽÕs¬Íc6øìÛH/e›|ÕB@‘"P«h€³C‡íO4ê}Ö>`ËžDï:pàÀkoÛ¿ÿÖx`óý÷ß¿i÷îÝë7Xùð‡?|ûÎ;š. û(ë–txrúh²J¡ÔeM¨©GÚ¤!4Úe¡½óm:”~i¯¶56/•é?výGÞ0ædr ECB`¦ 0Ì€¿62 Øfa!¯¬¡SòئŒmÖä³î‡_êºÍ3žñŒ%zԣηÿ, êOµ@~¥-ÇΞ=ý"3:Âêìž *B@i‚@<.bÈhûq,ÓòjX;Ó ,±Yk³qúé§Wv¼Dó %°z·Õ;<¸Ã’›mÙ`É‚Û,ApÝþç^ùÙÏ~v{²e Œšty›<ÖEÝ’_ÊÙnª»ñÀGáÊ£б/ÈË6x^Êó¥DFµã…@óÑy¼z“_! f,å$¦ÇŠr¢D¶Ywã7ÉÉc [Ð\š|5éÒ®¬]÷/xÁÊóÏ?ÿ‘GuÔy‡~øéÜoÁýrS>Ê&½¸B¯ÀÈ©! úG`¶?ç™ú<«¶cjNØRÕÒ¥K«SN9¥úƒ?ø$ ö™Þ.KÜc ‚õûöí»e×®]?¾òÊ+¿û‘|dCêA6í¦š<¨7éF~©eñB=ÖÐC¡NÉoIÛãd;×ñ\ªd@†E„cˆ€c¦\ AB NRúXoN† Jš5ÍÙ.ëÒ†ròÑnâQΚ:±Î´M2—ÛU© -È?ßnË?î^d“Òe¶,0 ð¢ŠB`â@¢`¾u;ß’¯ÇØr–%buáÂ…ÕSžò,Hì±e‹=np§=np£%®´»¾ñ©O}ê³cŽ:ÒX“¡xQ‡¶‘‡sø<—P‡5tQJy‹Ûú-u³¬<Ï*!¡!„À(˜eÌQ˜ÜÔæ#7CËéþ ËB!WB`HÊÉHƒøNš5ÍØ.kÈÁ+ù½xÔ¶äÕì.ºè¢¿ø‹¿ø ôa“ÈÙdr•›á„$DíjÞ¼y•õÜ*q5,Ö ±°Dš<ÕB@ñD ÎAs±+óN³¶@¼Š‹]±¯¸ìÝ»·²[üÇs˜Ñ÷~#-Xkýß`‰ïþà?ø÷~ô£›L‰`Ô%Í6|QN^¬#uA£4É[’Öo)6Q¯ƒV2 1†€Í熡ݩ:Ýã§Ñ®'"ýqâ1´?‹ñÑš ïø ]^…€o†ðc(ŒNYG‡Z ÆÉL¶QFÛ¡x”£î°ùó?ÿó‡œ|òÉO\°`Á`¯¶ úSóã‚w\:òÈ#+ø îÁ·ƒ/eß®~…€Ó˜xŒôHÖ€É Î+,H0I€Á}÷ÝWÝ{ï½Î‰ÿd3ׯ¹ÌŽÅXj<óiO{ZeË~KVÜm}Þ¼gÏžÞqÇW¼ùÍo¾:Ù (ç鬓—L:tJ;ž£J䣦,Ò䱟\—çg%24"„€1ŸÑŸÄB@LqÊIEárâÒ¬iÆ6jÒÔg;ÖQt_ò?ýÓ?=wõêÕO·`ÿtŸj“¾%Öјܺ€Þ^ðWÙ]•ù÷+øî±`ŒEE! úG€ÇNÜíd]u5d¢€wà Ú+»š_Ù‹=iÐÕ¸»`®õ»ÒŽíX~ùÜsÏ}µÐx”`»%#n3ÿß»ù替ôgög?I.ð3 I®hÇ“ÛåH!‡Œ5åà5–xîV2 "1…€Hè}P B Š‡!àà¤j¤YÓmòšêÈ+uûjã­ûO|âŸnùãlòöscqePùXp%·éƒ‡É©|nZÕB@©…xôÀžý¯ÀH `o”Åï°;®±„Ãׯ¸âŠ/¥¯0pg@>Ò6†}°M‡Ï6kêQÞµV2 +4-°yߨÖßö«QÙO¶ñhפãÇñj*%¦ù<v"az"0‚ Ÿ;V¸‰ŽÁ;u"6‘‡+ô%?¶ý þ«_ýêÓÏ;ï¼gÚÕ÷ÇÚÕýÓ- ?Œ¤ðj>}ܶ[öy%$þd#„€SL¶qç)ÀãL àQƒ‘ó¹Ûî¸ÅîøæüãO_z饷$_­æì5ˆACŽRò#2–&=ÈJ’GûŽZÉ€H–1ÚX €‘í:JL‘[f§û<²ÝOVƒŠÀ$ý1à']ÖØ$àyÀÿÆ7¾ñœ=èA¿kÁù£,à?Í~|*jØ>¯êƒFð¯«ùÆQB@…&áHĤè‘óµ×·Z’á?¯¿þú|ÛÛÞö³ä§[B€=ù¡ÚpGÒ© %„êá! Àèî€Úmm%”hï ¢„À8"0Š y, ÚÁ£¬2Ö´ãsùäÏzîsŸ{Ü…^x‘½ é é ÿá±ã~hܶÏ`ñâźªßhÒB@GsÜ-°cÇŽ|§'n1?XBàæÝ»wÿÛ7¾ñþÝßýÝFóÁžAÿp’íI³¦?´QØ.떴˯î èÌ f+ À¤ìÞSå*œî˜”ͯN'>á(¬›hÊb ºŸ6õjõgœqøk_ûÚÿiúoØsö±ãÁQè¸ß‚[öì/_¾\WöûNzB@!Ð7H àN{î¹''$N1»ì]W[bá‹ïz×»þéÆoÄó è{Õè&Ê»µ#4 ‘Ž` “m¼# =Úd@LDºqøJ4Â2c˜J(0);³“»:ŒaÐtÊ ¾W=ä(Mô¬÷½ï}O;öØcÿÀ®ò?Ìþæl©ýkT¸ŸÝ[¶l™¿‰h+i! „€˜Xð‚-[¶øg ñø€Ýúß÷ìî€ûìî€mÞ¼ùSüÇü/fÈ I´»ÑÔ¥^S›2Ô(ÐAa]Ò.,” (™þm%;0wúïÂZ!0˜ 3ðg Î ‘F]ÒÝÚ~²ŸeWøç_|ñÅ/°«õ¿gùß×1&¾™ÅŠ ø 8! „€˜úàS±ÇsŒ/-›6mÊ ôúâãvþ{ô‰'žøh ²ÿ_°/|æ²Ë.ûÈÕW_[ ¨ã¼Ëàžçf´cb€rcg]ðP¢¬Åió)'¯l“Ÿ?¬D@†D„˜Öè3€ú à´Þmðà ú' ¬ÉC»2Ê{ý{Üã=ëYÏz±½eÿXÐJáý5ÜÒ«üv‡€НQIL! „€Ó<"`WøóËû\•C– ¸Ý¾LðùO~ò“üú׿¾ÓìÈ³Ž €HSkvÛ9d,‘&¯V+PƒcÚ5tÀ`ß €Óî 5ˆfàÏÀ5 cPOšuäÇ@|´Qȧ?ýéKŸñŒg¼ÜÞ¼ÿëvõãDÓ¬gY°`A~ŽA¿ŠB@ACÉ»ÊïËž={úY}¼7à.û"Áÿýìg?{ù—¾ô¥­fyÐL fðùQ}FÒ%?¶A7%a™òL%”˜”Tï˜ØÕé4C À?Þ¤YcmAsª =ý¤i;ëÜsÏ]ðÊW¾ò¥vÕþw,è_•üÂgׂgøq•ÏñÛ]õ$B@!0hØ~Þ°k×®~VÉ€;MÿŸÞóž÷¼ÿ'?ù 21¸ ÒQŽ>†jS'Ö%v­(PƒcÊ7”P`RvR%&vu: è#èÇZ 0G)kòJ~ä“M·6~ÕßnÓŸóîw¿ûÙK—.}®}zï ³¥ý4ÜÚ¿dÉ’jåÊ•>×§"„€B@ôFŸܰaCµ}ûv¿; ·¶KšÍ[·ný»×¼æ5Ÿ°» Á=”¦@ þ# }´QÈoµê|Ê)k¬• h„eJ1•P`RvH%&vu:…ÃÀ?ÿ ô±æÔ'HSŽ:ó.½ôÒÇŸtÒI¯°—gü!£x\é?ú裫ã?^/ðK«B@!0ð"Áõë×WÛ¶më÷΀ýö5«×®]{Ù«_ýê¯YŸ â›’L@'Ò´ÁI£f!]Ö”wÔJt@2eJ v`ȉý”ÙS5!0Cè#ðg@° Ê"Ÿt¯:ûæÈé¾ð…'<ö±ý“ùóç?ÑtCÞ¯ ßî ¨N8áŽEµB@!0Jðeû2€/pµnݺʮô÷JÌÅçvO?ýôO~á _¸×^ôiCu• ª…À(P`àÉtæ"0DðJS ^ä³I€®µ]ÅŸûWõW¯^¼xñ‹ºþóæÍó“ñ±Ç[á%*B@! „€Op¡ æ›7oö;öîÝ[ëó&vìØñ¡—½ìe—ÚWö›ƒùX3€s#ÈÜcžÄ6mŒU+Ô­11wÓÝ5HÔè3€ú `ãŽ1¨Ìqü™ ÀÉŽ‹'Ò3þ/ïøÏŸ?ß3ð'žxbe/âÔÍ£õB@! &TwÝu—=àþûïoÍ¡C‡vÛ]—ï@ÀÏ%ùàÅ6üÈC?‘Û kE‰€ ›ïvð†Ã0|‡£>åtG»þ#]!û»©é˜Úé€1…SΦ+# ü±º ê›jù(¨=ÐOu~¹ß?øÁ?°·ú¿ÑÿÆûøù)?¼Ñ·ý«! „€B`2À…ˆ“O>¹ÂÜ_hú„ .h¤wü‘}5àm/~ñ‹?ecæ\(¾,0FDe" ®&ô`ßT¢—s^§D@\â :J ú0àëÏDx²AMêl÷ª»þ—]vÙSìm»o· þ˜¦¾ø7¡"žB@!0UÀ…‰>‹Ž;î¸wÚç_·víÚ7\|ñÅ_±ñcî„ ‰¶±jàµ@ŸºÑž|¯9ÏS" ‹Ž€¾ òêó¤Ðž\šjðÈgOjòb zöÛßþöGžyæ™ï±ìùIMýâÿcŽ9Ƴê–=oRO! „€S&ðAÜp÷ÝwWå;Lgù)§œò‘Ï}îswÞxã¯~ÃÞ🶘èàª?êÈ—w@õ˜ hš(AÖQ0çS 1%tÃòjQà“‚zúä±&ÎË_þòÕ~ô£ß?wîÜŸk™Ôq;eÈ+=ã_ÇE-! „€B`z € Hœp þŽ€7Vx_@,¸rÖYgýóg?ûÙk¾õ­o½ôòË/¿ÙäñNú1 O¢FÁ<‹Ig4üt$8ÿS" -± %jskeyðï‚N((¨IÇ6ù±fkÒsñˆG,|Å+^ñ~{‰ßã Ÿðë'J{@…ý©Ì|öìßSÅåþý÷W{ØSíÝ¿·ºÿû½>pð@«>t ½ÿþê€ÑûØWá2xÀëˆÖþƒû«øy¦C>7ŠãLwLµÆ¹?¹S ÿ;›ÀuÆUݹsêÓÄYvjo¶ý;ü°Ã«Ù³fW‡Í=Ì_N;wÖÜjÞÜyNÏ›3¯šØüjÞaóªsTóçίŽ8ìˆ=§EOન« F€ïÀÜÆžÿ¯Ö­[×1\¹ð ÿã‘|ä×ßûÞ÷¾ô{ßûÞ½¦„DæPLàÌB5dM?xqÞÆ6ꎢ»: cÀ¨Ùl嵺ƒƒÀþ8ùàääËÇ?þñÿeŸÍy¡eÄÿÎøãÛº .œ 1C×tÿ¡ýÕöû·WÛ÷n¯víÝUÝ·ï>_v?°»Ú½wwµgßžêþ}÷ûƒtL¦Yb ÑøøG[•&uÒi´ïÔΜáêgÃH4N³¢‚h!0óˆ·Sríìïr¸cä[ª:XíÛ¿¯cµ¨ô‚ªáïžö¥aä#¹0ÿðùÕ‚y ª‡/¨Žœw¤'¾Ð飿U-™¿¤:zþÑ *Ó\ØÀ;0×Ù²eKS"`–é<þu¯{ݵ;wîüðsžóœ¿°5eÀ3ö°²†ün ôic¤—Ž=•óBÝ @ˆT:ªÒÖÀuå¾ËªãÒTó9z¶Y“—~êÙílÿÃÞŒûv ªßìŒ8N†K–,o•i€ÀÞ{«-{¶T[ïßZmÛ½­Úuÿ.ôï½ÿÞj÷ý­«z®V®Ó^†‰/K–e‰†:ÙGI‡}ÆÉv`Iöò9¤±„À"0Ü{" Êÿö4—F2ú¬­oGXÕöL}rÊ6 HŒn³¥ 6ä!Ipļ#ª… V‹æÛ÷èm9zÁÑÕ²#–UË,¯p·ÊÔF:°,^¼Ø¸+ ;ïÌ5Ù}á _ø{‡ÀŸØc“Ÿ79N–L Fá‡:.Ô‹¼†³f¶wgøáL·|lÊíŒÏcwlt/Q¾pþÂjéQK«åG-¯–¹¼:náqÕ±G«»š6Þòp!Ë]wÝUÝsÏ=ÕîÝ»k½Û…”ÕÚûþð‡ÿß·¾õ­_wÝu{L!¾(;$ö$ú Qc^–H£ÝÞ­‘ øµÂù£5XÔ˜Ìj:OÄzòÀ=}õêÃþÈ{‰%›fðàÝeØ8ð$ë’Ïàž|¶‘am_>ô¡=ÏNbo´ý¹ñ ~xÎÏ¿©L;÷í¬ÖïZ_mºwSµùÞÍÕ–[ª]{‡´àx„%ñÆÇ¨HcMºµÍjÏ'¢N¤‰Ôo‰Jžô6ôQêöòúÌëÓh<~ÌÉêwüÖHž…À0h†a4~ªÃù{ì9'ìc½¢}¤¹v>–ÂOÔ‹´‡qfxè`Ý Ô‰mOxuȲ<ð-XT³ø˜jÅ¢ÕqGÙxŽ:±Z4¯ñ©=]õ8"pÇw4½À{´íwÿæÍ›ßþ¢½èo@Ÿ ¶(“à¡Í…mce÷€X“†^­Ìô$€Í—kë;ÜÆtŸF»þÃÅ‹úùxDÆ$ÕJ(0I»ÞØvÛGàvÅЋí²fÀ>ƒ}Ð9pÉ%—œ{Áü½éöDãw<ç¿råÊ WÿU&ë·^_ݵý®jó®ÍÕÖ[ó­ûq«#0ιmUÒeÀL>Fï4ö€PÀ‹:ÅÚ”³ÏKðÕ!‹Ó‘ GÓŽº‡N‡ïãñcL•“Üø­¡< é@¿ €ž³ñ¸Ôeµ{ÙSæuá‹ã£NvO½TCÞ¤yùއ`®xц‰¼Œpù¢åÕŠÅ+ªUKVUg/?;EÄø#€»6lØà4õfŸ¼ë‡?üá¾ãïø‰ÉàÇyØÒ‘F;.tOÚ ËLMŒ6V qw’Y;ö ©=~ J(0~{×yî#øgˆkÐl—?øäÕØþž÷¼ç½Ø?-Øç5ÕsþŠ !nßq{µvÇÚêέwVë·®oŸÂÓ–Eœƒ`ã‘ö:èäÁ&Û5{0ƒ¼Cfb&ØOö ÛL§J]N†!,eMnè®[Ýᣛâü‘ø™*'º!VMb!0mè÷o,WšV¶_?5Û"dê僲òj>üQFß¹Ýà?ËÜ-åõ4Û¨›éÀw^êÃmÓûb(xⲫUËVU§}JuÚ’ÓÚŠ7ìjãûR‡‡,QðåW¾ò•/·wàM ÿ¬±•A£€æÂ6ë´7 Y/31  Àèï!ý·ò±¨“qÑT@ €qÙ±&Âi?†-„mN#¨GŸ4j¶Yƒ——Ë.»ì©v;ÿ¥iüZ±çÕüŠ¿½ý¿ÆWcì¸æîkª[¶ÜR­Ý¼¶Ú»o«ƒ´…¤zxäsOˆrw`º¼ý>ëB¾%X:ì RÈýàÞ6qÓR‡þrô¡›'±Y¡ ‚~!²ÉõRqŒ†\—1êGn„€èŽ@ùw8ªI(C©îÝÕa!¬b¿¬á"Òî2éG~¤©yN›ד2òÝ&õE™‡ <ÊiËwà³…§­8­ZsÌšê!Ç>„.Uö5¿#`ÿþý=ض¹ÏxõÅ_üeb,ìEà±62·KmèaAaÝj…ß™”P@ €°kO'Ä×kgOÓý–Î5 NÁ?C¤XƒnZbðO:ßîÿÔ§>õ˜g?ûÙwØa‡=´ ]Üêgý?üð&±x£D`ݽëª;vÜQÝvÏmÕú-v•%mUG¼N¼ü™½¨“hèi 7 ÞMNš5Õr»ÐÇ0¼Ä~ÀàÔ¡ä·´óØÙdûaß”5Ö\§aÍåÛ\sb>Áݪ;! ýþ 2nŽÇÖ JÑ>ÒPÍc(ì³^~–·œx¯‘Gº±N>)s¸ÚøY–x úqÇe^Ã,Ý)°êØUÕéËO÷»ôÅß$cþ³oß>7 h*<ðÀUŸøÄ'žûå/ùn“3àïuW¶pÓ÷iëg9xe¦$”P cçžFãu":.úP dŠ7ûü±bx=J¤ì£æB9³ÿöoÿö•Ë–-{…Ñ_ÌÀíþÇw\uÌ1ǘXe,¸yûÍÕíÛn¯n½ûÖjǽ;òÖäqÃkÛR¨Éã§ÌÇ$ˆz¤£.y°‹üì‡Ég´~¢ û§˜2Öä{½,•F¹É0QæØ©Ûµþºéôí«›ƒ1àçÉÿø’ ! †ƒWZöõ7ɰˆF¨x½|±_×i²MA5õrWA7Ë ùôͶ3ÜÖO¾×ÉG7^æ§¢M»,ƒoü·_X³bMuêÒS«3–ž‘‡/bl¸û7v|60yß¿eË–÷>ÿùϵ‘@€ÉÔ\°ÕA£P^ÒhC ëV+üN÷D€J„ÝyâÈn“Þ‰A«'%&ñ‘÷×GðÏ0(Ö ›–2ø‡ŽýVÏ~éK_zú…^ø÷ö’¿Æ{úO<Ñž \µjä+#ËnÚvSuÛ¶Ûª[7ßZ{S?Ž~¼H[µé ?å¨1ó6z0ÒÔqv æ#|ðâD–öÇ üš,ÈK~×à;­“›¦1Fá$téêQú»Â|\9âùóçûíþÇ|)R{˜àö~\é¿iÃMÕ}{ïk¸¶¥pLÈÇ…´5½dè†>õb;_e7}L£-õ¹·°Íül~l,|£¿÷KÃ$/°ò¸³?û„5­GK=4À°õ[œâ·0R¿0ïh&µÉt‡’B@L4 '´_„?£(ù“{ô1„¿¦u¬ñ {ÊX{7I'òx<óÚä5Y—+ûþ}AÅ ¿Á6Ë ÀXjí`ù´G½pþÂê¬ãϪV/³„€„£*ëׯ÷Çî¿ÿþ?v‡Æ¦ï|ç;¿饗^g˜ˆ4ö&¸G”5|ƒ‡BY«UüN·D€J»ðÄ4G=‘£a*0F@Žƒ›Á?Ã"Ô¤1¶Y#ÀGaàßëªÿ[íªÿ³“®ñçØc­N=õÔ*ßzN꾸mçmÕ;î¬nÚxSµí¾mÁ¹m1à~lH[4±M}luò1 ÐX€»,ñ}ÀM}¹ ƒñjI€˜ Hú¹o¶­f`aÒçë“J”“çuÐA»«^ͨÕŽ.Í9if{JÔœfM‰ÁhB`b˜’“A>Ž5ÀQ޹C·ËßtM¯A'Êч·K=k×ôÒñ–¼ÚØ‚®ËöYɺ°MþÁó ڲ̧¤çþh“dÙ_êí¥ —Vg­<Ë_ xú’Ó1• €G1n»í¶ Ÿl(¸àv7À›L6ÔÝihLÐ5ö‚´'äš2¯§S@ %j;ïD5F2a±)0¨ŽÎgÀŽ&¡.i¶ð£MuÇò¢½è´'>ñ‰ÿlÁýJ“× nó_±bE…€ÊðØ´{SuÇÎ;ªë7^_mÞ¾¹ÐÚÁß¾ÿýƒÆ?k£Ä«ù¾e“.·òìYØ|PLUºÝ?û£Œv©>œD?ɶ%êÂ/ô`Ã1f?î1ý$ŸQ‡bN@›dM<ÚÅq’×SŸJ=êÒžcëa2y"N±&oêYLù·éë(Ö´ã.øêñ÷ÛÔ_WØBæx4ð9l·§Üj·A° ûÈØBœt¡}Ð>Û` ɯîs»½ êûÐG_¢W½²zðÊ{2`å‘S‘°"»!€À¦M›*<PÛF®¸âŠßùЇ>t«Éè7-Ø#ÀGMÚÈÜ…rÒÎ,¦C"@ €ÁNt¼Ù¼Ü‰Õ‰@Á?C¸Xƒæ’¢ÄÞ¿éϱ7ü¿ÂÞðÿ*£i“Wÿi§–Û"úGອ×U×o¾¾ºuã-n„À~΃Øl(ÛT)èŸÍ žÏî§àÛ+×imæÜvÓ¶}våº-·í@É…Ö¸™àZƒŸözå>È¢±µ;dÔqYpÒÐ.ï"¦5²=îÄ®»­év4ÂX;dQW³8¥ :"…€˜|r :ŽCi©ChÌ6 e¶½N§6Öâ˜ÒiÛî¯-ë<EèÜGößòã²CmŸ•ߦeaÔ ÂÕrc¿vPlùÆ»g ÀèC檥žM;•µú´†ýŸe‰iªQÏÛÉæôVšÏƒé‚RoÓöÕÆ­­ÏÜyü™ÕÙÇS=ø˜ÃH¥Op¡Ë­·Þꉀh† jÒFævkƒµÛ”¡®•©œÐƒ}€_übíU‰G GàÁ0äA]Òä±îø›ýœ÷½ï}Ï<á„þ·[w¿ è_½z5úTékúéÆŸVëîYçÁ²±¶5¼ÆÖ°â¡ºÂ?TÐ;·…] Ì™0àÖg;êBæí¬Ô¶wöà³Õhë°¯l’eÁmƒ¯l›‰H}’ͺCŸÔ…MîÛDyâõ»Ñ…ŸnjCñ{Žu(ãq’÷ 6Æ©K¹Óa#z­Û^:… —›=üøXäÙG!cpݱŽI/ò3]ÈbŸ>Ú”Èa­SÔ)ƒwÈè›ÁzG;¼(ú®ccaÛû³¾|À7›è§Ô_u̪ê¼Ï«ºâ¡êjöBàæ›o® (‹á»ݺuoøã?þãO›¬éÝL `Љ´ã×l“FÝQ¦b"@ %:vÔ‰`L•‰¥î˜ˆ­Ý½Á?C˜¦:…–.Å ºh“‡[¸¼}òÉ'Ïç;ßùóæÍûÅr4xÿ%ô¬ L—6®ö¯Ý¾¶ºvݵ՞½{Z/G4äýo[ Ѽ’F@hßj†maCÝg:úq~:ïp&}[ö>¡,x>WN}öA¦F²GËÇA¶ùòšÍ4H,3Ì݈֬TÁ®õõŒæ$1²{éG½™Hû¶‰+¦uS ¦cObù·Ø¡0©,Æ«Ù5èÐõØö°+ù#µ³á›¾1" [¾»Àù©ß¬ƒ6ìñ>’œI¶!£<Óè&IkòY»­…—Ô©ñ èûÈùGVYõêÔ£OÕ]À¹‚wX°_5})`ïÞ½?xÝë^÷{wÜq>#À  lq¶IÇ=312”²nqÓïTK( @m¨ÆT™´*0Q[¼³Ÿ>ƒ†G¨¹Àƒü²Žoú=çMozÓÃÎ?ÿüOÚ>w cYºtiµfͽá?‚Ò…¾nëµÕÏ6^[ݱéö˜[H‹+ûøïK‹¨Ñð匨:è&Ù.Ù°Ç;A·Ø $H>œÙ¦óq%È;í“<ÕüF"é“ÏlTûä×ÔÌ$4ÀH¥ÑŽBÔ fG7Ñt´ôDô1Ú1–öy•µ…À€!àåÖy8C!¶n÷‚å6³Nuô‘B¦Ú˜FÓƒo!XÌZ2óÞ §ï,ƒþ%†W™6ÉG[^çQ¿-·1mÊ0ÊÖ2·ƒKè{Y·~¢‡@êçôãVWçð{WÀÏ¡+• yrÓM7U[·níÐ2¬w]yå•Ïzë[ßú#"øçØ b2mý¨QÀãÛ¤Q×ÊTJ( @m眨ÆT™`*0Q[¼ÞÏ(‚„EúQü—A?ø¾Ø³^rôÑG¿ØÚµp ·¢ŸtÒIÕñÇ?*=øÁ†TWßyuµó¾Ý¯ö—·ø›?`Œàùߺ¡:ÓăÙâ£ûŽ[ûÓs?˜UQ—5l\—¼d ¹M­Ð›Û{?(ÁÖ›ô™d¨:Jðey<‘ ú˜&XéªÓ7ËSPÁúŒ¦ Õÿh|OÛÑb4UÖCãã…€¡ λñT;YáÐ4”Ÿš<ØE§5ðª}yÌïÁO´uºE_Ôe ÿ¤£mÉ‹²xwø¾àh  _Úå[ÿÙŸÕÑh¬[©G{È—¹¤ú…S~¡ú¥“~)B'ºõë×WwÞygã¶Î¡mÛ¶}ÐÞ õvc!¸çÒ-K&°gq¿¤Á«•©’P@ €ÚŽ9Q©2 U`¢¶x«Ÿ?æ0Ô‰5~ðôÇÚƒý$óÛþó˜ÇýÒ—¾ôs‡vXÇ‹þ/^ìoøÇ­ÿ*Íà6ÿ[¶ÜRýìΟù¤ ¯ б¼@ÿC@Ígüyg¼Ó.ë%›(£]鶘e{7lõëdG¦€.÷$§!D }{z,nRoGŒ!¶iÖØO¢ËNŸAœÉÚ8·‰ÇqdáˆÐýPª3Q>l¼f"Z'!0­Ã[|‡Ro’{`ZšxY%õ‰v7½Ì7Ýø·œùÉYnGŸ8fÇ6ÉAŸ6¨I»IÒëÊKn<‰:µc°}2¨rïÏþ§uÈÇ0´øÓ|g_¦jÈgÛ¿óO9¿:ãØ3ôx@ÚÆMÀ—vìØÑ!Æ í=Q¿õïÿþïÛLˆŸ &ô—5|‘:í^“¿V&; €µr¢MÛ‰ê;ö£@Dc|éÁ?CÔ%Ív øÁcÛþÔoÎ_þå_>þÌ3Ïü€ícó¬]+¸âoï¨ñÔh#pý¶ëí6ÿŸU·m¼­ï«ýø[ö¿gÛ*±v¾Ý€É ùR·ÔÇÖw†”¶<ÛÑG‡¬€Ÿ~|mѤ¾¢<ÒÔÇä³ägi¬®›~:tc²!*‚n°/Ur»ݲïl+¶b×ù˜ÐÓqÜóÕñhà¸Þwé¡Zú)ÛÞG²/Ç•u ÿ™oÆN¹ÿý§6hêF=ÐäãpAš5yn¯ðc°­¸çì#ùq¤ij·¶öŸ †Ï®ú»øNz.‡ؘ|Íñkìñ€óªs–ŸãºúéDÀžû¯pG@Y ˽7ÞxãK/¹ä’+LV&Ð6”s°Ï ?mu—AŽ¥¤[Üð;™I%”»âÄ‘Se‚ªÀÄlóQÿwأĠŸü˜˜ó©O}ê] .üŸ-õöïGá/ú[¾|y›)*#põÝWWWÝyUuÏÎ{<Èõ¿OC؃nÔEÀ7äägýRAoò@·›.ã2'ÚzäÓŽmÍàãŸT$cßdB ~ÒMî3Ò rLäb¡ë(s:øˆ²ý.zÑ&Ó}èvøÏÆ"šðIt“@ÇÒ¡[¬G쯦ۤWòRÞdWòb;'’?Ê|,%/ñX]èù‚#z Ì=Ì 2´y{¾Û0€O~ЇÛB¼ä×mÆøèŸ¾¢.õHã)üÐfñ‹«‡Ÿþðê'<CQ)¸þúë+{@Á­*{$àf{$à7í‘€í&DÀÏ‚}.ØSü³‹‘N³¿£LF@ %:vĉ`L•‰¬ã·µ‡üÑ1B¡1ȇŒtYÇ+þÍyÛÛÞö˜sÎ9çolŸê¸åÕªU~åUZlܽ±ºyÛÍÕUw\Uí}`¯®ø{ä‚-âÁ6jð‘è.Wûó3üÖEÔM—[—ò,c žúð.Ò|”v}‚—uÓy‰M»\7ðéËu|î±ýl²#rßmͼ®Q/ŠAcÒ×h[*ýRÜ—-•GQû$sö2B`ú#€ãU¯Òõ8ÑÛÌ]–¶±¯š¬Áå¬ó ]Èk:INž÷i¼ÜFÍùÀ!‰¢.h.nFêZÐïú‰Ÿm™ Hu¯çÿá×åÑiú·°3Ãd¥>ó›_ýâê_¬Î\vfuüB½™›5>¸víÚÈrÚpÝsõÕW?ç-oyË÷ŒQ&â]†|-{ò@£ …u«•~'2 €µo¢5‘j}” ¡‘ɇü#ÜiZü#è‡ÜþXÛ[þßÐô–ÿE‹Uþ:ªãËf>˜åÎ{ï¬n¸ç†êêÛ¯¶3Oû¥zø[ô¿GCØu«ÙŽuN‰€Ìcð\Øf9ûôM:M& ²>˜©Ô æÅû³û­ñ£Ç›H´jOzIYš|tð›tiú%îõª›úè¥?–2ŒSEÁF ëq ÇáAîPÈ•ze›öMüÌ+ÆA~Ǹƒt¨‡>Ê6}”³ö±D>xøÂ?$RÁ|âç~’Útã×nÿOþ©Ë€ÞÇÊ$ü&š¾»%p~»`õÕÙ+ήN^t2¡øz×®]ž°ÛÿK,mÙ²åýv—é;M€«üL°ÆV.“à•‹±24êZ™¨$€JÔv¼‰jLæä6®£±¡Gü3è5h.~Ë¿÷óÞýîwæðÃh9ê¥K—VöÀ’=°íµ»ÖzàÿãÛܾMß&¢ýïÐTÔl“ç€5Èbðu“ƒuòÝ/®ÔÛúC]÷Qò޶;Æ™3]AOþ\/èg[òœyœŽ9ÈR¡o¾©ƒº¦çŒ¶´CÖe;ŒßKÂz&»úLn ØU'{‘Ç:2sY !0àqÀƒÊ!Ö§wŽ_hÓŽ}Ån(ëeרú¨ùHÊä¡O§“~æ#èF±j(^Mõ‘(HíØ“™Wè€ß˜`°a1ØGM>ûþJÛÞ‡½0wœ³âœê”ŧ`mU nìÛ·ïª×¼æ5¿mw ì55üL )ÀÅÐ¯Ý €v\¬™Û¤Q×ÊD$”P ¶ÓMTc¼&­Ã¿ÃE¬·þÁ?ÞX#°GaÀƒ}зüÛ·ZOyêSŸú/D ÃXN:é¤êÄOŒ¬¥ø_÷õÕÕw\Ýî-úe ï1uCàïòpg @ýï[ÇÒ¨™àYªx$À-›hçì”(p¾1Ì~¼DÛ¨Û’.lµ³ŒNŒÉý»œþÑw*5yf¶ˆ&Y×vCË\Cý³øú±ÑOÝÃw?æÃÕ‰c®­ô…€˜ yhÒúZazƒflwô|G=šg^Ðë£I<öÉ6ìN>AGál» Gu À½2„Q—¶Îƒ®ýc2ÀCFïÜ¢G Ì!c°n¤ûÉvñŽ€ÏÿG»Ò—÷‘Ö ²_Xý ÕƒW<¸:uñ©­uð_<€ÇÊbÛ`û¿þë¿þæG>ò‘›MV&â]H`ÇÀ…<Ðà£P§Õ ¿ãP`°sþ&RŒ aÿ øÑ'éXƒÆsÞùÎw>yÍš5ï·`ª¶ïê-ÿ€±UÊÀöœÙL{`‚l¶=€µàÒÛ º­Í r×1÷^ÛVÉ6”Á¾ 1šžé9?%¢ç§þÉwÆl…óá/% p•ö,;¡šïC³ÌC ìÁyÞNr§áÃþÓ?m}<ýYÈé}§¶÷mv¹óÝÿ¾õ¿«ÿºù¿ª_8ÝÇ)€GH1¯¼ë®»ª={öp×À~¸ä×~í×¾~ÖYg½ÊÊL€ ;"ÿìÃÆö sYðQ“}д]+˜Sw Ö¡…À,?hLÂ*ó€< ]׺Ô58FÔ"ð‡Ïxp$]Ö80Ær¿Ý?ñçØóþo´çýÿ0ù³ªU/^\}öÙll—ûýtóO««n»ªÌÛ$Æÿu»Õ?ò±‰ }ü]úߦ5I³ Ò.KA<ÞåVGžÓ.„BÝG‹ f›ï¼˜³¿Ì3=/Ô·Ö‘…ý—:hCÆIZ“œ:”y~è›uµÈö0D-aه⌮}w±®~tSkˆB`J"0Ú¿Ùá·«ï u„9!°M¥cÚ"ªxMÖua«Uʼ]ø}–òhO:ê€FÀÝP{=è!õK{·µ€‡€æ ú!ÍDt"/ûDðΤ@¢së…%ê¤6¿.PÓ ö°yøš‡Wç­iÔµ2‰Ý0Øw(ðÅ/ÖþÈÔ£ þð#2ŠuLx`ùòåóÞÿþ÷zÞ¼y?_Žî˜cŽ©V¯^]²ª½mï¶êšÍ×T?¸åíaq ð’Ú¤¢íüRm[¼”vhC–jÂIG~ ¡‹‰‘Ç [>bèËǃÚlk2³Gñ¾Zd«>¬¸nÒÉm—@˜Ö`%»,£Jô—x^Û:»-È>£B ±þee\t'ÛÃè®3 ‰uúRB`òó¿[„&£,h–>ºøãv‘®¹*üPuÖMz‘Oš5t#Ã5Û¬ém̃oòcðN¿.K>Aûº²Àg¿¥>ù¬=¸/|ó[“§6Ç ŸLd=Œ… €ÂߣÏ|tõЕ­–-XÆUÈú–[n©6oÞܱî齿c ÜoB$š’¶Qd׌ãx"•’]öÅ6b–Dú ÷Ï}Eêö±Ï|uºA:e2 êC§Ô£~®¡c9 yЇz<ÿï>1œdË6ì—úu¿Ô ºàÓæ°9‡U¿ræ¯T¿¼ê—ÑíÀ–M›6U·ÞzkÇú¦[þþïÿþÉŸûÜç6˜Wþc46ï :.ÖÌmÒ¨ke,“J(PÛ¹&ª1U&‘JŒl‹ü3¬‰5‚|û±… ¯ßð†7üü\ð¶¯Ìƒ!Ë‘GYüñ•Ý@ÖÀÕ?Úô£ê‡·ý°ºïþû9ÖS Ž¿­”Û Í¿9ÎÁ/õض×uM'êik¹G×É9}Úcdã£äd@ðëü Ï±Õì O…r¾é7È9†RßýEm—-nÑf?z_É6WQ?ÒY!½dT‰ã/ìã8 Ñ„5óĹu™°A©#! š@(a%ÿݶš“òëc—ž{ÉhÒK§&KëL;ÔQN:cRê[»¦C -fq9B·T¢/Ú2 ‡ y^lSŽPϯħ¾à×ôLíÈ«ÑH à‘ M âgzžì@ßxt!øwl§àŸ6¬Î_X=úŒGW?áá„càêÝ»w{Ÿ ŒÅ0Úûßÿýß¿ÿñ?4~LÄdø†²ËYà ù ÁGAMÚü«$€JpŸšÐz*Lp±ÂJ ³3øg ŽH³F ðmÐ9ðWõW¿goôÿ‹$³ªUýyÿŸnùiõÃÛPmݵ5ð ~=ž´ŸÙ¸ênu;ðv©íI4­ µÙö‚@l´½jÙfIfo‚‡v0ýtu>P؆#ÿûF|ºNòç}{Ç®ÐR¤.­d±;$¬$aÖi-9UÈwü´Ï§<µÖ²Pr7‰H¢lý3¥¨lêÍÍz·Í:àŽÈywwuI^Û:[-! ¦49HãQ"ì«ô©}•¾öê«‹,û(ú4É:윺¦õ\œŒÜÆôèƒôQr  ÚY‰Ÿí³Àäi,Vçut^›Ÿu’o«¬Ĉõ¾ÚèÐþ×ꃞ¿.ƒï“ý!!uáÂôS»‰Ï;Ž]|lõ¨Õ¿\·â<Ó þ\{íµMï8xçw¾ñe/{Ùß& üQ“Æ–šAköy&J;V«†nG‹$€JtìXÁàä{"úêÕ‡½Ðé”õü3tAÝ´ ZlZ˜ÀËþþÜ^ö÷ì²÷eË–UgœqFɈöMÛoª~tת;ï¹Ób¾VðÍßQ6ØfÝŠ›ÛºÞFÀhÿýÊ>È@ƶó’ŒA}®“½!Ðq Ø ô}9ŸIƒduAg?>Xçtøjq[}°ç…õa›º¨kº˜ K)/ÛÔã»¶³ ¡(êê?*õA•Ÿ²+› –,µ…€˜ŒÇß.‚ñ(]ýîËuè°+ô9¶Rí’G]â(c{>ö“t³œgDæŸ.O›ä¼sÀeÁ΃psO9ûaMý|A;†c5e¨Ig½Ä+ÛnWÚ¦vöiaªû?ÉN]qjõˆSQµì,ïÐ~n¼ñÆjË–-«½mÛ¶OØçªßlÿL Ø/l¼¦~#íZm@ €ÁNÔ>¥VÛ³Ô]‚†7¨Kš<ü cÍ«ýḺO®öÑ~ôïçÏŸÿˆ¢k¿åÿä“O.Ù3¾½a÷†êª WU?]ûSÚñI?-€ö@ß^# †ˆA9ù~7@›}€Û1ÈÏ>ÓÍ~ÑoêÛÁ79eh» c‚ý<Þ46—%–¢ÿbÄf”hú(l¼¯–Šë–í,¢ÿä|Ö5;c–m× ¶”ÛÔ‡.ÚuГºm…îÔº…ïîžÆVÒ¸žcÛ…¼ !0òX…ui8<æU4Ž+]ýÇ:^³1÷…Bh" e)ý£ƒá¤”}›êÿû1åµ>ÑŸuƒO걸x°eÀô\ÃJCswÐæñS|®C?¶.³æ´üù{vŒÏ~Zæ­q‚çノë <‚?úaàÛù³S`O[ú²»ÿ<à‡Cô…býÁîöÍ·W·n¼µzØi«.8é‚ê„…'´äò‹ Röò¿jݺuµ5ƬOúÓg\tÑE¿‡GRÁVâyHYÔ±€ýX¸œ‡9ùh“ѹèÁB@ €ÁÚÞ#^Û1 þ™`ðŸëóÏ?ÿ¨?ù“?¹bîܹ'ÆA"@=í´Ó*¼íÐÊ÷׿úößö 嘰øb¶O^p2WÖ) èã”âØÁWô“|ó4å èÇÛü­ûô¶ÙÂ. mèE~jóe|ôŸõ¨†•¼.­fæ…f&£¯–bKäü¬•ÆÚ‘ô±FF=”NÙ_v‘pËí~ˆpºg¿œw]‡~Æ,! NûY[œBð<”Él;ÕŽuÅñ3öÛíxEûRŽci´ÇX ëÇX;ææc-‚zûÇâ~Ò8€S×n®§šÛ»èÒu¢áÇím°ó6…˜%E=køx˜›?ñ~ΖÐK<£¬ÙJ @ÿÞi$p®7;O˜¾Ÿ×͇ûĘÀ?Ø¢?+HFøf8w{BÀtÐ7æWÝ~UuåmWVðã«G¯z´Û ÊϪU«ª ø{ˆ+ÖÝ.d=ü“Ÿüä·ßõ®w=éûßÿ>¾!ˆ» ±ZiÜ þ±åÛ;QK rÚ¦k( ÐJ¿ÃG@ŸÔg{î5]Øð „º¤ÉcÀ:.9ð7þ{Ëÿªg<ãÿ×Nr‹­ËQGUzê©^ú7Håš{®©¾{ëw«»w´¯Ð§ _RÈ£í5xø‡¶¡M=êx;ÙgýØ4ä(1qûÿ$wžéÕ’:eÛã§ðã,Ž£AÎþ òu@?±Mˆj6ÎhtðKÝ_˜¹‹>úmõRÿmê³®1‚VÃ8GàE&B@ÌxœËÕAP8êR¸Êg^Ò.‡óx¢<ÐÑ?}e^ЃŸÌON½Ý¤x´Aíþ“ÌÛ/êqØQN:ê8m¾Èc0N]øqÚ‚ôÈË(ÂHê`‰†¼æ«°g`Ÿk¬æ/¬õK{è@Íü}äÑÕ…g^X=ô¸‡&$£ºï¾ûªÛn»­jx9àŽÏ~ö³¿n_ XkHð‘l¡¦Ç EO Ž‹5s›4êZîÝ6¿¯Ù·1Ý¡íú/êãoh*Ý0¶ÂÃ(‚ûKb  ‚ÿœxík_{þ#ùÈO[`T{Óÿ¢E‹ª³Ï>»3x3ã™ZÖÝ»®úîÚïV·m¾Í×»éª?PA¹ÁL¸°ðz@nº8ãRÓGKÕh—'›&Úu –l½FÛÆ€ÒÁzÔ…&K± :·[®r;ó½ƒÔh”¤Ûj´~kúA§ä×Ú}øñÏ!6u˜:¯ù‹êB÷­_ŒÍ'š]|Š-„€ðPaŒaòxÕϜ֎eqò;¤O[×/ŽHtç‚~kÍö@²cÁ¦vìL6OÍ'G¿6iw`Gôã²ÉàmÞí@ÿî²AÎÀúy]± \8ÔXêAŽx¼µß¯ÒcÛã@pîwUà > Aù¨~àèþ“Žóšµg´éÌÙX_܉`5|±?ô¿}÷öêsW~®ºfå5ÕcNLµjѪÖ8gø/.TsÎ9^¸sç춆Ñb»ÀõuûrÕ3ín€+M`({ðŸu¶jínða‡Bšº-®ýbÎ>Ü$@61p(0p›¼¿Aðà5T¬죅 €9ïxÇ;žtæ™g¾?ñ¬j•%K–Tg5X/•ùÞúïUß¾Án÷·@ÚL R`TH³ö5u¬A¾©L@ž×|´™HpÔ­]Óv©ŸÖÖÁ`:uÁC‰>jm—¶ä‰lëºb‹ {o¦:úm Zzñ—6™—Æ—Û‰Èzi¬Qže`6È©[Ó#³¨{êôð]¸ilÖ&° =ûnÐktL»FàC&B`<åq†C«¯dv«ûì³vŒêñ·„¾í Öóxìã+úÍþƒïxÜl’û*?¹ïr]“ŽËqŽJ} à—|Ô:Ûý$Ü&ù+ƒ|ŒÙ}…à:ùñt>Ú9‚}Ì+0?ðÀ~‚¬)à ô =\éOõìC6Ã8±~©_À”ûK~oÚxSuúª'œû„êWVýJ‰äŒlc;! pýõ×Wö"À¼ŽÆŸ÷K¿ôKŸµOW¿ô’K.ùYÐ"°WqÁ]˜'ãÖ¡P7ªM§=Æyþ£$@ Q½Ð#z c£à¯rÉÁÿ_ÿõ_ÿ¡eDÿ—éàà– žõ_½zunÏtâê»\}ûæoW{öíiĤÿ¶ð¹£ñ ¾óZ2(̆“”¹=l¡fËÖÉÖþ-~K],-_À»FÓâc"•ý&¨P"ßé»-³Á°¯tÑd×Ä‹Ãé&üH»m:¼—üÜnþkcŠràÛqüÎ/|à\f!y£ õ麦ØÒ…]¢=w‘ɃFÀîmÚ›ä›Zû3Ð…bÌä7é¹øÄôgtÛ<ŒÝj³mÕÐ!muòsäü#«ÇŸý„êçûyïc~n¾ùæêî»ï.WõÐúõëßþGôG1hzƒAkôÛði¨ûBu­ôs'€Íõk6Ãmè€á"ÖÒçßæÈ¬ÇÎJwŒ–3ÂÓÁ?£ÖðKº úÑæ]ž°Ïü½ÅÞ’úܰ•+WV§œrJÉž‘íõ÷­¯¾³ö;Õm›ns=OA¾ßÆg¨2¸G‚@1óíèG~Ò¿ž4H¾»‚ë>½üIžGí¨9ŽôB@Ú»¯¤Ç`g'/…ÁŸ]|È>©5ÚÀUÙ®¼þ¢¢–×åáà%Uð‡û@›|Ð(YÞjú/u(³i 4ý?(wå†Ú5ˆœ5”¼É®uÒh­ÜPý7Ù‹'„ÀÌG u¬çõä±vÝð˜çãâ'È~¾(ûaÿ…ŸlGy°s™ñ3>ÔI>ºñ³ žWéÂ6Ùa½Z¾eP í¬go箨'gùª¼ âÕ|ŒÁ.¬›êt@ÀžÆ9ÂE^Éw¬M8xnˆ`Üý´ÆÛêÛdÆo9¶q€4¿ÙŒtåßI3š®ð» €_'‚ .Œ<`|_gówïý÷U_øÑªk¿¶ºpõ…Õ‰GÕÞõlF3¯àB–½ÔºÚ°aC\¹Y¸ðesàì3o ‚ÖF ŒD"øç¼Rß¯Ý PÇC­N”èÄd`9# þýo ¡F€*ý¤=øÿÔ§>uùÂ… ŸjòZÁ'þhk¢×øþ†ïWߺá[­`ÞNÎ8IÖûК”ƒÎÉ꤀ÝOø…®Û%=÷Óúñ-DŸng³öÐiOÚ>…HýD~ÜH>FwÐòá2Ú$¿íÉV³NËÜŒXÉñºÜÆã%¨õâ×d-Ëüý:³ð™Ña“dÝøÁtØ$q¶¡ „€@GÒ£Ó!ޝ~ íâ¯6G(üäcoa ›, Ãr_ÉG–'[ž£J~67;ŽÅÎàÎæc©é±1âc´} IŸ´u9Çk5}ñÍû9àGô=TFã>ÔLdŸIz™Çä@ æñ|ÚØ<Ù€üZ[<*€™œËRЄ‚—äûà,KÀl‘˜Oã9xÀÞ7€GŒï˜$û6ÜP]¿îúêIç>©úå“~¹åkÿb^{øá‡WwÜqGm-q̾°üYÏzÖËL€w €ÆÂeäaNÍ$6õÓÆ¡šÞ ÐFBTJ4¡2€¼Qÿ8ákÿ±žûÿøŸ°Ï¥<*Â{Øa‡U8HÚ³Q‘=#éë·]_}÷öïV[vnñ“#Pãsø8Iú•þÀ󉇵=87eée ?Y7ühÓŸO(L‡z´ÏmÒô5Øil÷uÀ´â6pâV»¤ÝOƒÜYèÏŠÕ)o8•íÐò¡úËœ•lÙ}@²È,ùiØ…J»É>§›Ï¶(! „ÀÄ#`!ØÄwʇ:ŽR/Ö½†›üÕÎ fË㯯ÁW­]ŒÅmB_Ô¥/ºq>ûå¹#ÙÛÒ—Ûš l˱ÖdðG_¥n´O4^؇|¶Í–~x“xäGÚõLcŽë ÚƒyȺ%¬öíw@|Hxp¤€™:þ²A þóKMîÉ ³gRãŠk®¨~|׫Ǯylõàåöõœ©?¸°…y.’<ð@^MûÊÕ¯ÛœxÉïþîï>;3[H†&Põ‹i¨ hoC®$PP­#̨\Èxº#0Œà‡yú‘‹_é·6ë¹GqÄáÿôOÿôÅ2ø·;ª=èA3>øß½wuÅmWT_úñ—<ø÷Ü®Ü#øÝüM—Cw pÁ­ø@UºÀi;É£M™iÙn»n¡O]N„¼¦oLXì?&>àûï}¤6Ç÷×m ¤6.°¼oT°O}áeä{;Åå'8¡îà¡«hƒÞ0¤ª¡Ä±QLýŽ:ãËxër·ñqLª…€“@Çq0O»ñíàØ eš¹«`zM¾JŦc5t²m:*»]:DÐ+‹ÛÒ6©ðøÎóù^‡ó ùylÁG¶M<×…³©4Û¢=ú…œmÔXjüäÃu¨ÛÀã|€ã ÏÜNsït˜[¸-ç#Vû‹‹­Îã‰GÑ¿Ùå¹Nšó€·iÛ¦ê~ðÕ¿Üð/ÕîvªYã溘óÆ‚91æÆ˜#d9of]ì qvU£á6meõÒcŽ_WTk Ðµ¹;W¶ÇÔ(± :šò!Ÿªxàšs ',¸ì²Ë¾jÐSÝKú±ìgµfÍ¿=*òg}Í=×Tߺù[Õî½»['IœHqÒfNàÞ6O˜®ôÀ÷ªm]?éešm€ —¡/ê°æIßkè¦ñ”rßÊôgBÚQ"§ñÒü´ˆ:Ä-uZšmks±Š¼þ¢Z/ÚÐë%®ÉÐ^—š¤hôï²0TS™€@DZj,Wª36ÎÞû:>eípLíá3¨ÛÁ¼Öª7 Mc/÷‘޾Ý6ù£Nôç¼4–]ãgÝ8&ãg_©³Ú1=éÂÖ?¯Ç[ÿAØ#ýj=pŸÐIK¾[IŒ¤Wêø•~“MÖ Wô½+ÞÒ_è:´ãíü¸íãaª”ÁÆïàíÿ¸C%U¹6=|Zð‡·ü°úÙúŸUO:ëIÕC{hKwþâ3gœqFuÓM7U»víÊk8oÞ¼s?þñíâ‹/~òºuëö$¶8 ®þ³€Æ\;ò(‹5ÑÎ<Ìõûy1`61ãÀޤ2 Œcð$ÀÜóÎ;oÑå—_þïMÁ?>ó‡g£fj¹wß½Õ—oþrõ¯×ü«ÿ‘%GŸkÒÆ÷—îØ_£gÒm2ÀŒy´+i¶ýÎøOþ¼m>PÓtãâþ¡ƒ%Éj}¦L}Nï`"€>ð¨‚ÙøÄ€>“Êè5tÝÌØ'|X‰í8·¡<õã¼Â‡…zð]袔²ŸÚú§±´4Ã/†X.AÜDæ~̰ۿ»²ÔÆ$ª£ÿ.º>ÅB``×à(v;î ‡_n~lK›²Ýä£Ô±v>.Û±¾<öóâfÉÏ#´ƒŒ4kbu³^qntãÁ†ö¨½ ]Ž‹vä¥ó-íÑ}ð|}$[ò¡i޳‰çýc~‚¹ü¤¹CÖ í<IºÐ¡ÆBò\?ù®ÑÁî¾=÷UŸùïÏTŸùÙgª{wú¦˜‰?˜óbî‹ `±`ŽŒ¹2æÌÆ/ïàÅ5Ö†2gT@;²f«þß¼áÕÞöæ“¡Ÿëý$è @£ÉšNã„脵qv~«F£õù>¶[:Ùl¼Ñ‚µ-oûËbúô¥1¸˜Ti®~"ÀOd"Šg K¹kÕuèÎûÃ¥ļCÒ'¯u5ĘéVM׃Ž;I ïTe™ûH*‰öª¼Ý3¤­Ä+7mN›*ýgIé7 ziÌQcÜ'ô±3ÑB@L[fܱ¢áxXž{›7dáÓÂ\;­Ì`Xú÷s]R§,Ž)óÈ4Ý/v•t §:oƒA]ðì_ÖßQÉ&d68èeû´˜p9'h]ŒouЖe38oê2{ðÌÏýp—uѵ-8ÿáTgO§µ.E[Ãç.6oøš¹¼Д`ç†ìÀ|›.Dv‹VÂ4gWWßþãêÆõ7T¿ösO™±w ArÎ9çT×^{mµsg;Ù1gΜãÞüæ7ÿÇ¥—^ú«ßùÎw¶±ÈaÞ:–pfùVÈ-#t'@Dc°i%pûwðÿøÇ?~ùK^ò’¯ÙîèïâÅ‹=ûy3þê­_­~rÇOüÉŒ;N–­€ÞÏœNã$à'ET§'BêûùÒôÜÖ†N¤5¡ub-øt[ûÉþMdw÷µûN¾[zÁÎHôé%ùqÎÏ?㿩¿V®EìÀ\òìýuðÌØyÙÞÁ6õÖî¿ÕÙ^Ó§7ÒªÔŠFž8Å>ƒNö×ä+ ƒÁ0Hö= © !0€ÌÈcEÓ1Õø¾®<¶v;.#úl* >kª]üÁ•Æ èº¡—{´q^õsfÒËÛ©°õóXH«×Mzv¶n­7û7.‚ßäWëýÓ}¸U}CÀ~@’o2Ì%Œca£i¡_—c[zŒÃ2δÀÞÛpk¶”cL6ñDË ñ<ðïk„옮có#Âù„;”DZ°pv÷¾=~7Àí§ß^ýæY¿ g3²àBØu×]WíØ±#¯.˜½úÕ¯þ†½àñ_ûÚ×îÉ‚fBI€f\Äí%új¦¨qð«ývôn_ýò“Ÿ|ì ^ð‚¯Û ·2å²dÉ JfÌ0bÝ}ëª+n¸¢º{ÇÝùª?Nhô['Ý6í'Q F9΂¤q‚N4jèº~I‡D& Y×Oð­¾Àãè'ë§¾)Ãfáxö3t›çz.€kt`uòÑjøoë'™Ž3·“ïäÆÙÙRbÛo‡§a!C“z…J«Ùf£(2ÇÂ'eÑïphŸ¼ à瘇áGªB@Lxœà1x¢FîAãDuÖÔO·c¹Íç®c.}%è6WAGN[×M¶¡ØFy;á\GDD;öY{L’?7½»A`m„ý§Oél;m"¾…Ÿ¶È[Ã}bž`þœ‡À¾ÓÞÖ+òÒ9×M‰ÓζÃ5nñ?hÑ>Ç_ð ¹û6yŽq’“þ¯[þ«ºkë]ÕÓîéÕªE«ÐåŒ+xàú믯¶oßž×ÍæŒGÛ´oÌ;÷q_ýêW7gA‹ÀVeTIsd[CePP`€¶üÿúqêþŸúÔ§ÑE]aðÚN3=øÿÞ†ïUß¾áÛ~âçso8‰ù•{Ô‰F2À‘³Êiùh“ø®ohãùzÐô…:·Sh³ʱ{“Žu¤½4è£@N¶[tkY‰rú`í2èd†›øOÍ.±©f¤ižÔj²šX·†ÈVcÝ;)ÙÐè dŽâTб`²˜ñ*}«-„€0pœ˜¬Òí˜9Ôxøù>ècÁx\7ïÐG‰ ê¡gé÷~ï÷þŸÐ4^.K—.õ7ŸfÆ "Öß·¾ºâÆÖUœȨ̀q²D Ï`>¡Æ“^¶‰IЀ‡vè[½³R¤k5t¬ xeÀ}€ sLBiÈS?œdP—m¨À¯ teK”“q.Im÷jןT¢¯Ž<èy?Á†ö‘ŸyÁ1>½ÿ™G¥~ë!N¡eߥ[¿2R2ÕB@#>.MôÂ1¶iH6 oØ”}òø8ŸÁgcßÝl1žR–Æè~d|ŒÃôpN`ßyÝ`Ïq¯µ©ƒ¦ëQ'ùɼ g@[Ÿ?@fA¶÷‰ì?uX—ó™;³ ™Ú(@;nò¨Ç6jîQ‘'zP`6ò8ÿs-ø?Ñ‚ÿ³Ö‚çLþ¿¿þûÕÜø~¢CÀÍ ÝƒïPG¾'ÒÉ4ò]ß¿¬qâô“§ñœ6›Ü 擌m÷ ÀÄAá ‡y÷ û 2ó“È}&>å~š<ðG›¬à’–˜c +éæ&ÇÒÅBFÛ®ü¤ÀuÈú$ºøË“0êõ[‡Sj×>{øq¿=|J$„ÀôG`PŽ ÝŽ›Ǭ”Çýäºì»±Ïh†TÚr¬Á° Ýwð…ó9 ü¸Ì|{²çÅÐÔÜ'Oz0ãøqWÔCaÎàÞmÓüv±?÷^ âÙÆU|$0·ÈãC2¾Ð?Æa]Ã}Ô}ñ.„üh€3Á€õ¥¼½aû†ê¯ÿ㯫§<ä)Õ£Nz\Ϩ‚O6$ŽÄÜÚVô –¸«Ç 0Yšù) Ð'‰J0f"9Á?®øã@ƒz®Ýö¿2]ù¯ÿË–-«Ö¬Y3!­þíÖ«®Z{•ŸØpKƒ{Ÿ 2Þ¶3#ù@ ²¼ pgðN:éçó{”c2`ÿýö9”%>ýòðŸÛÐ-u°Exš02êB”õÓ@ØÎ2'ðcÅü·*tÔ¢½>­¸­ShüÀ£”6¬;&À 6´EM»È‹}×ø£lpò6ÿë7Ê1É\逎 íí×t<÷@´­2rª<—0 Nç/8nì+Ú%èök²qdã¾éËxaÁíô(Ü¢ Î5Ï?Ðã‡~ë¼[ÚüšOÈÜo îa‹ùƒîÖŸûØÒÂD€û7^ è]f;lüê} üaËñ¸ú†.’6OòÚ&ì/?&`ºqü™oC*i$ ¾rõWª­÷m­žö §µÖcý" pÓM7U[¶lÉkeÛhæØxÂç?ÿùø8÷ê* @$T÷…€}Á4=•Æ1øÇ~3ç /<&=ó_»íùòåÕêÕ«§'hCŒúË7¹ºî®kí„f§»ÿŸ½··®ªî{¼/ˆˆ‚@ä­$Æè“Ä´icŒ5OÚØöÞ&¦Wc¢i½½öæk’{oÓ›6&écÛ'6‰6QkHñ+*A#ø?QQ@Œ  €€/wüÆšÿyÆš{­½×ÞgŸsö>ïœç¬=¾Çœk¬µæcíµ÷NÅ{ûó|fh…µø¶²&9ÛŸðó…×øú9?ÙùÍTn[[ÜLöøñŸ×Aæ:²oiô|±Or§qE‘_ðì6}k„ÈeÉ6% 0ã­í 4=ΊP B&sÀ§Ù»¡“Æhù‰Ú ð;¶žE`é™…\ôÂ^»0Î^£‚I¢4«mDGš³m¤Ù7g]z\®·Ò{¥kj¶.c柭ë}]<·s\\b¹” ïB˜7㚑ر¯Þ~zlŠìò7äÇq&™º_ØâÀë2ÉÝg.Š< !ýöÉ3D‡ Fø°?P/à¡°³ß­Zq#ÀŠò=vS‚[ï'k<øÆIÜ·;æ©þèÎÜ ~mÀßpðm.±ßÊÔƒìí#~ €TÝøxÀ#ßp|Ð7|§Ùìš6÷Þoóì'>›QìªÆgìï׿¾ñ#F?ôùÏþùöe?~á…Þb;LdîïÙñz '(•Õz ?.»™ËÄÁ¦&ZÒ1•þ.¿h½óŸ‹ÿ¿øÅeSç ÿvkñÿ¥;¾Ô\põÍ7¾õ [¨Ò»þ6I{QÏuþYýÒî´³ä£ÓúZÙº-ÑÇ6ÉLu4¿ûo:‘Æ×ÆÑLý›¾óÉ>ûvQkƒëi£_WïÊ`yÆöÖ´h_}Ѻâ3FLe˜ùÎh Ü6©´úÉ"JÈî©“”h Ú`…Î6l†0’£¾û@ÞÑê}ÖÛÃûöô^{©¨˜7õš7b­þð”'~ÖƒaÍÉžYOgègñF?3û豉}wìYË’~ËOcr^»>KßÇšôÅóµ>éÒ72X˜>èËž=ÁÄùp=fiÿ uÄpÖBÂÜþü× à%Õý†¹´å/r€Â/>Æ·ß7¹É§ÝÀáŽ½ÑøßÞ1ññÛæc;i.ýÒ¥Í ·ÝÐüÔ÷ýTóØc‹t×4½VÜx˜åÜï³ÔMö—‚¿l³n ïá4è¡.TúÀˆ@½°KóÀ»ÿ\ôºð…Gh³«Ëá©à‡ž·¿ûwÿî±6]`†u~êÇþ5q™þ®iüÊ›\óŽE΋÷ôî¿ß°=…Ï£rmatXÍø÷¢¾åCç‚>ùéè?×c4ý™|šdÀ8žhõ„ËNtö—RîÉÊÖ\`Ëô×e¼´ZbÀN û’X}ŠvXøïÈFe?½}”~V`É,Ç]±Ò55;z./þóÄ2Îá¹HÞÌPâ“æþ™}È&¬ÑFÃÉãKú¶‚»ÈùÁGiK<œ—ü;MN-žÝŽôõx¿?¾ÏôÅío™+ø^òM®Có'Œçß`0Óû­h·BÝ÷Ë}»i`oóûÇÌÖ]Àú‡æ†…oàé&…ÃÄ×Sä6þe¹æOíÖ;nmþû‡ÿ{óŒï}Fó§ý„Ø»’K‡øq‹;7.¸çž{~ü£ýèÆ7Nî178ƒ8P!bY‘#‰œ–ŽjKØ+ü’—…Ù=¨7vϱÌ{²Éâ_?0â~àIOzÒQ¿þë¿þ^›ˆŽÎÂþíÆÏüŸwÝyÍe_þL.îylß‹y/À)Ôm¶´ß,ZþÆ=:·áNx‹wç—Q6ƒ ™ì &Yî'ÑÄSu e³ÁcLšÅÝQk;õ§?ÈZföë<Še÷M_ê–ü£Ñg­—=t{CÀøVð{ŸÉÞó¿ àÆAŽ_ø—ôtòëð€ýÙ½€ ¨©z®c.y¬ßŸ0 PW24|ò„O xt•¶Ö¾i.¼ò}Í÷ÞÙ<ë Ïr›ÝòBNÍñˆ¿@îMþ²—½ìï_vÙewÌØWŠŽ@½ 0#P¢¸ÞØeG}Jñ¯=eÊ¥µyYi4°|çž?öâ‰'þ[¿õ[ï± èXãå¶[¿íÿìkÏn®ºñ*+Â7ÞÙ·•Ë¢d[»Š:Ìr/èmÉ4¿h_ü¸{ž"îÈáŽC¾lŒlûH>íGè'¿­) -OЗÏÄv_Iß k“9.‡iŸJ¹ûÃÆú£uüÂÇŽ–üµÄ?ËMà¶YAH¶IJèKâÔÈE!ãi'àm.å9üŽTmÇwY£Mæ´leÏMùÄËPYH>b®Ÿ¾l nÛpƒÉÄó²Òô\ü¸®A#Ðç ØŸvݵ&Gæ7+<§0#˜ôáÜ98¸uæþéÌ*~þ<˜ÎÚ~½s»SñÉë>Ù|gÿwšç<ñ9.Û-/}¿@N.þ¯ÿõ¿~ÆM7ÝtOÚWlÏ~ëÈ´AkÐmÃÚÒ—‹>ždî‚Ô»à jfÿ\Ìl4¦iÑÂ%íÅÿá‡~è+_ùÊsöìÙs‚ñr;æ˜c&¨ÝÔø¼ÿ{®~Oûy[é(|mÂm ûT³˜y¡o´äD>ºŽ'™ø²É2|„-ëagü š ÃÖ¤;ð\ {GþðÑŠZD}9/éµt׎%'É6ë¶Ž¤îÐý&Øv¨>ýÐgnͼ'ïË<~†–Öy|,¨»Ðx쫚-?õø-?¦ÕcÀf#׃Tx/ì/®Qio|zÑ÷è#Ž6¬ú5-‡ZËرÁ—Ì}ÙX˜{„êâßóh2¼Äw¡h 5ÿ¥#㎺©¬ôê4ùFhÍ |r#ÅC¿ à~ÍãôŸ3,p÷iJ®oc÷è#‰öXú^€Ÿþ¾ŸÞUß @ŽýùϾ¹ýöÛ‰ª7rqËÉÏý…_ø…Ÿ´Ü—Ø|1`º9ýôÓ#kíñÞôÑæ-Ÿ~KóÍo}Ó+~ž†í =¶ÈRdóOá¶\ðÛo”:ø`ÁuØ›~Þ‚?ç´OÃfë>±Köy<—}ÊðåúöâÉÆyç "gÁÅ—0, l€ä×éÄ‹ü,wíôì#;Úy?Nїʨ±i>Æ8`YÔ:F‰:Œuîñ.±ÿÝàJ1ÜI¸âX÷¡F`§"°Õs`¹Flj?{Ö-ùïõ;EÂ.évøÁ¾çi­c}îÍLÀ_–+?HëzÎ[ Sžtý‚—uåCPz%øÊ<¿ o®ÄüI8ý Wd©ü[^å~R®vÛ·5¯ûðëš\ÿÞ¯+“\›œ;6ËÉOý³?û³¿4ž¿QgPy;¹|¹Y$ó›|ÂE„}Œ ym»0õ €]pP·°øçüØû¦7½éŒÃ;ìI1TøÃ›ïþîµÇßwýûšO~é“y±ñ/-`š"ó¢£…Í ë…Ïu™zÓ‹M¶úÏ´œ}'¾ÛÕ>?Q9›5’¥ØŸÓÖ§C)%ý¨ NóÔßÖœgh–‰Ï#z¡uÆ);ÉÓ¸DF(;ù÷ǣ‚¸üb.ß%>Êuw7G™,C)Žyþv‹—Ýr$ë~ÔŒÀV_÷ÿa½Ò;ÕãG4ƒ–Vï#ñzýJ?®9â%·Ù®_ðXÑwdlqôÃû¿ÖÚôÇÿa8»3y ´mzg_0òÜ9Œýµß'`¦>ò¸ñÁ@ ºyIzúÂÇë0Æn¸¯ã¦^Ò¸ ?bz}$À!y•³µãÍ‹ó.?¯¹óÛw6ÿäñÿÄe»á…œûª«®j¾ùÍoæÝyÈCò$rôŸû¹Ÿ{Af#õI€áØp.ïÚÖ8sÿÌÚ8îàÀrÓD¿£ø†7¼á•GqÄSM/·£Ž:ªùžïùžLïäÜ/œÛÿ¼ëŠô|×Ù$!¿ûî6C³ÐHè…<:†w6=E _ÉŸë 3_MzŒÅÜ"ãˆiŽÇþ¤+]ÿK}:?ùw[CôŽbx¾¸F]é'žGòÖUûŠ^Òí°ƒ]æ›Þf‹ÿÁq¤NعڜêsùPfŒssÀ׺±µïÓàºíSo@ÀúF`Öš2zÏl}×ÚT¿¨%UÖlZÔÞ nÈ#]ÏÔwÔ'ç`=Ö_¢Ý§áÊ_D—[ñð¥¾Ü/¾ÂÖy§Ÿ>‘%(Y~ŸÜ)åDÊg¤ãý¤wúý‰JËVc¿àø‡¯þpóŽÏ¾ÃC³[^ȽÉÁc#G'W7ù{| Ìï¡íÀyÞÔfè/6tkÛEàd¨mM#0PükoÊ [¾øåÄ Â?Ã?ýÓ?ým›hþ‘ö°‡5OxÂ"kíq¾ìïò¯\ÞÀiÑòÈ ù¸ˆùâ l/˜ƒ¾ u_ØŠE^¼Y0ä7Ûš~ö—K-†Z8£®x¾ø¥¾·—(ã`Akª7ioá/½¨yî“~ð¥¦3+°²hŠîfŠ^Cý”Peɤ)üw¨øÓ.èXôÁ]²‹u7jj–ͬ KF»†Æµnç=ëãàú5EW6yíMºâûÐdo|ÉyÝ×¾˜žç"¬Ïq÷ŠvÑòÛÉgð•ò"`Î[ 9õéc†y ²c|i,º _™¯\Ì2Yÿtzƒ]é}âºO4o½â­‹±•µ!'\Ý>ªûÛÆË9|ÀË|ßD„|Sm`dæ÷5ljÛ%¨Ø%2ì†.j]¨@.pšdådPN{ÿÛûo/´o÷ÿùÖ¬}eÂÙMïüñŽ/6\}Asû]·ç^‹h»¦Ð¥êÝrôÕ„Ë|ñ°s<@ÙM@ Ð ·mAi†ô z±€55O¢ù Œ¶Çî|ÿÒØõžC>ŒÐëPçýp¥ÖGB7ÆûMBÙå>4줻H‚'Ÿt‘ýæÁ,Ž,2–Å{k-—ÚgOü7;¾Eì—ºO‹  ÚÔÔ¬}¶kY´ŸyמÞ~Š9»ôÙ±)týkMÒÃcmÇOÇWÒ›¿·ãK7÷}”wÉ“ÌuõRðòx,pßžX$eú³|_ßSžà¸É£øÜPàÌI˳lV_àã ´¬o8vŸþâ§›n½¡ù©'ýTó¸cç:ëþB.ÎÇî¼óμ+ö¥Ü?o¹ûW~é—~éu™9Œè© øxxоa-íH}Ù}Pa¸ûöl—ïÑÀ»ÿ\¸Úˆ@Ä9ÖÐûâÛ(þ_þò—?ó¤“Nz©Ér£øç7I™|wC»ô–K›·|ê-¹øw©Y0âdÝyö;Ö<~Ææ¤ã7“QVÞ¹vÝt‡½NŸÆ×MŸŠ-ÌÞG臣&ÿà,¢è”|h¶¼Aýì£8êOöˆÅ오~:¼DLè÷èv>'oÂg!ß 9ïX6Ó¶ô·´>Y²µ”ov`sØkJ8‡‹ªZ#P#P#°–˜w=b½žhźXúìØºø’¾ ûOz}<Ù(÷ð<Ñ6gÀ· Hù‚‹É]’l‚Ÿdð=ÏIPý(÷Ýy€|JyQø8¤çOòøÞwú€çdÉ^>}¬aêó–;ni^û¡×6Ÿ¼é“¦ua¿ÈÉË'ÈÝÉámÿâG”ç«à,Q- ¤>9áÀ²õñJJ¯Atà×`¨uˆŠÀœÅ?«.ú5!Tì&2@IDATtà/ÿò/¿ÝYä³Dù"·omN=õÔæÐCÕÖòMÿç_y¾ÂL¢Z ´ñx.ø‹Å'/r¦£EÇmYt´ð¤M~œ/y©“øq;BnEùfœ®cÝâXòÑw™½D=¡es¬ÄË6ØöØGÊÕòG›2Ø2&Ý,xû§ÞÞ¼ÿKï÷p¬û 9ù©§žÚ£‡v9<¹¼ñ:ù} c-ÀY!œ&\tËm_ûxQ^ñ5ˆ@ýÀ¤8ÄÅ¿Tã…« ¨­wRøéŸþéïzúÓŸþF›0ÑËí”SNiìKF2½ÎÈE_¾°ùøuO &‹žm|n,/X,6Ƴll&w&úq!³Hí¶.oñE/ùÐÑhÕ“ßÔ+#h7wãÑ·GÞlL¼µËâåßïMúmwÈ­Áw„t’ ±¡lmÛH¬ÜføVx$_YfxnÙGæ82.c’» Ÿ­…w´ä—1ãXV—Ké+ŠekÈÏ6v54„ʯبWÒ¼q)så\.çm¬±¶Æ…Gò»C™Ñ—ÖØ &¿>§è’“ ï6I/«36ñÄ´Aúö[Ï+L oÜ7ÔóII p¬pŸÇòkû þ­%N­cÓ·÷ùÛñøcúfì~1¶#½ñº}¿ìøÄ7>MÜ2WÌÁýõƒÛ\Åév@>6ï »´µúiÜf{ÞåïnîùÎÝÍ3ÿVç+®Ú1¬Ù+¹99úµ×^›GnÇã`rù/ùËÿðÌ3ϼ! †"ÊQªé¨X½‰–~É“¬Â5ˆ@ª,Ö`¤uˆÍ”â_Ñá‚ìÛ8ÎÚ(þ…ýfÀŸøÄ£žÿüçŸmÇCŒ—ËqÇ—éuFÎÿâùÍǬø÷ÅV•ƒ¬°>(Ýyö…Š•†è±h¥Íuœ/}ƒ¶0µ„‡M«ßò‘·´møDÇþƒOïÇ^|-tþ†\þ€ôï:i àðiq˸œä\}¢k¤6÷ì}Oþ³,è«٠Σ+›ý6 á}°×gË’ðYãèÛ"<úÙt_Ö19×"ý/jca®­Fà€‹³Órÿ¶÷º]ôz_»¥Ì•vƮ¾lz³µÛ×]¿Ûõ{ÐgÐÕ¾KWÐùIo‚G¶þ·¹Œwè4 vÊc”´º)/I9 ²ö}#CbNrtÚ¾ Ø,÷Iþ‘uÛÊåžkµ2ϯ’¸o)Â÷Ÿ|Ä1¨Ÿ6—kûe}îýÍYŸ;+íðzrtrõØÈåÉéÉíïy¾Ar~me-àGÈä%4–7ø6P“tt*±º8hâ®â6•;†«ÐÎ:k=&€ MAÔKH¹¸EëB‡ÖÅ®‰@pïá‡~ÈŸÿùŸ¿oïÞ½'á@íÑ~tó˜ÇE)w•½ÎF/úm¸¹£Œ¿¶€ßÐóbÖmSa‹ŠéºŸTÌ»/ø-³3Oºv 6>`„5Ý(°â¤eºÀ>2é$‘Ï ÅÔ·1\ÖDbŸÐCºÞМÄlÉîUíõ9i¾ÎЖâ<9¡ÚȰ$«¶`Ý—aÀÛ.>>Û±»µ(Û1/ït8µÎ-œøk Sá Ï¤Kn@Y/!Áô\fåžóBð9.fî:–é ”ß\ðâ{V:Ó¥ öœÄô±Ûcúø|Læ àö(ÏÅ9¿—¶|‡±£oE;¹ë{?xÇ–>ñÏs#øÄÙˆ†çCãI,’¦6ËøZ¾ù¸øº‹›ö?Ð<ç‰Ï1«õn¼awß}÷5·ÞzkÞr{ûIïÿñÜç>÷ù™I¸66±¹ ÀYÀQ³HyŸ†]m»$ÜÚV<SÞýç¢Ô…)Èqצwý3´‰áeö¢6ÜŽ>úèæq{\¦×9ûÚ³½øgAó*ò¶ÄØS^ˆ‡ÇÌXÌà½ø§èG/?r–dá1/î“_·Ç‡ý»ìý1µ ºõo´éùcq¦ã‹z ÇË  ùí:~PÚ±mºÙC›Æãö‰/ž t÷ÛBõÄúXƒ_'ê á,½¥¬ì»”/“¦ÿ¾1¬L661Ú8nˇo•gÃ|[—eƸúªÇ¨žóÛ1/¯Ú1YtÝó|À&ñ¾uwbmF¯GW} æØ«xÎ’r‡k´o˜œ†y 8ùNÊ_S›ãlä,ðÐ!‡.r#×LJû™¤½¯$g Òw\y[âûG.S>Öùã•äÚRžEž¼ä‹—4ÿåƒÿ¥¹ûþ»Ù»µnäîäð±ÙS¾Çrýß1^Îýn‰g®Àýè%ÎF.ºåÚë@’åYÍp°k[á \Xå…­c)YyQ‹Ö;ÿ{_ñŠW<ûØcý¹¸ûGuTsúé§GÖZâ·~ûÖæµŸzmsÕWµ“¼/,$|QŸ-, ü|dí“,¦ï7’žŒd“?F€žd³_xÑ¿« …³è[‡ßM“/³óqÊ_òå¶ö’2ÐlÚ¿{˜4ô}à#lÑ‚»ä}MúYüeÞ¤-ý7&ümˆ¶+û_v'*dò« l!ãÕ4R<¦ÁÕyU@ÀvD@sÃvô5«ƲmÓë`±Oõ‡nhÒÌ9‚éeúɹ´ã<é„Ñä7&wR9‹ržÄ÷\ ñ º>~S.–eÆ“O·“ 9–á9ç(›”¯yGgcžðŸì&øf{Ë7oi~ÿ¢ßon¹ç–­õDÉáÉåc³\ÿgÉùÇ“¿þô¯AÕ%äè³Ñ _´+ð2P«dyEV/õ;Vø;.(]€œMÂu¡RäÇ :Þõó‹ÿWõWàÇ~ìÇÞœôðå¿'j?ÒNèÎYÏ—yë§ßjjz /N>á³PØDîÍÀÄBé{„“6¾¥E ™Ó©°÷…Ðt}A2?.OÅ,-{o¨£k-Ú‹v[É2±aKÉŒíeÛÆ©eŸb;±€KæµCËäÜÈfíçìP±˜Ól´úVû5É]óy6jŒU©F Fà€ÀJÌ—=Ga§ÆUö›Ëï£X¥ø‹µ ú‹xßýTß…ï4#K;×kŸµO]Úˆ iÒ‡L¸Ë"ßD|T€æ0ÈJºü¼?>Ññ`gãtÄéW´ûá£i?û{ Ýø>nÓ;äàCšù#ÿ²Ù÷ð}>Öu}!W]uUsçwÆ]Øÿ|àçþàþàSÆäûÊïài‹ß `Q'By3´ƒC{[§ï°KÃÞV˜¯›míu²3«Jj[ÅL)þ5\Jª¸q,¡…Çâßqó}òÓžö´7$]m!¼oß¾ÉÂÏ¥ëórÍ7®iÞxñ»Å?~qç·,þý‘° ¾ɦ—‹"i›èxGÙkltUüSÈ›n.´ô>KÔ¸‘ä‚*¸Õ—óí†€ß @×pÝI/m I(üùã_Mã‘ñ]'è‰/}ÑCzY> ¡ž~f™mFN,¶¢áW[á¦Ï¸ünÍ.æ!h?û`VªH@@À@âÜ1 ²£lÆ·*mbÝ혯í=|gëì ¿B[és3T|ç%‘óÈuü?å$Øño|÷N¾òœœÇ$Û(ÃÖóì‘[Sßî3ØD?Øè‰€h¯¾eë:–ûyþÇS¶å>á›ñÀ¿³ÿ;Íà›«n½ÊDz®/ÄáÔSOmÃÆNl¹ÿÿ 0ÖDm`< ÑñM¸ øíA2¥¤×béu véèTb5"À­m=" ‹N!£.ÈñÔÖwqï=æ˜cøi·ÛäÐù¹¿}ûö5üžè:·+o»²yû¥oo›ü4±3:®‰º)ÀäŠx_HLß‹ydfƒmÞ‚í\N?©/ïÏüBs” øsZ| 5ô$‹rÉ̳ëe™ 0ÛpÑæÏÇ’`«•äIž’ ééeþX$Œe¬Éfõ”pnÖOi¿U~Ë~zéXô÷*lž©ý‹pó^«‡-uÙÜŸX‡çuW¬»ƒþô:úIž·`ã¼Ìns éd™És>e¸ø@ÏÈ­îyM™o¥ÜE9:à9wK¹˜ç^EN‡ßÒÎõÈå¥üO:‘§±ñ×g4Ÿ¹ù3ó•Ò·Ïþ7ûöíëŒÉö•àÔ&ÐGÊzAuÐ"ßÙð'žp`mknm+)wÐâE/L]¬ÈÁ¹˜Åíø«_ýê7ìÙ³çq—ù¹¿G>ò‘‘µvø·^Ñœ}ÙÙyÁ‰“½&t¦¬ÌOE½¿«Î“î #'z¾@ØB!ÛÒŽ£Ã 4ýä›ÑG¡ƒš/Bà-é~}¬Æóñ9‘Æ.½¤ë6à¢AMGþs :ðHÖ&ô _Ùv,²Yû±ýzì˲›’Ùeûéo ‹~íS„3ÇSjjjz"çðui«>Ö‰uyÞÀëð ?å J˜›¡Êƒœ‡yù’ÿ§\%å'ÎG9é‘ã8žô…ã#áð£®çXQÇì'˜Æ}ßs·øFM,ö“¾ÆŽ¯l+Yò ÿ/>öÍ%s‰ïöº¾Û“ãÇf5À±V ü¹ñ¼.H°¬ íˆäZ\´¡ŽCO´)5Ì„neì\¸ûSÛ E`àÂÑ…§‹-ÒºHáq1ë"Ž6øÞ×½îuÿïa‡öƒqwwÃÏý]zË¥ÍyWž—#E NòLU<¦EPº‰ E ‚ɲ ¾L'O†ò%zè{?ö-Æá_²—ô|\­¢/¢žŒàÎô`C;nÉ2á?ÉÁs3[oÉÇ?32V¯´ë¡{ÇÓ£çûÐÃ_”µlŒc+|ÎÜ¿-Èwd?fîhU¨¨X·Ô¹¤=bËŒÃ(_iMŸe§¬´gÍ×çö [ø6Z²s†øð¢?pd}LAÏû 5ždžWYß‚Î7tÅsý@d?!àŸÏ§ò2dÆÃèúö¹}rúÂý;‡5õÓR0ZÌ}iÇø*€ƒµ#ìÚAÍ›?ñææþ§ÜßüЉ?”M× éûy@«~Àj‚ó¾ð?¥ýÙØq…¦…}?Ž~ŽFÇžZf¾ ïÅ„¤KãÚãÞÕ9Š7.B6h¶ˆC{áüßù`w_`xn|KèºÿÜß§oþt.þ)B™ø)ÄõÎ>´oeñ^z×ß ýp÷—©ø÷…Ä¢*" î‘6Ü ßÀcÁðúŧüt>´tO|ÁYïú{Ÿù(b®eÛ‘%~Tu¼ä—ô„Á0Cû8¬±!ñƒÜ4¶þ–ísêN²\j›ª8[ȸ˿ÙVU£F F F`#å"zC£b;yÖÙ‰ñëû ¯!½À—-Ð[’9ßrÅ’ÏaBÎs”N®b&²Í¾ñ“ø@å[’wxäqzã…Ü*Ò Çüd@‘ vdØØG7áåÜÑxyñ_6»éc¡]'¹~ùËÔ¿û»¿û“¶¹V0\õDYSØÑ úÞ$ƒ_²VÃ^jš,¯ÈÎF€ƒXÛ D`àB)/(]hŒX °oËO<ûÙÏ>åû¾ïûþÀô²?>ïÏ7þ¯s»øæ‹›÷|ö=íDÍ$OAÏÄ‚8g\†i‚7]¢’åÉO¦Ã"‚þyéä>C¿™göØù|'ÆcŒð5ÖŒƒÐ’L¸³ð]lRàwTK{l wQîã.ûœb@"¹¬¶ì¤tÙþ¦î§ þM†CcœÚgÖÔÐÐ<1 ÐAš±óÄn§Û¼ëng¼Åz?áK¹€`2Î9Gà˶”9ô<×!Gà_9ùtÛD{>…~ÐñÜ yØ:<ò“ÉV¸úp:=ö/Ç.÷‹_ò@Ý€6ŸÞ‡x‰ö›iï¼øÍGnüH'¤ëFó?ô¡í û‰O|âùÙŸýÙS™kÃûj x- -¹–H¯ð:m ¶éèTbg"P?°3qŸ§×x‘ bäÅ Øñã?þ0»¸ßf\çX—Ÿ šg@« ûñ¿ùxó¾Ï½Ï_k429D‡&=Ñ–y¿ðÅC±ˆÚ&½˜/é‘~r)t<_2èûÏéw^z´_|ÿq:\“_Ñ9§%àzK+iõ’?Ïጟs.ÚãÿøöÆøí'iä“>#ϼøÌæý4?ú]?ê²u|Ù·o_så•Wæ¡ÛñÙko¾õ¢‹.zÚ×¾öµ{LÀŽ+šÒƒ&8u° rÉ„k[ƒpkÛá Ü!ãbÓÆ9V¢u!Âc›(üoï+_ùÊ?·;›ÇŸ:î¸ã2½nïü«øgqñ»´;8¹E† Íïhtw|%s]Ùñ®½l r²-|ó/ÚH'Cœì€4ÇùbJ…¤ç(cí0˜qÛ;ÚÈs 6âùX£h ŎлÈHø„¯’5ä«Ô›E/ËϬ~úäô=wÿZBËe´¯ƒžúìQ©¬ˆ€®Ñí€+°»ä8¶«Ò” ,²ç}(ò€A_E®€ž·ÀŸ°•JÊÐ÷1]r5÷—øWž•ò.×G'ÑÓ8"/æ`ñ# þd(O¹žòÃhçû¢~õA³ž8ûÓg¯õ“GydsÊ)§è8´M­`ÄЯPc¨Þr”µé€ŠvÚ@ÓÑ©ÄöG ó®ðöw_{¸0Ê )Òñ⋤pÝ Økßòùû¢'Ç(Sø¯ó»ÿ|æÿ‚+/ðÅ Oò6A³øDÎâÀÂÏ”è<É46ñ³köë»Ã Ÿ|Q3ˆhtÕÄÇT ×!Ÿ`ŒI˜íŸ|Ãû þäèvèÒä_tËÝègŠNRÍ /ÑéŒ-kNGúüL·è—.ËO¿÷aîNô›ßÉV•ôD`'ŽUÏ0*«F F F`Û# bæúQä&k½q^G˜餄#Ï»Æg n«wò1I|Ô:nc|r#xüùøÉaзþ÷?h_â§¼Çxè ïüä¹÷‡=_˜r ×;ÈÞÊ·vðƒfc¸÷múYFº† ãâËš‘ÙM üËCÓ#|àAû<ºzg~òL—ýðI?LWk×N8á„æî»ïnn¹å–ö±"×òmÿç_y~¾Lâà2:.㣴-çÛdî<ÄIÆŸqœÁ7€~öm(|-ZÙÆØÒwóå‹‹@šëš½x¾¢Ë\‰ïÔ²nwíè¸j°éØá>aöèH7¬Ÿ˜>ÃK~´éÃçÕïóoY~†ü÷ñ·³Ï™ [ßט·±]ã0Õ¡×Ô¬P¶jÞÚŒß^۴ή+&Ÿ&Ë©Æø©Äs?ò'>Ç,Ú&¼´!OÊã0ÊÄ'ßÊ7!ÈÁR±î7¸‘ ÇþÛ´ªÍÇŒç-H¹™ü´ß|ßê¯Ø;1¤ö'W´ô?õë¹ùŸ5é{îgôÛ?ùv¿©ð·OüÛ._·—ÓN;­ùö·¿ÝÜqÇyèvcà_Yíð‘W¼âúÆCEqlÒ‘Ñv7Ò p‘ö/¬7¤­åtù™‡~²ÉIL´MÎZˆ³±p-vª²F F F E€¹myÍP[tív—Ám¯Ÿ"§@Çõ »ÌgIýÉÈ;óÞL/ò±ƒöœ¼È±"îD>¨|.ùp}ñ ꣞ &ßèxŽh6±ÿÒ–›ô÷¶O¼­ùôß|ºÿ¾R~øáqäQ;<å)O9Ú˜^O䩯°À8 M4°ÜŒå<`m+tå­àÈvùÞýg¯uE\<]pÐàåêŸßùÍßüÍ·ØÄyÔN:é¤nq(ÁÀ+n»¢9çòsº…¼M¾yRf‚×BaQQ‘Ï"© ]“}\`:öZ’ËXRÄåŸþ¯þ Sÿâ·*z~8']Ge“ø‘çc„‘šèœŒ˜Ÿ²å1HУ#Q ³_Lø)•§ÐÑϵ©¢eø˜ÚAÒ—þ{©¨Š}Á¥:ß"gŠÉ,¸EÝW·555;æ¿um›YÇ=çI;>è§È/Ð#¿ñ òçã+é‹ï,ÙÁM€˜[¡/ŸÙ^(ÔŸh÷o¹Zæ‰/Ú€‹fŒ†{¾È›Eâ)ðÃw¸ ~ÜÒM€7}ìMÍ¥7_Ê.­]#^'žxbgÜÆ;ì¥/}é[ŒI}¡ï Žõ†ŽvÊýˆ‡¿ˆCç6¥öÉ:ÙžÔlOœ;½ \º`€´Hs‘éB‹¢.È _ÿú×ÿΡ‡zš{H/ÿëú¥WãêæìÏœ÷^°GC±HÁgzÊr˜&õRW‹E'¢ø¢µ¥#ᾞm eSâ&òÇÚŒÏK"á>àƒ'žÃx4xÐ1épžÉà9Ÿ~zZö‡l@§ÇÌYê/ö5¤;Ä—!ùþ2|Œé­î‹bÕÛVÇ`Õ÷¿Ž¯F F F`(Û1?n¶Qö)Èk9ƘõIy„–²ÂÎûîÑ!žy\Ø&ïSú)虇o¾¡¹åNNë!s -ú#ÿ‚oÐ?€xô«–äNF†|*3yÐþì;,Ÿd?¬äwS_ÔÓ@°±¿7~äÍ¡O=´yÂqOpýuz¡6¸÷Þ{›o¼1ÛjˆSÏ8ãŒÿð‚¼à7I¤bT³^â+2Šh:’!H…=5Pý(@ ãÎà:p;Ó{íUHÓšH¿ptl€ÈÙ(ô¡ã¦âï¿ÿ÷ÿþï?âøßLžÛÑGÝœ|òÉ™^'䆻nhÞ~ÉÛÛ Þ&æ|GVwaÇ„íï°§â_ï¶éEÝ$@W8~2Ž£¥ëÐ^;.]`ÂÅjëøHw8zù0[Ö3fg± J²Í¬®‹ÌB´PǾ†t‡øò1$Ã_†±ýlU_$3ÚÆŒe;tØ×¡¿íè¿öQ#P#P#°n`ÎÜmmá5>ä1ßèø :ÄÍeð_vÙ&ðçNn…a²Ïü”“¹¯"?SY7ådÐYܶNÎ'yÐ'³öÒúϺéþè =÷Ÿü‚ÿé‡ÿ´ùâ7¿¨]Z+HpÌ1 ƒþ™—½ìe?a;¢§†êt´¼.a¿©OàÅVÒQVñŠª¶mŒÀÀ»ÿŒ@‘ < .*áÀ\üÿàþàÑßÿýßÏ·wæö°‡=¬9ýôÓ3½NÈ­÷ÞÚ¼ù’7û^3ñô>Y/Xüû:ӳ䅢Üÿû‹ÙKHó…C¶ÀÔÜ/xbù‚bòÌ/õ-}‘ÀŽ þ6º‰jƒ8IŽúTš!Øl¢¤âtF7›oU?*øýŒMrqÚ¿.î±ZÖÔÔXÐü¹.{m™Ã\Ck½®‹ü¢“{hQßxY'ñÕw?»9“çuÌÞm€–«‰öâ[ú)‡“L0èÆÈ¸éæÂ»dëãt²î”›17}݇_×Ü|ÏÍÚ¥µ‚üãj†Øžüä'ÿÞÿðk¼¡›aÕ$˜‚ÓàÇÍ™ñeJ-Õ*¾…8h§’×<láÎqm¡ŒQ[ŠÎÀ _^$\@âéÂTÁä‚ÌÛÛÞö¶³í±ÇÅ>á O˜¸ £|•ñWêÕÍíwÝÞNøiò%*>Ù¦¢™Éš)Ç'rSÐcÿyâN‹„ÑŒô˜è5ÙãËp|wxÉÎùI'/DI–iú…g $²sžd ¶Š¦il îË Ú—> …âsÂÏ(ËV©Ó¦£T—åY~â wj¾ŒcØ |+b¹ûQû¬¨¨ˆØ©¹mý.êÿ1?¡ï{"ðt|ÂT: úš)ž)»맦5µe›ô܆.ðŸ ïC¢yD_|X—>:þø~¡çúؤ-û ´|JÈÇ"ßû‚O?´þŽ<ìÈæ¥ÏxisÄÞ#´‹kïºë®æÊ+¯ìŒ÷¾ûîû³ŸýìÿŘ÷›ý>b£Çÿãfçh9Ï€ãâAç¶“°š,c;?W·³Ã¾(,kÛ†Œ,þ©"µqlØ ±øïà¯yÍkþŸ²øÿ®ïú®µ-þϼæÌâß j¿lQ(‹/Ü-2^¸[˜–Vü§DžBY7Dw ýR¸óµ¬žŠzAô²=Ê©eyf0c2_n´> éHŒq–7Fš¢VŽiÓQªËðeøÑ€•L¬Ê¤­q- *^Óà²úª~jjjV!šïVa,Û=r€…ò€6ÅñáúN‚Þxf™é(?Á˜K)_’]Ì9>•¦}t_ÆÇÎõ,O+¡ç˜¡ïøRÔÍïö'_ÊÐ¥}ç½w6ÿõ¯ÿ«y[¿vä‘G6yÌc:·Úâ±Vcüš1;uGAS£¤è+*ÊvÝ2mÎÐË@m$q…[Zm;.†ØtñÀÓÅ‹Z[ç"|ÉK^òÇüÿnòÜø,OùÍžY¸âÈYלÕ\uãU>U0akbö 6LèyR†Ç“:ú|›lÒcº9˜°/ClLæ¼D‹ç|ñp€^€Ù&ð’R{¯SúVû]ªåÁ#ýêÞhÒób3ð²M’{_Aî÷ fÑÍÒ™"/Ç´_¥­Šì’?––ý²ÆØñçÁñ2%vc÷c+ôâ¾ôá[Ñgõ¹¹k­Æ¯Æ¯žË=ʹ¯Æ7ä&}kKÞ?È:¹‰ôƒ®ftþÖÿDËGÖÃFù™YÓùùý‰'¨œÌöâtÒ¾²daó§DÍ­x9—Œý¢¯²-ÞøÁþæoÜܼé²7i(kýèGO|€Õ/ Ö°éÔF«."ãÀ°AÓ€íÁrÒ_JzCR±m׶Řr‡K‹ #‰Ž. ›nøEø¨G=êð§?ýé¯1~¾ Ž8∆Ïò¬cûŸ×üÏæÊ¯ô VSßë7B$4kj t^ÒõEB‘‹àH¢—èÉÀc ¾€ C3È»ø—,s-rw™¾EÖt'<é´ ÉÏõ¡­y¿3qÍÙð‘íç´«¾¨ÿEí4®ÍÚËà\þì°®J›kÜ«2è:Ž-ŠÀ*ωËÛÂ~,à†ˆ·”Sdzìñ˜åC¹ŠÖIéÃ7ž^Kxޤ1x>…änÒ:rr±$÷Çð0|D·æzô•xä‡ÎKrç»fz1þkŠ‹±=‡”ØõÇF¼NìÍgWÒ¿ø‹{.ûÜ'>7qÖPC\~ùåÍÝwß­AdµÆkßò–·<õæ›o†IôÙ¨E„‰6èhpbC¯Ó¨‘vò£Á@„Ö´ËÛ»«Å?„6$\ãqhm^ü½÷ÿð_gÅñ‘†çÆÝ»ulç^wnsÅWäâ_E½¿óÏÏùY OOøDl<§/}‡èòGqoQëÈ_<¢œmÌÎ[à¹<õÌuñᣱÁ,™¶ì–Pñî<ùv'¨'дd•l/¹úpƒq/øˆ>ÇY×Â÷¢þµct›é·Ü;ù5ž¸Ô•޶Žcø6t]»¨¨¨X©Ä9°ÄWj [4ÏC–仓oŒôI>¤Ü“^!oAî:O>dïû•t¤!¸÷MŸääWü'¾xN—¼¤?¡ ¿O–øÊ=]Çx9÷ÄÏ—¢÷É/|²yûgí—¬Ö°•µ„íïC©9lWxãXuˆêAŽ´pAcuxй ÔJY^‘åG€ƒTÛöF@éxë"›€ÿù?ÿçfïö?Å=¤.Xû@¿ÉÝÈuÙÞ{ý{›K¾|IwB/'XÑLô‰‰Ýäyò¶‚O-þËE¿üËöüKOÐWÒ“ КëÒ7º‰'éµ>“ÈËxB²=të¾T™Jk $E[Õõ­Dm‘qmÆ6ö'?£öa‡Šþ8Fáq*^#P#P#°[" 9n¸[ö}UöCyCÏØÜ#èõæ.AŽo× ¼Hk –Ee=É]Fn–|䜼Mù˜r7x‰eò‘¡ô‚®ËÈã¢L¸øýcâ—7’Þ__ó×Í»®~×Úä㪨%Ê›ÔÔþ‰š$ðTüÇz†ƒ¦#.\´‰jÛ‰ÔlaÔGÜÑÒ…À(„¹¸tñ”7ö>íiO{”=¢ó›©uÔQ _ü·níÃ7~¸ùøuo v¼‘§mD$OĉöȤdrîDM;¯é‡H¦Íx’ë#¡féY<¿ €Þ…Ÿ½°9|ïáÍŸúã.Z—jŠo}ë[ÍwÜ‘‡lµÇ¿³äýüàù½C"ÄF.š(¢ðÀi’·Tx­ÁؔӼ¶-ˆÀ@ñ¯‹A‚h•¬À/ßq{ñ‹_ü§6é¢aó(Ò¾}ûD® ¼äë—4¸æí]V&QÛS&ÓÞ»®6‰zÁo{׫ƒlå+Ùä/wN:LEÄOÓ”÷ ?é#s麰åù„Ÿæ5éH?Òn’ü‚÷6ºm»nÅï5˜dªÏ¼øMªlг¨ßÍØ-j«Å^âõÂrùêUÚÁ§IÜ}i2†æ_“²Aè©ÅÐWŸÔ}“¯iÅ>æ‹&Û–êyMz.tzÉR ”.–òeÐøž·-:žEíâøFù؆¢_ãŒc\W\û²l¸®ñ¨ã®¨¨˜æËujžW3Mi¹M‘¿LÈñ\fyÉK´äñ&9˜»Iùœë è²!ÜŒ&n$e¾)_Ê÷šnþ)@Ã;:}2å¥èÚö濹¹ú¶«}ìëòBmA›Õ §Q‹¯SŸk[¬mÄ3¶Ë" ¯¶mŒ@ýÀ{ĬxÒÇ‹c¢à·áå ì9ÏyÎiv!rÑåvì±Ç6'œpB¦×9ÿêóóD‹û Už>ˆ"“`g²•®"u ×"Й~äÇ&bbüå)HöògPsI×a´µ!F¾ð Ï[¢Á3¯•t^}âÐÿ@òÑésÀöý-b·ˆÍfÆ8k¢\FÞ²ðE÷{Yý/âgǼÈ~V›ŠÀVͳ›òKž¾õ~063ôzÇ@.C*”rš‰~¢Oé` {$…<Û‹o9Øã_ý ú~$Ÿä‘ú¸€pòCç‘÷ñ¨¿tÌÆeD’¹¿€ókjÙãÆŸÆo¨ß´0»n™Ø½ã²w4¿ñôßùZ@jŒ»îº«¹í¶Ûòx©E¬&9ï­o}ëŒÉjË: OÀˆŽ>€¨ XÑêGŠ€lÉ©m‰(þ9ùµÑ›pŨM 4Å¿àžg?ûÙ¯O´¦yÈCÒœvÚiޝÓ˙לÙÜ~×ííÝSîê.)0ýù—«€KÞK¹MêÆÊŸëw_ò ±r¿(;Yû×’-N‡6LYðµÐ¸NšÆ2ÞG÷MuÉWgÚD¯góů‡ßé³G._Cö’ÁEìµYÄnhÜ}|ü{~T§¼L‰céW>KùNÓ×4¸Óc¬ý÷_ó5.5.õØçóïº˱¹Fg?YfÓzÚgO&9ÐuJ›Dg™Ñòåö¢ ºQ/ã!'”Ždž"·œ^Þ’¯L›ÌŸŽÉ³mÐÍ<ӻ囷4qÙ_°WkÕ¨5¨9B;8Õ$z“Rµ Z8&~›\·:à¢]‰—Z*Ë+²ùè lÞSõ0Ü:Á# ® "Bp]T_÷º×ý{öì9>vrâ‰'æGÙ#•ñw}á]Ígoül;±2¹ÆIÔèΣXöNžl{t]–øL!ЂyòFž|g™#)‹´üKÖIÏýš:'hæÕaÖo©Ü¿H‡IUuݧš·^ñVödmûDÍ5 µ‰ñ:õŠÑÔ0±¦áŠ×fhÆáÕ¶¨Xb°GܱŠA¼t±è"ŠôÞç=ïyä#ùœ8T£¶ujç}ñ¼æ37|Æ'D¿äm/ý1{› E3Yæ©£/BŠŒd݆@Äè‚GÚôôH?ª~MO²4™¶Ê‰~ÿA<†ëô€ÙÂg¡÷þ‰vMWæ0ÛŠË8šû-dþ ¹È>[ɦÁEì¶ËfÚ¸%=–Å>>GûÓ– wºÿ%ïNuW#P#P#°«#°söfûZÈžœ©øèÀT?äkmêÔ÷`ïvä@q=F.Fâ“‹m° ÇF~‚¾ì\ßÝn8&WÜ¿c ¹oF¥1­ù£ýæ—| ™ëÊ.’ž+ïÏóˆQÒÅŸçnì‡Ù~ìÚ5‡ì9¤yÖ÷<Ë]¬Ã 5¸å–[òp©M¬FyÛßøÆÏ'¦¢C=£FäØ,˜H£ ¿·Õô†eiÌx /Íéèh øçd×FXÀi‚Ä¿Üt ÃúOÿé«“¶Í‘GÙœz꩎¯Ë ?÷wñ—.ÎwC½h·(™;ž¶$#b™WØx ,ŠÙGôíÁÝQ«ë¨ñz¡ô[ÓÄÝzhyÙÎ\ÍõZ £´e¬d ¯GTÛ'20Iã)ؤÁ Á Ƽvèo‡ÍŒa»xÔX´ .9mOò5ï¾çNì3âCú•_#P#P#P#°:м½:#š=’±9Eéin»"ß™°ï“žr7Æ‘ó0“ËCÑS ïd“{¡mœVn‰,å JÙ²|(7 6²Í0ö¥> ~ðslÞ÷Å÷•¡]iúÔSOõ$ ò`«QþÄè\³¼¬o iv¼E.:‰ëGr ¶ÑÁØ×¼KÌ:¡# NìË‹$_H¯~õ«ÿïC9¤ó-zÔ£Ö*¸|ãÿEW_Ôy¤Š½grôÏF… 1O˜Æ#:Ð@¤ ½¨«I5ùÒ„ÞÑ‘tÝá†Ï8ù»ÈtZ•¡9HýI„j¨$¹Ø™F'¨n˜f@%°¯ðìøÊÞg[¨Ló&.óêÓá"6-ò l+XôÇq  F@±«°F F`#ƒL,5o±¥:_g1'‰øÔ¡‡Ü› »Bî¾O9œò+ÑòáÐt’’£‰pêMÆóÌ”wj.K<üg_â Àœë"OmÅö]—¾kí~ ¬A¬F9žZÅb”kÃ˺ÚŽB®}ÀµšqxµmCêG–äwÿ£çxÒë"/^$ñâÙó¬g=kߣýèqáwÜq‘µòøyŸ?¯-äµç5Á2]0‰jRSCž¼mÂ_ºyªPôˆ¦"*h2=ÂïA2>ýÈV²Dˆ½m,éô‡œí2Äðûh±/ •ëÃï‘Gõ¬—˜ÃK~´>FGº‚óÚÌ«¯~úࢾfÚµ‡¬¯ËÌ›é#knÙ®~67ÊŬwó¾-‘jU#°óX÷ë’õrÚ:ÄqcåƒCÒ·®¦Cå_4Û«Ðs$£/Ãã£ó®Ý'</4ÍÆä9~ì1ûxêtr7Wmw{rAýŠ@ë&í9¥bÒ<ÄÐÖ<4¨¸y~—ñG×÷Ç ÿZvðèós†/kÚglß~éÛ›ûŒÛ Öà•„Ü|óÍy´Ô*V³¼ãï|çuìÞŒMQ‘N »ÌHý(@ÅR‘t*.ÕguÖNœàl´uâSìm¢u`ïsŸûÜ×$¹¦9âˆ#š}ûö9¾./|ãÿmߺ­-ð­hV¡¯B¾sW”;£èhƒŽ›ñ=’€ä º£Ÿø>AKfJQ?ú½Ã¤çr °|äX›?¾Z$ÑIÔJ’<2{äQW Šx¹/1¦ÀÒvŠjÍcƒî<ú¹“dQ_3í´ìôô KöËÚ²›è_x©³j´Æ¹\µ}©ã©¨Xÿ,2m…ÍúGrûö`f®Ræ>îµí“'žetíŽeÐ"ž³!1Ÿî7áâu`‘sJæygÈ%å+ç„túp}媲KýËW~ŠUré¼ùŽ››7^öÆvŸÖäuß¾}^“„áœjÞXVC}£Ú¦¬uRÝ8M<Ñ-·¾nI8 µm"=ïþ—'p¤K\„ .š=ôGô"{¬æ¤8´ãïü@­$Î7þ_qã©ø·+;í¥ÍiòL<{‡™o’‰4~ÔÑD,›¤|bšláiziÇÐê¸nÒs+ñ×ÞÄZÃÀ!~ÚJ3Óf#^¼ùÙšµº}ò¨û ß^NºŒA}á{ÆVÚŽÑŸÇfÝi}ãg^_²´óŸX²ù—õÇJ>¦m™ü .âc«l4¦Yp«ú¯~ûÏÅ——zÔs`•Îyriã>ØŠÙiò YÊ£à÷Ž¡O®Ü‹|Ì6åUʵrîfzøt¿ Gw‚&ÇLzQsJ·“ûÈ?´¶:ê¨_›úòòqPsñu¯Ý/”5 5‹Õ.¿dG%×2†[”:›EÀ]4QGí­§Ö’¨Â#P?°`à0qBr‚sòG(<^ñbÙó£?ú£<餓^Hjô8L¾ ð¢½è¿Zíí°ÃköíÛ—¨Õ|é߇®ýP[ØÛpýñ)BÀ¿O€”Æög¸^Ú|2t’v¶ñ¸»d—ô™^}¦³QC‡&]'LÇoPm †=-õëÓYËq^¤³m°‰r™ –…œÛËVJ=°´ëQ™`Íc3îDG‰±ˆElÔÿ\‰‡ŒfÀÍŒg†ë™âì{æàªB@@@ÀîˆÀˆœÃwt–žÉÉ«×â!ûÄWn6aìÜ¿’*õ—hõMå7lÐÙ§éÈVPnʼKk/|·'%L›\PïdŒð›€{ï½×‡jû°‡Ænüœ1tHMC„´ê['DEÑl¥-_x…KŒ§am D çÝNàØ ãF¬EƒÇ-ÿ/{ÙËþáá‡þÄèˆ/þówÉ#s…ñwîÝyÒcBóÇžlo¾ÙØ<.–yL’È :ßH— Ê–ººi3šÈ2áfññÛªí\ƒ/E×Ç&蹎OÂ0Óå ÐÖÐw:ÉÐ }`“åÜýEVȳßäŸÇ³#/Û«ÿXÚECø<6Zü|¿óKØïq©o=v.z \ÄF~´[êl¢75ÁÍøk«¾J8Ö¾ê?7k¬j¬ê9PÏÝp°^¬Ú~(‡=¾"_š°/r©RiáÊéÈÃà9?C»ÀÉ •ϽV…VGöèûf|ÏEEѵ­ÍaÉo!’¾ÁœÛ¢ø-ûƒš¿¼äm j-ã-€Æj™Ÿ´ȵá¶ÇÍö–=vžpAcç/·žÚ+Ë*2_êóÅ˵§œ€:yÑç¤]^ñâØsÔQGúä'?ù·½“ôrì±Ç6'œÐùÀ(^9üW¿£¹íîÛl¢;Ø'²v´Ý÷É.…Â'ExióÓvÅÈv:ˆüB]×kùÜ€eʶàFˆï~JÔ’žc&'%Âæ~[Uß$s¶ûB°uGü!,Ùê«ãÀ0Ú ¨tØóêwŒ˜×~«õ5¾‰w$XÎ;æºÈ&ÛÙWî´"5555»*cò…Ñ;Lî3æÑ}òžg1yê#ünØÿå˜Ê¾KÿQ_¸åÝÐSJÞü¦‚á–š¶O ÿ9¸“ÆG—\’{.˜“Îò1x¡¹xiŸýI|¨‘”âÃgmo⎛ù½ùÎ[š7|æ Í/<ùP[ùF¯ÜvÛmy¬V˼Ìjš¿ºãŽ;Ø«YwªQ= ý£ç|j°³Î:k‚*>;œÂµm>œ¼Úð&\ñ–Å?¼|à•¯|å´Bðãåf?­‘ñUGÎ¹îœæÊ›®ô™‚Öß‘g"´½Œ72?EÉom2ŽŸ°á Zö'#d‹‚D;´þ£¾péÓÌÃojÎË„!¢–[ÐYŸ)©ÉM„±̶Qav*ö¼úc#æ±Gw+õ56’‰1 …ô‡ Æ;Ϙ‡| ñc‡t+2ŠY…5»=“gåÔìŽtrœühHÇùÑ&âžRýìä†!DóPé9?é)×tYÊ+ݯGzÊm3TdúŒ]leoÐsã@Ë×§¾ø©æmŸ]Ÿ'ÊZÅöãˆW½êUÿÉö:×8†«æ–›±œ—"©¨9tF}Y^êsÆrÊ»ÿò¤“WP—~„:ñó…ñ‚¼à ÇsÌ?à‰'žØ<ô¡¬•Åÿú«Ý|êúOåÉ-_ÆÚkEÃ`žÓ¤u‘u.yE {pZò䮬OÂI&ÚaéKúfèwsqet¶I7—pï‹I<¶‚ôq ¿`ñOb;¦Õ›ækcuÇêi\óêg»ï"Hw.Ú÷¿’¿ÕþËþv’>öu'ã\û>0"° דß?0½ö{¹ç˲|öú!ÿš±†wìȳ”•¶QÆ‘DŽrŸ¾d¸£lÁQNx˱WË#õ½˃›ž½-}rTt<‡$ïä½måŸ$Ÿæ×õè#É;ß`&Š…rQ÷aê@téïßÿpsÜÇ5ÏØ÷ ¬v£V¡f¹é¦›ò@>ú蟠¶9ãŒ3®0&{§'ˆ˜há@ä:*@tz[}  7,s1 xm›‹'©6<Å“W|â̦wý…çÏ|æ3ÿ Ø6GydsòÉ'kõÛ ßº¡yïUïݸ j3E´ó¶§m7€Ž[T—NAË6ë‚UÙCw|$l%sV¢ÁåC0ë¢Ó×pUÊJUÑLSÂû|%žÈ ß#í¦¨Mž§)¢7î4_Q6_Ù±Hjo^¨~ÇîÓ<þ£ï­ð?ÏXÕ-÷a,½hÕ®F F`5#0öÚŸ¦·š{¶»FEüW¹ å6CüÁ} 9Õ„maïòÀ‹´ðìCzJ¦S6î›ÜÕrAÉÈõâY'èÅüÔ}¥\X>±õ¢?åÇêÇ¡õyæ§Ïl¾tÇ—\mÕ_¨Y¨]B;(Õ6¹Ö1YYQ±q4´š3jñ€µ-1½¶‘èy÷_'d„ñdÕ‰­“¨ !ã¿÷{¿÷ÜC=´ó¬ùûš#‡¸#jç|/&¿<©Ùuì“¡&¸ Ç%®‰Î'DÛƒ¨Ë9&ß,þŒ–?ìòí/&FG0õíŒô"yô“å­i&Ññ¶âÅ¿’µcc‹y}Žõ«‘m¶èÇÏÙîÙóõß“œÿÌÚå>³ôzä£ûmèkÂ6ÈPwyÁËnŠüPy¥—žnœrÆàü¹8ä­ØÂÖãûòsSäêÃýпeýÒ‰¸;Ȳ]Ê™ßzÉ[} ëðRÖ.Ô6Ô86ö‰ÚÇxÔA‡à¢ái3ÔñÁÇü»ëÕ—þìÚ6“Á¾*@IDATNRšNbÁòDÖÉ Ô…°ç¸ãŽ;ìq{ܯº‡ôÂôˆG<"²Vÿà´/,¹¹[ħø$faj¢Œs:Mr>I¦‰U—û ~šÌ ŒOÑÉÎ'Ró;¦ø/ƒê¶­Ã|£ ë°O±‰^ƒâ?{Wb6$¬^Ô>n¶ð×ø€Ëj[ásYcÃO_‰/³Ÿê«F F F`Ù(ç¬!zÙý®«?â³î¼®¯å¬¢žL&t WÊq1¡ëÌ ~‡*!ó¥ÜQ~<MÇ|Ôm“¾pÜ»ªñ]W¹m‚.³¾¢Ÿœ‡èeãßxûÍ×]àîWý…Ú¥¼ @C­ccϵá±&²=Vä2:@š`KÕ×MG ~Àȼû¯“/:9Åê×I_Ò{ìÎØ°‰æ!ÆÞ½{›òË4$[5øå»¾Ü\øù ›ƒ÷Ø7þ§œ(äI<ð5þ(w^ŒŒä#ë‹Eo‚VÈMßå‰FBÒ]Ñ*Òá¹ †ýwôdCßö'ûÖ‰ÀQ÷ÉDí.pl-–˜ñŠiÛ Í^ñ<‹ÿXÝeë1ð±>µ“›‰É"ý©ß!8ïø‡ü,“¿ŠcZæþU_555C˜5ÿéÚ!ûÝÀŸƒeìãèµxDÞ3ËWŸ¼—÷+ôYêMÐm’æ¦QÖ‹ã—ÜŒoõ·ÿ˜zÌMæîøH"ˆZ‘ÏaGóÏõ'Ÿž–¶ìŽ_¹œ\YcóþùY³“Ïw]ú®æo=âo5§>üÔlºª5Ì­·ÞÚÜÿý>DÛ‡‡PëØ÷üº1ô=éÛü¦z lŒœpA÷tý)€ú‹ Ë|‚´¶è)þK .ï¡Mw°€ºàð9ÏyÎcí‹ÿ~":ãΙ=2Y+‹Ÿý¹³sïïÂÛäç“•í©î^jsÚ&8ä~S„;L¶ÑN¶ÜF‘Ž¢,(=á0ØÈhI×Y’!žôçVð¤ÛY²ò ¤ð5C{B—íoLŸC:q,‡t+¿F F Fà@€æÉ!¸ÎñÑ>­Ô>l2Ÿa_”OÞ¯Ðç„me‰u3n2Çщz /óJtµ¹~²w¹-o6aùØ„¼WöÎ+øn‡?K_²7_òæ¼k«ŒPÔOPëPóظ;uѶÇ9ÁEçE|p—GÔhƒ¶²€€×6Ê“šùĶÜ8ñáùð3?ó3_üÇ·hª(ZexÖ5g5_¿óë““YÜʉ/Lv>™Qtó/¾ôE›É/ê Ï“¢R­Ô -Ó›ø®Ð2\/Éd›IÆcÅxî–Æ1·]2˜§Ï1ºctèz½±ºîw … ͦcÖߦmÂXýG¸ wÕ´F F F F ˆ@œ_K¼P]Rã\™-s 17 ~;9Xàg4äRº}²ž~²ÉG'm¢;0wÞê#“¼ÌKMâ²¾ÜVº•/+÷4~¾ PèüÍíÓ¼éò7­E@-S~!`ªyt@µPY'A‡#âÁ‡¦•ü–[_Š®mJzî,éD”•NH´}'³ d~òÿîïþîÿjwÉN‘à#ùÈH®,~É-—4—~åÒ<Éé’dÂó‰K™ tSŒ§H¹~ŠždšX£,ÛʯAš&à‰Ïl!oU:zÙÆ¹ÉÞ™-Ãý%Y´w•Ô' òÜ-Œen[3ÛçØdaŒ¿±¾ØŸ1þ´ßº©%z8Ϙfù]¦¯Y}•rõ-XÊ+]#P#P#P#°}Ð\Ü·o=iœíÃ:yÐ&»ëk¬^ÎËBN5aÛ'K¼¨›q“9ŽNÚD vrLÔB.ê¹*qÂO,؃΄_é‘3G;#²¤ãr|%»öcÍ'nú=®|+kjjx¼  º¨¯v∤ŠÁ£÷Yn=µZ–U¤?¶¶ù#À‰×·ÅUrÔ:á~ï÷~ïKc·\(ö%‘µ’ø]ß¹«ù«kþ*OF6-eÜ'ª8i§‰ëàƒì{ w4‘ùD—ðÌtô§ÉM¾:3îÍ>ÿ®jÒíØ´æ­½;jî/ɤŸIóIcQž»i s¶cû£76©ã‹Ñõ§]ßì£þò³(ÔxÇîߢýôÙídß}㩼Ùˆs÷>Û˰FŸÏaí“l2¿‰{ÓÉÁ¢`}OØFE6M åsÎn2÷NÚD vrÍä/æ°àØæÞ|˘ù!/†_—'ùЛiYnùyç¥ïl¾ñío0Š•nÔ4åM€Tûtê!Û ÕIáø‘è«©¤³Òû¾ƒ«_8å(õÜQÒ‰¤EZ8'l<¹KzÏÿñÿ²]ÔùÇ2¹¨ËÏ˸÷|¹àú š»ï»Û'³|yö\ºìSç’.uŒvEÍ îÐÖ²}’KfS`'ê,žèªè¢#šI7ë¤ÞõÁC_è´·@¯ÒÍr F@߇ 7¯±úcôÆè0Ôeë¹Ï¿ôpìXBˆ{Ñeùéu>À܉>†RÙ5555[Ý6ß/s¦ú"‹ï«íO v˜S\°'ßÚÿ ß+—Z‘ëùâ‰FUxÁfÜ>¾Œš<5#É3=ׄÏfy-_$(>>œŸ|+õÝKúîŽ.}ЃmÎêù3|Z‚îÛÆqÏ}÷4ç|þœæyOz^+_áWj›¯ýëmülœÔ>Výê‹^ô¢W¤=‹_ Hí›"CtØhâµTŽNû³€õ –Ù²¬¶Å" r$¾œÐ‚{N9唇Ú7dþ|ìò„Nh?üðÈZIü’¯_Ò\ö•Ëü2ô»™6áæ»šÂ r™–ü< JæJA¯¸+êâäK8…=“¼ÖøI}"÷‰Vg³Ñ4× 0òÀiÒi Í/’¹ï̇ÈVÚóú«?Fo¬Î2õØo_<(þǘ±(¶}P>6ë§Ï÷o'úKå×ÔÔÔÔìtÊ\hÖxПË&å{ø°›"‹º—¾rHÞÕwÇæ;å¨9eœ)'…×á§Ü¿9Æÿ‰'Ü!¾“ÿ MÊǃí'¾ð‰µø(µ 5NlV=—ZÈxz³T5½µEw_0õ €À|÷ëx¢rò–›Np‡¿ýÛ¿ýr›rÜ8âˆæä“OÅê°ï¾ÿn{ôÿ½íÎ2 Ù^ÛSýídaÍy‰ßp×Ôþ}2s‚V¿£Û²;At%k&n·¤gUeëǸòk"v·Ôõ˜$Mæ¹ i0A» ~  RC£ 5Æ«&]/ ‘Íj=¶2™·«?FoY:ìË_yŸg1FÀyü¹[†!ß}üíî¯o •W#P#P#P#P#°´̳~‡Üg°ÿiþzì=›Ó¦ÍßÈùHó §‰lÓ<#"t[YÚãyºhïæ vüC ƒº¿´v­ÛÖF}$­º¶¡GŽIþà¹&ù’[»’ýfž% 6fJ{×Y—Ù|ï#¿·yè!ÔÒ«Û¨q¾ùÍo6wß}·Òöy¯ÕBÿñ_ü‹ñ+Æà €ø5{7À–¢’¡±¼Á÷FíVŸP4¦Ã\ˆNW«Ò":Ë¢ZïüK¶çÿãü]G}ôE_öÓ‘\Yü½×¿·ùÖ·íÑ›uÚ;’¶ëÌ@DÀZæY!®+ž×ç|³Àx>á¹mòAñžhôuž9²YG~å›±ÂO«dh&¾¡¹9O”÷ÑÚ8 ÷=Í‹»YG];lÌN?FÏ[ ŽÕŸ¥7K®ñÑ£“ý¥ÅTô8ÿ!Ëð1仿Ýýõ¡òjjjjj–r¨±k99RÈúÆ2CÜgâ‰àè1àÁÆ¡!OôÇȾ1`)•ûê9_ÚÉdãy(†¦äý%œ,ŸÆ ûLÿþýûSîkJ”¶î3AL³¾ñ D=p>B€[ò^ã¡ëqð®0¯iîºç[ÍÙŸ?»yîŸk«Ý¨ut€‘Z-ô4j¢sÏ=÷z#°¨°Q;±·q3ÒiÛ{o@äµm"»¶"s¼ûOü8Ë-žÈù €ç=ïy¿—t½G~"ƒŸÊXõvù­—7—|ùf[è3µ…<¯ãÐLXü'^;Qmðq€,FK~Ä“¯l‹¾.sC}zH}¸Nòç~£á;M¶bâ³lÆó¢OVêjlÆ×¤2O‘ˆîý1zËòÃ~Œñåz¶b͵X§ õŸÔ'ö›õ1át€¡¾¶«¿aTv@@@@ÀÚD Ì:ȳ°™j×q’ˆä«×.ôãò@gWâ”Î L9°lÑSì_Ü—òaå©ò3˜ëù³yëäÖʕՇrá\ý‘æÓói ceaßϦš(×H6øøÆ)G£ÜT³†#•uò¾÷ÔpYV‘Ô'6b1Ó ©Qž`<…ïyñ‹_üû,Ì鱓uøÖÆûÁ/}Ð/Ùðl/Ûwótž…„¨ M¼¬ŸÄ~דwî™è>c3Î>[ïs“öC~ûø›kŸÏÊÛ¸nj,j,ê9PÏzì‚s /¿*s¦MÐ9“iýÙ(»¤¯tÔºð¼ÕÏKùêþˆ~'nóbÏ]“úÏùpäå<yØàÛ¿ožS·ODãÊ6©¹éö›š ®»ÉJ·¾Ÿ;êSŸúïlÐz)ѱ¦ÊQ1™ð>˜÷¿§–Ë²Š´ Àµ¥L9a8Ñh}'\’°-‡³æTd¬î½Y:Ègé0Ø1:®—îDOÝÁB8Öwa–ÉÍÚgGSúÐßµ*ª¨¨¨¨¨XFfå\ÖG™kMí6ø›°ë“‰'ú“}Î9½0O½›¾äpÀ=E‡ráßf<òR¾ì~’¿l'û e±w]ú®æúo^Ÿ¶º ¬}¬6:‘ÉFÌM€¾*ò,Bž¡GÈÎBO´)5Ý„îȨ˜~Ôu’¡%|Æ“<ßÑzÊSžòob7öÍÃþðÈZIüÂë/l÷Úö&Nj\¢ÐK•¨(Â4à´-ÙùûáךŠ=Ÿ‘'ûüå¦ =‡úR@£i’9QÒmµ¾E•2ñ‹â_ãDq©Á±ºcôféÌ’Ï3v=Ê6´_}ü1ý÷Ù‰·Y{ù™·£iýWY@@@@ÀªD`ék¢åVsç¥MI÷+›\NùZiWȲþ¢.¸å–4»dÀdä|rT{(Üù&'nóoq°> —àÅF^íþô<ª¼Ù‚š¡vK¡åéú0ñgíÜÏŸÛ¼èo¿¨%Vô•Ú‡è«_ýjaª‘¬àð(±÷Š{ÎÞAÑrÚØщх_ی贚¡¶ûÅ=wŠt2õAˆÄO<ð\øƒ¿üå/ÿ™={ö<ÂðÜÖá›ÿ?qó'šën¹Î/)/ömï(ªµéRt‚Š÷£|mn§H˜®Ó@Póß"-îtbIO<éŠn “¹ü@š½t]*­ªË…vÆ–™I“,œŽO£µíAt¬î½Y:³ä rŒŽëmó»þŒkìØƒ=C°}ÌB×ÔÔÔÔ¬TÊgæàÊÜj¦Áb ³ÆEœ[Dc^ˆB9è‰>Læ¼!˜ü¡#=g©O|kKºÐÊ‹•;[Âãöò‘å¦,^¶ <׳¾®ºñªæÃ_ù0=¬t+k j$j%t§~2ššŠÈ©Î]FÓT\/B𦧶s~}išúÀô³€“Œ¦“-Bˆ:1ËÇWüD>ýôÓ_Òºh_¹óõЇ®öov2Ò‹®½ÈìZœh˜àí2&8ÿ'4†¦ O2Ñ.t…VÇå­'•8'§ NÔ|ëÿð_hw¶ŽÄÆOƒð%«ÞÞãû›»ï»»-æÙ+Ût'R{Û¡ƒ™ÏN›¢%^òýO|=rå›Ë*k¦ïf"ˉ¾òÄ ž&F·M6Žóéˆg…~$ûObO¿êw¬î,½Yr:ž¥3K®ÁêM™bmät ÜŒí·Y´ÕþsG©¨¨¨¨Xã,}½´\KEñè° Ù ñÍñĸ•㥲±3dÊgð ‘hrQ×U_%$'} UVÞŠ¾ûÀ/9.îøÆp%, =6ZÂÉ£]†nX$=盚ÆÐ~ÓK:ç÷ÜÙœÝùÍOžö“îrU_¨…¾öµ¯5û÷·¡V¢fú•_ù•ר˜Uô#$ÀŠ:EÊ¡hA{ƒöFwÖYgeZüÌÚ¦G žhàÄ,nœ¨¢…ï±/¶8ä”SNù…èúøãoò‡DÖÊá×ßy}sáÕÚUe»Ê¿Ñl~™Ùh;4Ñ€Ç#þ襸®lããÿèFØK>hÐü%_¹o‰“:®^صL÷’üŽQVŸÒõI^Ä’à,Ÿ³ä c–Î,¹v¥W)t`E¿×F§ÀÍØNqÛ-:¶Ž“JÔÔÔÔÔÔìx!OÑÉóq W÷%ºen"¥ÔOp’}Gƒ)¸ösŠJ»OSfù˜%Çõ¦t6ÂÑ埃@lÆ6¸D·Úÿ`ÇUP#P#P#P#P#° "0o¾R¥Á½Ÿê³'×£?U'Äs‚àÂ&ÊØ‘D»^Ä£?Ãñ›}¥¼²ä!çà?ÐÚ i䤛íZ®ó3ÏtZÏi€ÉîŠ/_Ñ|äÄ4錄'«•ƒÔDÔFñ¨ì)€×Þwß}<þ7ÕYì¨6ö©ŒfâÚ†"°ÚéШ·Ž¯Ë0^~ôFœ¢ žNHþÎ{Õ«^õÚ‰}˜É½vØaÍI'$reáû¯{¿ÕwÓEŠgÝÑôBÚ¢yš´(À³l(ð¥›p§“_H)‡™x’;L/îÜ]Û‹pü«ÔÅSd2úÄš¹Ÿ¨0} ™ÍÒÙ¬œ~gùÔ‰Ól±c|&™ÜŒmv2€à{+ýt[Ù555555KŽÀ˜µOt0Ðô˜|boU£ûOû‰ÐÊ2¶v²ßTLv6ÞZ9vn"?ÆpÚíQ¤ã%ÇH~Ze—ò"[g²¬dÈdá¨qµZé¡„h’ð®ÌIÎ$wR§ËéRóÛOZŒå˜ÞðÎì[¿o¸j“û#I ÇkFËŬ¢‡±øöõ4vDU¯F F F F`;"ÐfÛÑÓ¸>Vh="4Sr‡Ùû3フ×'õówêÃ[^U)Côà~Ï5L2Ù·²«MÍŸOí1hóã©ø"@ãy®ëviÜž/cĆ“'ÿÎ/´\þ¥ÙAÏitéÏtØ?OqÍÏíߺ­9ÿ ç5?ùØgfW«†ÿS#OPCñe€z€=dcÏÔ`¶Ã¾A?`2ÙD«_Ø É~ FÃ/)cÄ“y<ñ¢ŽNBA À¾ÅríÞý¿þ®ë›÷]c_üǬa›OVÐ?˜iãCSø{¡ßêùdÏõŠÈÁ–Ì¡]‘ÆÃ¾Õ·~ ÷«>argµ¼v\W46Î3Xâ˜ÑÜe‹ú«fÙQF'Šs"»Ž“lÑ"v…\ä,½­–3ŽY}ä±úâ%jë{š·eø˜æ³²Ußf÷¯Ú×ÔÔÔÌŠ@'3°|£Ì8fÙ/G¾ªëQ7:=ûJ¸†”,ŸÌÓ÷˜–¬Ž›i~“aÖŸÒOÖ‘MÔ-q v;þí±ÐØ ZeàûÑŠsþk÷w¹ôû½p×ùc^LŸ\9Cpú´^<‡fLî»åAR&“Ÿ{Ú–úuÛÿ¼ôìæñÇÞœöðÓ\u_x àöÛooî½÷^OPKÙ/¼ºÝ»|#@…?7š6Ûkoº¢ž¸žŒU$Gà@¾À‰3ÔtRIÈ Æ¦wÿE‹ç7ó˜Çt>û¿ïþò«Ÿ´«ˆÂ¿Ýü’²u"EÁu6Ó@”ì“øe“}.Âí’t<]ªn“.S¿yPȳ¿¤“iº“­A¸ë$Yî˙ݗ‰…4øëjv©± Õ„ÿ®nßNm(mVާY>ÔÛØ}Êú3Æ.½YpìøfùÙ ù*m+ö·ú¬¨¨¨r}èËÆy§Uö7ÎjA­é©I¿Ó16Ót†d=|b=˜³ôèÇt¥ct;|öYgÜxÒÍbÝ«÷$C9èá.æ¢n—¶6žÏ’ƒª¥|Ôý*Ÿu¥”×?üsn¸ôج}èKjN{òi-±‚¯Œ·| Àj)žx­mz €â¾¬»tTÓûž‹×ÙãúÀF8äQh/“p¹è²É'›dœ|àåIèôïÿþï¿Àî\åoþçs-~ô£‡'§8‚¯¼ýÊæÒ.MðÛ®Ùžøãüé]{§)꡵÷)þ¾ÝatYâytÀƒ®OH&ðßIEfMTû8“1í_¸ë¹’«ºÌ'·Dºnš0ñ“õ“ßÎâ˜ú“iìè£0µÁEahþƒ t«åcúp¿} 6¾ÍûOËð1¦ŸEtVyl‹ìOµ©¨¨¨ØÚ”ëF'ÙD×ÿ?{ï¤Yq fUõD7tC#@¼„„…â! Ù–1 yÆ–ÌcËKØ3ò„´öH»`Y–=±¶'Â;bìðĬ¼ëPXalyÖÚ+f5Œ×z›W‚F¨y#Z ô‹~ÐM7ô«ªö|çž/ÿsóÏûÿ÷¯ªîºUYuÿsò¼2ódÞûŸs_jw¦Ú«"ʦRL ž›AÛ郕TÕ7Ãcß|r€fZQ¶ãù‚ǃ?éN‡¤Œ_9¦£õÙw< Çƒ?¬ íÇ ¾¬ÛØM†ÛW }F瀀~uµos0¼b¢x x x xà8y€ß'M0íF[¹ToAÕÄZÛ£Á¤¶kõ¤O)Ï×#.:ЧPúO:†qÈ!޶øZq x+ºÆ­è6âÈ< W³A9Ú‹2‚x¹o>ÿM5×Õ¹x3ùb9U̱„—æ_¾žzŒuoRñò“€•K༽p‘¤ t¿‘ˆ…©ð÷~ï÷>211ñ&:S~ÆB¯þ³ÞEøÈÎG¦›p˜ˆI}ßɤ0=ˆÚ‰túƒõxãß zúDœMA{ö!ïêZå£RW ö9UïKðœN*ëë )ù÷ýö¸žÆYhÙ¦¦¦F>[ßç;o¼%>6Z6ÕZ }êb¿Z ,(ð{‡pAu¾ËmÓÕbÄŒNŸŽ×ä)“Bw6É×Xè¨ëƘØÓ’˜Ù†ÆÞˆ [{— “ŒéŸÙòLX¿u}ÚûNÕqr'äTÈ­¤s-Á}&#¤'’ࡤ°¢–Ïp">ÀÅà§Ÿ4@nàç‚Jaí¬Ô%—\ò (°à·-eñ²ÚIøMßé–£v#Æ­C8x¨Œi^Þãô’Ðô6%9Tøbã ^U;FG]ep[ ì¡VµJßpÚˆUÚ"Áéäº>ZÒVb&Vç*ù‡Á¾>ÄVó†é‚?…7Í´)c3ÿ ês›æ 36Ú¶5Š\Wû5ÊŠlñ@ñ@ñ@ñ@ñÀ|{`¶ß§Y}Ä!.f‰czcü’Ñi²µa¶U¶¤D9¶kmhÌ+ý«ÁJ¥Ò<€8·òóOb_ØT=ðXÆÁvº‰Ì4~U€²ð‰ÙSê²Å¸Úôï~òîpÍY׳›9r§mÛ¶ÅZnõ! ¡‚G¸aôØl´ )f9ø„ài±»À;a —Ï ë8 !ê~#POüú¯ÿú/]ºôtµ ¸•åôÓc•äNÁ{·Ývíߥž!ÄH5á—žâÀ¡WémôZM6ïO<Œb÷g! W6ì@LhÔËB•ªlª¶µ9h•éÊnTê!zîU[cñ ?D£ýA2ƒxhº‰¯_ ¸¢ï“ÿôÐ(u|qè&?-qÒì®ÚŠC…žðôP‰£#M}ÝÒÜi O]ì×ܰX*((((8~Ðxîø57'-Å>[ I£‘‚Ŷ}<Ò3PuÿBÝb_Ò+T"„ª ²”Wht3ž§‹t/žfì âlÙ¶¿º=|mÓ×ÐÎäNÈ¡X[!Ç’:/º2ÿ"t^QÏ‘•Ó{f ô¼|b¸ƒ‹£åÂA8e¹RX[ˆW_}õÿJƒ€ëÖ­ x`— Þ ê=ëµ8`y><Žî=Y¿©àIl *[ŠÃ®mCð‚MšŠöTªª³‘ã+Í}d½Ä¦hÛä?* @²}0ùA<ˆäø>YW¾Kú•gÉýÔäTÀ†¤êh…{ZzRÉ>m×Ú…ý ôk6FÔ?â]ìÓ±g±Y¸Mu$䦲–à“†ø¼2SÉÑøÿðä?èðºúÜ 9”/–c1cþHš‡ðŠó\­®û ¬§0ø‰ø@:¹\„XH\8%îp]„·ß~û¥Ë—/?‚,é‹,Hï üÆËßÞ8 I¼ö‰#¤@t8(zÛ>ާ |€–Б`éÁŒBÂ'É øŠ#©„~ ¡k4ÕÅO)ž/ŽŽ>§I;Ûô*¶jBU¿RÕ¯„˜mÃÉ ââÁDÊï®ÐK—˜=éùám+ÞÎ[z^8kéYáàÔÁ°ñážý÷„=GöôùFç þ“¢ó­nÖmW¿PȃPÕTßœƒ•–´ß)>ê]ìÓ|ø¡´YÜ'Þr(ÿr,äZù—ù¸ôà'1:æe ¡ŽÂQƒG9xtzBÐRÆâ¢=ξ`Ry›åâ`“\$„X,À™Üâ$ ’}@lKýö×ý×_<餓.š–3Ï<3œ{ní|Y€;í ÿyý‡'‡±‰1}O F>>1^U”:>܆£WúÝÙExBi’`Sº*O}ž}ĉó*uàâ\¨« Èãß Ê*¡:Øù$UyóŪ´ëYµ+‰:É)Ìêf#Y9gl6üT·¶ßJ_ÀG²ÕÊ«Â%Ë/ +Æów àñ€õ¯­_ßóõ°rÕ; ýNˆ¹ë"­sè}?Ài¿;æíZæÅ ¥ÑâââââQ<‰yÚ¨×b•œÂ»º :ßï^Þða¶#?‘tŒExÚ&d€ÛEâ¨+ |¤¨RH‹_BFîÊTÜ­ ´%:“G'{|áá®Í(‹Ç8MÚéÔ—:Ãë¸ëÓdôP¡/_º<|î†Ï…u'Õ¯´W=ìÆç‹/¾¶oß;óúë¯?ù±}ì—„p$ÙŽJ’}Bxu@ñf„À¹  hÇ­è·Öš*wT¾a ˜ÛƦÛÄ5×\s†$ÿïðî}Ó›âxrgð‡¶==¤É?’¹ôª¾Ö-¹‹8=bÉ<=¾æçHà…'‡œ8ÎZ²núà3¤¬ötiSùa6¦Æ°ÿV8u´îäL@AîÃëE>úÔ¢du{ÃŒ²r‘[÷#Gt~ϵÉË.7ž|c8wÙðOãcãáÚU׆+ÞtE¸û•»Ãý{î~×¹„×¹.×Mü­s$_,œ+t^O°?Χ}}Ž#¤ký™/”V‹ŠŠŠŠŽŸ†~÷"n` ‘vKx£$KCÛ‚}ko˜lä§ò™>©,ä¤ÄþRÎô5FFbÎÁ"f–øMK"K±wKÑеv‚‡´ÔžÅç¯HT±´yððÁpï‹÷†Ÿû‘Ÿ¹“¹”?€\ 9×úõëqVÉ=Fï7zÞðœŒzÓ*Ö‰Y༱øÅ‘âð h€¹gLôÖð?ùÉO~Æd„€{Úi§)ÞÅÍû7‡{ž¿'&u¥&pÒY…2â˜ì!ñ“¤»q@ÝÀÇ넉žzÞdŠX{F×6Œ€:Œ<*Íè÷íMûéx}6ošÕÍB²rÎølø}º®ý•c+í«o ÿò´Ù*ùw] +ÇW†›Ï¼9ü깿ÖÊßÑCGÃä¡É0yd2=r´zGÀyOÞÀ÷àçñfìÅ/0­T-ôõ¹"ÏÛg×ú3oŽ(  õ@-–t1fM±-rÕ®Õ#ºÄÎ ;ðkbn“ótêúñw­N¾Øøûïÿ}xaï µát©‚\*¹ :f9s³¦ü |iÌ>€ç¶. w^úG“ßTÈãq@øˆ[\p²0—És*?a–.'ÿèãww|7ŽŒÐõa‰{<¸¸:dy`©yÆ{I ÁXµQGÉÐWlÃ¥N5ñ—䟴JMtzjO Ö?TÇHHú?g«n¡WËêºä›’Y92ΆߧkíÃGç,9'üêÚ_ ïZñ.×Úèè…'_~ýâ_ï[ý¾pôðÑpäð‘êdÀa9 ·žiòo'xK™&ýÒ—xÛšô‡…<ÖçÂ}>œÏ•¶‹ŠŠŠŠ¢ZÄM¹aù¸,ÇŸ­¡/>¾h·A?Õñ}o›Æv3ÞcG{)¯RÔ&)¨¸Éküb8ÄÓ-Æëг˜2¬+ úéíß÷â}JïêGšS!çBî%ýíËɌ潄a±N0W*å8‹˜v">À‘ƒ\TBŽuž˜øýßÿýOÈŽýwòÉ'<ÿßÕòܾçÂC›ŠÉ~Ü-ddµ[ýe8èÈu_=PLŒÉÍS©é5hú éžC‘:f ë­M —?MÑŠA°ÈW²“¯É¥tef>h_XÞ®—l¢{âÃdñGâ¹ä·üß~êíaé^G1û²l|Yøçÿ‹pÉ)—„»ž¿+˜>P½ßï‚X2®/ijeúޣ닽”8Æ£sŽ.¡¿Î׳ïåhùv4KEºx x x x x x`¦ú}ŒX¡w¡ÞŒð46¬SkÙ¶röûÊÝŒ}%•eû„THëB×¶IwñÆÁزµ˜×ú~¯ØÐ8 q4c*BØÑd¢mêx9<ÀX\n”×xMúò§¿®<ëÊðεïä¨:‘SíÞ½;8p@û%ñåä^Ÿþô§ÿT¸åÀÈ1Jz @¡'€CÆÊxÚ ƒsI,æ§ž+wðˆƤ_xð—ÖÏ9çœÚÃ3«V­‚ngËc¯<¦É™&h™Í<ê8`Ô’®)>ë/BJš—0jØ´ vb;à¡@m™.a´o2 ãKR¬&zH'¯΄j]!‰|£¬É ââ%ÍT‡/#¾yÉ›Ã/žú‹s–üû¶Þ½æÝá·.ÿ­páò уr'ÀAy,wØGôn¾€F¾Hpr%~qiEIÇõ~ɷǵw¥±ââââââNxÀÅ„­úÓ$ŸÐ5¾…Á„Î8˜q0ÛF]7‹ÉUŸ6m£žHǸ]›c,ŸØ‰1¹ UvØÖÃ[µ³%Í­$÷ú¨t 7Ÿ£9/©·0.Ò€*;¡Š¥'Ô˜1XN4! •§)þ¿ñ×MLLÄ·ý­\¹2Ȣ쬟Ýûløî«Ûÿõ@€ÉÁ"À¼Á6~7Švx T³B ‰×ó©÷åfFKs7z‰¦Ì;@OÜoa_¤.H'9]¬7A,0ðü‚šxÏ{Þó«Þ_«W¯öÕÎáß{å{q¹#IÒŽõ¥ Ô‘b´Rô€¡ˆV«ï%$|xöÛÑjv ‹Â8°Émâúø€k’†›nМÝ>®4ȃÞP´Ÿhí¢yôßÓÉO¡ÉǶR~C='?¬½œÍâA¦oCF›×Ÿr}8}Éé4uÌ ûøù‹>\𦠟úb8rôH—Ç&–N„ñ)y`R¶¥ã?)8>]ýTäô„¬+|9Ù—‹Î7Ö Æ`¨ÖÁGŸßŽAÅdñ@ñ@ñ@ñ@ñÀ í†â‡aq“Új°Ý¨Û$Ÿ &3²ÑnÊKë6Ð&yO±lÐŽ@¥§PE”¨ühñ’lZ7ÜÛŠñxhÃÉhL "hÈ`¬ÍH ûw\²6þš9H*ȱÞxãØ§÷¾÷½ÿF*ß‘·ÿ#G#ŽÌƒi‚ôšˆªQ Þ Q°ÔÑ…•ÚYqù$yO6m#¡¥2´ƒÃdÏtdJ³|“aôÁ}È´'I3lJ®9éš /dÌôôX’.:í¢ð¹«?NŸX+?(?ˆGð“ò‹Sr"`ZNLã¶ÉmÚ_¼68û¯¾±ñ óS[þ ¶µQäú÷«â“⓲Ê(k ¬Eµd0éxj1d†?P^BòS;ˆ›•›@¬€Šj”— qˆ@unŒ_«¬È>&й+>âg™=‹ñ!§ø´Jb´ùðË¡ ,ø9@äZ¾X.–Kú™·Éèb.›¯?áÊb~€ž›TòüBá¢ð4¿¸&–-[¶TÎD]ë &¿SéYóŽ?¿ïùð°<û_ñ“áÉ@ €†ã.|¥¡·ž/t½C_h õ€}lÏïFÕ·ø÷ B¤¡nwýW6z¢˜êx®´ÒG¯ÈÙÏ™\!fŸ½Áx5Û>¨™ò*óc᪕W¹–Ž/ºîäuás×þVø÷÷ýû°íà¶019&¦'p^B˜©¸àò‡ßľêp'€®?v‚6‡$ ùrT[E¾x x x x x xà{ñ‚†–¬&b‰ #Cjl5+Û`Wã_4‰q¤2ÉøÔ®§™¼ÆÜÂThüJ]¬|žÒÐpiOiÀec åë[þÍ¿PAÜ®}„tLiñ™òó£!ÿ(w¼÷œÞ±æj¶kȵvíÚ»…\ 9ÙáÃrUªwû?r6> €\Î?€: ø2bs1(õ2ˆW—\à5:dch÷1¡¹ Š ÃÜ(‡…Dð‰ßýÝß½MÏøÛk¸òÆg«›åñ×F¤Yÿõ `PpŒTiW¢ÐíĀޑBYÀŠbœEe(æåM Æ·6©[ƒÎfÞTù™$‹9=X6µ#ôœÅgÄ«Žþúœý¹KÏ 'ŸDsóW-_>û¾Ï†µr'^ Xû…€£ÕãSþQ|añøŠ/ |ÍA‰6çÀV1Q é]AÖoZ/“¡á;;þ¢ŽbV*š“‹:Q²Ò n¥Ø³®Iî¨K=¶OüL<ê@ßÉh_)ïèÑæDÏ’Rw€œgµM0ckʃôfÅ“þ£-œ¹Åm÷](ë°>üùýöÙ–¬XRͳ¬™É±IýrÁŒÎ=Î(ËpÌ…® ìY3(ƒ|8sE¥x x x x x x`61¾ª5ÕF·IfTz­a«äl´¥Á„—ÍàˆwjqbFfjrNFã%4ƒ‹'òÏ:t)Íé€ âeÆÌc,&öh+ÚAN€9‹Õ¾õÔ·ÂÏ]üs½cŸÈ¹Ö¬YvìØ{ö3?ó3ÿæoÿöo?%„¦üwØ`Õ;À¹Á“ä5y5¶·˜Åx€™›'ò8ñ<Ä…:qB}ùß)§œr¥7ˆRÔvrÏœgü›[¾=Æ&d8òÏÛ†ô ú&#ÓÝŸ1trÑÜÓ‡­˜ÔÙƒ¶•‡³ (*/‡ ¯§:àAÞ H¨R‡<Â&:ù€´íimpß~“ü°ùö6<žÚă,ù€ø{ÓÄ›Rǵ¾ëµ]áOÿþOÛK–ËMÿ²Å½ç]e;"³‰²æÆ&«u€›¯ð€ÜÆäÍ5˜¿Q ý0ŠN‘-(((((8†ÀWù S¥Y}¯K»Ãâ0?ê¶meå uLJM¶©? =êx:p>€dßñ”níCcVš¥ªÀk›FŠ• µƒ:däOÃl±­ñ9Ú‚m»Y>>Š`2o~#Üýƒ»ÃMÞ”Œ¼Uÿô¹Yæe€!6ŒŠ8f¸yQ°Šz®@·‰—“_p48c1.ûb̤q‘ N0nò¢‰[%y‰'K°qª«å> £CÂ5hÓþ˨U†WoM‡ÞQžTA§Ícð €%z„)]eTYÅ«Óu”Áô>Aì©3ÛWÛè ûÒic#Óå>RŸÒ|¾ð§ÿêOþUøÎ÷¿#?8%?ÿ'·ûË­þ“¸í_ ¿õj*y_Zø²™Á´ôù¡ÏS…P·ŠÖ³ÇŒN´ ˆÊŸÊ“G]tÁ䄤6kŠUQ™ŒQmdèÔÓ„±g†ä¡°}¢éÆ•XMm¤u/ފǦ<³·{,ð¿úú]áó_ý|KÆÂIJ‰05!·úËÕ}$ÿ¸Ò?…·ÿ•+üòöÿ©©É0.¼iœ˜’‰Ð߬‘þs J‹9ä£c1Îb³x x x x x xàxy€ANC{ˆEc٬팬eeÁèÉ#fÕ ‰l¤C\KO§§/4‰¡+UãkÌ$ FSc"ÒѶÆÝ¦+±¾¿@¥1´ïŒ›¼òT^hÈ&Û‹¾ÊX›‚ï}ýÕðíÍß?qÞO±{9˜ åh#=EÎÆçUŒx©áp:h€'\Yl'0‘iñ4N>p@â¬jòÍ5׬[¾|ùÙ4Úõ—ÿÝÿâý62ölxÕªš®zÖí¤€zDh<€­4AzújLm£ ÝsL2”Uz4ar°#Ú†áÚ®ÉyÒiÓDú€Ù×>n3¡m¢é®9k¾ÏƒlŽÂC›ÜŽL K{¿>™ëœÒÐîŸ|ùO—¾ù¥0¾TÞç/g‹øOMJ²ÏMÞO Wýå‹d PtõH+Sß(Ílë:Êôx2â…T»çÙª 6J$ÏØâè…+=Ø( ÒôˆŠU²©eúìA×Õ“:!Ûˆu“ÅÁ*-©LÊ÷õœ¾ç|PR^Z÷ýÄórpÙæ76×Hs]Ù¶k[øÒ×¾T™•=A“}œ!FÂ/ >¶‰¥'M!~%›?`g—yB kãn=v*Xþ˜±‘Ù(Ú²±®ð<=â‰NJOcsåCÇô<xäc¨ãÏ.Fÿ˜>èQ^hˆ×¾úüWgãc¦‹œ ¹‹ô{âsŸûÜÍRGNÇ|#cŽGÐQläzš ,ÖÅr@Óü¤ŒÉ÷›_šøâmo{ÛÏz£]MþÑÇõ/­—3u‚ÈhtÀñl vd¡)WøñuÝÑaWÿMõÀ‚A»U¥­:H¸¤¶! öT‡ÓåAFa´‡\ª”h£ªê§k¥¢š¬´O*²Û&<ãûæ6|ûýR=ʰ¾T|ÈWÛˇ^Ò—â%Ç¢|ñ|1LNÕõ¡Wý‘ÀÛ­ýãr`Â’ü‰er"À¶%Ë'ï À#²©®Ì!ל­Ì©¼Ò+èX ¡Ø,(((((8Þ°ofÍöâ¢ÑõGÑm+ÛBnÐx•‡8Z¢7\½ï“5ûBGÜ‹¬·Ð² ¢RūЭô5Ü‚ ø•X w(q™]ퟖëãˆ÷¦åEÓ¯áSÐU[6©ƒ÷íg¿þéEÿV;Wp€\ñýºè¢‹>"•ÿ[6Ü€#·#Ž‚†Mœ7ÐQA?!Êb8À‰óšßÀóuâXÀ}ò?~Æg¬—K\%¡í|ø•‡ÃÞ×÷VWmuTò=]vlŒ +¹Jº«::_íäCR¦øTyõ†Ã«ŠÈAödó…6cÂYDû©XÔñöZáI Ó;ö[ÄóÒÃ’ÿAvÚòÉùqÀwÜO /|)œ·ò<ßÝ9Áß8ôFøo÷ü7\Mþq+?OèÕ¹ò«ÿ’ø/”Äù’ '] À£²;É ƒ¸þð傹ÂZÀ×Ûœô¼)(((((X°@LÀwÔAäto0ðtö2$Çí¡Y¹œÍÍÌÐaϺ`IŸU¶#ÓR']IÔ1H»ˆ­tÓ¤"1ë©b/±‹¿h³W§šÆk¢ ±©ÈiîÀMw÷þÝá¾-÷…÷Ÿý~;U›mݺ5öiÅŠçžwÞy'oÞ¼ù¨™ìó$ N`t~“j5béjðP ŸÒ”±P?àœÅT8¡~L¤yÈEˆAžÒ?ûÙÏþ‚$+ iÁÏMÈ;Xíüî¶ïjïÑÝØeM¤I]“:È ¹Äõ¿ªën’ŽLøHÜðåáüŒ*B¥ÖŠTѫš©®c CõÀÕ 4ˆ× 22yPƒxiC²â›§<ŠÏIýÞÇï ¨æLV?æWõ'– ñGÒ_mK–- Üð8€n¸ Àp¾/ Ô—&ë¬ÖY›ë­TŠŠŠŠŠŠŠއŽqÒÇ¡IûWG‚ Ö'ê*ôý„Ž‹ÁGfOi C&“XŒ:‘.| Í©µJ5ê¢~ßïS{]ûXºtiH~ž}ìŽ;îøŸ¤ŸÌó8"æz)|u!é‘°ØÅp@Óœp29‰„˜ü ‹C79{ôao´«/ÿÓŸþÛñ¼î¤þ¼”îøþ<•àú“v5èØן#ˆ3|œ#“‚ƒ ^25&· MÁ€+}9p iUùýPmöðR¶!½+uƒgÙ–mÀVŸ®kÀó<îD"ùÒ6|ã·'ö?>xú£ì\!÷Pˆw ðê¿=F€1qmÍdnçf„ÅJñ@ñ@ñ@ñ@ñ@ñÀ1óÀ€ðnX›Ç#68mäÆÛàŸ(C&«tÁ É$Mãt‹Ù56G‡øÝ6ê0v¯ÉPÖâz𸩾£k;bó‰W$^ì`yó›ß–,é]Ï–;¶ßŒ\NºÊ\9FIš±Ž#Ki¨û’Ö=oÁápÄb)¹‰ cLqÖÉ×Eññüc&+ è­%øô.–G_~TG%»{e#Šƒþ<ÁÈ@·¢ˆÜ0!Ò«¤¥N›Ú6:YÊx¶Š¸v½|*×Ww¶Á”4âõÙ=„QÚ$ b›”¿û6ÎiO>^ØúB<Ùƒ5 ·ïK¯/÷‹/ÿã;䤀¾ü¯z<@ïÀ{ 'ûuacÒ5%=ÖuÀž'sHrÅÅÅÅÅÅЈeF‰gœl-&â`…_£;yˆh¬M™„§ýHiP’˜žq˜Ú`ìMY@ÙЮþo4ÒUO+!<ðƒPí\Aÿ“ǯüʯü¢tTó:q@Ž2‡ »V »(Kï”Éâ'—ŸÖIðì³Ïþ ïŠSO=ÕW;ƒ?°ýðú¡×õ6mÜb7ÄkÒ¥ëºê¦Ö¹Cƒä—±à‘/,Ü ÄÇ ^¥R)ù:d]Ù„¨ˆéÊpð£Žô¸…LR°«Ý„ÞT­ÙkJè9Í« êÓ ]Ïó¸·M¼ß¹Û¸ÀGýá=‡«N½Šj³†HþÊÛÿõ6~ÌŸ$îºÙíÿñ$îp›Þ% uüL ä©6½í'°¦ü¼b)eæ~Ö)ŠŠŠŠŠŠæÏ³øng逨ªkÉÊeì¶•‹ýJläô#ÍÉ2®ã„©ŒðSY/—Ê(ÏUi¬hOâ¯ø(0EL†>b{W`1Ü”=¼ÿõýá[›¿®;ï:'Õ '^}õÕØ™³Î:ëRùO²ÅüÎpŒ4µâ86ÒëÎÂb+pÂB-˜ _üÄy<•áÄûE¡Ï‰\xá…§È­#µûý»zûÿC/?TÙ“‘bEÔ³} !™3zÅÔOaTPeÉ :¨çø`S–8åYH] Š›-­Û‡ôªWuhØ€9Y”æ¢ ³“ }›ƒt=Ïã^Ÿx?ÎÇ-ðû¯}?œes1`ü¥|eHƒ¦!H ªsÊ/´{_¸—½íLs5ärJN'ä{|·Q1ôã=·¥2¾¾`ñÅr€[¢q9§“ÈÉOšÂ_ûµ_ûyáE[é-%]™e¼üoóîÍ1ÑÒ¤ ºŒ"âRõxmI›hz°Àˆ)/ˆ¾´ÏhàÃe‰×|avb{živ=)Åc)ƒuôÅŠ¶ÏÊ0§—£y“ƒøM¼&:즼´ÛÆxÅåʧÿ‘¿ ¯nï[û¾(:dÿòÒ¬|±­_‚Ç+úruÉ>®òãê¿^íÇ^õ_ZáªoOWá,1¿pâØ0–RŠŠŠŠŠŠŠ<c†~¹µb©ä w“Í}`;ˆsìºTV®¡íšl*Ã: þ¬ïÔQèyÄõç5€Œ1$b@Öî:lÀ'q-²-¬§RŠŠŠŠŠŠŠ‚f·¤1rßý¬,øN†ú©¬ÖMÎã²´E9Dá»Q&ê¹AÛ‘› ï +ÿ]}`š³YN‡Ñù ¹Fe£Ž8ëê|Xì¢, õ€tBXô'4N0!èÀÇåy‘•+V¬8› €ëÖ­ëíž1Ïøc[“A¢ëRì,ëܹ+&œ!r"C>è¤E: qÊÄ:ô“D_yiÛ0ZS±.+ÛäÔî0áÏ4éÎéåh}]Ô§>áŠ0ÈnÊKë}&1fþ<‹àêoñß3ûŸ Ûng®¨=©Ò§Þ†€÷F°ð‹€y¼Ôxúr?òã¼aNeC=® }>„j)ÅÅÅÅÅÅ Ð3ýÞ¦×ÀGÜ“ÕaîÊÙ˜Kmºþdû 9/KÜèª#„8l³nWéÁ«È•!Ö•¨âB§)jOôkvA—øozÒèrW½@åüÁƒáÞù ªß¥äl/¿ürìr:äv[·n=*DŸ÷á$~ÐÓ¨gQ­:“‘,¡—©HÊ„ õ€wuµâ+ q@lšÜ;ÜÓÀ‹w|úÓŸ¾ÅäToÿ×$GkÝùxdç#ᵃ¯Ugñd4ØI1ÒxÛ¾týF‚ 856¥I\äÃØdô*#Ž“:„ ëAAvþˆÃ®üQ†6à!Ðñ¯€è³‡, !pÕ2 xùbYVÝTfЗI*ëmË$çíá–zÈbî0€“c“áÛ;¾n;ï6/:#|Õ›VUsŽÐÖ†î9Ø;p„püéq™C¬ØÐ/Ì!ÿ´#½i×jù(((((((hô€Ä ƒb/MR®¶1U[¹\GÑm’MéZG¼Äq™4^G'„NÊÒG±n1¢ÊJŒ]•q¶”¦–,~“Ä^i&˜/o†¡ÿÀ‡aôqxBÛûúÞðÀ–ÂûΞ›ÇQ1Ô¹(È3ÒÇÛýæoþæÅ>"Y&þ6"=­:ÄL`uW”þ‰/¶â'¸ß0^¿§õóÏ?ÿƒÞ§œ‚wGt¯<ºýÑ*±–ž×l; 4ò¬-gŒZJíjnEªèHü]òYÞˆf'Â(ØŒðà¥ê¹6¼ªØ×ƒ§€·ÑMe|ÿÒ¦RYÏŸ)ÏÛð8ú9ðó©ó%´ûvÝŽNã„æìÊi§ÈϤrNÅ”¶'ëH¡=i Û¦:\o”ç\rMÌ®kE»x x x x x x xàØz`61Kª›Ö“žk<—ÐZUi×A‰Èz1¸3¢1ã1£û8NI°ãlÅ8&¡ë!b=O™6wó'ÓÜÍr;æ} qBÐÒÍF  üEWà€…^Ò‰cãBÝO4pÊ(]Þ9±råÊs©ˆ[IºV^<ðbxjÛS1)fÒ©wHg¹ãÆÑa©åw4ò@KõYÔƒM6Y˜² !mǺÉè™CIjÉw¦QޝQ`c6ºÌŽÌJû‘Ösk'!l^âËÁøÀÔðàÎsª#ÑÎ9ýœ(OûºÔ3±'î¡Ì9Æáu¢¡‚œ˜ÈÅ—'¦'ÚÚù,ÆÎFc=…4ºò,VÔº¨ã1:¯aG¥ ‰1ªÐAtABÅѾ·ù{aÓ¾MJîÒGš»!·CŽ'}ôy Ä\ÐÓ9ðý:ꋪ,ÄGü$äpNšŸTO„nwÜqDzÀAÓròÉ'‡‰ °ºUžyõ½ýFwZôVF‚Ûqô6ë>w\í¹Ép™Ç¤Þ0¨t1[8`ø$UëBGmÈÔ l°xÜhz%MŠÚê;*õ„úÚé±Za~ M ©L-ñN”RYÏnË$×g.WCGÿàw̧mwo¹;\{Ƶ:_^wü”“N kV¯ {ߨ[©q½ mnÖæC7é ÖÛÄØ„ö«Ö^ÿ4ר¥RyòŽ*¼ ð‚UˆBw r7äpÐN!·CŽ÷ðÿCÌûðü?GÈž 7`ƒ^„ƒ·à »˜ & …“é!ÆŠ: q­_zé¥?#´XÒ[H"cž‘G¶>"@—­ŠD[$“@Õ# êÀm£¾BñL´I9£ˆ®Êug•eõ™hqЙM™­þ(mjk¯©FŸ™¿õʼ\ßrxKøþžï7™iM¿ø-ë\rýè\ºµACqMØúàÚ!¿Àâââââââ™z Æ’M›dÊP½ŒÎ@RC;ufÂlh'ë SÖ BFåËK°õ CyôWpåù¾“o<9™cxž(ß¿in•Êwc6xšÃIŽ÷³by 7Œˆtà~“jÍ[¨/ª²ïH'ÀOqÊ ž›hÒtâ奒õÊi§É³Ñ+÷l Û÷n“Û®ÑeY•0¸€+ÊÂgÇ¥ !)YäôÀP©÷è°„Ût‘ÿ*¯Õ]ÕiAÈâ`b:,J«*>‰­.–ЛLF}ƒš4;[ {hµmÒÊáé„zéRÙ&¹:µ¶6*Mï7ÚªæÎj˜;¼•Uüƒ¹ýï[ÿ{¸ì´Ë(:#xéù—†‡ž{Ht+»ÕZ€)«c.t=À ü©TŒ‹›°ãÚ^)ÅÅÅÅÅÅ'¬7ôŸÝ0SŶzmårÝn©‹˜i€(B¦4Þ«Ó ,üˆ¢¶äÃ`%KF«!B‹6bû°=@Äj¢ƒ¶4ž\ø¤k¶Ä0rW]h¨ªfTú UÂ{i׋áц+×]©ü®| ‡Û¶m[ìŽäxo·îcÔU‚†Ñ³@Îo Wޠć í&ƒ…Ã: i˜HN°§'Oo¹å–[~D~êl9”QäyݪZw>Ÿ{õ9éŒtŸ£;§^ÙW:ÕêDB¦;8d€ÈFšââ®bh©¬|Tö’ Ví¨œÉWJF‡®Y¬’A(Zñ¶Hk€´ÑÀJn«?L.=07 a”×dêæw0L <­âH­Ï㇧ö=^xí…pá)z3#áW½ýªð_û µÍvPÑö”PáSBÀNHÙ‘-ÂÅÅÅÅÅŋ׈fP[ , ü¡zf4+—³™¡µÕU¹T?©ÇjDªø ݬÚAü.LðUq½üyy“£CÜ6µc¶Tôž)ù™i3«y#ÖÊÎR¨¬U'$EŠ ¢ûä+Ovîó¸7ÞxÇ/¡-G®÷å/ù ©"÷ó?˜Ëé*h­°> êÄ•°>0ðÅP0 œâr‚‰+ÿ†nøçÞø ‰.–ïo“Û½m„L²Ú(õD€à5ž „2º3›l:¾š®Ù íA'ÅaSÿp €í¤T''Œh|oËkÿ@ÈØñrÇý¡áT'­çL¥'T&õ…Ôá?}pySÿW^üJÎ\kÚ•o»2,_jç¿ì0ûÂúã[”oÝj,((((((¨{ )F¬KÍq-µfi^Ç0ÄfŒ\vìà7Èxy¶ ˜âÚ–³áE¹·Æ¢ Ô­Jƒ2‹ÐÞô0k‚i.÷Á~¹žÏÿ|>èé6ÚèuÖ;5¾¹èÌB» 3'ÆCÊÆ‰%?¾víÚÚ½+颡±ù„ßÛý½°ûÀnMøÐ½eG®#±äI¼ºGxz[A¬c1hZàÁA—¿4Q…mo×óÙnÏLeÔË7WpíA<ßþ0¹4™m’o¢£­A¼?mÓ÷Wq¸–s†y”—¯ðæ£{ Ïï{>\´ê¢>µ6$ÿW\tExè…‡´ßè;úƒm ršx|ºZ¤G‘-¥x x x x x x x æÄ,3 cŒZZë4ô«~ö»lN´”κBé¿k4ã¦tÁ|ìñStàøŽøÒn1кñ4þt:ÞÞîý»ÃÃÛï}ó{9ôN@är¯¼òJì‹<pU5rŒR7‘Ž uà„ÀY(Cúè‹“Ö:1à…Zü$q œ$N$¡§ãöÐ'V¯^½\~b-•»øüÿS»žª-M&ß¼Œ¥K<òp‹Žæ<åÓ•HE3OQ_w‡Ü2G[´@ÕÑV­]ÃI§É}ÐúÓGf£òròmiƒÚl²1Lg¿É.}¨ÐæO_Î"'‚þëæÿÚ¨Ö†qã•7V‡4Ì7çÜpMúqÂ!¡«]ÒÚ4RdŠŠŠŠŠŠŠfã†8qh|9›6é6ôGUñD@ãs:¹Ú8ŒNZ :Z[^GpèP¯?:ºÊX'(«úcz=í.bù×Mr‡ [7hºô‘ær’ë­AÎ'}Œ9 à¹#óôtXà/Š‚A.”âžÃAÃæ'Ž4ÒÉSø©O}ê&ÓQtñê?:¶q{õ¶w "îtZ‘ªÀ µy SÓÑ Ô³{€ÐC¶VmZ…^B¯ UvÀò:Ö¨Rz¶j2ž>‡xõò9׿ m³3‡¢ZØf§ Ê mÓÍtpæ/o—Ûÿ ß÷½ðÜ>¼#bfåú+®K—,Wþ«¤_®þOMUgƒqGp­ƒÖÎOc³_»Å‡Å‡e ”5PÖ@Ye §5Ä^ð»ÆÌ-bÄc2G™þôõ ñ!c{ôSyó—ãÕÆ»}bÉÞx5UP[BÖJIÚðb÷N`IN7ær>Ÿ w#ÓQæè0‹Â¡§¸2ʸP '€“–Žƒt@?‘Àu{ûÛßþ“^)ýéÏ›/ü‘]„×î׳pØýÎ\wm¡|ôöüJuðW}<:@=!S__îÁ:!õQ ª¬ÙS}ay›Lél?Ò¡ã·´OÆ“t³.çuÆgmåf*½am¤|¼Xí ƒê¿¸Š«9 r@7™Ó/oú²ô`f唕§„käZ^ñ×¾iâ/§;ä܆8øŠK“ÊóxÙŠÊ(k ¬²Ê8q×@C\7,>/.¤5E&}cuüHƒ¬£ÃoÊ#ÍÁÝÚ€¸êSÎèÃ#€@ÌDˆ¸§›\% ùÞîxí×Âú­ë¡Õ©’æt–óÅP:ËÑÄèÚh¹q@…°ª-àO z!N€‡À¹q‚QçÄ’F8!g‡ðÓ±¬Y³&â]AžØù„î`èoÉ!®·€ËË[vⲤWü „åÔ@ÅôU&ÑÏé©6å};sˆWéq³ÁaüfÍ~Ÿ{êçÔ)3ms¦zlÝëÇy—¯Îœظocذkæga?tÕ‡$‘—Vìs“ŸÔ÷ ÈQž4|cD9Êâ,@)ÅÅÅÅÅÅÅÅsê46÷q¹ÇµQ›kŒ(Á}”qñ½P«¬)í)e%´SÈ,æìkCèn}4µ2ïõ4§³œ0ô9"FL:p¿a<¨£Vµú¹P^èÃAãÆÉÄ”ïƒW_}õ'qÞ–.]–/¿Hò¼Ã§¶?“+ÝYÑ#©¤\ºc¯íÄðŠAÈaçÕÍhÑŽˆ)¹6ðmgö…¤C‘•­e9 ð×?øëðî5ï–_ Är­\wÙuaíÿ»6ì9´G×Ä´$ÿS“ò@²M…ñ)y) OÀwX;ØPÙ7%”ââââââÒŒ F¼y²ª»Cuh(£ VŸ~F®OFiØÁTWêÙ8ÑäÔ®ÃûÚ¾Å[‘Gšõ=ÒYG@¦ÿÒrç¢/úºÄlÀµ¤ñ›Õ)«rN†ôÇ_|<¼f¯C9r»#GŽh¯ó!÷{ðÁ·£èË …†Ÿ$Ï»çˆÍQJËá"²0Êè™B÷Æå'Æã¹‰MÏþÜvÛm?뇒<+âYó†oع!8t Jð°Ö0:n@yõß½uužõ£¬Oþ!êíibCuÍ–ÇiŸ¶©˜£yþBÆãrÄAÌTÍÔôýÜâl¬¾  ‚[n ßÚò-ª'Æ'ÂÍï»Y{Múõ™iÙî ”çbò¯ ðð7RkE¸x x x x x x`Ñ{€1Ëqhëøó8öi¤a»x;7Ò‹÷áMcKèÐã†>ªÊ²óR÷²1o‹â1€‡¶>DÎÀ4·³Ü/æ‚ÒÑ\®Hz¼3ãš‹Ž`à ±pRÚBŒ““ ñ³Ï>[zî•t‘ô8ó‡=¹ûIݱb¤çºÚé@0*”$­’¨d@“-îÔÀ•@¡ êA¡N2FŽ8ZÚ71QKx3&‡ñ½Ê0Ùô¬¨×m‹k#µ3J›Ñ¶ó“Î’l8ˆËI€ñ‰q…_þá—áÉCi“­ê½ú£aɘÜ„sžLôq'ÀQy{®øÛ]z2@Îó.œU<9ÃܪÑ"T¶ý1“êHs;Ëýjù ôÖ×½áÝä {‚A/´â–œv= ?‘À¹A.â+W®|‹øé§Ÿî«ÀŸÞñtÕéyÜÙ8ZpŒAwF;~Üy©GȰ¡‚/…‘Ø^E®>MÆ“¼êz~Žæù)Þ”aõa|¯6Ь×#îõ=N~˜ê’üçì׿sÉq`ßÑ}á+›¾’SJ[sÊšðS—ÿ”&óz€$þúK|@î Ðd‰¾ ˆuoݱxzÁ‹ŠŠŠŠŠŠŠjˆ±²‹³# ’ŽSbB$ú7˜ê!7PÄœ>iä£7»Øå©+zhóñ—ä1€Ž•4·³Ü#ˆù ÃAãèò6Y´ñý² z; ´;PÛõXxõõW«‘ ? ª¶s*] J®ÉëŽéd±c×Jb3²S1HH3HÛ5{£VhÓôÒdyTs£ÊÏ6G{Dzσlëü»ä_ïX"w, _}é«aÇ;Fu‡ÊÿÒu¿¤ïàÕýé£Õ»ôª¿ÇÝ; «EÀ\øtF/JÅÅÅÅÅÅÝó@ëu¯ƒ §GŒ½ ›GœÃ ¿› ÉiÉ\Bhj§IÇÚ‰mAÎ6=i ñèžý{ÂÃÛf/:Ñ_äx,R_‚Pê1'4œ#bîÒQX¯jU=‡“Öiˆ.´â'}g8'tsâÆò'ò&³¤·ˆ>Ÿðé=OËÕ]ôÉ•¤‚ü O©yºòñž(5(4ýmO0*QVéî÷BÅ3•)Wé ï¯éª!eéÔíÁ¼~ïmKš™i«.Ûœ×å`·=ß~Š{}§rƒê©Þôôð1Ò^ª«t_ûmVÃ1ÇXÜÆåq€Éñ£á‹Oÿ…øsôrîéç†.½ÁnùÇK'Ã4î—N㽊 u} ·ˆ¿ÁóãÓÇúç…ã+°ø¦¬²Ê(k ¬²:»g¹:×fäªx|´¹¶sö\šlG}„~fCÃuùOù sKmÖÚ¥ ÂÞX4ÞƵŠúÆ…Ø­’æx–"ÃâQ'Í㌎Ôt@cüãUðÖs:ÞCàÜ0‘L¼üO_¸nݺ+åä“OîÜ•Ë'·?©»fuFN† ÿøíNœiÓÜJF¤<9ëVíÙ2ÝÃ1,ÒJÑßüªä ÁîÊ êi[àƒ¦²QÔJöXTŽFü>èdšû>­>B“.»Ò§`„aWª½¾Ç½½¦¶)“ê¥uÊåà0YðUó/”»‚$羺!<òÊ#áª3F-ë/_÷ËáëO|]’~9 !ۤؗÄR¶1ÁÇ&Ç¥ Iü'¥=i3Èãh}1Tëå£x x x x x x x`DhŒÓ¤ƒ8##!5Y裷Õm+—6ÐF2„ˆëc¼jcÎó*9÷µa–êB‡›2À“„òÈ)ÔfÌ!DXOÀ†p@G!•¯hÐ×x|°ÅÐc/>¦/ƒ`w r¼W^y%vÈr@ŸòÍÿH5™ÕI4/T.‹F ²NpàæÜa2I'Hœúãr;ÈÙ0²zõj¢€Ïî{6ì9°G®êÚpè-66<à(š€êþgr±±Ã£.–-—.ø,¤æ ̓Ǧ|8ë9ý´aIôÕFÖŒlºþ{}76˜a¤zi]U\›ÞDV¶. ëË€wœ€ÑMÖ Þ0=>-w|1\¶ö²°t|©×ŠŸÆùáÆwݾöÔ×䊿ô·þ‘+üK+œ4´1=! œ(Г@‚ãfàÙµ6´õ"P¡žH]ÔwîÛðóKÖ\âµçOs<ËûrCé$i€<)œÞ0g©ÓàÖw„º@J×Oй9w’èq?ä¦Û 7ÜðIN–Ñ ~'r|¬î”gö<£gæ4‰²‘IŠÕë Ð4ÙšBœ…ÿœ}ÃϹA–tî P&¸zMléY<%â£*^6z—< §Å]Ö?¡£¨>i©÷i2Q§Ç Ëéçh©Ñ>çZÈz¾Ç‡Úq©^Zw¢}h[YÈ©,–/Æ`«\PÞ°ãÐŽð•|%Üò¶[úÚFøÄ Ÿßzú[rÕ2Œ•–mü¨¼c8®üc›ª Û‰?ŒÛk§ð‹ŠŠŠŠŠŠrhyÝV:ˆQ’ØOãZ½ÅÖ[ëÇ[ÙïW«â5ÐsmS^xˆå5.Oúcu¡³ ÍùíŒa£°µ ‚°w,J»}2ºÒ';Wnhs¦ía~5ùÇ ÛðÀøRyVb2üÙÆ?Ó9µû·ÿØíaÕ²Uõ¤à±¹åI¿þL n³ÛÍô2ŒO¶r`TùâââââEêƦ‹txs5¬Cð—Êx¾Ç›:Ù¢}“cPSÚk‚0…\q§Ë+6ïܬô.}¤¹Þ™gž‰\ˆù¡ÕIÌmB^¥ëИԣ–BMô…ÏIõp⤓N:Gµíã´ÓNóÕyÇÿqÛ?ÖFƤ;pÝÉ0"z¢ªÅ:åx7€ŠÚΩöDö´.Éêø£,tµž¶¡*VÉŠ”Úè‘b¾O0›Úk¢{SƒdR^Z§&:ø)/­ÓFŽ"«S…D[æzúÇ4xÕ¥$äz‹¾< ðľ'Â7_üf¸þÜësÍ6ÒÞ´âMáã×}<üǯýGý¼`j)^(‘Õ!¶õNœ ’5‰wŒËk`q»U\?Ö £x x x x x x x`€ã4Ý–øqPRFŠ¥f ;Sû5=ö0éG®ªúGÁE|¤ƒ†8PÙ¥®þ=ú2¤i ‰Gì1¥Iûƶ‘ƒ°}Ä~¸ ø¶}í‡_ 7ž£šéÂr½Í›7Ç®H.ø©è‹ábD~Ã(Pw#ªáÂÒ:œ ”Êá¾ >1À…XèpßwNhÄkð­o}ë)’œ¬ ÒÄÄDçžÿbçU÷ü ×äŸô¤2+Q¤¹âR'Pœ O(ÙøjKgö¡ˆ™©Õjc»OfÀîÚ';´-Úœm{˜¯xõ_pÜ€ä|\~wüåsöÚÛ²“=±\õ‘ðö3Þ^Ý ¿ àDoÿ×/|‘àŽŒ€_Ü ãîµT°ââââââââ6`L^‹×èûx¾)†§Œ@ÚB»ˆ%µ¯ÄŠDó€^ǸU!•Ƕ<I]@pajÉ’Þ5o©/¿ä’KðxŽ2…è6ié@o*ƒxM:óBïò €Ô‰œˆagmkÛÇ>ö±ë¼—ÓgB!žu¯æ neúú5È6y„4’BÏ÷¸Éecr‘룓F„b'Æ•þÄìCÆôÔžË(ŸÙö $:UÒÇn»í¶ë¥ƒµ<Ñêè6¡PD^éYX}O'%¨´®“yÁü?Ìt1xÞ|à÷l ¯~=ž}ã-:8hOJ“ĽƳ+­1ù”:wôš=IÎhOeM²¾ÞçxÒŠö‹IÞ€+¼±/Tœ!ÅN*›ÖÙmvÅó=N>á(¼>Ùõɱ±6ÐlêÜ ®¶lŽpÐÆ‰\™Çíú÷î¸7|`ûÂ{ôѧ6Æ+™Kßriøð¥w?yw˜<"·ÿãÖÞþ/öñžx#•í™x‡L}@Ö”®AôÕ­Ÿö=(’ÅÅÅÅÅŋ ±PÓØ4¾idæ}qU®Í -ÛV"×FF{•è–íWF1jl‡|ÐÀ`q2* –“!MuŒN}Àhjþ1؇-+”Ó»;ILyUÃUâ¼×¾ÛñX¸|Ý副üUqÑwïÞÞ°çŸþÕÒ›ÿG6‹\#LsHÔñ¦+/'Õ…]0¨…P˜6¢ÏéD ž›4Ðt[µjÕEPdéÚóÿϽú»¦£CÒ¤‰“ŒLÏÀËQ'¸¡±îuŒ§v½œà}4´+}h[r²<Øh¿Ûš¥\ls–vf£~Üú`Ó£¾·yÖµ"+^ïàcx@6¼pÿ‘ý#í“×2¬^¶º÷€¿@ð/ä ã—¾xÊ£#û¼(t˹XwÆ=bÒNŒ]Gjú>Vt21§HûÁ: Ç¡ëhñîä ŽüÉOú–æOs>9!pt*æˆçHÀŽBë¤y|Á”…p€w6›ÖI#†zm[ºté³Hh'à3»å–×cM"9*éam§zNú~Çg2 qXN1¨>_R™9yIx”ÏéÒFR/Ç› m{©lZ÷g6Ñ—>¾ë çy܉(šòÒzÚ&õûäȘ¤-Kì8ƒËʉ\µß}hwøÂÆ/„O_ñé‘ZX½ruøôŸ¿÷Õß SKäE€¼ÀìN.‘»ŽŠIî}ã]òr@]g#µX„‹ŠŠŠŠŠNx ¶åE„–Î`<ÅÅF_Ö@µ-m£eûú;˜GTÞú ¼O?iWã?»Ú‹Œí1&êV˜™.éÚÐð’@ÙÀWŸy˜à´m€oÛÆmCx§Zíć:$9 Þïz¬8X !šE!¿ªõ>AG”Í’ÖIï,ä»ÖA8ÒNÀ0Èñúmâæ›o¾X’Xòƒ¼²–$ûÆæ iÏKÕRCd¤Lâ‘<ÅŠži‚PåU{“AúÊ#ø‚jBR6iŽO{^x<0K8нQdgÙ­Fõ¶}h+ר6?qn¥Î»°GòÏ~{û·Ãúmë©ÝÞðε^«É¿¾ðpõ2@œ Ðwà%|) ýL`y!`k÷ÁâââââÅïÆ”s1Ò¹´5ý9Æ6bìq{†ïu™'€F\í‰^¬c,l£æôÕ"¿iÇ&E»òq!÷c‘úØ-·Üò©ç~ bÈ1ò6äYè-Ö; cBÜÉÞ5wÊOF:Ai]eßÿþ÷À›ëÚóÿîx°z{ºtR“7ë¬îˆ-g+]Z¬ Ty?Pò@NÒ ½Äx!¡7U)ŸMjÚh²u<éÙþZ<ÏãiÿñTÖŸ#L•çªn>Æ<`ãÙ[àøE¼Ì/þ*€< ðùï>¼vøµ‘[¿ó§î +'V†)Kþ5ñÇ/¸—âä€ ûBÀãá“‘GWŠŠŠŠŠŠŠæÀmcßrŒ­Ûö¦Qmئ2¬7Ž2žŸöÓe[¾]½è$áî€{^¾Ç[˜w<}ùûµ×^‹ÜÞðÐNùi}ÞÇ2Û,¤G¸ôüyZ:9¨Çmݺu—yg¥‹Àóæ~ïóÕ”Æ%Ò$·QcÇB’‰3møWœ4JÃ-ûFCÿ£,oãiTÜÉiW4yËì¢x»¥ÿshܯҊ2ŠÝœl-I<ûø®Wžçq'¢hÊKë©<êmdrzmhÑ6V?Æ‹MÎoê™Ú)ù”»𓀟üóá7ÞómLF™u«Ö…_û‰_ ô? “Gå…€Gd‘À¶ÝeÀòåƒ8ñ0>-‘> _Ú¬ÙRŠŠŠŠŠŠŠZx Æ5-d!2ª¼7;SÝ6zmd|_âX£Ûc}6ÈChe±VMD°r€Ž?ä (¦¯mÀ.s×y•¸(¤r•E¥?³ó™ðcçü˜šîÂGzñ÷Œ3ÎÀC 1W4žäpÒIƒó@3'‚ÜýÒõt:=™ÖAO'‚õ”Û>΢À®Ø²wKÕ=¡&JvFÙiõyjx(„QœKÐät)‚fô(ƒ: ÌWBæÃËÛ…¸çgÔ‡òs:FÓƒÌþŒXÃÆ;˶ûúܲ½%§”´Ç<š #ù·—NLN„û¶ßî}ùÞð£çühÎR#íŸ]þÏÂ?>÷áÁ— “ãr@’ÿ© y/€ü€¶ƒ“’äcÍâ˃_Zàa=€¦ýB_±~J)(((((8±<Ä+?H6ÃCœÚ*ËèöÅÅmdÐù¶ré@©G˜Ú"Ý`mläQõ–[´ãå}ß„®2vâò„%Ÿ4Bú~óîÍÞâ¼ãiî'¹áÙ:Œ*EDšnè3iÀ}ÞcIë¤wvý€w‹â!ðtã™ЉOLLœe©íܾ{YuÔ­)Éô˜ü…¾ÂÉ“â;ŒÔ «¨/ôX7YM¼˜€ùu %µcÉ™çÁ¶kƒmE‘ªÁHn‡¸ñ5*´‘©”y°ñ¦úh‰¹>¾WŽƒÃÞ(:¹~^³,ÕúuÈ™=ìÙÆÕv¬é^ ɿäQÁå.€‰¥ò(ÀÆÿ#\²ö’°fEíý˜C;ò¿ÝôÙðK_ü¥pàÈë’üË;ÄN.Çòä&ÍÜ&ÑÙðÒ@¿˜à.°J)((((((Èxa&/&dØ ¤áñX^ñXên»7v¯k8â'E{¼(oq¿8Ά‰øâA‡ŒÐH‡,pЪxÒdЈÚ3¨ºst튘E[öØÅÍŠ2ïŸiîg¹aÌ¥ƒ7Oh”êqŒuª¶€>1Ю•Ô™t:úI<1ê²>ö‘|äm’ø’V®\©‰1 v¡àÍìoz#Ž»Žn:Jù@×c÷%ɲYw1¡{ùˆc`à‰j¤wu4HýÀ:åÔûC(BèB”¡rKˆƒJl‡6(O‘•fãxó;Ñg›ß8÷R—KñµmLÞ°Ë €Ó¯‡?~äÍÛ-'PÄÖœ¼6ÜqýúBÀIyþ¿Ú&+(ï˜Ä¦/œ–Ê& F׌L p­'s~¼ç«´çŽ e.Üñ¦¬ß²~Ë(k ¬h ¸ø=÷Ï·‘Á÷=äLVªŠGŒÀ—†Ðs™n1?Ñ\¤·3[;pð@Øyp',t¢ DÈ‚Ü9¢Ôe´µ " Å\2áSžr¨û’Ö=¯8¶ JÇ{ˆq`<édËK®õƒLoñ¼ùÀ°ïÕ2cã2*,Rlºü¨ÒÁô²ÊÄGO¦ª5|Š.õ£h,Gò‡ÁT˜¼ñ«CHKaËÉ÷ÑôÖ³ÙÇï±²ö;¢ƒl¨PÒ&hCu¢õёԶ_CñÖ|\—ú‹r"ðñW_yö+#7xý;®?õ#?ðÒ¿ÉÃöKö2@¾P-¿ €_°_à:Šgó3~¹3E¡x x x x x x x`¡z`†1s®×\saÆ\Âó£RIekq$)*£ˆV㇗íCП8„ùGÒÐrÄ4dÆÀÓtÀYºþ—+!œÌI ÃYÇd¡ Î‰;óÌ3k¿D™¾JóY6íÛÔk½—„(&s.9ÂÎéÔ _ v>$U„L´àÕµSy‘OÖ&èµ¶=ßðZ\›ûúŸQh#ãÕrò9ZM¾h(^×ã©xÊKëêÿD©O&áÏ´Úg׆§I¶ààóe.¸U_Þ/Y½¼wÈíùw=sW¸üŒËÃ…§^8Rî¼ñΰqûưõõ­ú€>ç¯{¬9{æ_÷HX•fÇŽJ{8 ap½ª¯„_Jñ@ñ@ñ@ñ@ñ@ñÀ âæP¬Ïñ¢AG;MqQM=§—‹S¹´Ž.äôj5Èx[Ä >ã9’ÒñE¾è²/5˜Ð)¯ñ¡õ½&oc"_aMê'ú‘ãé\ ž³1<¿ûùðþ³ßñN䀯¼òJì‹åˆè16æŒH-¢‘,ô( uŒ–´Î ¬«…Îgÿru?1à§u¥ÉdŸK#€˜|,ò®l[ö%ϱ6±@IDATȸ‘")熾K  ñ xºCÊs9|ÙZMÇlk²a¶IHúBôkXi#ãmääs4¯s,ð¾63Cí“9¡M?ÏÀeã]ØKô§åçñ‹ãò(^à÷‡ßýÃpxò0-´‚+—­ ¿óÓ¿&¦&ô§'ôþS¼à¨x_2ðœ€àMl(ã³È+Hñ@ñ@ñ@ñ@ñ@ñ@ñÀL=‹os´™Ú?z-ûcüDÞÓ‰#G n)F¯Î1™Êù¼4ÖUûꑺuË{n o~8<¸åAm#>  §àúç–ð1Þ­‚~iGj½,HXœÒ¦ï¹ØJõZÚÈêgtûä22¯¸N÷é8^D3vúô “‘ƒ •õ<Á54ZÄA·˜>B3JÐ#²Îd”O¢vI©‘Ž 9ñ¶ÜŸãöìß^?úz8iÉI¼ä;È9¢}AŽˆ\qÆ […€(™¸ß@÷õT|ó"P•õu%våáùB)9§ƒf)FœÔãö¡}è=~€é­ž7ø3{ŸÑ]F{o@bÍ‚…ªþÌ=!ÃMªªS™|_ûèÃL mJ[¹6¶¼Lj—;/3×x®´sÕæP»6u:‡6—|@¡œàã¸'þäÑ? »ÞØ5R±þ>wÓçšekâú"ÀÃrå_î лäex)`| ÞCà–Gô›£Ô‰"\Ov'`š ~øÃÆU/æ“1‡š òÐÒAcmA ²«…NÌ9}ötâ}ðÜsϽÔ0tÏ›üÅý/J³q/¶.T¿ÃYåÝàÕ7æã„Ê¿Åi&b½Ò…l֞ȑN˜¶×W‡í¤OµºñåÆïÁrf£­œoc&:^?‡{›OeñRÙcYŸQ?8ߘ#à¸ú/÷é»ô}caÿôkáúCù©>Ì_û²zåêðÛúíä–ÿê]x~°Ú¦Žâr`²‚Ób =SíÖUZ´Þ O&Éù®àÅe ”5PÖ@Ye ,Ì5`1tþ{]†„LGËàï}Æô„5{ ÖxBN/ȸ:š«d «ÒÛ¿g ÚIù˜›^ÝÄJ'`š J®ø.ézì7ô•õGÅËÖyصGè08sP¡³Sȳ7 ëœÕ«WŸï ¥“îyóoÝ/wœÄ½Jz =ÇosjIG¢ñ°ëkUô£»W·=ÒÛÄÙ:ÊWZî“öMÇm½2m–ÚÊ¥ 7ö?LåÒº÷<{àyš¸Ö5f:ƺ•þÚ ~Ô¤ãb±ÇEÀÄú­Œáe€’„MÊI¹­ëû{7†¿yòoÂÇÞù1е‚Wžweø…+?þjÃ_Ù¹TiG^0Ø»'Gêh{\z//D/t‰ÊÞZ­Kœµ”âââââââžZÇ==•ÖV¿­œ7>è·ÕKå|=â»K a”Ò‰ƒ©¿ >ƒ0ð%þ«d*娃˜,ò*;ÐC¸«8ë°#xÜ Dý÷âbgwJúS€«V­º@z§y£@ŽÀ甤 d*W’šg×õBgç úžÒk¸bÅŠ3ý—-[æ«óŽï8°£êF‘)Ùdˆ#†|ªg¼¬ž·/rQ&µáåp½å(Ç[<„äØsAkk?•‹·˜ÏE'æÙF:¶¡Ý±9Ö9·¹à]’”ã¹|}@~üͳßñøPÓ©ÀÇôãá²3/ Srû¿Þ ` ®ð‘ü:ž!“úR@ ¾U ¯òY©ãih-'[—am¸d“D– S¹´N¹\¿ó²ÃÇW×.ßëÃhX½Qt±†Ð/A\‰—„{lbZ/Ê9"LËéÛiyÀ¤ÜžÿþáO¯ÿÓpêŠS[71>6~W~ð_é_‡=‡w‡IY¢cÒÖ4ÚQ\êÓ~È ‡ /#ÔÚ 8 kÃÌ/µÖý)‚ÅÅÅÅÅÅ‹Á ±â„V}Ô­„Ú«™ÖØŠ0jœa•¶}¢ÊVaRŒ7ãGB±ù ‘žÁŧˆÛâE™1<®‰¶ðQmÃE™*ίº €6§ÃŽýòkg*i.(u¼¡Ðç”è-V•ßÀ—[Zk4ðYˆcà/]:@ÇåœÆ r¤râ"|×»Þuª$1ãÇO?0™Î52´×÷tBpT10<…Í*. Ýï@²(£‰Xf J¤ªºž<€|¥iz²+ƒ`´ «ìÁ(Úª4$4Øò% @Æ«¬÷гÓ4Îh¿I`=&¾ìÿÙùbÅ>ÎWæ¨]ÀglÎæˆk0}·ÿ#!'ܰ{Cø/Oþ—‘›|÷[Þ>yí'值P6}À= àWÜcŠÛ·Æb™³‘WŠŠŠŠŠŠú<0›XµÏX× sSô—¤¥š?$éé˜dìžqÊ9HžBñ'a͵—í…½/ÔÈó]Iß wã7âWã˜=¢›ƒp#•!½³°Kw49 Nõ…Nqbc\Þêø#^1lÏ›üå/W‰¿4ŽT“;îX2:Ò"Ô5aìK&/(©wv¯¢@ F”©ò¨G= yH[ì‹ç9œýéX$iM}l¢»®E4•MëQc /=ÑpÏóxF´ÏÎ0ùœa´9µ)óíaÁ’Âý2ñ“€ãr[À”<«×3w…‹×\ÞóæÚ¯jën¸õª[ÃÆmÃ7øM=Ñ öц[ÕÑØźŸœz»p®¹Z¯ kŸl}m´,Jĸe&£C8ÁËÛ#è·m³&ÇxÞ·“¡eûC9BØp8tR=­ãVaˆrŒ¢£¸Áx‘¥‹rè7äj²°A=òå‚ íGÜò 9öWÓÍx/í})\º¶öÃlÖ‹ù¸(üê«¯ÆÆÏ9眷KEóG™„Qw!"h׊óMúíù–R0µAÞêxžÜÊ•+}uÞñí¯o×$‰N,ŽÜ†¯‰’×Ju$Êœ´¡<÷øÿÏÞ—hRT÷¿™Ùû¾ØewÙå’]DP@X¼"žñ$úW!ŠJ„?‡`DMTÄ3ˆDM"Æø7&j$PÀ E4rŸr.»ËÞ;3;³ÿ÷{]¯æu}Ýß×ß1óõ7S5Ó_½zW½z]]]U]ÕÖ4(¾ ‰M¤Ñ€4BÃaghãˆäÑ߈ÝÁ9Wœ] €§ÿx) ¼pÃü‰ÀOüê´nûº°è5Ó:îC´lú²Ì•»ù“ƒ¼ `¹Qàcª÷­ÁÕÌ42DDDDDDt†²ú%#a¹ö+·ð@¿EþÜ ZÒÀ<<`¿òZØæ —ʘ#«¬ ï‚çCšñ©4Ηòª.ǧã 點G·> ŽÒ~ñ_Ê3.u”N'tl œÖR…³bÕ©¼š.]\ÖêTu˜:Rcà•GcÅiÜÍþùHh(Ûd0%úÙB<å”+Œc€zeÉm½‚€Oç"’\•CÕR|ìôjZtk¢JœÅçprQWmŽTYVèCCZ<„¼a:Ô”M¯Ì3›/Ñ–EËÂ…yדn¡>W-’‡ëxÚÎ>ÆSwÍ‚ãnôËæ-´ƒ|ÚÚ»….¹ébºü˜OѸîâMÇäñ“é’/¡3¾ýÚÙ·S^ ˆ ù€n%çË0ÞA@üÔ1¿‡\n80Nì³iÅÇ8z z z z z z` x€;ÚW±¥ÍÂYºÂx²Í!Õ— eƒ´çµx ;Ý(——#çØ=$åÙ"¥derJÝÕ¿›·‹oXÎÀƒÄH¡Kÿ¬î‹èã/2AVpŽ&xÏ'JE¯ÿzh"Ç4èâ4b±°ä—È=±©\/ Ç„n̈hØËDÚœ” |©0ºÜ¡x/¾}åPgÚpV8œ<9|rgX³ñÀ2…õÛ×û6,)Œ‰­äÁj ò3Iޒα¼.ͱb"@j™E“§÷ 2‹ïyYÚ&º ÿ€Z() RgÑ+)KG5Ù,~5!” Óʇ8¤UÓkåŠÂ­Ö—ÊWêJÀ'W‚làá7Fãܘwá%}ßµõnºò·WÒ{yOÂWðw¯9{Ñ9Çü ÿãóY7ߺøEª¬ºùÉ‘Ôq|€øf‚ê$ÛI”ß×;gjÁ¬#[ô@ô@ô@ô@ô@ô@™<vš`[.ÃæA 4³BˆÓNFû²)!¯IËàYäV<†Ï’öy)ŸÆÊ€˜qžÏáSi•Ñ"n ïØ½âèà \siIÖIøÑ¥ýDhÜ=ççšç®›à‘†~=¬>æä/Hy†gÝæúWúò ~ €? 8³A×S{¦ k—V(lcÅ#î˜P®q¾Û² N‚ÂHFèêîÉ/§m²íðÓÛŸ–A<å„5ZJg™ð¸iš/;áP9Ef Ô‚à›ÉôêMc‡Rš0µx‡¤ZÙüëÕ*V½BüÕlhUÙ/ õ"©JI>¨:ø p|©`ù?`l@¬ýü0çZ»bm]öµÏQôš'^Cÿtû?%õÞm1­®ÞÊ`ß/CHê[ÅûêÊ52GDDDDD ‹l¢Ž 2ûMV—…C½y4‡ÏÔ ÕèòÈ#—Xù‰'Zm‡·ôo¡ÞþÉ ËZ ɤÇL2Ëæ˜qaÉR¤yØ„%…°S¤ièΡ} <‚ÊjÌ(\´©`h)| y¥tv¤ha"à ’CP¹ !TÚ“Í—0§i•²šWcq«õUXÁæË©•úÅT®'2Ƕà)<7è²%`Û?nÈ?ûÛÏЊY+håì•êª!Î8â º÷©{èWÿZò/ò–ƒpAþx °ð¬ÔmY‘ÀgOlcF!€9†èèèèèè–x Ý©©2s€k¥êÕ‡e”Ï3ÀCÌÓTx¾Ìèÿ„!­è‹1=3?£GÙUaOІD¨WMÓX¬¯”†ØÃ vc²ÀáÅf7H÷y)¼_ 3faÁÏJ”&tǧxä!0˜4@.½}û6ÚÒ·…¦OÀƒörlèëëScºžûÜç.üÅ/~ñgF [ªAº¨œPœ¦•®±âQpÀˆ,œ`Jð[– €¢®Pçj 9‘A¬p×a‡¶¿UZ¶/<ºãÑd{µ32y²î<<ðÒZ£ÕMkÆd,#ø²ä³œ ž†äý{–“ 9¯µrˆ×ivúS©ê ÕW+— ÛóB5Z(S„׿Tßò!Ÿ0móiaÚò6·Z_® R§× ø'…Æä×,Núƒó¾~ºäæKèsk?GS'LÍU°Äÿ—\Doûç·Ñc;ãw tÑV b3,u«0Ї0b$ù†#«…›“ÔëÄÔ0‹˜Žˆˆˆˆˆ€pŸ,*³V®=«Ð•%àDÆâ,,JƒTwf.”qr*#Ép°™9ÉÑÑ*òË ü6_Ñ%x(¨Ë°1“‡5*>kÿŽõˆÙܯ7˜Ÿ ðJƒNwpOŒáÄ¢ÇàùuΜrrÐ÷ð¦‡éóŸ!|eøÁØÐLÐá‡~ O<¶±µ2¦Ôq%bà+,ˆNûÑ•ÅnëLunV {oaÅuñçVÙB•í o{<1› vAò°–Îð ÈxÏÈäâ4¿¸ÊõJ eMÚê0è 쬠—”9i²ê7´šœ6°õk-&Q-ïb p™s+uÀÕ'ûUý"€|€ßÐÍ_x¼÷qúÄ/>ánòq,Ó&N£ô1šÌ}ÉџăýÉä«X:†ƒ'äȪÇÁ9.nE䌈ˆˆˆè@à¾Wð@%óÐûª‰ótêý×ë12BÓ{µ‹S÷oàð…åì,a·G….—çáååXb;$V6†ŒM;8yjÍ~“§×ì>Ë–'Lçù0Ö¦ªýêYÓÏmÅù‚¼‘•Õ“&íiŽ=.‹qÂcõBŠ4èÊ Œÿóf<\/O˜2eJʘ%K–`ìˆ^qx€OqVœAG®´¡Œ+Ô‰ê4u Å+¬±ò"ÜÌ™3÷°È²mX·ƒ_†¡ÖsÌMÖPÚ®h2ËTà´ÀÐ[#@VòÌâ3ºCr®LÈX0݈¾,™,\hBȦ-¿¥YØòia:ä¯7Ýj}¹ù£Î¸FÛç‰éAàP°_<…‹£›·à&|˺[èšÛ¯¡7®yc®ê,й+èܵçÒ¹?:׬ÛaNäÉV²èUÈqæûœYùD\ô@ô@ô@ô@ô@GxÀ݃kÙŠ{ofÈA‡¼ò¡œI§x ^û Ðíû š‘å«‚Ké¶|YòŽ®2«XÕ8ÐW—,;ù–•3°'Ëöм2˜òxÐw²6+ŸÆI‘#—[`›¶æ?ˆ=ÜW„o…}J €ÝñÄ–r} º±£Z¬%@¬8-NaÄàA(p¦Ævü–qÀúA¨1hYÎǰx7| .þ¾ã\0kà·;JÅÔt»ã;7¦M°%´”°´Ló3ŠNƧœ>ÉT ;E32L< \»ý1âv žps…ú!y£éâ+ ƒoüó§ý$o ÀŒý7îøí=kozÁÒ_ÑŸ®|!½ù7ÓU·^%yú²ÀÙá& 6Á–ÌI€¢™F¾èèèèè‘ö@¡@îÀ´^ÙߤSy<îýR}ƒWºå.¥S™²ä-“¿€œ²ÔŒÃ¼k¥¡0äÉÃÕÌ|䤯–7T®ï']=…­|ÒLú†ÈÏ¥%†ß4ídªÙµnëºìúbóAcCxµøXs@KÄ2x×B!VºÅÕ·Q>u“©Çæ"¼Ac榋¨K<:  nÜwã³€ð­;dÉO\öëËhÉô%´|ÖòºÜô—ÏýKº‡_ xãÃ7ÊÙç+™ƒÔuÔO>äé?fµ†Ég aF|€8+þDDDD´Ç¸V ¹Þzå,¿Sú¯1Û•ê8¤Sº´LG·bð©Ê4Æ=?ÙJ®˜ì8ǦlæQ€…_š)s ùjƒvx¯‚®ú\¬té3ZC•ςۃ‡Ÿß®(ãS€ø|<¬F@¬cK‹SXy¶8àKÊ6 Ô8t u²…•OqÝ<àŸ¬HÄáI¶´vÀø`*àÂÎ*5ã¥AæO^}ã¬üˆfi¿Ã‹ž$3ð6 _ÕÒ Ÿ ÈLZ@ߺɄ|Aº^+š%—…³2€½ß¡šŒ¥Y¸–Nɧ¹¡T±tµ|‹ih‚+ëœú+‹ë!?¡—-ƒóŠlØÑ»ƒ.øÙôùã?_×Kq³8ïøó课ýWtÿ–ûÙ{»ylWþsàzâGiZÏ4’—öñ‹~ð2@=v1Œƒ_$/ÒôàéCØ´†é:숬ÑÑÑÑc̸gT9dàƒ=ôÄq(««â„ßðÙÜù—äé ñÌ éü ïp¿S¼êÑtƒnq¿¾øÎÇ0Û–Ga.LæÓÃrÖL—¸5ÒÇÍ,NF_)“o„‘EÊ—â©£Yr)Êš¥Ïá6mß4ÂÞ¨ž]wwzÌiÝ‹‹6“¬Òƒž‡·²# §É#šs±ÌÔa«”¦ë,ÆtðÁëá÷x¨’vÅ;vPï®Þd0ÅFÈgθ$(ŒÀˆÝÁ‘¤,O*íS|"‘ȯ#zÈ(…©ñ›b‚{³‹Ü`êáWÍÊ©¼ÆÕôT£©üpÇe°ANßóѰùÙó†§ïœâ4ŸÁ~97•r.ÑAàe{¿]+}õw_¡·?ëu¹iɬ%tññÓþã2ð—‰Ö€j¹›Ÿô#»ä` Œj^,›` ¿ Á@1ÊðE0z z z z`ly@nVùEÆ ¸"({+Iñ[¾ìç2ñò!ͦC›,Íë©°Z)y„4žuÚr¥‰1Õj„§°ˆïCØTD.´ý#žJJЬÀV/éöge¤J!è&cIºt@J³ªrŽ“wJO’¶õn“ñÏÄq5—¶ÇØ"¾k×.µ£kŸ}ö™u÷Ýw?éJ®cKÁg<"bšÖXeÿ)Ó€u`MÛXñ«•éîÃ;l¥—í€ò¶ —¶:áç´3R®!ð?A©¦SÄ¡j׹笢/‹”\Ò^º&P/¿U˜e}þ¦ë”eéÑ|BZ˜V>Ä!-L[ÞzàVé©'Ϫ¼\÷?sÜÍ ÄW8ÞíFæ]¼  ›+3žr|ûîkiÕì}èEË_TUmH{}–望I3|ž®'ÃЪÙU¤SM^³mqè¾zË׈|#2Yv5ªGúÿpôÙYÞ\Ç­t[lÒÕsHD¢±è¯qBXÐ7CGÑÅÊ£CG·>J+f­`rŒ·lÙâ9òÈ#÷á €§<"é‘j% ЀCPZ’JÒâE”%ÆŒF™B–ãg ›-^a™¡ÙsÏ=—ÚBñl²íðS;]½r%B¯Ÿ<óÆii°°Iû'ž^(ƒ×Òš€³ò*|cj"ßvŠV+_x3¯Æ[OZ¥§ž>$^ºté2g¹>õ×’hŒbkɧ1ha:Á–è·L+B·¨sWØÆêÜ0¦Ù³gïa•…ßy´´vÀv®Og«¥lr3ëÖל+Mb{©ãÎÆŽÁ ›Ü$%°Å% ¯p€n› 2ÐRÛ ê ®Ñ/[DgȦ­U–faË8¤…é¿hºUzŠæWƒÏV/Wf~Ÿ4Y‚*å&øÅ€XÐß×Gçßøé³Ç}ŽæMÁŽœâá/x'=¼é!ºé‘›“ºŠúÚÕ#“Éé&u7¯žIÚg©çxw ³¢®È5WÖYG‹[9£¢¢¢Zâ*·=ékØLŠðZ{=–æôfÒB9µ!”ÓÌ—ß_Q%ÂdLy ÕïHQ|"y¸œá|Ïa€L}eš¤ã“B4˜h$od•'—…ÏÂ%æÊÚcñ‰òplÓÉš}“úTœ;°$K?]šY\z¨o9ÐÖmÃêúò„pŒhÆðJÞ€† q ±¬?ežPGZÇ*Nýžà»§L™2K—퀛û‡–šX;ãúÀàE÷ìøíÀ+ÝÅ¥‚ÒÄ€È]k)žfþFY§¢B7Ä*:³ÊRDgho5™–•§šÒ´òÕ‡ù×#;¬¼Z±¸^Š\X| PÛ<~ ߥÎu1Aæ˜ç©ÞõtÁÐåÇ^N“Æ_…ƒOþ]ðâ éŒkÏ ¶<à·Èw!؃Läå-ÉIв;ÄäF'Äñ'z z z ý¨r“ ïÓy—ŸêÓ˜K(t“F¡ ɨwÙ,; ݧC=ª?Æ-õ@3n®Õ~N +dªðV#5ª'O. Ÿ…“¾”–³0ÎGÈ¢7„׫aÈyB‡ÇgcèDØ´ss”ä7#º1$ …€Ø‚t8…+Å•.ã€:=tœu®…-Ÿày6§Ü}®òëU¤%°W ÃÀèÍ OX}p4½Âd ãˆò$Tõ!«~¯ˆ𯱥°Ú ‡=©MLC©/®"4\z«dÙV’+o2±Äƒnþö©{<Ƕy›*žÂc_þ8>k¼$ò®MwÑe·\Fç¾à\‘)Z|ಓ/£·]û6ÚÔ›ýÖXØ0ÈÉ”kVÝ$êkœ(êñÈ===ФªÜ+ú9¼žÏÒœIc“+ðFÖÓP4ƒÏ+iŠ?‹©€Ž,±ˆ«ÓEü\„G³ yÃ4ø²p*ŸGeÂtž\½zUOýàÑCåÂXéKý%þ“úïh’V§gƒ‘´Ò$ÃÐ! fmãör} 0œpcHÞR OýaòÇuñ þ9Æ@ßÿá… ò¿ÌžJ{B¢¢¢¢ {miNïþžð{>«ËÁB³x–­É¯ú9EÛØë²H ÐaÙ#Ü>h?¤ š‘µù5¢§ä)rè×u4K_5œÒ4–ò°^\‚s°ä©8Í_˜“Ÿ„{ÈŸ†<Œ ur¿ }·-;óWAõ#†cD3†Ôq%—DzYq–àSÇX8‹·m8®‚:¶FPœÏ'sŠp¸Ÿð;–Öxso•å/¶t0Î¥õ)ÖÍ1³ ªÇDZê“,ðÄÔ‹—‹™/þf‚4Í(È‘.½šÝpë×|:*ª&‰Ù®ù—òÀ»{ÉíÁ/ì™ÐC×üéúïûÿ»îâ¸è@º`íDü…–Ô‹ñB@ü­dú&ir±õÿ¶þ6W•ë¶= DDDt¬Ð^f2HÀ @}ÑÇ–ß¿pÏÐÑNûæU{Ñdô¥z6¶x§×æ _{»Ô>³LŠ?£|{¾¢áÑÆ¶/¯ã%ËN¤x†ˆ н×?ÔtjÕr iÓöìUÛˆ%Ã1"O` ©=^ÄáÛB:pÚ= ´NS\èpŃWaË£ø®žžž Vaxr-­ðŽþI¶l½<«tp½pê¶Éé©[.p^ÅàeÍØ‘üqašÑ5œ¾(«]™evuÄÖU™Àx|@¿€Iý2À~GÀ„.úä¯>IZ÷§LµÕ/\ùB:ëð³d` o€pT|! è—ÊQ­«7Ò¢¢¢FÎYƒ`Æ¥Òn°A½t œLÞ ßÞ3ù"ƒA=tºÁ½Ÿû.ßTžv@Â}VNà‘ójÌ)z ¥û³…”»þZU^í÷󵔘®)zÝ*^ÿ¥·\+Â1"§':‹Õj-M‡¥«Æcyn{\–-êTuH˜¶øÐÉ4œŒW$b;X±øvÁ[ú†*¿þ`#à”­\R¡»ã"T~-WÍí®üV.«ÜJϺÐÕ¶,¹j8ÕY§-OGÞê yÂôHðÚ<òàjvåÉ´úˆ{…ÖOô »‡nROÝÍ0þº»©°ŸÎÿÙùôùã?Oó§Î¯«/?è儛Ɨoýrr#qׄnPeð%¶h¾° 0ðþÚr¶«LŒ£¢¢Fµ†šçT1+µø”îb/¯xÖ^«FKY3”ð:†PCÑ7„ŒÐXô@3}§fd­¯ÑÓrôÅÐç ® ÉÇà4_Ä kYl: –¾–d‘(Ķdƒ¨ bØ|æu̶–m €ï:gpcc×Ë”ØQ$²xÀYxãyÑaÓY2#Žk÷ €°ÀÖ™YN¶tȆ<]“&MÇ'Ïó4É0¿¶¤wöí¬ž¯·¾:[.).@ÿru5H@¾Í†<yøfókD¾Y[š•oÄæVÊȵÅõUbnMdöàc;@ÙÀ«ºùظk#û?çÒÎ]5® #ßtØ›èÔýNMoèLV`;Và‰“>YÂÓ ä%MqêfÔ|õ̰0¢¢¢¢Úè´k‡ïh¿ ëÉ:p ;ZÅÓyó4?Üz¥¼™±êãØÛ3Õ–0¶|ei£wcÖ#éfûÁ#iëXÊËž [äáÏŽn´•i#Ž9-cI6 % k©–4GéV¦4pYVÀ!ÖQVg)qÞA‡vØB@Œ%o¼ñÆûžeÖ¡¼¾ç©ǯIÐQøÒ…2Md9G®4ëh¥i ž®¥K—¦ÖóËT¶ñÖ][;0j‘cÈ,û¥?©nC¤„ŒÔ&¨`ŠÖ,NVZJA³ dT%´*Ï<=yxkRÈ# “e`Ë_×òAE˜ÔÖL6+_3ƒád —d åzÁ?:¦ç/ð°Ÿ}ÄŸês_Àü@ßn~òú»_ü½ïyï«ËBL\ôâ‹è=ÿöºcãœWr-à#€%0䉭ŒVGG§T&`´Iãoô@ô@ô@ÉOG¿‹ÿ|zˆ|).-Ï*;™Íü9ô2M`¬h'ÜXò6VÛÃâ#€ÞQA»êe4:t¦¦õ$„6 ~þüù³-¡lÛú·Yó²a-i6µÔØjƒçz ÏÓ“‡¯GwÈ;:Ã<²ÒíÊ7Ë–†q®®Ú§ê² €oó Ûºøé¿¾_Àv€ïß÷}ºö¯­;ëIã&Ñ'Oú$­˜±‚z‡^(/t_­x¡”n pËPõΤ76M×mDˆˆˆh¥´çlbYŽÏp´WrØvÌñyGÃ2|ÿR½¼eûàµ/ܬ¸¬<4ÿŒXÚPcs*ÝJÿD]ÑÑ#ã&Ç ¶?˜gðæU¾†–'4Œøp¬èÆ’2®ÌÈÖâ­·,>C¬\¨²­°Ž´ž²x…5`9fΜYê €dî–`¶¦FR‚Ãù´åc6<ÚôrNÄFBW„ê×´‹U·Æ¹Þ$w!ê©ÂŸ§+ª ù´åiaºQ^+—WË'‹¿¤8WQ夠Xòò½Ä^¼’Kô»e Ì<{Ì[vó‹¯üÝçiñ´EtÄ^/H˜ þΚ<‹.;é2zçwÿŠÖõ­c•È4Ù p²Ô€×ð§\ I¾€ñ‡t¨ãJ€‚lç24/¸ìbH{ ç¼øIIpgðxºÒ\,xÅA”Û5 ŠÓdˆO¸R¿Ê’B"‘K¨àŒˆèó€ô9ZZ7õ¢©§#%ÚækÒhw}ÒÒòíÃcâSáÝ»ÍK”4{é;ðKL™˜†´œðY^ðì&û2t•jgN¸±$<©‡š‡4‚Æ!,D÷ž°ð–ÞV¸,E©|6¬M:u¦õ(pè†h m‚·ömMÕ.Kb8ÖB‰iܲÙZ# ÚlÆ Fx Þƒ X=ª¢Pì•Ôænå࿚®"ejà†ì®&ÒÂô–´/«Ùie²àfd³ô•'uä:)_p•7^€-ÀtñS&±ì#7]LŸžüizÆügÔUŒÓÐß¿ô3tÆ¿AXN†»rÆv¹¦pÑðMHòCžzÈÖИ튓ì˜:˨è5BV;X!R@O… ¸˜ ™l+À—b)¨;%SÖD†Sç¥]i.9Åqy½ÅY>øCñY¾É¡yY2=PBäTå†,mD×HÉ„ ó ÓÊâ5­1øëÒ|M#FCŸ¼Í_@ߦȳU€~““ƒ¥_¥i'âúbЈ^|Õ©Lí ÆŠ6˜±$îHöÒŠORé_ÐPT '˜ü–y €º'ËÁг1ø»¦L™2CW–9ŽÄªm»x ¬¦¬ hLy£²#5˜m4ŸFåB/–©± mk{ÚÔi©Gœ–- `÷eív€þž~ú›Ÿþ ýyóŸë.Æ’YKèïNþ;š²{Jò5þ*À ¶h̰]ê*Í1O^˹ԦYs ÓŠqô@;<€ú˜s þVné¶¾ÅÝÊ*®"†ž@®fº†Lá|³ÊÀ8+_nÇyÉʳÈy –Ö‹Ÿ­/í’üz–î«\ ¿šï*êŽ;YE‹¸èèõ€é—Õ]‚fd‘™“ÏW0mk¯{Z݆ @8VtcIõâð°†(ÍâJ—kt<ä.ëô!ìÐ Nny»&Nœ8Í „³:–ÖïÀÍOFt`ÚÅÓi£à:¸pÀ«8½ÇhѺcQ9ñ pìè–À‘ä‹™8I„Â<æàשðXÍÏ#ŠZæjExT>‹×ûÌ1eñ¨=ŽP7” ÓÍȆºJ•vu#u0 Àx¼«d€ëeoÐcsïfúÀO>@WžxeÝ/†ÙgÞ>tùI—Ó{ÿý½Ôß×/õ^óGŒ?¼„P®Ø•¸æ` ®1¬ÀuûÃú.„ø=0Œp×M˜ƒÖcøRt¥iÌB):”š×Ù* ¸nü5eõ+ÆŽfy3ÛÆ€_UZ9ÅUÄ9²|E>Lù¹]i{Å!ÿ,¼£{þ,;­G¯ÊŸ¥#â¢ÊæŒzšX¸ž‡ºÂ4+®©«ˆLOØîV´qd*t„ýQ;€“œÎT™'逖‡“Þ“ê5²^§ÃIyŒNÕ§åDZîk)\¶ €p¬ÈcÉéìEÜ=ô¢p˜†·5XšâJ—m@ ‡YG*^qyíâ}¥žØÞ¿]l× Ã%¸°\4-Æy¥l?Üú›°/å—&ô”YtT—u‹oè˜ËM€ÓR·yåÆàp¬¯øƒãÇz£ o¸>¹ö“4¾»¾¯w¬^´š>qÂ'èýÿù~è<äzBvI–òÉAùL¡'»IfÛâ$@â·ø;¼p¥0¹^ðxð|Ì7ƒföÌ”ð¬q³hú¸éIºg†ÄÓz¦Ñ¸îq4©{’㺒Û=âI=“4'êì“CÛ¶KzçàNR1Þ_³e×Ú:°•¶ lK§yeð‘À×\êšRåîZÔ¤å\1 W~ïÆOeö§=„1º‡ ΰ©<«Ñݹò2–×Á¢Kñ‡y@ÃãQÁ@@ñ1ŽèxàŲ́óm+WÙìiÔa9Zìcéÿñ‰CÛ+ý» ;±ºL!œà±äT¶¯ÚÝæƒnÅi\K|m e˜¨×Aêlë4ã“6Ù“jií€wìÚ‘dËÛÎŽtR¹}É›, ôdkc¹.T^CP—’Ì©ÎY ^G¦fŒ.Ô%®ËrpS<ýïäCÜ=®›_ 8˜LÉ8œ»ß=õ;ºôg—ÒyGžÇ­jN¥ÌñÖ¡K¥¿=îoéÜÿ:—ø/O\^ ètÈ +ø/5`­õeŸcUDy .e„T[ex€ïéê¡ùãæÓ¢ ‹äX8q!-ž°˜Mä4Ô·*Lèž@84L—šCWt¡¸°_&6÷o¦M»6ÑÓ}OK¼y§û9ÝŸ¤1‘:b{¥Vã Çð”f$qVêÞ>Ãki)?QI?õ½Æ ¸º?t¯WñWà ' ïd<¿f¨±êÔ´‹sù¾˜Œˆ¨á´9×Y ÉR’m˘‡·<5á ÝôüƇ©¶Ò3¤íÓw[o/¢¥Å‡5Žy,9ÅeˆR†È «}ἡCmù”f¬8åSZ*îîN?:´lgÜ·«/é$à%šl¹.ÑÇ~@Y"ͱT5¥ó2i¤å…jÚX†€—™ámêü'9d0ÈBŸƒ%èá?ÑÏ0@#Ac¥'ØäWå,® \«¨E³ÉâÏÄUyBò‡i›gHk´3ê±yŒØUE”GýäËíêš|&ïÀVŽ1)€ëà'ý„fÞ2“Þû¼÷ÖíŽ#–As!Ýùò‚AÉ›mA ݨ󈑗æë·&`Õ‚Ý€ÜõZ¨Û’(0¦=`ê¿úA¯MKûË <©_5y­˜¼‚–M^FË'/§¥“–Ê$€çí+wfwϦÙãSãɵ~×î]2IðTßS´±o#!ÞпÖ÷­§ }¸=mß•¬œó×#_—©{»^§sŽtKsФMrøðüˆ¼;ž†4–ñ8”Nñõ~cqz²•1x2‚בA‹¨è1åœkD}PøZÉÒà éª%ÐÕÎTðdæð„m…´]ôq4#¥ñ8À÷½§ý °yxd^´_Ž/EwøÁ7/÷¥<“Õ4ôØCt'ÆBe ©ûæÆ’¸;dÖtwñ| ).äcÏ qÛC;'‡ Óʼ¥¥Ò|ÒR¯r Oª*iWŒ'$AK£1Æ…"ö[¼ gá”6œqƒÕV.úá´+GwfÚÃ[ºQ½íòC=ek /ê§«+¨Ãð—Äîi»äÁtøóþ|á¿;®½ûZš3y½þ™¯¯Ûœ£WM ^@^a²Ê“»^`V`õAæJc«Ú¨²uÆ–\}·…Nµ¨ïü·tâRZ=m5=cê3hÕ”UòDßÊŒ%ÛæMœ'Gµrc›Â“;Ÿ¤'ûøàŸþ|²÷Iz¢÷ ‰7ìÚ04ðv׺ŸÌÃyq8‰9-í°Åednχq¹@;eq"îòIµñÀi°°ÃyÊãèèè2{ífF[¦m«ö÷¤ŽWpЮÁ]¥*¥´ëÆ"Kê£TÅêiÀ6­`‹Â’)KäȒĵ¾¾w==±ó ztç£ôØÎÇäxtÇ£’îì•ëÚËæ\өΫåQ˜c{/ð0㥠>6¸{fX7,K„£¢†Ù¦?2Ì9)õ©6³Ž’ïìwï‹©Cf8Yñ¢KºÖÛ|VÌQ8Œ-MáðÎ|[CY&êu‚žU¾‹OÚPž±rSVj âAÞ›ÌÕ@:Ë ƒÒi@Ú=]Ð4ød€ÄœèL¢Ã‘’A™XÎÀ8´:ZÐüò5|Æ"«Á¾j¬J+’GÕ§q–L.°7¤Û´…5CZ£¹PêÕ±9¾ü¸JGŒ­,x+?/'Ó7ôw p-ç­—Þt)M›0ßëðº]ôâ}_L»vÑÇnü˜¼@^è´àüÉõ„Û8Í´8 P·»ÇŽ€©ÏZhÛLéžBO;˜ž3ó9tèŒCåå|ÊãáñV,œ´PŽƒè ŠL09ðÈŽGè‘í&Þþ0=¸íA™0Ðû«ñíQ®½«&íUàöéο¿W»[ª¶/¶.äö?Ò·aÍ%ÆÑÑ¡2Ú[Ëb¯7‹Ï„C]Aº®Z2½ˆùÐ!2_J¡y<ã¬\¬8YÊÏÆ«¬ÆÒþ©GG¿t/ Œ°Áñ Æñî€-hõÑRkk­°ÆL’ tMwL\Ö €<ç9Úóó 7µ lg"kÙKÑN‚^€™üyžQx)¢³ci\‚"dá–T²^þ”p‰‘ί‡Gu7 œ–I,·@žÆó*Ä>8þÝtþÿœOÿâ¿§èÉE“8‰0éöñŸ}ùn¦fãèèèaôÚ"i£²Ú#—¯ððÀ½jpd¯/dj6ý¤@ævèP®i.‹Ž%a½-µJñƒVßʶ.ë€uŒu,ðaZyÏ'-U&TÈ2…^Ù€«Eíʹ°’Ò86ÃÃx^ òªAË—”Uue¨ˆC Ed*”TEdu€B"<¡LzD©Ô"ö[ CG˜V½Y´j¼VÎÂÈXù†QÕ¸øò` 7Ncõ}rî¹£íšZt¸ùy<’c7o èïí£ýäƒô…“¾HKf.©Û /;ðeÔÏ{ˆ?uӧŘ’ƒóáV’xå¿}-NˆâOØ$ØAÿôžéô‚Y/ #gEL;€kmR³¢×:Ç{&Òª«ä°Vãk=÷m¹îÝ|/÷Ð=?°åþ䩟f߯PØz´(~’Àá,/òïwžaœ¼EE8z z ô@xá„ôzÒèjD&´©Y2Y8äeñ¶´fg¨R^;˜_˜œ¨Ešûp,(÷Gà}~ #FHbäÑÛ[®-¾;¥×±d^KâôÓTÞH X^ Ó–e98Åó9LøƒdZ[R»ø‰&.±’­ÖËv*¬¥ÑBy¼±òƒ,žTÇ“ÀeÉxq0ppQ’àߪ2ž«> ˆÎ"}§iÒ¸IC¡Sj ×aÑóPôœ(ŸÊuXq¹( Žzƒz ^¹á/Ã@5§f9]q«£$Í7N[|2¨V–öÇ;û{‹·e\" A¯¤ÿTàœâ18v(s'D C\TwQ>kb–LÎÊyj¥U>œ\唯Z܈L5}MÓŠ‰B 3,g†cžÐŸŒÉÍ’|&A ,·o¸>ü“ÓÇû8ï-u…—>㥄…üíË“ØH£u#Ù€wlÄíu¹´s™qòMÀÀ/ð{ÑœÑË翜–LªÿF]Ç æLšCGïq´(þæ¾ÍÒfý~ýïé7Oý†îßz?·e®½ãFÍöÑÀá@Ð^ŒÒs4{?òýdbˆˆˆ0@›‘<(4Èl´ ©C®¯¿\+|[ê|Ái´Â(‘-•¦5¶žËÂ…tÛR[Z[à2L-¸= V&oyÊ6¸V±éš6q o-7<"š-=èH#F°p‚I~•Ž”…-OlóËá©Ù¸äȵ]GÙl§ª¦uè­©k,38?Jg˜+¢ÄØ/‹Šë:ÀØÐÝà ´Tàç÷_âéÙ/Ÿø%}ä§¡‹Ž¹H–õ×ëÆ“ö?IV\|ÃÅò™M‘‡~>d ¾JÀï!<Çv^‰ O†ã×êuwùøqNMÀyÔ=‰^2ï%tê‚SiÎø9†ÁèÆ=0c :bÑr@ËúëéWOþŠ~³î7tëº[éé¾§“ÏŽbÖ“›>é £t+ª®HfJÅ8ßµu»Àýºñ’EÉèò€­ÓA–Òoàö»PÙj¥³”Ö’ é̩̾ئ5_‹W8/Î’Nõ†r qŸÌŸG—4„Æ;ËkppiÆ jWí8¯5ÍÃ×ÖØfŽNš°®R‡k š…-o©` 4u°9ÈW† vØBàÛ?nñ"éH‚wOOUFy#¯qNˆî¼Êâmºœ¥'K®(_(›%W³ ŽS`y,êGÚÒ-Ò²dC\(ÒÇlÕSoÜœ¬pç€[¨”ÿÀ†-®{ø:šrã:çÈs|]BÁŸö;A&.üŸ ùJLžú#/LÈ$€ÃéõÕå¶Èu… Ø‚N:Êá@IÇŸrzçÉtB&tOÿ«¾šf›e¨Œh½æNšK'ìu‚ƒ<шwÜòø-tÓ7Ñ]›ïJÚ´%|è$€Àî„ò•×Öxz`fª]RZlŸÔ1eHõš([+ô4¢£™°˜Ð‘§ÇãÍýOqC_ç¥Ïí îŸÊcã›d¦°ÒÑ× óDylË©°Æåµº€eeœPdž1Š£¸jpb—ˆÅ–¨Y³šÑÕŒ¬±{¸gõ´1Y•+¤<25îÔ;¾O Ã*u‡Óèàâ|ù ,7àÇ \ƒÖ³ïßû}š>q:½û¹ïVR]ññûOãzÆÑ×_PñbÀnþú€N ˆRÜÏÐbºo´Fbgœ¨Ëçmc¶î¸à¥nÇÍ=ŽN_t:Í?¯mfŌǮºy•é¾³ö•ãû¿QVÜôØMtÃc7Ðï6üŽðÒ`?àGó‡6_p“Ò#rÍ¢ °÷»ŠÉ´¹1DD´Çæ>4"àzo0ϼƒ#bw¹2±­f-Xé—«$Æš2NÀfå1„ïøºS/ÒË»@лø×}­@;á¨/©Nö¹FSÛæ­+l€¶Qk¦­¡w.y'-›´¬mfÅŒ£B`uÀKW¼TŽ­ý[é†Gn ë¹^Þ0ØÅ+1ðçÙ€‰R¬t¤2?êÚžª“æzð=­Ð˜ŽˆˆhÖÚÖ ]RØéàÏêý¸Ùl†IVëQ4 ×wFËZ¦ u\–£ë= Y:Jç/0  ™ò´“KâC£Ã¹0­ü2˜ ®¸,œòŠ«!VPËöBy8¦<]Yø,\˜WȦ-H³éF,+oó‰p†p `?êÆù€±ÿžÿàGÙ‡z îøÊÁ´Knº„ž½Ç³i{d(­:bùô©>EgÿèlÚÙ»S7þ0 1¯èKÌŸ{'¶Å•µ=’\GlÀù\0a½cwÐá³·¤G”ÎÓÆO£—Ÿ(ÇÆÞôÓ?ÿ”®ûóuô‡HÞ‘Âm¤NHŒ•I®=R< å'´mUˆz ½!z C=€ûo+B+ô4¢£)/®[WtèÈÓ“…œi Ïó±N…«Å–– ó¥þYýÀuÀgar‘€³P­­F+¢ØxÜâ±aÓ_¯âFe߈|½6¶„CˆzƒÜÈë¿Í*nD¯‘‘šIG0z .˜zéë9ãБ•4&óä^ ˆôÉ1c>z&ôÐ9ÿ}N]Y†Ì‡ìy}æÄÏÐTþèåïôó€^>8ÞÝÏߨÅñ.¾uñÜÝ.f˜ïerÈ„&,\”$âïˆzÀÍç“8§Í?®ÜÿÊ8øWÇĸc<0{âl:måiô¹£>Gÿ¸öéô§Óœž9IÛ„6ÉÜ6I[Å1¶+I{…v ‹ݵ‘j«à½fÇ==0:=`úY5 XoMe†a¸ôš,Zªµˆ®G}#2õèoŠ·L+Š¤Ñ“PD÷ÈñèMÖÆ(ÒA,ƒËW Vy[+cñVƒKåmð™`†|&_$wg pÕ`iŠÌêÔÛ’²d2J‘ο˜ “I%®Ï¾bºtž Àþ|ÿeà¸s{Ï–{èúû¯§­xQÃÎY³h ]yò•ôž¼‡6íÜ”êË;ðuämÎÄþ‰Û »½Í¸cÀÿ9Aꎣí9aO:{ùÙ´ßÔýr¸#:z s<°dÚ:cÍôöÕo§[»…¾ÿ÷éæ'nöÛ|[ÄÍ”n~ÚO×Iû„¶ªÚWbÛÕ9•b´[Z¥­—¢×¢«B¾Zi•³q-™negÑC\˜uX=Ê˱ï7)¿¡ i{¨‹³°Òm !àKåÐ|™Ÿhèô_´ÝJvÚ@§W¾’?,]ÆS);HÄEâa~Šð(;nôV¿â[ÛÎv+ôæÙ[F&¡l˜¶ì–fað„i+—×ËŸ¥cLáPýõü1¬“îRI¹×ü¹­˜åö¯ÐQËjèÓ€ª|ŸyûÐ^öz÷¿¿›Ö÷®—sŽó[ôšõy« ˆÝò[ã$€:³•±Ö‹@gEû£|Ÿ0ï:céò‰¿@,&£:Úxàá{.ÇcÛ£ïÜýúÁ? mýÛü„¤¼?Åm À'UÑŽJŸNêD€¶YpˆàèuÄ|1D”Ù-ëg¹{w3em…-èÈ’QœÆ¶\'pPv¥‰-O祭-n’h{ò®•k‘ÛŽòh\Kg©èè¸Êáï´í1ÏßðȾ¢óÝ€Ž‘Ñi¤óùô€¹šmU¶¸mèØÊÁ{òív€¶=@×=p]ÁŒòÙ–Ï^N_:åK´hâ"ØÉÛúx+€Ø€mXv‹­8°-Àl€fm #­éü,#Åz@}fc¸QÛL­Ï±Äy€hḅtÄŒ#èÊ®¤3—ÿÖ¯•Xˆ*8–€k4NdŸ„Œ¾„:¼€ã™Ò=…ö²/í?uÙ˿ϔ}hÞ„yž-ÑÑCÀö€ã–GÇîu,ýôáŸÒWþðzhÛCÉÀ_· ­âöRº»‰Ü‰½fµ-Ê2BÑmó@+ûYÍêjVNlF‡•̓Ã<²ø§±ÊhÚÇxÓ¿›ð8)RIƒ‰GðhºFYÐQãŽ(^»'²œ•…ëg5ÒϨçà"Á`¢ÌA/ø2ÛØnÛFqc7r®ÅeÀ÷?ûì. ?À†%ñÓtÁuÐuó;P`žœ9¸{÷š£UEŒ 6‚m¬N¨/¤Ï!pLŸ7~2ã:húA´fÚZ0qãŽQô@ô@³ÀDèÉ+O¦µËÖÒ×ÿðuúÖߢ¾]}~k&+eÂÜVɤ*¶^ñD‚nÐö75þ¢†ÓÁ=¤"«ZtùÂ4ø²p*ŸEùô•Í’ÏÂÕ£CyÃØê-ëP• ÓY2gùoq¶yßù-_^ë—‡/U©Ë:P*'µÚ 21˜Á¿8%ÍiZóÄgÇxôMćêXŠæ„+dTi±všP‘+šUeΣåáUqȦëá­&kõdåÒcº ªã‚kËÍÆx/ßC'O¬ÜJ™àùÕw^-ÛZ± €µÓøžñtÉq—ÐÌgÒwîúŽÔ«žÝC+ P7üvž„?îXÃFÛçàf¶»&ÊÓýCg*ÿe“—ÁÅ1DD £&›Dï8ø2pù¯.§›»)™à‰ÓîAnDù_&¸ý´“«Ò†ñ„€´»® Nµc°mr ÑÃáÔ­àžb³©§_få²àfu5+›šÑaeóà0<>ŧbwý§pÎæ§ù¯4Å!Ž¡½èô €1qËA烉ÚëpÓ^kÆnîèxê$€vR1ø—À„®ñ|µpö‘ÞGè‡üNZqRËœ…ɸù!š5i}õ÷_M²Ä„¹F”í@¸Öê11 tÐÂëefÏLzÞÌçÑóf=Oý»'ÂK1DDŒ°ö˜¾]~Ìåôãû~L—ýê2ÚÒ·%i¯0€‰nOe›¶àºF÷ƒÑˆeà/h×îabAù’Tüˆˆmp]ÝÅ‚\ÐCª[GËÊ2ШSá•Õ¸åNj—B?ÃÎèìY;'Â}»ü¢ùªO4ãQîÓ„VL èh^Ý*YŽÏËY¯¾ëjzñ²Ó¸îÖ6ug<ç š3e]~Ëå¼}ëf¹Ì_ ЀëT&ÜÄ„Lðg·d‚Ùp-ù뻓;η4ÛN`iÿ‘³Ž¤Ì~ìåogû¥ç&ÆÑщŽßûxzö¢gÓ¥7]J?{ôg„vsp¿ª‚­T:øG³æš6iwñþívq›HÛú¶ éw“@¤>íÙÃLàs[´Ž¡RŒ2·Á _ìwÛ°œÿù3ŸOÇÎ9–q¨¼·D ¢¢:¯>ðÕ´fÁúÐu¢'{ŸLµ¡²º ׿k_Q ´aöÝ©¶ à/s{cˆˆ¤új#’c̤–:u so+®-7K†ñ„ÐRmÚñái¡Ð]Znª|Vƒ¬þïuB†¿»©¼¾XDÏ•ô¦.Hµ!ÅÑšD*Ÿ@e5ZÀšøÀ ½o®–.K·0ÄC]&› 0”­`ˆˆæ=àêcê¼ eÀŽª;ï}œ~ðÀèÔ½Om>Ï ‡ìy}éä/Ñ{þó=´~çz©'èË5Š—kakÛŠëUÿ˜œÀµë¾¹ {…W'ÊP–\÷ÖßûNÙ—Nœw¢<íŸÚ3µ,G;¢¢ðÀó «^v½ÿGï§ÿÝð¿Ô=À/ æ‰TècBmü¡ ã6KÞ€¶ mš:ôM$Ái´ejËðI)‰‚ûµ*³¿•ÅâÂ4+­ÐòÔHWÈÃP+ca-D€«ÐÐ3õ9‘eXcÉBi˜°lé!ì&õ…ÇñË=ßð‰n~¡}Og~Àa6dñŠm÷ƒmT´jè"wj' Yç˅ج’ yè.ÝÙETô@ýp-€<=‡4§1¨–媀¹£Š=­ˆ¿~÷ש°¿þ< J¬œ»’®:å*Z6u öò3ÿ¾äØÝ·›ûƱkvó{äÀ¸ÉÊHo¼ÈøvcLÑûäîÉ2èÿüŸ§Ïð9:qþ‰ÿí>Y1ÿèÖx`ôÅ—~‘ŽÞóhèHÚ2n¿Ð–íîçc—9О¹ÉNi³’ס0h0¶ÆÂ¨%z €â!å¤Tÿ"E‰‰±êNž;ç¬FC†›mê†Û¤gZ©«IS¢xô@u¸kC&kO©ÜdÞ ðTÿSôÿîÿÕu5I]8}!}ùe_¦5³×ø üuÀwœË> 3ðßcâôÎ%ï¤oô-:kÙY´jʪ&=Å£¢Êè‰ã&Ò¥/¾”N\q" ôò$€Nj¢=Ã$7ø§ž´šq Œ§4Ú=0|¨1F¾Œ£æf<Щ[ —yLÍziǽÁ‹±ÓþnáJó=Àu_–ÖƒËQñÆjLðRüoÜý zéò—Ò„ž ùòMRð>€+N¾‚νî\ºá‘üSsýB€ÆÙ¨Ý£Íò«pM7x=WäQ <©Ó¶ó™ÓžI§-<ž?ëùlÊHSËØHˆNà“§{ Ðïûa²}I·1áS«ü'í¾¼Â»íûM0 €ö—ÿb›1œg)ê.½‚ûj…½µèm@ “ÚÇhC‰b–ìQ?P¶³¬ƒT¹aòÍÁÂYiaªçG/Ö&ûêjk=Y7Â[-Ÿj´0¯,Þ¦«éyÃt(kÓõðZ¹7àÔsÔyŽå†‚<øÇg±ïǺ¾uô½û¿G¯Zõ*F _ÀÓ³Oÿ ºìg—Ñ·ïú¶Ÿ›0¸çN4¾ {hqõc/-ORÈ>[÷^€Ðö¹Dòf»Ÿy8½fñkhÿ©ûŸ³¢æèèÒz“wmý÷­tÃÃ7È€_Û þѦ¡ÿ"Ÿ<åRèd«L†“®.ma£aëÔÃV…fu5+r4£#O6ÄÛt-XéEbËca[.Å·êœE=y nhÌoK59(o<ã(=0F<Àט,ÿǼœŠ[9ÝpÍ=×Pï@ï°;ç¾ðƒtæ!g&[Ü;dKï¡ÕX¶`ù,/§EÆ¿€-”É µ´uýÕ(ùÙ~“vì×ÎYK_9ð+t᪠ãàÈ[Š“èéî¡K^| í5e¯dk“Ý€÷ =àÑ>oíx ˜¾ß“6 G;fõG8z z 3<ÇBm?O°`tUÜõ@Éô†ˆXÓEè¨:*«°Ê#má¬4põè¬'Xûê‘k%o6Ôœ•¬CW+‹uôŸ<ògœ/®³ò4ÊMlìÛHÿzï¿Òéûž^Pisl¯?øõ´hÚ"ºà† h×à.¿¡{°›w&OÎ`'V*À~ž´H­à¯y´|;ò3Aþø„ßëöx-´ÔP#==0Ö=0mâ4úÔË>E¯ûÆë¨·¯WÚYíÇèÓ~Í©´gÒc;Ú34À< [±# ý©·/!‚ñ'z z z ´è¸V­&J{¶[a˜:åFÉ 5muË •)gÑ,. Î’Íâ³8µÉâê³Ê’%_¯-Ô•Åâ´ÕÒj¥­l‡²!=¦‡Ïâ{4ź¾Éu@eÍíoÞóM:måi4©gÒða4¯]µ–æMGïû¯÷ÑÖ¾­rcÐŽ3lÅû °œV·¤¶°­K2 ƒ÷Fn5*ëlÓ‰’çÎ|.½cÉ;hÙäeÆêFDD y`ï¹{Ó{x/]zý¥IÛ…'ýîm™ö+ìþqÐ?äȘôÞÙL†ÍêhV¶×ÔÞÛY"+„zl: VœÆÖàoc sCP•'ËÆˆ9hyärŒ95çF:þÍ娴.j kcQ‹¯zQÑ]Mf8ËT-ß1Os׆b®× žþ›¯lØH×Þs툺ëàÅÓ?¼ôhñÄÅ4¸“Ÿ•aK–Òò7j§>¨ŸÖÒe´î^žªÏÙ÷÷ü2~èÁ·ø_¾ßåôÑ}>ÿùž‹”èèç×<û5´zÞjù2€´[hÇð‰S|Ÿ ¿p¢[Lû#ªÂtôpô@ô@gy@ûWeu´Öx NgD0z Ï©ÁWSÄ—Ë|ƒªx&øøÖ½ß¢»v¶w`\› Ëg/§«N¹ŠöŸµ¿ üåÛÚyÆ$à]É!Ëfí§µ\‡9U‹t¢Ácø ¿`ÂúðŠӕϸ’ž9ý™Í*JGDŒ`rõ¬£Ï’ L|Ѓ}·‰Àd£›È”xÌx*4z z z Üˆ[FøüðíÐçè—ÉœA³¼XJƒ xlù~S¶W1¯_-ºUòÖJ[YÀÕøCZ(kÓõðZ¹·À¸Np‰q,ƒeÄø³_àmO÷=Mß¾çÛôÆýßX(S¼k{ïvš2qJ!þ<¦9“çÐOþbò™Àdž>[e®p|j‹C׸¤ Àµ.ÿõ~!`¨©_Lêž${ü_±ð4±{bž‰=0&<ðÙk?K+÷\IÇr Mš02ÛFƒc[~½`Ù ègþ,ig“V~å}XqÅ8ð2Tm‹¥ÏÂíœ_¡åÚéÑà“X†rz }±fu4+ÏÖ«#‹¿ÎÒckKHCZPÌi –×ÂJq{<W´Çï£:Wmš-¤6Íê‰òcØ;ãkî‹›UÛú·vÿOl|¢0ãäñ“é²_F§ïwºß [°€—ÔÊ“4·@—Ôâ^ªOÒ 7u Ýg“,‘v8ðáxÞÌçÑ?¬þzíâׯÁâ¥ø;Æ=°hÎ"zÛ¥o£5oXCïºü]ôݾKOo}zŒ{¥Xñßrø[’mLæë&º @·3É*&·°„°­*–]䊈.$φK{¾ÞØäûf„(qÀ9:•V|Äö“¥i¨Å[XiÀ)¬rˆÛÔ¾vämól¥­ÔemŒððx€Ï—>q’ pþp}èÓ)žØÜ·™þåž¡7ðæÂ6,œ½þpÿhõŠÕ…e²ñdìý‡¿Ÿ–Í\FŸ¸åòEt’»&°‘l+VÈ5Ž3Zi”‡'.0˜—'h +Œ P¾ €>oÂ<ú?Kÿ9çÈ€“ÑcÛ§y*}äªÐ†Íè{7~¾÷³ïVú¬Y¹†_}8=õóé°ý£éS¦mGe”þЇÒÂI é‰É„(Ú¤ÝüÅ’Á®äK˜¼GZÚ]wÓü*€ Ý=éŒ{\&ŸE†2µÒVVáZ2!]å4éµÒ*gãj2 åѯ<6†~›.gÉXœÂC§…ô#Ǩ=ˆ#ì÷ÔSm¾)b‚ x´¸«9Î2Yy5Îâ)œ–¥V~µøjÑ­þ,Þ¦­<ànÓåÂt=¼¡lL·Ör.p‰éZ' ¨ã³{Üúá]¯Zõ*š6~#Š…ý÷ÚŸ~øËÒ Ï9¡˜@®WøJZ—Ví¹ŠV.^I+÷XI{Íß‹öœ»'-ž»˜æLŸãùF3𬽞E_»ñk´»‡ï–<øG<Ø3˜¬TŽ—ÿ˪%¼¾tm˜¬Íþ‰e‹µÀµCÇ{ Ntü)Œˆˆ¨éíԃѭ§êü¢½ºïŸèÕ«^MÓ'_ê»ÇÜ=¤ãé·.¥sN?§föµö™»}ý”¯&îÜtgÒYf!LTÐød2@u¤Vù \nÐú‰óO¤wíõ®øÔ_5ÆãÁÝüN žÂÒö*=°dþ:êà£èúß]Ÿ\G: ÀîÂ$€\[€1€A,ƒz7Ð/ïû%ýòÞ_&8nSdÒ˜;ÆxÇÇ’yKhñœÅ4æ|ÂdâÙÓgÓÜs%=oæ<;ùåƒìq€|µDùnÀ¯ï,±1ü&혙@ŒIÕ‰¿ÑcÆqâ T§:N´étHgÁå- †-NÍJuöYgŒm–î:Õb¯'ŸZ¼µèÖ ,Þ¦­<`K·pH åÂt(Òcz„<Àu>©Òa—'äœÆ¹Ñ§UBãeªXðÍ»¾Ig¬>£.ÃŽ>øhúÅ¿ s¿z.]ò–KšîÐΛ:¾òÒ¯Ðyÿ}ýôÑŸÊÀMÞ Åà3¶ð»ä+”pƒ,«›=~6½òl:böu•!2w–°M{ÖŸÚü=µé)7nÙHë7¯÷é [7~ݦu´eÇ)àŒ©3dùúêå«%>pÅ´÷â½ãÄ{çåG¿œ®ÿýõÒN`pU62øçwnÈàXmš;tð*í Ú>ä>ÎñÎÝ;éžu÷Ð=OÞ“¼¸“Éþ3xàGà/5uÍœ:s(ž6‹¦OžN3¦Ì÷ž:iªÀÓ&O™É'‹ ðX‘ÔŽ€I ”pg?°Ü€Û"~êïÓ<:òX€4wò»ÇuÓ·ïÿ6¾ïé4c !ý9ûÕgÓ«/z5uÅYô©w}ªéž~òøOÒgnù ]ó§k|§íÿx¢+|**èP?kÖ³èüýΧ9ÆÆÒã¢ç¦ø¶íÜ– ÞŸæÁü–dàŽxÝÓë†Ò< Šéë·¬—OQÚrÉ@ÔUiÁ[˜ø”$–Þ-tó7Ë!þÁàqÿ¥û&ôØoÉ~mPª]#ŸðÜä3€½½Òèà_Va@'Ì$€NÀV½§ãZ,t¬4Ä\¼cpíØ¼ƒÛü˜Çûû¨ò:/ËiÏÃðøžñ2)€I„ ã'Ðä “åÜ&p®Ÿ0n‚”uâø‰ÔÝÝ- P?mÊ4i»€Çª¬ÁdÚ¥ ãd5 »¥·¿Wڵ˥m+Øtˆ_8V¼õŸ ãOô@ô@ô@ôÀˆz NŒ¨»93ÜÔù›%ßåFèpz#ÍŒµ3 ¼¸—Ö‚µl*«éáŠ[˜ElØÜÚãÏIÃÆDÁ¶y€ëvBÅÔ \?XšÊzp2ˆJÆE’ÅÀHiˆùÐ=ês"à=,I0 f(vIçôöítëý·Ê¡í˜X½lµÄ€q`Éúh x Õ“bˆ(äŒ:[S.”©•ÎRXK&¤‡:Bz­t(t5ÐBºÊ(^yllyjáÁ‹`ù#(ΊÓ8¤iq mó@œa×ëMVo¬ò’/‰htÀÊ7Âæ5•]=6×â­E ÍâqaºšŽ7L‡²6]¯•‹ððz@Î úíèÄ#¸Uò$á¾ÿŸé/öù š=±¾7|ãÓ€—¿ërzóÇßLoøÛ7ÐW?øUÿd-ɨ±ßS8•–ÌXBg_wvÒ¹çV` 1½g:]ôÌ‹èðù‡7¦Mk¬26­0býŸ…U.Æíñ@œhßS¹â‚HݸSÔÎH¤:aò°X‰sCÉ<€Î+Ÿ €¤žjW<ÑBg÷®îØI߸óôîƒÞ]wÖ>{-ýå IWýè*ú‹‹ÿ‚¾þ¡¯·ä©é¡{Jלr ½÷‡ï¥‡¶?$ƒŠ½§íMŸzá§hÉÔ%uÛ9–08×=ëöɼ<•w{ê…Ç-Ç—‘Ö8ÏÀ©5ð\Ÿä)±:Ùñz>#«zªÒt»ŠÕ—§“ñ^øC>ƒSu>ækCÚ-4]®ù²ƒ6ÀO÷>M·Üs Ý|×Í d7ßï·¯XÊOàøx3~§M <ÿÀç'>ƒßp1ðgÿcÅ…xâ­çدðNdƒ{81Þ|_:?yx3ài(#¸ÈË&X¯Ïòøófy,çaé[¨Î >ÒüÄR¿PÏàø¾AÌê›ÒµîâCIØ?Ç==0v<¶Ac§ä¥-騟Л`iÏ€3 7r¾•–ÝÌŽ±¯SÎ{Ç8t4ŠÎª®0á4:± çïÐk÷}-Í™Tÿ~úó^Ýü§›éöûo§W\ô úÆß|ƒð–ñfÃÒ™KéêS¯¦ýׇ¨{|7}ìE«û]ÍÚPFù¾þ¾äiü¦õÉ`Þ Ú1˜×}}BÿôÖ§“bh3«±+\ÅO€m›ŒzbžúZ’žnu«œÅ!O¤•ælP=™xð*ƒ“Õ¤¨Ó: ‡ [>¡š_tÌøðm&`3Põ4Å;^lAÁÞõGŸ~”®ÿãõ‰BG[0s­Z¼Šö^´7­X´‚öÙcyéàžóölú=Æò–Ë-— »õÛ×'mƒN¸.®»Ô ¾fõ³÷Ÿ™ÚçĹ0”Y>¤¬L‚IpJ‹¼ƒÁÅ)ZBñ4å±üÊ‚X&8öõeæ¢ëÀ?Œu‚ÄǨsyõŽI`g-Ç£èè‘õ@fûÑ"†Sw‹LÕjFý@ùΞÞ+-Kæó$RÊÆV§Ò,pˆÓÊŸ‡Wzײ¹Y~•ÏË'ći•·qÈcÓ¶2 çÑóð*ã¶xÀUgŒß¤¯Ìûþå:C‡VVpŠ÷­îØAÿx'?qæ™u›‰½ÿW¼ç :ù¼“è¾Çï£Ó.:¾qÎ7hß%ûÖ­+˜1q]qÒ‚Æ;FcØÑ»CöÅ?¹ñÉô“z~!^€§Oæ×ó€ƒú­;·z7È çAc€:`g\½ËíEä>…Sù|`×< N@Å«>ðЍœ|’àdÖ€ÞÈŠˆÚgð)Û¾Â&»¦ÊwÂÜ%aÿBÀ þõɶÅ9šÐÆÄÀSÛŸ¢uw¯KV ¸¼ cBÏ„dR`á Y)°|árZ¶p-[°Œ°•&e'äF0,[´Œ6<°!yÊÏ~ ŸtË$€®ÀÄÎñ»÷§úþr¾±>U?ÙXdÅʼnŸ5⋜3T¯ÅXótÜCˉ^‡ñz•tÂ4ÊŠ"£Îq”ü»mv•Tùº¨rV„£¢¢¢Úæ80®ï©6{Ü_“w@ù!á“{±ÜÏ5m%²p ‡ø0­:òðJ·qEGÂsàj~Ètž\ˆÓY:C›¶pYå©%§|1n¯ð}~sÿðÃIc¸‹'vóàåÚ¿C¯Ûïõ4wÒܺÄRèó^÷鼫ϣÇ7>N¯øè+èê÷_MÏ^õìºu…>ðÇ||²îñõÓ=@w=|Ý~ïíô‡ûþ ƒ{L ø¯$€H?Xæ4vfóÈ"¸XøL:…W^à7ÏâeT®Š.o#xÍ<·Oupìq¡>#—U/çtyû ÇbèªKóЃÆAŸðÊ5€A=}bí²Ò¾ƒ¦é¬ÊTN½ˆã˜À;î|üNºó±;‰~BBCŒ ´¥ó–Ò²ùÆÑÑÑÑíñ@œi¿ë ±=`Ò|“ÌŒ³äT1‚ò¨Ž;„×t«cÍ·Õz›ÑW§M¾#œ—gúòÔD|›=àΣìûç †»¯‰Aíîæ4wèûv÷ÑÕw\Mï;ø} ûÆãÞH?ýýOé'¿û mÚº‰^ûñ×ÒßûE:jÍQ é-BøÙüYóåX³r/|tÛ½·ÑmwóqÏm2)ð𺇓¶Ðqé ×úù| §/€%|$ˆDø!‚›ƒ5NáÀ#D ÁÁÄjâ<¯ò‰z'Â5oGöù椑G*¿i‘I~†ìVÛkÐvcè#̓O?èwƒx¥á]CF·Á ±N@ìîЧàJ^&0Çpÿî~ºwݽtï“÷Ý.Ù0š ¬åǶ¼sÛ/™·„Ï]L{ÌÝCVÌ›ÑÜ— 6nÝ84ðÇ9ãç“Ý=Éüëb©I@YóQQfGS"éyuð­²B`:—_‚Ó-²@¸´ä£ ƒST"Ììz>¬¬#z!Mõ©”EF6þ¸‰ñ‘[!>_w¡KèQÝÖ|b=z@ëKˆ¯–ej¥³tÕ’ 顎^+Ê#]M&¤)?ðJSXã' ¯<+O;º¶uþW9+ 1´Ýq`ÄOj¾½ãYØ#‡Å+¬ñˆ]#Ãú®æšƒíª¹Uæ•­¯’¯R­å±08Ãt(GÏÇò1Ýv`.)øsï˜;û s‹ØÅî{ð»ô†ýÞ@ó'ϯÛLtx/{Çet܇×ÒSü¹·í}Ûé­ÿºüퟢSž{JÝúF»ÀÌi3éÈg)‡–{÷ïïéÖ»o¥_ßù+úÍ]·Ò¶^^òÏçKÎ ø—ó—†< ìè8¿"ääÔ„Ý8^ðsP]HyI9Àœ¤Å„DÜË9u’NM&˜IϳGUÊIJ⠃/%hœ’_m®äÀ£Æ`ƒF‰Ï{¼ÅàÞÑEÞ¥½,ò?¯^7àÌßàLd™:äÍøÂ,¬œNìêÉmOÒ“[Ÿ¤ß>p+å?ù=DxÁ¢Ù‹hÁ¬2Y°cL `Òiöô94wÆ\š9u&͘2ƒ¦Lšâ¿Ô­$¿¸ãtÛƒ¿s~¶XsÈJ pÑ>pÜÍO»uÕøØÖc3Lƒ­RNŽ’2€/ÄÒà áU„ò$ä„8Á â"Ä8 ¢#I¨&I¥òRf—½èÂy›€²J4LŒFÌe_–IøˆIâ?†A‡ÐβL2!`•"“¢†Ã­¨gÍêhV>Ë/5t†×³WÊ…ie¬…éH+.+¶8…5¯·Ëq`„=ªû¦^¶¦ ãòäñZ¹‘†SO f®å*ÈžbË’-ŠK)â„•³0øÂt5YK«%gy#ÜèE$1w¸e€Hs'«ˆ;®½}ôµ;¾FxÖ2ƒKßòqzÛß½Mt÷ ôÓ™_:S&ÞzÜ[Ò9–„æÌ˜CG?ëh9Pnløã¤_ÞùK¬ýúž_Ë{’ÈÐùÓÁ˜qb1ø ÓøÇÈ8 Càt20a(åÍ¥—üxy<,|`‡~È Ôí C&:p•ó=?éÇõïÿ2èJ ƒÃãëŽúWlKì¶Ÿú£ýä‡3$°MÊÌ$k³ª•¢ƒ?(‡Ð]žÐêeö4Œ¬òYý “ûu¼Ê§4_çXPê#bøƒë6âdÛDâGþjéÐõÇõÅ— ±KÆ(z`8<`ª{Ãê›ÕѬ|hxx=†t¤óò ñaZuÕ‡t¤—[œÂšWŒÛç8Ð>ßÇœ£¢ÚítDq £Êw&éÐòÞUtd¿÷à÷èMû½‰LYЕÇ?ûxzå _I×Þt­ Ô0Ùpñ¿\L?ý8}ø•p6¤}HŸª{bó´pÆB£ £/`ûÀ3W>SŽ·ŸøväÜûؽtó7Ó¼Q^6·Õ¯àÊns‰bMÃ5 3Zi¨:°ÑXê…Á‹W‘ÖA<#fœÒ’—Ó$hªÃ¤"x]N‡Ï[ˆÂâíRÝ‚UN.…KÄ’¼+ÆJG¬½1Ä–¦Kûefà.ô¼4ä@Óma¬ØPÞæÇp¦ ÀC"èØHûA7МŸM3*áE ðs ±v;Òá ðË“nGG}pº VÛÃTÉKÊÂÈduÖVÇ£8ÈJ,>AâWhÂ+)A$tš y * …8Ï›ÅgtJ¾(§Û•]¯#ïGö›\gðxøšC‘Rõ[õÄ8z z`t{ VÛ2ºK_ÚÒÅ €vœéñÝwT¹0ÖŽ¦È“GÜÁaX–''¬ÞTÈè…Ø©ò8ÏèËÒšN«!u(BYY²¸ByX9 ø $+è¾<ŒžyÀ&}ªˆKH¨cÝO}tÕŸþ>tÈ9J­;¾ðuÒMú9=¶éq¹LñóåŸ|™žÚ²Ž>ñÆOÒøqãëÖ `пxæbúîo¾K7ß}½p¿#ùx!Íš2+d5i $Ví±JŽ7¼è 40¸‹~{ÿïèÆ;n¤Ÿñqû#àñ!Öùd‡Œ"ˆ5ŠÍrnÐ"NÓ4€!‡€XÆÙ4ÐÊäyÀvF(.Aýö¾Àªëÿ03tDADÁŠ4QŠ`ÁE°+RTD,‹²êªŸ»úù_>×îç®ÊºŸºVPV׎Q°`AÅŽ‚Jµ ‚€"EA@úÌÿüÎÍÉäeî{óæÍ›J2“—äää$9)7ç$7ÈM!b€ ‹E@wã4Þä§(Åó0t]G§+¸lá`Lèô'Gû5Nv¯Y<5Gùñ|.pX8? cD0&‹8ü³È"]ƒ[D‹c,žÄWéI$¤ 0ŠB)c„‡4`´ä!?€ DX~G*óÂ*NˆpÏñ¢4.÷ô‡HÀUQœ„ «ùIþŒƒ†| Àช -–b8´`””" ?G§¬4ü‚:´éÀy#óširsjS÷=»‹½ôøKiõo«éƒл_¿Ko~ù&óze$à¡mñ¯;”@Ðo à¹.ƒW; MœÄG?Ì°× FÀccyoÂ’^"$:Š×8·i"”¢<Ýtš·³erÓ©?™«— .‡!¬[!ñ² cÑqFàÆñþ/‚IC_!ßà*=…–I‹¼¬ß¤EÆ=I Š Í[Ò¸ùHy‘H’J¹€#e2ù#FÂÅH¹PDÇü¹±ÍQ·€â,a…Á…剢øa€)‡ºª@¬*Bà‡Ar12™x…7™b@Ñôy,|²@K9‚(o´P 0œòjZ¸Z×J–]©Â:>À#Œ#ñ‡Q-ôgkA.˜Àòæ€Û}3Í+4ܼËJ/ôÉpâà.,ÎÓúh\œóÓi8¸•ਾ§Ÿ+F¤ÁdSflaa-»þvÑÊQ|òBâVÞY7]ÙýÊŒóîÓ© ?|8=6í1¡!çÿÞ—ïѰ £qŒ£KÙ`\zîÕ“&^>‘λë<¾<ïúdþ'4ú©ÑÔ¢Q ú]—ßQÿ®ýé°N‡Q£úâ’×N?ÛåX±xEâó%ŸÓÔ/§ÒÔ¯§Ò·?›(ô‰ÇÓ,\6¢€—m¬B@û‰ÆGÉ?"`Ò)\ˆ˜ ˜Ä+Žq­0eÒ&Ç Ü…©_Ó b‚Æ»¢@IDATô#eŽ;(I½2 œ³q…W Â=$9WHg|Öe\1 r}]Òi<~Q,€€¡Ì]¸ã\7_Ui©ß('„†DF8ô Þ¢=!¼òxGãýr€oþÇiXƒ" ##ô‹‹´¦ïØöŒ¨åcÂR~É–éhçúcâ5‡¤j¬‚€_#=—kT”§—·EMW&!®ñ+”?ç8Û'Õo’'p p p p r8P«¤Ey‹úØ€ ±ZÙ{ã0\((\›Çaœ™…«6ßøë²›?qâÄGÙµ¦cÇŽÖ_<§¿xz´ØÀ‚k6È‚Ó,"ì‚pàø»S~Ø]|À¶â߸â7‹Ôß…Ç…íƒ\zcº®Ñ–Ž¿,}..ÏX˜YĦ*›Îõ#MB8f!”ïd’ î oUâÚ–­´ ð‰³Â­‘-Ø\@9[sè™#Ÿ¡Ö [g\òõ›ÖÓ±7+”‰0ñ‰ÝšíF]øµmÑ6cú~Âõ×Óec/£—¦¿T$`‰ëZ›wË»íÓŽ8àê×µµß­½Ÿ¼F‡¯^L¯õ:Mýf*}þãç|м škÝ9s3·ª@#ó'Ú¢€™[%‘ÆÂA[î`,Gѳ˜‹ké¨y¸¸q07~wŽ3~+¸›x;oC×1\ø!^iizq ž‹«ñ.,A© t]eÁ8uò³~ÀAÌÅG¾ll$‹(_‡u”ú‘†ßÆ“0p°¾Bÿ¿|ÞËqµ­4ØÜ¹sò8pà ØÄv#ÛÍÆWíãßÊ®k¹Æ¨µXp_-×lÔ†àP%š ¨`æ{q˜<e¡Ýü›Ýöua)®ø#.¼Xœ!BðAß]œJ’'*& QÄ™xu-4Ô(Ž ËbKãÒtËÚïãòL †aç7ëZB¸„´.Ù„tnDðWMhÛ²+}/< Œ `KÁh=€®îqu™êðÑWÑi·5.1^9ïf ›Ñ¸óÆÑþ»ï_¦<ÜĨÏín§>óÏâ„"ò˜nլѕ•ô£C;šµW4‹ªìnܺQ”S¾žB“¿žL·ñsžy¢s©¸ë\k\ÔIãßtý=x]#ô¦®AH"½8Aqa®Ÿ#ÒºªßÃGßó£5Îqâî‡AOæ@¤1Vpà‡A<0kºòq‡8,›ØXž¥åÂ5YdFŠÓ8~À¶n›Û]œ0J«0§  Hþñü-£±üÔ)Î$ƒ{¸ ´¼¸¤´/Í<]«mÜ„>Û˜æWÓº°àˆã@iú¤I_l ø4üpL¾e¦áåQŒžŸ§‡/ѬXz'NI%Ì‹êœ(0‡‘ÆXKOçcÀáÒ±#8puN…@? Ÿý6~¡9ÿØPQ¿*ï•ó_á ªŽ € j ~ ˜Gƒ<° V‹µîî?üÕþ@MQ`ðgbìd“AâdyÆÁ‹ÁbŠëâ¸~-!\BZ·* é܈௺@û²•¶Ó™QàÁ…Sµ¶Ô¢g~–vm¸k™êñ×GÿJO¼ÿD‘àÀ³ž.ŽëçÕ§ÛϺúuìW¦<üÄS>žB—Ü} ­Û°.ZpcA.«rÆtàìÇ¥„=÷éIýèO}÷ï+—ìùôjjí¿fãš·bMùv ÍX6ƒ–¬[b}QþÅÿ -•¯xš“€Ã0moŸ÷ŠïÂ-®T¢>€ÃN[&M“LAvnvç;ǯ 8ÁW¸qÒ2ÌÛñ|c}œú‡ŽrÀƹi•Hb! 㥓|ÍÂSòeKKðÆ–#à(äRÞUˆ__0ñÒæF)dy:%SÜ’ÐJoùå&J7Ÿtñ\ھ߭·ñ[žø¸»øqñ8àr ƒ>ZlLø4ü°›Ÿñ—™†—G1z~ž¾D;°bé8%eçCãyFÖ8€9ÖÒÓ¹qð 騏*ð@8À]#cÃLÿjUø‡«Â?Ü `.€UUí€L´¾l2I+³Vñ„qe)äæ?>eØK 2>¾’N×øàVAhûâa¿˜Sǵ:Ž®?èú2Uà×ß~¥#o8’–¯[.B$„C{ÿSÎå«Ç¯t q(NžeÏ|µä+ñ´pùBžtyÚÅLËŽLØ…ôv0Á‹]›ïJGì½*Ð{¿ÞT/¯^„¼üþ¶å7š½b6}¾âsš»r.Íûy­Ú´ª¸Àç§ËSõ«)Ì6 tã”§&AÇ=2©â\;g;ãDsOgpâu|!1âÕ›JH×tÀ‡Ñ…*ü††Ì»JÏÅ7i,}' ¼Ö€Ïle ¨‹g/ Q¸‚¿+ücÌ(¾ãpÖ©GÖéVÁòàQeÕ%ä[1È` ØùÇ-¡KÇõ»8Ž¿ ?vҊ׋/F¯|ŸF±ô}à€ÏÔôÂÛÛ ØÁT$°ÐÁÃOõÚ·õÛ¿_(Ø—Úîܶ(ƒê«_§>´ËAbµŠ?®û‘æþ<‡æ®šK³WÍf¥À\Ú\ÀÜœ…•·›gðWodÒgt|º5wé¸~Çõû8>M?ÞM ¿ï§/ ß§QŒž€< R.â·Ö ¹a:ç7^²ô`–.ÙØ2˜„âhƒa†ßJâ@PT0ãµÛÃ5KW¾Å*Â+zšâWi(Í()£´êj¼†áªqÓ( n2¸â¸4–Ž›i:ÐN–6sËçÇ—vÓ–¶,~Ú®¢AíÈc¥5½X yׯ  €îŸw?ÝØëÆ2Uร#;E¯ÍyŸ‘<¦Y`ÁÂ8 ç;æÍ1¢¸õô[)¯6Þ|*»iÒ  =<êaºiüMtßË÷q>\Gp8Cüë ö»FoßT¸™Þþb½=>~ µÝ©-¹ÿ‘txçéWû^”_÷±Ö|Óªa+‚í¿Û‘RY|)bþ/óiÖÊYb?_õ9­Ø´‚ãxVA› {ù‡I⇉ Gø\4§ ±„Ž‹$ÎhB@h$@ʈ£éOÈe‹ÁáÞâ3‚õsã×µ¡†åÜÇY8èWl”IÑ.Í"E‚)ˆÐ@"“T:ðH” ‹P¥³ÏÅåñ7ú `ä*\?ý'ñHcÈT+§ZºZq8¶’9`f‚¬–¢¬4Ëš>®2>M?ì¦ñãR…5N]ÐÑ9:¸É$΃ôàT"‚ ™_]³ÇÜ«kË…r'åÃú”‚Â`8 \ÀÔ§,™Bç®9—Ú5iÇ™›N»Þ¿þ}Z¿e}ôÒ“æÉ$Eç|'ÏšLË×.§1#ÆP“úM2ÏÌI™›“KW »Š:µíD—?xy´s %Ž:›ą̃»/xŠ¢Ò—Ký‹~YDL}€xãª[».ºß¡Ô—OàsƒmvlãäZ³½øªBçæÅßw¸TvÙoË賟ѬU³ ¯×|MÛ øÅIô)´·ëGÆå½°›aõY +®†³å&£‹ñáé;1ø®b@Ù~Z©* ÝIV˜HãÇé§ í3 4L?ÕbiUdé8W8ðl×r³+0Œ (:Ì«xÒ>Î8Ih/!¤¹7p p p ðçÉ, $À¯pò¡É²Á»ØÌ±@£jq  ì{ùÒðf·wpaÇÎK7|S™ÊÝj‡V4jà(ºú©«Y†àL‘„âfgð}L§Þ}*;wíÚ¬lºØ{ íÑjúý ek–ÙKÏPOQ™‹%Ž#TéE@®»©`½>ïuz}ÎëTøh!íÝjoê×…_èü;¹T— nO¦eý–tÌîLjE½7lÝ ¯ Ì\1“>Yñ Íý…_ؽ6`ù¬üV Ùï §2÷ Æ‹ Q?R¿ÁqƒY÷kY|Â1‹Ví×ÅP=ߎQéù.p0nø/áYïà©àoçmÄ™4nâG}À×èÇ*iT9fë`êmÛ¦¡HÅ„9;bˆ+Ôx@¹p­ Du" ¦ƒ°,^°"qLL£SÅ'Y|2¸ÒM×Õ:¤‹_¼T´“ÅÅÁã`n9üø’©Ҧçâäõ†ìJ€‹—áâø6”¼øÚÒ×häê‘´gÓ=ËT‰3?ƒž›þ}úý§B„槂„—«л‡Ð¸ã¨Ó®Ê”§›¸KÛ.ôâ•/Òùcϧ gDõ3uDH¨S\°…OE@ ¸NxÁÊôõk_Ó}¯ÞG óÒa£¾¢ÓøìàöfêÕ®G=wî)uÇsVÍ¡ËgÐÌ•3iÖϳhÖ Q€÷h´üF!$<Ó0ì×~Z,Nü£m¦aNS!&Y>~yPÅU×) ] ºé\?pMXžož2Á’bá©Áõç{‹ÇÁCY´<êg×ò›ý2^5s—@ðT ¤ç™0Û4³Aϧá‡ÝºÆÅ¹°’üqñ ƒëú‘o\Xan¹‚¿â9Ïójc¸ÕºùBáÓä€üè—•*„APÀ/í™3†F::Mjñh9|ÃØÃn¤GŸí^ª ÏH‰2¬Ú°Š†F· ½úwìO0èŽw¤'ÿü$]û̵ôÄGODB?ç-'pÔå`£õg–í´êmìpqÙþùë rK;‡Æqë ÖÓ+³^¡—?{Yâ:ìÚúvî+¯ tÛ«ÕÎÝþCy9yt`‹Å‚¿Û ·Ñ¼UóhÆŠrBàÓ•ŸF ÜçD(Õ>Á0D†Ý„¶A#øqUŽN0Š›,Ç@ªüü²q1¤n(NLº8å€ð)†Ø¢éO1nl¾([ç§‹)£ÂÛœ¹w»ªw5¨ìö·òª ‚á[” 0,"tÀ(Ž“ãÉΑ܄tnZ]( yT¦©Ìr”%ﲤ­L~‡¼KÏ´µ¶·ñ«ÒK\h1F_ûþ5úêç¯hŸfû”>'EÇ6éŒCΠ‡ß{X„cw×Ý vÇl7l ‹¿ˆþç˜ÿ¡‡p¨”Í‹ãù?í\ÿüõ´­Ö¶E€=PÀ°£GªÁ'ÂàBÞœ"@qæ/›Oó~˜Gw¿|·ÜmЧcú]§ßÉÝ;5ÙI²ÙÞ~ðùÇÎ;ò=l¿ßï  â Óš.vöϳi붭–¤ m"çÄ€œ(A*´à¾áö²&&ÚÆU¶Ç-§)‹âýr;a«$pÊoùCÓ¢94À;˜”é€“ŠžP?s “ñ—Æ…¹þdóqü°ŸÎ/)œôÉòP¸ëúþtÂÀ)É¢.N:aàSi € f½ ~¶XÌ N]7Þ‡Ù…#)=ÇMŸM¿æ—Mš.­Tô“ÅÅÁã`©òññýpª´éƹxÁ_…8 @É<À¤ýÙ/ßÝVPX cM*t øïÞÏî¥Ûޏ­Ì¹|Àå4ù³ÉôóÆŸ£ãôf‡R}závåY釋än|åFZôó"ºúÄ« —úeË ?d8íÓjºð± éç \sA”È_•N†2ïàø?¤$æ‹ ùú:1ïÔ¯.ðjm‹ÞÙþu˯4iæ$šôÉ$¡Ñy·Îöt@×=ºfµ~N±«¼ Ðâ±çw:_îÀýÓ—±B`ùtújÍWòU °]Ú ¨± a€B@ú4p`4]Š~Ýq`pÜèJõk¹“Â/»âi:už›ô™Ú'$ (IÇl éREg›f¶é¡ì©hÆÅ¹°’üqñ Kåúq©xâ*†AP1|Îz.L®" ë‚¥æ€Np¥NTTh0®´ŸÂt7ïó¿ìzÃËaÌY¨zsñ›ôŪ/¨}óöe*ãúiÔ€Q4êÉQö(½äi7¼!B4 ô“Giñ/‹éÎawRýüúeÊßMÜcô½@ç?z>Íûi^Åy[%€Q ˆ°iº¼¿£ÀI(T1 .+ŠÁ†qg/M³Ï¢;&ßAÍ6£>úD_àË›5jæu»òãCZ"_½i5}´ì#úè§è½eïÑòËE¨W%€¸PÚðŸ(­ÐÐŽh?v¤¿ûð(6úÕ±`ðݨ*ç7Õ*±\nJDŽAH7Ÿ˜¤88888PU8U¥%ªA9dÁÊY 8Š˜”®’6 cÆB*Âh±û¿œ0Þ/È) {fÞCÿ:ò_ P&sJïSèÑw¥9?Αt-‹å<íî;ç‹tpo÷6 ½(ÝæýÔ²IË2åï&nÕ´=uþStÕóWÑó³Ÿ/ŠBÝÏ¡V ä(Pœ¸Š(Œ2§DàÜ ¸€ËévÙô Mœ1‘&~<‘?»žC]Ûvµ§p¡›wQ!·_Óü¦tôîG‹E¬^@.ûÞûñ=¹Tps¡ùÂú \í»êd”LÒç‡a·oÑ®jOÃÕÉ­Îe¯N|e ¨Ò €Jk]QaE¢~-ŒÂÔõánXý> ÀýôŠ›©—G¦´’¥K•G²8î‡ãòòqJ »4|\K×øàV Üf1~xà7Ö†!\3LÂÆÏXŽáÄ1²‰Ê~–Iéí%oÑÜs©c‹ŽˆÌØ@À½fð5tê§H^øø€”MÇ0ò6Gð‘/(Ó+çÓ1ƒéþ3 »tÈ8?aÝ:uéÖ“o¥N­;ÑͯßÌE± àÌ™¹\ •lPqQVðŽ-Š õEn!%€o»áŸoR7R 0\x\/¸ ƒ»­€¿–0“fò× n}þVjѸUàw|w@_¹;§(¶g³WÓ½öŒögЦm›h&]à½ßçÓïÒµ m[i*R0ÏùÖ ýì—þïÕÁè›®^0UŽþd•f›f¶é¡Ž©hÆÅ¹°Òø·4®âf£-²p (ʽ2¤Õ!€µ“ú•œÂÔõáFJ} À§?}QºÌ|qydF)yªTy$‹óá~8.7Ç Ëâ7.‘¹¸.Z2¸‹üÄ·1Œ_Ú~cÂ,ß&„Ï¢GDäîMxáB˜*Ì-¤»gÞM÷}O™+Öc¯tâè…Ï_`á˜32à‡ýøGž°øÐÍe†"`ù†tÚ¿O£Û†ÜFýö넬™ß÷þ=uhÕ.yî¹£ ú¥\ vqÙEŽÊfŠ(Œâ8s.¡‡rB€WŠ#ÐË«êOáOöŠ€Æ'Koè´Ü¡%Ÿà“|olƒº ’Uk»ƒ¯Ý¼V^x{ÉÛrw.a”'/sÂö-´¥y†Øç„†Á1m_ÅKÆEÅKàér€ ¥5ö9î&té¸~Çõ{8±4SàËú"E¼¬IRÄKïâÂòye,(à‡$ŒÂ×–(&­”AýxŽÆù­2Ÿ£?Ṏdúü6몄°yn+ Å{õüWáT3ož¹÷È”hàÀg°wÛlù½:ñÃU»Åøñ‰×â%Rµà´Zá,ón¥›p Ò› z Ø$U=ŠJ¹=pÀJñÒ§žLµÌÀÌÉF™˜°ÇIŸ0/kzå¡ 4P¸!Ê6½¬À»kÆ]4æØ1Š™±ÛºYk:û°³éþ·ï_vÆ‘‡–e`+ùjXeÄÖúû«§o–C׸žjçfozoÙ¸%=~Öãtý+×Ó³sŸ„F”‚!—C…G«PVÄãÈ?ÿÁEXX˜v@X,€y‚~2¸UÁ_iþ´ö'zòý'é‰÷ž :µêP½{ÈÝý»ö§½wÙ;*ÓvúÛ(¯³û1b·n£O—JÓ–N£·–¾E‹Ö-²í(J´_Œ•6ÿ¤)Ѹ‘ßÂÃQÖ'˜ÀÀÀÀÀÀ*Áì­«Duª~!T8á½S''²ùüÊ¿:ðÁ÷ÐÉcN¦…+f£H 4N?ðtzä´G¨yÝæ |$´ Œ ‚xmÁµü*ƒ–Õ¾â½êÃeϩˮú®gàð³Í­›[ &éÜxøAƒ_¡°ô8¼dÍùÚˆ»FPÇ‹:Òéÿ8îŸr?-üi¡{{þÙ½ñîtö~gÓ¸þãèíÁoÓM½n¢£w9šÕjD›ùU~å¥p [¸°PÖð˜“ñ…1‡1ÈãOÆ Ž=Œ/ß¤Ö áÀÀÀÀÀÀrç@¸ ÜYœ˜Á©“O¡AðØÃî \ 좻-XÜ#®ÆaQm²<ü#^we8Þ.¾xÀI¶q‚‚‘^Þ%„‹b²ëƒ`–ÌH¼È8˜‡"AŸ®ŸÎ »þ(q"Åbñ&:<1u•šn—`¿å3àÆJûÆø%Þd˜Ð€[ãà‹àÃa+œÁ÷<|ìÃt`ËKC9wÓ–MÔç†>ôÓo?YA¶Vžs'€ªÝÄRbFHCyšÔnB÷œvÔî 5+þåë–Ó%Ï_BŸ-ÿ¬è^½«€Ëgç*ÌIlìüÃ~Û¦ÍÐN"@ªk9"LbN@Ø•â7Jõ'Ä«P Õ¥£B*╦Z‘wÛÚÊ連ºE½Ú÷¢ü:¸^&œ¢øðÇéõůÓÔ¥SiõæÕѳ ó ²Ï<3ŒµÏ$°Ð…%c)p‚ ˆãOç¥5ö9ã&té¸~Çõ{8±4Sà»kAóéù^¼ífeéyiäYŠH·eæ°õCY‹xÀ¢ŸÈg¢Â¿ ˜°ÐÐg+pá×g*ž»øwÂÖôÈ›5lÂ*ë7(*˜ó§N>¥haŒE<=pU°w]Q8qÀ…°o„|»øbXŽU0ðà˜…w6y¡¾ï)%qâ:Œæ3  Ì©LIP¬àçÄÇÁœhëõéúéܰë^±‹Å›\’Ám!‚'}¸<7~á/üjáÕüç'Ú¶*“)—½´P2—9™#,…60Y@°0üëBC ~GŸ d€Y€HM[Hœ( O\n#,8|,NŒ_ã5?¡ÍÑ(CÝÜzÔ»}oê¿:¢ËÔ¦EŽf[Á6šþÓtzíûWéÅoÐ/[XÀMi•=ð‹5ÏÊ€ÐwÊÄÌÍ¥4öÙï¦sé¸~Çõ{8±4SàËz$E¼G^ž?.z±ô ‘ˆ(ïÙã‚x¿Þ¼S?î£qtÞ#çѺë4YÖÜSºœBò픿“}Á¾+޶3í$m£BŸœfâ2««å‡Ë' P9éàøå³ˆslÝô=}ïßÜp/@=¾7 掹O@ñ Ÿ”_B<äW/¾]õ-}c, ýÇP¹;à®ÉÙiã¬5@%Â%‚µ:ˆ®>èjzcðô`¿i؞èE|%:cû·¿ôŒ]ã”-\pôgÀÐOdµèUý\­‚¥ç@P”žgU2/ªd¹B¡b9  zÇÅâ_ý,(XÁÀ®"~íò6C+6ϲ•µüLOw3]EÀŒ3èÃ¥–57I?è AÔºIë"¡I)£°ʆÙJ£P!Ú Í,̾µð-2v-Zµ(+ås‰tÙ¥ M8cuÛ©næ¶t/Œs”nÛIz-;—?áÂ@Uh}àºÊ\|htëzB|‚0ï)r]¥üîeƒJi `PËðß ~£›Ÿ»™nŸt»[ýíÚŸÃï›á‹Wô¼‚^ô=Òÿ¾×pj™×’pEB_Ð>”ÛuŸ •¨<ÔøWì¹òx›³/°óÒ–å>¦ê¹±‰Ó‚–??…W”›nþ©ðâââ`quòñR…ý8Ÿ^²ødp?ývV=•q…gžàn•`ÇIXq”y&½ Äí*^9ºr¬™éæ ìa¶GÔY8ÿ×'ÿ¢^­{•9wœ8¿ßùtõ„«£»˜~A.gÀÂ>(´9Ñ/ãJ }ÇŠ¢6Ç^°z 3˜î>ínêµGÙË(ù™ŸìHÿúºéÍ›èÑÙÊñ¼ ¼ó‡¶WEŠ”U M[_g¶‚†öñ³RÁÂÙ˜ðC•Cp_?!(.Òi»X-ý¼ q±3­iÔ•´ÌÿÛ^¾öo·?õíÔWK\æ”]wê*ö/=þBŸþô)½´ð%šòýúeó/Q››¾(J+n6ôËðš@è>Ùä@y¬Éʃ¦[çlÐ÷iøaäçÃÜpiü>®Öz¹0õíªò™–»¦»º\¬éõ õ ¨,°¼AM-&};ùA,#þš®ÐÐY/G8áÕ/"ÀB¨1ÇÙ?[õ½»øÝ¬”l(ß°cýåŽVË+x%Àd‘ÊfÊ#;é,pë«î6vÅWo[Mg=r=>ýñ¬”Ñ%¥ÅÕý®¦›ûßLyyE§ôD€ÙÖcß¶]Q|ź¯°ßžnÀ©µîÉs:@^à#ûrR@OàU|Aëm_Ð~uy§?7¿è5ûº@²“œ®°N!]ôŸ‹è˾t«ü ð9pç骃®¢7‡¼Iw~7ßæxªWX¯ä“Ü¿Ý>®ý%vÑèÌ/NöÁ88880‡³]q (¶«æ®¾•…ÀL5〻(g¿ íºƒ Wõ, LÃ*Øj“:š>V¨LÖ@ðv„9†ÏBj¶î¨[§.ì;RN¸Â¿ˆÀ/Ã#\",£<® ÌGç„bŽq’ય¢ë'_OøÔ[¶Í NƒhüÐñ´K½]ä;òò-y(Œ"À¶¿ÓÞ±m ¥†«àz%¼ê`òêƒóŠ€___ ¢¯ˆ°E€Þ¯¸¯hœ ã4ë ÖÓþýZµnU¶ÙWãèA1tø®‡Ó͇ÞLoŸü6î=šúì܇r·å&Þ  "VrI7Š€e€ÂâNÿ˜±Pã*88888%ÔøW²Ä§ì‘Á⻞P½¨Ô!Dh~àÀ~×8…«ËpEÆ1UÁŒâk0䃰Â|?p`4> +<›.ÊV¦,tË’¶<êR•iº¼b¿UÜnú´ykè`0ê·ȤJü1åƒÀòÙãé\$ÂÙµrM[4úìÞ§Ì=«ÏYt÷+wÓº­ëø+üi¿Ü\ï86-ǧ1öy÷ÜÎ+ì8ⱃŽòšÙ>§w¯¹ÌüÇb.=üñÃôÍòoèÎawR“zMÊ\V—À~;ïG†O Ë_¼œÞYüÈ1{µÏÁç ðúúî.0;ýR'øaŒ#®Ó'”Ç~æÃ¤ÎHêb¾d¿ç×W 7L «à‰r©à J”W.·3áï×~O#IO\ðAYLɨW»·ÇqbWoZMS¾›"¯ Ì\1“ øs Ò—Ñ7Ðvl¥o°«¯ H<âØŒ]ÁHÌÁ‰  ÀÀêÀÌá¥5qi\˜ëOFÛÇñÃ~:?Þ—¿¤ôf]•@Ö‡i´”žÂ0 ÃU¼8¸¯ia…)ƒ,=Wúˆ ¦Ò8Ìz+™|E€°#2ýÂ$KçÓWŠvq¬v“á:(Yó¦“W*A/Yúdp¿à>^ª°W-/)âÕ8“¹ã^è$¯0˜´«‹Peà’Tq T}A³ª*®Ô‰s€ ¶wθ“Ûý°"á4ÃB7¬ÛFünÝñêòî?^À¸sB5„i®YAH…)xËåS!J„*„5 êÝEïÒ {ÑØ3ÆÒ^;í•a)ã“5­×”ÆKw¼{Ý7ý¾"A›;qÝbqbA jèa]Ê‹*¨RÀDK1uÓ~%.`š–ý"ÔC‰?ç'íÅïð#/ú¡4…a˜¤×EŠ.`Ü0p† [#Ÿ-ûŒþëñÿ¢ûμ/«ŸYä\j¼išß”†¶*öÇu?ÒKß½D“¿›L_­ùÊöQ´§ ýèÅPΠ)Ñס s GYãEYxðÔ(TÄš,Ûydƒ^I4ïã¸áLýn:t$„]˜úÕ­Q­Vˤ`JÏ,ªuaÍ.2±ô ¤»¦vçTwQ5-\#hÙôÖªºq„¤U@á *sž+7ïg£:çqåçäG»Ï¸@JÃÏU`Uö¡Œ˜á±»áZß™××ôÝxÜpÏÇÙ®](—N?5ÅM ‹á.=ìRºwÀ½Ô°VÃè5ýR€Þ  Ÿ:DñëÃuß¡ ~ƒÇbñZêj¬ ·¯B€¨»ºzoî püxU@ï Ð×l¯ Àâ•×eÿß¾A×MºÎ)að––­¶¢s;ŸKÏ xŽ&?ÎÜûLÚ!wûÚN^È'ݾoüÒÿ1ØÊØ@?Š›K0>Ô–¶€?p p p p p pË¥`Òã€.œWw]€‹ÐÅ7/Ì¡°JW¨s„U›>½T],#p»Â'„oÜÀÜ(s¹›5lFƒ{ ŽzŒÀ,<†ßå¯ÉM„dÊ¡PA..Æ3¿úñNûyOžG÷¾uo™ËGàˆ½ g‡?K{7Þ[îûœ{|¥†p^_‹£ ˜UxÊ(¬ ÔÝØœÚ,ìžàÂD ‡À(J”7r¡"„~Xð•þ¥‚ö8Ý;­|x—¬Þ5¾o³}iTÏQôÖ©oѽ}ï¥#w92ºTÒí/è÷ª 0sŽª 6•2 ¦21Ô+p p p p p †á€¦”/HH ê×–ÌU<×U܆7{yyë"¤ð§ÂóË–‚LZQéÐK…“,.Ü/”—*ìÇ•DKãKJ§xÕÐÕª——ÓE»h ËnD#lâÄU?¢ãã’°ý8C7¸EÈÀÉc9žŒ×øx>¿ÎLó™G¯û:¹Ç‘e®ÜÈ~#éñ÷g៿­Î}!Ïà…|_-¼AŸÄ‘v­gaWŒ:ƵÓÂ(0¿À¢,—ɘ·}ô£é‹eóé–!£³þ^{Ûfmé©áOÑ•¯ü•^\ð"gϹsæ9( ‡>ÄB9ür|߽߀¡è{rÚ‚ýÉ ªeëÉ^Û¹YU¬_¢oB×ZÆä~ª÷pLäg>C¡PÈå”6Àin Â=Š\ÖN»•šÖoJúc@0eå@n­\ê³k±k7¯¥—¿{™žÿæyú|ågÑ}èçh;¸h\ôã—~,·k« ²m®¸ÁÔ¸»¼ª“í<²A¯$qñÉ`>Ü «_]åqª0âüxMÜŠä@PT$·9/‘{¸ïËzÄ€±ÅX\Æ5k–(¬¸ž«¸R Ó:ùa…Âp’™dI“á—O‡^*™0Yúdp¿<>m?výBÇxA›U2¸E¨n·BÆï þ®`% l0ZÓù.׿Fþn;j¥n&B„jõsY(¼kæ]Ôþ<¦S:—p¼Ÿ]ö¡^{ö¢~( âÝP(`sp ¢9*ABvlU`–{ L¤,2D’o¤<ŒüµXŠzaÞ$únåBsæjÕ¤U|2„Ö¯SŸn;ñvêòñþtË»·Èý…PZÀbGž«å Ë~"ÜAÁe€z ’ OEÊO·`ã²-ÖAí cüÂø‘7—KÒÁÏüÅŽ2`ø#áq¤™×N¹–ä7 €b0Yâ@£¼Ftê¾§Šýþ×ïi₉4ùÛÉ´ä·%¢Ë’¶BûHB[qƦÝ]e€Ìc.Ü-ŸöÄ88P58 ã²¥ñ×}’Ô¥ãú“Ñõq¼°,zŽ(½ba\/¾X™½x/uñüÁ&Që²_ƒÖ˜á+Ë9.AGaØ/i L@‚”HGórЀL%rÇ`Š8 3´q!øˆe¡Ç¾ÛoŽÝÊnvBF¼¦…ðé§·O˜¢¬ª½ÏdÇÝ"t`ve»Å_ýò½úÍ«Y©îˆ¾#¢vÀë¦ÔÕW.”÷úеB Gö8¼9¯GÝíëùæÕ>æ>{Ål:éž“hÆÂY)»OdDôð‡iÇÚ;RaÜ\?­“ãÖ>†>œqÛÀiE… ˜ðšÚÉXnùÄí§¯X×y=@>7ȯ(ÿàäÐ_^ü MýjªfÜ,s`·Æ»Ñ%^BSNžBõ0¿Ûñ”_O|‚E^ÁØp_б‚~£ó“éGÅ”B(«™¿ìÊrù¹ÀÀÀÀÀÊâ@PTçC¾U‰îb×ø±K& c,–u¡Ì‹g›6ŒEµ eHgÖViP…þ’Ú…N+H[îàS87^Fst×£©Eƒ‘pG/Ñ3N‚À þ£]`T0æY­*'T€wÝ]aVÞogav妕4ìßÃè©OžŠèdù·çn=é¹3Ÿ£®-ºÝ à*Ðߌ²Cû g¢ðû˜ÖWË©õ†c¬BÌ<&sæ73—¥Td«ÐNà@à@à@à@à@%r (*ù¼d—?d Ÿº Oæ–„§ñø¾·úKCßÍ×M†q€…'WX‡€*–?-§ â‚m c+Â/’%ŒxM ¥€ú+p{ùqË„S˜]Ç.Ç«ÐË ^.3Wjç֦ᇠ/î%‹rŒ !G•12Å¡X„]yG™X9a•*Ôbg‚¬^á–ýfGME×L¼†¶nÃËîÙ5;7Ú™;í1:½ãéT°‰ûÛfî_zÙ»"ÈA@3B›(Œ² õ+&´ùJ-.Úõ 7®U¨âmh¬(uTà+À7ðÐ9ÅÀ–œ-tÁ³%€Ççò 6ÎoLÃ; §ç=OO÷$ ÙcÕã?ª(sƉÌqFð·ãÊ3§+'úU²¾U 9ª&°´ &p x©] 5„ºˆu\´·Qªtììö eð¥k ­#€YX aQ™«ÁBf1a’_¸çÓ{²r àôÃN§ZÛø]gÄÇõu´™i7uÑ6 ²[6hUÀ®Üvo÷–{(™ñ 7œV­[Ufùêä֡뺞F5šò ù(7+ ø'ìâ:;¹V àôٚ裰©L e’Ù6d>©"@: Ÿø¢€Q¦@ ðÇgÿ”©Ú¡âºìÔ…þ÷Ðÿ¥i§N£«{\M{4ÜC”Jqý)é©3žŠOûVIý«X¨|@å·A(Aà@Åp@­Èý Åò"WwŒuGL„{(Ìî˜üƒÐßV$Iu àÛ5ßÊÍ÷Š›©»K³]è°ö‡Eíƒ6bÁX„G@–65í\LAƒòòì/e…ë+XxÅ'ò¬2aV àxÓ—L§w ¹KçfZü”éuDãOO­ëµ¦ÂM\7÷u³‹+uõû&ꊾì›"aWà´§â&(þYÞ1Á/= ~£Ø”³I”o}ý–’ nqNÛoM4‰<êAêߺ?ålåË“0B¿U0¡_¹}Í/7úWº}ÌOÂ5” 5´ŽÕ¹ZAPY­ç.Ôïº(—†Õ¯®ÂËâf“VYÊÒµsyðÂ쎪@/;ùº«…câºsì‘® iÓ×§Uå­)41¾XHäCáÑ.²¹xB÷ÝŸÜMÛ Àв™Ó9­ès¬Y„~çD€„¶³ŠÍeÄ+ø7ÇÞ­@ëîj뉣øá·èä1'ÓóŸ>¯”²êvعƒÜ phëC£×’(DñÁõ•“F9¥Âš?ѧâW%õ5·F®ò |Þ9íëòJ(ànªµ‰.xæziîK.åà¯@´ËAô¯~ÿ¢—¿Dgîs&Õ+ä×XÁ$§\EjèWF¡&ãÈ̱ýKûX&ýÌë[ ý6Ä•ïó1ðwûæoÜÜSÕú„_ÆLÊ%¥óq4¬niÓ?.­ ‹0Âo%q |°‚ÏûY’£ºš=†¸8xLé¨GKã*ÃM§<©p’Å%ƒûuôñR…ý¸’hi|Ié¯B\|‘û¥l€©…»¥ÃÀëîž:x/nøI΃ÊOö‹° —?¿|‚_X¸n!Múz Üw`rZiÄsà1Ô¤^úu˯r/ƒ¼ á³: ý9|=ßÝ4§5Ú¦(§k †à⫃ 8»Vèå0ü·l¤?=ý'šûÃ\uì(ÊÍÁ7û²gšÖkJœòÝþÎítïÇ÷JùQ|P>ˆ9“ù*7üü—ð©@„¡ÜPƒú;A§åºéœ6=7qUW<ÃwÌÛ[ùïOÿDk7®¥¡Ý†¦•u@Ê>Ú4nCWô¾‚.îv1Ÿ?žšó­Ú̯µ oãn üÃE˜û›|VÛÑ:¾úŠªíÎɃ ¨<Ⱥ§œ³/ï<2¡_Rštããðâ`.‹5¾$×Mü•Ã,í‚©ÐÁW«ª”ŠFØE(ûEðÄ{ûº{¥Ç[yÇßÂÌñVM»[š*ÏÏFX†`wØY°¸gæ=e>W;tí~³ÀATv'×D8å¶—8ôþ· J­B ž(+„få;^ 0§Üãìò¥¼€SüÉÀ±Œ¥Ž 5¿­Ŭšþûe}.£ûÜGj5Šîpï@ßuN¯h}µKØ-‘_7.]¿òÌà ÏàßThTÞékxÀØ‚Úô×—ÿJ÷¿wº9¼râ@£¼F4rÿ‘ôÆioÐÕ=¯¦ÖùüÚ‰ž0§jÜS2Ž (ÕS5Rw[¾ÉF_ói†pà@à@à@à@à@8Pã*U7 mH$r@šÆµ}ÝY¨Ê"5Fè—…+ÒÅ]MÌ%„Òá€#ÚAÀŒ€-. Šß¯ûž&~91Š)q†ôb9E€ Ŧ½E6 ÿ¢D›³QÅ„(PÎ8!Jý×oÝ;Â?î€"`ÚÂitâÝ'Òüç ÝlÿôÛ»M8cíÓdŸ„¯XaMë aL2Ô™Ô?òýšúJésÚ)­@•(hoU¤˜WT~á”ÆMSo¢[^½%^x,eqzÙ8Ÿ›/_ ˜rêºå°[hÏF{F¯¸÷ áÕU¶9ó«Œ+íw~QÐ×ÊÚß|š!888PÍ9`ת¬@­ þjÎÎRË”`ª#tai\@íξ CÍŽU±÷Wƒà_¾-o„´cNl-À™ýÌM÷½ºÓîÍvOúÑÖŽ"ýAÚÝȯ$Üên”^V `ÆŒ__;–â2+%LÚm‹'«Ã;«Я0¯„g¬xé«—høƒÃéçõ?—2Ç€^^`Uõoן& ™@wö½“ön´wbÿb@™åUð@7p p p p p „KÓ`R6QdÊ‹Q¹XˆßêÊB”3Ò°ºç¥„ÀB Ì805Š£au  ¹Øp7,½Ò)¥›ŽR!N±…{Šü}:~I}z.ŽëËÆO«8%¥S¼Œ\¿T˜W8»ö¨³ò¤<ˆwp2Ê;$*dœA D;`\ÁÏ»ëØ¥¿÷Ó{iоƒ¨Nndfô@·¿x{¤`å.þ“F!¤—æärÆ(GãBBÌ)bŒcsú—–™#lß.[( P/½˜Q€6î˜óúgø=´Cƒ,élyFôAwîP;2@IDATH—L¾„VnZY4oráP/ù3®–Ý–ó.ÞÕw¶ KÇ2H«†Ãšø$?j\Æ•¹×$RÿŒe3hÈýCèÁ3¤¶ÍÛº)‚¿9€ö9r#©_»~ôÒ‚—èŽOî×wT)&ãHï}À˜à¾v—±…¾¡c 0Œ5ÚgF7p p ;°sqvÈÅR)ï<2¡_Rš¸xVRÌpqÔŸ®Ë̬P`‰Là@à@U劺X„—…ôu'ÂÞMÕìøpÏ¡QU«Z£Êå,ìíÂ0žq!|Šåt|NïÙ/ž-SÕ÷k³íµó^Eý‚?ú9¯}CŽÁãtˆö}BÊŒò:e–]l= €÷Ú±›£íæN= §>Xü×ñ4géœ2Õ/Yâž»õ¤‰gN¤®-º]ܦ¯àÝm3.ÜúËx`‚ ðÁ5^ÐJéwÚx–whkç…ð§'ô\ç$Àµ ià˜ôÖWo¥Ì.DV<på {Ÿ@¯ }…®;ø:j^»yôŠ{GÆ[Ü«èWl“ö¹Lû]ų!ä8888PC85¤!C5jÌ‚QúUQÁ^èD؃`g¬ÆkúÄ™ê[¤@(»ëY Æ6oÛ\¦ºÔã¤hgB/úBæú` ýBûXŠ\!¼ÊN9Êî]h•*̲"ÀU@°Å~Xÿ 3„ž›ù\Šœ2jÙ¨%=1ì :½Óé‘@ÆŒp&ãÃ(È„à‹©¿(CÜìÏÄ”R ÷€gª0—)®)XCç>~.ÝóÖ=‘¢&“²„4åÆÜ0¬ã0zmØktA— (¯ ¯dE€ŽEís‹¾1q>8„ʃAP\­"4y \EJŠ‘¼E  þ"¸!‚œ'à‰°çîèz4ÒÊ7 •¡Pv‚‘ `lí)Vü´ñ'zzÞÓe*ñݎ„|wçŠs @•VÀýD„_¸q‰SQ …Ž;›Ëq“½~&PYü±«mZ„7ÕÚD~æÏtÝ ×QY/=tŠe½x}↣n ÑG¦¼B#©"ÀÝ¡5‚˜å9S¬þ™Ž!§½Q¸Ø“Ê?ü¡SªD1§ð™ÀÑSGÓû#­ß´ÞÖ3xªêשO—t©œ8©+ß¶ðôŒ{(Ì)™§1W;}Îö;®üÅ”O¨ú^0åÌ (gò%rÀ8)Žà/Êy,ôËÒÄëŽf‰y„ÊãDÑ1§îûì>Ú´-ó›à;îÖ‘vk¶[¼À""Œ /Aø€Ð~‡þÃ&V‰¢äמ0JW¡GÚõ•œ«ŠV@ðàGÒécO§UëV9”³çÜy0==ìiÚµþ®"ŒáÖvµzÀ*ÐTÓúƒ¾‰ù(ÅÂqJ i»ëI ¸Fð—Ï+š×)ôøõÊׯÐÀ{Ò7Ë¿)–MT ìÒhÝ4M<h~lŠúœíoFgF! ãCPû¡[ô»LúžK#øRp \˜‚9å% mópçer´ðÖ0_ZÅKó([8®5…‘ËÍ»«â’Ib]à*̤Kêè‚ÕÁ·eHš¨ôéÐL…S’€â–ȧã‡ëÓsq\¿KWý~Z O›é(€¦Š\Û/ήiˆ†‚pôS”Vq#á·ªrÀi'í;Ò–{F)ðÓ†ŸhüœñtÖþge\‹ã<Žî{ã>*(( œm9Ñn$vÀsùbÀ\†åäPANä"_¹Ä=øƒ€ª—ú¥*€¦ìö’;ôOž— ÔJßF¼c$†}´ä#:þÎãiìc©K›.Fv¼vî@Ïù]6é2š¶xÕÚÆ9°…°Kág ž@‰!—¸1\êጽö´Š„¶óê’VI6GzË >á¢8x1˧0»rqœ€¸l&Ó¯ùšN¸ûúûI§AB²`ª :´è@O ~‚&ÌŸ@£?M¿lú% ªðˆOûˆ"ˆûŸëJÿà J6·nè0è7ÁlïÐñP >èó6!IItüøÂö™¨™”€¯hÖ-?ú¶ÞJ®c…¦†QöÛç‘)˜ <[×ÍGý.mM£0¥©®É*8•Ä~,88Pap']ΡFȇ°/»”F »ýÖ4’óºŒÙ×Xc>C·n̸Gv=2:r¼Õô!Ý}tŽ%Kÿ2p¹#ý »ß¦ÿY¥S’RØcí¨‡'܈ÍõpO$¼€×ØþøÛr/À’_–$É¥làêí@ãNGõ¸HŽfº¯@!‚ÊŒ7ÔŸù  $]ÈØR`Ì–ÖxB›hž²‡¹ßœò³µÉ¤ÿÙÄÁ88888È HäGdºhƒËF…~Yø™Ÿ!Xð9‚ˆ*ð+ˆDø­ ð„@÷ÀŸ?@¶nȸ–õóëS«ZQŸö}èÂ~Ò“x’>úïè¯}ÿJ;×ß¹è’2³nwÂ]Øé{¢ ð…S:WÛUfÈihåØÑƧñž;\´ìNûnZÆõL7a¿½ûɧ÷j²Wt_Ô&÷ø¶ù 7Î ¶îf,§›¿|Ûž ð•ª8Ái( <1ÊáóáÅëÓ©cO¥›_¼™6o-Û—#Ò®C@̈wêHN@—÷¼œò·åËØK¸(PÇ Û÷xÚ“( /fb@Åp p p p p p @ ÚÞ¢YÝÞªœýú‚…Uð—]ÀYÀÁ_w~ |áUZF1 ‹Àì.P¬8»Á©N¬Ü´’õhV‹Ø¼AsÙk$½ù‡7éÊ>WR³¼f‰§TQ%»¾JÂ1¥rwµýÓöˆ»s@Ž·C˜eؤ+ÄPÍ.¨m³¶4ጠtž'DŸÄ+æ$€¸ì·G³16!x¥Ä0†Õ¦ST§íî+â'¢PE€Qè—¶ÕÞF÷¼sóÇÐg‹>K§§’8€Ïžßý|zá´¨ÛŽÝŠúŸžÐ×Ðñ0Êyp™%ì+àJÓ÷*©Þ!ÛÀÀÀÀªÍ ¨ÚíJW8à-Ì#ØëŽ¿(ÜWð¯NueÍŒî)ãWúY| `Kæ§’(¿v>è6‚Þüý›tÑQí‚Ú‘@¢Âˆ*Œ,§R´_2ÑXa„áV E=Ò¼@OTÄ)ð£~^}ºã¤;èŠC¯ œ­|A"”j½ú§-ˆ°Žy¸©L %€¶»¸zÀþõ4\áߥ°`õxÏ@ºö¹kiÝÆp7@*öWv\»ÚÑã'?NWr5åä-J7cµÿ¥TB¡B%õ¹Ê®tÈ?p p p p Êr€S¡Ї¶jõ%Ì«C„mV‹«ËAãµ NÚâ#`hÀ £qQ¨ä_ЇÑrE¡¬üòÒ&M:)ðJU.ŸŽŽ«§‹ãúcŠî–%•kªí¨pveGd L! ¿â‰?Ál0ýB†³íG €mnn Ü÷$ÂÎay|ÃüϽÿLÇî},ýåõÿGó™Ï}™sޏ%ßÜŽOx·ÊW77—Ë4ƒŒ{Pfcà•ª¡N@\!Ò8Ü#ÈDï|ÿÓ󜄨ò Œ®¾sîߧmÓzHö¿ÂyQ—  0ðXñÛn8 ]×Ú»5Þþqð?hÿûWöÝq_zú”ghô{£é¡ÙEïž‹0‚2±\ÁV„x~P‹PICÊËñ²°0a--â ”¥(¼P7mAÇL_6]¾|P·v]Z¾Þn»v£.ú^ýêUšôå$BÖlY}&B7†-ê/|`¿¬UPH_¨ àÂST 7aq¤€Ww‰ó BÃÄEÉ Râ=+Q(´°V DË6,£ó>ŸzMëEWœxuk×MȇŸªÇ=›íIO }šîúð.º{ÆÝòÙNnFéwpEñƒ¾€>ˆ¾'MÍý@tô 5Á¸°~<èpñÀY V%ú©ÊçÃÜpiüŠë»`2`°aº7*×@åò?ä^Ý8 ³—)w‚@oâ|˜„省nUåÍðÔC?`¡Q?ö±ëtK¯[¨a†WQ?y¹ytUŸ«¨c‹ŽtÕ›WÑæ‚Í"ÀË»ýBŒ bû®#ŒHÙ¹.‚ëX —ïÝ#žÿ ÔŠlðãëøhÓ–M4}étê³{‡Bù{kçÔ¦ãÚ'¶€·`¿Xñ½¿ä}zï‡÷hÆò´q Žu‡Ðe¬´$2´!6UpXy’[8®á¤±†Ó m(N8OœH=Ë7ÉS"_µ(ûsrøu(#DPH}ÿ ü×@:±Ë‰tåIWRëf­c³ ÀÊåNøüéà?Ñ¡»J~éÏrúTamnwh›ÐÍp€µL» 8;®D¹æÔý ý#˜ÀÀÀÀÀ8PãVø*55Z’5µ~V/oñ^LÈçÅ;þð…ŒÅ‘€€ÂOà@1œÜîdº¶Ûµ|ògå˜Aû ¢vMÛÑ…/^HË7,—ÏùI?F_†PšDpŒ_ ADX O¨E ÝyéÅï¤Tlܼ‘òëä'(²É%|2°ÃNÄŽÌ Ë¢Ê!jY¦¹d¡€6Vù(ÌI¼qèÛ²/]Õõ*ÙÝ‹‹¯ ØÎ w¦'O}’Î{î<úð‡£ïÑã’<6Ñ·!Êeìêã¨2zHªìb ˆŸƒ qZØ…±cÍŒ•oÖ~C?¬ûvi¸K„ó{x§ÃiÄí#èê¡WÓ>­÷‰Á(?P³ºÍhÀžÄâu9+çд¥ÓèÍ%oÒÜ_æ²LÆZÔÙØ”§x×^æ ;§JÏtdοÀ#8úêN^Â(Y€ëؾL$`k¶®¡[§ÜJc¦Ž¡³9›FöI;5Ù ”‚©"À¸9§û9ÔiçNtѤ‹hÕ–U2¾0ÆÔÊøƒò,¼PEZ-£:rÀ>Ê©ðU‰~ª²ÄÅù07ìúÁ:7¬~ßuñü8 —S3²ipK†`*šfá«‹;q†²$ó»qŠ£®Æ©«ðàñ³$^`7Öà鎞ì¶`Ç…­|7·1kXw‘0'½Ò nO·k^8}c†{Ð?{þ³Jìüsë$˜†ù éÁ“¤¾múRÁ&où¦yXùlž9@[£± cBÇ ôzj{CØÅŸü›cË¢L€B-^HeðÎþŽþsõ14ùÃÉ©PË5¯ tiÑ….îz1={³ôÎÉïÐßúÕú(ªÇrbÂ95¡|’“Bàó-aîpO €o†wÂ+ÌC0`›Ã3úõ…{" §‚åݸú¹@9—Cë¶­£»Þ¼‹z\Õƒ.ýÏ¥4k!ßBL•â@Ï6=iÒ™“¨kó®T¸‰—Ȱø\%ú”Z>!`Çú ž;{è_è3®‹ ñ.nð'ò.ð#ð#®ø3FNU†¡ü©Ê—,¾4pàÂøù¸0A?•É ¨L«t’2¥‘Ý|ìXꂜ]Qf„|Ö´pƒ Hƒy9ytk[©nnÅÝ|ŸF±PòkçÓ}ƒï££Û B`q-Â-êµ “÷9™îì{'}<ìc×o Ýk(µÈkQÄ'Ã/Úà7|Mçæ—Ì;xÍÈX[æ›(ÌN¿}}¿ZüYøOüÍ+öõVlÍÙJã§§£o>šŽùÛ1ôÄ;OÐúéÕ×–)xÊ-µ¤'N{‚ì5 hì±ðŸ Lrû‘>«¸D2ý±ç‡Ë­äpà@à@à@à@uá@PT—– åÌ>°02‹#úå*ìcgEýXœë‚ËIŸýŠ5ЦŸ¡Ngïu6µoÒ¾ÊW¯NnºsàÔo÷~E‚ˆîF²"‰*x|رÃQ©”RqG¨…@ûÁ¤%Ð_3ìÊÍÍ¥»^¸‹N¹áZõëªrácƒ¼´dõš¶`m݆mû’Mœ:tØ®‡Ñ ß@ÓN™FOû4×á“bÇž3ÿTNB®U‰á€ n ^þI޼³9†°ëÚÈ$ÅOÖ<€I¥ÁMB¢8]š©ðRÅùú¸ a³’E'ÔÅ’†±W˜4„ü±àoÃðǘ„|bâ(p`Ǻ;Òùûž_m%À½'ßK#Ǥ·½-󔾓,.æ-"„êÆB) ƃÌsES]ToV;‹À×(Ô~Ýú+}ºüSêÞ²{„“äïÿë;Œyíš6{qùôŸ¿ü‡ºîÕ5IŠÌÁ»6Ý•šÔmB£žE­š¶¢á=‡S«Æ­Ò"ˆWößi±ÿÝý¿é›ÕßД…Sèå…/Ó«¿ö½~æÜÅ"xeÂâ×Ü×i~ðö+¡»8NNXð= rÂ.žôëág[˜Ëm³›0¾|ðìŒgéÙŸ•:³ÿ1tB÷äÔ¾ÀLÅscç’C/¡Ö[Ó¨)£h[á6{€ƒ<Ödœá^ŒÃTcý}'˜Àí˜å½N«JôS•%.·¥ »qêWÝKý¾ëÆmÇݰJT— ÁlÀâÖ<Ü]7ì¦ØçØ¿…9é•NpJä€Óo~¿çï©~íú%&©JPŒ=u,ÚæP{'€ûu»“mNÆÈ®¤ogî¸K¨„¶z@I_д£NEõë2ùéµtÕR:î¯ÇÑc¯?¦ÑYuÕmD·¹•òø¯÷M½iä#¬ùúmÂe€¥1{6Ý“.ìz!M8‰^ô*]ºÿ¥´_ãýä4@ÂÑngg×ÎG†— ù¾YþAðcaÞ= ÷`×?îµ€º|RÀœÈa¿œŒqÝò+ÿh<ñ¯3¨ýÅíé¬ÛÏ¢ÿLýð:¡ !P!Òe<ŽêÖNâè)¸8M›îØsæ¢ )|È$p p p p Jr –,Ð*¡h¼[a–¢“†"B­Ù“½ ì[¸6ÃøB.\µØž€/ÔæOœ8ñQv­Ùwß}­¿*xO\|‡FsÌ÷ÝXõ «À6S|ÃA…)'e× Ü4ñØR¿¸ˆ2—JiX]^J ›¢ª%d~@/£4KJš ¯4ý4ŽÈE«HdÁ0â± AŬéGË+ôŠHD¸é¸ ù:ðàÝÎ9`úNƒÚ èíãÞ&¸ÕÑlزF<6‚>XòAtÙ.šÃ‘s¼ÎÇÐEeATv!1å@(5so´âfÜɉs$¾S“N4aÀÅHéŽ~v4ýcü?¬àä³:›n:÷&Ê«ƒÇAöÍÔySéâG/¦5›ÖP»ÚÑðÞÃih÷¡Ô¬~³Œ3[ôë"zñ›iÒ·“hÁ¯ Šæe3[¾éÜk\s® s•ž^Â<¿*4Íëf^[… ÀS¸ñ‹é X°¶-ÚÒÁûL½Û÷–ûÚìØ&㺇„¥ãÀ‡‹>¤sŸ>—~+üÍŽ9Qø˜{ düáõ(‚Ìk"ÈAünVÚ—\XðTu˜çh©Š“FæÌTDü4~ØOëÅ£ïÅûÉ‹)ÈKÀ/F߬[èaµ@d¿Ä<‰Ã3C"8ÞД瀃#iøy`Ó{xªˆ”xUJº.òÖç ÓzáT@ªŒùòË/Ê2pàÀ3°‰íF¶›®Zœ«ƒï º\R .©7™8*ß@·AP$gx*º4ãÅNb&+„%½™¬09l3ŽÑd(8þ°ä°_®deññ’×4Äl7púÓImN¢›{Ü\­«%ÀYœEÓ—N/ºmJ(XU+‰¯€0ËÆDt± ‚) —µ¶ò]§}@øì^I—ÖõüsOZþóòHHEæu·}ºÑƒ—?H»4ߥ$Å·â;:÷þs鋟¢cüùùùtB×èÌÞgRÝ{dDSÍ_5Ÿ&3™^üîEZº~©UöZ% „:8É„8žÖì<¿.¾˜¿²ð‚€o¬½ÃAÀå%ŒÄ¦i.~Ÿ‡Û4oC·?˜ºïÝ:íÞ‰:îÞ‘êæUÝË-…ÕøgÆ’ôûñ¿§u…ëŠN{€UÂá_•V‰¤õNÖw4>¸U‘γ4íâŤI¶~³4ý4~Ø"_Œ¾ï'Çs+Áøá„H3¿»0ž‡‹CÖaµ@f¿}N˜°(%‚†¦Ìû†–M*üà ôŸÒ~(é2.–ˆjà É„x8^ÃĆ™ŠNpî$( boòC¼À5ðLXéÙè$Ê;Oñƒ»sÀéKÿ>ôßÔ{§ÞÕž¸!ÿôO§Ï––\ ¡DœˆQXá‚'vXèüç¡ÿ¤÷<1-ýçÿÐå÷_.‹wìíØdG÷çqtHÇCÒ¢SZ¤õ›ÖÓ¥_J“>›$u”“Ø ·M?q:á{ö5Á¬Z¿ŠN{-Z·(z ·Í«¢G’q"€ç&ç¬@t¿Ñ^@ø‡€É €»¤[¿5-ávþÞ—÷¦ï~ü®~íÚµ _ øãqŒ©XŠÒ0ÜùÊtˤ[h[-¾œ s0Ž^ó<ݰ~C|à`:«×YÔ¡U‡Òö°7oÛL¯/zž_ð<½µô-ÚZ¸5a¾—©üL67›¹N ºJW`OpˆÂ'\e€s@pUø÷\™[ LçY¸yµó¨íŽm©]«v´W«½¨]ËvÔªY+±;7Ý™Z4m^Ûãk _ýðÍ^2›æ,C³—ͦy+æÑþƒÐÏ=ÊWtÜÁÅ:ÁôCñ£_èšÁí#®ßË7ª$x)µ‰I“lýfiûiü°E4?Þ —w~2O')“ÍeR \ãOˆ×]¬‹U©€g³®“5 žêÇ\£xª XýŽ T}î€Æ›¾ P•1Û› f¬F«L÷ ©P˜¹ÇæÉaLV2a!.&la2ƒ™”×Ò žÀlpýʘ®ÍºÖáUjÞ 9=zÖ£tÒý'ÑÏ[~fIǰ€ÁâÖŽ˜¿FÃøŒ€|DûÎïðÈäxÅ7(qNíÜÚô?§ü]p×’Fq@{ÿ]ûĵôéÂOéöso§u³{ïò¸äØK¨s›ÎtÁ¸ h͆5Ñ¢‰;k×®¥‡ß}˜þàaêÙ®'ÙëL:±ó‰"kÓuóróè¸=Ž»jÃ*Q<óÕ3ôåj~WÑvú°ÌòÕ°ùV˜Ãí€x(*¸Œ°ðcñ(.‹8cS.—ãöÃ×dѦФ nA‘« >™E$n«Þ–Â-ôõНé럾¦)ŸM‘¹Y¦`t¶ø´ãŽv…@‹&-¨iƒ¦Ô¤Aq›6lJ;4Ü×oLõóëS½üzrÏÂèp¡`‹!Qájh~Xõ}¹øKš·xžýó–Ì£yKçÑ–Z[ŠŽú³€¯wn íÁW´™ =ô´·3xnyëôƒjÈ–PäÀÀÀÀrâ@P”cÙrä®á°+ôcñcÃXìÂ(, E¿>7.ø²Åîgwè˜-jU†NÛæmé¡Ó¢S:•6nÙÈrK!jŒà!Â'‡­PáEwŸ]à®Ú¸Šð.|‡æéíœê=ˆî˜tÍÿ~~D ù ÁöùŸ§/~ü‚ºø!Ú³åžNnÙñöíÔ—¦\1…FÜ3‚æý8/®yVªÌ‚Øôo¦ÓÇß}L×M¾ŽNë~š|J|ËÄ4¯×œÎé|ŽØ9+çÐø/ÆËåk·¬U «€É¢Q @h”fS…>A’wy°Ë,Jô3‚?O ‚g”¢T0~¡Mo”ðÇ…Qª‚‚úiÝOôÓÚŸÇ”4â§$Cbñ$ÆGP «—WðÙB( TØ©ÉNtàÞÒ°#†ÉýŠ^îšõkhÉò%ôíßÒÂe Å¿h>}±ä Z»1jC´ú­ÝÉç6¾¥ýà)ÚÍÀ4q¶=Gm2ŒŸÛ<˜ÀÀÀÀÀp \XÁý`Ðsü ˆxÐã¸þñ`60y^›E€.¬‹ç·â3ŽÅEzÃŒ‰m,(Ä(Žaˆ Û¸+ú5I\à'Ò `G/“$bÈ`á(pĉ—©`á cÒûdÃý¼â’ˆHú¸>MMÜí”Ú ¹?ÞvÐmtünÇ×HFL™;…F>9R¾Ï"Ç’qY- 0ör2žïd.ÂÜ«ÆnðyÁ˸œ.Øÿ-Ñ}eæ+tæÿáñ¼%y`þÒ9'®ÆõÓ#ï¤cþ?{ßhUqü=Î3/ŒÅ'_ñ². }Êö`ìEV/Q†Z‰ˆÂ›Ò+y\~û‘1H#c?Â(BÇs¼#Ü8ïix„4”‰¢Ü»þi—O“r*Ê;PQžD•åÃýrä ¬~mløVŽÇiš¸‹<…MÏ[VáÂò—&ȱ(/äëÄ tРƒÿ:øI ÞÖXñ ’’6m<]R!¨¶äÒn KçVúŠi÷ƒ»ÓeG £Þy€°0É'“™-¶BË"‰û…ñ*%èø­B0I2üû©‘K3Ï(’àä'Ë-ô~÷¡«’Ëaa_?VØÅ·íÏû×y4¼ÇpÑwD‰ï$¶9€­é }ˆÚ½ÖŽnt ålÏ‘ñ‚†! Ñ!;7›¦9¦=vÝq7Ù0èðAÔ¢q‹x‘… ׯUŸ´ ö›ÕßÐ3_þ‡&;Y.åC~Š0ÅFS.ãTÃMÒäA2㺒/.v$­ðszQDùr9¯äg~Q8š„£ÇÑáG€ÂV†jÔ綯ƒ¬qQ‚(Œ~$Q.ŸôâR@ä—2Ù;ñ½‰ôÖçoÑß/ü;açHi™kVÐð{¯ Wß{•Éü‚e8Ú“Âî iŸE:gå ¾ð‡ L×Pm¯ÃPðO)!Ê7cŒ€þXÊ Œ²®íÒ:ÕM×ÖTñqZ~á0® ¿Æ«›Ž'£—¶ ¬võô›Ô/ÒêC—:;2!†¦4¼¨“&Là°ÓôH¿æA> ³WÊpi% hšF&ˆ’8ñ¸?H7©hñ4)Ây4 )Ò€”']8N°_z¥¹É£ß % M|RhÞr…¬E Ê͘pã|¥KO—(Á|Õ×Å ¬šÙk&íÚ`×* n'?môiôÁOPVÝàr2]±t;’V&Ýx$sü¾¡ÌãÏÐÕÌ©I þˆÖ.ü¹ýY_Ì¢þwöOŒ:fºqÒo\Å mO /xvj¸S©<ÿ›A—h0ê†þ€&cr_Ë:ïwçÑ­gßZ¬{PU:3ïÛytÖgÑÒŸ—FIöòÊ ÞÕ¾?ð3HåWšÿ½èïG]ý]銿†5>¾€ù~§Ï\Ýt 1º!PÑ~×…f-E?†¤+$ž'Žç‹ÇÇÂyæ…±ø¤1,^6Â¥Ç# Þ¥pÃñ$MëüIã£ÒÇÅÅÙàÇz”ÁE /ÿÁþ뻃ýÓ/ŸÎ‰*Ž©n;ðzªÒ?€Šd«4Ø™j á@…C˜Ü–TXtÑç,l„edŠ/+Ç(*è‡lÕ.þgá¢*ö_le=x45­Û”r·òï–·óËrÜ(Ë/~}ùËÄ$üB q7ÝÏþiv‘Ü¥mêÚ¶«/CÊÂÛ ‚pŒXPšöÍ4êþÿºÓg‹>+R…M|ìÁÇÒë×¾Nmwç{ 0 Âä“*×^ñƒmÛ¶o£—?}™>:ºþ£+=üöôv+Ši°+à̃Τ—¼LúL Þ{÷¦Z9µ<þú „7}þ3‡ák*`:W”*ö!ü‡Ÿ—ãÕý”J‡‘ðꄘ™‹g™õ‘ýG²ÜI<ºÚéWR!8J€EëQŸö¡ ïM(r=…ɰWó½hê_¦Ò©OM^q‚¿”¡}„]FKúÉ‚ èÆ—n¤Ãn?ŒþøÜéãE|®¿¦ã®iT·QôÎàwèÊöWR‹º|Ô T(c°"£ü€ØPˆ„_(*¼ªpª«¨U W]B‡¯> ç^)£K( ðy;'ð Í ñ¡`/ÊÐEú½ŠØ˜ò@•sÍ¥n·v£9ßÌ)ÂQÖÑSFÓ[‡Ð¦­›‚?0SÜ/Q¤ *†ìJ[†Ê—`æ”ÚNé».Ÿ/'Pˆb@w€%§|ðÏ´è§ŸCÀ0 jŽ€)Ê£èdK]ð ~¸0a8ô禫,~'ÈûörØ Æ¡< œåx¿âºvˆÐïxÓ6HÛ‚öû6jYÚ—Qž>R"u"¨ŸDâ}͆‰õê×0Àôì5ºñôq:¡‰§GFÝ(dËS”ó¨¶Õë¡p“b/“åøÄÙVü4s+ ë·­¯,¬–˜Ï‘'¤}wÚ7Ïg¡Ès¿qù=0‹×/¦ï×}_d^®ê{UrFl¼@¦BS°;öݱtÚ§Ñòuü ºR0ú £ñOMðñ=“™_=N˜Ó$Ÿÿô9˜8‚»í0úë ¥¯—­QEvkeÕ¢^ûõ¢çú?G“ND}Zõ‘;TŪ6aéÊ\è²T¨…€êR¿2í„ñ$× ½"ÜÆ.½xãáPÀײƒ2$Ÿ¤½+ÿjáÚí.£*l³›S;‡®›|ó¯shå/+ÃVçëÿfÑ7ÔsdOzâ'"a}+…À/‚;c¤‚¿ðÞ˜/UFø]_JÓ4Ú6_°àråYhÝ:£ÓçåZ ;bòmE†€!`T'ªü%€p@…zž§Næ-¡Y|Û±NÜ…P:A->¿ÌE£—¹³—:‡ùµÑ‘,ÐþK^„aekÐ%¤ˆ®aD‰_<îÒÆM*Z¼Èu&âŸÑùcÎ'ô"´a¬Æ8Ãó”¥Ãºœ sëÎ4¤óêypÏ_d·týRzâ³'è?üuÛÖEï‚àý!ÏL1»éI?†#ž¡b ža™†4­›´¦-:ÐM¤=šìA{4Þƒš7hN j7 †u0·m¤ [6ÐÚÍkiÅú´pÍBúqÍ´puä~»òÛbíˆð|*؉áv¢@A^n:õ&9º‘®­ØñÀ Ð]î¢-[·¿þý©Ï.ú›î’€w)°›GhG×|Ðr8›ÐtžàúpRÿA™ åøòŸ­ïó·BS¯¹†@¥@ãHQMŠ<2äWN§s ŸÞÅ#<í²iRTEùóÍ7ß$±Ò¯_¿³™€A~3Û­ÎW-ïm¿ÛÛ¨{EŽeŽ`©CáVâ¬pÊR6¦(e€ãÅW[º}h8œg Áˆ€ÁF~&‘‹TÑx—ÿmå€Sä‹çá$ÞÄó§KOç 0OõCÀuK}ù½ØýE:h§ƒª#'Œ¤'>x"YàVj±-Ü æ*ü@Xnnòpü®ÇÓ£Ý-2foù6õ¿›¿ Š·R*~ PLP^ݵøßM}o¢óŽ9O¢3ýgć?5œ^˜÷BB ¬ †Æ žŠÓü˜~aaØmÞ¨9uøYò9Á½šîÑ‹ùB÷¤¯'Ñ£Ÿ>Jßÿò}¤˜ðò‡0„Q5×óÅqÂ/óW“ÿuÝ­+õÞ§7³Û1„£™09ü]ÁVÿ@Ÿ.ý”æ.ž+öËþmÃx y̓¡ëgÚßäh On¡ jÛ¢-]Ðå:®íq´GÓ=è×M¿Ò‹¾ ×æ¾FOO{šV®YéÛèl4 ÏÂ;úp „~/ø#..´»øÑ”å„©G+ ;¿¸ùä[’5FJ2רÐè¸W&Säñã@ºrâyâáx¾x|,œg^‹ÇÍxÑ.(}<ž3ɼ™]œŽÇRþ`žÍqÂÒÖ§ cdp­ä1€ ÿpMÀ ÙðK ¯ µîµ)¯O~•A—-Ë¡­ÃáÚl᪭ëüõØ­;yòä'ÙõÆv/‡6O?ȃ£nÊN•FÓæçê £i†fFx0 Á€æ¬89ìý’(ñ'=>À§L#•å䣋痯¥ÄÓ)ÝÜjˆú0U<Öõ1„"jõø»vÃZ:úö£iõÖÕ‘Û›±JÝæÍÂFzYÁÔ1È fõ¨}rÎ'T§&†ú¢™Þwô¦÷¿?¡ˆ+P—Ö‡ñcV‚!òJðÀéŽwPÝÚx½dÖ`ü¸ïûèŽWîHìso@y-†¼iÕ®?aØJš!žiYüÁøãÛ/»Nhsá« Å5Ǧý0F<šÞ_Ɔ‚&x¯ì¦å•£kæÖ¤3ö?ƒ.?ärÚµaÙ|þ_N˜õý,š¶`Mÿn:­Ülçžµà<¥[±Jzþ˜à²2ȹ‚ûƒ„9-h~ò{g$ႾöoçÏC¶èÿ…Áe¦RàY¸ü^a€öâ9±ñÏ) Ff~C "#À?½"›yÒÍß|Ùñ<ñ°Oè<ñøX8ϼ0q(_/(Ì…Éx†B]ZÿÎЊL H$¹Õm€{E$a`C ä`à *öËä.Ðu²í&`2©r›e0XÉ ‰t°f ÊŒ÷á~ý¡2· X¼ïØpGúËÉI|0ŸÏÊï<ö[ßœ½™>XöA±êþsß?Gc‡Ž!±²EPr«°"”©B¹ã?OýèG?­ù©Xõç— ÙÝ® Ç/|œ×muš‚™Z|ÁJ±tNYâéxƒ³Íáo~õ&ûø¹täGÒ¨·FÑŠ_Wh©Er¡ >¡Õ 4áÔ 4¥ÿêÙª'eegyX77Ê$¸ºÉ¤VrÜîÇÑûý—né|K™ ÿ¨{Çú;RŸ¶}èžÞ÷ÐÜásé• ^¡?ýÚ»éÞ"CHVÜDá,c‚¹ß-‚~àU¡Ò*ôû´\FÒ¹|äÃÿø9\Dèèr®Ê0Uй´zÎ_ëÎã‚/ðÌn¸»@ú3ÚEú›Ù™ð¯½Ò\CÀ0 ÷šIæ/U i8)U:*W¿Æ‡át´0M¼Œ0®0ùã鋯dP'„ìêŠ\?qäUFZþ-‚?VUÂ2ŠR·¥Mî;†G…Áã»ußáWYíÌYGEmš·Iþ*€û2€|&+îÎÊïÞ22Z3Î(fǶ=–:¶ê˜<Îè¸Ä%zÁo@ª`¥·ÖÏ[:NúÇI4{þìbñPP¦“>‰^¾âej½Sëʉ߬3Â#üéTxU!|³:„>„Ù]¼f1Ýñêtøm‡Ó¥O^J³¿›íà袚v-ÚÑÝ ·Îz‹·LõrëEŠ]‡RÇ=¿š95éºÃ®£GŽ„Z5nUÔª2šžEaúM‹ßЈ®#hÖÐY4éìIt^ûó¨YƒfQ=À”1‚±Ã1© /„Ö)†üΣŸ@ð÷Â? þêzŠ‹ %ÒÃ2¹.éwJÓpÈ”Aà ûÚ‚>Àÿåwã\NµÕÞæ=4·³çbÏ¥,ûFƒ¢Ö§yÔEþÐ_Üò4Ÿ+ΜòAÀî(cÜûMêMÖ0éà¹LÜàw[ûäEî&sâçÉ©¼ÇCÞël5ħ ƒŽÉŒ¦qAͧqâêM£a¸©h¯Âì·Y‰°²®þkZçÊj?òa‚žÆø4±øTô°n$O™FFÂDañ<‰˜¼ùÓ¥MUOXŽù«Ú·ÑçY¨m·S;šØcb5 ÑÔ×?{Îsv$éê¨ KCèaÁÆo…æ¬2VðxÐfÇ6ôêi¯& +‚ï•_¡!Iú àÂút\Ã3c+-””NÈ­™]“þÚó¯4ô¸¡E¨½ðI×m\G—>u©l[×1?é=€wC`üø~RChªà@ HE<,›ýwÞŸ†9„Î8ì jR¿ID,ÆßÕ›VÓ¸ÏÆÑãŸ=Nk¶­‰Þ)ü~©]«¶|^°ûÞÝ‹QjÙeÉÎͦ7¾}ƒÆ}2Žfý0‹rr´/¡¬V—»ªàÀïXû¥ÄKFæÛxGã]®»6pþ_x¼ë5Æãݬùô=0ÿÞFÀÑà•:¢JQqdàª^ô™ ìR%Ò&,`TÜXV$NSäñãgº‚âyâáx¾x|,œg^‹×1:^¬”>Œx°Ñ¶ªëëB<çÞ?f“Þ ‘À呱Oß/ZŽ›Û':ßG~õ£(ù]¾i—Oã@Å1v â< ã¤2  xe?~è~°ÁÜýøuR4Td` ˨ m6 ""ðåš/i{.Š­~¦Û!ݨÃüÊ1Vþý…kn7Ž~¢˜X€ùzõ×´lòbvò¡'S›–¼ûc’³~üAñNH‚ %B”Ò Ùµ²é†—o ËÇ]N¸Ä/Óf‡;Г>ICaƒŽ…pÙ("B¬ÛÖ)ŠðŒ°6U‘*毜O×½pzó¡ô§gÿDóÏ“ò‹ú§iý¦4¼Ópš}îlºñ¨i×ú»Ês½ó˜;©¢ ÿhkÍ5©ûþÝéÉÓŸ¤Í ó;_¾>àq†Ü aÝí ñB»®Ì»¾¡ý#ÜÊ/ÛùÃmþzß…SzùݺÝÏË)¿ôÙ….xðõ}Ô?W§8¾¾¹?K_†"ÿ§4éè)Ñ0 C ª"ê•«j­]¥€NTQ6ûóþnµD'ö:±…r@ÿ)­4س2 Š„À–ì-ôÉÊO*KeÊˈ^#w¸Õu½dMWDø‡Â« ™±hF*¼ÑåÝ/V°ê c’[z © ¥+´*˜©Ð縉ŸO¤>÷õ¡…?/,<…L‰Kûnè}:}ÕͪëWð=à“­ x*ð{Ñ ’>¬Ê ]mvmÜ”½‰žþài:yÔÉÔcTúÏÿ¡MÛŠ®Ô¨_«>ûÛsiÖÙ³è¹~ÏÑ©ûŸZÈ–Vœd­vjE7x½ÙûtU—«h§ú;E‚3p†rÈ)¼P®ý.úDhq–ß ÿêêù~9¦ ûüÎJ}ð«2.„y§Wû*»¾/@9PÐÏŤU TœGbœ†€!`”x˜1 @aL²ÝQ8Á_* Ë(|Í–Ò¨œ`òÍæÝeïFžjø÷øƒ§ßìú¿­^„·ÅÞ+‚ñÂCÄØÍ\4Ó‹ê9­óiÔ¢I QPÊxä¶в!Ð3xaJ…¯TB qÿ[ù?ê~owšþÕô¢²R¨ô:  ‰O¤–Zúm’šQ„R!B@ ȤÕd§HŠWAe0®Ÿ,þ„þïÙÿ£Co9”®ázúvÅ·ZU¡ÝZYµ¨ã® ¾"&lR¯ ?z8½{Ù»tÍñ×ÐNõœ"Ìâ·Ëxy¡\•¡@¯ù´$¡+þÚŸÂçÅ~î¥|î{¢ŒÂ³Õ猺ñÜ‚Õ}í«izðZš1 CÀ0Bðš1cŒ@øûªÂ@IDAT(´³?íŠ(ø»Õ<ÙæÂ2 ®ÑRU ·½U¥ÚSÔÆ\ÑýФcr  îÐËÝ꼞„ óÎ’w¢ï»µBN_§VºôÄK£Õÿð²A(âã„&¼!XC{º}îºmëèìÇΖOùùzΖ)Ó~Ïö4uØTê°{„JxÕ ˜O/‚O§´ð«ÿÊ·s=§Pa“ÛûËæ_hÌÛc¨ëÝ]iÀCèÅO_¤mÙø¼qõ2 ë4¤Ë޼Œfÿ~6]qôT¯V½HFŸpV±öŠÅÚ ÿ²ú¯~wË¿¤E:Å_Uà`õ>úý³U… ú%l*£q¡›*Ñ CÀ0 ¼ÖÌ”%ry†›yª_‚üǻ΂¤a%®óø¼š&…ëó§ˆ+L~¤Þåg._š+t\–$gx™–Í4„a%§õù™ïpÂÍIí ýQX¾,aUÉúÀ§«æÑÏ›~æ_=M¯½h÷Æ»±€Ç Yýç1Býr/@4~ȱ¡àٮݲ†æ-/Þ™u =äØ!Ô¤n“¨NQ`¼Šê’qLëâA ;¿ÅªÀÇs l5 8×f['²9|/Àm¯ÝJ?~mز!ã´e“–ôü…ÏÓíÎðãjtD‘@k8 áÂ$¬cˆ»Žþ]:IËtn'Ú 777‡ÞùîmºäÉ‹©ãm‡Ñ¯ÝAKÖ.ÉxÛ*zø4ãˆãGÐÌËgRÏ6=¢w˜v8+ÁMñÔþ¡Ø‹°Ïé5^ŸsåY)îîŠüîúž¼µOÂMý²Œèa:óÛ;Ñú@ìñŸ°ÃËòY1 ÉÈòºúósƒt((m—N* óÀ¯Öå×4L6S>ðkÈLY"à\©úQ?ü0qšÒ£ØD¼¦+5— –߸ã)‡°×W3÷XåwB¾ÇRÃΕÈ'[MÂÂØÏt±1² CÀ0 L"€éB•6*V·Â‚ɯN€Ù¼xb¬B¿Lʱ}6¤iMo‚…}¼ÆXù 4ÉçÉýG+>¢ë”3 ÖÝšîFÇ´9ÆmÁçqFqìíùnŒÁؘOW~Jk7¯ (E󶨱õ?¼Tê„"SŽp9P4Ê)Y…iÃi„ÿðø_r~¡³ÿ}6=ðæEc¬©»îו¦^<•hz@Ä·ãÙÇ®¯¸`aS…zðÝNU\„¼{šÛàóÉn?Êb»hí"ºõ•[©ÃmhØÓÃhÃÖÌ}($ež —^vôeôÊ%¯ÐÁ-N]?ú xôûÊ ¿ G¤(DJ’ÄOPÌg†@•E ¢ÈeÊG•:MÃðÊ2SP!@ÇjX(仉²ÐV'Ê._uýáTç.cm/ád~gsùÌïÓ_>]ˆªn’þúG«ï*ô;Wv„»09“›]¢¯ ˜Kº]âwxÅ”N!4¶!ÞŽj±²*pÑ›ªU˜Î©•C7¿v3 7Œ6oÛŒ2jZ5mE/^ø"uÛ·[´ƒÂ)0dlŽ×ç[W÷uµ¼‡VÛæ\¿+@ÃZ÷ãm9Ûhò¼É´eÛ–x­U>|à.Ò˾LWu/ös§pïLix¢»F8èï^Q ¢Pº¹†€!`†@#€×º™ò@@' pÕ>°úS¹Êsæé©ünIêS!_WÄ0 Ç6S˜#m01ÇDÙ+ R•m´Äs4,ª7ú›T—ûÃs_=G¶UŸÕS4=4½ëEµø`´Þî>r®ìÆY¥w¿¡™ g†ÅÙÈÞ‡ÐQû•To’"@•ŸÁo‚šX¬èòÛÒßïjþUf¥@Ví,šôÙ$ê3ª-Y“ù ôÕmD |Œ.?ârÊÝê”n¬–1c¸ãßóŽ6€_µ1a_ªÐpmA;Ââw¨2«q½ÆE~U!Cíšµiä #éùsž§õ[DJq}?Â…Å3ß±©Âî9éó2×áf¸øß°õ ë•¢ðcÊÃ'hqƒß¶šÐ¯4sËS”)ÜZ™öüÐ…_-Ò¥òkú°MWHWκº´ì—[ýq¹“¬ú3“`¾Ñ_núGZÐ5ÒsZØ®,ϯ… ë©ú€ÜÎ#îÚmkèÙ/'è¸Ú¹M4¡#öëÄ‚R4Ö¨mÉç¾£cÆW°ËîÌE3*^羯Wë‹ÁÄ×/uq}¸©=‹¿ ®¾&û±’ޝ°Í‚àï,®€ÿóŸQ÷œDï~÷n‰øM•9‹¹¦Û5t_¿û¨NnmÊÝÆã±Wš0¯1ÜÀ»Zá[v30ï²ÀµÃ·;mó~M G ÂÕÙtܳ#ý÷¢ÿÒQ{°R ïL| ïO|)'ð+MŸ \y‡ºçäÇŠxXûŸ¹Ü͸›5 ¬”Bà"Å„¿±T´x|ýš7îjÐC<…Ë S”ÒA=èú0¡«?‡8MÓi¼dt”V(—a~!iùOžü1wá ¹ÜÂt–ôð#=ÿ‘¯8¾™äÂæ7,¬­ŒùìÚžƒ›ïª§éÖî$’3¶w"¿»¥cÆ#Sܱä˜ôlãrúúç¯KXi÷÷H®OypõÊØÇµHÝpyñ_ú7¿-s!üòJºÜìÎ+éþ}^9%`ÕÖŸiÀÃhìÛcKÄsºÌýÛŸž=ç9j^og÷E…?ÁSÆoÆü«ÿ°,ÄK;À?ø,Žø0+2ä+¼ÀÓ/í&úeó/éX«6ôf ›ÑÓƒž¦³Û#Ï@°çŸµ—¢o‰R áF}šÃìñ}LŸú»úÍ5,¬X(å>ÀÅ‹ ÇT´x|ýš7îjÐC<…Ë~³›©Ò„¿4öû­ûGïO~ø$öài´òו%â=Uæ]›ìJSΟB'ïw²Ü  B¨¢*t†ïôAXôC¶þ^æß1 .ð§ûó·©Ø©¶´¡‡Ò¨Þ£¨f6æ’•1ÞB!€¾WʸgbJ€jÛe¬á†€!`”¦(7èK©âp¢Ç~¿š…ɬ³&ø—öV¬!"!+fd7h·dÃzô“Gc)ªG°fVMjߺ}´" R¨pÂw\8úpé‡%¾@±YãftzçÓ£útÅ\ëvÈØ©{´õ±„‚³^ ¨‚3*(Cð‡_w°ûÁ’è$¾à“…ŸhisÔi@œñý¾óï“O:[(°¥ï§ð.î¢À¤¯h›àmœ·|^TŽýõô?¤?>et¤p—4ÊN(°#@•ªŒÇ³Às‰÷3”¨ÏÉ—nCÀ0 C 3˜ 38¾¼ÔãVsÇéaiÂpèGœî% üÁ¤ÏÇa¢‰ò"MP†ìÐIH@Ó˜?3ÃÃð(R`¸$= ‘zCûýsï§UW!¦Ú™¶{´„Ÿp@(ˆÃ¯ãš¯¶fo¥÷–¼Wb¬.îv±#E(Ó-ÛÐØ/6¬;6^†ÏQVÑõ¦}ÈáÑ€PxfÿÒK©ïý}鹞+qâ O]}âÕ4ªÏ(ªÍ—B…Õ£®myÞ\(¦ Üp Ý倶äÙáàÚ8gñœ8 fzÔƒìû emÍ¢Ü-yŸô7=*åÞ·x_‡J}§êwgnÒ¦Hc±agØYHôŒÜéðÐ8u‘.?]Jói9Qiö·0@™ƒ®½>tã~„ãVUº ‡Aœ×ÇdZ„|Ž ‡ó½ÕŸã!ø›1 RC• WÞåÑwýöõtˬ[J­ÞŠ\ð»˜ðURÅ¥ F)†¦’ÞLÚîÙ–ŽØ÷ˆ¤]ÂTó `yVg¬ÏQ„eŠeÕÂl¥<¾`[Ímôûñ¿§¿Mþeç ÒÌšÓÚFΞ@Íj7ó ]}NÚe¡Ø:W”RÜOUø‡àïÛ¤íã¶é1y«æU[åUAO¬×Á½è®ÞwEwŠ9€¢K”\(0U_]Ÿüf CÀ0 ` € €X”"ô]ºq?Âq«u(=iRàˆþë|˜H„–ã% 7fµ\s C lð«­<úBØšøõDš½pvÙT^jÙk—½ K¯TøA(X MRP²ü9cጌ´âÜãÎõuŠ€ŒíÿN0^NÇ8`^üöy÷,eµ«æî~€PøÏªÃ÷ðÝz,à¡w¢A¢µ×f¤=a!öîD/]ø°ÓÑ‘BýÅtñmèœÑc´IP@øGû Ü€å0lvV6½2ÿ•°ZóœÙáLÑuDB ƒXù×ã©”ò~ÆŸ  ó†€!`FÀ´LŠÓÉA8Y VW0¡V«q¡[&ŒZ%†@5G•3"øcÄ­óJëˆ7GÐÆm5iµpwo¶»£ €Š°²ƒ‰]¥é¸åPùá—èÇu?–£¾úR“zM¢íþ¨WcU8¥„Ž«InX»{ž"$c§‡–½3v÷¨Æ‚ÔóŸ=é»ß…%fÄ¿×N{Ñ” ¦P×=»&îPáS@E;1Œºð£]诮=þ8î¾€ñ_GJ3i¸â¸+¨ç=E ³5'!ücl\ àúº(dÂgúÓÔedCÀ0 C °àõn¦2 à&Â*ûýä'ècâì'á„Aó†´ÊÐfãѨJ@ ‚a««¡€õã/?Ò­3nâ«ÉßæMšû±KÇ0/d§R^*. ]&vÔ«SN?’/ĸ©‚˜S€Ð$NÇUð3²mžÏÞ‡ÏRž-d¬ž+æ^ S,X·€zÞÛ“¦5=VzɃPpŒ;{×þ<ÔÝ  «ÐºÓAÚ Å Løžà¦åi[ àøtõ§4wé\Éfò"€þqï€{iŸöá?gw"wþ?å± ô1} ñ£yásÉ[•Q CÀ0 B#` €BC•¡„x‰‡ņa}É+M'.¬“R?ao±FZ)…·Zž¹yñ6L “²ìüó¹—ÇÁ²°8îÓqôú·¯kl•wëשŸPdºñJqö«ëÇ1<¤aÿô…ÓÅ[Ò?CŽ™Ø(t7€Œ§Sݸ*i¾âÀ3”qÜ ÌòLƒ•òpõ<¼I_”¬X—½Ž=2ˆÆÌSÒ&åÉïÔßÚëVº¥Û-”µ/¦S%@x6=¾#Xk;µÄ m¢Är}÷ÞîÕæ¦@ a݆ôÀ™P­ìZr) 1´•áÅn Ý‘¾çÞå¾Ï1)OÓgbn¢†Euêñ1¦¤mGyZFèWZaÝt|¥*Siñ<.SLP¦p¡2ýÑiëÖX™cŠ•)¬Ú m8a‹çÕ2Ì5 ²G‚“3"(ª å¶‹Ë6k^1ÎÍÊ¥?½ú'ZúËRM^¥ÝºuêFcWllÓ1M]ßB$?Ü@¿-›—RKhÞë`êкC4–º-Ù^€Îb|•ÝU¨c-lÌÈŠ?x«:ëw¸sóI»Xð—{êFwäÖÎ¥ë^¼ŽþôÌŸhëv–3l.è|8–g5N(Tðwm‡ð)mÖ÷Jü]¶ ~î·3–̰]<«v{´£+½2øYñ’v'ú°ûžšÐ¯4s CÀ0 ""€W¸™Š†@ì%ï'd:)À$Û5¬é᪭hm2~ C ÚN T)À®Žn»øš­kèÒ)—fD¸­èpoÞº9i¼ò¶ŽaêrC|œ@Wƒ6lß@,ý #Mô»0®ê.€@ðÇ8 e!/©”¡’GÎÏ;E\¦§—ê½8;ðÔܧèŒA«×¯ÎHûÂBN8àš|þdÚ­þn‰èp% ÷^ñmÆsˆô_×wÑÆ›ß¹™¡H•0ž±ú†ÿpÂhßöÎþ3æ¢ÐONªâýOûàd›ÔߟÁ\};‘µÜ0 !` € YØb0IJù^¹7»øÜX99|qüÎæðuþ˜˜‰uy4NÜÔ¥Õ0Êò« 8å"Ì+þžàŠ­Éa^QýpÙ‡tík×vH©´éÖoZ=7Öq 1®…ãûa€ ¸ÀŽm&î@y§v>•ÖnèWûsðÙT§ðþpÌu¼a¼•ñ8jEâ/ó&ÏÕ=ãð9ãùæâ9³"€j¶û;gÑ:éŸ'ÑW?}Å™5¶8^ºø%:¸ÙÁr/QlE‡›³ÝYùt,Óðþ ÛŽV:ü}9Õ/®NÀ4Ë›4)ÓÀtœfaÃÄú@¹õñ«ã·Œ«èŽÜ>ývšúåTMVåÜ—ÿ˜Œ?m"lÆú¥ÐÐúÎÁ/W}IË7°!fp×Áþ6|ÃËU±M›ÇâÐ&ñŽÉ!ìdz•gíªì…@L —ÆŽlÈÙ@çüûzhúCher ë4¤±ƒÇÒ9íÎ4g ¯öªB@ÞCîh„¼ƒÂ6¢H„٬ݼ–F¼>" Øß´üßIÿ—÷ø…^Ì%@ ~†þ•æ·‘ô›Ÿ‹ù“Ç ÃÃð¨¨} >R”ŸZ/êƒ)j½Q®ôùò+Sóš[®˜ <à×êvþðE/M¦ËŠX|rä)Ö­NCÀ(& ™Ÿ%CW† †Nø—ÕbÞ&Ž­âÙ5³iØäaôö‚·‹YaÅÎöÅ_AŌݙ g¯ŒX®ûu v= ò!léºÀÍA JZ'”ùp¬¼¤ óé•<à]Ÿ5?cÿu½ @Ý:¬6p6§V]ÿÒõôç ¦ìh"2gjfÕ¤;O¹“®=žœ@éDcÂhÒ{JÙÐçÁízã‡7hìÇc5ÆÜ×ö8: ù %c,ï|(še“ÇÚͤ(øÕ„~¥™k†€!`~e›)Sô¥Í.^ðq!_hÐ `ž¤-S­2CÀ(uB¡Pü uUعÛkl§óÆŸGïýð^©óSÖÌùbNÞ*uÌË)MTØtîŒE3R¥,m`—ј¬«ÝþÕïV`C¡LÆîT5)aÓüóÆ[Ï_ €€WýÕM:^Èþ'>x‚Î}fâ¨DX~ ý—w½œF÷MurëD‚©Sè.€$‚£tR­k¯öágÜHŸ-û¬„UÝìÀiБƒ¢•~(Xp £S´x7ìwº+søÍ†€!`%DÀ%°ÈÙõ%Ž÷x`ýÄRW–âÛ{?Žˆ… ʇ„%5êW0ø,`xN|Sî&üô`z÷ûw5g¥wñ€w>§ÐíLøLŒÛ¬Å³ä">O+猣Ϡ¬.´€²úŒÝ~×­ÏWéNu/€?à>˜t/vŠ€Y?̢׿x]K̨Û÷¾4þœñ´c­«Ó,œÒ6~UA@uBªWN+Ì…Wnp·æn¥‹&_D?oü9£üU¥ÂúÖ7Úq|±ó"P¾ºó÷þ`N`íª ÖCÀ0 2EÀe 7¿Çeû(^ê ›Ë·þF/x÷–‡‚jþýÛ_"¢8Osi}8]šTéV-âKËhÙ Û^‘ù4Þ}¶òcQCG`ÜË_¨!Gد·Åóñs6Ò §Î¢×¿*á/ìýeáýƒÿÒ¦-›òV%B3ž+ŒºÎ8Á ‚4üDk¶¬¦y+æ!A‰Í®Mw¥®wVýÝø,ŠY|1^纛ñ1^Gc6ÓeŒæ8Y™¿Ž¦ã*øU¿sý3ÇW 8Ï[Ÿ¹øåSL“ ÙuG²ØÍbeÀKŸ¿Tⶦ+àˆVGÐK½D{7Ú‹…Rn§ZQð{ŠW¦\m»¸h›ûªÚ·„/0¼øù‹ªÅç,Óa™}f{PÛ–mYø‡b…q—1„+_¡`ŒÃ9ýGñNêk±¾ïkfL #à ©„¿Ìòèaýð—&ZW~u¤âAiš_]”-Wia8??ÒÇËÒ2Ì-+túYVõY=²­”ßí˜Pâ.š~†ÅÑAÃïBß÷âGØÙ¤0Ð âR¦áx¤ñéàM“GÓeÚMU_JZ‚Õ¼,¤à9eÅLV˜Ér­¬Ôý­Zãû rÐw?^JåϬ1Av°#4,nÊÙLçÿç|zæÃg˜P¹Í£SKÛ W0ê†~¥¡ÿ!ÊÔ=(» ôçˆ@Æ<°›¡«´2Fã6‡eg^ ”阧os¹`7¤Gw@0óxÞˆÃ3‡Ï›Ÿ}®(˜èv`üÄîôï§K}œ²TÌ>Í÷¡—.y™ÚïÒr¶pû±:-G¸½²RÍ®(˜o÷þÒ¶!´öÝ%ïÑ•/\Yª¼– eTè‘ûõ3ÝaÁØú~\]ŸóXc¾ óésQX±7—ñP\Ì5,Òôÿ²M_â>„10´±z’#K·ÏêP–§MÊŸc4•‡×Mói: # ›$?ÂB \!€h¦¼0@Y#Në^äúÃ)k6¬>CÀ(GX@ò†ý²Å£1üî(€¿ q1à•“¯¤›§Þœ±­ïž2òÌûvMûhš´UaÅ.ÚÏ‚p*ºgé+N;cñ URO¯Ž½¨~Íú2>ûsï"äò 1–Ã~ÜÖñ\Ýüß¡A˜­ž×£þ>÷ÜãGVn^IŸ/ý<,)ãþf ›ÑóüáÃ²æ¼Øõ}e,Íþ|¶´QE¼œà+íÅêH ñ€FñqqÙ,-ÍZ4+ŠËÀßS;Ÿê…}ÄD@ÓÕ¸-òʬ¶#ä•Û,   þ ëN¹€Sñ1€i?L s‹ù×mÌŒ"D Ïâý7ô¼né~ eegEŠ€Ø.€ Í'|CYƒö°"ãŸïü“îzë.m¢=wÞ3ÚM‚¿ßQE÷-¯xR~Ê&Ó0 CÀ("x=›)K ½7c†…Aö‡B  ȺÀ¯C d!ö§ ?Ñ)ÿ:…î˜zG…¿píóŸËê¸Å~´S­ ÿÚvà#iÂcаsñ3ÍÌXêÖ¾íPo‡h;¶®ÎBÃhÃ@vÀ¯´ÂŽïŽ÷$¦!ì‡ „¡ÀNvåsN 0wÙ\úeË/IÙ‘wÞÂy´`ù‚$z&u!=rú#T¿F}wcÁ«Õºj-x íaûÿÂ;ó÷Ì»é–×nÉ;U¢ŒFõyAß÷#·ÓDOès8báúš( `ÃèW ¬†€!`åƒO'Ì”%þ€VŠ÷¸ZL ÕøÐÓx¸ái"gCF6Î z~ÆçÉ/Q1ã [v~ét•-ÎBª<ñ´)Óxp\‰Šãéó„Ý$¬0¼ÄÓXØȃ@Ð÷ägЉ?n¶¹¸]~¥oC @ØÙí|[Ø=oÝCS?›JwŸ~7¾ÏáY±Ì÷?}O§ÿõtÚ´•oþ‡`¨[ùÙ¶zŸÃˆšú &ëØ&®ÃGã¦/šž±×­]—pÀÓï<-®àî¶hC “÷¶«ÂBøÆóÀ½îùÔý8Œç“ÿ°Ë Ø ] #ãò]æ:~{Îvš½p6¼?WL—6]è”»N¡«û^MG¶92ˆ)¹÷ä¶'ÓÄ&éœ'Ï¡•[VR~°¬þ˜OQ` *æQÇMyFx®ÌûýoßO¿nú•në{ÕÌBcª¯©]«v¤P6*ø»¾”Ã_ÀŽ íW¡@úúÒÂ-l?ã¤f J‹@šq2ßö¤ÊÐtŒJ*#ˆz<œ”˜E¥ÏÃC,¾Èå‡ü¹²üûCË]ö ! e€®ïÄ¥ »´ñxÉ/GŠAAQyˆ6S~àÕc¦ Àûº4-š’ªü‚š˜*ÑRci¸.í\XRy<*g1Eä_øe…¦ýOú e›ÔÇf²YÃÀú€õL÷ŒË™.3^ê0S~ð+ÙLY"àÞã^–é0Ú’ªÌ‚Ú˜*ÑRci¸.ïüfL*SÞ”¼² :FiŠÃOÃåbï+ðY8oY S+—žþðiêtc'ºóÅ;i통ýôK5þéן¦nìF?ýü·«bA+ÁÂ;ø‡šs…æÒa—€³À@pà)‰àÄQŠ,¸³à;}átΘsì!ÇR> g±±õŸ³è“w¡ŸiÌŒÄ!ž«?hðÅ¢=az„åíÌíEÛ9,}ÀcÈ÷,œÆÄ¼¦g»ž´ßîûÑE]D£^•7A ){7Ý›^¸äEúm‹v”ÃʧùSvò¹:à 6Z×’6i[ôy³ûÊׯPÿ‡ûÓªõ«JÈMå;fýš¨ÿ0H¾áÈ wªD?B˜ãaåŸóK4³†õë™ïYK×Ê;zW ÎeŠQ5šb­0 C Š ­ßRÍ#µl7—•r^ v‚²\‡ûp1``7æn¤»^»‹Ú_Ûžn~þfúi5 àehü´€þm ]z×¥´aËúýyvêÕ)˜1Q pe¥›Ž7” £íX& Ã…U㙼 N­:Ôó°žÑlh±ºí¶j'‘À&3%NAÍ›Àëié–ô7L¸Fü{eç0ã4øLàÄ &Òq­Ž‹îÀíõÎʶu`¡mgöåù<{î»°s—̥Óÿ–ü/ƒœUž¢¯Xìgز]˜)nÀÎ…¥¯E€¦•§™Æ©!`†@DÓ 3†€!`å@\D£´sÓ* TAà”Yuxs<+Ö笧{ß¼—Ú_ÝžÎà|zõãWKõ²À¯~M—ßs9uº¤M}oªüUpWv/p“œ ºrÑ!èPÈê¿k¿bÀAÁ"ÀE•s–ΡÍÛ3·­¼ï}y%–%1bŸÙ•Ká4ÚüyIŽöÂ/üE1úÌÃ<œÑhCØa3ý‡éaJïïuh/Ù€¾3æ14äî!´i ß¿AÓ°nC7d øÍù:ñ.€\÷…[¨ÏN©#Ïœûêâõ‹©ç=iÂ2ÈYå(jî7s…Qí7êJ?ƒÀCÆ™ß0 CÀ("x›)cð¢Ç¤U^ø\7.Ò—?&zyè˜øñË?Ì#óAä‹Ï4]Zi’›CHùñtH¤• ¦Tã2I™ù“‡Ç4Åæ—N1‰gM•'NK•7ž&„'—'Ÿœ9¦âéâ¼ZØ()~‚zÙ áÅ€R&~ËlUP”¾¨4k²kdÓ Ÿ¾@S>šBÍ4£n¿é&ß»ïÒ¶ íÔh§B±•.ÑÂå iꜩôìôg郯?ˆ’¡n¬ÞÃ…ð¡Õ­^‡JñªÍÖ ‡Ò¶ØÊ?Ú#c#A³‰iˆßš³•f/žM'´:AÒ”ôÏñ¿=žÕmDë³×'.dcá_.hÛÎ P°<«"BÚ¬í`ᢚ° ?‡µèÅz8pq‡‹ó”ŒÏ÷ýþ¤ßÓðdž ŸS?šJ}nìCÏüåjÞ¤yžôÅ%Ô®Y›î;ý>jÞ°9ýkοD©ƒñVž0ÐÞÿRã%Ø¡}l7mÛD—?s¹|Îòæ~7.a¬æý¯Þ°’>‚ç …ÿüTùÄa]Ź:`em4¤ïüvâ& ¥œ³ññ¬ŽÇÇÃñLñøx8–>Ï|µ€ô)qÑ<Ε2CZ R½ñ|+ ž0¬óaGØÅûzAŠÑUæˆ5ß‚eˆ€)Êl«Ê0 …%$æ°¿x«BxR¤ü¥ Åú2A9¾]yœ…@¶zójzæ½gè™wž‘u›–m¨ý>íéÀݤ6»·¡Ý›íN»ì¸ Õ¯SŸ7h,õá²-Û¶Ðâ•‹iɪ%4ñ|š÷Ý<úhþG€7ŠÙxa8¨BŸ¬ìó ¿¬ô뎸ºê¯»b;¼ ‰²#@’•ÀŒ-îÈ”‚艿=‘&Ï f,ìãÖ{Y¡…páíe¯qØ)€öb²<¦Ï M\–7Ãp* ¾·ì=ÙõP¯V½(.ø{fç3éöÉ·Ó²UËøþˆ\úpÁ‡tÒµ'ѳ×+ßgˆ)•CÀ0 І@$/%¸‚¡tŒÜlE@†`íõ¬Î…P­®¬!d×uÖ]˜U7º# ¼80î!]WçUH‡Ï~Ù®õ±³Râ\¼¤¯ùરïxðá M(ø«ðï \—‚?‘¯ ƒÆöÛµßÒ¢_¹%wN<ôDê¸oÇÄÙ¬ú³`/³áR@þMÂÞØBÈ͈AÛԨߵØä÷õƒ!]†P£úω…ïUVQï{Óë¿®¥fÌ=­ýi4îìqT¿F}€(›‰>Ó°ßj_Ùœ»™®ž|5õ¿¯?-ú9sÏ2cÌ@Aãþ;.QŠ>Ó%ÑÇCšù CÀ0 !` € Y”bô}ïæp’µ Œ&_<™Îxô Z¾i¹<;(C¤@Ðu< Jy¦s¿ˆš€¢®ß¾®t-=ûÁ³t×YwÑ¡{Š,•ÚÜ=þùv?$Z5)W¤}ø¹ñ_Þ§ã""DÂûÏQÞõ`QûkTeŠÓ×Så h:Ž&ÁÄ'Ñ5‡5ºñøxXÓ97Ï|µ€ônÐL.Eó8WÊ i)üIõÆóé}Y ÅÓ ‰‰/+N®D3å‰@ð.O6¬nCÀ0 ´89ÀÇ# A FqgeKµÙ#«êìb%~·"/Çà¨ß¹rD ôkz^™•rbé}ÙœÎ/à4a9² G4/ÊDyl!Êñ¸,IÛT‰ÀANµÑðHG# ì;KÞ¡m9ÑôDª’ùš4hB“FL¢}šï#ŠܠǼŸwÈgYrÓÛÜuâ“T{Iç=h'LÐæi?N‹h)þ¶Þ¹µ|ñA0¶Œ±÷s¿¹aü tõ¸«£‰ZŠüÅ%Ôò š:l*µjÒŠr vNˆ’Éáã Öãò̹ŸBà’ °ýä§O¨ÛÝ花WÐÏë..Kåžï›EßЯ=ÁŽÛ‰çÇíWø/?¹7¿k¤si½_Ã’Áþ†€!`EC¯3†€!`T“~ ‡Ña¬,:AÏ ÕNÐÛ U^hW\özœ? ‰à^Ï î)â´q_â8W ¨Ð¯.„Na!Â)„´Mó«¢< `Àvý¶õ4wiôõr)z—v¡ œ@-·H¾*:Á˶ªÐûd• ˹¡)‰Àµ3Ä&¿{Pí°ß ó¥«À{ôë£é’Ñ—ÐÖí[C.Kìß³éžôÒ°—¨mó¶^ ø0^¢@‘- îãy«Hûú…ë+¹µsé©÷Ÿ¢ö×´§;¦ÜA¿núµÄü•u#)«ÿò{Åst¿Y «Ÿ]ß瑆]¡9¿Ðì!`†€!PLðÊ1c†€!PP äÕ " „BD EVVUÐVÁ Âÿ:ÁÊ<„í¡Ðï„xÐ<=Pxº*TèÒ„Šá<(?*¢-ðï¥x»Ã0üvþüVÄCèŠêß§Å>ôäeORݬº‘@‹°nõ?þe(° ¤Jm£4—®­pß^üv$X¦iÐÑMm÷l›8΢,‚â…ñþýçéÌœI6oHSJñÈ»4Þ…¦ BGìq„\ H¼9C•€E·…¢ÿʳwJí¢ B?uvcÎFúû«§×t ^}€6oÝ\<ÆÊ8×ãS§7æ¾=·°Ÿ¿Ù$åèxÆêêóV¾6c†€!`¼ZÌ”%Xù ­Ö­´Taƒ«&N áéÃpAþTå”Ç⋆±áex•¤¤ú‚Æ|WÝù%ÌÂt’PA[·XCðS!<°DàÂX¹÷«÷0/¿‹Ë£༡B!‹/ÔU\]åW× <úÀklµŸ)QkC¼@If²¦_¹qe”¯þvhÝîxw´¥' ° °áv÷$…V»¡y‡Ã¸Âø]û6nßHïÿä¾+ïhqçü®ç'ð …Nøš3¾šA}ÿÞ—V¯_Ï^¢0.#œpá:q¿=nr$¸AA¢÷Lp0Tdi?7ì«ì_½e5]?ñzêxuGzôÍGi˶-%â±43øå‡„ÕßÇñ{u¿ÏЕ.8ý-¸Ÿ€äÕßÚ?B¿ÒÌMàcX•¹à÷šÒj‹Ö‘ª|Ä…ôTiÃ4ñx ‡iPž™rEÀå ¿Un†@1_èB!J…l9ÿ¢pBU|•Uvü" i?Pè6÷ÇT©”“´ª«[þÁ“®úãä„/ùÆEq>´_ÄÕ«]þÐñ>YixÎ:ê,ºôØK«ÿ_Ù†PË;Dà‡ôKÊÚ®íwþ‚Žœyę԰~C¯h …N¿€ŸÉ'‹>¡wö %«—””ˤüõëÔ§ÇÏ}œNi{J¤`áßãN¹=Â[¸ƒE…¸Ú¯œ»tÃRúóþL¿½ê·tÏ ÷ÐÏ¿V¬;>™ÿ zÍ©´qëF¿Ã÷w<;ôy(`œFžÚŽßr¨sÏÙƒŠ°CÀ0 C àÕc¦Lˆ«Ñ4 &Ô¯³¡0÷ÇÓ&O¼ŒD8ºs8NæÅ膇õ ÙüUàÁó ·ÏóEDøåÖ¹]Ÿi4jq¼(8 WÎ\nöÃÖ\’0„/G×8Ÿ sš-:ãÏù¸âsÜR—<ìgWn„Î ÏhC¼mñpÒxéÒsšá‡ §Ö;¶æÊJ×Ü4à&:fßc¢íÿª7‡i,ñC€ã9ì—nöãsvrîã”ÿxXéù¹Š»Š×[ ßÊ·Á ë6¤zœoí^åþðíªùÔóï=hþ²ùù–YÔÈ:5ëÐèA£ià¡#ŒäèD„•à¤X }è¯ÒO¸ôWôQô;uEàhì_µy%Ý2åf:øÿ¦ß¹œæ~—ù{ ŠÚÞ™ŸÌ¤SþÒ—ÖnXËía^1ãr¿Iéûøíá7à~Q{¹íøJ¬þ&~à‚g.Œ°?¿>bq†õJØäÇü)Ïß9؈ןЦ‰Ç‡áÐÝ>åvj÷§vÔãÆôЫÑ‚e ¸°Ò3/¼óqÉtû¸Û)§?tQ`0ïè÷²âÏü¹ßšü^D!ÀüÀuíÔ<²k[<€Z°¿CÀ0 C ˜à•c¦,Uex‰kX_èOq¿¦ó‹t0a¼Ò¢˜¢ÿU~œ%-3,«¨þ’Ô]˜¼…I£<%­æ1×(kâýÔý¦õ¢@ŒbtÜà Äi>vå†vÐ1¸ôJN6À'àÁñþ~Ýú+1ú zìüÇè¤ßœ”œ¯„¡ëz]Gë5¦[ÿ{«`Oý¡æòöwßwÀ xb¿âéùtÊ U&ᓌ5²±rÎ@±_”0¼ãÝïÞ¥9óçÐȱ#i¯f{Ññ‡O¿k÷;:ºíÑÔ¬I3ÔPl³bÍ š0m{m}ñïæ™gޟê\€¯~(ÄÅ ¬*a°mžÈ$ýF•h®!PÕÈgÜKÛôxžx8UÆ‚ÒÄããáx™ñøx¸ ôŧ*Oi¡[õ ÚTõjœºažÐƇôÐ4fÊS”+üe[y|Z¶µ[m†€!P¦¨ÌѪP!û¿#ŽD é‚—·* ’„pMoŒÖº«C’Äü"ØÅÓHÂàOXV@ÎÏû‡và]Ó*-æ—2óqןr=½ùÅ›ôÝêï’„hÁÕµíNƒ•Õ°­À6 §bñîh™’Œé³–Ìâk²y·<¤ÏÔæ´ÃO£ëž¿Ž6oãÏç…uÁžØõB6‡¡Úœ½™Î{ì<}ÎhêÛ¾oê‚‹I½òwWRÃ: éÚ—¯•#VFˆ‹Usn«çÃñˆ_ä3‰ß/ýžü´@„ý9ÿ›CŸ|û _óÀŒ€?Ô§‚øÑ¦‹Ë³.ú±KÂ?là—üa>ø]XÊGjB¿ÒÌ5 CÀ0 @ÀT¢“&¥Õ¡ÁÖFC :! B‚}ÓAwq^Ðg’­H¦OçG:5Zº kù §i¶$7Ì›‘"ðÔªI+êÓºOŠDeCªW§ÝöýÔó=£-íh m¡àŠi„ExÅj;ó/~쀀W\ƒºœ]»y-}¼ìcê¸kÇ´¥á“|½íMÏ}ð\ôŒ‘ƹ²b­e ™̽7?[@IDATßÖì­tñ¸‹iÓÖM„/ dÒ\ÜåbÂW®štËóÑ5Œ•§¤Bæ?qü€!„o¸Nà—|$;üQ Vø0ҳܾ|ÃrZþÅršöù´H¡€¾…òq)¡ó3%ò‡®ù„{0ËÿÅÀe>äùà 8€•~=&îlÿÇ1U íGÞøN­#ªÉþ†€!`EF¯J3†€!`Ujãmo'pÈ6dlEfAU¬®¶" „¦TVójuü鄗t|qU…1´½ ÜVÿ•¿Ã÷=œÎ?úüèü¿Þ ·Ü³ŠU¾Àò#\¬XÃ:Á XñkA Ö(žìаÉ.Ždäk©êÑòð,!„:+‚) ª95sè÷ãOÎz´ *ŠögÓƒg2ÇÉK?F~u‘FýÁ„~L&’„)7E>ÍWÓ„´Âø•÷ÓÆ™2¤-#Už-eÞXš *µ§ÅÒ¦,‰cé|~ó•LtçtcFIËò÷iÕ›ÖnX!n\¿1Ýxê4ôñKã¥Ã byôÅEwnãr< ¼° Öhûá†ãû?á#k6­¡êï”¶”ZYµä,ÿ£ÓM ëàVÊT‡±ƒ†œ\Ð 7M½‰Öo^O×ô¾F¢3õ§o»¾þ.~ú"Ú¶u[Ôãè˜Á+vÈJ?þ¼´\ŽƒB#mA9l¥½ð›1 Œ"€a¢¢›LðX˜2Ò¥),=ž. ‡~à° iåßóô•Yþœ†€!`†@A³‰Þ­{óD¢âM%Ú·nO§vjôEúåÓtp!xb›·¢ë…€áŠvÊ]hoÐfÑ‘-¤7û½I÷{ÞâðbcСUºó¬;iÞmóhD´C’VØ“¶hfX·¤eÕš ¼HÿÄûOаqÃh{™9sÂ'ÐSç=Eõø_.ïìt'…ο°JÌj`!L;>»˜ïø|·"ŸU×]¨«õêbw[‰w~w€¦Q7LëhI庺d¶þ3/Â[|åüs”Û?žCÀ0 C Ø€€W¬¬:™ÃK~u•ŽBá‡IGC\˜/ Ã_ÑŒ¶§$|•¤Œ¢æ-(}Añ%i§å5 üÐß»Ý÷êžÚrŒ½¦ß54åÃ)´} ů+«Ã–0 á/3üÐátUû«2úÕƒîDéý:¯Ëyô§ñ¢×¾z-±;|Ã0_žoÞÕ#[ÖÙ‹ù‰ó&òN€ôèùRÝZu%>ºЕ&\8>6PÊ—súœÅgAßïP^Õ&ß`™Û…Vþåýª+ü¡‹tlew€ì ˆÂBãg•¤p@Z˜ ¾è ¿£3ÝÎ?}u±@ýLVlµ, £|”­õ°×Œ!P-(Îo  <©âSÑðTq©hšnQ㋚>¬Kýñ2Â0ü]¥‡nXžÒASqÜ0¿–on¹ À¯3†€!`†@åB qÆÔ~çö–éÖ»´¦s»œ›ôý´ßà¶¢ç» háÈÃFÒˆ#2*üÅSËZÒS—\ŽÃŠ~Òª~°Ò/tÍïÒ'•íî$ÐUÿT üÂ3Úá?4ñpg~CÀ0 C ˜ @Y2CÀ0 rF‚¨3ØsðÙü±×ùKpü-8쌇uG¼ÐÊa/üCˆu‚vž£ÕoŸ~tE»+ØWúf`§ôâe/Róúü©@æKyô«ßRqÖ>…`ú·ÓiÀƒè×Í¿f”Ñ#ö9‚Æ_8žÒ)„7ÅPk†ÀÌ<ª"·Ýè6ló( ¼;!Ý îéŽ Ô‰¢`¿O¯‚¿æÓòØ…’DëôGÜ®ÁÒñ*ìƒ÷ÐÄÃaœù CÀ0 " ` €"€eI CÀ0*,(»û±€‘üYØ­én4ø¨ÁþÌ¿ìàUkïÊgé¸ ²!ÀÆ…X&5«×Œn=òÖü+Ëpì¡{JS†N¡¦u›&”Œ{¨œH§xoÑ{Ôïþ~´zÃêŒr%À3>C ²¤Ü  ÷*žá'¦œ"À ÙNRàuÖãB¼®î³‹øÐz@,úUù€]ðë%€˜…Ár‘‚'‹ ûñ0Ò˜1 CÀ0Љ€)Š œe3 CÀ(?*ƒè ï=œjåòr³îÐØ  G ˆ ×^ÐfúÐß ¥ëîXæ`ÐâÙz߸vcQZx~q£¾3"´B@Õãl¹¹ó–Σ¾÷õ¥¿¬Ð¤q;ïÓYv¨@”)ú©E쨖ªDI°Õ >Uà†«Â¸ çØ´CWëå²>üˆw®ß)Jƒ Nv€ ú\®Ö§¿úà‰mZ៣͆€!`™D¯,3e‰€»¼ˆ—Q‚Zùí¯tù„ÇaR€$¹˜°G“«‹Üšþä€P¢?I‰zè-Lš0}ýImÍ/oظXº´e¤Ê£¥ÍÖäÉ“>ˆC–<ñZN,’Í5 Ì à~b-ê· Ö;´ÎL™¥\ÊÞ;ïM½íM“?žÄÂ'µj1ÖË6zÅc„T ÿõøB½ÁmÇ"Ë.Ønv4æ¬14èñA”³6[¼’¢OòEÂk†`‹×]8_­ü’zêE“.›D{4Ý#cLC ðÌÏÐÀGÏ”‹£!™kol¡<·Väz0¦bÔE~ή¼ ó(NÇzCZö‹…?•AYR62©Ÿ½xÆbP@`$ˆ8G‡£I5Y,‹’ŧMŠ´€!PEÈï7®‰åI¯¿ùTe¦LŸ*a@K•'ˆÖŸ½'˜>– ”rRҎƇ®Ðù¸.÷§¢4T*iñÇùÅuiB¢¤C—VâìOy ¸™2D@»¼ÿ ¸º5Œ úS¥ ãB<ŸÆ¥£k<ܤ ÓW¿k¶wªB›¬ É¿ãŠáÁTž)ÿi¿sÿÛ­ žËN¾ŒWЙµ²RÍáÀÍáUõ\^¹m›KÇìÚ¥\VÿC\wàïèÇý‘·Ý£ 8ÂñîyEbpñýz|Ë^¾wåÞ °`Íêu_/Z°rReÌàbÀgøN€z5êËqð–üÁWáùÌa «àɵK¢tažY€ Þav~QÖ +m”V –Çþ<õ(úŒfæ<–JOåjÞÐM•®´ha½æ÷}‰á6%Ä€YÎc*Ú³Œ3XþPFAùÒ¥IG—O†C?òiØyÍ)'ø5gÆ0 CÀ¨<ü¶ùo+³ÌéáûNöí ϼE]„h¸j±¥ÛÖac3«.{t©m½ê¤«è‡83ÉB¶œµïà™ V¹õÖ}Ùþî¶Ç/þu1õ¹¯Í_6?J˜¡¿PàbÀúN @^AÁ ‰’¹þ_¸l tûþˆý…ЮFø(àWðAÃÌ)L§éáÆè¾`¾!OìÇE†bÑ/Ô¸Im@y™´à½ S”ú *Ëâ CÀ0Ê ;PnÐ[ņ€!`ÅAààf'[¹ævÒ0zÿ_ïG‚3„gP±U^i„eÕ9úF}.ïEWóf‡pdù|qá®wÑÉ÷žÌ«ê‘Íâ¾0–›åøE­l¿‡t ¿K³lã2êsšxÙDj»[ÛŒ5è¨ýŽ%ÀžA›·m–úDè–êyåžÿ‡Üš‘+Â{ľðFZ6lI­›´¦ÝíN-´»sƒ©i½¦Ô¤NÂ''ÕnÄÇ1êQM>ÿШN£<üÿºõWË/[~ÿº-ëhýÖõ´~ÛzZ»e-­Þ¼šÖl^C«6®¢W0Y±a…øLQ¹¬‰:\mƇþDŽ"û´¿åÉXPùéâ«yÊSBº|o®!`†@©!` €Rƒ¶€‚ñr _ú2 þÐûµhM§áŠê†í,.%)£¨y J_P|qÛhù C =ú»cá­ÍNmÒ§« 1½ïEÍÇ6§U›WE+ÈÿŸ½ïô¢8þz)‚"v¢&jDÝXQÄ`ï5FM1Sþ‰‰5±$QcTˆK~šØ°#Æ **‚H¯"H/WøÏgnçÞÞ¾û¶÷m÷}ì¾·ßÙÝݻۙÝÛƒò¯F@6Èê¹> ÐÆõëÔ¡D¸½ìEcöC¾ó`°zÎ}e_Þùçu›„Ea †÷åÆ/é„ÛO Ç.zŒöØn‚µ F€qgŽ£ïýý{Tµ©ŠšÕqÝXõg§aðÙªU+¶õ0Ú½çî´ËֻЮ=v¥[ ¤­:äÍ Œ꺴é¢Á¬`umµ­]DKÖ.ÃÀœUshöÊÙ8õ|ªÁ{êì1b‡5Ý…YЄÆÍëæqã†.b8HA1nhùz=k܆©Ê±i|xË’@ºñ’J™òÄ¥Çá´ü¸´8œÒæš^z· Ä熕Gŧƒq´6NÀ®³ËuÓ|¼,ð€²ˆÝWê%à%à%à%³xe­o§¾9g-w†Ö-[Ó˜ÆÐmÏݬúÛÊ?ŒX•f­ß¢úˆã íØX³‘`(€C;2š7kNíZ¶‹ËB«7­ È \Uma·v&`‡v$,ß°\ì%Piˆçù¶¡eæË“ÏŸH x@"»Å3å%à%à%à%JÀšÔôïÔ_”»0­‚§r:ÝöÌmÁ§ê°íßõl€Ò/ÆØZmçIr}ºõ¡1ûŒ¡ûÞ¸/T²ÁŸ(zx7}¥ÊâˆòÙ8ï@ «kVÓÈ¿Œ¤‡Ï{˜öÝa߀¨¿‡í|Ý{Ú½ôû~/_^8n÷ãhðÖƒ Pry‹€Ü è§Röã¸Ã« êrÝ‘ ù`$À®œá¸hMÖøâu‹iSí¦€\û\!°Ã2 ‚°Zéiä³î×—Nñz x x x ¤”€7¤OððððHš¶ë´]ÒXÊšŸ¶Ý¾¾Ã×éÝÙï6TþÕÀJ³ìÀéóìÖW¯§ö­Úg]G)/:ô"ºïµû‚•}ð žÍ¹¡ùÙŠ 0X4x/þ俞Lÿ<÷ŸtÀà ÆöÑ»MðÞå/œu0¸Û`ñq¥A¹Ç+ úºÂìU³I<¿º0cÅ ÚT³)0 !³Ž FŒŠ)Æ”mHÒÊ-E©}!Œ#G!ð///-[MÞ ïnÙÝ\¾Ö{ù—Oö¾f/¦(í:V®ý1zÿÑôÎçÖa€ªø+4»T‘ƶí¤m3ˆ†N¯Ï|=b¬p‰Ò†¼ÊŽ¡à%Ê; Øå Ê߆š tÊ=§Ðg=@‡ìtSyWIÀ΄m;n+~¿>ûEX¯åo1.X½€f|5ƒ>ûê3šþÕtútù§ôÙŠÏäuëØ1¡J;C1 Xq-8B"5`Aw·€–e‘ø —@ÞpÇYÞnYxý ¼ýÝä åoLí¸aÀã¤7 k܆©Ò¯0¦ª”¨ÆäIYX†mKF², Ýr²É– ]n&úLévY>ì%à%¿ôšcå²wÇÞù—WÆNÚï$úéý?¥šZ>À=Fàpf‡ ÒŠ +ä”ú“œßÓ†ŸF¯O{½²%MWúÃg 8€ûʾ €ÖàäþSï=•î;ó>:r×#“Ó@ÏI^À×úwé/þ°í Ë‚a`Þªy4uÙTšúåTúøËiÊÒ)´xýâÆ6鵈q%Î\GhƒÔðúÑh8C2ÚN¼ô £™ò8éR‡>–—ÆÛ™âÒâpéò¸ôˆ§ÃišM§ál x±é4®ÐN‹ + we•€7”\ü¸"ÔéHqˆkXi\G‡só•+ž©=ÊW&ºTéqxçÆµNÚ4v4™âZŽK§x½¼ %î ;/×vuïÜÞí[4þ£"¯4ƒò/‡²’ …™ã3¿šI;õØ)×jŠNÔ׎¢Ö›[É6oQ¦°êÏmØ,Ê>ÚÀ^þ3÷E¤sPvwsÓ‚§ŒD›ª«èÌûΠ¿žúW:þk'0Æ»¦*¶ßj{ñÇ :&l&"üxéÇôþ’÷éý/&Óä%“éË _†Šº(ú Æ€‡cè„CNi @Ĺk›>Bè#[ŽÜA‘Ä–7–Çlò¥£‰Ksqnòsqn<‰2Þ2xò€÷³=ôõy£8Ä5œŠ­8š8\ªü¥Ægjò“‰.UzÞŹq­Ó†6M¦¸–ãÒ)ÞC//H€/0¬Ðôäï´Wº;þ'ÐóŽêXy†€õ#Æó]7vO_6Ž|lâšÜ©]':`§éÅO^”à …wðEŸýà ŸâÃgC{àÄÿ‹ÇVM|rÿ9cÏ¥»øë£¾> ÞmAèÞ®;Ôÿ ñÚl|þpÒâI4iÉ$1 LùrJðe?<|¬WJdLéxB†F‚6“†¨8ŒKÛYùm´7] ¸C ‰-m,ÙäKG—æâÜ8äçâÜxe¼¥ðä [JOûvz x x 4 tmÛµâ[ñí¯›Zü­/ôó29+ͲZ¨žf=ðÓ¥Ÿ&¶½G;’^˜ò5«am † ¼¾eŸÛ/È.Äá˜DWqe«­ †:ºèá‹ädùïíû=E¾À;.|µ€vÜvG¼Í`êÙ¹gAÊõ…OÛuÞŽàG !•T×UÓ'K?ƒv¼·ø=9€P•…FUàÆîÐtÉ$ÅG\MŦRú˜—€—€—@ÅIÀJÝex¨Ø}ÐÄÁ8xV<Âvˆ'ÉÙ|ƒ¯lÊÏ†Ææ-}¦t»,öðÈOz½²ïتc~å% wÎ=h¿!ûÑ3ÞgUü å™W-ñ¾ü›sßh¿7Ÿ€& ír(ý¢`é*¿ì`àÇvà5x†Š¢X‘…‘ƒw€.<€ûF€Ë¹L^-8sø™L]wøn‡Ó5ÿ¼†®øÇÂÏV·¢!½‡ÐÐÞC ‡ÙvˆúõèÇo.¨Õ¢0uûR #VÍ[Ѱm†‰?‡Î‘Bñ‚·¼Eo-|‹Þ\ø&M_>Ýì* ê#‚˜'Á1ÌÛ  e%úßRH€ï 9»LyÜt7îV˜)ô.·ËL—¦t.M6ñ8ÅÚÞ®ÇÆgF~—8Ü÷‡³¡M¤úß2IÀÊ$x_­—€—€—€—@îÀ§Éš‚;zï£iâ´‰õ«þª,3lVdžQœ—®YJذsÏ×ì{ïH[µßŠVn\YßÛ˜ÁÆQòCí‹›å ž'‚0@È5rÀ pÕãW‰àüo_°v_Êõ´výZºÿµûiÅÊôöª·éíioGÊoÛº-í¸Í޲SF °k`жƒ¨MË6Z)¿¶é¸ :B<¸Y±q…Þ˜ÿM˜7A¾@ ¿QÚCC”‰c,ælP…F›¯eiÜC/"H@vN¡\_ä–)oØ2ûÝ·ÚKÀKÀK ò$Àï¶-ÛVß1öµÃèš® }(ûª8C€¾åÕY¯&Òej÷~»Ó„iä•1Z ¦ €jÌØÜÂ(øP–ÔÃÀbtŒW?y5UÕTÑe‡]#ÁÜQà÷–³o#Àão>(~Ê Šãð† hÊì)⥣ìµhΧÚ÷èOCû ¥Á½‹A`§¾;I¸sûι3ãsExEèÛƒ¾-|¹îK‚1`âü‰ôúü×iÎÊ9õgRpzJƒÆ…¦c ˜x€”ßú3FbÓê©|¨©KÀM½­¾}/o¨ø.ô ðððØ$`&WíZ¶kºÝPêÓ­-\µ0PþUi†Í+çÍpxÚÌøÿLý]¼ïʼnl÷>C赩¯ñ†Ì¯*ÿ Ñ&+„"¥Ê” C å_aH@ô‹§!;®:ꪂ´Šü_/ù+­ß°žž™ôLÈKÜVq»ÂÚÚZšµd–xÉgÚCͶ]·C èWÀûìH½»Uö'+íöWjxë[GvÀðÚœ×èµy¯‰A`uÕê¨A_®€3c3vw@@üêXVœŽs»éŠ÷ÐKÀKÀK Œð€2 ßWí%à%à%à%›ðpSqï~006Tô# 4¶Ï›íñ“æO¢¹+æRÿ®ý×ô¡}‡FVüÃ6¨ACŽb*ÜŒ×Ú¸p'€Qž®þzªåÏ$üøè+I^°U‹Vtÿ•÷Ó¨_¢×>yM”==˜ oàW•7jCÐ.Y¹„¯XL¯}ÌeÁ!}çvipŸÁ´Óv;ÉŽ!}ùÌ6ôïÕŸ`ˆð®ô°Õ0l1ì ª©«¡–|@/Íz‰^žû2MY:…êêxÀ¢¿MŸ‡ãÔàlƒ€ìሦ˜<‘V!]]\º¦yè%à%à%PB x@ …í«òððððP :ìPû*ìs„ñd†âŒ³èX€BüÄGOÐòv s}{ô^±ný·Ûc áŽæ_'´Ã(UHCT %…FÁÝð tÄ®Gа~à &?ЦUzäšG蘟C“fL ”vs¡¼~ᬇµ=[©C˜½´AÈÁЬ޸šÞûü=ñaNÆY;ôÞAŒjÀŽøv­›Æ—P^ ´lÞ’öî½·øŸ ÿ -_¿œ^šý½8ûEzmîk´²je}rŸº¯ à°NqÁ­O×6¼FÃ1„›ù€—€—€—@ñ%à Å—±¯ÁKÀKÀKÀKÀK †ï2¼^yV¥:…*Í| ¬Ž³2úÀ¤è²á—”–$¹^]{Ÿ,Ôƒ Á;Ú€öÆyF«ò VZ°„\Fë­i@B[¨ŸömÛÓ£×>JÇ\w }:ß|nÑ]˜‡¢f|h¸°h#Ãp÷€Á‰AÀ¤©,ªêªhêü©4uÞTÉ<ÚÞœÿúõìGbà0 í7TâøjwÅ•@÷öÝiô.£Åcw¾.ðüçÏÓøYãåsƒ²úoŒDàD>:>$Ý(ö ÆŠÁ‡-Ð1#…XhJ°û¸)µË·¥IH Y3‰&!ÒLÀ“O@ò`ààá ްâ8:Ä‚ÎD"¸ %LÓhJˆÌ…w¹XjÚÆN c’êåItÊRFh܈•§½•†l Òµ,‡NÑz x 4^zYbuµ 9(ÏÛ÷@³—Í”~(ÍêùÐ<‚RÍïų¦A VÌ£§§þ—NØ5ø&zRİu—­ƒ~1F é#œÞŠq€|†Í˜n3· Í ž}õ¸Í²ët5Ë@yüsè Cä‹…nw.=艟?AGüôpš¿|~Ðj0Êž(õà×Yñ/Â'à7ô߈7CY œIJÏI(g3Î]:GüøÉÏÕ?j8­g—ž4d;þT!Ÿ¹€×Ôgm·õvR´ÿ)¬`hÞo¸ø_òkš¾lšžûü9zÿ‹ÉÜSuÁ4NÆ1gŒ83®eŠgâ¡1igBÀ8P§4÷0€-£le’)›žrng*té]>Üt7ž‰ÞMGÜ.Ã+­‹CàPŽA¨·ËPœæã½¦!Òᄎ”^pVx$ 4ô@yWv x@‰»×<îñz=€…¸8ðJ£Ï# ÎÍ`ƒßti./TØå5]¹éhsMséÝx6m¦¸–çÒ)ÞC//<%`..€õÕë©}«öy˜œìûíôMšõÚì@I„r\ËÊ/Cœž/Ê%Oºd¥‘oèw¾yWâ 8_æ–à 4·ð6X^úÓåϺ¯êÃM¡tî0µ©C†Z´NëÓ£ýçÿý—½úPZ¶nYPøa/; Ä#ÎJž» \ˆÑ6öb¬–0œ ëÿ†é¡Á<ÌghPã–®ù’¾˜º”&|òºT©åvlבp#v `ÇÀྃiØÃÄ0*žAÿ›‡†ô`£ ûïï{¹|Yàù™Ï‹AàÕ¹¯ÒÆÚÁõË]—q£V"MG# Na ƆÝ4Å{X  [*Ý¥jC*¼´×J´‚ D‘*ÍÅgŠ7(Ø#Ê"o(±ØñÇ&AÞå'p”_1>·—€—@H@¯wlÍmJn¿ö£q¯Ž Þ56Š¿¬sX ¬ˆs˜ïÍ^šñºcñ”á\eÛ²%O#xÆ'Ï5,{bö—É;•¨¢¾S-Í ”<+Ñ÷ûo¿¿“«°ÑÛ¤§~õõó£hͦ5Fqã: ü³—]è xnf¨èq4tè38·ýŒGä¹']ÒâdRÝõÂyĤyM=ë6­£I³'ѤY擾M·mhÜÕãhŸö¥w”¾,pêî§Š‡üÇÏOOMŠ^šóm¨Ù 㣱S>\ÞPÀžðEy x 4Vx”yW èd¶ Uû*½¼¼*VÕuÕË{ãûÝW”ÈRh”yNØ pýK×ôq…•×{Ÿ•G@WÁuã¡"­J5f%Pº6kÁH÷èÔƒo=ØÉYøènv£G®~„Úµáƒø”…†/ðÔ¬#ñ1 øÖõ¾YN‹óm-¼fZjÃU!Ok‹aö(_ð\_" Ë7†‡f-9]=h9¼dõ:âÚ#èÖ'nMÔxa®›”ëк¸Ó‰t߈ûhú%Óéžcï¡@íùos ›ÅàyW¼ÚÛ%^ñÁ5ÁÆõr Ù׊+%ûsÓ|¼iJ}î—@‘$€Gšwe’€7”Ið¾Z//Š•ÀªªUË{ãx»C›RÀxYùU…ÍdðÃEÒ¦þ'®¨²àÖmXÔ« b;¼‡Ï;N AÎú_ÖkCƒf'ÆïÑ{`õ¼ž2ª©­)˜’;|çátße÷Ÿéc~Ä>d€î€!ÀVºUI7Ê{C€­ø[áæmšàRåµ PþÙè1ØusXÒÖ5¯£ëÆ]G§Ý|­YÏ»¼+ªÚµjG' =î9áš~Ùtúûq§w<‘:4ëBc€žõa]ïÞPÔîñ…{ x XhòL4’ä-ÙK0œ¹ >î%à%à%à%Ð@««V7ÀU2߃ߵ߮¡Ò,J?·ìUu÷9ñËñ¿¤ªšªD4{ÍV,Uù70|æb…m³iLôʶñb°”n|»=kÙ¢%=õÞSõu¥#Î"í车¿œÿ—¨ÑAùc¾Ô`€®^yª"¼e6Î#Ÿz-ÓŽ[åªò˜þÉ÷ž¤o]û-š¶`Z­÷$…@Û–mé¸!ÇÑߎÿM»týíè¿Ñ‘ޤVµ­ìlPC€íëÆ\Jþ4=‚ô/äK |N$DOK¾Ä Ëa“7V\(MoàzÓVˆ¢í4kºÂ8¼â*­‡ÑIg‘åy?³ÈuE&Ó¾®’ö³—=ßhÊ8æšš·í¯ úš¬˜Ë„+‚ºMجFVÓ9ytë„[‘µì;DÉ×1¡<[ñˆ"Ž5M¡3-b•ׄˆvè¶CNØ©ÏNtùÝ—Ìðáß¡ŸüyÀ+Ú^mgd§ï ˆ¬Ý¡R*ðvXq€)û0Ÿ¦[J¿äá¼áΔã”?cé :øºƒéñÿ=n·Â‡K NÜùD;r,}|ÉÇtÓ!7Ñ7z}ƒšUóùÕl$3¯  êÍìP¯»ƒÂû^?€zÝéXµÓ|¸á=gK•‰ŽŒûleG‡CyŠ7Á0n×GcÓûpI$à %súJÂ’ôd>ÕKÀKÀK`‹—ÀêMMk:t{Ô+ÑöDžÃáóA'WFñ¼íõÛhúÒée_¬ø"«+‘x$âN#‰VD•k·ßj{+1>8¸÷`úlñgtÉ]—Pm´§üÝ•Ç]IzAPÓ,ûU9ÀœW ïæ[ïçË{ü0¨Rní€ÂQÚAãz[áÏ5ÌeÙ寯[OgÝu]ýàÕT]Û´ÎÒÈ¿·KSB·vÝè¬=Ï¢§O}šÞ»à=ºfÿkhÈVCDñWC@ƒ×ŒA0²3@9g\J+²½ÎJÓd_‹—€—@%à é”p’—~òe£©µ'_yøü^^…‘À²õæ3m…).¥ìÒ—úwæ­É»ÜG5îpZUWE>v!mªÝ䤔6:wÉÜú me$U¸ž:cH_èÕ¡WFZœyÈ™ôàËÒÅ·_\0#Àß»‘NþúÉõ+¬v»X¿Öך×d'@ÜFùÅü©1ÀY­‡ÀVÜu…_ŒöÊ¿¾&£A¶Æ¦½ëå»èø§%+—d%WOT ôëÒ®øæ4ñ܉ôâi/Ò9{œC][v­7˜ÕÿpGÙ›¬âº¬b¼ÚcÖM÷q//-RÞ°Ev{²vÅ(Y¬zn¼¼Ê,¥ë––™ƒÂW?¤ïà}s3YÜÛÕš'÷”%Sè·/üÖN)yxÚ<ç½r[Ù°ÃÙp…ZîÚ–•¢,Ü ûœ@[u؊ƽ<Ž.¸õ‚‚`„¸ã¬;èÀÁŠÒ¥ÊXøZø2†5X¨1@¾f` ”0v°_PxÞ% §úË®Û(`…CÀlÅåÀ«a@¡McÂÿ›ý?:ð—Ò„O'd!YORl ì±ítÃ7ÐÇ—}Lww7Ø÷@j^Ã:¿ ¯Ø_0;°í_ïáx4÷ü*>×k²AAá%à%Ð$à åèE½Û7d‹"l§7;îÐ7°üº´š?›|ž&µ—ƒ—ƒ‰‹×..Ç]»¨uvh×úvï~LîíΫá{¿Ì ÎÑ-èw¼q½:ãÕ¢ò—®ðg|/ ÎçŠÉߥM—t,„iíZ·£ïø1¦<üÊÃtÞÍçÄкek{ÑXÚ«ï^Aá³nè]‘u·c[ñØ`y1 `&Àâõü@ÆÙ¯ˆñ›ÆÂ×Ô` F‹aÁ„_ºa)øãºé©›¨n3á]¹%кEk±Ózü”ÇiÒ…“è'ßü õïØŸolÀw^Î à±9+À24¸õÞ’ÏuêóæwŸkŒüÜÁ™OqyQ>ðêâhâp ×|vºâSá´Ë"o(¹Ø³¹JÀ”}Ť §£K—f——-§ÒÂh£ë*­ žßì® /§&)§f›YáÅ5¼™–®¾sî^Ù•Òw0·ŽÇ/†0Ÿžz9E)fl‹rÉa#“ºæµtÎ#gÓ¬å³JÞôM5›hÒô÷˜Tð2!|jÌð®mÈrh9™áY‡Ÿæù׫й7[#@çvé‘K¡í» `e‹ù’íÙ¬Ii_á$k«]2^›™º¾ãØ7“ÃY„²3€!^ œÞ’}+¦Ñ4…òú@@+¯´f §á`·ÓÉgÊ®+Îøº–µôÛÿ^O#ÿx}µö«Ìö%“@ß.}é‡ÃHï^ø.ýû»ÿ¦;ž@-ëxˆ ŽþÀ‡cc㲎ñlÐ v0÷s ®'Žc¬¦Â[ã8B_Iø¸öfäßíZ#§Œù’D—ª ŠÏÄ+èRѤK³ó¸tˆ{—4 x@‰{—\ªK…oÙ ÒmZ;ì–“mZcèìÀÏ¿^ûóù1ôèÔƒ»ôqêÞ¶ÕÉ–ln¯´Ö‰1€ÃòÙCÓNmú žûJ<+ü›Õç† Ž°ò/«ÿ e…ß@ofP<+ýÁî‹FVú9nVüÈq^ù—W ]Ï´/ö ð«èÝ™ïf+jOW" ðþ >`8Ý}â=4åÒ)tíðŸÑvûñxðê?Æb8Ù&…1)žÇcñö½DÂÌ{xMr L·ñ[XØíÎP>$‡TmP|¦6.Mº4;K‡¸wÉ“¦Þ%L ›0¦<;^^^å–ë.sWÍ-7E©à¶eæü§Ûtyv9X•å Š6 ?űÅ|úWÓéôO§ªšª¢ðWè&þ'xÁM´ùCZ\ÜÍǬ’ÝÆšA Ëß3?3 4õâu€ n.Ì™{¤‡/z˜Ú5kW¿ V_ÑWfëuØÊ3ó‚×6"Þ}=€ã Î À,ú©A„åU¼€W_`¼R<+÷áö ˎƳ!À>XpÁÚôíß›îGt¼i<,»¶î°5ý`ÿÐ{½GŒ~„Žx$µ¨åA1(F)žAb‡Š}ÿà°§tŒâºRï¶(Þ¥óñÄKÀë‰ï¢²2è eÓ¬<2QmšMô­òð(“VU­¢W”©öâUÛ¯g¿úI¹NÂmhW­ 5žàÆCœ0gñà%ù2@Mm =öêcõ\'uV>Ϫ¦¦æ sÈŽ>Š:¶ï©ç¡W¢ ÿxaAvì½ýÞtïY÷Šâ¥ßqßцò#€1ˆ¢NЗp*@«ÿ49/(ùq†lÃ^° PöÙ 4H3Æ9À3]x6jZÔÐ5_C§Þq*­\·{—@ 4oÖœÝáPwò8zÿâ÷éòo\NÝZwkxV€ŽEÕ «T÷´WÓØvÏR è=&E²G{ Øð[ ç:áIëž///¢J`ÎÊ9E-¿…à ÆS¬Üéä›!páj²=Ác½- 8Lÿ«üÛPÙ,ã€î×Ìn ;»ôÕ€kÐQ7E·h4µoÓ>¨ 9Q§%£±¯±à/—æ½½½uËÖ4îÂq´sÏÃÕ=@*³íZ_ @¿†Æ}·EVûݤظÊц6¡…WÃŒk7ÆŠŽ—È+8@=ïX¼~1¸e]ÿÄõ„C ½« tiÛ….~9M¾l2Ýzô­4¸ëàp¬† ¿ýz€Qò`pLgt `̪¯‘xN½¶h àQí]Â% “ „³Ù(ödÔ¨œåË$«]å«Þ×ì%°eI Œãf¬˜A5uMOéÞ©{ýDZ'Ô ! ÂYÊ­ÔÙ¯ˆÇÛ»ï{ë>Úû—{ÓƒlÔÖ÷›6Ò™¿9“^žür½­Š?fxýʾyA —ò z^1¾¥¦ Öv™ø¾½÷¥÷Îzp°RäñZÅIœ‘ShŒ0Ð~3«ÿÒ‡xÀy%ÀX×¢Žnzö&úö ߦ9KçØ5øpH眺ç©ôÆ…oЃ£¤a=‡…†}m%\ù‡À¬‡†cïEn›Ý{”›îã^^‰nÿÞU€š² ø·Ôv§“‰OóØR%Àê¥4}Sí&šùÕÌ&'†mºmS¯ˆêDZ'Ü Cƒ©*ˆ8‚-ÜøÆó)~Åáôoü_°Måóì!¬ÇVúMýîjs¨xƒgÛ§èÅS†žBOœôõïÒŸvê±S ªÌèð0@Zõ Fñ;q,]vïeõòÍ\l,E﮽鑋¡vÍÚÛ¨­Ãe‹µéK1 ÌýY]µKÕ>¶q¹†µ½v>ƒ“öÛ†ô'”í?]ù´¾@­™ŽãïÌ}‡†ÿj8=ò¿GìÒ}¸B$#ÐÑC¦Ï}‘ÆŸ5žö﻽!€•~ŒQ1`œÂà"ãVïUnÛ_ˆ±ì–oO̽ûÍÍ7‹rŽ|PÒÃü›™ˆËœ»r.]÷øu²•û¡Cv;„ö¸' è9€ÀÞ‹_òÕzçÓwè‰×ž 'ßx’jjj…õ@Yt F™Ž¬üƒJ¦ë˜1æ }1î¢aÑ/‡ÿ2 ‰IϵïÎûÒоCiÚBëܰd{Ž>0áiÓŸÎúS<ÏYVº÷À½éÞ³ï¥ÓþvëL¬5q=ÍXîò|4aÙròÐ~–ÒÂUyð¥év\ñ®¬MÙèå Å¢_5®i2¦À£ÃÌšš5tþ½çÓø)ãéÖ3n¥Ní:5†3Ÿ§ÌØ«ï^ôäOÒ²uËèIЭoÜJë«×ËØÃ½DwñÈ5ñhüæfœÆáð×±ªÐn—Ž¿¸4›.UXó§Jwñ™è3¥£<›Æ»ui<›æÆµ f¢Azâ¨Ï©ÂNÓ°Ö­q¦ #Oª4ïÆµ>Ë"&o_ѾR™$8àÂ×âKôððH 0qÄÂL ?Yú 0ô„2Úx–¶Þjë h§ñ¢ÄCq·N¤l c/Š›*ÿ\P¨¸ÙÅpxcÍFzú£§éé÷ŸVûÌJŸ¬îéjµžXÙ‚)[Ýi ÛÅ‘Ž0 f%9¤ƒ±@à>…5dýjø¯R¤6}Ö‘gÑOþþ“úÌÊÃP©áÔ^g#,n;ó¶z¥¦>WÖ¡£‡M¿õ;úñ£?fé¥ ¾<Ça¤±û…K£ Æ–²Ûñ¬¹pQ†=n¬2e¼@Ñ3u5à•=à ð‰À@á‹Ëyì½ÇèÏß¡{.¸‡öÙq§b­ ôèЃ®<ðJºâ€+è£%ÑC>D/|þÍY5GÆ t|HÿÀCI bñãVÇ 5þ”¼¢¡¶«PÈT^¦ôBñQÄrš’~VD1­h<²½+©ì«Vï€.ÎŽƒ9Ð8wÒPRÖ3Væò1CخԔéÊŒK‹ÃÅ•îÒÙq;Œ¼n<.iÞy x ä/àzüà‹ò/*a%tj×Ñp´¿X=–[lgLÄ«úÁ“!˜Œs„'â¶ žPþ‘% Ü, 9'‚J:¾NðfÛ¯Ô“úá$Âa¡e€ú`PÅ_”Æ!Þ‚ëc#@3N'kQxD~ÛsTÝ} [¹U£ƒ§r ýüë¨j3Ñ/²@; 3†ÊŸ©íþ‰ÿ V-[ÑͧÞUfräæüCΧi‹§Ñß'Þ+ígþÓç¸B)šY‘8vL Ü¡L”m;SªEšÌX”ðÌiˆØGpp\Æ ÓÏ[=޾ñÛtÕÑ?¤ŸðcjÙÂO/YBépOÙ}ÛÝÅÿŽ~GŸ}ù=?ãyÿùxzwÑ;ü6 w>÷½Ït¬bÌ`üàºBš (Ó|Œ×i>Ÿ¨8˜lê.®q8•ƒIk@Ò¡˜-“ÍG .‡.¸HÓh}½'º8;ŽÒ@çâÒ×RúTL\ã2åJ——‡‹ãË¥³ãvyÝx*\:<Ò¼óðÈS|3ÔëqÊÒ)y–¼ìÚw–Ê¢;7´qvõ÷WóÔ@ð* ¡â“\o 0Û¹9!(Ã@LÎe¢Îwx|» ±Vgð¨uÈÔ!ä‚Õ~Ì$Za.k3 €L+ÉP”—õží{Ò=GÝK­[ðKævÝ:u£ã÷;}ãÑH½hsQVÐãîžp7µjÕŠnøî Šjüý)¿§E+Û¿`@IDATѳSŸ5]È_ÚÅr0Pd  aÌ@Ô¬8„óu(Îî»>ô—,àe¬09/4üÊ8‘4¤xRjªk醧o ç?zžþzî_ihŸ¡¨É» —@«­hH÷!4¼ÿpêÞ¡;½»ð]1¼<çeZQµ"¸~tŒš1¬»E"M×±§HÍ£ñ„A°×Ô]\ãp*‡Ti©ðšOa¶tJïañ$`=òŠW‰/¹°Î…-Ö—æ%à%à%| `ÉO®eë—ѼUó’Ïovl¯;ê3Éý³&Û#ªJZ=iRÅ OwöáA}FQׯ„ŸwÓÃÞ¬ƒÞäз6¼Víâ ­ž2$ŒÕ~”ߊëÀ©<À°`ø1š°Ë5ÝtÐMÔµm×øB!Î:⬠({Êl ?Ê›Ù]¯ÜE¿xüyUߢy ºçÜ{h—ž»‡ÂÈ‚/Ø_»ˆ=Ð­ÙæÛMkLm·Ê‚ah<З0ä°LÚ}ñ€1⌓÷¼Oþê@ºã¹;ä< »®< lßm{:|ðá4÷«¹4ò#éçÏýœ¾\ó%4ä$:iðI´{Ýi«–[E Äý F£ðþ…fÇá8\å‰Èsì%Pqð;JÝe¸Ùé φëYÀ6 ÒMnª²5”Qâ4MãZ†×p’ ¶¯1<+o6åfCÓ˜6ù<^^ % × z¾·ð=ê×¥_Cú ÅÈ!jXm×6*N=pÃiz“_VÇäY"o<X‰ÓCèD‰“lfõ™ W¡e¥žãµœ‰ó`ò.‡j€(O=ʵ”B}ÿ?T¡<ªGã„? Lv'9™ŽÙᘠR¤ßv;€vØfš¹tf ?m—]Ú„Un³óáÖn¥6­ÚÐ5Ç_cSåîØ¶#=zù£tÈo¡%ë—H^È@žá"L«8ðÄʶ¤Áh¢²Víš>p‹##ãÆh¥ :~ùOV}Á4ÿWÕTÑOÿõSzzòÓô—óÿBýzôs«ðñ ’ÆÃˆÝFб»K¾û ÝôÊMôÚŒ×Âk<4ò¡ûƒ_äµN§‘lÆuŠqó›‰>Sºò¥Eg¢/tz¶åÅÑgã5lãmœÝÖT46ޥ׸[¦·Óܲ@ç]É%€Ç³w*y0'€÷úí©¹1“þsãÚS{ x ”\ÖdQððÞ¢÷JÎJ1+ w˜ Rì=ÒžHs0”= ‡ì¬\QÔ±JÏæÿp_Wqêê¿BàS…9-\ù·vˆq µ*àÞqíZ¶£_ìÿ [ø(dsÆagò‚Ì,¹ _̛𠈃 qãÆgo¤›Ÿ¹9/†útíCã.'Ÿ´wà#²ú¯Ð2òÈ–{—OpaóW&s\¿h?©L0SÎŒ#‘ Æ5Ž"»tg‰3'Ò~×íG¼ú@!¸õe”Y-›·¤³ö9‹&]9‰®ýÖµÔ¹¿¶TÍÃ’?y);[ÌXÖq.ylËýLǯBmOÜX×4K'·_JW³¯©Äð€ ¼ÐÕÅN ]IËÛRÛÀ®ð,y ”^FiykÁ[¥¯»ˆ5bµ¹Ó‰±Bh8n²f+o¬ôÊ*ƒOˆóòO°Kàl>†ŠSšÈyjX€ò¬+ÿ˜epººn³Ù’?!pÞçÙ¨¢†{nÕ“NØ—? %rT¨25¼†¯. nV½öïŸÑ_^f>7bïôóã*IP–TaÒSû<Q˜Êi@[ÍXBÿ…}¨r1†žØ]%0™±¤c也£o\ó ûÚØ<¤è³&I½:÷¢?ú3½pá ´Wï½#$ŽgǨ…ëNæ¬z͹I…wé|ǯ04%/,ïΣlx­¯"h½ŒÇmÁ)â¥vÚw¢‰7O¤ƒw;8ªŒXŒÈ}ürÂ×&XV×\AcßÈoûŽ3ï ½·Û;\ý_€ŸaT¥ßU,%ؘñà–‘*ŽöÛNûaV¯˜×KÔX¤»ÔðÒ´—hŸkö¡;Ÿ»Ó)À–s…†këjiúÓ©¦¦††~@l¡ cV}…¶5g¶‹yæÌL™3xY”¹ê«Çcß»&$äá\ä6…ÛTYO6ÆŠ|ëh$k>›—€—@Â%€{œÜXyk~Ó: ÑË}µ=™Ò05ׇt†0ÈýqÅmFÇYᕉ:_à”†“"´¶½*ù¶ÓB<è-׺Ek:lÀa¦tÁÎí;Ó×x¡Fì5¢Q¬÷ìÒ“ºä!:ê÷Gцš ‘%u»3ò-›-´ÇøAœaÄ dd%rbgŒSCÀææŒ«1m4¯‹`ÜLž?™üùtÞ!çÑ5#¯¡.º Fï"_. f}@Îü&ÏšL“çL¦ek–ʾùZ^õ]D–áGÆ+â0^Á`Ƈ4ËŒŸØ&¦K‹ÍPáHûÚªð¦xö+GÞPê¾Ò[Ô›€ qÓTœ†¦á?¼é‚& ú4E…ISþµ=aÉ9Š™?›²³¡É±IžÜKÀK ƒôºSÈäÕ5Õ4qîD:|Ðá2'?¹y3hÑÆ¡®‡2‡Ãý]ïñ AX%+E)T>r_×r8ŸìÐqÍdC­×®Ã2Ù·é\8¾Ï¶ûØe Ÿþ­Ó©o÷¾4æŽ1Á ¦2´MN\Þlà¿óî?Z4oAÇ}í¸Fñ?lÀ0ºýôÛéÜ{Ï•üáÎŽ¡OBE 2/Š—>V‘év¸B;·Mùá8‚A <0Ÿ;Pü᤺«AÛ¥q±u»1ûqúÕè_Ñ÷ü^Ãq$¥ùŸbJ`Îâ9ôÁçÐ3ØÏü€Þÿüý@Ùç~ ¿êþ…â/Whò«+%ã@=îI¸Žì{î+Šç`Z—bÜå•'S™nºw+O—ž. å¸én<]]q´ÀÙx ÛxçÆ•/Í£Pñ6Ô°Ò¸éìÂg”ÿ)£¼ ŒÂ/EÕ…Ü ™$–‚y_‡—€—€—@œ0±TÇáWg½Ú$ ë6®ÓVëBht*+LÊl§“sÆËÄݤç4IÓ²J(ßÂÙÕ¹ázìä¢Ê?d·Cèé?M'ÿédZ¶qY°ªmÓ)m”þƒœªk«éìûΦq-ÇÑ»’æµÏ(šº`*ýáù?ˆ Ei6òÔÝ¢dA°à•&YI—Ç•¯\*m,-êŠG¦¼p7;Vð°›.Ü 2…2ƒA¢qγtýRºèž‹è¾—ï£?œùÚcû=˜À»BKïìϘ?ƒ¦|>E<þ÷g¼O+Ö®û$TèÑ?pnß#îxYx‚ñ¯£êvŒxîëp,#â Ãîglþeyç%à%VÞV~õ¼@)âÅE mDZåÏFN»û4zøÂ‡éànT®;é:šºp*=ûɳ™X9å~EÊUœÐ¿Êc£8É"“–o%ÅIõ,ÞêõúÄ8Q#d) 'qœMÁŸEZÎÿΜwè ŸDg|6ýìäŸQ·Nݲ`ΓÄI`õºÕôñ¬éã™ÓG³>¢)3¦Ð'³?¡õUüξö <Æ:ÃðW¼öiXæ@ß/ >gŠ(þHƒÓ1¢0À&ïWùMgñ5–߯æùäo…ÇYÞPdÇ+…].$ÂÔ½ŠâpÈ Ÿ>M•ùl J‹ éÒM(£õ¸²°SS¥¥ÂÛyvé츎£M…ÎÍ`ý¯—€—@á$è>Áµ6}ù4Z¸z!õéܧp”¥$½w⧸ – e¥¦j‘ p‹µÓ¬Ç äœÚ™BÒÒpn«<-«ÔŸÿÓzÓÁAÛ ¢~úû‡cèóåŸJ«öo„¥­Ün TÕn¤Sþz =vñ£4|È骈MƒÒ{÷ywÓ7AS¿ø$0>p=õ;¸.k‡@1CåÂUlÎJ.Xõ¢.Û^„ENÃj°*Ž‚ Û€¶1ëh¸•Eq5µ54sáLš:k*+ø¬ìÏüHþ¹KæÊJ{0V x®c@q.äþÓ`ØáHÐoè[ }€ç%Á ”ŽKD°"\Œæ@ZÞ¦×3Z²9ŠÃf‹³Ë±ÃA~¨;õ÷ DÌÀ³I}¸¤ð€’Š›+Ó‹@ǾGΆ Ó¸†°›œëRÐK¹w«Ûí‰%È™oiòÃ8’ÑH‘&Ü{//ÆJ@¯=…\®Y¼0fؘƖšœ|Ú.Àl<8·érm‰Ö—k>›>Uîsy ¯å<ÐfÝ oÓeúïUOÓq<–f,›Áìòª4ÿ‰3 Pøð…rÄíÅF>Èïä;GÓ¿/û7í;h_·ØŒñNí:Ѹ‹ÇÑá¿;Œ_CXÎôA½Á ªÆñ…bÅöi¦„"QdlÇ+¦sûßÄe5_˜áʡس“ç«´ ‘ú•a10Ï ƒ6±ô™fuõ*úÙC×Ò_ž»‹®õ3úÎß!⸥:(ú³ͦOf}BÓæN£©s§Ógó¦Ó¦šMX €ëÙ›ЊT€†´ÂPô5-4ÚðBƒ²a´ò!{GcÂ'VúT.;o&úLé(˦±Ãv=.uº]ŸNÅÒÚaл8;MÇüñ˜x#€²‹vÅ–X!ÂgÐN¾ãd1ì=po¥Êì5þ~þ}tÒm'É÷ÔÃmó¨G4(¬ÑÁuË;×PÐà °E&ñbþ([Z‡Í˜â{7€hŽÀi›D‰d†ÑYj¹0ÞÅr³Ù!0õºðoÒïÿï÷tõIWÓèFs6M‡÷ôq(Ÿ*úض?mÎ4šÎŠ~UMp¯€‘%ìwbŠ3@Ò¶ãˆ(ΆȈ$KáÐI?™¼Øý‚ êCq\^‹á°œ8—éKä=ó+8àí8G“äpù45—©Mnºy02ŸBXq´À¡û½+¯š¼ ãJnyå¿ÅÕžm”u‡‚Ó+ºbá }ÔKÀK œ0H ¾2ëy»U‹Våä*¯º«ªƒI}^…*sghxÔm®c]{“ézuéEO³àØ[Ž¥Ï¾üŒ'½ÖN{`a(7ìð¬X]½šNüó‰ôßü—öèŸûví|ýnôïè‡ýPÊ%™ëÐÕô@©b^dù•+…ò…ü'Î —r¦zÝپŋð}ÀÊ§Ê #øœIgå_Ú…6! çâ”yó Á™ËfÒywG¿}ì·ôýc¾OcSѯ|µú+9Š=æ›±€ý¼4sÑLÒ{‚ÈEå Ùe¡è˘@Ûc`Xñ°\ààŒ¢®4½†5MpJg}yÀ ¸¼S#…æÑº¤Bó‡³Ó}¸ÉI [} É5]ûГ—?I‡Ýt-_¿\ž×á³Ú(CÒg³CžQ_müŠN¸õÙE0´÷Ð 1‡ß›ÆÜDŸ-þŒ&Κ(¹¤\³B®Š±(ÍPìP·=7HΡþ¼HqMÓšúb¬y‹¶%ä™Ópý†»Xiƒ>#Èÿ›[˜Õ´ŸwH{ñÁ cX¶~ýá? [žº…†N'}ó$:nŸã¨W×^õõ1´~ãzZ¼|1-ür!Íÿb>áнùKçKñyKçQ•y½GÆ xáf¨ÃÖyqNÚò‰Ð€V=4ÌP”q§ãÔà$ÝÆ™°àµMGyPâ·p‡å¸*û1ñ0MËG‘j”_©œ;ŽRÑŸÓbR¦z Í¡ËËÄ6éIä)¾·poHÐPÅ6œ\$ˆ7ÏŠ—€—€—@"$€ $&64“ÊñŸ§ßñ_¥º5ë×T*ëÙóm&‹_møŠúvî›}¾2Rì9þuñ¿èØ[¥ |ØŸ(Þ2™)(;pƒ&¬F(¦bàCõ$dÙþ´nÙš¸ä:èÿDóWÏ,l翈â„záê.e-Hà_½^BD Ê—­(Ž«—yŽáY¸á°¶+ÜÍÀ¯ˆ±g ¯Q,e‡ãÔ0@j àCË&LŸ@¦N +vÜvGÚoÈ~4¸Ï`êݽ7õíÑ—zuëEÛw–CÛ¶nKðpk7¬•sðjʪu«¨º¦šV®YI+Ö¬¨‡kWÒòUËé‹_Ðâe‹éË_Vö‘7"sðªNÃX×0Òvã@ÙJ±Mã„C:-CÓ-¡Qûâ3úlÑgrÆ€¼zÉœ7€ºd>¢|§NqÏÑw& ¼:+,í^q6mL8B¯yT‘6åæµ!Ó…ù5¦kšv]¼ÎáTu…J?èM]q8mwXŽTê’&?_OZž\¦Þ•RúptÊcˆÉ…<°,œÐÇÅÁÞãbå’µ\)¿ðL‡Fæ÷}édzÙQ~p­±CøÙiÏ‘ ü]³w˜¶¤„hW¥ß[Xáš±|FÅõÐA;Dwžzg hVs7TsG@é„×>A«ŒÒ$ +£‹V/#Àüå¼’Ÿ£6`ÝvêmA]¦N©WëÇ6xVv±^yq•Ý7£ü†q幨PÛl×£8†¸nC…PH(¢ØRŽ•sö²Mžm¼/a>ë³Y+÷ŽÁ­õ8´­ÄQâð¦<0"@™7u¦… 3´š7R¦–«õhýšÏ‚Ê[˜ßð.ü‚NÛ m´ÂÔšÛ¸žiÒ¥Eèíòìú´.Ói3óòªxKfè·ˆòÏlˆ3Sƒ8Æœ=.|8½<‰ÕÿÆ]Óõ©A([™‚:ŽVñqu)½Ò(T¼B¯a@ïÊ&o(›è³«¸©XáriŒÞy x x d”€N,ÍŠèŸù왌ْJPS-.…Ó¶Æ%§K‹£Oî“¥Ÿ$€‹ÜY½ßhúá‘? ”nVüEùÆÄX'Ç(ý1 %J%+GØñpÜ£…+‚"'÷Ýý¿Kr‘¬t‡J>ŸŽ°Ôh³›y W¸“ô8§À/FÈ Ê¤ª\'J¯*µF1å^qFŽ(½ªÀršÒj9®‚-éFQ£ÜF”]-ÏJS]”c£<‡Š2èµL…Z†Å¯”¡Š<ÒÛ°´”úH»:´­ ËÇÆ—¦4ÈÃõI™Ê%ÛcËKÛ¢íœ<ÌxûÐ\ÒŸèj÷Æyç%à%Pz À¶è]Â%€¹Ü4ΧgÏKÀKÀK $€Â ŠæÉæ{ ߣ¥k—RÏŽ=KÂJ!+ÁabÙ8žÚgC–hšÉ‹&'š¿tÌýìÄŸÑÌ/fÒï?!Ïæ¯ {à¡ü0DföŠÙtü§g~ø á ¹¸ë¿{=}4ÿ#š8sbP&¶ÿ7 æQâü'õòõ!|Aáµ~àìp€)í¯Í‡Ö¬8ŽË\¼ãµU` àtYQ†am4gèkj,ƒ Ä+Æ8"´È‡× €G™ˆãë! #;ö8IäcC„]gñ+Iv\Àv„—þÑ4…&MèA£J2Ò5ÍŒ%)ÃN×2 ŒäÍ6 u |v‘ü@|„7!1ì´ +4éR¦âá4o«ÿM…¯§(o×íܸ–„pÒùK‚Œ¶PôÒÞB›_!Íæ +y`UË6›•Ê·ÝöðH¸ÌıŽgõÏL«Ì]úÍÑ.{Rl‡#„•™³r-Y³¤²˜6ÜB¡¹óœ;i×mv WåØp›Iw¨LaõÚ¬~¾üs:á–hÙše9µ½e‹–r(`ŸN}¤N¼÷.J®ªØ†Ðð ¼D*Ó´²Ä‘¸q¬c¡È3TÛ9êês¸m¯Rc…Û^97«àáê¸YùŽÐz]…¡Y!c¥ß^Aוu»nÅYPVê]žtµÞÀÈj~[n¼]†î°pšò—¦<ÛòÒ] J[±4ˆ•}´EWö‘n¯îÃ0£^ûq–×ø:ið*€ö1“6pqc¢QDÆv³N®„¶¤áHï’+\ªÞ•R¸ôšˆ ÛiàËŽsX”iÍg§)­æÃü¼¼ühÒc€§™¸ŠCø©OŸÒhEÁ›66äWÇ.Rì°R*®’ iË«³^ÕVTlߺ=»tumÝ5x?ßz_”pô»Ð Š+QŸ~ñ)tÛI´zÃê€(Ë_9ð²q¬ò~oû >‹ <@ ¼.¼`V½ÃñÞ€+÷˜Ñv»|_øü…RÕV”zpªÿ=çßÙr¥['Ãúü‹¬fCÙb¥ìÃEÒ¨?¢ ›2ô¹ÃùžÛïIó‡`ç´~9@ÏFñ>tBn—§“uWް¹n#U+Ž¡*˜¢tªRªJ++«±;Œ²,в¥ˆ7P¾YO»*¯J7 ½R¯xUäM9aY.­oÀ‡–hø½گJ¾¡EÛÔK£ü«8‘ è\ƒhÕ8ÀP}ÐXòmæ45ˆ¢oö‡|ð\Tè9ØÀÙé—Ú%eÌ—ºÝ¹Ô'£8\.ezÚÄI—«wå”@#/*<ÐurQNö ]·ß2Th‰úò¼š¨ìÉ£†Íä²zs5=7ý¹Škxu-/ëæèD¹Ì1OYɵ¯˜‰—f½DU5Uee'ßÊßýpºò¨+ërœÈ¯Ê·>߹ͺºªJ©·ç¾M£oM«cv~¤aìôƒN§Ó‡ŸÖ‰/ˆ!ÐÔ_‡ºm´ÆF˜d®i(•ªtŠ 1{Åêtœ!Š2”Z]%7Jµ(ݪhÅ=TÄmÝ¤É »·ó­ùn:Ç#õ Òh~UÁÐåß^ÝW%_Ú£FUàM<¥¢Õ|¥…±23«þ*?“v\}ä5ÛøeübWÿ‡òGX=8M³a¢&ŒÐë?U3¥§Ê§ø|ók9¥€•Äk)ä‘€:¼ Ѐ….”$ŠÁ[R 7én0È<ÂK iI ¼&y²‰ðÓŸ>]q \³ž?è:<+ñ&âÖlZSñ»Ð?ù3>hx¸¯J8Và#ÏAŒMUÂŒâ:áó tÆ_Ï M5›rêÕ›O»™†m7LêÔ]!„u¨;b+Èa¾›¿ÐHw¼kùЇ ¡”BŽ˜ÁÆŒ’*¾¬$‡ÆKÁo §'ç7PÚU‰T¥^zÅiœaå^ë°¡†AŸj54ðPâêJ¾BÁCQ‡w}Uö-Edfä'y±šo)û¡b®6âµOlèÒ ž¯+ÃØŒ\¯ùò¿¥æç~KÊ\}Kí‚lÚKÛ» —nXI»i%Ÿ ïbϾ—€—@: èdS'«L‹íåkªbêtå”9­®{¶³tÚf%wãŠO*4ü>òá#Iå0k¾Z4oA÷\xukÛ­~%Þ}÷^Kãvc5UWb¡|=7õ9:ÿïçSm¶dçÚ¶jKc/KÝÛu5„»Ìk0ÈsJ•«X¹ñìX(.Ƈ#aEŠ3PŒ~F‰m`0Êp¨(ÛJ´Q¶E‘W¥é+T¼*þWhÓ!¬ñh+÷‘U|ЪҮa†Â³µmc%Tô•F(ù©}Md9‰¢CAœ²¯rtdÊ^nºÆ5ÝÃäH Ø×u±ËOŽ$›$'Øä]I%ÀW .|‚7N8¹ˆ8Ÿ· ÌŠ LzÆQ’ð ÜÅ…Hp ~"y"‘¤ù!Òð®`È%­K“›ƒŒ­Ã¡k@㤃Ç46ã1ôv²{ x Fö¥&aþá[[UÍFzvÚ³4zÑ…©§¥¬^‡CáÐÜ›áLXÛ¥(Lƒ{Ò\ô¤9i3¥¼"Àÿã?{ž¾äÏ6n]Ÿm´EÜ»[oºãœ;è”?}WšÈ‹©4Mn†G3ºÕxÄE$-ðÜ&ú7R°Ãíéö3î•XFetýzô£»Ï¿›N¾uÕÕÔ…õ¡À`>ÀŸä1åQDŽÏä9  ZÓ"ñ G2~EPñ¬ )høfi t „<ìÃtBÌ @„Å@ÎI@8u‘ˆ"(Gq”-_[ÎÊg+æ¹æ‰)Eø„òiiçs’4*0[ºH¦Fì>ɶØLyrNw28ÑlÙév¸!# ‘W†âb!#-¼ u+.i@Æá´ HÓtà4.4¦a\˜fá4ÍÃ’J·JïÊ%"Œ<ôñWNרúý®röš¯ÛK ò%N e"ÝŒþýñÕ¨šZ%3ëŽAUTÃÀ¬Õ†PAa\ÍæºÒל8†Ùë:ë ³Ñ(^•g ݂ϻ":%dÁ^ŒfJúØ·ÇÒþQ\Ñ)q‡ívýôøk‚\ßfhÔWвËÓƒpÒ_Þ©BÊ65H0òJ‰7²Ô-섘ݚ•ï`åm­žË*;ÒÍJ{3†ÍxILÓ{ù(+ôhç±=_TOCd¯òSȨˆS¼ #D>’qj]Èë©eåÒu‘•ɇ˥L¥-W›´~#ð;"â(~¤U‹Ö´©nSðÆÍÖ8Ýk#òTx;M•p~$ëÒ•›! ¤Ö›i·ý ‘’&EB:œKãÆÁ[®žg^yÉ@QOëC^^…’€¬âæÆßWø3sø@—¶] U|QËY·q]¤|ÜcÂ;8Oðí{ŽÜ¿ÃÄH¶dG„qsÿD˜ý=ïÞCßþ}jÍÏÇJw¿ýÞoé¥^¢¹+çrÛ¸Ïx¹9تν‡Á‰6Ãj˜Áó¢ýuÂߨ}ëô«‘¿²l~~tüè­oÑ‹Ÿ¾Èer=Z/*0u„|`%œwHÒLPê±Ã‚HØiKäB‹Š·Ùe€n3ï°éѾÐ[™€ƒSè„Ñ7‘¹”•Uòe‹¶i5¬…™pÊú,ÚØ2…¡4?Vþ4T>‰%Ðçpá˜IÑÃqéq¸Ù#—ÒDò›HË–°’yWN À6ØÔ\d¬%­qÍ›—V丕ê&Vªz’Ö§ž//H[ö2q6áªÚ*zzjåXµÉ:ß´¡d··Ó’V¾~±ö zôÃG“ÌmÖ¼uhÛî<÷NjVËJ=vàµ~õP¾u†‚öÃcJÀ^ßçÆJñ-/ÞB7=}'dç``¸û‚»©O—>¼û€«ÀÙ`ÂZ? 9@ž×Ê‹]MÎNOBXeçò¢xÈÔÈVw( WÑuÅ´áʺFºñè ‡;âò(Î.SëÑ4 FVðu5ŸûRΈ@êM[$®m´!“6pvºn@èe‘@¾×Y¾ùómtžõãÜ”„»<[˜ðÖ1{¸½4i‡måIò±Ânì0Ë!öòÀe ?d!ÊÎfû±øÏ¯õ>·—€—@Y%€É­ëÌ„“þ'>©œ×"·Méâ:ÁOG“¤4æ74Ô€/Žß2᪩ƒÖZùîÀ]¤ïìû@ ‡Bn òi>×`)‹¢hò¼ð7ÿý ÝõÒ]Y £{§îtÿÅ÷S+ìE7uF^`å?R?ó!Ï]Ì#ܹ„Ïš‹ê¸t¦A¾eZ  c•KIoLº¶§ ½ ‚Qòm^•_Å)tÛ‡¸¦ÅÁ8ú¦ŽKÒ¸-7/Ũ¿±e¦È—$Ý,¤©]>¸ÕxWÉHqa¥j’*ë…P¦µ¬Tuy¼—€—€—@É%€É0 ?á^å×–®Y*¨¤ÿlØ´!=‹Ú¶ôT•‘j)-PÆf~5“ûð±Êà= .wêï¨S«Náj|hÀû´xn›g7Ú®cãÕ6\ýøÕtÿë÷gQ[@òAßW´.ì<Ðpš]!?YW–4BOq|i *Ø€7t(å–b»2ï*òvÜÉ/u˜òC%]ã€6?v8ï6-ÂMٙ룠M,F™e°Ä…å"\hKÜ _]ã$€[QÒvEê!UàfSÒzç%à%à%( Ød0ÆñZ>íñO›©˜Iù-ø¦:Ù·û‹Ã׿x=m¬Þ˜J<…ïѹýdÄOdû¿*ß ^0QU>uµYˆÿàáÐãïf?~/9ò:þkLJ»ÂWÔ€•ìH@Ýî.û±n‡+IòΘŠeÝ¥±•s »4v\i\hÓ¸áXFéÒ¹ñTù<¾ð¨Ô1_ IÄ­‚Çá Q> QPrʨ¸ÑƒÛW“rrÉëi³ï_/+/«&;œû^3ë°5L4þõá¿@‘x·výÚ@!p9ÅýN¡†+í¾©|²“~ ‚Òî«Ðí¯ß®˜Š‡u!m·ÕvÑW¬WôT~i(+~ák<3Ó3êšÕÑ÷_@ÏOy>+y`¼ßuÎ]Ô¿kÿÀ`ÎÏÀ[0˜/H˜¿R{oÈaþ›? ã3NjÙð—Oqùæ×r³)ËÓ$_N…¼V YVº±c?·N;MˈÃiš ]:Äá@ǰuËdøêêŠWnž›ào“3$½"cʾ`ì°Ýˆ&?íÆú°—€—€—@$€U48³šöÁâhúÒé.Á¿uu˜…¥v‘Um£M‡³Ó“6ýƒ~’¶ñŒä¶ ·Ñk¾H§â§M«6tÍÈà}ªp‹Á›pUþeN Ïy£ø«ò/‘«æ¿Óï9&NŸ˜Ûw¦±—¥6ÍÚÔï@PÅ_&ÄPSÏõ‡|(/Z“W|%CkÜé=¢à°’åãyO¶Ê}MÆÕ‡K¶·x ý ªÌ]ÞJ?}‘îbAûˆ±|§ËcÚÕ Á‡À*# Ûø3ò2î^^^YH@•`r¸N™_µnUÃÚÊŠ¦jÛ4^ÉPÛ‡Ù‡×V¯¥ßŽÿm%·(Âûwü.mß}ûúUwUÄ±ê® ¸æ°d¡Ê¿¼ÀF€ué»ù.Mž3Y©ÓÂ=úïA7~ïÆèJ¿FhCÌ ”„Õ§-Ý'z 4m 4˜ãº(”+dYq<¥(?Ò¦4qÅe‹‹”Ÿ*“©·>ùšh]2•xsÁ79+”EÖ¹ˆ4=mËf-*öš%†s4'«‹JËHcÊOGÞ -ßü ÌQ0d_eÞ”²3ïR|^^YIÊ“:Ëõg”JêõÐQÝæd?Ókk±4ÌÎnK€iø› MÃ\ÉÁ€í' s?áµq“ÇѤy“’Ãkœ´lÑ’.?îòxEÜl½L[ Œ[| ò0_ÀççÖT¯¡QwŒ¢© §fÅÑÙŸMßÙ‡¿F€-ÿPú­×$ΗƒÂpÑÏyõZKŸýÊ‚‡[*}¼•Šÿ|ë±òGîAf¨Åár…Vùv>”›ôÏ2)¸·[RÙáJ6Äv÷ìë¡KZbK 8åsR;ްzsí¶(>Ú0¯K“)Ý¥/rÜ¿ûômÊþ*²ü}½^þMz èýݢՋ蕯‘„þ®Û°.zïŸÙܲ¥Ë¦¬bÓ¸¼"î8ÜxÉ¿.¡ªš*'¥2£cC½:ö#€¾‹¯0ÕÁ€ÒRž¡‰°E` X¾~9üóHšµtVVÂøÓY¢Á=§?@_ €¡ )ŸPì±íËÏî~ÕÔåä^™Im/øŒãMñ A£aÕWÜ|šnã]œÆ¶kݱÄ8WWäxD—L £d¤R :ˆ‚ß¡ÄðL¬kÕœ¿Ñ›‡ ö¤h~ tVÕå“7« ŠH”‚÷JÜ5PD)ù¢½¶ `P=?íþ9ùŸ‚NêOìgµ-`ZÛ¢ °â‘Gv¥M"4|ÊûÿÚÌJØO[6nS¹Î™'Lv/>æâà0@]ÇL…½žÈøµtȲРy'À¢5‹è¤?ŸD W,Tê”°}›ö4öÒ±Ô®%O¸QŸ}øŸ*þ†]ŒyqŸ­nÁK Äh*c³Ðíȧ¼òº t¦ÞÇΨ$»4º$¤’ƒd’ÛJ<^š”ãAˆGYèr”aÆ"Z¶ÌsЛa—ÖP$Þ YlÒú¥móey x ”I¶âËáðTu„ùtô§§=M+Ö¯(sé«­­«¥MÕ›%ß%µÛå¦Uzm³¼¬x£¿xûûm¯ÝFSL©ô ÿg~¶(á¢ðãMÝŽo+ßvK!DdÃaý4 ž 0û«Ù4òO#iÙšev®ØðÐ>Cé§þ14@„u«1B!æ†yF7™©n¬X£ƒú°Í_•~…àÃ>˜|Ø^k°øS”‡^^YJ ×O¨'Y¼…¸,›!³ÊI…ÇΤ$9·½®.™$^ ÅKR ©†K6íÔ¼¹ñHM¬kݼ8ß¾Lkˆ“†J-. ¸Lé©òew/´,²$’D&g‰äÌ3å%à% «Êîöòû'ÝŸHá¬[Ïïÿ«K¥ 3¾"·úk»â ÚŠvñ°Ïpøþ~´ø#ºá¹ârVîœ#Ï©W¼ñ†©¥|‹!@ß¿·ZˆlRÞ_ð>rç)ûúˆU‚8`@÷õ»´~ÌšŒÏ€Aç`a. žƒâ4˜tgóÚ˜pÒÛ×ÔøKÀ˜j°è”OùämLßfª/Szº:óÉë”›ôWøÞs,œ¶Za€m¿I14V” :„­6‘¥‚¤)›­[¥14hM¼XÜœ,²œ VÞR“ÖÙ¶92éÎ6“§óð(½XqŒ8ć"õñ’éÝyïFH’Y_µ>àÓbF?ĵ VZÅÝ~ÒvbV‚4@ö8üîÖWo¥ ŸMEE»oîüMÂv|Q¶¡`[ïà‡«ï˜¸s–‡¼#ûÈNŽOœ5‘θû ÚTï¤qXu{äòGH",¥?4D¨|aúgpyS~]˜†¢$¹õk<ßÊ´æ[®Ïï%àJc¬]Êy}šö´iiDOH{Ý6¸º¤a3M‹Ò6¤±ùÒšo"±MÊmÚ´i£Ý ¤ Ø¡u›½¢…1˜Ý[Y ‡eVü8L¦3v8¤‰ŒzÃA"»Å3µ¥I@hÿñÎ?' U¢¥<¡Ž­­Aoµ$ö",‹(·XeçÂ^xÈ…_Oë%à%Ð$ Š¥hOÜÄù©÷ÄÇOÐÊ +ÕÀ5ëÖäÆÚÒ]h°^ìX²n óÀ9„Ã+Ù>2P@UáÛÕvfÇø\aÝðè{ÒUÿ¼ÊÎ>yß“é'Çý$j0_Pc@¸+¼€W5¸ÆÌcT¡Öš5·‰0`§§¢‰dˆ‰Øe¸ÉvxÒ¸áO 2/B;loæJŠ‹´)›öi]€Þy x ˆ¹¿^F.ÚtJ”„\]±ººÚz'/–U§EšŠ¸ äy$}¤Á‰@Hî4&/Á±Õ&r’’Û©a²y:¶a·PV¶Ñrë6O¹P´õÀC4xð¨™ÆÐ‡ù31¦ô¨†t2yÀ{–%vá  õŠœÒåSyÅФÊÇK› ªŒ£sYqËvÓ}ÜKÀK Ð{ƒöu¸¡f=4é!ºhøEE¨¸qEÊ+Ì+øÄ½_ï-Í6›0Ú¡mBnf§7ŽÒçŠáYú *ö››3?_ñ*ýæ¿¿¡_ÿ‹ÒóY ûnÝ—ö¼/½9ãÍàT~<ß‚­;BánŒ‰yÈÃbA:^ ±‚8ÿÝ3ñêÚ¡+]7⺴_{âµtÕ±WÑÆê´rýJZºz)-[·Œ®ZH³¾šúÙ«f3{Ì æ"Ê×öj^@PDõ×$kmˆ87ÝNti5ñí[µ§}ûîK»õÜuD;vÛ‘ztèA[u$캬ã×y×W¯¿tíÒ°m3—Ϥ@³WÌÛ Å2‘öÉ8™“) MšäÓ›W›NÓ=Œ—€-·xŠxl¦|9¦KßÛ5¥ËŸ. eØévØ._ù¦»ôˆÇáP>ã¥]šnC„­¸ÞO§x\ÿJÇPŸOr_pñVU#_HoÒ’¾`ãÆ™ Ò´4?h©ëâp.MÉâå6dj¨ K¡M‡£õë×G–Q’fˆµz¡%ù>$2•a¤eߨÔð` µÐáð¢oDÁ6¯Èî³x x x ÷V½?Å ’»ßº›.ØÿjÞ Èò»¯X,…÷j<'ò}VXå&5ˆöŠâÏý¤alßÜb3Ýòò-ô¯‡†nËïÒW¨uÀ(zsú›b˜oVË eŸw`§ƒ;Ø`/ÛýÍs;l¦ö?&ãx €ÿðœD>&þûçOÝ:v£K»$ÌhÛª-ÁoÕ~+Ðc@‰pnÆGK>¢( ó'K?¡š:>ÅPÇ¢áKžÙëõ†þ‘Ò)5)ήÕm¯æ„{¶ïI#wIÇ 9Žöê½µjžþ³b:÷Ú¾ëö´ÏvûDJƒQ`✉ôâç/Ò³ÓŸ¥•­ÝAàÓø°}‡ñMœan\Ûäâà >h hÿ5†É|ò6¦¾\ó€¿RðSG—¶]r嶨ô®®ÈºdæO«Ôs¤-TXŸ’àPÒ ©Dg YÀ›×°³3ñAv´ìaÙŽ ´"ÕƒBÓ¦+'‹4[9'˜YäˆÄ.;zOã%à%à%P4 ð=UV˱bŠ0+˜³VÌ¢Wf¼B‡>´hÕæRðú‘·×R?â Å3#Õs#Ž>I8ðgœÛc°‘¾cå_ +Ç V.¨hÀ‰ÃO¤«îæ­úPäÙc‡^³:n¼‰ „LW£•Ê8¤ÙF^hàíì×9*ÍHä¸(Πqç1šO ùÿì} EÕÿ é½B$!B  R¤(E:HùP@¿ ‚EüáC@$ˆt&(-$t @z !!Ô$Þóþó›;¿ygçîî½÷½ûîÝ—ì$ûΙsΜ9sfîîœÙÙÝä?Û¬¹œ¼ÍÉòu¾#mÛT!­Öm5Ùo£ýìON>õáSòÏ·þ)÷ü÷™½Èİö9Üî¾p4ß&m åIKãäç0°ãµ–p|$ÕÝ\~œÞÍÝcÊûjÒxF¨{§l=ÆŠ.–D+Ø ‰ûæ¶F$Ë å8˜2„2kÖ,µtkÖÍ@Eº…{Ñ®Bc;¾¿¨›«„¹Xû!†‹ZcW—]³(˜æ®*šá°œRLÒ JŠþZ9Õ`6eA ú~Ví(²ØRE˜ðwQ håÈ@G¬\¨<вó|îÜ-ãþô<$bª3‹W=ueffÏÅ ØÇ“5¡#ƒî®6à€,Äõa²­2¡ AÂZá ·xƒkçs¾¤[W¶ïþ²ÉMäÕ^1;LÓpŸŸ48v>ø—ý!o}ûä|¤†„ÅÑl”‡¯ÌذÐ.”ò?¾ééÙ¥§ì±ÉLLþï~ánY¸t¡ì·Õ¾Ò¹Cú7ºq#cça;ÛJQî…)/Èãï“qïì° ö"mÂÆ€µý `Ê:QOGÞÙÜÜå?§ó囃¾I‰íÛ¶—†ídßîú[¹ëÕ;eÌÆÈkŸ¾V˜9Û­}®]~1À6ÇþInú)loºrÿ¥o*õB©rñá [dZ?Eš¯ñ¢JYòuâ„¡Œ¥›?äjò!ó[,6’§!bä‘4å4ÍÊ8y£¯G§öœeËfàO¸Ä’º•¥¬¥l)¹ºóyZ®»!Õ2àË/¿,Z¨–îjèéÙ±°íkËÍ/§èøö)„ˆ@IDATejNq´jètжJ`«ol{5•ÖI—äÔ©î¼ÚܹŒ8ÙôGyüƒÇå½/ßË„‹.¾ ­ò6k¢ÃÙ¶V«!ŵÁÐìB4xrñUÜñ6Ç;_¾Ójš–dèî[îfƒ{{' fRl¿<É6pL¢òz8ŸxhýBÿ8hnï,[e¹5æHÿöxS(9áùýGíoëYïÔõäg7ÿT^™21¹@ÀéÔ®“ì°öòë]Ï—§O|FÞ8åM¹ä{—Êw‡í*WéTXÜ@y ]ç ÷ í5<´Óù¡W‡^rÅWÈØŒmñàßÔI]ÌBȶ:Rž<ñ)yôGÉnÃw/ôy\£mÁ¢n“ë·Æ¾3|´…ýgPŸ’è^`%Câ|”u4Çææ”Íš_t[4îìŒ!I¯Î½2ÕŠp Œ%3el•Œim GqcÉ»cÊ”)3}Æ a§j^=p<÷²Ü÷®!®5l!lŽÅ{¸2›]ÙÍ•£žªC£°ê:›jsŠ-…E• ÙÚÔ6æå²3Þò¾hÝ}  Ï–ˆ»®ž–›[¦×>{­ÉÔ?Í7ŸĹ‰FZ{ äbÿ£-N¾ÕCÝàôf™tÆ$ùëè¿Ê^#ö’NØÀ»çšvã}?ÿÆÏåžC é5Ô–»Éš›È­?¸Õì xRvY{» }×à>£èw ÿ° €›7XÁ û34;Ÿö„)/_Êo¥øiµ4§lšÞWªžæòÃú*ɳnB– ó¤‡0F缟$K)Œ],Ië‰WbvSÊT¢¿Y²¸ld%¥9ªlç/Z´È,ºâl›ÝÔ©ƒ¹ð±E„0—xcxvË›ʇù°|x! åó|r_ä¾É}“Ö9p4©ðü¼ÃM…Oþõ¹¿uü;oA_ÂØCÒcPç5®eZ ®í'Ȥ‚Þ9‹æÈÁ×,ÓçN'·UAÜußnÃí¢?FLÚÀØ\§‰û\»ƒëwä3Ìèà#>.á fÌŸ!ß¿üû2í«i‰~Z´d‘ V·_{yèô‡¤_§~Ò°¸AæÏ›/·>y«ìöûÝdËs·”ËÇ^._Îù2QO[ê÷¹ŸÜtèM2é—“äÚý¯µ/ó[e¹1÷jÌÑnY;¹zï«åœÎ©û]ÿ¤v€>rÍ‘r÷ÿÜ-wu· ë9¬°`ìBÚ²ÄjaÃ?æû1èKOo-¿×jÙú¡Zz+ÔcC‡ ËDÎÅM-k†D$5UÊ!•*ú;©Œ¦G u¨ÅtÊÅð;wìLj&!bHÄ’e¶4,~&S–´ƒè0BÍKÂ}'˜Ï9Dnûgm= gg÷ù‹R­#ŸÐ´<¼;޶ñðŽQòž–€„úÄjFΚ=¥Þ”—%–Ò™ós䨢p‡T'äõa®‚W?{µ,X’ò ¾.ßBøüEó wtSô¯tç×OþN7ò¦¿x—ßo?쯇É⥋S¼–]Öö#·ƒ˜rò@ ˆk9ò€q×uíÌæ×;Ì{è+Ð?™ý‰ì}ùÞ‚·þÇ¥Î:ËÔéS-k³¡›ÉØ_•A½5·Kä©ïÈ¯îø•¬÷‹õäˆkޱ¯µ;âô¥Ñ°pÀ¦ÈGÞ)ïœþŽ\¸û…æE›ËM‡Ü$orpZÑLñv±‹ªû3®_ãh™junL³ƈ.†Ô–W‚S–P{%SxÊqKˆ27ÏrDnå˜å謙L¯./¿Hý‘•cZ­”Ñyï•r”2Í)¨*•­(ø/¥,…þÐSDsVîÜ+¢,!PRÇ¥O\*øx½Ò¬y³’«¦É+í }hf.üTàß_þ»üñÑ?†%2Ÿ1xDá=æZ«ƒ¿ t(Zˆk2hö"4ÏøÅ/’ÐG楀vÀþz'À‹S^”¯<0qçĨá£ä_þe+Ôo­t郲–SŸ‘Ñç,iUõÂÃqÉ’Èv@ÝBâ„õ2¹*õ¶¦€$‡‡t<»YÚ;·*žk†û)@®ü¢Àõ¡iÀu^Ë…x(Ç uO:a¨'ÏGû#÷Gî| ´Î1Àsžî?žÍ©;t¦|5Enp«ÉÕ'-XhÖ­a“I~ÇËûs?ÛBÝ®G{Í—ÃÑGÖQgÁaòëþZî}é^On öo¬ÿȳâöÅq|F\£y õ5Ûù†w“õ;.àýø„^4ÿÎx9þúãíÛÿ!§S»¶ídÃÁÊÃ/=lÉýzô“‡ÏyX¶±}!èÇ ï`›:°0°lÉ2ydâ#rø‡ >'xö]gË{Ÿeã3›º}-‰ÃßG}ã(yöÔge›ÛvN`Oª9°‹B鸞ÿì¢ û—PÿŽukúÊŽ—òK)~šÿšS6Mo¥<þ¾ Ãò¤†<æÙ° è,ˆÄ²€¡|M—ޤuZï.½ ôŒü cDCÒ´2Ì—¢“ŸY˜…€$§Âià…|Òé\Ÿ_¸paäVJع,P/Øâ«_¡ÇÐPz'ŽW/G¸zõÊ`Y¦d° eÙ åÈ=Pàî¨9lípn+¿äñKêvçïHM°‰°+ü£i~kÄãÚ½ À~þ®AŽ¿ùxyñÃ[Uk·¾EãõÙLŽõNÞý\¿yý#dké/ýNÌðà'ìÀcÜ €Ç̧ï|éN9õÖS©!‡ö*3çÌ”ñÿoéÝ:w“{ϺWöÜrOØmìæ³}‘@ÁÙ»¿üúK¹ìËd‹³¶Ý.ÚMnîvY°8²93Rߊ–ÒoˆqBm¿Õ1cÆŒÈ÷iÂï;êõÀñ›HŠk l‹˜©ŒÑ—úƒ­B•q*Pg=ê³%§åÈ=°’y€Á$Vˆã“iæŠxñ¸‹eiôC25qÎìùfݶ¤%Í×xZ™Ö΋ig¸€~ãîÏç~.û_±¿Ì[TÆg3àì°Á:ƒg7°`€[l6t{ýŒ¹žû1düæýÿ˜Ã.hÜíøýƒ¿—Þ!Ö}‘wÅqòÁ§X>‚ÚkNºF~²çO ‹°;` ¥É. ¨5iö‚Ùr͸kä›ç|S¶;o;yéÂ_!ÑQk’gÏxVö¹á1<âáïHÚ à}ãSÏ[!½•7ª&(ü$ ¿ÙjTH}¡®˜ñÛ¿GÿPª®ù0FT1dØ*Ýò4­®í¨´r\ ZS¢ÃµÍÚù–?uêÔȇnÍ ´|ÝñÕ{¬Þø£c‹Ø @Nh)y #1¯a]ˤà¼HëIGl=):Ê•oVôMì(×^ÊÙg+ëP/ëÏaÂØÏû$þœû¥´_pÞÔÉMØpëjÿ.€9sç4^´MèG$ÝŸa>NF˯(¸u„ûƒ…·8 ŸmG ûægoÊ1×û|»V‘¼g·ž2la…þÅõÍþÎ06/¢ï¸U8¯!Ô}lĘ";ϰ(€….<€·è……+Ç])oò6‹yا{¹àÈgï!Óf¦VXXøýQ¿—ó>¯Ømqhs8¯ÿøÜàðÃ}=+:Ò£s¹þ®—+¹Rº¶éZØ €©©9컂÷>` Ø…7&|¿Ó§€š¶²àÍm{Zù4^½ü[-›ðCKjyº.ÒP†tÒ˜)N<ʸFÏ5( ƈ*†TVû­)Ùê()XkÖ°:/ÌÓg¤7¼ôÒK“I ;WóêÛ€˜Šunq¬ª3)”¤²a…e ÷æÿ–]OŠ`£¶ IÑ™³räÈ=P‘\ÀhË0x4ÁŒ $U@tɸKj¾ ÀîˆiŒ¿‹KÛ !«ñ˜²+ I·¸9Â-îvúÐmuè‡ìKèZƒ6ºQñÖo7¹.º»ŽKh9—Qç'ë+ŒqÌö@ã8wïàΉ©_Oµï¿ÿÖø"—í¶Ån²Ëæ»È¾çï+ÓgO÷ü_ìÿ ¹ü‡—KÛ6PŸ0~}_™ú‰ü̓¥{çl}<¾Õ¥ñÍ#äÉÓž”MVßľ À.ö¸—)ú…VÆö¿6©œ± å³‚·´ÝèÇü´&©%«iŽîj•-SÏš½Ö¬‰»Ë­$Œ] ÉÖ†êBz˜å3—Ç%!‹ ŽÔÎ$NÚ¬åÞzë­¯uùðùްp­óÝ:t“Ží;Fž‘ãªxhKꢀNòŒ–i"®ƒwâ娢lÕN®-ØÆrÚS ;ù©†¢\GîÜÍ÷¢ð0WÅÉ_M–›ž¿©ùúËÔ0wÁÜBXJ¶†)Žʬˆù ßümØ^1î óï1™o=8ãñw}9«a0ˆ¼ÆÉ×­ Ç‚ò‘]HÂŒÏ\(!üxÖDzáÀ åÇ7üX^ü øEŠxUŒ¾`´èVûÝc废\'íÛ¶/´×iUwøƒ-»o¶»¶|¥Â×°®<ö‹ÇäÇÛÿXÚ,mSx) ^ÀŽîúÀ"@þ‚À쌎ï8‹ÒxqòšÖœ²ZO§?ŽVnùrÊRFAÄ>Ý;fká/ˆÃÖ³¡wH'?M>,_×|VJ9…&¤¼Ï›7ÿãôé“ °}®þHâ—Ф¨ŽÕZ+ri”:!©q]2‰®elñF’° HM²U[l¨ÀZ;±ª@>Í={ Žƒ$˜Â`Å\¹-úÂG.”¹‹æÖÄPÿ@mmJ²@ÉF=©h«§;ߨs/pµn{;ƒZ¼éþô;O—¸»ÚYòÁúk­_¸&ëŸz¶ž7 ü\Æ\«c¯waÿ;_aŒ-(}>ïs»`‹µ·®8@&}>)â"|àš“¯±/<àwÈâ¥ø¶]!ð­äÎÓî”®»’d¡—ÊþÖ6´qDveËtl×Q~Àïå–co‘ží{v¸Ï+úªE,þؾ×c$tZ™ó·°XÍó­ÅΚ;&¡Â¦øK•‰œ'=6ÐüsbÉ,G+$Ò«[¯N}Èþ|êªW±#Z¢[ÃiZ–üóR‡…dXa÷M«'îß‚‰“9’no…¢“o`8)Àæ=v@S^_,H«&•O¢W¢»ÙZ×W‰m¹lãøÍ}‘û¢5{òEüDM&‹—É]öØeN¢eÁœùæù$øŽ‰~DžôÆüÊ釠­‘¾SA®]03œ% KäЫÍô÷è7\{ÃÂÝ}\çܵÎï M_‰“ø®òs ðT²þÒ¹Z<ùø«eÛõ¶•éó§Ë¾ÜW¦ÍŒ¼NI¶Ý`[9éû'ɯ=!G^rdä »l²‹ÜæýbonÐÖ«^®î>Ýú»RÃ=7ÝSž9óÙrà–þ}öfG€}A °;Щã~çØ`ä0ú[(壖ò_µôÆé-Ž®ûÞˆDÎ )<CÄ•µ0Y¤“eQ’³/k¿{ÛÖ‚…ö¯‹i5½D‰¤¼–ײq8iu‡YY€#è@:%Ìkºæ×yÈ5˜ï8ºU¡X°Å£@¬ãßU{4~ €e™¶ØÂJŸ_íK‰è§ a„™gräÈ=°z@$lž Šx§ôOãÿ$ŠZ:Íæ—kC»˜¡1(ø¶´YÔ¯ú‹w•¹€;æ,ž#£ÿo´LŸÓøüz–š´ökKûvf =®ÅåLæ­°ûwý昡\‚¿¸ãï˜úÕTùֺ߲ïQ˜4c’ìÿÇý%|7ʇ+ë^_îá~9áÊ 7\£†’GÎyDôÀZ1P Ð-6€¶dY¶^ÎÜhpí±Á}Ë#§>"'}û¤Â#KÌ,Î6àÇçp1È3sÆ¢ M›ñ7&´L½ðjØUJG)¾j»Ÿ/+ZÍÑ ì­Ø6ê&¤‚0:ÆX\Ò²“¡éGÇ>1¢5'…±á¢E‹;†­D^Ó¼¶[Ëæµl]ñz.¤9…<@kg‘ çÏŸÿ•ÆgxÒÌ,ú 66Äéž’·m4®ËÄÉ-ÅβXMhYzë$´ÒOÜëä÷¼Úܱp‘¿3Ê Å@|Wþü[¬šÄÙsc>¨'¿ÕÝTjñjVÞštÑ'´™}¾äŽß¼wŸ¹?œù¡qõ‘­ëTSoØ®m;:`hcPÌjRï¸éë£ÆÑ¨Rþrc}µ«É5‡^##Œ Vß@úöèkƒõ7>yC¹âY´d‘wQ§ödÌÿc,nyâ9íúÓ<Ȇƒ6”GÏyT†®6´‘îúI/Ô|òÕ'ü³ïPøÝ¿“¿ÿwéÓÑìŽÀÝ~<àvØ"‹E¡Ãñòó|eHóg¯²Z¢Ò-¥7ZKc®)õUP¦Ïþ™ŠÅÂOΛ7±#Z”v4ú+£Ò„ZŽx258ý×;Uê ȇe4Íò¾úê«/tÃÂNÖ¼zàkôPŸÁЭ!n ^5+jqšÑÔád Ëj1 à§©ª;¯[WˆÅŽº;<7 ÷ÀJê Há.€¿¿üw™8eb‹:åë¹xo­Jaà¦X%Ÿ0ä¯Èù¸6û‹w™ã^ øôOËI;)“ÞY{õµý”Ó^ûqíC°Çk `x”Ó’$!7ÿ7¸¹<}òÓrðæË€¬Ûæ0ÿ.Œ'ß~R~ð§D¶ûoºö¦rê~§ÚÚ¯zð*¹àŽ "– øììÇd£Aæå†L´ÃÁ‰µìoŠÕ¶6¸ëÈ]婳ž’-n}$ üT ZðcE ÝhŽMËñÚz %û )º“îôÓ+Z§ÆÉ×PñýX_Ñ5>°÷@]ºîxΘ1ãsg[HœöÆÑÈK‚¡Ž$¹šÑ³° «Jg‘F¨åCœ2 ™¤™ág4¯ø ^ƒ¢CŠ­­Ä˜¸2q4¥“‹Š”]´D[*5<² ¢ ç Ê9š{`eñ´¸9âv4¬Ò gÞ{ftA¶Ê>²;¨3´‹ôj¹·¢çuÛ‰èû43»á"^ˆ]€·ýç6¹ôÁK3ç¡a‡æ¸îápÁ¿ßþmh¼†B®¬ë}„V7ð»Ã¿+ÿ:æ_Ò¿{p|:oïódŸÍ÷)ȹ&> §ÜpŠç9môi²áZæÝ&]xç…ò§þdqþÁ¾‡ÎxHF ER¤î‡ÿûp#=Ç"Ôg<|êÃò£í~dŸÿ·/ä#fÀ ·ãÁŽ Œ$ÂB®8Oz­ahWSêo®Ž´òi¼¦ØZN™zÔgW¥v”+¯å ¾Vßµâj¯-Œ Mè8Ù«y¤ÙFBÈGÒ´%c³¶@÷h’¨J\ËzüÅ_ü@\¼¸ñµš^/|­ÞkWí­W,Ò@®ó¤–JA9Lø¯TÑD~ 3Q.gy   È%9!÷@ý=€àH¼«üìägåöÿÜÞböí@M°‰0Ä-Óñµ é+dû dŸùîq¾‹çÝwžÜÿÒý™òÐÕ‡4^ãݵÕuÈë–ëë¯ÆÁ+#m¹æ–rÃ7H—]Š¤Û­ÒNn8ö9açüøóØùßü¯—íЮƒ\sâ5Y¤3n8CnxüÏÒ«k/¹ÿÔûå;}'BGýãåȬù³"ô<Óè|%àâC.–kºVº¶íZXp‹x) ß à°`dÇ‹[8ŠŒ¨åøi¬bÅÄ*ø-`\vJMã•]AŒ`¨7ÌÇi1R\Ýš¦qC[§ß:äfšgþ#v<÷Üsï- ñ0¯Ëkž¦gÏê€v–îÒIÓ<Ÿ7 xy›Âm¤× öêÜKð=Ì&%ß*WÚ·ºBmN_õR]üjC¶§½È+Л‹æÈ=°{€#šdáOã Ëp•4Ç™÷)3æÎ€dÕSd´k»Â|È«º5­DaèäÝQ´ÀÏÝa'€yÙúó‡ýaì÷îëÕú5û­ÙX5¯„à'¤4ò¦U»®*7t“tnß9±$|ø‡ƒþ §ïuº—ùõí¿–kÇ^ëó›­³™üb¿_Ø<‚ÏŸüå'r׳wy>,0Ü~Òí2zËÑ~FÙy‹æÉuO^‘Í3Å8hÔAòøé˺ýÖm\p_ð‹i„*›0^BMÊ׫Þ&[ÅB-ÙîRº ?27†|\™8\´˜zR—N]¤G§M(ÙrE‚—6ü÷¿ÿij£§è'®Š£i~&ñ¬,ÐÉp’ƵӴƒ)C¡.ß`:6òšY»:ª5Ö_µ{ã—RMak•PEmÑå5®ôy|þè=±†H)ûjhJ%UÙ g%rÙܹ²éHúmäæJ9sÁLùå=¿l›gÍ+¾ê"X#ìÊSÔ¡OtßÇ,‡ üù8À‚å äð?^ô©»hµË­±ªy/¹þÙk;®ƒú0×äf‘O‘/3]¶çe2 »zSJ¹_íó+9sß3½Ä)=ExñŸ· 6˜ú—-_&?ºêGòÀK|b·Àu?¼NŽÝáØ‚Ý®ôÅ^,ŸÏâ#·^eŽXõåÉ3Ÿ”½7Ù»ìGüøÇ tW0VSòl5=P­~õ„ù8›µŒÆãd-6ö(§¼‘Yµg™1ª¯%Ѱ-&fÄVq¶FCà<`RÈ-L”]ã¡\ÝòYY ’œ¤éÄ Qxx,7[;æR1àòåM\¶ÒJªˆÛç6žñÂàÔGÑ ˪¼Ø*_äÍcÀpÐõ¡ËTg=ÕÖ›ë+þeä>É}’Æ1€sýܤ6 Ad‰¬¹ZÞþâíòï·þmeªùgælÜtP‰ö"1Oœô•†¾@ޤȊé?½+€|2û}ùh™¿x~¡PÿècrÕþÍÿ¼6’â:O ÿ{ÿ'{¬·GE-ÅÀé{›F'î˜uéQ2á½ VGäQÃ_´x‘üà²È¯?©c•6«Èû£œ¶‡ùjì1Çœsä”[£ïˆÊ3Þ];v•t£œ÷ýó¤í2³š…ÇðHvÇÜÎûÌ!ùù@ò>䡯„§‘WmX­ºš«'­|/ÍM-—¦¼RzKñµ~Ê‚Ǥå îƒb-KyÊ&”Œ£°¼)»ZÏÕX20Œ MÌ8Ïc¹mmÖÞiÌR–ùLÁ¬-h焎cx(Oº…æS€‘W+[=tÙºàzVà±EgyÃró·ñ_œA–·0'L=Â|s t麚«ŸúšaüÒSþ€ÖØk¹Í+…x÷ØþüV:ÇŸþý§²`É‚ªºá˯¾, X¹Ðï2‚MH´±+䉯l>a»otÐowsðó€Ø €Ã<¾þú§¯ËÑ>:ò–{ª©%Ð×¼Êk"¡6‚4 58x Ï럷Ëy ÜtòÙž-Ç~§pþ¢ù2ú·£åÝiïÚBxàgûüÌ×E€/>P^x÷…"¥gïs¶\xà…¾­÷½xŸ\÷ïüQ€"GÅ0ž¾ûÏ宓î’^zþ>àGãÐéFëå8Ò´ÖŒ§Œý°YÍ+Щ§©å"J\¦šº´~ê%Ô¼4¼Ly¿ `t­Ù[=攦»F¼ðÑpó @>ãÇÖ×VizÈóº\¦ð,/ÀQÚÉÌÓä’Ï|ƒùœCäC³Y{à ÞƒWÛØ*¶ÂAýãñ"h!’ƒÑ‡çQ΂?i¼@41 qGbù4Ùœ—{ ÷@îZx@:xt¸¶Íß“ÿÍý¿©ªU_ÍÁ§‡ƒ¤m"+ŽFÞÊã|chv<ÌvÌ¡s°€G|ýA9÷®sëêÁí;H¿^ýüu]_[í<À]³¸Âh5•ý ’a}‡‰”K¸ä˜Kä{[~Ï—ÓgM—=ÏÝS¦Í˜f‹ÿò€_Êz×óöc‘`ß?ì+¯L~¥HýIß9I®>új³þbV`Œ}§ÝršŒs|‘\Nˆ÷ÀÎîl Øh€ùÌ¢yÐÕßýÇN€r>ªUc$d5;ß’º›m\¤ù%×\“Ót“GÖ•D7rúeÏ]aY“Øg` µ~¤p`æÌ™ŸkÐJ}À@×^qG¹L§,-hÇiœ$ 0逬—›lLY[Úgh|K`0[Hœ+¸ažtʈ €}„Û¿½"õèT‰·òÌè¬DO²þ¤SBÖo§,!WÊGvkp3u”ª#ç›—û8÷AÆÏ*D@yåWVõQ€™³Ü#h3ÛÏ< i9Œ÷…ö‘Â#»­Ð—x) °`v\>ör¹þ‰ëQªni¾æ=H¼®óZÊþf>„ä—€Ç:¾ ¿‰Û®ÒVþö³¿ÉȵFZ§}9Möýõ¾2{þlûR㫎¿Ê¸u¿õ|ö¼Ù²ÏEûÈ›¿YTãaߗ懦–KÓY/¬C¤T9–,äIcÙ4:dCy­e‘@C¢NBCÒo8™IáÜçãu `+[ÉÛDIüP¾.ù,-„Ž ò™å|þ‘Gy]{5ìlÍ«¾éš›¶Á•[¹Rº [¬iì H*OYÿËQ”“ZÄ‘‰i‹Ô+Í={ ,˜˜Ð'àM°¯ïþ3pDðxÜÇÉÌyÁ³û^AeÈô¯§ °N‡aMÓ5Ê®ìyúÊ@Û—˜ñ¸Ãö¥ þ¹àÔÛO­ëèÕû¬^4Ž]äŽë׸뻢m=pk±wŒãÊV@ëÒѼÕÿÌÛ¥o÷¾6Ðcòrð…Ë⥋e›ÛÈq»Ñfw \¸§¼ÿÙû:2{l¶‡ÜsÊ=Ò­S7ÁbÁìûØ@QÁœ`=€/,üõG•sö:GÚ,3ƒ;Ô»ünoúñ j|X…aÞ›ñ§ÚúšaŠ.šºcF ojÒÊ¥ñÂúËÉ'è+Ù΄rEU&É%Ñ‹#úHàÔ‡Þ7nV*Ѫ´CK„ò”!ŸùLÁ¬,„N ótZ’“Á×<œîdÒ¤I³ÌÉÎâÈã…öä‡LFRÏ®=O0l5!lÔx\^·ƒÐ4ↇ¶Û;˜J’…IôˆËT"W¾‰´’'·&êÍ‹åÈ={€ø6ùÏæ~&?¾ñÇk2Ä›Óq511ˆMÈÀ_:ц‹¶/¹`v£/iX"‡^u¨Lú|’ÖP3ïÀ5?2OÁõU°†yZ†|‰tð&—(Ÿ½ÖjkÉM§Ý$mÛ´µ¶Žu¼ÿÇ[ü¼ÃΓÁ«ŽØøÅ×_È÷.üž|øÅ‡E•l7b;yðŒ¥_÷~2kþ,ùþß—±ÇÉå„x`LŸºç©rËq·H—¶] ‹ê1»€Y0Œíøb>;ȇ4CÊ|j6Ç95®š¦ñJÊërÀ™'¤.æµ x¤‡rqyÊ*ˆX§{Çî”ÎÔï…3¿‰åï¼óŸÅÓ¿¶‚6#¯Ò5Œ+£ù™Àë½: N!M;˜8'òäÙ\²dÉ|²&ÎRZ£7¶ü›¬Yøãk§%6ÒÈ+›¿J>Oãc]„G¡~W—¯7]··3¦ÞZðÌkü’m»k᛼Ž| äc ‰c *œ‡½k\È›—™›»È f¹˜gÇ1ãÇBÓÓ‚Eî…‚¶nèA=ø´;€›…i× s–Ì–}ÿ¸LŸãveÀÕ5J«õÁ[²a7€œ¯8Ü^Ó ¼UÌ€úÞˆÊÞü_0"ùï#w_l>‹iÍl;Æß.çÞ|®½›Å®@"Þ°§Ù ðñÌ‹”n6t3{öXÜwÌ[8WF_8Z.½ç’B Z$â<°çæ{Êc§?&ƒz ÂJ–Ù `æxØ €GB—™ù’]0yûeCý17® ã,Ú_±´ OÃ>ŽäÆbD¦}U•UlªM-WÕv˜>K²ÃÒM;“ø1vØóK }VàÃwÁX±yG냨á÷ï…s[vRø+.4ÖÁZHl¤Æmkt$ÊiHºPX^‘ê‡Ö{ Ü–Ó±§IÓ|O›;wndføÒ‡r h)¹½ÌK1œµöw£ãZℾUÎ åäQ¶Dy>Vò9ù4'”cK•dìêuºJ¶«]ì«8ûç2tçï¨`<—áϸ¾Éi¹Ë8Ïqœ7ÉÇâ¼»ŒGìB@9ó®_Ê‹“^,6á/ž¶ u29œÕY2m"1'me‡Ú?ð…KÖ§è?$ :7ýÉG<>œñ¡uõ‘v[»•«ÑŸ^ÝÌ›ÝÓú×r^× ãÊPÖð°ýµný«ÞŠÓ>]¾±Þ6…9†©ï’».–k¾VvÙt9h;³ãv);>úò#Ùãw{ȧ_}ZdËð5†ËØó•ák·Ÿ<ûƳåˆ?.³æÍ*’Í ñØhÐF2þ¬ñ²ÍÓ'8­Ø÷š®0‹ æ¾€Ÿ ´ý“4ŽTߥŽË¸ñWMZsíPåÃø4µ]ª\ª\ØÖ´ri¼PO\>ìú8Mc},iZ.ŽŽ2šæYú©Û@íë}ÌÂT†’¾û³,X€»ÿl!XÄ5$¼V—²´ ¨qíTÝ!Ρy–Ïü—†ôÒØ>ZÝH±˜%³µžç„Êø!ëåc˜²®yÄ”¨;©q²î¦ääÈ=°²xñ"ß`E“wpáò…rÄ_—Ïfá•'¿(íbR«8¡V«i×29^ð@œ ÍÆÿîE€>ðÇ» À˜ÇÆ¿÷¤œü·“kêÉÞÝ{Gê³—hÌ¢ðzM¨%5_Ó¾ã:;ÆP›OÂKÿzÚõÒ£s?Ù?å/?—&< y‘ôéÖ§¨’Íã{ý~ÏØû”GÏL6_gsÓI"÷>s¯luâVòÄ«OéÉ ñÀ£÷ŸúOÙ‹ý ¿ üͱÁ¿™AñÅ€nÆ\˜ï]Cáø óñÕF©M)ÕPY®ÖõUf]ùÒq툣Qc2–’¿¤ŒpòžâW©Ê¯½ÚPmIÝñðù÷Õ8ZLȸù¤#®-,žÆãdëFËÒä,:rg9M×0iÒ¤´@ØéšW|~ë.œ®rÛ0óÇ7ˆIÌk¢ÍW²±åb䬛Dp¹QÊÃÒÍͯ5n6´ÕµþZ·7¯¯¾ã-÷ÿJì|øþn$€öÀ•Ó 6hl#ÏžfŸÇ‹Ð*MvGô¢ Ó”õ{Üðˆ[9“±e´òNËæÐõ}DÿЗÈãˆô§6_ÀbÀ-Ïß"—üëC¨MêÙ­§¤qMGÛk»ƒa>îºo‹A¾PÜ–ßfð7Z¬kõ_K.8æ;ã‚=K—-“#/=R>üüCùÝz;hìzûÓwdO³0c?»M®Ø— >ôë‡dûw°}óñŒeÏ3÷”_üù2wÁÜFÁKô@§öä¯Ç]/§ï~º¹ãoÎS&ø_n0ãÂÀåæ1û€™% ÉcÌà0Z=—'½Bc²OvñÃäl+ôS%eZB¶„hXbÛBãlÄq²IúXÐ×EyË(”>À|"4C)|)ü|ð¾1M°±£Ã‘› ºÆãäBZ¦òY\Њs®îò Q6Òy=öØZaÖ6¸™™GªnЭӆOãÓ i2qz’ä»ìd•:j ¡ +¬qUù×jìð¼ºÜMð@ø9ý&ù MÿwÓÿ3“%uâ,£{nC@Šƒ)Ìk:ñ6Íô³IýÉ—þú¿–½ü¯¦ÕUa),Ä&7¤b¯ƒ%†æ[ Ü"VmµˆÇì~Œl=bk?ûš¿p¾ŒþÝhÙÆ<°ÝÛªá˜vþýã×åûø¾|5—ïÝj´¦[çnrïÙ÷Ê^ÛìeËÛ,—?Ý÷'ÙäØMäž'ïi̱D`lÿj¿_ÉU?¸J:˜‘/˜ÈÌòJê´Ö^bœyÑrå|Hsõ5µ|K”KÓ™Æ+á"Ï.Gú·T¢Â8ùW"¿Á€ â´ÔÆ‚&VÄWãÐ ôó„´yB¾æeW‘gæìÓÎ%®!B4Ä˽÷Þ{ø6=Ù„ç>* ±lKÁÞÝzlòVNÆöÙ|3™´Ð®Ø\çãðͱ0Í;g@.›gò• øÞ.W?ÄZ*Ùö…vѾ2 mSŠqEmÖ:“Êi™O*S=Ô•ç£ã1÷GîZޏß,‚FFê: Á•Ô‹7?w³œw÷yq%iK—aonÐN&0Ù¬¦“Hz-ýÓšêÒ¾Ò8ú“vÀϦõ¢ú´Á¼ðñ˜¿#/ø².Ù"x×N]ãã¨-Éßär,¸üàžƒ¥k£·®øÉÒ®yvÓfsàóûýv?9çÀs¤c»Žcv¸1ýê”Wí"Þþ&Üžõô[å»üÀÊ£Ÿ>™ñ‰vÁa²×{É›“ß ‹äù¾Ýár×ÉwI·vÝü»ìãz3dÓgœÛù±†¾ä¸ƒnâir•¦Jõ…òº¾ÖƒÍÚVÝÍ éä¡o˜¨yâFæ¿ 3'd?“OH>òÀõÒ˜ lèÓ½tï”/À&ý“Ǿv- Ziuœ´|ˆ#ŸÙ”µ:—cžtàH¤iÈa ñåf«GdßXøöG«­Žõd[ƒAɃ­D>’‚¬åš-g ±Àñºu]¨A*é…\þ·©€éK­1r‡_hg˜&¦]°|rÅ!2mæ´¦ÖXV¹®U ŽkuÜjâ50௷jm¶Þnft­@KH®“õ-ÕtàL¤3Ÿ9ˆË]VR’ãH§35¤í”A¾¨ÃfÍšõ9ñìkVŽ¡ý†N¸0N·„8[ ¾JE'0Ê;ðùÏ’~¤.¥×£¡¼g¤#Õðkz åq‹üS^±ºIùI~Ý,È+Î={ Õ.h±pŒÁ"ÀÙ÷œ-7Œ¿!U™/¼ñB!uº-ÝàEçð“R/©LN/ø~@p‰Eן6ït¸°óÉœOäÀË”ù‹ç·˜çztíQÐ^{u¸Î'YãäF¬6"I¢êô39Czt2mÀ,ÌÍÄ&¼7AÞøø d>ñI³îxyò˲÷Å{Ç. _~ÌïeÞ?çɤ›'É„«'ÈmçÜ&'>I^yÿÙøˆåú…|6£i/áŒØ´g6¼±<~Öã²n¿uý"€]àNö™ƒØ àÇÇá ì§¢¦¥µ¹©¼¢J*$$Õ›D§ú8~ ò ¼Ø9uŒœ­N•]»ÿÚ™‰·Ÿ„Ïÿ›ñ Õb¶¿&ÕïÊ‘§!q”×8õefi Î!t!e˜t—!¡M:u †Ï~h^=ðá« /T«[•fH¹rJ«¥þbNN)á¿=¸„\ÎÎ={ •y@Ù÷#踒šíâ8Ú˜»ÆØ6þ“›~"~ôÏ%9îåqþÎ&"¿¸½ú€&æKjÍJz¾DRÐ÷©Z°}ŠÅ³àµi¯ÉÑW-Ë–ãViõ“}¾þg^áv"nò˜Ì–Jƒ{ .%R5>¾bpò~æn½³•Aä¿_û·àn¾MÃb¬ó®þ„'Ⱦ—î+sF6lzÛÐ7ú †n$ûl»\tÜE2áÚ 2ẠҽkwÙþÇÛËI—œ$~ò¡/“#Q î7X;ë1Ùb°y'„ù4 Þ €v7fÏnÍþ³Z8Ô£ª³‘K³­©¼–hYš-Õ¨ý¦jÔI„aÌ“ïàˆµ[„¤ i0ŒMŒø‘‡µnä[!-hDlJ¢“ŸI˜…:.tPHG¾ÜºX¾á©§žzM+;_óêo´úFÃŽ-ÔÃ0¤!ǧ\ÏzÙ u¥• eÂ|ZÙ:ðl»êPoÙ#4·­ü_sî«ÜWY¸HÀ&Ðøàyë4´iSo=Uþpß(YH¾ð¦Ù€+1Ê×)l?y!=ÏWö[u_Ò¯ìÓ˜O>øêƒrþ]çS²ª¬MìGj7ùÔkZÊõxµ®«QKMàOöý‰àStvŽ»Ü1ùóÉ}cÈz±¿Ÿ}ý™Ì[4¯";׸®œsô9òÆ-oȶ›l+žu ý›£å•w_©HÏÊ"ŒO3>pÚ²Ãð ‹f! a‰`zA¯%áãfaÀâ4wÞY4?J·E²º~àÍ8RKÍÐëmª´]ºÎReÑ/¥äˆOÕ:‰C€¸ÖÒ‘×:tSG mä ‘Ð’™Æ€.FD 4d«JÁBÉÂ_–×4àIôP®fù,,èÆÒA„štò4N9Ð0ü8-?~üóƒg9Y²gºì¤þÝûK÷ÎÝMÃŒ‰ÞÊFû”é±ü¢2JGäDG•ŠwR,‡µ÷€ "j_m^cîÜåx€9D´ØÀys5µw3± ÀÝ1Æn€óï=_Ns¢,Z²¨¨†>ÿH-7t\‰Q.Ô§ó®Î"% ç©é ÿœ} OTŸê—>|iÙx4Å0;0ýõJxÝ$®è,’æc~QËÔ½KwùÙþ?kœ…9{µ}ÞÇð¹ós‡ä¶“o“þ=›foûvíåà]–®{AöÚn/9ìœÃäÛÇ[þþØßeÉÒlÍùjÙquáe“wÿünÙk“½ ïß €íÿn³i;1›FâØ#,PWÌ¿imLã¥y£©åÒtjžÓ¯o¾Ï´qÈ›ÃÇqö• ù²Ô æ¾è±zÕ5§î¸Ží ˆ GbGÆ‘Ú^x‚Þи–®eB^fò8õf=ÑÉt(ì%M㺳È÷ÐtxäÁ½ð%õvÂÀ¾‡ Ñ-&-ÖyÒ´<['§iAü`ùO‹µ&ö—“bOZåÌeräXy=À€0¸ f\cÆà}X¸á©dßí!ø¦¹NïL}Ç>2€.Ø@wžò@aàL'-‡•{€~t~¶}Üõ+߀¾Á£€?»ùg2þÍñ•×Uª/_„'NXJùF~Õn«2W3xì÷Ž•] ïðÛÈa»¶ßùšcû¤ïž$#7ÿNá*«¬"û}{?™xÓD9`çäÄ‹N”u÷]W.¸îùtú§5óAÖ+êØ¾£ÜxÒ²ïæûFp÷ ¼ó™µ9ì|‰³lö#aSÛœ²qõ¥ék*/®ž–¤¥Ù‰zKñCÛ´¼Æ!‡¾ŒKÓ²§| ¼nòƒVÄR™€aìçbCX°7ÆöhÒZÌú‹DHœy:ž§%@ƒoósæÌ™ŽÂLáÒëñ"@ŸØ:ˆ³¥rô¢`—ò”k´ xY¢7¢ÊjT´5ÙZ#—äÕäÈ=Pm0x^ƒû;š\@ ˆ;úX 4‹/LzA¶ùå6rÇSwxk^Ÿb>= YTZœ:¡Û-°B˳ѓW—#Íñú”IùÝ/ ا¦¿–˜‡_u¸Lú|K5vëb>ÕVnJ˜øân.У£ Äkœ° àè]nœÁÎÌô>7Gûöíåäïž\U+;´ï 'p¢¼rË+²Åú[Ø€aû “}NÙGî~üîØ9U5 (k×¶üíÄ¿É[иÀÀß숼ÀôŸ]à¸c?¶t{«TOÙsÄ´úšÊkIÁ¦8»âhIvhY[ÕŽ éÀ™'„n…ã€YJaì7{öì/ÅÔÉœKñÜ¿=§Go‚FNœ¿Zø•sõ1rýã×Ëù‡œ/c'Ž-,PÎǦ Îéüí¹4L¨7<ÈËau< úÖ÷)úÒÐm_º>BîsÉ>2þœñÒ»[ïf×m_”çú×{íÇÓ‹æ¿ÆýÌÆÉFÆ­p¼ömÛ“RSxìÇÊå÷\^"9†i/ffΟÛ[ ÝJúvëÛ"ö­¹Úšr÷î–{Ÿ¸W~zÉOå¡g²¾M~ЮÉá».[n°e‹ÔÝ”bÌ9aŒ`çÄÏ›ÅIÓGصñfq3þìB¦ë;{n MOŸ£J5ò•¦Re’øItSê<+¥œý½%ÙßåPô†ºuž8!ÄqîÀo IÑýùƒtÇãuÊË‚ÎÃè‰ð©e!HYBS|㣖̤pà“O>™dŒƒ—`5![Ȥi¤“ÒˆëA?¡/ œ4c’våa²xéb”¨^jÊ%-,còÛw®žMhZgÍudÇMv,L©9­&„Ø Ÿš4|€ûR!Û"÷ýö¾òêm¯Ê¡»jõÏœ3S®¾ëjùÖÿ|KÖ½¾œóçsäµ÷"ï‹n;²¨‹9î/rè7-ìÀÝÿ¥¦ƒð€¬íˆs`8îãdjAËŠlk){À§ !ËjÒuâ„FçÎÝ7ÚÒ™€aìgžÿÙFË㈑®qÒ4 ´Ì&\ÖZSÒ¦cyI$N9æ—7/DÞ&ýÒê ×Y};\l oÆ ÿE†[M¨f« Í.Éëk@IDAT˜E<ïÂ…-Ñ©¨»ÒD;ë47¥Þ¦´³\¿DrÊ-”ËåÈ=Ðú<àk¸Á¹]ß‹î÷úq<š³€mÚ›ïp ,ý:\Yh}Þj³OÝáÐþùh‡ƒO¾ó¤üô†ŸV¥}~@¨—fÂÏ|À¯×˜sØÎ‡5N™ÍìË^w !àlÒor-žzuë%ן{½Üðë¤g÷ž¾'}:I.ºé"Ùꨭdä¡#å7×ýFÞšüV‹Û“¥ 0î®þÑÕrÐÖ¾ ÀE¼ š‹Áø,ËM)S–â¡´úÒx ê,9­\…KñcêMœãú((ZÈÊ£Ö¥q-ªù¤“¦ó†¶öêk“’¨c?ӿï8x­ ΖÊyتÿy-€°žP«Ì={ ÷@y` iƒG‚Es…e°hàcA8vgóî?q`Úr(gÏq¥Æ¡ë2YŸ@ÏSõ<@ÒßFúý¾B?xã37Ê%ÿ¼¤Ù6àÓ‘„klp-âGÙÉì½ÝÞÒµCW{"vVæL]³Ïš55úàï,ÿ¹á?öÝø½Ú€æxwÊ»òÛ¿ýV6;b3ÙäðMäìkΖ oN(,^ÔÔÊÚW†E€?÷gÙu£] ‹|`µjÕ´”ß æÂUMUVWd[¨_ç5΂š¦qðKå©#„,Gèø˜‹ÛÐ7²Y¨¡®ù0æ3»æƒÂX­ ö‚Æ4S&¤C†Iã¤Õâ2ÖM'2NBB¸î4Ò<œ1#ú f³ €²™I› R?XDâ–iØ8‰iG/-„zÂ|9Jé"g©«â‚®@ÕOüM5$¥œ "Rø9+÷@îŒy@E‹îrq‹öî¿ "5´‹&¨´A?¡ FýBisÅ aŽêO¿ðfMü¹»¸[8ÿçË/?Ð"Í·“ì¤krHó-bQi¥øÜÜ.›ïÒ83Ó³45[«Ç— †¬>DþýçËÿìý?¦M[Ø·j¡ _éøß[ÿW¶;a;Ygô:rÒÅ'ɃÏ>(óF>*UÚ­H¢C»róÿ»Y¶Y{›è‹K- w„a»“衜Η*SНu•ƒ§éKã¥éN+—ƃÎR|]o([*¯Ë¦áFOì¼Yë'Nhôm>dó4­5ç…1ßÌ™3?1FÀbžx†‚mšÎVQŽyÊéu1ŸÂ»ò´+eÌYc¤SGóRhúÞýæøÛüÄÄ c#ûµŸ Üg ìsÆ>rõ=WË;SÞ©‹í-Yi—Ž]äÞÓî•õú¯]Àæý8€›SÚàã‘040‰ÊåùÊ<ç×8´j:p«5MF—%NhtuîØY¾µÎ·â´ÖÆ|ï¼óÎÆÔ³Å:ŽÔ|ØN Il5 §¹,&:–¶!DHœr¤kÈN#l¸ë®»^²ZÜŸp0h^½ð™7f²ÚM#NÊ‘hŽÈÉ™²”‰ÉÇ.„ò,˜ÆÓrÀ­/2`GnBîÜ+˜< 1ˆ0°h@ŒÜ àßÀ]FF–ön3 nÖc+Ìÿ´¨ŸGú‹\Ø1‹7è·ùËçËÿw L›9­b³æÌ<¥Xqù°®wó×÷nõ®[ïjâgã(=¥ÆœyƒöéVŸú _xôŠGeU×(,¸¡Ï1;æaäð;ä1É|yxÂÃò³?ýL69jY÷ uå„ÿ=Aî|üN™9{¦lý©G—rç)wJ¿.ýü õ‹}ÿù¶i³ž j¼©î(¥#ŸÂkÒ<0E_¤Ýa[›ZzX–0Ô´eCȲ†nåÁ×2Ä)H¡¦r¯•­·ÿü0æ»çž{^4d´G2¡!ùDB2G"$®óV ‹pzËZÒŽžtÀnÍc§‚OÜÂÏ?ÿ|¾yd Höy-|·»PSùG ۪ȭfË´P óq|ò*F_(hWîQ¶Zº+±c%”5a@c®„í÷c9o{>ZËà9Ð%û;fi FgA®Â*¸ð¸ >lÀÉòZ'ðÖâ—ÁNú}ˆs3û(wý8íëirðåËüEÍ ¾ÓüF{Òd oöÂÙ¬[êÛ³¯Œ:²0oÀÜÁÝE¶ó—ïÞ±{ÝìcÅ[­¿•<{ͳ²Õˆ­|ßâ·g¯„øíºß/~Ã<>6O—^ÿðõrÄGØÝÛ¿­œqÕò¯gþ%3fÍ`­®3`¹ö¸kE°‰$x a™\èKô¡9¸³Ãž“@Óã2Ìk^–ðÖl'm'¤_MWDú‚ô8XŽl ßÇ&šnôŒfb™ %ØiwX9› N:ï€'h= iÈ“G‘Ï|ÁG=Ó)‹ ¡ÃB'†ÎŽËëNcçY8kÖ¬/tá3!šW|Ïö,T«[­ñÐ(óÏ‚ž&–Óy]NãZÆáøñˆagšdOT™¶07.÷@îVï‚H€îˆÜ5vA?ƒ>?îŸûÇcF†|ºÌÛ/˜,õÍS z@÷)ª1yß\¨Áîô éÉS'ÊÑWÿìl‚©^g¿"²»–×{6ï¸ÙŽ‘ ‘Á"o*´k‹A_ÿ4 ï{ÙXÁË }_ Ýo6q±»?Üž†¶ òÒû/Éew_&£Ï-÷(›¹©œxñ‰rë#·Ê¤i“êßÐ2-xöÍgåüÛÎ/ôø]àÏ~´sOÎ ˬ£EÄRl¨ú<0¥®Ô9yZ98¥?ÎqºLW.ަÊÛCå‹Ä5Ïáûo±‘X= a¬7{ölÄ‚°6#º;ÑÃÉ“'¿Ý§Oã+g±%¤K—.ViVþà›¸ï~þnÁí PŒ7ì ,ôŠÎ»†Ø»,p&Êk>y¢{T´Õ'R[u†‚Èk[K™ãTJ æüܹrÄyçÂàÜŠsdÃ*†H: ;Ú4Äœjs7ð.£þÃl,8ºvìÚüJª¤Ï.ßvÞmrÖµgÙ ¾¨?\ŸØ9©3¹ß3Úiùnæùδwäíß–ë¼Îú O÷>²Ùº›ÉæÃ7—M‡o*›¯·¹ ]ch•ZÐ<5 /”ûŸ¹_Æ<4Fž~ëiÿ•;ÖÍ{Ú,+œÇì9KµmŽ7B¦)©T¹RüJëLÓ—Æ«´žJå+¬»h®Ëò„¨8rìÑeYžñqÁ;ì8ÆÎÓgvÌ£z6 f¹öz«çïx†’ž§VŬ´ö5•ÃÊ-«å4žÔ¸?NY/d´œÆ)ê§Œƒ£ÖÍÖö˜Æzˆ ëQ Q×|à< Gœ´¸~&S–B…N£“ !ÏŽ"e˜'ßÉ'~nžýXÚ¶maÏVÜñÈRЊÏÞôÌM…‹'¦E6ˆ×wŠÐ*òé äy€‰ž±¨Ê˜¼½0¤e‰r¥)<ÉÖÓ·¡-•¶%V>ê¾XNþb™­µ¸RAÑ\4÷@î,x€ç Bc“=çšs¬^¤õç_m³;[yÒy®Ö¼Öƺ/Í® {A_™ÃÞ)Å9Ûü·¸Ù~ò 'Ë ¾ƒd‡ wHµï«9æn½ëóPÐÔv° “ùlög¤Ô ®Ño é×£ŸÌ˜kž‡Ç¼[È<š´tÙRÉÊc‹ OÚ÷$éÓ£ùñb¿¦àúØö‘ÆY>G2‹}ì+#Çõ‹åÃH†öõ¯åù·ž—çß|¾± «}Ûö²zßÕePÿA2¸ÿ`{àQØ…£wÞ‚÷,tëÜMÚµk'X¼èÙ­§ýT!”æÍŸ'K–.‘ÙófËô¯§ËÇ_|,S?›já[“ß’ÿ¾ÿß‹"Ñô‰9ìc,°ö1ÈNpw`qÄ/N²—‡,RÂx.0þ²lÛÚQM^Z}µæ¡]ºN'ñ C9BȲÏXŽ<Ê‚„<Ê ‘GH]È#hÏ{*Ï2[Ù² “‘¿°Óî®rö D,h²lUcZ•ê¶åX–´ÌÂ,/Ðith„LHGG²3Á#NØ0wîÜé={ö€ÂH .”Î;2ø;r‘Ò¿gùl–¹pãä‰V O¨†oOÂqgZ]¶ ¥ðt§ÇNB üh* Þ•N¥®p’P„Štªr•¢öäTi¡\>÷@îÜÕô€>oóéhö\Hš©SŸ³üy’çûVÓÆ\We`Ÿ¢”Á¹=Ú? áÎ6.Üæ?®§‹—,–#¯:RÆ3NÖé¿Nb]s˜wR!à‚~öw(Då\~ڬʿF ªYä†n$ã_‘aVfÚ‹—%â­óYL‡î|¨ôîÞ[ޏèˆÂqø_õ‘ý†}‚®çÂ=~߸yãg¡†„Ï":žç«Ñ2(–Óúˆº²[­“­àæ…1ž‹m` ”[°[ªM°5iú$ûyÀ¤€×î@Ù¸­‰°KýûɬORùµb0¤qšÍù  ™™Í^¼(R+ûJÕ3jÄ(yìÂÇd¾k4вŸ0“æÁàšw9AS^/¨Å¸S‡Ó.è|$Ч „¡mÈƧ=0^ÑÐÙ¶QCÃNMM˜¦êË3­}M塺¬ÆÓÚÈ&Lå–ÕåÂ2a²!y·\{ËÌÅSˆñtr1 ¬ÆÁØtÕ*ßrò´:àIôP.SyœZK¢ƒ a7ð°Óׇ–±ôgŸ}všùä2óbœæì³! íÅ„ ¤íÖÞNútë#3çÍ,XƒV˜d_œƒ“´NÈ>ts/´ž"h1pºtRt׸*£l]ŠWMýQë¤Û–ZwMƒŸëáTäÌܹšïrÎ%” ÏÕͯ=×P °œ.{¾ÆKãÐ_&ˆ²yóõX8?ùΓrʧÈÇ\QT;vØà SÞßýwy_u²^ ‰SÐä³²/³³6ÃFÎÐÌ;ðøâŒ93díþkÓêÌ ÖÚ@Æ]8NöO¹räÈ={ b0àaDˆ–曰νû\yà¥"UÍœ;ÓoǶÁ£ ºlÀeŠEÿHÉ ƒú]Z¼l±Lû7¼ê›úõêgç->ðçìÌ\z§ÏÆ;¹ZOZ½ÏêòÈo‘kŽðs1o½î{Óvk=·Ø"@GPáÀUà¯ùš®q-ãq½€ºØ'Á$[h§³\ðÁ¿›6ØŽvcűGèSi¡)˜o%ª.b·-Eõ$Ê©2åÈ¡-– y”'t$æ TKßfØ6Ìe†±‹ý`=Ï@€!®iek‰ÇA´™rÀ3Ÿð³Íj —g§±3Â<èšF|ÙwÜñ¬nxø’Í«¾Ã°¤gçž…ê]ëq23[X|°nFƲNÞò»Ã/„‹l$Ë!¯qòË€KMTPF¹HîܹräÈŒtÀcpí x÷ß.˜@pY›erôÕGËëSïE|>Û|™Ê\þùkàÌC?-à¨ÃÜá$GiL7ÛÕëœði:ÎC"ÐÌÊ>ý*/*¬ÄE«õZM9ÿ9xdã, 0íÑýýƾtwÖ¹`¡ Ð}ot ¯ƒøX™ŽÑŃHYµ¨P.u°^îÐcX?À ¿h<š¦V-¥M'ÓxIT»Lš¾4ì+ÅOjCHG„ÃTŽNÈðÊÙX"Ôáòq‹*Ý;w—GìL-™alçb?l‰Bk†8òq4ÊëöAN§0¯y™Â³¼GÑ‘„¤Åå9ôÁÎCçÛŽï½÷¾2+CþÍ滂#k)|¡FY)Ñ¿H9ãü˜íÁ&ïëòaÒ$SÎÑôb@¤^ÊeVbW¬/jІ½°ÖÀþ¼ŠÜ¹r¬ðиÁíy³,wØE"˜š¿|¾ìéþ2mfáýtóu*dáíLͳؑ;® &ƒzà×´k^>XïÔ¾ny›Äù Ã?úü#Ëjmúõè'žû l6d3;ãŒ<ÍÆ°¯8‚…\Ã5e, 0ñÜ5À»û&Ø·Á;v„êÐG Ÿ?¡—‡mf¼úE Ó–ÈڈĶr…<ñ4È1‘&Ó^“æk-dK¢ùa}a5 ¸ÎÛ¬"(4"§è~Ϋh¨&6AFË×Ðà[­›½·ÿ‡qb>Ä~®EˆÑ +†yÃŽ, 9LÄ IÏ4Ä)©5%:0<ÐŽ°#!£i‘UŸ3f|ŒBLá³"¤×úÇ`„n½ÎÓ@Í×8ù‚OÐ5Ž,Âà?CÑJ’^¨¤\KÉúaKUëÍ={ ÷@î•Ë ˆ(á.=ƒ?äH™  Õ´ÙÓäð?.óÏ—éóÌVxlù…Œ(ç^Ìf–+ÖC˜àåg|˜À©¹[—nó 7°šÁߟö~í ©rM½»õ–ÏyPF 3lr¶IȺÐ?8Ü8° ;f íÝŒ Œ Ô1Âmü.ï}Ê" 7¸_ àâvhœ;Ô¢ù>àw:i µM-^±-±wÿÑÖj¦´yg/Ɇj—IÓ—ÆK²¯z¨7ÌS‡¦gž0”K“Á¸FbY³¸ý?ŒéLÌ7ÍYÏ_¨Ž I£˜g‹I'$°U&œŽ²–8¤hWèlæCˆÎbY@æ)§;Úò_y啉¬0Ü*¢yõÂw¾“ôìâ¶Î)#üÊ&[GžÉû <$ÊhXàÄÿe9WuùÇô‚@ ¯,™ª¼ÍÉâUçԣΪ7"W˜{ ÷@îÜÙñƒí"ò Ý"&Lž Ç^s¬|>Ç<€ w‰)¼•=r§•õÄyÀñ²ð@[|t‰sØÊùƒoM}+ÎúVCëÑ¥‡Üwæ}ò­u¿eßÁÄÙ'8|[M‹ü‚ú†‡ég¿(€Ÿ  ¼“ ‹Á¼†Ä= ì™çþØòF‡_pcÒÚŽEØŽE.¶¥Ò^ã8¨´\ y?G.!a·-‘:t¦œú´ p·YC錮Òã,£ençÆšŽBˆ¨L*ò«‘ëÞ¥»|wÃï2ô7Œé^{í5Ä|Œ Cˆë-Ñù$\Ëg‚|¦./­%Ñ™Æu:Uwl˜GK»á†þcpêËä:ç›Ã¾Y°’­¢Åºõº•šž€G.LZFסq%Ó°ÌœÜËS å“ÊÀ&}$É5—Î:š«'/ï~=jlä>É}’| ¬ôcÀ ë@—"Aâ%·3€ßýï—¾ü 1Dè¿p -[ºqþEJ:Ö‡Ó?´"™øcì ç_ÏùZ¦|9%æ5Õ<ý3ÿ!ßñmÁI–M887 çC ˜1 O:Ìš ƒîÄŠâ iXH2¸¿“¯ÆTxW¿HŸ[„òõêÀŸ¶õö3…Ú„1ˆ¤!ð¤#ôIœ\šL/NhÕ.SJüÁÚD:`9¶éºXVëÔ|+ÜkëV2¾¿(GÖéè£Ö3»_2˜‚€†ë¯¿þc&¬f‹ˆ'Á¤^AkÁC",äZÑ߬/„Ž ót>é€IGØÁ ,Xb¶ˆÌÖýeh:› |Ô򾂴[«ØÊÐBÊizMëHâk 8ƒi{AOi*'*ý¯©zP®zZ¢ÍiS^6÷@îܹ2êIH –칋wû}@†àMp”c9êÑõÆ$<Pïë×â%‹£óÎaÜücâ‘ ™1­È>©KÇ.r×éwÉ.îRX0ûNíbgŸ¦­‘~@"²ÑçažãA=‚yÜé!hî°ãˆã‰ ’]ªŒ×çts|Fì1¶Ù…+Îqh̲¸†À[KjÆ<¸¬&¶”þrôB†r„Úè4šæg^Áo®knRf,-\¸0b‘‰íæ æ3DX®~‘~1€­ !ô\'Ðu óš—9§˜¬':TCà<`?pt(i̳“5¸}$`Ê”)ï@S°bDr]ávël'z (´– uD·¸@¶4{‘qrN8*«y,§¡æ;]ß7íÏ_8¿`š3Ð>ÀçÞ~Ng[-Þ¹Cg¹í”Ûd§ v*^À¬“3Pø‡œ ȇ¸¦‘G¨{}ç_ãz¡€å©[Ûapøc' xÚ~ÐÔ¸C61%Œƒˆ|šL /v® Å)e"õêLZ™4žÖQ ‡ž8]š†q$ûÒIдœÆy›ŸZÞà‰±ƒuÂ,c`ß^}e§;AS¦RË}üñÇïa¹~œ¿F@}@Že ÉÓÈ#MCà­"áçÛÈÎ!-ÌSFw®wß}÷“Úá Ñ¼zâÛ®·m¡z´‰Ð¢.æzÃôÿ@Kø·Ü¸Ž<ƒ4êTº-õ…IË„<“ÇID1"­Š”xAiU­ÈÍ={ ÷@îšz@D·Á;f^îðÁ=/ý]¬é;‘àß5Ä?À†±NBC¯÷csæÍ¡uÅÐÌ'ž~ãébz+¥`'À§ÞQx`©iœ™qê6pÃŒIÍ¥Ðö0 E6ÐN‚\ RcÆ/€¦Æ—ÅË‘‹“1zìøTvxÝ[<Ð#ßš’ꃲͮ¤L%²eê:ˆjæå‰)de}9Ê9¸íú.6ñÙ@ÂXî¾ûî{ÊXÆøKqŒ ÙZ )KZ˜ÏFC›aNYLnhyÓØ¥ ;ˆš¡Çò&L˜ðéÒ¥KÍÞ´B2¸˜OE0›¸éš›~ÈÎ6¸Ž{Ó ¥¼å½P81ø€Ýœ1ì‰BëÑxšÞ9¾3À^øÒʯ <뿤-ö’·%òûË}bÎ3ù˜È}òÆgð—I&¼k ˜\àÄ€ÏX:ˆƒ ‚1õ§Èû[,`EöغL½õþàìyæiˤñblåƒWdúló„$aàÎÓî”í†o' KLÃÍ´²‹x/‚0$öŽ.ýÁ›ã…‹qPìA9¨Seãô„ã¶ ‘‰#_Α0OŒ”M“Iá%Î1SÊDêÕö§•A›™t™OÓÙ$¾¦g¢~ò µ.ÈRŽPˆD^Yé-Ôaø[ ÙÜL¥0Ž3Ÿ\òôÓOO5FêV°5€Á/ÑÊ¡M”¡'Ò ä™ —ù”Õí¸Ð‘a²ì“¦!;Ðã_~ù%†Oá³#žQGäkC†®:Ô4ÔçÎä‹ZÈXícëµí¤Æ%G·uüQ«3,“¤‡r:xP$Ë0¶Íu0¸è.OlÈ«Ì={ ÷@î&zA’ö|Žh öÍ]ظ¸»kïühe]ðæõP¯a[}€:þ¤/'iJÍñ³f¤Ö¹¼a¹Œ{u\ªLkcbàž3î‘m‡oëƒÿ‚@3Õ»ì\ æK¶?Uû<Ç yÌ㉠LrwI _àQ?!l$Xi ÛWiùjË'Ù“Dë/W.,‡<˦ɼÔyi’>ÐãxŽnu’Oˆz Ž8À'‡®Õ-Ù~øöžœ$|—›ûä»ùŒÄø£5ú@3‡ y…\ã_Ðu óš—I?ïÖèXBØ œóìTÒ‘×è:o;߬ =L‹-"š)¸ó†;Z «ØB@&“FHyæ,úQÇép4.Z}•f¹z2«Tiå³jW›˜«Ê={ ÷@î–öƒ%<ùE€0ãBïÎbËwüsöF}%쟶þ«öÖ|9¶Ä•#­œòåÈPŸ‚Mš¯%Õ•DWõY´\¹°ò,K¨eH# x¾­š¯ñ@Þ×Òu8tP†Ä)ïò[ ÝŠ”Ì@øF/˜üòo¼ñEc ‚:XÎøOCÐõAYÒÂ<è­>ey t0;¢dGéÎ-…7Ìž=ûKÝ›æó€:› |½ÕÖ“Që¸O²•Æþd@!yl}œç”¬þZ-G¹89E‡ <¼ž¸úʤéw$>ÓU¦®¦ØS:›bg^ÆÏ ¹sçc UÆ•V Käí³úÈë@ŽšnEŒ4žÏfâùùüƒé4ÎX®†ðã/>n¬ 6êdòhÿÂ% åÎgîÔœïÞ¹»]ØzèÖ…E¾¯œ2÷%íîÜŸt‡ƒ‡¯8ÿ"d×Ö³n¶³)64¥Œq¹O¬»RØ”zÃ:`i¥ôQr”% :âh¤ž#âê2Eãx[ßR6X}Ô©4oÞ¼ˆ=&¶›nÞ@¯” éz¤ŒÔÙZ2Y^Hó!:#Lì ЉÇAðpzµù×^{íedÊêc;­¿Mll%(h a!ÍÇyÃ1 ÍcYÀ4}ZNÉÚXpÿ¼X¨Ë3J#\\ ,]¢éöd×ôâ¶ÕÍ(žX´¹v%*ιräÈ=P;0v×Á¾ÁíóÙX 0[ÿíBfh<@¿ùïX|\Rô‹È´¯§ÅIÕ„6í U·²ËVÎö˜Ì˜GÇÔÄžzTÒ£K¹ï¬ûdäš# Ïÿ›Æ>€¹’™™Úk>f¨Hœ?¨µù[:ËÑQŽLL‹çFiúÒx1u‘Òʧñ ˆ|B­\Ó4®Ëiœ2„ZÆŽ¡c.îP}¡DH²ðÿ³÷&€²ÕÕp!ˆÌ8‰Dĉy‘Á‡ðUŒQ (1æFT1ȧ‰#Ä(êQˆŠ‚( ň‚ ˆ¨8Šð© Qfò˜ßðת®UwÝu†¾ãé{«Þ;wïÚSU­S}ºvõéÓ”Ó'*Ÿ·åó*f}©ØÜí¿øÅO}ßBžç©n©Et*hp”5£N£¤> „iÒ‰Ùܳã²À“Ä.e–ò¤ò„+M ¿S™ŸúÔ§ð4Œ]¹…ö¥ìýŒ½ÝcÖ|ŒôÔ÷,õ:öÒ×Ó'èüd¿@ÞRÑUÆi㊲ö‚+6d¹P¹Q9IšË$C77•8Å· P( ­0 V «2OÓÃÚbÒ_Ù !O YMùíŸ~[£™yñ’;´9ô›}÷ôªß_å~xíÕb^ñØøú;¿îž¶ÁÓRò?´ «Ó°ÖÂ*…k2ÒtfÿNG[}‰A¤ºö§Î®NÎøMt²¾Ñ¯qí­±ëxÛ7k‡ºÊ`¯uÏ?z­G»Å[-¶‘zQ×ÛÿÑóO~ò“{Ê<#‘W×ćÀb[Ø‘‚·‡%T¨ƒl¬Ê¸lÔZw’ì‰Ó“OÊõ·‰<¸dÉ’ÊSj|½®Ý9•ïùŒ=íË´Ã3 4éOô6é‚!öªÏä<$Âñçï7 R6ÉÀŒ 1CkuN•È#UØßÉБj0&Ž &EU( Jâ’`I„S«´¸)e`[Ú£^W¼ ¿.pÝm×ÕY͸üºMÛ¶ÿ¬{úÁs?8ãý™ËÖ[g=wÞ;Ïs›<Öÿ²Ó2¿âñ#*{û?Ö4!A§¹t"ËLgÛMãiÐlrýhðÉ™É&ëßÕ/g—“¡c£ÈmíšvÑ6`hü‚Î˾b¿û»ÁÕÍÙÓ!·ó}«ä{¾ÎMŒŠ:Ž2­+߇¡NKV™–(³'Åž ­+oO,êñbv¿þõ¯¯Úyç÷ -ø?¸•dÍ5×dµ7t»¶sç\qNxó/nŒXÞÑ_i¹?Ñþ|­X9òx¤ÇiÅJ±Ž5 çé@:½q~¦ZºÆh²›Œ®ÉGÇTg7ªœ1ëü ·º¦ºêðú îQÂc ÀßA<Ú§öh«ÖñºbAÂj/1wØd‡‰G/þÚÛÿ‘ÓùŽ¡ç<˜ø£Îü£„Œü(Ô»gᥤ¯½ÇI¨+ÔñDÁñ½hï‰ëíמ½é³ÝfOØlâˆÑø’jÔ£,(¬ŽÂ6š‰C¼QéaÛ£]Vnú[ôÿ’ï˜1è)‚@A  P$r<Ô¹IÝå·ž›¯üúw¿žè%ûÌq™:ŸqðÖϽub3á=¯¸M¿©;÷¸sÝzk¬Wýu¬Ný‘îˆ+×ði,—¤3…ÈtÄï£É®AðÈ¿Á§b^gW'¯8g*M~M:„ªÓãÜÛRg y®&ÆÐºUb$Ä|ú_=Ýíö´Ýl´^Ôííÿ1§ ùï`|¥Ü£²:ʈGÎ:ÆIx[štÖvÎë}ßP€r'€2Pž\øçÉU=d¸¼R—øÛo¿ý>ÿÉ»€Å>Q’ò¹¦ûlµOu í˜Ê”§ e‘6¾¹ÀF‹©wÚ PÿžéâÓ`[T‚@A  P˜WhrœãGlL²çjàê®®ô˜w†;ÿ|ßXO ~ezùu—»³.Ÿ¿ `l¶ÑfáN€uµNý&W«~Ý6¸þ%¯A§ÊOGÌ®1ºÚMuLÖ2í6ù4élÛ¨7Ù¢S[ð¬{ÖÐFVéJ“Ž}d¼Xßg[Ÿ{ô°Ø\ ¹r:ßU¾z”2ï# Ô“§rð(9JÙÀbŒþŽÓ€ÂJÀ•‚ç[ò <±ö¤£®úå×^{í/àÌòðÃø–þ•·>Ðáge*£D7uÔàQHÉÓ&(;ü±þâRÙvºPÑ‹_¥O*7ü¸lÌôfE-ޝR- ‚@@ &þäo¼ëF÷àR|%vv˯®ûÕDƒ¦OšôóÓÿ ó«Óc?w¬»µú Íqæ·í¦Ûº¯¼í+nUÖÈoà9\ÅzvF7t½7×7ô¥vMÔàÓi8uþuò.A­¯­×ÅÀ9%­1éKJƒ6J{PôÉé¬ÌÛ®¹úšî…;¼^½¢6W‹¹_5¤Ìù0:ÈP·y¡9êzøj× ¦ý-ãö ‰·¥£@ÆmyÔUÆ“ÎIü>ýéO_´ýöÛï†`(¸¥š´C=÷âï¢-¹s~쟀‚]t|‡, q (aTþ;í]4IÈU= ¤ü(EüÂCn×—©àhûß—çØ~ F:½kß즷™­ P(æþýï!K—/u×ýù:·Å¶˜Õ^ñ«+B{x¯ä:…k’ õßsÇ„ë„Û—Üî^{ÚkÝ^÷…$›ÕŽÏbcÏ|Æ3Ýg^÷÷Ò½Ô-_Š…›/XGiA‡_Ó…u).2®ÝÔ~2¼ms&c´µU£ï¼ªñ•c¬³‡~²:Æ&EKëäI£_3d”“B>NÕ'ÚÐßÐ&»´¾õ>ÏÛºŸ?ý‡á™ÛÿÝg>ó™ïETBn'¼æ~Ší SÞWCÅÒt ÿŽÃ['O(êp)ãÉ$å€Há Ô¯Ç*w®Ñ&‹ÔTýGéC[[mú¶1NÕ_ã7ÅjÒi b3Š}ôZÚ¶nÛµm‹}%6å zDÿŸ¼c.òœËðôäj,>g»ëøÃ=¾®¯Íõ˜ªž#ޝ®2PÖµê+Ž6ÔõžŽÃ€Ñ‚ÌBÊ“‡º=¹¬ÓV'AâùË_^©Ú'Kªn.y< p»'m—¦$ÒT8B(ÎÉTŸœ£OÎÏÚh<}šøèÀÊ(êF%LÆIGõÕ¾‚õ¨Îž P( ³…€O¨y{ý5ÿsÍlµÚ¹ò×Wº¥Ë|6‹b“~ʰ:üÂyÒwžõN÷Ý_}Öó¾ºç¡î„—ž0ñU€¥~Q…Õ©?*›\Ï):º­ÉúÒFWÛ†¾Ly½X{Ty×±¨]® •‘'µ¾mòœ1TNTyÚQÔ±âÉÖOÞz\þç~õ«_ýÔwŸù^Êí¼ <…ƒzå!S=yR¯N²±.ã¸Ày2ºR=ÑðAÝN Ú,ûØÇ>ö]‘I'ß-Y¶ æý+ûnµï tMÑ`W9 RÊsÔÛ„a7ÙRGã\¹Èõ²þ<ê»k¸ ´»wÞr:cå[–N×áPER(  kn™Ý €K¯ºtÐ+îHöQ@%ùgÂÏOÿõ?ƒ·Ìÿ{éG^ê®øÝà«ÁwÿyÓ!orGï}ô áÇ ›a€uàbÖg­Pj_°kœ®vuí´Éëâ*Ÿl;9¿º¶­­±Kç—vFŸ=×ÞfÈþuTã‚ç{Ïï»­Ï5zXðÉ¿¹ýÅÇ?þñ‹|Wks<¯³‰¾Ö9ò6ÚC4FëÒ¸nè(q’Px²Èó„*¯“u=‚îž{îyðî»ï¾Xì_yþæÏw¬³A}zÑ Ž<"n£L) ‚Ji—‰W=ýr²:úE?y¤³*úÉÊ€ÍTŽÉ¶[üü\œ†óWbË(s Ì©Í_ß"?ÉçCÍtùöeß4öWbæ/­ú÷>Ï'Pš€Ê±ä¡%îEz‘ûé øpoþ—ýa·ÿvûWïÀ~•îˆ|¨û5Se%‹÷Ûºu˜}/îjgýl½kœ6»}úʃm[ë þ#_;Úbé4Ô>äø\¬œ 1›üÙ&l±¨-tZ6x°i%_Pçƒ.Æ[oõÜ~[ï‡ZïŠÍÍ|þvûwÞù€ï(FÝšïE;=Ï Æ 9‹ò”5— >ÇCÆCOù& ÝÐñ£ýè2=³f‡IUsÎ/ÞvñÄèÙ¢DT(UÊ#_¹(dôÉ?§³2¶eåZo°Ñ„]]Ÿ.À a°eŒ‚@A  0sÄdúú[¯w÷?|ÿ̵#‘—Ü·Ä]öóÊRª’Ô‡ {ü£,}uÜyÿnßÙ×}çß‘Væ'»ò#VvŸ}ãgÝNOÞib¿ÀM“ôWÖm\S‘ÖAÔ¦¯ó³òYˆ3åõP]ëävŒS©#Ãh+uýÈÉ!k×bERöIã©.Ê÷Û©ŸÉ?ºo¿¢s·¡œÎ›R†Q¯£^•ÕQŠb‘HÇè/.«ãX¼Rð<êN4å vg¨RÿÄ'>q™Á.|  ¯›»ò•\/ÚbÔГ’' (–¤cúw\7ì‰àIÑÓ 'NO&'R÷ßù_vÛm·Ý¤íN“êæ’ßìñ›¹çoýü4}Ó›€Žhh]G¯HE>Äh±I–ŒE§íÖÙv±_~E Ó-aâWéWOåóqLã€{飿Fôô5QúUÎM™S˜Þ5àé¯nú¸/|ÿ‚‰6¸ @‰­‹<} n`S€Ø4xhùCî˜ÓŽqGž|¤»ç><ì{þ–õÖ]Ïù–3Ý:«®3± €gàN„MYÁ†õ긖׭«ê䓹þwÕf× ëQžâº>6ø×^;š|Øh]›MÓ‡ç‚õÍõCeì }­rÈü‘Öÿ´%ú`‡xô¡^êas ÖŸ·íóÜnÞ›“!gó›xe`´|U€’WÀsôÊC–+”“ælÆJ6N zއ ‡=‘*§N©NŒ Þyç}GϦlª›k~·§î6èGËi¼/içoPøõ‚޶¤Ñ´ÛèR´:y2ÁOѼûcÍ1ô§G¥'‚@A  0/`ÂíéO~ÿ“Îõõï}}ÐŽ´ÍOøIy›Jðakøé¿óÄÀJ+{Ïé‡_r;³£»ð'Îøxæ²-ž´…;ó­gºUWZuÊø•júô_W­qe›8të-]s)?ÕAuÕfצŸJ?ëb×Ém[]í¬êu¾䕵´ÆÂ9îZjÚI±©%ØRîfÏíÚÚ¬ÛÙœìßøÆE¾úŠÈñ]|¥Jž£&¥㢠¼-Ðe§ ptž$ž8R•sB€’‡A~î¹ç^³téRÿÚ xÞÙNP7×t×§ìêvØd‡ô"®ì¢sD‹HXʈ<½‰ˆ,˜¡n e¤uz+×z¯Útà™H :Ø÷ÁdœúÚ¼J ‚@A`4Â'ëÞå'œù €Ëq¹»ùÖ›Sk|X0á‹2á‡|¤A‡Mpà¦;or¿ç`wÄp·Ü~‹WÎϲÇÖ{¸õ¡tV¯üôŸTW±i H8°¾š¦5V9±ØÇ MÉ*tumŽ*Ï´“ÕÅ¥ñTõˆ“‹YÜúÐÖÓ¡5;lQĦR§Ž”1b}ÛM·uÏ}úsƒKßþ CNÆ‚\í+_ùÊÕ¾Ž\®)·£ŽTÑ/ê¤ÔyQ*9YRŽ3ÎÀ™'B)ñ§Œ'’rðöàd¨È¯¿þzL¨TúútpñÖþa€(¡[÷ºÊE¶ ‘åéC*±.Å©“'ƒéat3 I6û7=£-Q ‚@A  ÐŒ¾ðÐÒ‡š¦¨ýâ_D`ro(?ùÏ&û°E‘ä?l ñ÷Ïrn¬âe«¬äκô,·Ík¶qï?óýî¾ûù«MƒAMþ﫿ʽvÿ×Nl ÿ‰+×të¿®`±Î²Ç䛟ðeýÖfÛ ¯¬%'Z¯r þUC©MÆGÜÛ£Nß&÷ú¡qÓ‡Ôö¥©n|†bÃWmÀÇú~Ûõ÷á6‹¹šÎ~òšÛad”s¤¨SN™…ºRêÆžŽûOOêä•ê &O=ê:AÀ³¾Ì? ð›Ê‚I‡[ÛúXž·ÙóÜÆÛ8!Pù.9ºÌ#OlvjceªcÊH)'­“SÚÅFíGä‰ FŒ5Yß¹n²ý.~æ53Kó¥à^p/s Ìi™F”zÀýêæ™{ÀC?äκà¬Acæoú~?äLôM¶J[O‡6üJw,yx‰;áó'¸-^¹…ûoüÇŒordû9ÃÂ=ê_Ý›ï‘6V´=k*®hñž5Õ5Ö(þm¶mz}Ŷiœ]ã4Ù5éØv› íêÆˆyÔ¦CÚëVÆ8ˆI]ÆVs†ÖßÈ=+ÿl±ä`v æjœéšÇa¤”sôDŸuR"EŠÑ+ßC4&ߥqÛÀ‰`ÉÊp2í e:NCüï~÷»»–,YrÅÄ»÷Þ{Yí}áN/ô‰H‘jO)#Z¶.¶ÙÝBч—êŒu?£Kîuòd0ó ?W:Ý­jl𥠂@A`Ö`òÌ}ýg¿ÿkÓN¿òí¯¸Ûî¾mà£m=ì§ú^ǯ†EÈ’¾ñàWõw„¯ø;@ÿtÏŸÜ?þû?º­ÚÚöÓæÕF~ðô7Ÿîžø¸'f¿’8YÉjR—Öi³± ™bSZCÖµ]'Nþtµ—Ä6ùÖéD^7‚BÇ#52ÌÔúÁ”ñ-Õ0FwðΫ¶W›Çù`´°!¥½ÖÁ³€·uó‚· =uœ»ñÏ7ú7Æ·ÙtwÊ?œ2ø)@| À¯ZÓ/øÕªòX…uœ®Ã”ï‚Ã(öm¶ ú´ÞìÒ§œM]ì:¹ÑdפCœ&}ò¨;}Hkúšõc\ú²nc îuš+¼K?ýGî…ŒÅ÷{9r4_Êݼ yó9ð@”ëDG©7ã™;ÿÊ8nà±äxž@=Á*' )í©c}Ê-·Ürµ;Pª›kþ廼ܭù¨5SWGޱizÑs´9jÒº‰—^^gÚ«ès¾”ÕùR_èй´ç¶Ô‡ç{Á¤`Ræ@™e8‡OÇo¸õ?¦·œtúIƒd¢.±ÇªºXBRϊЕVD#¾×ÓÎô÷±àî(À†€?ô®€´!àŸù÷ßéNüÒ‰n³C7s{Âߺ‹:3› 2Œe_¶çËÜQ‹ŽšØð Ï@~„uš<$u{g@혓޲k³mÓ³MÐ:ÛQ別EÛP¾.®ÚÔñê˶ºØÂ†…öŒEªzÈ(‡½­3)|=Î}äÓõÏúzýê\ݱ۰ìe±¹×Í7ß|r4ßY‘¥Ô“B„H‰ýX÷&Árå)+ŠKñ¸ž(K9.Èõ¤ê §\©N¢ÄŸ~úé0 (v¡0ç@÷ñ8hûƒSÕ¾²;H”tÄD„¤ ©—§i¡/mY6ÉuëË8£ÊéWhA  P( £!€Ú]}Ñh~-Ö·Üz‹ûüyŸŸHБ«ãgýb{á{ðHÜù4ÿ¨ã×B´G…¼Ð«WȘø#ùx'ïw<Ò›GùÒG,u_þþ—Ý>oÜÇm÷ŠíÜǾü1wÇ=éQOhulÊÿîƒn˶œHö± °Ì/ªüê5%üXÉbeŒ²¦Ò¦WßQlÕ/òSZ/fâeEu}¬“3H›žv¤j¯<õ "¯Œ:¬¥µˆmÇzòC]úBÆXª‹Æ8`çz™Ó ÏBÎeホ¹Fˆƒ9(yêH‰êD‡¼…BRÁÏ«26ì áIâ‰SÊ @ yP0Ê/¿üòËoòž¸›áøʾ–ç<õ9þ½Žu)úâ¯âŒA¿\:P´RÓæP;V¥ ‚@A  0}Äe^|íÅÓ×G§ÿáçц9¸&ð ä£OX»H?S'%fÚ ??ýÇ­ÿàuà‘>"¿ <6®¹ñ÷Æ£ÛäMÜ¡Çê.¸ô·l9–ãQVÔêœáÖzäZnÅÃ~!ÅOýã 6lp-æ×cá®O­mÝÕ¦gÐ.¶ 6iª1Gáb§0]l’±0m~V¯uåÒÖÙ å ä©#µ:[§(cxšÅ–¾¤Þ¯»Ý7ß]£ôŠGÎ%߯Fv7r3ßIf7 š»)ÏlDm)# ¤7xå){ŠKç¸=1äAqðD“'¥\'xГ']~©/^žŠ½%)zÀlöøÍÜ;˜Pºè!PÖµ‰:õÁ$VDÌ[êéâ;ûrc{uÔÆ®³+ò‚@A  P(ò0y†6&×ß¾úÛÓö„ü?þÏÝ©_:µ’ø3éOßÕg²iöSMüÉÛ¾Çz.>¿ÀOÿ™ø;Üà“½ Ô½²‡ü¿s.9ǽàí/pOyñSÜq§ç®ýýµy,{&}úFOw'ýýIaÕš>ýw`%›îÀzÊiS㈲¡!²öêbÛ`“ÖˆìDí¨rÆk£uqáפë¢×¶5–ð•ñC.ºà^SÏú©-×Ûì'c‹MŠáe‹wZì¶Øp íq¯x›sýð‡?DNÆ|9›ò¬S r”2"Dê͇Πdc]Æu@O Në zðäPÆ“K 9x{¤¤?êBÝ?hâ~÷ |(xÅý÷ßÏjïèsŸþÜvdÐk‚^šPB!ŠƒZ¾N핪ŽrÆ$µ6¥^( ‚Àô às`~Â~÷}w»oÿêÛÓ÷ø?Þ=øÐƒ• €øûU&}~ú_IÜE:¢É>¨³§§éNÈðÄ‹ßùɾOî± 6Àó$þØ€Îl üÏÝÿã>ôŹm߯=ëUÏr'}á¤Þ?8ðÐE‡ºƒŸåÞæW¨•M¬n±jÕU®_o……°îb©ã©Ÿ ÕØmqêlëämñ¨¯ó¯“Ó¯‰æ|U¦¼Æ±rÖIÕ–ð{m¶×D7ˆé„&Lw½T¦?ìàƒb}sõåà¯ú©¼ŽW{Æ&­ó)ò‚@A  P(º!ÀäÙÓó~¾»÷Á{»ùe¬–.[ê^óî׸å+ü2Jâ¦Oæcbž>ýÿKu}H ýÙê¹B9©oíUÚä&yG@¸ >À~- ÔyG6°QÀzÜXñˆþ¡û§“ÿÉ=é…Orû³Ÿ;õ˧º[n»%×Ã9‘=nÝǹS^ë+Vó,ÈÒ­ÿq<ôÕPÈG)\¯Õù´èÓš³ÎŸòº8urú6ÙLV—‹kcÙ:ûdå¬7aÚ±mÖI5~”eñ…Nè·×–’+0VOhî§×c.ÆÜ è)Ÿ«C†£WJÞ¢‚:‹ò”=Å¥y\‹=!zò”×ñAΓ Ê§î¨Ø\{íµwÜ}÷Ý•íßô·½õ´ì°ñwø>V.Šxʵ‰:õÁ$VDÌëêÉ\ „ m²½: {u6E^( ‚@;1y¾ïÁûÜ™—Ùn_cqÊžâ~vÍÏ*Éú¤ß·ÁDŸ·ç'VŸè)øØ§š¦ªbÚ*õ|e±q ñÇ×|2_ùZëø*€&þüª€Ê`7–­´Ì}ç§ßq¯ÿÈëݦ‡lêöxÍîä3OvÿïæÿWíãÔ|ÖîÅÏyqXÑVîÀJÖ¯rÓq=•¾ À5i[ß»ÚÕÄ©¬EaSoTyM{C⺸M}a&_Ú(¥=iÔ% pnPŒ>Õ)4ùÑrÚ¨Lyc“bxùÞ;ìív~òΰîe±9r0äb¾³š·Å^‘Y=ó9 ^QÃØ‰’¥Ð±XÊÇŽâÒ8‹=yzҡ㉧¼Žêäìþë¿þë; šœªë¿çf{ºaQ±ÓØ×õ¢}i ãppZWžzRls¥MÎ6êìr1‹¬ P(  ŸÿòSzŸ'þ#~dð þˆØ ñ×ÇÞ•â¤ØøT_’o&ùÜ }PíS·õ¾öð1‡î@;¼# ÷|€˜Øóki3_`â/w$;ï·üËÝeW_æÞò±·¸güÍ3Ü.GîâNøÔ îÇWÿ¸òÄò¶¡L§þ¯þ€[gµuÂ]¹M€ôÑÖP\ýr]Õ¥#]Ö^]lØVmœ~m´Î¿NÞúœ¯•ÙzÆ/¬µa—³U{œ-êc}E—Öò9_±ƒzÑ–‹Ôªw¼Í±Î;ï¼ }'9s™›1_£¼ŽbôÐÚ±NÚ;¦»C¸,Η‚“f döDóäò¤S¯uðv2±¾ìÌ3Ïü…ÿ>ÊlléÒ¥nÉ’%¬öŽî¸ñŽnßm÷MšÊ…h¢÷Êk]ä)dM…zÒ:[«·õ&?Øvµ¯‹Sä‚@A  PXhøúú?_ï¾ñ³Ê·¸çÞ{Ü¡o;Ô=°Ô/…˜„#ùŽ·ø#¹·Þ“"I87§õðEaŒAm´¿Cb¡/ÚŸÐ~ìG¸#€_ g¤¯ð.Ü%€¯°Î»Œï.¸ê†«Ü{Ïx¯{Îß=Çmò‚MÜkÞ÷÷µ‹¿æî{à¾ÑÆ4ë¿|ì_ºwñ®Áêׯ\í&@º ®z‡¾ дžjÒ±Ï-6iýû:Û:y“Ûïj£öäGm×Ú·ÕÙ)íI)UYäv¨ëA?ÊèÏ:h,cïíûýé?r+äX,ȽÎ:ë¬_ûzÊÉ"ŸËÛ˜×aôäA‰JŽ÷êJä*ò±¯Œû€=1<©Jq’´ž<&e œX–§Í²Ÿþô§Wx»Tì*’¢'ÌžÏØsЋêZ|]/9Õ“gœ\Ýêhªñc=©á×VšlØn“M[ü¢/ ‚À|G€ w¤ï?ïýïxxéÃîÈ>Ò]÷Çë‰;V’8+òL¼E²íu¬«-øÊ§ÿ“Á>Ž#Ä5üÐ׸á©ýj@HôyGÜ“þʳ [ÕÜ  }ýÁŸîù“;í§¹—¼ã%î û=ÁpÌîßû°ûåï~9™Žäóªý_åž±á3&V³\ÕÆÕnØ×Mé«l%·ŽÊÉhOÚb“Ö—°o±eÈ íâÓd3Y]¥±Ò &Ô“&7/€ÌÈ£zBgõ]|BXëÛ¢¿¨÷Úb¯Ôl›[ÅÜ+Îâ”·qv׿l~lÐaäÌã "be”[§|,).ÕóµðDÙÊI9yPN RÊH)ôÄOüoÿ“€Ð…‚‡TÜwßìíð²Ý®t§Mvrl@ºà ]„%e °NLP Ì€Ú¿Q.r¶nímö]åj_*/|A  P( ȺÓñ³?üÌyiû³(ýž£Ýyß?/%û)éI¾~Òn?õO¶¸Sí£°ƒÚ„œõQ¨‰:6ìC±úåFôüjdøt }LæS’» Ó»Võ2n4l<°ü÷í+¿íÞ~êÛÝŽGìè6>hcwô¿íÎüÖ™îÖ»nõ NoYeåUÜ Gž0üéÿ2¿0âj+XX+‘Ö­› o+-6•ugS¬º8uò¦XªkòoÒ!†ÕÛzΦIÆ …=JM=áG_Ò×À¾Ô‘F±xÇÅî™Oy&½{G‘SéOÿ!çBîå;ʬ”³Tåà9»IŠòŠøQp™›O…'ŽoO¬Rœxž|L\ò¡§”“F'R’û]©‡o¸á†k6ÝtÓͽm(øE€5ÖXƒÕÞÑ}·Ú×åùƒ‡ÀàÍ#µÅrÅJ+ü{²‡#šŠ¨Ú#†êX'¥­©ã"âÃ:cGñ”¨Æ×¾N)hq. ‚Àø"€÷`½ýûÿœóÜ v|[cÕü:Ÿü¿æ¯ I+>ÉOŸû÷ÕðÉ>Þ_‘Lǯ$ªŸþÃFP…À}¯H¦öׯóͬ´Д(¹ò¢p·TqúŠ1-÷Nž¦Ûç)ó¶Iæ}B|¬›(GLø2¦ß@ÿ§»þäÎøæîŒÿ:Ã=b¥G¸mŸº­[´Ó"·è™‹Ü3·|¦[õ‘~gaŠåÀgèv|êŽîÊë®ôðÍb]ç7Bð•€pî}GÂxÑŽ_cᜱ]ôÙû…¾SÖ•ÂWJoÈ>™ÖÉ›|’ó$ãvÍvÐÇ\?U¦¼ø0?P¬ ê<‚ÔiK} ñkta=¸^yºß¶û±•^RäTZs!÷ò2 ˜Ëј¯Aσh@ÞÊ©ÕB¹ÊæËÞ¸{Ò0ž8Òœ :NN$N ¥:¡Èû“O>ù|}óÌýTîKÙü ›»—<û% ì…UÔXç ¨‹4]Ô)ÏÙÓWu°×z¬ÚYEÜÚÙ:û9Y¯Ô ‚@A  0® Á‹ÇMwÞäÞ}λ³#¹þæëÝ>oØÇýç7ÿ3}—Ébå“sŸD¢Žd’4|¼‚•&èôÓÈÑ> û2¨Mý¯Æ#i¸#ý›Ú¿ÀÇ1„OÿñQY<Ò§ýþSÿ¡gø¯¾:àíƒm¼c`è®Ü5¬¼$ø“ë~â>ðù¸çÿãóÝö}‚;äØCÜG¾ð÷³k6¥‡ ›A‘~«\¿ :¬‡b=­ÿ¸F"õ&‹ñIëD0zŠCÛ©b˜:5«³©“Ó·MO;PØæìs2ë‡:pF±ö¬“Ò&Ök×ë´E=c4_?d·CÜ–m\úøþÓOÿ‘k!çò}‚•\LdÐåØRƒŒ×L G]ÊÈçUÁ%m>œ0\îyB11PÇo= ÐcbøK~š\s’)OÙ²?üá÷ÜvÛm7¯¿þúOð¶¡`®¶Új¬öŽî¿Íþîk?þš»ÿáû'ú4Xˆ˜¯ã‡]â€ä(j‹º—㢒v‘Å? ªöª ®1>âh1vCqhkí(ïJáÏ¢ý¤¬Ð‚@A  P(ÌgðÞÇïˆNùæ)á¡[ÿ´øŸÜ_<ú/Üonüûâw¿èþýœ_sDÒŠO’‡ÖÞ7$ÓXEÉÁ€@aƒ_@{X}iÝWg¬ =”š5×/zGC°…=†Š»Ð_¿ 6‘ã… äþÓód‹#ª÷Gî΀`Ï»`»¼í’‡–¸ó/;ß©Ïw¼è1k=Æ=gÛç¸Ý·ßÝ=wûçº-7ÝÒ=âèD{Ùe‹]~ð¼ËýW6иŶ <^†Ö}8G¡2 Cç:Š»”tÒ8¶Ãj¢ur4é ‹ m•ŽâÛœ½•Ùzlo íxœ‰‘æ%u¤°¡§•ø”«-x/_}ÕÕÝÛHM/©ýî?r-ä\¾³)«á"l@É ð¤ÔQF´H½éü/+…‰5ãäwššæåáxIC—;x[¾EŽZîå:ÜweGyYîXu×]w}Ò±Çûw^ŸÊcó·êªS¿}+œf挞áNûîi$Ú§óIôÙò”š6 ×å)­“«Ídø™Š;™¾Ÿ‚@A  P(L'XêÆ#<%¼_6Ý¿Ô ý ·zŸ&Ï¥5ŽðŽ•U\añSó …ŸŠãw®Ä¼ÏÐúÛÍJÁxQH…O tÔkªàeê"åf@J7`ÏÍÆ´¶&|C”ÓÏÓÇ®ûX·Û6»…̀ݶۭuCà=§¿Ç}âüO¸Û—Ü>8xVÎi¼kƒ+åpŽ€ ÖB£¬‡ÐO)œ#Adtb6sEè+M>´m²™¬Ž±•â\䊶¡‹‘¼¦ßx¾l½Dñ’Š·%R¾í€Æ·£°€ lèÁMMü!³õU?ûÙϳîºþŠËšk®éÖZk-V{I_øo/twßwè[Jò5á‡Þ E—P÷²¡MءО|F9w›ioô¬¦¶’ 2ÖÏê§ZŸéøSí_ñ/ ‚À(ÄÄËÜ”°Æ¥17ÅFtØ`"Ë%2ßßAýªªò‰?“̸⢮’hòý•qFÃtØê²ž¼Ð¸¡Þp¤Ä˦¾tÄ 1"Ÿ0§Ô)–ئs„ñRNÞ××]k]·Ë–»„ãY[=Ëí²Õ.nÍÕÖ„E(—ÿúr·Çë÷¨&ü<7Xýò¼aµWÌCë¾A¨æ¿è›”)'ÿ+Œ[ëÊ›v“ªNž „i³ÅùÉëWSçÛúÓVcCÆl|fDp¥ÜRµ³ºXq¼ÝÚ«¯í¾öÖ¯…p}ýƒŸþ»÷Þ{S÷î¹çž;?ü𓼀ɽnØ Ú é× ?nyn)ÔA_ ²i+<Óp’ðÒŸï'o-<¹äYç Íœ(utù9çœsÁ‘Gùr‰'W®¾úênå•ñ®×Ïò²]_æN½ðÔ€ &cØÁgW‰¨/AÏ$]ѨèCÿ'úP(|Pr:/Æ›D¥ý`U¶M=iœú©RöqjÆ0Õ&ŠA  P(æ${aQŠ÷7$€xÏCRèo}_±² B/[æüÿðF|ï…kø2™Œ‰e’éwíiïÍCñõ9{oEÛ(Ë 6ø‹~âöÿ?à(ä= 6¨ûñ;bÞâ¿&€•fð‰«OÝ H±¼.µI{¶I]ì>ÌùÖßrßúÑ·B_WYe·õS·vÏÚÒoø¯lÿŒíÃztyØa€“/Œ¥”rb ;þA)œ/Adtb6èGE©LÆ¿ÉÇ6Ñf‹ó”+ÖÏÖ£O89ÈêbC§ñÀó0ºJ|úÐÖÓt.<ÿÒç¾Þ½-Ë–-úE5äX¾Ã@ª.£6¹hP.Èê(¤ƒÚø;_ïÀ©Ã%Œ.Çà‘‘Ç·¨À£Î·)~Ÿòƒ'Å'þü䟔w¤úç?ÿù7ù_XÛÛ†2wñÉ#Üoÿcèï¤ï€7EñW>Í'úQG›p&BeàÔÜ`€–¶:m­å3MçªÝ™W‰_( óY W>Ù÷Kåt»?>õ?¨.£¬ü‘>åçFVYä£M°Ã{>Þ?ùJª1çŠ×T€<©ïSJÌ)Í;è]´Ó¤?ÈTŸP‘ãœðÓàL[°M‰`€6ü¬ÏôÜøo:Gàñ5žœÚbÃuž­-è””pBftbÖ¬£ádü›|—´‹-ÎM®Xß\ÝËÒyѰµq!ã–ç~´¥žTí(3”íoø¸ ݾî?­·Å~úï?P]òò—¿üƒ¾ÃüÔ?÷‰?t”ãSð¤øÔ<6 Às³¨‚1ðŠœ¯¦ù´ži 8É@x©Ï—Òt‚¨ãÉʼnÖrž|i¼Ö©_vá…^äu©àç+úr’S§ ó²g¿l0ݽ<]hˆlÁÇR m¨'…­òZW¹òŒOG«k«Gº³:kýã1k–† ‚@A  0}¤[¾±*Dîg?ÑG’ˆ'ÚÇï§/Oâ#ÿ‘IEÇ„ÒÓ\2™ÔØH,Y”§l.©&½ä…|hé˜0‡Ä9Ž—/AÏ#È€U<ˆ©~5Èð+Àš_Lõ7é/ÄC\ÆJ >úCÌyF®XÍÖ»S;£«$ÿjgyãgÕ­õ©ú£.1êp±¾¹º—eñ°¶¹¾¨ yPðñehm„P ŽÔ¾¯¿l7¿æïqÁXìOÿý÷ÿ÷E¾Ëµ¹WÔ1³(@F žd8PHµêß&]ÕrÌj¸|Ìד†Ë6x=0fêA9!H1ÙpéÔ:È8)[vÚi§ýdñâÅÏ÷ÿ ?€ÛXð–>? `ß-÷ußüù7ÝU7\Þ$Ò…Â0ŒÈa´žâ /ìXC†Ã ¨:[§=å¶nåÔƒZ­Ó¶NNýLS´Ï’ȺB ‚@A  0×è{–ïKZð½ÜÓt«ìkúõvºi?ÞY˜|| ŸÖN$-hGãÄ6ÆŽ`±T0ÄØx@õëÀ Ÿð*Ô#i÷ª § ~§;ÏRö má—Àb-Å_7HmÄ6SÿæÁ§öO‹MˆsnñK.uvur86éRàŽvÀ;Wl¶Ÿè›æƒÚ€g]©‘ürz#Kvô'E?Àû¾lµéVnÿíö‡¤·9r'ÿKüÇüÇ•¾žr­È³”Ák2P=5¯ªÌtÕ‘‡Í¼.xÉϧ’;q*“‚”<뤜T](b,»ôÒKèi*ãpÀ‹v|‘£Πä,ä­mÔ§ ‘Ú«Ê ŸÞ,hOý(t*¾£´Óf[ƒO›[Ñ ‚@A`V`’ |L+·‚ó“m|ÊŒOµq'@ü„:}*'Éóio>…Æ “‡WWâ³mÒYðA?›ŒÓëyg@ØüàØùIÙ3†Í»B;ìu]ÒI}_©àEÜr´²@bóÊ×°±”À ÎiÓÀž‡·I›ܘ‘Xб´!lÑ'œ_n Þ¥´¬c*É«ÆkñK¦]í’ƒgFñi³mÒ[­£O9ûJ)å9?ØðP;ò^—°ÎÅ‹1÷Úv/·Çæ{Ы—Ô~ú\ÊçTßómͽŒ 2 æoäA‰¤R/n<[ÐÏÛ‚KÑ|.z¢•ǘY׉A^'ò­ñòË/ÇŽU*ØÑZ¾|yx‘â…ÚÇã íò`x8ˆˆ¥•i=vÀ¤XÖOíˆ*ãDä+·µ©=c© ¾¹R'ÏÙÎ…Œcî{?ç›ÒfA  P(Ìšô÷GJÖ™¬"IŒŸü§DRX& ñ;ïÁ†¾mÅvfo3ØÇÒDk|f@À–Ø€*ŽÂ¼Oêâ†7 Òy‘‚Êæäâìq'dÚg_ ²¦Ò²nI ©Ñâ—Ì›ìêtuòT˜6[èël¬ÜÖÑ Ö²¾„uð€ õð'ê&žc{ŒåiCÚÁ™<©•Iý8x§ƒ{™{0BŽd?ý¹TkÎå‡ÊlÂR QR^JzÚA· Ê|ú=az ÓKx½ôêå—I=¸· Чýó‰ÿ–ê/ÝÙgŸývÿ3,ð ¿€£Ï匞áN»è´‰7~‹Z¬WvŠÕƒ“z°ã€)WòJ…OþðÕ‚3¦Åê»êÔ®O|ÓxúÔÏÒ—‚@A  P˜`é‹¢K`ÏW6ä©S[øè{ÞŸQ—£²fP{õƒ|¾â…q³>%|Ö§¦ì©CZø”‘FU <'¨€+á´!¡2½#€ç qJGΦÅ7¸4Ù4é´½&»&cX­+ûšzÂAõä•*Ïx^V9¿56h{ÈNm¡÷?;yø¢ÃÝ‘»ÉÑõ’âÓ,øôÿÅ/~ñ¿ú:ŸîÏ'ü£N™¥|ò?îÂÆ'þëÁÍ„ÜFãáÙPˆ&ëÓFÓü˜¶ˆ“ dÓ©ÉEé·—žTò¤è9yP;1l¨ŽÂ~™½ àÁ1Oû]{öanƒu7¨¢¡ÈÇ0È+5Úà°e!OJy „µÝÉÄèÒÎ\ÙèØæª¥Ý‚@A  PX8h’'|Jc²’F~šL ò¨#†?lòÏ™q )ñ¦D[ÖZCk> ÐâL›lšt]ÛéÃÚh]y´ÙVÏõ‹>¤2dq¤}´Imk=c³Þºëõ>ù6Gò9Ôe^Œ<+äT‘oÊ»l®¦uEɇÊf´~Á\Jɼ<Òí!:Y”ï:+óÃþðwõYž¯ìnõðÞ{Xþâ#åâ”l-ò/½)‹¶C¾Ôƒ2yœ1ÈTN踎Ɏk\ÇSú]( ýD‰ ÂH™œòãFj}‹q•‚Ÿ…ïÛ:6âÐolž¤ n`Å΃›.žV¾À‡1B¤Ÿvð‹|úcI¿†6m:¬?ÒzÍ71T:ø­Ý4HØ7Ù5éØV“Õ5Ô´±TÛSç+¾ÐQO¡ÉVdÊBØ^‡©¨—<>ùGŽÄ‚ÜÉçPùz%¯êPG&ÀœMó8ò@S³¢KêÕ «àå?K— À€<' inB5NLÿð¿e?úÑ.W`Çáößz·ãSvœ@‚ˆ.<*#z¤Ô)Êçô±D>]àTglXMJÆVšŒÆ˜Ññäðã¡•® ‚@@"ˆ’¡)1ŧÔÐ3yô4éðuêa£‡Æ?ß ß£»ŒKqQ˜²ù„m݆’zØ2Ñ÷´r‡@<'IÆ» è_¶Å[ÿ½¨kIë´œÃT×*]ý›ìštìsΆ2Ò:[Ñ',(#¥/(d99m¨§Ò¨Zƒgl¶yÊ6î íbÔ^RŒÃ~÷¹r(ßᶃ9i.W‹ˆ…á“'ZM˜t±iò öB±'Sëà1ô²KiÛDÒŸxâ‰íâËÊ+¯ž€ùŒ®µÖZ«×x¶ëaîÇ×ýØá÷aÛÀ›C—[ ( ñK‘dXësȦ£0»@:±ç2Ç…>Ì—1Í%ž¥í‚@A  P À÷RƒKø”ØÈ†ªðå{9ߣjâ ùŽ›`¦Ç%X*öéAsĸ)ÖìeªWYp‹¶ÅU1|jJJxkôIÌ~$0uº:¹¸¶É®I§q¬Ö•‡­«LuäAÉÓ–uê< çRêY«gqq¾PýéO_¹hÑ¢Ý×Xc5}=üäÅ# @QïèÛè.¹æwåï® Ä€ÐŠ Nåy°#â°%O¹­Ó†rïÚ@:°þî‰p›ôZh§²&^b6™lY´”oã7üK ‚@A`<Ð÷Ï™ÁTÛÈ­Sšbæt1Žèg=ù—¶‡àž¬Ni åacëôSyä+¸PŸ£*³¼ÖÙ>d”ûÌ#m A]à}}»§nç^´Ó‹úÿµþó›÷"Wò]Ö<ª 4˜—ð m‡7I6àYà·` R¹…Xx’í$ádâ„ÒºòMS¿ø³Ï>û¿dì|ùÛ]TÔKþ»¿Â¿B•ï"Y¥Êc@ 2= ÷¥k ü¥­•¡Îø`ý&@("Sý@ÿªMEá+M:kË:|xP6Δc™ ã<îÒ÷‚@A  P(tE€ï•]í'c7]m qçÁ~°^Gsv”EšÖ^Fž­6­)št¬Én²ººø6ž­ÓOå‘Ïâ¢vðEÝÊbÌÊšØÚ°®”|ô׸ˆuÔ^GQÓ[ŠÜÇ~úÿÕ¯~õ[¾ÃšW!wÒ\Juà5³¼Õ5=|U‘Cua–…°`_2¹3ÍÉyRN&Rlñ¨¬çœsÎÕK–,¹[¶;`ªë ¿ù6w¯Ü땃ěhdèŠå^HTÐyÚè@¢,]0l’lêŠê”Wû:9lšt#ÇÃWœÍ8ÉæÓXÆ ÷Òׂ@A  Pè'|_œéÞ¡é.³.ñ‡…úAmèoZ³ i2mת›tjÛd7Y]]|ÏÖé§r婵rÔd×®3‡lé)ô¯Øûn˶Ôõ’·¹r£/}éK¿ôE.•Ë£¬ Ù†æcäA 2^2! •†?ð]Pe!lØj'ˆÖ™Æ*…žuL°Üa'(l*²ÓO?ý<í^cñ@Àgê6^ãAׄ-@Æ—°“I=¨=Fr­“EaœA­R¯¼Y;Ú+m²iÒiŒ6qx´Ùö]ÏqL6}oé_A  P(ˆßYŸ):Sít}ïî`WYoµáЯI§q›ì&««‹oãÙºú‘› 6”[ ?•Y^ë´…Läé.Ê`ÇeOÜà‰cóà?»s#Í«*¹“êP>eôa~4È+…¼îðª…[æû3xfqò¹ßI)uœ “Õ‰„ ‡ïöCÆÉ—£˜Àážþ[ßúÖõý×ý§õ×_ÿ/¼,¼V_}uV{KÛí0÷ž/¿gð|ŒœHrç˜h¡®zl¢.hṌ#º€<åð§Ž¢ÜóD·JiÒU §¡‚¶Xt”Õ± ßã>žq¾ôµ P(fû~7S-ÏT;]ãv°«$·]phŠÙ¤ÓØMvM:¾É–:RúÚ:å6^´«àC_Rú°jøôåêC{¥Ð£¨,òèËßîñ·}ÏÿÚäÿÖ[oýr#ßmäQšø+ŸË±ià€Ž<¨"ä«©N4Wà·àÊB¼'Y'‰å9‰r“‹2N:;1í¤­Ô?ô¡}Y/ø5€{ï½·÷“n¯Í÷rûm¿ßD?õ¥Bô¨QA™Ò ï€~ë®f Ü”qŽªS^Ûkâ'ãÓOuˆ­‡êÆ‘ŸOcGüKŸ ‚@A`ú˜í÷4´7¥kÜvimÕµŸM1›t¿É®I§1À7Ù6élÖÕ'òY|¬ÖM¬”üS {{Q DlMÙg§}ÜÞ[ïm¤ý«"×Ñ_@ŽþgÿÎñ=µy”Ö+9T´µyê<˜›1Ȉ\ŽzõÂ. uÀžuL$ZçäRª“¼¨Züµ×^{ûõ×_ÿ[fÁ/ŒCyÕž¯r^ãÑ„Ða"¥¼— ]i§4ú$[«ƒr-¶NÊ•§´NÞ¦ÓSåÑS5×þG®sÝÇÒ~A  P(,|ÿ²ò™ªÏT{£Äíð^Öd]q¨‹9]ýª‹Ÿë_“­ê”G[gl•+O}Î×ڡάOzS{´¥žõ?Ùª\m=¿îëºWïýêèÑobsäBW_}õm¾×š?!WÒÜIušsi.Fžèò (¤ƒZùXHvp‚ò´á„ÊQNBêX'­›¼A~üñÇu¹/œø=Lÿ V{K‘ü½èèá ˜ENëDSGE=d9ž>m²KÑm²iÒ šÚã1 áæ4ÇA:§) ‚@A ƒÀl¿GÍd{ˆÝ¥tìCe=Õ·)f×~¡&Û&í_“­ê”okŸmˆO#Ê›(tªWžñ•Òž:ðÈŒ }yÕâW¹Ç¬ùXõº ÇA®Ã‚¹¯#obÎDZ—KAnó.ÖsÍ5PÖµÁ_êT¶ ø…´PwByòI3/µô¤”“TiÛ^ê_÷_á‹v?‰¡/Õõ‰ßwë}Ýó·y~¾Kò²JIʔ›õÀ¢b E¤T³Nêå©-Ú€Š^ÅŸ¬n(Ð4 Ð'=¦1ôœ„Ò±4á='+ ‚À‚A@ßfkÐls&Ú%v‡÷_¬¡²ë¨º¾7ÅlÒÙxM¶MºÉƱ1m]ãftŒ¨'¥/뤔{šýÚ+ìì?Ü¢Nâp}»×v{¹ý·Û_5½ä‘ÛØŸýCäs¡|‡[s&o£9yÍÅÈu¢9ŠÊ’ò7 °Ð68xú9QP'OPL {`BFJžT'5x­/{ï{ßûmÿ[˜•{ÿÇáü8Ü+÷|¥[kÕµª/)E,òé'ÈyAüãeɶFŸ^¾p)ê2vTåbtÒ%£fˆCÓf¸ Ó~¾gZÁ)Á ‚@A`Z˜«÷¶;­ƒ‰ÁF‰ÝÑ6­ºöqëJ“Îú4Ù6é&ÇÆ´u«ºÈgq²vZG<ÔÕ¿Noä©-ñÝcÝÓ5W[Ó½úùãqë¿Ímû òcÒ¼ÈæIªcnÅ\Œ¹)å¤DT« *ñmU¶`ø…¶Pwb9 Hu"é$¢œ”S)'.)u•ú¹çž{¡v/û„LÕ÷…_íõÝßïó÷ƒ¤h)Bu<@{ò¬ÓGåÔA†ÒR¯\4Ã>”çâuÕ©ÝlðÄÆŽ6Úž‰6t<óeL3S‰Y( £!À÷—Ѽ¦n=ÓíŽò^ÙÑ6­™ºŽ¾)n“ÎÆo²mÒM6ŽiëWu‘ÂImà›«CF¹åsíÑ&GÙFÔ¡?¯^üj·Á:h¤^òÈiì@Ì}˜Vr#©[9}˜‘ZÔ(&Сjåo@`!nä&e <xN&¥œˆ¤Ð‘åÄ­£Ë>÷¹Ï]u×]wÝámS±/”¤è³x›Ånßíö­öJŒštá´ˆªm䇞Œj}Sý´ÛK„vM6SÑ¥†f™!&:¾Yî´7§cšOãšv JÀ‚@A  PB@ßC†”3,`Û3ÕÌ(ñ;Úb]–Öf]ûØu¥Ig}šl›t6NS]ã(ßäÚ*¯~”7QêbÌÆ[ÿÙnô©œ#}Ø{‡½Ý; ’þ²6§A΃ÜÇ÷˜ù’Í‘¬œu›cA®9y¢ÊQ>”¯~õ«C2ê ]ˆöÜrXª :”ƒrr’*åĦŒuÐÀûŸÀ8[_ðãò³€ðͼÙm¼þÆÕ—•"ù4>«cÁP|½öBõÁŽèOŠüÞ”µº=ŘôûÅè˜ÈÏ—±•q ‚ÀÔàûéÔ¢îÍvAgª°®ñ;ö¥²Fê»­ÛMk•º6»Æ¡ûœMN†˜*¾‚夶/*üÐ[l zÚÓ–ëWÕû6ØÈ½ýEog˽¦5?ûw¶ït.'Rs%ÊH5çbF´H)'r9ÚkÜf³s«Ìfc=j “e¥šþp"Q:&ìyp’brb#xLÞ• oëÁîç?ÿùŸó›ß\óô§?ýÞ><,cµÕVsxDÿ÷f^¿øõîõŸy½[i% Ñ$²DÊÓ+­ØEŒ4cÄþ"â© xõÑ:åÁÄû³3"‡y¶4Ù4é²ÁæPˆ¾²ð\°>îTdž±Ì·ñûù)ý/ 3‰€}˜É¶êbÏFFm££}úpEÇÖæÛ¤oÒiàÛlÛô£Äc,RõÍɨ§Ž4tÛWX·~Qnë^ž6hCûL=Ø6èÑlŽ9蘉¸h³§?tfüwÝu×]‹œÇw9}y&ø*g.E©æ^–Ï ›¨|ú?À¥ÿYfþüM·4÷ÒCœ`Ô£žrPLLÖ9Iu"+=ê´[æ ãkË–-ƒ,¼Èí ‡º¾Ñ­6Úʽb¯W´w‹è)U/+g6Ê×Õ5Vp“)Q²˜¬.èCÌH{Ö½)w‡ãR:å %@A  P(ô½¶ƒŸË¾ÌtFgGû¡ä¿Ëxšb7é,Fm¶múQâ1©úædÔgtC˜ÁVí”§Ž2På©e¡ )å ôð½wÛl¼MƒETÈaÒˆïrœw¾óç‚•Cs!Í“”‡½æWäA)yÔQPG!¬¤åo@`!o4M;iPçÄÓ ©2Øä9Áí„f}©Hƃ\pÁE:ñ½™¬üH€ª{ŶëaîI”ƒ>­aéJ;¥AìFV©{ÝÆ¹±{ů@”Þä.ö»ÿÈqëøÎ§ÜÇóš'i®D¹¥Ì·H¡'Q,’©ü-ŸþO€±7&PpvâpBéSÈ9íDÕºNlòª_ö©O} ¿‰y·vȾ€T×7þ û¿a°Û§èdxÝLcP;c={†¥#Š¡¾!ùøFªMºœ}_e‡}íçtôKÇ©ütÄ.1 ‚@A`tôZ ¾/Eû5}b{]ÛÁkŸ´þAü.¾°i*mzõm³mÓk,ðMöÔ‘ªoNF½ê"Ÿ0£® 56!eì;ê*‹}kbê¨×ºçaó†ƒÞÀ^÷žÚܹ rßñJÞëÜ€.›‰Ÿæ\DÉ«²ÌÓX'U;ÈJú&G]áÄ¡ &x; 9ñ(¯›äœàÙI~òÉ'Ÿ£ ò8=pó 7wGï}ô`€()zä½nÅr_QÄDä¬{l¥žÐ·2­³}Rê´®<õ¤“ÕÑÜ(ƫǸõ2ýÕñZ~2ñŠÏàÊXp(8”9Pæç€½¶²N}(û:[ýa›]ÛÁkÈ¡¤²ËغØxˆRiêûtÆB;MñT—:ÕÙþªNymÏÊ›bD]Z³¢ Œ¥qÀÇ#­…—>¬{ŠsùÊ}_é¶|â–Ðö¾äüwÊ)§|Åw¼./b>Dš³Ôª°S9°äP.åÓÿ*& } ŠÆð„BÁDÓÉž“O'lNF=&¸=¨[vÅWÜ‚z›Tð=š¥KáÒÿòÒg¾Ô°£ÿi‹’Öu*Ï¢r/KofÐ[;•ÕèÒŽ®ÚZu-Kåà›tÖvëqìÿTû̱×Ñ©Æ/þ‚@A`>!0n×Jíïlž¶;J›ðéX*køti¯‹¶ßf?BCØ6û&}“+ñº¢~ÂW>¹yZóQFŠøä= kU¶ 9u´£LåÔ‘ªç÷Ûy?wèn‡BÛû‚\Å>¿ì·¿ýíµ—_~ù;ó)×ñ¼ÍƒPW=yͧÀCN™A*Ƚ:¡®zÈKÉ P62 ˆH'xN>Rœ´m47ùƒì¸ãŽûšÿäÿai襺¾ñÇ,>Æí¹Õžƒn-‹ ¯§ eÎÆúhÝò8 ˆa©‘¥M•3h®°o£êröã*zŒë8¦³ßŠG?í•X‚@A`.¨»ÎQ>—}ëÚ6û :›e²íÒ¯C_‘¸f“ÿ6ßQ±h³oÓÛþ4ÙCצ·ñXÇz°®hLáGNþµÊ£]­“E‰´²&¥ÜØ]œéO´iG_¥Ê{¿Ê$ã€"–ÖÉ«?x[`·Ð ±QºÐ0è2^ŧï¯Ø éF íÚDýt·;[ñØÐÙ.l{ÔvGô«¬kÐVWÿQ1i²ïÚ&±h³oj‹cd,K±ž«+Wø´¾„ŸÈ¯2ÚPêt(·v¬ÃÜßÖb[[±yüãïŽÉñŒEÉ=¸¹ r?Íu˜ 1¢.'‡Ž«ýÜJØEžu" Ê6¡dr=ª,]eÁ޼ûÀu"çdï‘ãÀ$…<6U@-:&ùÊQ¶¨ƒ†ã¬³ÎúõÞ{ï½ólðx/ /®ÕV[Í­´šéyí~¯uoùì[ýŨP€‹tÅJ+¼ÈWhcôÁ¶>@?ê,ˆ‰¢2Æh*ºÔ^FW‰A=©O9¨êT¾Pù‚Çìžù‚÷ìâ]Z+ô ¾ö­_³ÝŸ>à0Ù>Œè—NŸKŒ.6|“O“ÎÆi‹5U}]_ Wð•äß¶Ÿó£/)B#¡§/å z@ï3„J{ª§l|¼×ø:xŒEAíƒÿþüç?ß‚\Æ@{å™#AFÞRæT –§,‡âXàÖ‡N2õêC_欙!Tè_ž*IHÊ j'1ê:ñÉÓn¨þ®w½ëlÿ¢B¼Püoh:ÿ$MV{OwÜdGwèîñ{KŠzn¤ŒTõ*ƒ+wN)Eaäm= þTÞ8ìÄ%Ÿýä ¨8,à qQº€á˜ñ¡+ÎsÁÏøK1B ¼gïdY¬g¯åjKÚª¦½FßvË`õKe i×°¥´ÅL¼¦öÛâ5éët«Nø,Žì_ξ¤Ý5ù§RåÑn¬ÿÍ^ãv~ÊÎìIï)rä(,È]Ãøº&÷CyNÔS®¶ÌH±ÊæJ›hñð,ÑK2¢ ËäxA¾Ðÿ” €æÀIĉ¦”‘““•<('¯Ø:áUGù²›o¾˜ œ@IDATù¿ÿýï_¦]ó¿¡épŒK9jÏ£Ü>;ìSÿÅ@<š)©W¤£nè% —©lÄ6†.üh…}ÔªÛtÐÛ£aáÖ,.MX.\”Æsä¹s[dÃׂ‚ÉÂÀd<_ÅãÑkûšë^³?“éLj¾ƒ´NRºÆèj'¡×B°3]Q×,ßf?}/ä5º´¤ž·~Z»ÆäŸqH½_²§ÌRo³hÇEîÕ{¿š±(¹¼¹ r?ä@)¯1u+§-ó&›K±Ž3Ô^TwÆ¡*Å"P6""™"L.”åÄã¤ä„åVÊÉÞDÕ~Ù‰'žxÉÿþïÿÞzÿØÛlT×GþØŽu{n½góËÔ#.ÆDQÄ3|§M£|Œ7ô›¶Â¾äìr:ÈôÈù-T™âB~¡bQÆ]( ð=Aé„vö‡þ#Œ ­UÔqº”®v«Í§M¯±À·ÙOE_盓GY“6¤¹¾BG=)DMŸükœèŸÚÌè¸FÄCÿÞö¢·ÁblŠÍI³ wñ¨ä3¾Þ”ûP§>Ì¥4·ÏzîÌð ‘3¹]—?Εg4ÏN$|ÓÖN8ÖI11aÇIŠÉŒ :¹ÁcÒCÇgÒþÿò/ÿòÅ÷¾÷½Gûヌoúâg6ü Ì­½öÚÞm<  ø››~ãnºý¦A‡FŠQEÄÒ÷óUF-¶žM~Ê«øœ.ŠU‡‹rxýÕOí•W[•wõµ>£•/Ä:Ï{ÁÈ"Rê‚@A`~ PwÝïÓè¦ÚÇIøW’Fb1‰8t k§TÉ0“‰ÝæÓ¦Ït£ÒÏ&ÿ:å¤h#ò ÓŒŽ6µTâƵ¼È†6 h‹LÅ׿žèßß?¨É_ä"ú3å~œ+³øî3¡o¢6ÊÕ™KÑ: Ô¨_JŠ•hØ)ÂÄBáSª“4Çç&¶Êì‹„º¥×\sÍí—]vÙƒ¦s·Ü¨¾ük÷írè` šéBÉAeúÐ!¸›³U}• ßø†À8–J?¬*mHQ#àIkÌ´˜ØXº A)ƒ/ c„€½~³Þ×!° “)“ôÇš$­KØ.c±> íâ;êg"&ƤýPÞŽ·NG9©ÄL˜ft©]ê,•ö+kOØ©-ùhŸliG½RÏ¿î ñy膖ËC.¿üò#gñjä4)‰uæ9”×Ñ\¥2E’¼o"ð©4ätÉf!3eÀœýÌ„á$ËQLLÊu’ÖMn¾”ÒVeà!_úþ÷¿ÿ"ÿÊÇéY€8Ù0Qt’‚ǦŒ¼Nj¾ ,¥ÊƒìƒüàYþƒvCÁOkâö›q*/ÎËÝAÏÐ·ÙØ˜¨Ó§ÍŸv6夳qM§öÓÊ}½vM*m…qDßJ»eŽ=wØÓsÐ1Úrïù\ÞÜ9Šï|%oñu›×hÝÚjùSµìJŸv ¿L—t…™@ <p‹Q8pà™~âqe<0¡Ás2£Ž x!€BFž:Pû@À•Þýîw_ø¹Ï}î©k®¹æZ^Ê}÷Ýçõ¨G¹øŒ@Š{M=èX÷àú‹~qÑD? F êÃxV ©zQx_ ˆe°°‡!mVƒ¿M2Õy>Åa»Œ£v”)ª^cM†GûZÐÿR¦‹o[ä‚BE_(Ì&£^Ãf³o³ÕÖlb0‰¶R’9Y<º´ÙÅÆ¶ßŧ‹‹:ýHs6jgõô#U}”UpU;ò–2ä¢KqŒ<ب þ¾ìéÏ !Ú=éñOrǽø8¶4ãAΡåÞ{ï]‚ÜÄË4¹·êäA™'Ú:uD™Ô›–2v•’A ³ƒÄIŠ¢”:NT¥:ÉÁÛ‰¯z¾HôCû¥ïyÏ{¾è_„l×-[¶lì¾ àŽ;ä8·áã6 ÈÑMNÊàž¨²õÉÞÈ+gˆ:PÆ&…ˆÐŠ,ت}&ç£&mzµ*¶ì1՘ſ;û©Ô»·Z, ùˆÀT®ô¸´‰c'm³Ÿý$Úº#­=&Û´ÛVºØØ]|ºØØ¸¨Ó4g£vVO?RÕGYWµ#o)c@.ºÇÈÓ:‹~ Þ&Ø‹PGßÕµš;áÐÔc,xÜúœƒÅqr_O9JäQ×Fsåé§2®ò•õDÓ™ ]ËänA^þ #P6†1é*ÑIYÇccr“êDÇäÏ´±ºeW_}õmßûÞ÷.Õ>øàƒÎþ§êûÊ¿nÿÔÓjè°—§ hÎ2êÀ"yÏÈ+2ú€¢¨ý@2ñFL]”YNN›&lÚôŒ3”}'‰6JÌéG€çk¡ÐéG°Dœ,”ׯYJwt^t÷ššå$ÛÄš%¬[¦Ò:ÛnŠÑÅ&ç¿¶ÒÅÆÆÐþ´ù×é#§² ¶jGÞRörÑ¥8FlÄ.¸ûz°W9ý"=þÐãÝFÛˆ­EŽ\CËÅ_|r/CÎ2”¯ÔÈiÇ<‡”9¨A,[÷f¥L²Ѐ`f'I'&<µNžÙNlÖ•òÅPGÕüÒû·ûþwÞ‰ŸÚHÅ߆SÙ™KŠ3;>yG÷†¼aÐC"Gû.¤ÛB™ø${ØŠ<ð”)UžñàŠÍÕ jÅvB¹&LÚôCgH€~è1CÍ”°‘Ð9Yøêk´à1ÇH“ªÏ[ìkb6ʶGlë‹´ÆÑ·bŽöÛJ›\Œ.~]lllõQÞÚ¡^§‡¼I5×p6ý,…ŠÆö|ŠcäãøWb%{%¾¯?äõn—§îRqï{Ÿú#ÇЂ䤓NºÄË» å)QÞ5¯¡.w"z‚r艕a&g òò'@ÙÈãÒ&Õɧ|n÷ 2;±C2ïå¤úBÑ[g”§Í²w¼ã_\î ;‰‹Žù¥@ªzM÷ßnÿÁÏ¢—Š"yö^ë–W_„Á…6(u¶Ô£hgdéB®1holUx¶?¤ˆ‚6}ßLÊ9N¥3Ù^‰]( QÐ÷§¹zeFé··Åš"­+Fô­˜wm2øt‰ÝŦÒáXÑþ(ßf«ú¦¶cÌ ÆÚyKrÑ¥8FÌ){†IëNcƒŸû;h'ÿKXcV[$,|ß‘{ ñì¤òï—Û4`ž¤¨‡œ2å!+eŠ” €3;JvâÙÉɉ¬/ÖÁóȽì‹ ›•€›o¾ù¿ò•¯|[»þÐC íÒ©¾¯ü¡Ï9Ôýõ®=è‘%¢ž¦ e°´¼‘ع^Ü“n`U¹ð'QÝ.r2 “¡l?£ ¢6}ßlʉ³ÒÙl¿´U(  }ï™Ë÷LíLjgë‘´ŽÑ·bÎ>T„™JW;ëÚß.66.êê§|›­êáWçåœÕ–¼¥Œ¹èR#攉=äÁ§FwÈn‡¸#ö8"¸Ó|òÜB rä ^Æ%A‡ò/cž£Ôæ<š‘WЦQ'²¨³ð „z&W£]¡5”_¨¦E¬ÏŒ'åDŤ…Œêx! NŠ ðxQ€·~ €/Ú„úgœqÕ3ŸùÌÍ7Üpÿò6¡à +¯¼røeÊÆ¾zÑ«Ý}ÞçÎÿñùƒ—9‘Œ÷oŸ¿ttUOž>àQÚl铳2\ÔÓ¯,0Þ úàoNF=t(Œ?¨MümÓOXö‡cŸµGuãS›Â ‚@A Ü{Kílȧ؟”DNG_»ö¥«íS¿.66.êô#ÍÙP–³¡Œ”¶¤Q^Á[mÉ[ªþ9dVNå1FSò¿ïÎûºXüÓ³ Ä>ÏÅwþíSÿoò¹‡ožy ó[G¾bµÏœÔDr"N9ëmù;)Ê`ë°³¤“Òò˜ÀÚêöE¢õÊ'ÿÖöo|ãY~w®²=7ŽôãrÇìŒ[´í¢R|i MX‹¼ÂC‡âõéÍ ÉVuÏjì(K±blš&Ê8I`˜©êM¸ÞU1>{ô®“¥C‚@A  Ð ìûEÛ{älvš}›D›X+ð˜„û°K×¾tµ³-tõƒÝd ýHëbÔõƒ~¤Ö?Êk×hô³”q 7º‹2Ø‘§-ëQW±§.Úî¹ýžîØ ˱+6—@®ásŽ/ùhŽbùÆœÅûær Í‘eË×bØ!G«õ]ÈŠ²Ðñìg&˜NNDAEå˜ØšøÛº¾ì ‰õÜ­5A÷ÀÊR,ÕÓ¾N6z5<±¶tú^úX½Š< e”90Ù9`ßøž;Ùx3á§}œD|¬*k„IÄHëø²?mqºÚåâŒrt1™‹•“1>iβ:½Êµ}ðâ7„»ÑWâSG¶iˆ¥²Ï^WiÛØî±íî¸ë±+È!K° Ç8å”SÎAÎáeÌM”Öæ)Ñ^sò@ ‡­ëLñêp¶I©C=”LnFU¡-” €€:¨1!QxI!å倖“]'<'>^HÊë «I¾ô?øÁ—^zéCâÜ`wïTßgþí/|»ÛðqÐ$r¤¾ãi·2”YÚYÖGc)O?4å/‚©Û(KJÏä|FÑ«í¸òÀ wŒëxJ¿ ‚@A ]o{Ï›KÜô}h’ýÀš ².˜dœäÆ>%A3YlGiÃ6ßµMÚ‘Ú8¬×éëäðƒ.ê³ØsåM[PÆ•ÙXVO?ĉºÔ6m…>aý'¸w¾älu¬(rsc±»ì²Ë®¼ä’KþèÂ\EsÊ«4É™ËjN$èU¶¿šÎæXáÚÇΖ €ÎJf§ “Ein"sƒêä'Oj_<¨·í¬-ýÀ>ðÝ;î¸cè§~®ãW>zôGÝ£×zô ãŠfD9\x)‡U”W(eP3q§¬ÍwÐòp\Æ£}l:õk>ñ<'ut>µŒ¥ P(Œ#u×çÜ{aǧýŸBÿ°¦HëŠ)Ä©¸vÅc¨8w¬tmÆ¥M¶Ajc±^§¯“ú¨Ïâ6‹ÃºÄŠE]Îq£>µ­öÑgݵ×uýû²cEñ©¿ýÉ?Ÿ[Üñþ÷¿ÿ"?\~BYSžÂü†ÔæA@2Ty¦ ¸fr² /º!P6ºáÔd¥“v¨£¨œ/åù‚å ©Ž6¾ÀÞò–·|Ñÿ^'â¤bà‘=gÖ^mm÷á#?ìµÊ£=U$#ºáL9¬¢¼BE_¹`Ó>çÓ¤‹öˆ5~,ŒËº¥]ôm66æ|¯¦c¾¿Œ¯ P(Ì4Mרq}OÒ1M?¾ï§÷þ)Ώ²aMe*ç`²¾]ý8Òš!q]Ì:9œb\ž‡¡ðXY³Ø8¬ÇÁ,ÊÒù¤.g ‡¨ÏÚGŸG®òHwâ«Ntë®±.{2VÔ&ÿÈ)|nq¦D]ŽÒ”—h.£¹x̓ÈçÎð³rÈJ™ÊÀˆ vØqÒÉ “ÛRNxû¢°õÜ (+»õÖ[—|æ3Ÿ9O‡ƒ;ÆõyO|ÜÝ{{ï9 Ê¢D^H9lˆ4d(ÔÅzå­zòJ•g<•y~(ô,l›uKÛô°×v­©W žm´êUj‚@A`þ#Ðv]¤~¾ Áñ€N±à}>½×O1VÅ}¬k*£ØÚSõµñruâL𳬩/M¾Ñ¯ö<`퇒‹Ï¸ª‹²ºœ­Äõ3!4“Ú¡_´yßQïs›l°ÉÀfÌþ"W°w Ÿ~úéç#·ðCAÞÁü$›ƒDµ£½¥Ì¸b·”¨òld‘ì‹eýŠpò3€XL…Ó‰ŠEc?劼(À“b3uP¼ˆh‡:&ÙJ_ÿú×»Ã;ürÛm·ÝÒû„‚ïòàN€5ÖXƒ¢±¡[?qkwÂËNpÇþøÚs ìÑX±’ÿ™>0@è D]®Ž ~øY?Ú¨=e¤ªÏ"úl<ÚŠ­Š?U} T˜NïÉÎ­ÉøŸ‚@A  0Löú5m÷9Æ4ã’ÙótôµkŒ®v¹qvõ­³³r[·mÖé!÷GJ¾á§¶Q_ G}ŽFY:Çêßfom¥þÏûÏnÛ'm[鯏T#Øïý_uÕU¿<÷ÜsãÇÀ„Ÿö“å§ÿ99ôÈmH¹ €•:xP{xQ ªáLk6¥LH,K†'NTRDÆ$gÝNx¾(”ê ¬ŽÏ½ðcé»Þõ®oÞyçw a¼¸ñ›žãXv}ú®î­‡¼uA"‰ÁD><‰Uê•qÂEü:_øž¾ŒÅxQŸG_c«âÄkÜ$¦M/¦…!8¦›ÎPwKØ‚@A`–˜îkBS¼YÒX4£8MS‡ñ^žÞϧ)f Ãþ&Á$˜®1ºÚåº0Š/lmÉùçìÔ/§‡,®žk“®®s±SiäÓ9F]õˆ£uµ·¶RóKÞìvßbwíÅØðÈ ì×…}qçñÇÿM?&ðÌEr¹u9ª¹ y›IÈQX'HåoC&V…mC l´!T£ÏL@LV-œ¼¤¼T¡n_|aähîEEìÉ'ú¦7½éLÿ0ÔS±/ð¤fÑÖ‹Ü›^ø¦üe!¢:tA'ꤧðCöÔ“Š-D•7ÖåŒf†1@Å6õCõà› m›lŠnüày-tâõY°(XŒÓ¿«ÎxöØÎ‰iÖ<¦)d5 û]•Ž^Cœ.¥«].Ö(¾9Û®2m»Î'Ê“>t l"®%ðÏüÌçËîöRà_ôYèþ1t¾}òÝŸtsw›[úð?0°ŽþÂëRDã)gÄÇ’×àî<ïr¥ìÕY•5••‡ÍZ‡+`ïh£ ˜‰:ꨣʾŒ;:&ZH©Cäá ÔAσ 6ȱ%‹»é¦›þ¿3fünÖ¬Y»{¿¬áK—.u'N¤ª¯è»f¼Ë­~mµûöÕþ'VPET‡kâùìkÀP“3Éç¦Ç82i–DåŽýFì8fï€Mç¡”ã¯[,Ž>°±ÅrÄtô7j° X¬V^¬€¼¶ ÂøìËñvj=šÉÓŒ¯+øfccþZ§åª}ЏÂöú0Þ2m9Ír)]–‡:Ö²§u1°ÑîÙS<չǑzÍúFÐ/ý»í¶ÛîºñÆõ+˜ƒ|Œ¦ìÄ*’Jðž%OêMñfŸþÇëÒªÒZˆìÜ©yª²æõ!X¤8øäS’—6¤¯]tÑE·>ã›\½•+Wº+VHU_ñGí~”;eî)µ1ë CëuÑwn §Ê2Fé †>û’ºÌ!ÿÇ-‹? !å[¦ÏÓ…~)ǨíGŒÒǨUÀ*`° X†ª]º>ñZ®Çƒ¹¾\§Nô\UZ»}Ví‡c‰ùk–Kš²çzn3ºî…K 'ò šmû˜:æ ìi] l´{öoÿ[wô^G#²/0°€lÏ>ûì3_ûÚ×nñºæ ®¸ƒúчTú ŸdLîOþÝïXF÷%Õ÷þÀ_øÂþXÁ¯qEÀBG›¤“HÌ"y‰qˆƒPuò¤ÉzVÀXÉX3¤+`éÚ´ká©Fœ^©Jïüú‘6d<(9—¢<@³¸ ¼øÃþð—r…0 ØÏ/ĺàI€ÓÞuZmµd•¡É«=¡ ;ý$ ¢¥—îÑÒ!Ö‡´—åÖ~ÍÈ\ïm&ùZ¬V«Àð¨@ìzPåÕÁµÇu•KÓ–§’ë]îYÍÊ|Õ¼ã÷Ucá×ì6Šùk–õxRv¡OÞ#Á‡ 󊸂Møeù(k*ó0—§É˜ÜßùïçOþ±¸ç×Oÿ<ðÀ/x³ÄàSø‚zâ '±‹Æ5úz‹ˆ­PØ¢²µA¬€Mt¨¸‰*¹££'¹£CŽ òÒ<8ê)§h8PýøÜ~ûíw£S6¼dÉ’%û’âgyfm캺yõÉ^Ü"äIe¬çëb´eP4Æ×¤Ú¡C¾,gÊ·LÏœÈ'rR] U| mì+FÛHk¡V«€UÀ*0Ĉש‚¡ñJÚÕ! Æz#gÕÖ‰þ;ÑŸÌQeLÒ_®k®¯Û–ÒŸ<)â5OYÐì> ²ÐžcPöF1xÛ?ç«{}ýÒ? ~làÍÄÀ äSTâøSŽÑÆQÕ÷j[Kê3%þ%°U°Ózl õÚÕEVØQ±ƒsŒ”:È<€xÐ@–¡”y äÇ(bCÌ—¿ü囟|òɧ½.´W^y¥îû@ÁØ'ÌÜsݧŽþTm´¨&š¤ž'xÚ¤=¦C ’¤ü´ž9@eƒ}Áò+JBRúàPÌ'Õ^ôYÐwKàz¤h·ÆaýX¬V«@}Rçfêë#ºªÁµR.]íœ F-šÉÙŒ/Ǭi³9àkR/ù”o̺\î…/ôY:Æ’Ò‡TúÓÇÓpÏ&tì/Ë+ãs>‡ÎÇxïsÖ1gõõÛþ±šË—/w¸×— XÀc‚›¼Nb ð1,AíŒ øÂÇÇ"ñ‹”YebRo0U<д•*`•ÊÔ–wzžR¤ ž¤ày0‘â€_vò ”.å×üKêßZø€ØA}L_µCw>ÔÌùµ1ËJC“W¼p¢çV TÆz>ÄО¢*.zÑA¬ou¾šºøŸùŠÚ öNø dì.Çñ—ÑîŽÈz³ X¬ý_²sª´õØšâº(—!Þ`Õˆy«®üÛmÍä(ó”ùp¬ô¥L*ô¥÷@ô“TòÈ‘³œÐKy9úxÚ(æ¼÷Ÿçæî6—Ñ}Iü1 0ÀYgu…×Sh\AÌ@*qˆôe¼¤àa$¦AÕ)‹-൵-F]¦°Ý©€Mt¸Î‰+îÜ h”q@ ñ`áB™(0|äõ¬eIyg­hÕ§?ý韼æ:fÃ[A•Ц¾¡ïx°û¾P¯¬44yÅÃ…‡[ á—%Émˆ)ĉ|Ì›Qn=™›ù“%®]xêræ¶@dlP*¦S>*mOˆºŽerO Øa° X:P²s]#[ºïF ^WI»Ñgi¬k©S Æfó6ëR³9àk2OÊGÆ¥|r}ݶ–þà傼)»°rÒŸyàÇF]Ð|hÏý?÷ÁϹCv9„Ñ}IqO¯ßø{`?1€G$>È0‚×Iü^êéO <Ü“òn˜Xú|+„ªS®yùÿ ,ìÆ´_›h¿†u*ì¸òT#ð<˜b”BIá/eÉó †îµG}ô¥¯ýëWú`8èÀê·ƒÖ­X(öÙvwÑG.rcG8¡s-óª‡ÕæVv¬#õäsãÖƒsI^ë„\—3K"þɱuí”O!iŸ ¬A«´ÏV׆k° t±­žWZëâªu£+\çôÒ~ö!·OCç&˜»jX³þ©¼ÈSµ•õÉì'å#ôá^1BŸ¥€ŒFã#¶,'õ’’Ï’æy¡Ëõ!Ž~Â6fô÷õ¿ùºÛûýÝ·÷ôòÀüz¿ñïÿþïWø•f 6 •¸!ÆK?bŽV¡ŽwȨ0x4QíšBÿ¯€¡tˆÉ-T`t 1ÒZ°Ó³­áyðà  x,8ȃbÒ†2x¤”Ë(ã2ú›ßüæÉ+¯¼ò†cŽ9æ Ÿ5¼ o 2e U}IwÚ|'÷ïûïîìKÏv//{¹ViVkä«ýÆo¸5ÖðJT^ÚÈK=yÄù¿,Ž•?|Ð Ó?Säÿ´NÈYÎ,0‹Â?ÏX#ìŸ>cD@4WÓŒìÿ¬ËÈ®‚­½UÀ*`h«¸žµÝ:¢t ƒ™¿“¹›ÉÕIßT®˜>¦Cñ…>Û'(“rI™¼¦ÌG=Òó|Ú$%OМ¯‹£w™2aJþ§o8úºá^^¿ôïšk®¹õúë¯Ô¯Á=A—uæÜ&ëmâ.=óR7À?îá5øÇ½þw¾óù~u‰$ا® %þ”8…[CóÐ¥¶R¾ìÑÿPˆ.060ˆENLÈS,< ò@K ò`Žñ±¸×.¼ðÂ_?þøãOÊA­Zµªïë3uüT÷ýO~߸óµÕcµQQ4/g„œ/œšÊtY(‚áäóJ¹f©·Ñ_Ûs}˜Ð~ôOéÙ·ôkÄsÜüÌn° X¬#¶Eˆ? µ\^{H[NÔ ùA«±Nåof¬ÍôÝÈ7e'¦Ãú }v/C”¼ò«»’vÆ1ÖÓJy…?û-ÿû_ûÑ9?rS'LEï}Ýðs¸‡—íé§Ÿ~÷ú^,Ã)Ì@},:‰M4f‰l=n 9º¾fp6®í Ø@Û%l:Aê €žyypÅøØA;ÀyKbO?ýôÿçg —È5ÁûAôËC¤½ŸøÏ¾ç³îà]® •EC¥ó- C¸8Ð.©ä›ËÙmf·…޶@c6©Ë‚ý?ÑG6¯`þ‚\¦Ï×#¤g ìªŽ¢oö_g4…UÀ*`° ÷ ¤®зÝx!m;aIöÑa—ôîJ}š1rÜUcª®_•¼©\ZŸÊ%ô¼o »M,ב6RèÉ+Êû ‚>©8oÏâøüyï‡ßÜõ@÷¹c?Wúü?îÙkïöXÜÛŸzê©ÿå5ážßó —ö2>†E¤Ž%Êsk‘§ìMÖ†¢kààŠVøõP ïÓÏ8 zïGuTì×ÐÅ–ì;úÞ6Ê/ీǂw6‚“ë@ý[ï2;ÝW'óé\ZnfêX-3—ÐgûeÒˆ_¦’vðZ†S®«Ã)€•lŒ“9r>ŒGÚçs¶×aîœwŸCM_Süœ·þÐoúÿØÇ>v©ŸÀOèãÑ~ò ±…~29AÀ9@ÐU×Ü …6Ÿþ{lVC·„ºý¹[«~ì UÁKvly0ð€à©ôäqPçÁ&B¬Ô‘R¯)ìÈúª?A¬<ï¼ó.ÃO„x94œPV®\fQ9›ÚôŒ¹g¸cö;¦vZb屦ä=ÍL!K[”Ïãà bs]Îòý´¯”9&Òr™>å˘Äaݪþ¥ÒšÞ*`° X:Wªçdø JãµBÓAé,’Tö1w\Åþ:™9;ÑôØ´\µÆÉqQ§s}¶/òSvøÉx-‹¸ÌOÊÒ7×Àt¼C¦/ã­»—ƒ?ZžãèýŽvguö°¸·Å=ºÿ¸—Ç==îíýZ´‡{þ\ÃÄ6ÈýÊ…X„ø„[‡[ˆTmŸAµŒ¤LH½ð;áÜ)sO¦ïîÍq.›_ÿ7p/{z¯Ç=?îñå=¿ÄäAéCÄäA¹Hl"q x4êjRí?·šÔ?° €.=1ÃÅÓ)óÀ‚<¸ÅÁ =`¼”qPóq}€KŸ×î¸ãާ¾ÿýïÿ*œ@} ~GTÿž¨W÷mû଺3Þ}ÆÀECV=ßÙúk=e¬¹æs]v“ƯÕä¹Â‘1Ôë<”AÑè¯ù˜ ›Ì_¦£­ŒÊ1”ùµhÓ7µÍÈ-viaV«À0©@3ç‹^óí©MÀó|Œõ@嘺9öÛÉ>;™Sæ’|³ãE,©æ3cþOô“OúSÿT—e¢LEqÿ…¿ÐèÕÔ)î]©g’\þäÑŸt'Í>‰Ú¾¦±{s¬?îáq/ïW¸ ìž_c [İuÄ+¤¬>(š–kZÿ?‚ݘÁ«¾Gn­KÀŽyŒßÀ–2xPÔ“‡Œ4¶à •zLô@%O»W|ÝÏ~ö³§M›6yΜ9ûÀˆ¶zõêl`Ò¤I®WÞßPYkÿçΘë6žº±û—«ÿÅ=ù“µ ÈÊûêàDš­+õ¨X||ÃÅ+|wžq¹-䀣ÔÅøZ²¸Ÿ¶Af“ã,ÓÑÖˆÆò5Šd{áaû Ûqûh'u·êÐÎ-Ö*` ðü=„C¨ÜõPŽu°úît^æ#­\\á(cÉ“ ·À [vÍráž)õ¤Ò:¿®gÒ/â UÖWîWþ§­7Í}ò¨OºÝ·Ú= ë÷XW|0‡{sÙ®½öÚÛpïu0àƒ’çd€ÔÓNÊþ ôI ôAó->í§Ì­§eRkþY‰¡¡öÀ.¼PoÚÈ$¡(>—þA<)x¾/õ“/¬òRÀè ó\c.¸à‚Ù»í¶Û^m̘1ο00ÈÃù§+þÉÝô‡›@6·V.çäd4IÁã§uP­A¥²{±àM¸d­/óÍÕ¿*ñ*¤TŒå+ 0£UÀ*`° t´¼ÅîhÒO6ë<9YÆNæf.RöÑ •±äIcy„­øÓŸ>¤Z™¶Í\r#HÌ/¦ƒ«Ã†z9kÂwÖγÜçŽû-Âúïö»W_ŽhóçÏÿ“ÿ¹¿¼F}ùô/yP¹ÀŸ6òrB:Np¤¨8x491 ¶D͈ÿ½þí%€Ûø¡«Ž2 4y ñ@ƒŽ tX8K')ZÈ\ s‘;í !'’ûï¿ÿ/^N88ñ §öÙcüÏîvpñ‚Ã-ê—7^Ç¿Ÿ­;x4nðÔ ?\˜ ³ÒÚr$¦Ð§È™éi ‚ð•:òÌO4–SÚËøvbËòšÍ*`° Œ¤ ð\Ú )u’µéä:3o's2W§s3h+ñŒeRêI•üÓ‡4+màÑEî,?mÊ^¸W‘6Ï×Ý›1GNÚí þq¯žƒy?/ùؽ¸ß÷å’÷ÿ1L‘ÂØ"Xp7ŒÊ­”)"2õF‡°ü”y‡0òºNÌ|ñ â#eÂLèÀôÇ(xØ<ˆåãyb` å×>ó™ÏüÒ¿Häq¹•†ã$ÀyGçŽ|û‘µÓ–¬\Á@„ýð½wŸ~ï§ Ãëw!öÉ?îÑq¯î× ÷ü¸—8€÷óZ¯} ëøÆ Ž{eì.Ч’[â@K` ãºR›èJ™ë;)9xúByRpÁË<`Røò@—Ÿüó„ )ìÒõgœñ?Ï<óÌs^Úpœ8í§¹½ãCõUgõýÚ J@ÏFIa£ ¶…§²Ÿ„áпì;CîU“D¿¹y€¤l‘œA ¸TN„ÑÖ)Ú`(fn³ÚN–§óû¾Õ´³5móP±ðV@îÛLR1Pt˜Œü¼ãku¨“ne9Å:ðž#»~Ëô!¥MÊš‡th9Þ¯0.FE,rd÷BRG>Å›þO?âth‡M‹ÿgŸ}ö9Ü£û•Ä}»¼——÷ÿ1=±@á~ßçˆa â PîA¨´ä¹Õ¼:ÛÊëZ ö©ó5ÅàVÀ&·¾ÍfçÃIRh<¥Œ2'xãÀ/Oò`‡ž'ž x‘òêSN9å§/½ô~R$4L,Y²$ÈÃ9~ÖñîK'ÉmºÁ¦ÅS˜ØQ •>Y- £)}Ý…KسÜ>€´Ÿ y>ðŒ£>§¸°†–ðÉì1[L’U`Ú¯ÐEXoöet`_èD-ªló± X¬íT@Ÿ«ÚɕЕ}¤|ÚÕ³vóÈxÞåI]3|lLr"&oÙ=„3µÌ)mRGÚ¨'¶pB›Œ¡_Âî¿h‡?Z.3Î{ì¹ÃæMÿµ•sÙ½6î¹eó÷ä‹þîïþî§^ÇûzIyŠ%v¯/ï÷‰ “X‚Ø‚{¤¨:dn I½:ì à­õXì%€Cð@¹D^3^±Æ…2&k “/ÿƒ Ê/Ï—òÅ€¹à|I`ŒR'ýG¯µÖZã¾ûÝïž0qâÄ >>´±cÇ:ü:ÀpkÿôÓÄËùÈráÁÊY<Ð’Êž½¤´3&³áDãŸøñŠ+p '¦áö$Vî³ïý¬;t÷C ˜°ò-.HrK±2¹O!¶Ü—3Ù!‡°…©#/óB‡F]Mªý÷ºÂ“Òã98ÞXHC],gà s° X¬V¾­Ïû’öÂÊp<팥9tÿÈÉ;;m«"ÇÆÓÉ\°£yŠ{ ˜SW³ ü§T.õzÆä>¼ßÉDÚd.ÉÃIùî“h>x‘ó%§_2"À?îÁq/.À?ïßqÏ.ïßc¼Ôñ_‚}èˆ#$¶ Ï-Å=–²Ü*Ü2Ðe-uh6:°¯ AÑu—‰ƒ$}°ñ`åÁª)dä ô£ÞËÙÅ´Î@E9ª†«l51–3êhJ«€UÀ*`è¹ ð.i¯ ²“cc®N®#s‚¶Ò/ccº„= ª¥/xæã)k?Þ…2FØC?ÒÆ<h¸§bNİ?ÏO[ošûçþ³ûØ¡£Ç°¡ÿ¸§– ÷ܸ÷~á…–y}ìþ<»G÷6Ü¿7º—§/h ;@/*x©ó.aoo­O*`=²¡3d8ÝÉÆS&t<Ac‹> yk`Ï“„<Ä&¨Ë&ü›G—ùYÈy~vrDLìö–ÝÜÎø;`§€5·† á15n9Rl14Ê"¦pꤾô“2yP4úÖ´µÿÌG¨ß[Â…YêeœäéÓÁÖJcÎVã[éÓb¬V«€U Zä9ZòÕ¢‡Æ‹ãìDïÌ…ñ0Ÿ¤ÍŒ3G}*—°7|ÔŸ9#)m¤°áÎ~5©¦jåS‘+ÜK1§ìÃó³vžå~ô©¹Ý·ÞÆÆÀ?îµýÛþŒ{o¿¢¼ç}9ïßy?/íÚF>¸Ÿ‡ŒEb†¦€®ÁVÏìÞm %°Í€ƒqCV{ à¿PoùAx) ^ˆÊ…/÷Ó”/”/$Oʘìå‚›o¾ù”¯}íkð/„>4ÿÂ@ç_äáÄ\ô³‹Ü/îüEí…}|É^¸·F.]¶ÞqÚÙà”ëër} Šòì'sP>:&å“ò+ӗ墭 emªøšUÀ*`° ´W\—ú½u{ší¯ÿ˜oL'·YÊÑgŸ¨ËXðÚ ¾Ì1:NÊ9ú£-EÑû¥OÞá)ØürØ^‡¹sŽ>'÷^$þýÛÿ_=ûì³/{ì±Çùµ•žþ¤ÐƒçB?M þIå$xlRT_NpKå[¥np½þí%€~‹Zë $}€I™$tÄÈÖ(GÊÑg šâ³íGT7êè;uä)ç>YŸp’zé›ûA•ùP¦?Ôü …>žn¹ñ–î›§}ÓÀñл†{eÜ3ˆOþqo{l¯ç}8ï¿yžÝ‡{;¨ÔI½äJ\@JÜ™wªÔqKAF£\“Äÿ #¼Œê ØÀPoêýóô(:ò¤›¬E§rVÍþùÓ´™Æ8Æh™zÒ”=¢÷ŒøÕÝ—Ð_ú‚g‹ñ¹oø3^RäHÅçùøeœçO<äD÷Ý3¿ëvØ|ŽdXÑøÇ½´ìŸà÷ñ±ûoÞƒó]ß›Cfœ¤Äx‰%ÔÖÈJOðÖú°6У-1ƒ&4€¤8`Á“’×7O± O<™ðä¢õ”yr} (}ò“Ÿ¼Ì?ÂTxu)&üO–ôh¥ÛÖ ûŸà.þ›‹ÝnQKÆ-âix‘ uðÊ­E9BqQÌ|e\ŒG,ìrÑzÊ ôkE'ã9&™§Š]û§äØ8S¾¦· X¬¨Ï;ƒI;1Îá’CÖy(Ö‰ý7껪ŸÎ#ãȃÆZ™6´Ð•^ßu)7Ág÷(è1h1J¶çýîsrßÍ7ÜÜ]|ÊÅNÊÒǸ7Æ=²lþzî¥óÇþq¯.ï¹%Ï{uêxÏ®õ°óÞ_S‰xGŠ-@ž4ßRaëbÈù–[k ìB³Ñª€½°Ç^¨÷&_ ˆpLêè/„N¿2^Þ—½Ð/§úe”Iá ã$?zà 7œø­o}ë¸q¾yŸÐÆŒã&OžäáÈ|åÿ}Å]7ÿºÚªñ¥vž†—ûq¥…-¼Ð:ø%V¿hPú–ñ°¡‰\Q9æ“Òµ¢Ï:õÿô8¨o–v*O³ýšk¨»]h-EY¬ä½rN¨2Ž*>e›…ñ¤)ß”=¡\æ‹ùj”É“"W¾Ð/|éOªÇC½¢!ô¹íà™»O¿ïÓ2ðãþýSþ…õZé›ÿ—?÷ÜsK½€ ž2x òS:ÆÊÿÈäƒÕ‹W…ÉðÜJÜŠÐe­ßÀ¿½[ÎhOV q@é2Z4ÚôAL™Uxæí‡&Ç;˜|?ÔÂÆh° ß èó[/¬)Ç m í4Äón,•§¬/ÚDlôú {Ä·N'}È“²Èl>ÜÃ0Ž>” J¦0á«hÂ6{·Ùî’³.qsgέنá¬wì“Ü+ãž÷Î~µÃ½´çc÷Ü)Œ#û}ðXxïO< 1÷VRn*·Ä–À(Æõdl '7KSƒ’¨»Ê½7}<ÞëƒbÁ*)·÷\ȼI§Í«¬ — Ø@ŸlÉÄ J4yp’ÅÁ˃™<(O’ò$AÊ“ )ôä%è—zÚ©[úÛåÏ<óÌó>>4N¬^ ×áÛæÌ˜ã¾{úwÝœÝçÔ¶V5ßj¸†&·ZŒqY<·*ÒåçG÷ØýoéøgýéüÌ-†SÈ•!Q¾PÎiè_éSþA/û“±Ð˽•ý¶Je.Q7Ù¥ñV«€UÀ*Ðbô¹¹Å4ƒÆñɨ#•¶Vxæ)»ÆÐT7Ú”¾©ë«Î!eò¤ìGʾÐ?ìrý ËÆøõ~È•5Æyz臺ïý=÷Ι†{ÝøÇ½1î‘q¯ìW:Ü;{ž÷Ó¤´A®r.ò^Ÿ¼¼3¡ ž‹gëxèBK`“`7¦w+`/ìñ—ê]§ÁKáŽ×¢É“´5×\Ó?Þ­µÖZA7\™î½ÁÍ»až{ìÙÇ^‚—o©5ä[ñ C«J¥/ÂòâÑþÐt.“ùÑ'fkFç}9†,o*6sFö¯mƒ)U¿ƒ¹N–Û*`° FÄee0Òw4§«ä;Õ‰Ì)ùTþ”Ò ¬ó(¿ÌÜH§íR&OŠ„9_CĆF[ ÍîE`>›o¼¹;þ ãÝÁ»ø¯Jól¿|ùòº§^ýÏg?yÆg\åWŸ@à^}‚R þ¡§Œ8ðŒÐg>‚~M ú9­CÊ­%¶XØz>m­õ;ø·—rKí‹ $8¬\Ê < å®O”y‚ ”'ž\x"≇'©'ÏQ–'ºûî»ïaŸ34<å¿ûäü‹Oƒn¸2³wœí.=ýRwò¡'.„8­†Oèå–“<Š"eÉKÜðD€>WKðhÔÕ¤¢¬m1ÿ”©ùT‚Î;©—4Ö§´Ï~I«Ëk° Xú©<'JÚëãçXyçC¹Sãf>P4Ê5)ýŸþô`œÐ×]7µ/ePƧtÚ.eò¤*_ÿ {ÖeÌF]NÃúPŸ÷ó¡Ã>”}ê?À?îmq«¿òŠ{áÀ?ï­I øy¯-ïݳûn_rèb‹ÄØB©#Fn=lA6è­õqð‰°µ>«@ƒI”ûÙÏ^÷ÛßþöOºäË–-sXFBûÀþpßú»o¹[͸ˆç[+Ì”£±-H½¦ð¥NÆåê@¤MÇЉ>2mÍè¼/o E*>–Ÿã“¶nð\I»Ñ¯õa° X†¢ò\'ù¡K+}j(ƒuèd‹Õ„ºFýh?%G¯‘Ì©|3u#¶K™<) žc‘º/ÇÅXÞUŠ<ˆ ÷2Ô{ºë6»ºožöMwÂì˜iXS|껯Å=0î…ýÊ§îµ ðIS÷رûsæMÝçs«iÊ­…íBT·˜Nû˜Üã°¯ôÙWäþÔàë|°”= ñˆ?x.úëÙ#ûÞN*ç—øëÇÿµ,}‘ röõ‚~ô£»Î;w/ý¨øØ±cÝĉ½ÛÈhWýî*÷ƒë~à/_\[a±Õ²¯9T:­§ 'ò¤R^6úÂ&ùVdæ×yr½Þæ™:áËT•} ]ªŒ» ð.¬V«@i†Ã-»^-—  c£¼ìèJúH>FaR\-â›™µ¾™¾¤H(øÂX¨' 6i'ïiþ¢É&»9ѵ×Q2Û°æñ©ÿªUÀí u¾æšk~ûï|ç÷^ p€.?L#à—Tƒ-Ëx þcrª }cËA‡ÆÉðÐs,ôYóF’íK:Ò¿PfmxU œ~µO ãÀا¼Wu¥±ßЙ?Þí_~²Ä¿üä`ŒÂ /J™4iRðÎÌ»áßýp÷ã›~œMÈuÅ…´ðn¹E¥£äcv© •΃ô–‰ùÒ‡±))é^ûA盼Ù›ž¾p9 ³Uñ¯ôcl*'í­ÒX_Ì5X}2¿Q«€UÀ* +Pv>’~½Ì7Z‡FöVÖ­jÎ*~ô!ã‘×>¡®±ÿèµLû•É´‘¢'ÁÆC=© u hÈ'üN<ôDwÂA'ÔßËÈüÃŒ½ìÏ׿K/½ôúŸÿüçñ« Ð.Á?@=»þà5Ø×r«àŸ`Ÿ[вï2ÛC § :kð6ÐÇ_H<€µâÁ ž“´5š |IQäiÔ8úAÆ‚'ÜÕW_ýÐsÏ=·ô¼óÎ;b”oСáð;©“'O®)†ù€üðA·óôݼç¹»¼»V%_ùì‚êéoàŸ/ª—¢¨lh1èþØC=|Ù¤ :)3ôŒ‰éš·ìÓ‚œ“̽ì'÷‹Ù_ÌA愽‘,G³:Ýg*¾cIõmz«€U ÷+Põ\ÒËkÒÎ:´«I³ùªúGîªä5.ŠÌ%y9Θ^ê$¸2YÚr>Œ‰6RŽ2©ìƒ:A³|B†;÷?áàÜN[îĬ#‚âÞUÿºÕk¾}å+_ùùwÜñ”/‚ü”ž€Ÿà_Nh°¯e™|êqè±gÊ[‹ ôrë‘÷êºVf«s6EoWÀ¾Ðç°`÷JLV€’çW “ç×@ùÕ~%€_ÍÝ÷<<)óçãÿГ—6éOtôôéÓ§~éK_zÿ%€ÂOŒ=ÚM˜0Á‰¹ï>üÛ/çÿÒýè×?rÏ¿ì9‘[«íùè×èCšûf•¢NSúðtN;õY°ÿ'õÚVEŽù@‡ÆÜ‘1„É€šgí?ý¥.ÆWõ“±­ÄÈø¡æû}üC]?ëß*Ð ð\×¾:ÙÇPŒ»“}¶’«j ü”oØrЇTÚÀÇôZ׌,}s¾0.褃ԓÐðÏãןº¾;á'¸¹»Ï…fÄ4ñ³ïûkðï`ÕùçŸÅ#<ò²/A»þä>öi?'b6Nä37('îõ¶$A?y¯Êö½•¡g£²³¯„R4Å„'ešŠê¼³M ƒ ì=2 @ÀZe€£¦N:þ[ßúÖ{ý§þ…àñ‘ò3úðžwÓ<÷Ãë~èÏÊþ¼K€—Ó0@=‚É“Æt¹­p#àupÇbeðhÒ¯Šó.ÕDþ06é+ìRå›ñ• Z“9Œ· X¬½XºÛùd'ÆÔjŽfâèKêKW¸¦ÊRÒ‡TÚÀÇôZ׌,}s¾nl€²1†6ò¤Ôy9ä£ÍS\§O8ôwâA'ÊÌ#‚çÏüi`ç¿ °ôŸøÄO_~ùåå¾éü“ןîkYNô“2/'ºþ±am µÝ[ï'­ei? ŸúZÀ×"«A(y=ó=tzáIDž\Àó„%©<9‘×'0-Ëø×p‚üЇ>tÙc=ö´ï#4(x‹*Þ¦:Ò¾ðÍS¾éÚí ÚÖãVô4» 9«”Á£IšÛñ“ƒ™^ØPçBNÆ ŸKÛ¤¬ý)Ç| K5ÄåKmdùøè/ìT%©ô%Ÿtúj*\Œµ X¬=[}î’r¯ ºÕ1É8ÉWY/éO¾Qý^›dy·%õ"GPk–áHƒ¤á9>ºgñ›Žž:R¥CNí3{æl÷S¿1"ÁÿŠ+²{T êžxâ‰gN:é¤Ëøç½±¦úÞXËÒŸ ŸTߟó¾]ßÏsO$ÅÖåž ·4¶¸l°[†°'†ÉÜ7;ð$¿ ¿€Oê¡ÏÙÏy|ÊÏOðIåäù$|4Ï8ùõ‚QŸþô§÷ÛsÏ=·÷þ…6Ò~!@®ü-÷ßâþû¶ÿvz$ÿE~:íixBâ….»xCÚ?|êÎXÄH¾2r é¼5mü¿ð cÔžÂG›’r+1©dÌ•êÃôV«€U _oÍ›w³þzÏh%>£žî*€cmHäËü¥¯öÓ2|¥.Â×]ç飩ÌE[Lçmø ûöÓ·wGï{´ÛÇý¡q-ö¦Á×ÿ¾þç¾Õ³ ´ƒäSÖ¼ü’§?©ÌM <¨ä±u!ƒÆ¯.ìUÑà›lö@²4¥††çÒèÎm`˜M`×(™ 4Õ ?tø“@çÐŽE‚vyN ès@RØ´?ã¨uüñÇïpÌ1Çì#!Àǹ1cÆŒ˜_ÀúêvÝ=×¹ŸÜø÷øó³ßr&ÞX#?—c+ëF)ì9€6m¤ÌÑH¹ÂÜA&£sQ£Ê7ŒSû*?m.•Û‰-Kõ×Uf¡°õiÓ<}h§œûqBa7¸ ÑÁSªd¬Ì×2ÆÑ‡©©—ñ1íÒ?÷+<áu… ˆ'û©Jc¹b±zc>ýª«Zƒ~]?·UÀ*ÐZpnÌóCƒÜàrô)ÿ”žq¼S¢\F‘KçÓr,^ÆåþÉñË|äI‘;ÆSçiÈ+t;zÿ£ÝÜ=æº-6Øâˆmþ˜Ðí©§žzîÌ3Ïü9~îÏÛþ%h'ȗྋ×à>Ø ¡'Ø-H¼\¼˜5ê(°w ÃwÈý8ñ\?¸hz~ò^? À'0>­÷¼üŸŸêƒR/?ùOñô% ù?õ©O½Ý-`Gü4 l#ý½¬Å}ßç®›ûÅ¿¨ß²tbé4…:ͧb…_Óe9¤MæÄ¥H¶”Ÿô!ó¥4åчõ`lŠFbS®ƒ®ow,ºþƒ>`ëÀ*`è» ´{žh7^¬b®j«ÄVÉ Ÿ*~èOú‘'•ãѼôÉ'J×Cú“'m4ïr3&§söœãæÌœãvØb=Â'Ǿï"Üyç÷ñ‹_ü?Ïø€KÀ/¼~ÄŸ~R/'d.™oÞ¼[®¼òÊ^O@.Á>y‚| ìËxÆêƒ€Tÿ!ÿ~ ö¡…fêSÜjØ‘~ŸÁªZ„AžÐ þ æ)§>ù—“Œ‘<–Q[o½õº^xá‘þûÿkéõÇ$kÎa"à¦{or×þîÚZ9LQxÇ7ô§^RðhŸš#¶ZPþ_Ú %Äüb:„¥ôLÙÈN?Òÿ°žôm†ê¼¬y39Ì×*`° ôBÚ=•ÄÀ[Ï’¸˜{¸¶E^™ÊÓwJ—ç ë)óJc¦L*u)>÷ àCÆú˜wìþwÀθ=·ÙF|ðÇ¢ÛÊ•+_ùüç?Õ‚ ^ô6‚r ÖË@?üä'þà¡ã¤ó@Ö¹ ü{üûñÙŠÐB Ç` ± ±'FÀÜaÚœTá'ÿ \ö¹¤g@ÝëA ü%•`Ÿz91 uz2!ëc­µÖã߸zÄ´iÓ6ð}^X3qâÄ‚n$ óÿ2?›øÕ¿ª• 3Ee±è]³|SÈ©ìSÚ©KјoLÇø2|Ù™GÓqÙú«›-¢-¹Aÿmå¶`«€UÀ*€ Ö9ŒÀ´Q­öß(®Ì³Åt©úÄ|¥Nððr¶ÓI¹>â@‡´ùNÙýwà.ºÝ·Þ=ëÒþ9—zäßßÿyÿ}ÿ«ü÷ý ò Ø%%˜§¨ú1N€6þñ¶*)x.ž ¼Úò0e-¥§=IûýT‰’ë6˜†p,f'rÛÀšÀþСI þ9)ÀIP9ÀIy‚ê)“B›  !¿ÿ™À=÷Ýwßô{ðSø•Pkµ Ìx¾»åÞ[jÀQSi«…ÖþÓOÛ©'eŒ”s>LH›Î‹§.Eu>ú¥ô°—ÙªÄÓgh¨Ó ä¶”V«€U`0+>ÅNuƒ1]*>¥¯’£Ì'ekFóÕº\u’vÉc=)“J]оl®/‡îy¨;`§ÜÌ­g"‹5_Õ«Wg/—• 5ô?ï÷Ç‹.ºè¸‰@@Ÿž²ùš—¾°é<ìz¹ðqP.ز]ÿ¾O{Eh¡…c²…ØN†ØÀ›ÀÎÓáI€Ø@¤û. þ â%Õ`Ÿ ÒOˡٳgo~ê©§¾Ã¿ºB³Ÿ ,”#xüwë}·º«ï¸Ú­Xéq“@¼–uŠ”½Š¹r¿reœ°ënëd'R¶”ž±ìômÆWÆõ¶SŸÛ†kI`²VZ€Í0œ˜.›`šÉÓÈ7eOé1̘­Š.÷ ÛIÇH¹U^Äe CÈúøµÆ»wîõN·ßŽû¹í7ß*kyü£ýø×ñ“¯}ó›ßü•ŸxÒÛ$0'ˆOÑè—Oè8}æ•ÀŸ­Øb1Z—Ë•@?JÈxR–UÊ1^è²¾(çtÝÉëº#ö>Â}pö™Ñ¨¨ÀÒ¥K^ø§Û‹/¾¸èœsÎùÙK/½„—”ƒêOí!S/?tôK?úƒÊ…`_S‚~RlÝ–Á¿Å‡ Öº\›° €.ïrõÝ á$€ž ÐÀö˜Ž¤ÌЉ€QŸûÜçöŸ1cÆ6zmíWtEŠòÿüöÜU·_åîñƒzäIá%ù¨¢^úH^Æ+}˜ Hå,Ó«\Ò5ãÙáTÅG&nÖ_Æ’/ËÁ›9úµ X¬½XÔ¹*¥ofšÍQÅ¿‘¶k™ãèënòéC‹•¶*|ž£Ð—ˆÛlÃÍÜá{îŽÞûhöfTT õ–¸Ü}÷ÝþÃ?üÃÍž%— ]‚w êÉÇ@¿Ôé\”Ù—¦ý¤ØÊm¬£M  Ýo…ãµû݇í+#ð+aë{f'øÕ€Î}w°ƒ'Õ|JǸº§˜îܹÓO>ùäc_ ð¿½ÀûZ‹Tàú{®w×Þu­»ç/÷ a Ncû$>—Ƀʉ‚}9!@ÀOeøÈ§8 )ó„~ÖYgñþ+‡¯¿þúS}|¡á+&Lpk®‰![‹Uà7üÆÝvÿmîú»¯w¯¿ŽkMÞ(I¡ÏËŠÖça™yДŸ´IŸ,D)à‹–P7­¯e«ýOå”>’Où³.Ò·*ŸÊY5Þü¬V«@'+ÐÎùL£™\Íø¢Ÿ*þ)ŸfôÞ·Û ?[=1ÖQkŽr³gÌvûl¿Ûwû}uµMÎ+€û™eË–¹W_/6ÿÈÿËçž{îÕž.÷ ÎɃ¼k*?á—6ð”eòúà øõ¶r#ðÏ=”¼gšÿ°ØÀ@}ºÉÙ€} ›û[þš˜@.‚}@ò’ˆC– =tÏ´“Æ€?'R6ÄÒÆ< è'ëËkÏ}öÙgGý+×^{m‡'¬¥+°à©îÎwf¿ð¢Sà”zRDH^Ëe6é«ü’OÈðº©<ÁœÒ‡œ©ê§ãL¶ X¬#½1hÓU­SÕØ”_JþS6¯o ôëœ:¿”%Ÿ×¢„}ý)ë»Ãö:ÌíùÖ=Ý[7}kîm$V|â¿bÅŠâ“Þµ½í¶ÛîýÚ׾ƷüŒ¤“ÈKªy-ëXÊøC'??elm~âOJ7…=:±gÀTk1ð‹Mäê2)Ë]î[vgOØahc° @7¨ÿä(ÏýÔ âa'˜'•ŸüS׈fÀßçâ„À¨=÷Üsšÿ¹ÀCÇŽ‹ØBóºìi=APp2!«Àµ¿¿ÖýïüÿuxøÁÖæ%<[¾)?mÓ²ŒCš7¼Bé’µ”ÆVmµÌÅÿe¹Šž&Y¬VáW^ äšÅtÒÞˆo6¾Ì¿›I~Œ]ç,“›±åu)€¿Ó[vr‡Ì<ÄÍÙmN£ Žx;jˆOýc/úóºW¿þõ¯_{Çw<í EP®Aºõ°Ådêä“Ì#c؇¤à±ð“~òØâàAå?4î´Õ´â üÃÅ&D¡ºÈŽé.ö«»² ›(ì˜à× @¹œàŸ<='4¥”‹ö‘“œȨÿ´ì—¿üåÃ6ß|ó +Œù¯ài€µÖZK›LŽTàönwóÿ2ßÝðûÜ’K"^%ÁpYR~Ú&e\ödl¾eODô5kæØ(S‹€FöhÒ\ÙN,óò²OÙ¨UÀ*`è… T=7Uõ‹­S£Øvì>¶ðc 2§äµ-&KŒ•<|òVÂgÒÚ“Ü3t»m½›Ûg»}èn´¤¯¼òJö©ᫌ¹ÿc=öìyç÷KÿTA;À6À:)@=x‚{IÁkY}Ú¨cNæ§ 0^RN€b thÜ3h«iÅÿ2ð7›Åê"[8¾»Ø¯îÊ&l@ï8)¤ õ ’¸G…^OP— Á?¨^$à—@_> õô×y ³ÏÑøÀÞvÌ1Ǽ݃~ŽÙ›k x7€µêøù?w×Í¿Îýù±?qÏÐ ì-ÔIŸ_i‹ÉÌ'©ŽÉÒxeD/ÃÚáÜ(Võ£¿¦¼´k}»yu>“­V«@«H§Z͇¸$œ‰$­Ò#ooø9.=„ ¹Ca[P&Ï“ƒ9I½Û¶›oëÝýPwÄ^Gˆ cUŸúc@7?ðúW\qûe—]ö€·i@™:‚øåÄAÊÎ\¤ý r‘€_òØ ¸ç€r¯•¼‹­ø‡·MkÖ-É&ìÝÚ×Zê§C“€+ßœ%—” ]‚w èË€¿ô•¼Ì‡þ²~6Úh£ _üâß¹ÞzëÕ½ pôèÑÙ“ö4€¯V / ü݃¿s·üñ·xÙâZd ¬j½”S<2JÇÓÑ&iįáSˆÄÉ´¾ßB  V«€U`˜W€p%¶š­Út®²<ðõöJ`?÷Õéäª3…yRáÆ\Ð{î;yÂd7kçYnæ63í¥~²nx€~,«Ww^ô÷™Ï|æÏ>ûì2o‘€œ ]R{èÀS®J‘¾² üÁKÀ{Áþ ߇M CÐlÀ&†`·k®Ë&°èkÊINüS ²óä%•<ã@59LäöQ§žzꌃ>xÿýÿ:èfOø*µØ~5ÿWî׿ÿuí§™#¯pvâó|x‰Ÿ®¼”S¼ÊI1£2¦`PBÂ/9.ÞT_:6Ñ·v3Ù*`° Yb µ“ƒ!´i'gÙ½- öÑ_,®ª.6^›âE¿)З]¶ÞÅ4ã wØÌÃb=™®ARŸúû{7®¿þú{þõ_ÿõnŸBr€{ÊÿøþšÒ®)ý6ð\`ÇžO2ì=à%ϽJóÞTlU>ùg„=ÀJt—Ú@=æêîÈ{óËôÛ/¶1 ˜#'8@àOJà/ºÿ’Oþ”žÌÍÉÈÙ²Í6Û¬sÁ¼sÒ¤Iãõ65jTö+ö4€®L5yÁ ²wÜxÏîÑgxó.pN“ ›~ìNÊ’ÙËt¸„VÏó$ÇÈ~b4ÖG̯Y]3yyÛÐlæo° XÊ*Ðʹ¥•˜Ø˜'§I XúÆòPGRêSTúIþ 9Œ‘vR²åÆ[ºw­}·ÿ­›Ù›üSe/Óã¼åÿµ×€©‹mÉ’%Ë/¼ðÂ_<øàƒ/y‹ßä\ 'h'o–"cØdò¤œ ð'Å^Á ð\<[ÇCWhÍ€Ú@¡|]lÀ&º¶³u¢£ÄD¡¨æ©Ó“Ð|s€” \ZOpOðNPß •±è‡rèóüóÏ»ÿµ€·ÚÓ¾:ƒÐ~»à·Ùÿ÷§ÿsÏ,|f ¹×xmhÓ‘døiƦhÊ?¥Ïó$Çœê'¥oÐO4LÜDFí¦´ X¬CYvÏQy|ݧæzZéP«JÓ¹+Êe ãu7voßáín×·ìêöÞnï*£0ŸDÊ>õ÷o÷ÿó—¾ô¥Û}¨âà)“'å$@UÊ8PÄp@Òð‡{RÛà¿YàïûÌšM°Ý¥6`ÝÝã:Ð[‡&súA¹Œ “¬ƒog"€“2'óR7jûí·_Ï¿öÉ“'×½ OàI€qãÆù¡Xk§·þéVwçƒwºÛï¿Ý½¼äåT{> ¬¥£µN˸Ìj]*–zÐT }Ùs¿°.Ur2·¤ú†SÚšå+Ž¹Ù´æo° ôQ:yNieµEÿ(Çò¿ºO×cþ)Ì-Ë8mÓr,>÷©›¨±ø^?@ÿžÛîéfí8Köh| À'þøä?ñ©ÿ2ü¯»ï¾û^ô©5— 6‚}‚øF4Ã>K” >(t Ø;4…Ž‹gëxèBkü#M„2v•± ›èêשΓHXÁEËÔƒðk [øi=»œ:dö5j«­¶šêß pè”)S&y}]Ók¯½vÞ­Wàæ?ÝìîZp—»sÁnᢅµDÜs >€c¡“ö0 iÊ&æÓÅRTõ‹ÅJ]§òÈœâq;bÍ*`° 4ª@§ÎUóÄüb:Ž;fk¤Ëíð#—ŒÉùu'¯ëf¾u¦Ûý­»»v<€=í@V¬X‘ÿXªE‹-ñßõ¿ö/ù -$ð&@'%˜‡¬Á¼ž>Ú7–:P,ú’ÇT~òïÅ #O*÷0è²Ö.øG›¨Õ²ÛÿmÀ&º½Ïu´¿&'iìÑþ%\S‚uM ö ê%%¸'ð'ù0/c ‡å´ÓNÛmöìÙ;­¹æšu°Œ?ˆ§¬u¶øšÀü‡ç»»þ|—{vá³µäz 9›r e(cºZöôÿF1ì:s³þ:~0äè-†ï¨Ç:ëo9­á©ã¸×­Ù±6ò/³§l1½Öy9 øQ×ÜÃu7Ì@ÿn[íf÷Âþ†OûS?í÷ú믿qà 7üñÛßþö|ß57)?(tRÖ ^NÐ>¤È!yæenPIÁKÐ=2õโ’‡>´N€$³ €PÒ®26`]Ýᣳ“èð‚<©ž€À;6@N °.y‚w}NH9þGÊœ aÙh£&|þóŸÇ&›l²¾××5¾ÀOÔÙLÑ~þðÈÜ=ßã~·àwnÁc rÏ¢FÈÑ ø †EuÁØ€‰åÓ!U|tLJn7Wôv"Õ™é­V«@I:y>©’«‘O™=fKèª~Te›Í·q3·éfl=Ãí<}ç’B™©Õ xpŸ}âðkO=õÔ _øÂþ÷ÙgŸ]æíßr!8'˜Q‚yI‘CÊ:vêȳ_€yð ä±§Q&*/™ˆ—÷›°ö·Ó›wr{l·‡{×ïj®.æÝtð=,1ÀäŸX=oÞ¼Û®ºêª‡}b‚oR€sð¤ÐCOvò’jæ‘”}Å(Á>)ö ð’‚çâÙ:ºBë$øGb›(”·kBlîZ碣5†j L½ÐüÕ Ãèë1´9 € A¿¦àÐ îy ÎÁs?õ§TêÈôSF¬Œ¡,ûåûãg›÷ßn»í¶ŒíÃöµ_Å.¶Û¸Íýáá?¸?þõî¯OþÕ_Aq=õ-vzQºä¤@-Cú¿Ê“t¬êKÐNl,Ÿéš¯@¾+5hV^vŽª±e~1[® ×n¢_\#Þ¼é›ÝŽoÞÑí¼ÕÎnßíöe”ÑA¬@ÙãþÀ,÷ßÿ£þ©Ì›W¯^ Ю8@:t¬C¦¿ûô£Ž²ô—:öyP|RI±§Å¯zò …Öiðä6P(qׄ¡ÂÝzmÀ&ô>ѲÜ`"€† ^óÔÉIpÊ0îõì¨KOà;A>uÒOÚ¨gNÈäAòË.»¬ÖYgûÉ@ï—ýd ¾`¿€jt¯ýò®_º??þg÷×§þêžxî‰ÚÜËä0bºfìÒWórkÊ­Æ1Þ¨UÀ*`(«@ ì–ùwÂÖjŸUâR>)=×'f÷º‰ã'ºM7ÜÔ½yÚ›Ýv[lçæÌœÃ£]¨ÞîGýSû/^¼xÙE]ôë{î¹ç? ¾Á¬SGTƒ|)ƒGŒÔ1–¹$Ï…@2yPìi’z1èÈ“ÆöJ7À¢Ù@­Ýþoö@·÷¹®ô×ä$ À=Á?u”º9@¸à%P'O`ò°I>&C'ÙôR^óÃþðsçÎÝÍò}]³_ ¨+IWϼôŒ»ï±û܂Ǹ¿>]›xq‘ÿYàØŽéb£­ê‹ÕºNæÒ¹cr·û‹ÁtV«@w*…¢ëFváÚ¶ÙþÊüËl±ÁJϯ;e]·ÙF›¹éÓ¦»m7ÛÖí°Ånãu6ŽEš® ({»¿ÿ¤ÿµk®¹fþ÷¾÷½?ù¡Pxƒ¤k™À]S î¥Ì ÄHžùIe_à%à‡Œ=:ð”=&ÀCFŸš$þ&øG76 ŠÝEÖ&l ‹»[w»j0 €Á†Š'%ð—46 '40—^ózö˜Žqöàcº5ýÏŽýû¿ÿûýR_ ÀSø¥{?€¯V´¥+—º‡ž|Èýå鿸GŸyÔ=þÜãq/-})>:î©qkkÚÁȉ‘ VÞÖÖÒ¢¬VnW€°¢ýv2—O•¼U|dοÎÄuÜFëmä6Ûp3·åÆ[º­¦må¶yÓ6n⸉‰Sw³øŽ?ùǧÿºñqÿüǼÕO¬òv þ Èc:½H°O[LG¨ûR–ã Ø'Åž ^Rð\<[ÇCWhƒ þÑ™MJÞ5Á&l k;ÛPtÔæ$€ž Ð†Ž _SعHàÁ=x‚}©Oédò ì§Žn»í¶ëœ{î¹³×[o½)Þ¯®áý˜ÀW¬õ^–­\æzê!÷È3¸'^xÂ=õâSîù—žw/,zÁÁm1ÀË|•‹­GŸvã™Ç¨UÀ*ÐߨzÎéæZ¦Æ”Ò·1¶ ã&¸õ¦¬çðS|ÓÖæ6ÛÀ²¿ñt·õ&[;جõ^ð˜?€¿ÿt?:¸… .þò—¿üë `f^qÍkÀ.eðü4_‚}­CNéK:ÝÁ¿¤Ø«áJð^/^täA ­àÚ@¡ì]lÀ&º¶³ UGMN`˜ö„5ä%¯—: î} #h—«€U ?* ÏiUFÝJL"ïøqãÝ:“ÖÉ–õ§¬ïÖŸ¼¾›¶Þ4·Å†[d@òøÉ‰HS÷Z^}õÕ øüÇšŸXõÓŸþôÎ+®¸â!o¨&Ð&'('…|jÑ`?åÇ|´³?M1žØ‚=žàºšÔCಠn–îR›° €îîqCØ[ƒ‰BIÁs‘Ð¥&2ðíí¨¬È—Q=€XN 0©Ì—l,gžyæÌýöÛo»5}󶺆¯`"À^XWš¾S¬|u¥{üyÿU‚…ϸç=ç01ðÒ’—Üâe‹Ý¢å‹Ü¢%‹¾z°lÅ2‡ß5nØx44t4«€UÀ*Ðc¨þ×\cM‡ŸÕ›¸öD7yÂd7e”Œ®;i]‡eéº×Ý8û4ܘq=¶‚6œf+€GüúñȬùëâë·Þzëý_|ñ]ÞŽ‹¤Þ”%@— @:ò ôoDe~ò¤r<àåB/)x.žÍxRèëZ·>õ—Û€¬F÷x›° €îím=ÐSƒIŒ€_òÔ@ƒrád@7u€KpN^Rð±¥ÊãØ(ss<™mÒ¤Ik]pÁûo½õÖoŠýl ËÞ €¯$æ àbmUàÅ%/º——¾ì-[ä^^öröKœXºÂOø§ p³´ü•å.û´dõ*÷ʪWÜê×Wg7O¯¿ñº[¹ªþ&ê•W_q¯½ŽûkV«€U ý ŒZs”[ktýWÖÆ­5Îáz¶öZk;øŒ;Î=Æ36Ó5Ú_k¼›´ö$‡Oïò'Ÿä¦ŒŸâ¦Lœâð½üõ&­×þ-CÏWÞxÜ?ü†zè¡'.¼ð›—,YòŠ_¡è&ЧM‚yè ôK¾Ñc%%ý°AO°Ï‰¯ z}Êð¡|hCþѹM„MÐUÆ&l «;\/tÖÆ$†OÐ/)·žȸєà€]Êšçdô’§sCOJ=(Æ5jË-·œ|Þyç0mÚ´è]n¦0 €§R>5«€UÀ*`° X¬=]€€~€ÿàyúé§_ôßó¿éÑG]ìW†àT.ÿ¤°ç™@_ò´k‹‡.µäsB ^NPöêð©?>¨äáShCþ1›(lŠ® ©ã¡kÈ;Zc¨Ò+ Ç|Ý®ùˆî¯duá'þäI¢%/'üIèöøö”€œzð1p}£…ñ¤2/û$ÍÆ7kÖ¬M?úÑî=yòäè+ˆñ¾àYÀwoÍ*`° X¬V«@ÿT?é‡ÇýS_w[¼xñÒï~÷»·ß|óÍOøµ"ÀNpxwRê«PÄÈIæ<}I9FP~I½:L €— Ÿ<ô…6”à± €Âæèš0T¸[¯ MØ€Þ'º"—LÜ£éÉÊÿ𨆠M=xNè ‚qP‚u‚|ê(§(ü0aŠ—}¤ø5?üðéÇwÜžãÇ~¹ïÀKm"ÀWÚšUÀ*`° X¬=]|m-ö“~øòåËW^~ùåwüüç?Ä‹ØÞ) €>yùÈ?m)Ê™+ÕŸûð!èOÐïÙ ‡Ž ôš‡®Ð†øs06ÀJt—Ú€} »{\öÖÆ$Ö†à_S€n9¹ÊDüšýÒŸñ š§Ž4ŒçøÀ[<òÈþñL*Ô5›¨+‰)¬V«€UÀ*`è‘ 4þþk¯zÐ÷¼yóþì‡Là]6@ _ò1pO{£ÉöÉ\”%•ã‰~‚RTŸ`2ùL)ÿõ øÇ˜l@n™îñ6`ÝÛÛz¸§Š“X€z4‚{ÉSGÊInðܤ⤩Oó ðáG^Sm£,)x½p,=å”Sv™={öö£}ó¾uöŽ€ºÒ˜Â*`° X¬V.V ßñ/ûĵo7ÜpÃ}ÿöoÿvÀ6A6©àä Ò%%ø‡yMµMÊäAõ±€’'ȇL^R¯O€‡ MÓš6ÿßKàC² €Âæéš`6е­×;*™ÀÐ%ð×&WÑ!§öc?—æ© cž9sæ'Ÿ|òžÓ¦M[/L5|5OØ×R2½UÀ*`° XFNð˜?À?õO5€•§Ÿ~úÅK/½ôŽ»îºëyï'A4@7dI5¯>ìZGÀí)ô!O*Ç¢yŽ þó °¢I2ýȃZ¿Þ&X‰îR›(+ÝÜþÀífwÖW(™@V‚{ò¤Ôk  Á4xnÊ €SÖ4â¡Óú˜¹´ŸÌua¬›l²É„O|â{n»í¶›âg|ÎhãׯçÊ& ¢Á¦´ X¬V«€U o+ðú5zÌßÿ|ßë ,xò_þå_îxê©§–ù&€€ÖTêÈ5Ї^ëÊ€¾öeÞåx`Óc%ȇž<}Œz·0!@;tu­_Á?VÄ&ê6gW6`]Ùц['&°Êû\}}ÚAi#˜¦ N¨åe<Á|¥ yÈ“JìGŽã‚|f÷”aàÎ{ï½÷¶ä'_ˆ9~5OX³ X¬V«€U`xV€/ôÃcþÛ'WÒO¬úÍo~³À¿Øï~’€@[jÊÒNž4ÞµŽr#Êœe”c…(Á>m”±þ´k²ý࣭ŸÁ?VÈ&¢›uЕ6`ƒ¾“ ç*LÈ£I >¶OöÕ<`O Ö¬V«€UÀ*Ðÿ¨úi?ÖtáÂ…K®¼òÊß_sÍ5z‘€YR‚êÕÀœ€zò¤ÔQ&¥>F¡“ Æ9FØa#؇yÐÔâM™~ÑÖïÀŸ+e¬Dw©MØ@w÷¸aØ[…I¬5?+@POÀ2(m¤@ûŒÃ&9õ ¼K^Ú /³1Ÿö^÷-eŽ™~kLŸ>}ÊßüÍßì¶Í6Ûlê_ {´á©~EÀÞ-‘)­V«€UÀ*ÐÓàwûñ˜Ù§ýþ…¯?øàƒOþÇüÇüGyd‘_)e‚kNPŽQ踔yéC?Ri‹ñÔiÀ=Ǩ)×…Û >ö’‡ zÚH¡/´áþ±R6PØ´]lÀ&º¶³ ÷Ž*LУI ž2@1eò’’'¨†Œ… z)“xê@Ékÿ”^÷ÅqÒÎ1êþ¨“N:émxàÛ&Ož<Þ÷lö ÉÒ˜Á*`° X¬=U€ý*oòÇ /^¼üÆo|à?øÁ~‚  D7Þ´§€|LO)s€ÆtЬK? ö¡`§Ž¼¤ä½[úСIJ¾fÿ‡ðçjÙ+Ñ]j6ÐÝ=n˜÷Va Èg5(k ÐL4d€kPè$Ð&Zu!À×”ñÔC–<í’ÊñPÏqK[X‡wÜq½}èC»MŸ>}#?1}²É§ð”€5«€UÀ*`° X†¶øt_~Ú_6ïû†ÿ”ÿÙïÿûóï½÷Þ½/À®ÏÚÒÜߤÔk*Á»äáGYS#%³o96ðz¨ƒ^òåâŬQ|´ Gðµ €èæt¥MØÀ ïd#±ƒ »’‚—2P.u ”®)CÇz͈§¨õäIeŒÔI^ú oÊš×㢠º^øáxû}÷Ýw›)S¦LðºÒ†É¼<_°_(-•­V«€UÀ*ÐÑ <ôãÓ~|êߨùOû—Ýzë­~ï{ß»/©€.4)€7yPñO;(A½æéC;iÊþ¤dŽƒ:R¬ ì\'P.ðF”¥>sÒÿ†+ðçzÚ+Ñ]j6ÐÝ=nõVaÕ€Ÿ²ý’ÏÀ²w’”<€7x.”%ÕZFߌ%/©@øà7ùúí¸É&›¬×è+>oöò@<`“¨†5«€UÀ*`° ´Wf@?ñê©§^ôÀõÞ믿þ ß3@21³¦ÝÔ‘''…<¨ïÒ¦í|Ë>H¡ç¸4•ëD 4PèÐ$™¾äAëÚHþ\i›`%ºKmÀ&º»ÇÐÞš˜@…~Ñ@¹@@¦LJÏÔŒÓFÀ9ÆS'©÷Z–¾e<ûŒQŽOS¬#r®wÜq[pÀÛ®¿þú“ýcÿ°•6ù΀ Ìh° X¬V‘P>ÞGû«<Þïýßxá…ß|óÍ^vÙeæ/ôЀÕàYÊÙ1 ]3‹úZÖ¹0ê4Ï1Â[ê@å‚84©££ÐÚHÿXq›(lþ® 6ÐGtecø¾+ýX'C[&&$À%ØQ€fècTj€iêÖ!Çxê$ÿ˜NÆ€õAÇ“¥-¬ãøñãÇú÷l·Ç{¼ÙÿŠÀÄ*àž“x:¿,`Í*`° X¬VZüOñ…Gû+‚~¼ÅÙwÞù°ÿ^ÿýË—/_å3IPL­)µÔQ–TócK àÇt2}SÖòzݤ,Á¾ä}WY£øhiÀŸE° V¢»Ô&l »{œõ–U KÐÎ@¼Ðäש‹ñÔ¥h• €Fù9PúJ^زõÙ`ƒ Æxâ‰;ì´ÓN›ûÉ€ U&0€“þ>•5«€UÀ*`° Œ¬ øïègŸðüciÔúÿøÇ?>öÃþðOÏ?ÿüJ€ P+2’ImГ%§ž²¶Q¯i#°/ýeNÍC¦cG¬\ò’‚çâÙP ðhÒ>ÚF*ðg1l€•è.µ ›èîg½… 41 €^4P.”ˆÑŒ3pìeRê ®¡'È\(“Rß.å£TóRæ˜õ:Á'Óù €±'œpÂv3gÎÜrêÔ©“ªLøØl"€“ö󂨈5«€UÀ*`nÀÏõôWù”ëðòË//?þ£ôßç'ðI?A²¤ä%p=)“• |¥Ü.Ï|¤ÌÇ1Q€®yÈÔÌC‡FxÚ@ÑR´fÿG:øG)l@ì]dmÀ&º¸»YW± th"àÿoï|~%«ª/N«@7¿AðÛBÄÄÑ‘þƘ82qâŸçÄÄ‘‰1ΜèˆÄ‰°¿Â7H ‚@ó«¡…þžõª?Õëíwέ[¯ª^W5ë$·öÞk¯}šª»Ï«*h„Õ s€¹•?:Ôà+G£­yx§µÌ;e•›:Ø8fÛ×îüùÏþ|ûšÀ3<òÈ¬ß hç¹C|] Ÿ"Q D(p¨ xï €9£5×ßzë­+íãý/ÿâ¿økûxÿµVGÃ۳¦5ÝÊOYóM,çè§bSëU¯¼[ùÊiËjŒì"kiüoŠ‘ €›Zœ¥— €lœå¿·œk ÀŠMU©ÁÕ ¹_D7cðžU-«†Ø›k|0b·ÕW<÷мÎõ¸úÄnµfÎï×Âþä'?ùzûÁ‹O=õÔ£sþׂí¾qQ4»4ªØŠ»•ß‹Á{–¦]9ü)»*G¾Îç¸çt}5§¼p¬òÄÍ]â=LyáŠ5<–?iü‡Ò¬Ld`¥D;!èujF¾¯ìÿÃZÊšÐju4±žSÓ¬!K¾bäÔ‹£xÎQxÕ'Æ‚cwÌqù•ŽÕÚÅá°Êã˺¯œò'ìw¾óGÚÿrðéo|ãéSí‡ïlÍ»xmèGÙàSÙ ØXÚL¢@X©€nš9ÔÔë Ñß´Éçämþëíú®é¯ûÿûßßhÿk¾ÿûÓŸþ¤óÓŽ¬š_ š`¬øø²î+çÍ2ùjkíx„9Žï|0Ãqb·u½¸^×Û¦_^kS^8‡b ÅÕ.P{LãobœÒÍÀ)…Û°L¯cû0² €}øwxkØÑF€7¿4¹4¿nå÷baÞdצœ ¿Æ=¼‡Q‡§Êq]5>Ç¢‡sÛÔKªN›ßÿþ÷Ÿj_!xìÑG}àž{î9ßšwÕouh#@|Š@±oèd[Ú‹Øêº3YˆQàV*ÀͰ¬5ó²üõ^Û‡³Íu¶ó\ÿðï¾ùæ›WÚGøÿýÇ?þñUköu*Ý¥«éÕèùÂüÞ*[›iñ½9¯yrXåk_±).9,ç#­‡ë‚OìV¾Ç-\nÈ'/ËÀ¯–üÒ¦ñ_J±±“ €%<Õ»x=;ÍB² €Óü»I)°ãIM³7½½Økq½é®ÍùœØ9øÕêœ`œ³&Ö.ׯ‹ÃN]K-µ3eÅ?÷µ¯}íÞüàO|ó›ß|ì«_ýêC?üð½wß}÷]»ØÐ ëЧØ ðMa~Pçî“Q Ü üF¶úŠë¡æÞü³X³ý?þø“·ß~ûƒýë_ïüíoû÷þð‡Ëÿüç??hç÷†SþªC¯†,\÷…Ër€“S£ V}jdiÈÁ<Ư–:ð^-rk]ªe}ÎÙV¶¼þ꫆C9 ÅÕ.P{LãoblÉÍÀ–„\s­\³t«ôld`«ÿ >¯“­Ø,jL5ª£q­±p5¾µ&‡%/ë‡ò4æîÃ!7÷8=Œ9dkÞsî×õ«¬Ú–êê ‡æÖ ®¶æŽâö[÷´O <Ñ>-ðhÛx𡇺çÂ… wë[ã­92¢@ˆQ`Ïh7Ô×Û'>mÑÿøwÞù°5úï¶¿ê¿Ùþª¹}wÿö\o0½ ůVW¨Æ·âŽÉ׫¶6ÑšKœUǜƽÇéa~®^ž5)‡ï5Žá»ÅoåK„qÇ—eàWKþ˜MóLŽ­ÙØš”kM” €=¹Ÿn/,k=q!G)v¼ଚ\Ås¬7ÛðiÎ5>¼]Çœ§Z®Ç×V­žxž“Ï¡¼y|òÄðˆkþÜÓO?}ß÷¾÷½ÇÚï <ò•¯|åþxà½÷Þ{þ®»îº³ýE_ªÍˆQ D-+ æö•€O?ùä“k|ðÁÕ+W®|ôÆo¼×¾§ÿÖ /¼ðïW^yåývJMŸS˜[âš÷¾s“¯Vmm¦58«Ž^ƒî5›æë\£uϱâôŽÃkˆ«Qí-iü‹ [³°eAgN— €=¹aÎÀ̱¡­¥Àš×Né*É÷,Í+ÍðÈú_Õá8V}qzÇi7´öZ[ç‡#KŽ…# U¯xÎ!¾ó¦brÇlû}óú½gžyæ¡Çü¾|ðÂý÷ß¡ýá]íëw¶‚/¶û!Ÿ$lQ DÖ¶Ñ>¢ÿYkì?mÓ¿Ö~€ï“÷Þ{ï£wß}÷£×_ýý—_~ù}/¿}OÿjÓ«6WN,ÎèP³¬! Ž…S7„×Ã9Ûnò}îëšX‡|_¹jí˜Ê×CÇk€-¢EŒ¦ñ?!ÉN€lìDÖ•“f +ÿ‘„pø ìp#@âôš\Çðݺ¯¦×åV4ñÔ:ŸœcøS98XÍ/ë1~Ï:&ŸCsh0Wõ©N¬F§0ÏÉg,çj?xîâÅ‹èwÚ' îiÿ·mœoŸ&¸«}Ýàèh_j*ø‚¾z ËÐæ>lÐ&•Ëœœ#?2¸T"NˆÛR w³ªÆ½Í½ýQ^îQ¯F¾ÅŸ]»vM¬ÿ¬5ôÿýè£>i‡þjÿqk쯶_××_î?Ô÷ï/]ºt¥}lßCù>F9pçW¬Æ4¿š_9ÅîÃñZÇð{Ö1ù½¼gkãóf½æ¼®úº.¯åÚÅÃw[}Å`Í=òÁz±cò5ÄŽ4þCiv’ÈÀNd]9éâås%mç„Ïýoì\ᜠÜTàDÓv3u䑟²ž£±†O“ÛÃÈa½ù‡¯œÂW}ŸËëÜ_UÃ9|._ûp¦¬Ä$O­ì:‡æp~/žÂ<'Ÿ¡95°Õ?JÞxpÎÜ9ñ£@ˆ»T`ÔÌÍÁá`Y§b0¬ràSXåx<ǧW¾Ø”UÎóøÞlOùÎg®jk}­ÑšS빦Ês\5ÌMαꋣCc•]°N>Rw2$ ܆ ìËÀ—nCmsIQ`_ànÔØ‘­_yÕR¯7|brXáz#—S¬Æ¸Zq„Ó4ciÜuÇܧ®r›øª÷Cóû|œ{®e}mšå5óCsi8æ~ÍyŒUþ ÷h^ÇàÔ¼sªwŽ­óÏ© ' D(à è}ã4ÃëF¾æ%WmÍÕ¼bÇF18\ol='\Ãóøs,œU ¸òÎÝÄ×úU_Ï)Ü1xœkdáÉ®:åG±†ê4ª] 'á̉Q`ç d`ççQà„¼ñ5òµP|åtȧÞc0äF;ÆgnòSV7Þ|knaªÑ!_ñÈŠ£y”ǧÎç¯õ•K=Ök™¯ÚvÊåy='ŸCóiÇ'Oì<0qÜ'Ã:Ö³Â|Ô:åz˜×Ìñ·1Çœó„¢Àþ)ÀûÀ&+ëÍÑÃtðj9¿ð^Üs¦V~å{ß9ŽÉ×Ù©Ûsª÷CçUžyë¾×T_sŒ0懳ʶ©–k+¬úŠuhàƒõ¬°ÞðÚ^>Xˆg @6Î@äœ" àpÔŒ‘§\±¸:ä7w‰ã“ƒKnS¬Æ\9lYݘÈrÔ<\oÆGsÌÍ;Ÿ¬Ÿ¯®i·ËX^›säO^'ß¹ÄXåð±`Ä=+L£Ç]džw<~ˆQà¬ÐûL޹/qµä*®x„9®÷/ øSV\òÔ͵ްk.ÕùÑØÛk½f”×\µ†ù±ÌCìV~Å×àœpª _VÃqâ£ÄàAüŒ(öDlìÉ‘e|®àqÔÜ‘G$Å• î1ͳæñ¼nÄ!¯X~µÎ‹e£ŽpaË÷ÆÚ¹X_ç‡S-xˆ·PlÜBñsê(0PÀß8G žs4bç’Ç1|,uºÉ Ù–¯<±ûŽõpå9”÷OÀgŽj{›«jê5¦Û–t⺛ò5‡xø²5ÃÂS¬AŒuìˆÐypn'( D(°5xMèy|,5ŠÁ°ÊƒÍ‰õÞ¤!nÏÆ<äÁ°Ô®k©¯¶×Ô3wåz,ßcjd9j~ŠÓÊ–óQ/«±*†ã¶úŠë`þŠ'ŽQ`ÏÈÀž=!YN( ð†:jôÈ—²£P5¼ÑË'f.0b5ËÌWÑDëæƒ0Åî{ ¾oÖר»0xÒ`ʇ¯“«V\ÄXåÜwnÏ_‡Û«¢@@Þˆ§¬sñ±Ô)ëYÇ*×caÍÛóábáôbrûj§ÖLNVë×à:ä;î\rXåøÕ’ïY¸½\°(öPlìá“’%E޼ÁN5xp(Wì|òÂÀƒOž¸æ¥™×MGs—üÊQΛj݈P'\ƒô¼ûâyŒï¶Q–ÇýÌÓã’Ã:L–ƒsc…k(ùpÅcùŽË×èaSøQÑ:|ø÷|ÎÙË‹Q ô˜zÿ€_95L„“w®|op=Gc®ùz>\,œ^Ì9à`ÅÅŸË¡Æ×åsôÎOç¼ËZ¨—œ¬Æ(&wDºÁsŒzò=;‡Ó« ¢À) €=z2²”(°¦¼O5zp˜Zqå;VÔ;×}o|ñu£B½, 4y°Ê!v^ån’“µÞÏ9•‡çùಫbçàËjø ä&F<²ÔŽòÁ£@ˆsÐküœá<|¬êñeñÁÇӋ½ö¼ûpdÇïå+×c÷5‡Ç“µ¾®‘9Å­>\r½˜œ¬†8Øê%;Îï¤E(pH dàž­¬5 ôð7æQèfVù`ÂñÅWÌAìyÝĨ©Öp_5à4ݽO¨Ž|¯f×ãs»Ïz´6ǽÎ}x`½x #çV>Cóú¨ñÜœóâG(ªzmš«±êÀª%'œ\#Çc÷UKÍ<Š5Ç÷Zù•{V˜¯£®a´vá^7Š—¯¡: lõ’çwÒ¢@8T²p¨Ï\Öú øö¨AtN–›7 4³ªa>°3¯pÝÔÀÃÇÖ<bl÷¾lõçÆzOq®b æÄ:Žïµøð±•+¼‡ÁŸ“wî*¿^Ë(v\¾†æfàcÁ{v§W, DR ôde©Q`Mx#¯ ¤OG¶ò ‡£ .XK-ëÁª…ãÍxåôbçã÷öZ WxÏgŽÞºœÏ¼âÕÏáËj¸uŸØ¹ðás[ëÈpò±Q Duàõ¿Ö­ÂÉc©W æÖ}qá9Fžf. ½xî+Oã=ßç¬þÔ•Û‹{ëñ„kÇÇ’W¬A\í";~„?f$¢Àm£@6n›§2† øûT“OV<¬O ‡ydñÅ#ëźyrܹ½Æ»r·kÝ£ÆÞÏ%Þºq¯¬g…iè<ØEt2Q œµ¼p^bì÷¼|ç;†/«1÷r4ìžÛµ¯uúÆÂè|S×C«9ðo¸Ë†ßqxpFv.oT< DU úÄeÙQà” ø~m.}Jx²«xä±Ô*æÐÜ=¿blÀ_µ!0—Çyd§jæä˜ ®Ç«0ò²¾’7à€ÕxN>6 D(°®¼ž×ºŠ×X|°jkŽ<¸â)Œ<œoÍ?ÊùîÏ­™â)çsÊ×sŸœcø²•S±#ÒàÁk”ÀQ Üî dàv†s}Q`¬€ßŒšJUÓ…ç>g€'ŽçPGN5ø5çqÝ Fõ£¿Úo’c~_˜æÅå{0,µŠ5ˆ«]d?Â9ŽÞœ£â‰£@ˆ›*Àk{g„‹G®ZæÞË“c.ðmÅzoÍuÚÜiÖȪõë¯9Å•³@O>Îå¬ ¢Àm©À¹ë×oÍë¹s£ûØÛRç\T8$æþÇé<|,×K,‹¯œÇà`‡¯ºå5ê5-ÐÅ£çÀÁˆÝNåàÍáÀQ ¸sn §8žÃÇrÅ`XåzøF-œ}ŽëõÕ˜µ × Æ:vD˜xðš ZRQ œ¥·ªï®×˜OTEG(à7S¤óPMX¯®r:*Ükç`•37Öz9לøµ¼Zx÷xä{­8ulš¯ó%ŽQ TxÍ®8ñܼóz>VóË'îYÇÜ÷ZÇå{ì<÷Sk¦âÞS˜çä38¿â‘·g½¦—¢@8R ù‡¢À”õ†bÔ|:O><÷…)† œXë‘OìÖ}ç÷0åÈ»Â}|¬Ï†%GܳÂ4àV»È„s½9GÅG(¶­¯ÝuÞ.¹j™£âÄÔ÷ì*l”á~N8=Œœ¬ûΕ¯ÑË/2‹Çš÷çõ|j{¹`Q D¡ÙJ“Dˆü†cÔ”ªÌyòÅ«u‡ë<|Yüæù#Œ<–:·skë5fNp¬ã`=+ÌǨÎ9ò+¯æG(¶¥¯Õu¾Š×>xµžïåÃW|âžs.˜[÷+_CyŽ# ÄÔ+‡_­×9¯úðF–yGùàQ D• d`¥D!D(0PÀoDV5¢Îe:°Z[qå…a©WL-V9ðŠyN¾\üjçÎQëkP_í"»x$ç|òž‹Q 주v³6ݯyrXåñ«%7wþœ9*·Ö(Ö€Wí"{2_qâ)ËÜSœä¢@ˆ³ÈÀl©BŒQ`Bzƒ2Õ¸V.Ó‚×ZpñÈÉ '®9ñábÁ±sðÊõr=+L>Ö±#Bypž§F¸sâG(v¡€¿&ûü#\Ïác™ƒ¸Ú^ŽçÀ°ÊÉ'Æ‚cG8yY xÕ.²‹ÇQܹ#îhŽàQ D¡ÙJ“Dˆ(Po`¦ÖÊU,>x¯–œ–H¾Zå4„ï"ÇÜnåkÔó/²‹GÇÜ÷zçoïçÙÆœ™# DÃTÀ_G·yu^Ýçœ`Õž&ϽÚÓæ4W­­˜çÝgSv]þÔ\ÉE(V* €•…¢À¨78«QçˇNìK#'Œ¼¬×Ã÷¼ó·•¯sÖóq·pÀj¼ '¢@صþzëçªx{\縬ڳÊë<œ»ú½XØÔð¹¦xÉE(v¢@6v"k&Q`…õhÔì2Må+¦Æ}øX¯ƒ¯>~/7‡ãu½¹j¾7'u§ÍQ¢@8 üõµžonÎyî3ŸcøX8²`ÕNq¼®ÇcÎÞÈzýˆ< D(pf dà̤Ή¢@˜P wƒ4Õk*¯Á§¦ÆõÔä…SƒOÎqêÃÇÂÁ:î>ç7²µ¦Ç›ÃéÕ‹Q ¬«¯Su§áxû~p¬rîÃuläís8¿æ¼fʯsLq“‹Q ܲpKdÏI£@˜¡@ïFjUÃ[kˆU‡¯SæqNåùî‹çÃçv_œ{ûsxs8>gü(¢À¦ Ô×ÈÞ|s8ª«<ݯçðÜÈŸ[Ó[G­Å~î'xˆQ`ïÈÀÞ=%YPˆ ôn¸æ4µŽXµø:íÔ\Îc‰•¿Î|̱ê¼õ^? D(° ô^Y×TŽlå­Š½võu>ëZ<? D(pP dà ž®,6 DŽ£³9s­õ¸6ó:uS|Ǽ¾.ÕyäÀFuÊrÌ¢@ØV½Võò=¬w-=Þ\¬7ßëÍ9âQ ¤Ù8ȧ-‹ŽQ`†S7r4ÞSÓôêcÇ4x[¼š«µµfn\ç[^ˆQ`•Ûzªç™šw”áuî©xsLÍŸ\ˆQ`¯ÈÀ^?=Y\ˆ;R`êpn3=š£â>_Íùå9Ïñ9þÔ¼sêÉQ ìB¹¯Msys׸íùæž7¼(¢ÀÞ+ €½вÀ(ÎX97Žë4ësæÓ%Îå!Ç:k &6 D(°‰ë¾Nmr®Qí>¬a´¶àQ D½W {ÿeQ ì¡ëÞ€î¢Y_w {(c–¢@X{ó3’E(¢À œ»~=÷è—Ò(¢@ˆQ D(¢@ˆ¡Àb•YdˆQ D(¢@ˆQ D(°‘ÙØH¾G(¢@ˆQ D(¢@8 ²pÏSV¢@ˆQ D(¢@ˆQ`#²°‘|)ŽQ D(¢@ˆQ D(p dà0ž§¬2 D(¢@ˆQ D(¢ÀF d`#ùR¢@ˆQ D(¢@ˆQà0ÈÀaP@IEND®B`‚ic13«­‰PNG  IHDR\r¨f AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs%%IR$ð@IDATxì}`•U²ÿ¤5¡Wl R”ÅÁ®`ë>uWß®úÞºÛ®]W¬Ø…Už½÷¥(R”" ¢ôZé!=ÿùÍwæË¹7·%ä"$÷ÜœœÞæÌÌ™S¿¨êêjЍ"hšˆnšÍŽ´:ˆàAMЄ;?Òô" ‚4aD@îüHÓ#ˆ0€D Є!aM¸ó#M@ Â"8@†@„4áÎ4=ˆà@M±ÁÚ,JS·»j&vÛ?bïsêp«ÖÔÞqÔ¿É›¡óÊš<ØD¬D®&¤(ØUšR·†#Ø#ªnPÂV‚‡Ye²€©n;vU¶]ý"¦˜|ðÁ^YþÎqãÆÙk4ì¶ŽawÔ½÷Þ{lFFÆ ÄÄÄþqqq=£££ÓY§²ô”Äá lÎHeçíøDþ+”h«xôª`ÏR6÷WUU°Þ]^^¾¡¤¤dõ®]»~¸ýöÛWp8âW²C°5ü¡•aã©æÍÞG1®Pc¢‚‰ Á¦…XDU¢‡ "Ý¿ÿÄÿú¯ÿ:·eË–g3¡Óá“Ò¬Y³¨ÔÔTb“’’’(>>ž8Œ˜ ˆ ƒÁñ€z±‘%NB3Ñ‹®¬¬¤²²2Ú¿?QAALŽR]Èa;˜1ü”““óù3Ï<óÉêÕ«K` ª½¥…FÅ 1À0˜jÒ ÀÑ+ÁÃŒíÒ¥K"4˜à'0Á÷c"nÙ¦M›¨V­Z ±'$$¡r$<<c(--¦°oß>ÊÎÎSÈa†°†Â[,™½µuëV0H`¶´ Ôq¸KPGÜ @ôåc¯¹æšŽÃ‡ÿ ä#1·k×.ºmÛ¶BðÌêXZ$úÁ†¿0„¬¬,Ú³gO$–fÍŸ?ÿÑçŸ>“ëf`K*!–’A„„ˆaáctW¹yì%—\’~ÖYgÝ–œœ<:!1!½}F{Ñc„¨ÃÀ vîÚI¥%¥»‹‹‹?ýâ‹/|íµ×vsËÀ T:#€>¬A„ Çü(‹èu^¯">?nÚ´i3¡ÿ966¶W§N¢x!Oæï~²‹xæÀ:/ ÒöíÛ«+**Ö3cxüüãëܬrÖ*(#8,¦à)}¾.äÅqÆiS¦L¹Eüñ,Þ'è±€QM XH3àiÏö¿ÿòË/ÿmöìÙ¹ 0{ŠpH3‚°ð6áÇßxã=† öoÕ ïØ±cLçÎe…ÞJ±6A`§aÛ¶m”™™YÉ[Œó,Xð×'Ÿ|r#ƒ¢Œõ!Ï" À ­!~õuÄ¿úê«»ò¨ÿ,ÏçOêÚµkT‡"[rMЃ5[f;vì -[¶TóºÁb–®{á…¶pºZŒàPÚ9hò ÀõAô²}ÇfÜ…^˜Îú9ñÇÛyQ<dž‘ð¼F@¼}X ‰àwÞ¹†5 uk ‰ÅÂ&Ë,·WôãÒÒÒY„{0%%åRóc˜øÑWaUùeù´¯dåîÏ¥œ’*,-¤’òÑ¥¥TV^F•Õ•"y”W”Se•àÏ:®†øèŽÏöØžS4º1£¢£(.6NÅDÅP|\<%Ä&Pb|"%Å&QJB µLj)ºubkjžÐÜÎ:,vf˜T¾ÊSÈÛrssq¦Àf`¿)#h’ À¿-îcƒ> ÿémß¾}J÷îÝÃ"êï)ÞC›s7SVQí+ÜG9ûsDížöcv„€zàWì@r®­q£ö~T(Ää'éoï­„¤&vmÆ v“‡Ë(Ù]UYEÕU5'Á,Z%·¢6)m¨mJ[êѪ¥'§)µîÁ¨Ï¦M›hçÎE,ü•ÁÛœK)k],¨þ­¦MŠxúrp‡?~üøô‹/¾øu&ü㰪ߢE ön8µvßZÚ°wmÏÙN…%…M±@Ü0Õ.D·Þ T¢±‚wà ’slŸµ Äg„FàÉ}=ZůªšÃՋð`7ƒ0ø1c€eE%¥&¦R×Ö]©W›^tT›£<ò>PG~~¾œ%عcçò×_ýâ÷ßÓ¬ØÛ‡]h2 ÀǨÏÀçÓ]×ó^þÿã‘Gw´ŸÝôksÖÒ/{~¡ÌœL*«*¢áˈŽQÞ0e d±ƒøñg˜€˜ÞÄRØO‰\㺅7"‹=ºÛÍòð7DŽp!zX +:â‹Ñã§Ae f†À:.:N˜A¿ô~Ô¯u?dÓ Ó–*ø Á½|jôIÎL@ ÁѪ4Ðè€×¨ù>Äýø“O>¹õŸþô§wxž,ür ‡ýHe—dÓŠ]ËicÖFÚÏsø˜Xácx¤áóå׎Ë=2ú3Ë…vÃÏ&~Ô”•ú ±Fà„8ÿ9•íôi·èÃgø¡ïé»LÀ4Bý”àá­¢¿mV)Èe!6™à+YZ¦;K¸'wey%óBïŒÞ4¨Ã Ô6¹íƒ‹eÇ€×V<ñÄ~ûí·{9S0L À Š4Ш€Eüº­'sý‡~øÜ^½z=Ëûù‰¼µXúiïO´rçJÚ·‹‰žoñ ±ó@Üè·#ê C€èÏ )›¥0h¸«!ˆ•]þÀàfÓæŸ0ÛòKzË}¸Y•¸½ëíí¯Sñ·$ˆú€ BüˆW ?0&vqW8va`å`¯¢BC‡´Ž4°Ó@:ºÝÑÞÕ¨³›· q~ dýúõ×ÝrË-ŸpöÚÀAÙ)h´ À?¨c)ŽîBäOœ1cÆC<Ç¿¬oß¾Q|K½ê¯ï\L?íü‰òJòˆ3±GÀ#>ÛEc¤w¥kÎUcWâ¶ÿÀD©aü¹“(ðo‚ ûÐuˆºFJpÛg¼dîÏÍ€¿®À‚‡Ó±cÄ7#•a0E"3`]ÅAEy¥%¥ÑqŽ£a‡€øÖ!­]»¶://ïß—_~ù­œv tm ìS‚FÉ,âÇÈ/"?ßÅO»ãŽ;>e‘¿_÷î݈ˆíXD«2WQQyÅÆÅ ÇÄÅ8#~œÃÀviâ?kŒòè`ðÞs!p&| ¶»Ä·QÍ0x!^“VÑ-(°M!xúF‚‡Ÿ?L#C`»2>ó/»ö0! ¨F8AJ| ê2ˆNîrr½»õÀNO ÖÜsÏ=£ùM)Ö)$°­ 4:`ˆ£¾®ò'^wÝuGŽ5êsùS»uëÆAõSKv-¡Õ;VS~I> ÁC¼ÁƒøÙŽ‘^$,ðÅ:«üÎüß?Ëôpƒ¨e„³¶Gþh– D™0šÂχ²‘ßGp£ò ÚV/^è>CA%ð [€]˜_¦C5HFÁWWT áƒÀ­ ¡Eb ØyàI›7oÆÚ@Á—_~yö³Ï>û3WYß"¨ ÇVa£a†ðì  ¹­ÇfsÔ‘ x• ?Çxë£~Þû3/î­ ]<ÇÁ ‘[„ „îCì×ÑDŽ82¯Ç¼ßˆô.õ²‰žíGëìíÖ4A‰B3h$¦G{}¼ÝL6iÔŽp!x&veÆN!z³Mf€)AµÙ)©Ö0-ðbeÌ Ê*©s«ÎtB§h@»v5B¶ã813‚ŠU«V]Êë,N¨ëØ.lðÅÁFÁ,â×Å>™ïóÁž«XäÿgïÞ½£[·nr'Øgm™E+·¯Qszˆü2êóˆ/„¯ó~?D}Këè®D®£¾+pAâ‡-â· ]íÕ¼HQá…ƒ•µ‰ìk{P¤×逘XÐ5fˆ¦ £¾0¬ 0Á‹`ìÂØóÄn'Òè#F­ª¯{÷î¥_ýµŠ· ï¸á†žç8º.I A{à‡ø“ž{î¹[úÝÿ¯í2ä5_€ä·fïš·q•V–RL¼#âÇÆÇ:â>F|3Ú àÑSL:d¤·G{žÁcÄÇŸŽþÖ?Õܸ^•d“hâJáä Ÿ´ã~6Cb·¤ ×u&zqcä7Ûƒ.#0‹‚")0ðØ âW“Hgyv½v øáÚ¹{'­^¹ú‘k¯½öanï~ÖXhP&pX3Ä'x’_|ñÅ;ûÕïºN;ÕëŽÿlþÌõenÏÄ/„šÝ ~›ðá–•~>kÕ!í3Ñ»ó{ã–ݲ» ªEÜÞ ~‘ÑŸ{••MÐŽO€ÿFì×6ñCì‡Ò@q ¾a"°&…mÊN€Y$Äè/Œ€M‘ÀXB]ê0H ƒº¢1½ÇH1uù‡H¶gn§5?­y®º‹Ó³Æ” Á˜ÀaËü??Ìpÿ‘Gy‹þ2Wg`…¬6äm ÙëfSqE±ˆú2òƒ@ìg"WS¦²Ço>D&~]éâ6£=ì b%x©¼·iS+ ¤Gº¦ªêDô<žý=ò10‚7°ÝfÍ@™ƒÍ`w· u§ÀH:5¨`“é@iD—Bcû¥Þ­z[µ nEy8=È[…3&Ožü?œ¢A™ÀaÉü3¾}'o÷]‹Ã=BŒÁáëÆ˜·mý°å{Š6#~¬1q' Ìtί ~éÅîŽú÷kVõmq_æø\šK̆¦mĬ5ò»µS‹wPïFbÚ°hè&iÞ>ƒÅ¤\vÛ iT †`v twÀ]°× XS‚r0ÖÃN#{ŽªSóP>vx{ðy~Ÿâ.N\ĺA$eXmÿ­”.ø‰ØÏïóýõ¨þG]‹‘¿®ÄÿöÏoÓÖœ­“K±¬Aèû£ã™ °ŸˆùÌ@ôz¸GFuvÛóûje Ø|BÜÆ.c$ÝÛ0y}…Õů¡ò©K™‡J\_mw%­$÷¤ÄE¿¡SÑÏ8)…íÙhá Âä£Xnϱ†ƒ¾Eãœ`Ñìç„Íßð mÏˤÉÇOF!)àî©p­®aNˆ&$wñG=Õ§¦Š÷*Ò‹$No抈‘XYfÍTìjqc aʼL¤uÅP„™|¼Mˆ¦¶öoên[t ïþ‘¸èK(tÛµ=L3 ¼`fS§‹8„ \ŠK`ž±¹«`=¹àIÊ*ÎrÊá?¾<¾ï9 >&zøM˜ÀAc†øÁ³Áñp¼7‰¯SsÜqǽtÄGDó›ü~‰É›È2 3éÍ•oPaYpè8åÖ̽a—ŽÃ–w` svèXaŽèÃâ4¤B~|†§\-Yäc‘Ñg6€4ìD­m c;Ï*kù!üÝ0  jöu§懜=•Ï»¼¦èváh`* jõ÷§\ÜB?ÂÎý ¾Ç/অ°cíHÖŒ ñ;LÀÁ«8–DCÒd‰ —_ziñ‹"zã¨?7ðø¼þsÀ@ ‹¨ƒ- àEüàv ýúõkÃãx¯Ÿðç¶BU[ ¶ÐûkÞ§ý•|]"ë%v¶G3¡Û¢]w*æsÕh©ÌéT;ºãÒe‚å/Sº(»­qíT®ž†âϹØyJ¾È[Ò:‚J 5¦gyvÙÝ®°U3X{}õƒFY©ëÆ‹¾gT@¿€³‹[ÀZìÀÖî48Æ\3ø&S– +ŠèÕ¥¯Ò†Ü ¡¢0ß÷ÀÐ'Ä:èâ 3°3‹£¡,pºDÖ),½ËgûSð‚O¨j}Þzúdí'üÉX>ÜÃs|™«I§8¢š3âcÔwæüî<ßpx™r'ëün_ó{™ãY¼~¾æ¢ðóåï1p>OMï¼³[Û̬+ l¼ ”Öß:ô?“œLÍ:ì _ œÂú¦4)þXgb¿ýUûéÍeoÒÚ½kí*´ïÿ Ž˜Âtúš´è†½Â§Àu†gCY²èÇ}îã­¾¾uyÁgKþúâ×/„øu~ù˜¬øƒ `u‹9½Íöw¤»˜"b0«ú\!ª*Ì …p9ÜVˆïO ³òö—Þö”—/b¯ °óö·û[ÃÄdÜᬇ‡ Þ4`Zd¬Õ4ˆ—} |‚bkQi½³âúÃÀ?P¯´^ŽÿÀ^ãè zàƒB·qtÌ+¡¡Ê΀p§¼†ÿo¸Êñ'Ýu×]çôìÕsb]òÈ,ʤ~ùˆJª!ö;#?$YÍOpDµ¨xge~¸É§•®âWEñøÃZVóyevÞéuFoÌùYc„R?­¼Ý¶¿¯0¼þ«ZãÚ&ÒøûÙñ"öÐ  °ôa¶?Xúßôµ„'/_[Õæ Naçˆ×’ÏØŒÞÁLt4$âêbz}Ùë´5kÈÄ:=€.@†N@/eQ0l Àš÷£ ýùV_»cŽ9扌ô Y‘eÿ  Ïm¿÷ó{´¿z¿+Úƒø1ÚƒH§¢GGI‡p©¾ˆ_!t!’D¾â)ÁôãFìá€ö7×¥4»ïíÁA lý‚… ™0>‰ž ¼“ÁHÖ™!À]\ULÿ^úoÊÞŸ·R'ètú`/{*öEÁpO”øå°Ïßþö·™|¥7¯öªXJe•eôÆOoÈÑ^ˆûº,úát¯Û{˜¯±†H†=|ÙæÁ\"=s{(vÿ‹¸SÅ}»| 7¶^ÝNvVb÷NS+Bˆ •OˆÅ5šh¾àæÓâ¼Õ‡¸Â*! å‚Wlb¯éG°P¸ú ÷öÁ»~Lw‚?ðS;Æ!×çT*i¦°ølðtïþ½ôÌâgýBùº}L:õÿ MœX¢?HóþÄ!C†tìÞ½û_ê²â?sÍLÊ.ÊvV]eëÅñÀºÕ‡E>³z+ÜšG|é(0puVÚ¹ê†:[¹µv<Üþì×;Ží¶óôö×|½ãØùªÝޱ{»ÂÈ6}ÁÈÕ.xä`%iŒäüÑ0W²Ô#yºÒ(ã¥b|ÅBõŽüôÜ÷Ï9™†ðôÁLà¿A/SÐè(lSpMÀX·¬úó×T^ä-XþN{W³·Îæ³ý[x«W÷e¾ÅÜÕá°8¤Íó09¼Ã%à0‡ÞA‰zl—;MÅé@·°‡1 æm÷v»ñLR׈FùòÓ0˜ÁÂí¸»oÔôœïðP|kõƒ5XHzq›…xŒ'ŒWödsŽÅ}9<ÆU(ˆæiA5¦U¬y× †u5몪PÖeýJŸ®û„dX>@' —… žÇ±ñ̸NÂ2hPàKôÿç?ÿyQ§Îú‡úqÎ_r¡E[Éþ*æø²µ'¢S:ˆS\Û5\¸æÂ::ß'‡Òù¾Ýù¶qÔ­¦í;”æç¸jÒ¨[M;õ ŬoºPò>Ôã Ï­üÁ×íW—Á›¾¶Ý†âcŠsraL¡ŠqxÉŒ"š ß1™T2`¿Ù?EÝZvékE “’Ò’þ ›¿ÿýï3¹4>t5ÓWƒ¿+ˆq³¡òĪs´æ|ÒéÎôv¡³í³_?«Yà3s*a˜[Á ±ß¬öƒ+c ¸Ãv]ðƒ)ó7&k„¡ãÕ »ýƒ¿†Ù¦Ú%­Y»‰ïnùÙþ¾ÊA¸¿Ÿ¿©ÙýÁÄŸ]áƒ|‚¦a¼ÁOð xcÜ‚WÆ­çIï0 a ‰ÔÁO]ŸÒµ5ßúñ­é ôºý€Ž =…ƒVSG!×,@D3ú3HDô—U~ÓïŸ<¯Iâ/õ:ó*‘e~åÇüxãÇòT·¼Ï¬ô뢋̈@øz¢uâÎACIbäWîí£,‹Û¦m×:êBÜ:×Ô0~®ñÕTÿˆB…Â5T3Ô|íx‚OŠ?¡\Á À€‹`¼(]J“Á vH±<}-() 7z3 þkÙ Р臋Á­A÷¨°¡3T­ATƒpS)&Ca(2ú:´S›6mÎ õ´ß{¤å™ËÀaž•UˆUíy¢"'ühìɪøoJÄÞ­ŽôÂÀ”{³]¹¿Ž&ˆcû©Ûõó1âk¾š‡ÆU;_av¼ˆýð€+ œ‘“~¸qE£˜ È¢ŠÌ¯ØÎÜþrö‚­²ØÇf%Žqr'TqÈ/fb‡ÉÚôõiÖ Ã¨o¥ÓpÍÇvû‹§þÓÿáÁ!Ó÷þêì‡ñMñ‹Ñ° n‚g!½b½Ê hÀgàwQe½µ&´õÐÓщ 'ÎY¥”Ò`R@CI`$¨˜Œþ—]vÙ\yáìPAô_º}©¬úëœ_nd`Lø"b±è/ ~*MàüƒÓplãQã¯áLD¶óÐ|]X¼”Ç+(â[ÍQõÛU,}#¥©M€Laä>P¥£?@Ò„ nç½L0… j^æ<ÚY°S¶öd´‡øÅˆü @wôGnš£1t¬»`¹Õ?˜‰´Xé—<`×üЩ>ÜOMÄ÷N£aÓáá ®]oÛ-v¼Áà¡(?agVü•B#Ñ*~oÙ·…þ³ñ?NÚ ÿAO +ŽæqD8H²‚BpGÿ^½zµá‹ CB=ò»tÇR”¬öË܉GuHÊRØÄbKU´³£ Š.Ð{›MñSÓ4~f\T NLýúSrT2}÷5-Î_,; (Sä§iA0”8ÒGÂ1:ÖZÀE©·ÚÕÂ€Š ²ó„õœHÊ‚2 aNó YT…3ÈA¢ýfÓ74ªÇ(¬@Oüåá! ¯õë×Û_BΦVóðŠjÕW>'Mñÿ¯ýë­,²À?¨ú:ókÊ-Ëuüxä÷˜`ôÇ–æþ r4Ú² zfX¾G¶~öVì Q 4%m Öì4jÛŽRbøC­ÆÒe-/£è¼h*-,u¾‹Kø!/;ï@q#a‡@¸¾~¶¿» &8 Š‚VÆÀ\fу› vtyqpßþ}ôù†Ï9rpº}qLûŽJ ‰Þü•p *€•0€ävíÚê|Øþƒ#"ø¡(£¿>ˆ‹+"0¬ÑYføŸtžáÚÆ²ÍSšB±µŸëÓ¢Ý3=óÓ3´»d7%4O‹Â|¼@«ùqÖÕ!`pI›æO °ñÀÉd:¬3`%¦a˜÷ ~ƒ1X8ÿ gàìžgKü@ÿ@Wüåá³8άñu!жh1Õ«ihÓP¼ô3@B(õ˜»c.”ȉ)ኘ÷ó \SvÌ—z„sòÊ¿ü°`R:À"N¸µ#$Œ+äm•pûúV-“ZÒÕ}®¦Â…´?g?áóPšRHþü?¢"€®²¬ðÆ%áŒÎ‚¿<ú NcK#¿Yã“ýrKré‹M_¸Ùù³€®˜¾âAgk ;ÈÇ C»ì ]ˆ€‚‘[‰}ûö½¤mÛ¶„ã¯?d:£?R(Ú0]õS9)ŸVÞ à…7i®¡G—ЭÑßõ3D wZLš¿êÐÊ+éηï¤ê–“Wmñ²‹t3%ÍËoâH@〷 ’ë†]<œ¦«¦ÇS³‹i@$*ÈÚàÿ‚ èÌng:™øúb:»”£¼Ît‡/ éá ¶Ö]ˆë£Ð ¤J8ñÄ;òÅ…Nxó<˜ú!ëÊá÷ÔÑxá‚Xe-Àá]Ñ›í:ß‚ç½çÞÞn_ý¼ÍÂÊBŸU[·mÝøØ´g÷*+*£ò’rY @zÍãS=»8âjLÁZ?àí®e÷_qÕ5A%œ‹ß€óFê…Va}—ùOü´=A_LgAoì Rè±^ #x] C³sÿ„K/½ôÊPÿíà}:F~pA6°ÊO'Á_9¦îù3¨¤øŸ£Pºr`㥜ew”º÷–ï•…?‰`ý»óÅ;©¨¬ˆ’›'Sl3~È!9Vl@ün™Vüˆµ‘C@ñÌ4SqKqAÜ6þÁn¤OÄ]ñPfŠ×ÂÍ«+?a  "ö›·i í84(pAgLoW-Y²äÿqdФÐ#gªµd[ˆª> YÛ 1==ý4ˆ'ÁÔö¢í”™Ÿéœúc¨À¨Ñ[rUö‚ÌØ`êö¼¸®i‰þÞሣñÖ¯£®‰]ÅU›wn¦µÛ×RbËDjÖ¶¥´O¡„– “d˜§Ž¨¦ Å…‚íV»šGñV^ñ&£ÆYàÐÝä‚MÙ›OßwmnžÆ:cz;•ºÖÓÞуºëô)"þóóEš5kÖ*.ÎÀjA懘9r‚¶”pPpQÖÑ|ŒRæN8lÍJVUM\ºkZœ~®¿!â¥ùKéŒVg˜ÔŽQ,>%ž’Û&SRë$ŠOÆ$õ¨Œ0€5‡W·D±áÚÙCì¶¢Ap4ø »}ÐÌÉÄü7¸/xjì³7̦+»Ò#š·tzÝñ«A˜×‚ðp:k¦¢l QÕ• ªýÁËPpü¤I“¦ðµEÀ°¿Oµ6k­—®†ê¼HG~!v=ïÀò£¿¢”Õ<‡Äí?I]žY‘I[ ™Ã¦tuë–œ˜,×ã›ÅSB‹ŠKq^®îÆŽXš ,ÝÍ#øÜ4æþØÞ€ø/§ý$^5EX´y| «ÿ8+{u ÁBµýUÂÆÎeÌÊžEW¥\åæÔ©]')¯¸`I¥:Î)Û±D ÀPÜ`G½pN¤X&=7ž‰#n¶+®«)wXºÎßA¾ðã!Kv.¡ÛŸî 7ÐG²§ Ë:Ÿ ¨+àæ·À¢H³„„„¶øìq0µl÷2w_T¸s<˜"Ö#WV"4ÙÎ@ÆèïoÛOâ+s\ý©¿v†v²]Z¼”Æ¡ôd牲m:PûVíùTE±”‡¸’.8F1Õ˜!`ဋCÆOÝj r˜¸ýŬ ž‹ÉvY `)À¥¶.ܶ0(½î@EEEùœ3èR@§à¡*Tñ]ñÿæ›oÜþAÕ¦¼MNJ¤æê ´öHuõ_$ž< ·d‰ÕTüì/Á¨]Þ€çc›sݸ©Å#ü{™ïyÔõìAgSey%UTTPe%ÇÇŸÈ/ ˜' µZ?øÛøi‡¹v“ÆÆoIÜçQZ(ÊPÖ¯{~õÀOÐèÃ1úÚÓ€èQó­ @dî2¾œ02”O{ÿ°çÚ_¶ß™ë0Ç“ÓR0v9#g€â U~0hÄ—c˜GÍZñ9æYÖå®s àÿ»P–PÊ‹xÿ¿„™@ßPV$,p_4yøc €»ªl»Œø81hÑ€Ø?‹K‹iaæBMæ×Ýþ8‚ÍêDüȼ® ñ!n@'°Òƒ&%˜UÙ«„øPšŽüR2ª‹a²Îâ³~à¤êæXbW?!vöQ·Æî‹«½æ§á(+:)š^ÝúªÛImZ´¡súŸC%y%rÒ€ ±›Zs‰˜M ftoÐ6c!Ûàº÷â‡a´À&nÉc¤ ;~<´§àÕ+—&‘C9Teª'@<ŸJJæ-‰”ØØàYlÎÙì2,êÛ‰bD¬@Á¡(:¸(¢Õ0Q—$%’‰‡p»“¦n Óø0!l«ÞFŸmùŒFw-ASNBó¦Ï£ÒüRŠoÁÛ€¼/+Wƒí„{Óƒ€{fTNAÇÄaê¯vñrü%®“Ìä s/Æqý-‰`Ýž Õ$«e€îX§¤¥¥¥ä²â`!ÊFB^ •c€¡Q(>þÚk¯= ‡_@µµh«|ߣ;è[æB4æAÖOFnca.ni™ÏcTgÃ_Üü˜‡¬`®oâºnS?ÛD¹Q‰QôîžwiwÑn©{«ÔVtÅIWPñÞb*É/‘Ë@ò$¸U¾GÄø†‹à8ðÖ’fÅøoÑ‚ÒGNqmÊß®ú› ‹çÂÛâX¢)ûùTxóO9ž˜†¾YÏ@3€]‰_ü d] šÜáV?-[ýÔDRcWÊö§ÅÅŸ7w¾IýZö£Þ­{Sû´öô§“þD/}X>J i%–?P*õ¶3ŠØ›Be†è÷`g%ø «æÁ¦‹ƒHdüƒŸ¡´í¹ÛƒÒètÈ©t'ô :E.Z*[ý«º2pa|{/InðùÏ[B²Š²–ÁUr¥®F}Q¦š"˜3ÿš¥ ,ãa»aWF¡þ® ®ê£ýµü@Û©Q4õç©ôÈIPr\2ÞïtZ–¹ŒæfÍ•g›ÀWq\3´Wš˜i‘‘8‚Z f%z‰kW€IíÈv–p1ú#®½Æ·þ jWþ.Çà?è5NbP]ª’ªàçˆdδì’l*­,•'¶DÌçã½ÚP×Ä”€‚)L0oþ…¸P¶)7~þü%‘ù§ql?)ЧÙeÙôäOÒmƒn“à›N»‰6¾¿‘¶ïÝ.`Å£y¤88¨¸ ^) †ñ«å†¿:q@è¢Ø<À*˜ ÀÄB5²ùì‰kç7)Ae%e²HÞÌ9µêdRû?oÆE]xá…ýßyçl ¡C#sè8þri?>ÀÖÀj÷þÝΨÏs&˜ûãì (Y`I@ìUäÉW”pÕD‰°«[M•(ì0»vÏöÓVE'GÓ¢ÜEôÞ/ïÑù}Χ¸˜8ºçÌ{èºy= ~?UÇVËT@0=2ˆ8Y€Hý(—î#žG8⨰ `⃀%ÜF ›8nÒ#§úã!Õ¸ ÀŒvhœB•“¨``lfdR ¯õåR°VUšEͪP%WHü6™ ˜3‚¸ôìI×@(ò ¬ଌ•p½M*ÿ³H&€F ¥4­ååaÅíĸÔ8ú÷öS=èØŒc©mj[ºcøtÛüÛœ][òÙ€¾¹¥gAm›µ¥c:C×ö»–žùåi= á³Ï.S«•QÄ£Á àt­Gvg…Ôò Yˆ¨n+ïZi5__q4ÉÐ‰èæ‹2Hg´GÞ2RLŒú]ýØø`’=Ûwç±vP CÐ#G-ƒFu°ª&(NâW®‚b™ë„ôÞþÓ„ïV ‡“O^[~vc½‰ÖÛ]Ó„Ò{Çóv×Äö´¡ž1É1T’ZB÷|•T”H„ñÇŽ§qÆQIv •– §–öLqÕ†X¦J$ K«˜,##?§%£%FÌrK—»š³âT—sžœZóƒé–ÜQ­DiÜZ7íõª{-·?˜€¢ ”²Ô·¥³‹0­¬°zäXÞ[ZJÀ B‘4#0a|19”ç¿‹Ê‹Ü_÷ù±À¥¢?ìzXüàÁŠ»Ã±˜ÿpÛ~6±sWK,ÛOÛiÔϯÉ-ØR¾…î]t/Ý=ìny—àÃþHÛ¾ØFË÷.àí@ýŠß¼"žðìΚ‘ÍòGÿI·ÃP;ç"v䆸¦n˜–rãZ~bEÚQ&½GþZÍÛvÃ.•5…š0;=æúpãºplÎ0‚üÜô ¬@‡¼€9Ц-(ÝÌ >@ 3€ÄP¶ Ë ¥Q:ò»RWI®ûò¢ Ýhµƒ Õ³–›¥~jÚñÕ(Lãx˜R˜%ƦÆÒ²²eôüòçxò]#ï¢n•ݨd/Þ_!¢švžG5o‚!fÔذ]W·Õt»°øÅ#4æÁr»Œob–9v¸E›0wÄ7‹ešˆF4æÐFk¹µÌC±_€oL¦BJ®p›_AiA@âE è¥\ªE@9¨ž; `‚tr U\Ž˜ps„Ëa”Æ"Ÿc"H›[Ï~äØÙ×[ P®)ùÕøùò·ãKâPÿqK£¸uqÍcéÃì(cmë;ŽãéÁQÒM_þ™víÛE‰Q‰Îa!, :MQY]åâ‚·ܬ%Ü2µ›Õß_-´ªåaÇ>HvÓ.·(VÚSkÚ)aÎ?§‚&®à¿Øñ `0z  É îj¹ìQž“S­ÿ<•=êè: #ëÂ)´2¶VeUeÜ 4Ršò— 0¾GcѬª íZ#*o;€¢~ŽÍ‰kû#­ÆÑ|B6¹"Q¼âÛ"ަmœF훵§“:ŸDiÉiôÐÓŸgý™r¢r(¾/ â#"¸ßp*L­º'v§î Ý©sBgjßžZǵ¦æ±Íå[‰Íb›qDQI%K5Õ„o'ä—çSAeTP~E>åWæË9‰ìòlÚW±²+²©¬ºÌY¿ØÑè?Øa¨ð°Ýj‡?â[JÒYîCÎjêëQOøÙíR»úK i‰ñ\G<üVpKÿ]8²¯^VY˜(MU‡”¶® @¸ ´€²rf¼‡ŽÊÊ'‹iÑÕ|È,ð€ùiu‘ŸˆB€+%^5½ý´#îþ€|FÙéÔ¯®&¶ýb[ÄÒÝ+㦣2Ž¢v©íèñ‘ÓŸfý‰rø‡gÄ¥íÁ±-hpê`:&åÑÉ1Á?Ö’(‡ÉˆRbS(#!ȾuÝ^¼¶o£ÌÒLÚV´6o¤œrþà‹¢LtGM—øµßÄq8ýS¼´pLÛ綉ãˆ]Û¬n´~F þƒð¡•¼Ó°»¤ÔYˆ&Ð!F@\GÿàÄi2 …hf0µ@urÔ01‡Âhƒëºf?ý €8žM¼Þv×<¼Vç¸ñ¤äzþcp⑊ô¿‹ÿ—þ5ì_Ô«M/aSϘJ7;‰öUï£ø–ñ¿98¶Ù±4ªÕ(:©ÅI+a=ÛB²´ø4‚îŸÖß#vÖþ,Z—¿ŽÖ毥•¹+é×Â_ÝÇ^eÀPLòHu˜8 ºÄŽjÃÏ಴Bí&®w˜$Ñ㓵.þFÔ-~ÇAèÊ›øC‚v( U°3ƒÝvû­"Dù‰!ÀS ±?шcr•x£_Ó¨]Ü.nš*õWw}Mˆ÷ØÀ‘æÛÜF/Œ|Z%·¢Œæôä¨'… ì¡=ŸöÛ0ãSާ‰©wrïú6±ÁÒµå{)ÐCÓqC•»@+²WÐw{¾£…ûRQu‘L—Kf ¨¥&¨¸«~þÜWM+?¥ »ƒ!ÛË+ð½”7M†DŸÈ9TP«J¤µ,Ì+c¢bœã¿ðWgÈɶ ›Ú`˜P¾òUb"¨‚÷²k<ÉÇ„I¦ò«…iLt ɵ*—þ8ûôÚè×ä¸pÛ”¶Â°&™›)¯ E'²Tƒé‘ië(mZlÝØñFÜbp h¿iX³¸f4¬ý0ÑU´d÷úhÛGô}î÷20€¹ X5$lÓ|½ýl·Ø•A˜2Ú3~ênõãýùÁ_ô å6„ ±¡.ªNhÊÛ4©¶ýÕŽ­µ{›®Xä•§w¼p¸…˜™UƦÄRVbýó»º0ƒ4I Gy*Í)¥Šb³Eèu˜¤¡ê•L}“úÒ}=î;¤‰ß±ÄòÆÑÐöCé CfЩ©§Re#;oý¹r~ƒ¾m¨~ñ—à¼W»jù1®@)mH8\œ®ŽªNô‰¼ë-„Z1 ‚pZ&¦4í3ZÜ~ªï¤¬ÊÖ|ÅîäèLÊA@C*®Ž ãŒÀ¼Üy´b× :&ýÁÒ’ÒèÉ3Ÿ¤¿}ý7Zž³œâªãl‹°M\:>õxê߬?ÙìHê”Ø©![õ›äÕ)µÝ~ÂítÑÞ‹è¡åÑúÂõÎ ¾—w¤§z5ÚТà©f`ã.ü‚¹MÁ]‹)ˆ·å|ñû¡Äo(V „«&Äý…HMa×)€wÃ${ú2m?Øm·w> âfy / Åò§~yŠ^ÈxAq𣤸$z˜·ïž7ÍË™' ƒ1‰¼EXsت;£å40Q³Ózû…â–8ÜF˜öùªÛ.#\öz3Nè§vG8š®.‰ó|EG]?t8¼€¥¦Ú5O×ÈŸ•W<ò×Hº±|#ÍÛ>Ft!×7cøsg±1±tψ{hê©ôÞž÷œsü¥a9'¡±rBê tN›shPóAΧѲއh^˜Ü2äJX@¯o~âøì…0Nœ­³ƒÞ$F/·€jF‹_07*‹Í0ä¡xʦⱘpãgÂí¸HUoje´1bšÆÛv4RXL®¦kuŒ*’ú‰›Ãݲ¬¸š¦AM0^웾y: ï8œ@ü¥å¥”À'2!ÂÞ<ôfê°ª=µî)Šm+Ÿ÷÷ªÿìÖgÓ„ô ”žøñ‡mÃ!–ÙCo¤•™+iÕ¾UŽô"ã<ØÍPœ³Ëõöóé®A_`jÀŸÆ°Ë ‡=¬ €Øñ?ØUÙ"¿†kÒ©R»/ÓöÃ"¡*õWwƒ›è ÞØ\¾™¾ÚþìmúrKƒ3éŠJ¾œS\(Ä›™•éµ!Þ=¹{(§ Ç%æìül*ØÏWGQ³ë ‡l`ÇÎ…eÂÅï¹&¤ðz…Æeñ{]é:Z·q}þëçî{u±Õ±ÔµMWêÒª ujÓÉÑm;QûÖ|©ˆÛ‰Ñ#~t<ßIç×”Òä¬Ê–‡7øQ}„C¶•€)`ïðƒbÂ@ý!öãËMŽàèô¶„bÿ¼q,˜Õ×8Þ¦†yOc/:;ÐÔ›„R(ÈÇ™qã &ƒ~(䘳ë/}_«± (-Kâ7±7B$ªšš.¬&ØÎê]ôñæi|ñRÔ~Cè‘·¡œ¢:ã¸3Ä/16‘ú¶9R^ÂéH<<HaG!-•ÏܳîÙ±'åógà×e®£ÅkÓü5óé§ÌŸDä–u…&èæ|%ÄŽÓu r¬7Ànk/?¯õp_ÜÁ«:Fo+ÛF[vm¡êm U¼¨Ã‹ƒ;|\Í!bN“Ê; <½‰k'Ó%x!p‹>RÂwææƒz ¾ØÀõ 7hÛC2ô’¨R/¸_0·´“ñJãOa·ñ·f*±Ãû/¬ Àm4·[joýIÃm W¨i°F}`hÞ~R–â4…Q—çªØÝu4añ êÏãÿLcîCûXÔžpÊ·:`Ÿ,ÿ„^û*ØíDÑÛóXYCp#yY°@Ö"¥ ê3Hôõç]/[»òvѲmËhÁæôsÖÏ´©`“ír‰ßùUQŸ—e„Ip¾ðw*¸9FoØù)-<È!&üÊŒÛ<¯‚†Û’w;šñŠß›€ʃصKØtû]b!¢c¿ÔË0°Ã™>‚à}´[ÛÓ¶kñg¸J˜Â(LfX€4„[%?ÓXm°6¦h1ZNk½`r’ü$½Ø_u#%|ªb:Êâß?  G8ÄG]ù¿£÷|Ÿví¢g.{†Z$;;-SZÒ«~•øôš¾lºl¥¸6•n¢ K7Ð ^ $þ íÉÒON=æTÙkw3bÁå^i½DOè5A`JŽÍy@IDATÿÓÞŸhIÖZµ€V寒;çÁE)Cð•/¼¶å½GríôM£TV»”ˆÝ¶”XÏhÁ]Ë lÃxB—µ,¶+€öp«(·Ò~Jâù'†,¼:šÆÜ>`Åbk`õ‡Ïÿ +ÎXÙżPÎyó|YöŒ±  Qˆ³@3ÊE,v»v ñQ€"‰Ý¤m0õ1e´ _‘óä”ÒúlôgòA-{îê¹4yÆd™#Côþâç©[Ûn,æG+?¢;æÞAåq|œGaYE/á+¡ûyK¬˜oÌ3B°éGôcf0àTÜo°ì«{dTGni.-ع€æïžO‹ö.é}5¾¨Cž:*úÝ(ísÁø7êÂÀ0Ïç5w­Å,¼V—òGCJù*pI5}yõ—Z¤_sÍš5ÄŸëÇv°Îb˺ˆëôA°JFy˜ª]@˜¶f§?%i ¤•¸ÕnñCxÅñ—_Èþ¨òFç¢Ó¼LS¤ãÏQóªóhæš™tõ1WKRüÃè}J÷S軬ïhKéºðßÒÔ1SéäÞ'»qÆ=–zµëE7~q#?/²G>Z*åb®”ïWí¯’g¸fü8ƒ^^ô2%T%Ðàžƒiø‘ÃE:гn¦A,i ir~at·ÑrZqñÎÅôÕίhÎî9”_ÅORG˜'ØWðnõcSüBýá'èO¼”&ò;Ñ%aM~È3L*¬À„Ï&È“Z²@Dðu”˜Ñn »ššõƒ·G}•&Õü …ÁŽy¯Å½G‡›ò0r7+kFŸŸû9¥&8Ç‚´fÛóôŠmÇßÀ*ù~¢ÿú?tù°ËMJÇØW´nþòfZZ¸Ô9>Ì⹌XuÇ f¦_½¿šþsí´H¿æHºäã7shTPÍÐñûó"`¿ñüçа!¦=2ã9š|=_–ÁÛõüN½|…†÷¿E\㸗X5¡DÐŒŸfx€®_ç~tFÏ3„`ñ5÷¨VQtï’{éoüpèGU«f­è¥q/Ѥ.“¨¢Ðy\‡¢›ña›4ÞooÍûíéq”Ð)º$PbW>JÛu·DÚ¿ƒÎ{êS¦2Â,!®¿e¿.e{рЈ©»ôèÞÐËöY°ôáeh(~hœš¿e'A1’ƒ qº #¿!|¤Œö˜k«dÀñ¹Úuל#õë_§ìbϤ¾±}©²™Kn½ª H> z3ë úÛ£=æòf!£=ˆ^E}í½GH?·¡ëÿà éüžçûí¨1}ÇÐ˧½L‰‰Îv3.L t]`nö\I[YÅG‚Y«Â{]ÒºP~~>õIêCo|K¶éîêh9‚*¤ýh¦"QÉÌXZ2ciGßåG¾r!¼w$ýßÜÿ#¼eÕ9­3½1î ßn¼,|Ê¡¥F" €™ù•Pü5Ž2Dé#䇟5ò«=˜y }Ö£À¨˜4Šÿë‘`¶zØáíÕ ¤ƒrM ²Q‘…0%l˜ùÛWžšþ`™#ÒGЙy«,ˆ:¾ÓñòbÐe\Fe)e2bC|Ç¡¥iGÁêÚ~XÿƒÜ!hÓ¢›ãÙýΦ%—ÐYOžE§8&?‘.:â"9Úûmæ·ò\Ù×;¿v®sžXg©ôt]Þ:ºõÓ[éÞþÒu 9bpÄ Ô¿{yÇÏ-ä,ñ±ñtÿ™÷S»ùíè韞–òqŽAî€p+Uƒ‚‚³ÀCQ04ŒMñ·Üæú[q—Aôˆäå0`^`¤@X¬<«Å+'€ `;VY!WQL¢³,2ñ»qÅöÛþ» ë!WàøÎÇÓsg?G“?šLòME~_Ó0ow|KúL A½ÑäG&Óco¤ã{ïæ}biæå3éšé×Ðs_=Gx[à’.¡³úœE§v>•ð‘Ö9ÛæÐ;Þ¡»PuB5ÅÄrþ¼ûÝñŒc Ã;eðOêÍvÁI8à¯aêo¹5ÌÅa+ŽÒ†°Ã\»2)0<ÿÂÊÐÌa2Zq¿;;ü¡ì8vá¯áb5@ÂgBwG3â#¾vˆ¦µóû-ìZzÎýƒÕaX¯a²¥vû··Ë'¾1wÇþþ¼]ó„ ý÷_tîßÏ¥‡®yˆ.9ý7Ëö-ÛÓ»7¾Kçï4sÙLúö×o©mó¶4áø 4ià$:³Û™¢wí¦÷×½Oolxƒ¶óOnhò“bÑi|Ìw Xã ú¾Ò}´7o/Ug34dF ;TÂë tß%÷Ñe§_æÖ–æ@7L½ŠË‹'˰%ÉÒ†<Ƈž¢Ê¸ç«¸ï‘Íá&x´ÔÁ]//×éÕß6a· u»†É^ £¶ƒ35£8ÜÞÚ«€óÇ6ŒìˆÏS`9†Ëù `Oåª0Ã1%­W~¿…35®æ2P¨å_2øšÿë|ú2‹¯2à•Ü"Ä×uqD"ú©ƒN¥›^¹‰–o]N÷_r¿û?Äí‡þðÛõXºýÓÛ)«0‹žþæizfÞ34¼ÇpºäÄKhä‘#éºc¯£k޹†¾Þò5ý{í¿é»Ýß â¾,˜bÕÖf×Ä}Ïåoûô6š¿q>Ý6ú6‘}óQzá“d”‡d†úã´"˜v$pFA 1ý*\‰xÀAU@I¡á¯aÆ.8èÃÉuÔ·íêçm"N8U½€Ûø`µS 3í|—•;ŸgÂW&àú™8.à%$;dþWSRlRëó±ÿ ùÍ—ƒD˜+ÆÒŠ=+hPÆ Éë/çÿ…f­™E3—ΤŸ÷þL/]ùAP5qÈD:²ã‘tõ›WÓî2ç Âü­óiîú¹"ÚO:aMž, R€ùn˜<@¢ý§•>L»Î°«».vk›h»Ÿ¼B¦³zÂ¯Þ ”òt$Öi€º}¦Uë1êCä4£¿ø1”\ »ù!?o»Ï2²çú¼õÔ:±uKMOK§+]IS˜êŒž|6`næ\—ßóxyàÛßÒ¹?ÒYOEÓ~?†öê–u\—ãè“k?¡«ß¾š~ÌùQv¢*£(»4›ûæ1z|ÎãtZïÓèÒ!—Òi}N£û†ßG7ÝLoø˜Îïs>á­[µLlIÐýÛõ§ËŽåÅJ^W˜µq½±ê šûë\¹×€cÊZð0(q¦A¦XËÀìµ,þ±' wœó§‚…i¸â­m"OuûË¿¡üûcà#\ŒíÚ(1Y|rM<Äzl噃:î¶óࣥ&žËÇ!¬A´õUSFL¡¨¼(çÞ/ÊÍß1ß#«›Ï½YÄtÚ·.~ýbza.‹ß–ÊhžAï\öíÁGtùc¬r¥¸g¾®È¯’áÂK§_J'Ý=þÕãç)GO©EüV–®·G1š^=ÿUúôòOiØ‘ÃäÀQ\FŦóèßšD~^hÄB¦.þ™^?¤û-Ü8¾áâ~üuFKX€Ò}­Fƒ˜•ð™¸=GHMøáHøŠ@_nûRZ_ŸþÃgµ~×õwÎþ9Æ[~{÷ïu³Öo×þ8‡ ð¤Õ-«é®wÑ 3o•jD|öëÉñOÒ­o%ÂQæ´!˜Žã”àŽŠôàœé„N òJDª›:ºýÑôæÅoÒ=§ßC \.C4ó™P]áÕ˜LÁ÷@ÄÁŒÀO„‰®[WÔ9v½€¿ŠÛþn#´1j²¤(7'ö€˜ºè„…&ˆþ®©iCssáfšµiV;Eœ7ð<ªÌçSt|slæoó”&Ÿ,[xÄ»kµqøƒÌhüsãiWî.ÍFÞø»áäèù‘ÏSR ¯I0|%>ÏÓ‘&¶-k^¡¯Jáï²h_…» “M¦.ø€Ò«ÓÝj2}íÃ~mжØ6 l೿MOþìv’ºÚëÍB)HÅ=Ä…]þ˜ãaT—Õ|ˆ÷8§oe—0óD²¦?lM»ÿµì_7ûB›Æ9®çqñóƒ €ÑœÌ9$æ¸Áãø¥Ö4ç>ÃTNû±ˆ¿²l%ýÜÙ´|órø¸„ôÞ…ïQ‡ªr‡@ú„ù,ܵâU{–g.öHSWÇQGÑ;¾C­JZ9G€Í=‡Ã¶sÃWû@ð•þ ¡ÂÂÏ â¨¨c Lô:âcž¯{Ìj‚I4QqmÁZzeù+õꪎ­;:÷ÿ‹†ü NöÙOEC¼Çj~eó‚,à†Sv±i±”˜Mçÿû|z÷ûw=Ê>2ãHúdÒ'4(i#=@âÇKX#˜¾vºGüú8:·ìLOŸõ4UïåËJ|ïÜE$†d0ÜF¦7^}€_Ç4aeÚé B¼Ç–“@4l$¢¾ÛaÞÌMÄi¾û¸Ÿ–m_VÇ®!™ËËmF<ÂðÃÀª¬UùL>}2_¬*ä8Ì$@ÌòJ¯ÂW¶ª¤?}þ'úÇGÿpˤĻƒo\ü]Ôñ"Ù¾¢OÀ°¾Ùó }¶î32êãÒsé<†*÷±ôÂÛƒ¨¿âƒ_xyï±¹ÈPÛ¤qëü:¤©7ð7ñðÇÈy¾šŒz3Ïe 4~E×8ØúÂ[ÿ“?žLëö¬«C×ý¼ùg!!$'Vs·ÏSÿui×EÎñC S|ˆ&€½w^…Çbß´UÓhòôÉÒ>NúèØGé/þB•¹NZ™–ñöÜ-ón¡_öøsb8Ž\‘]á<†©€‘×¾¬W½™âë’ ‚S8iÔ BŠ õ1ëÍB*LŸ;^F|¡tFhi!'gÓÕ¾r³ÃÙ‘6Pøo†O«äÄäÐøÿW§'º^þôe§mLÐÎ>z5}³s>ì¡ÎÄ‹…¸r˻ոv xðúCo¿Eó1ßXf³öü‡æý:¯Öûñgš:b*Åð)@>̘G…QtÉû“hýžõåÔÕ1 ëf.üü2!ÅððP﫺Õ „_ÁÂ5-ây+„…_…•Tóê44V©ñ•#Ñh·Íê( ¼L G<'ºn/íæååïï7s£½,ZC,ϋϧ‹Þ¸ˆþùÑ?©¨¤!~ÕËŸ¼LoÏ{›·Óœ´xi˜øTà²ìå”_ZóR2;x,Å”°ÈÏ»UxWRà@¾KÅë1ü䨧›>•/ ­Þº!®ºà¸ èµ±3)¹ˆ_‚¸Î!»ªvӸׯ׉a¹KIY‰äWÉÓ‡Ôî¿ß¬__üâ·íòîU¶ÓQN|±›p×ßÀ3Fx ÂÇíMV£'™€q(¦ºE5=ýãÓtü=ÇÓoÜA ×,$ÜžÃ]ÿÝûvÓ§ß}Jþߺé)þš0¿ 1‹s` 8=WUQk;°uóÖtò';»f½À·MÙÄOŽÍÍš+·ù¾ßò=}þÃçø„ï¾÷û÷¨My™J@âȉ͡‹þï"zôóG©¬¢îÛƒ+Ö­p?f"ï3`¸)ã¶Ý›|¸Ñm ›p«ð€ÒvÀôÖo5qÒÆ»¦É nù˜H(5~H.þšÑ¡d2´±U‡vâ!g—>KOÏyZ¶úð8Ù!,˜ø¢[ð¨ÍW‚1‡‡ø|L^ó2çѹ½ÎõhÙÕ#¯¦9ÏÏ‘'¸¢š9gï="pºÝ»iõžÕtñà‹ià­)3;“®:ë*7Ú‘í¤.ùHNn*Ù$ëUÍ«èá%Ó‡?~Hˆ÷ìÆfyú]Þ 0G~AøPjK{H†;Mpª;kÅAñ4~Þvi³¦Õt€þ,vùY¦SXøþ×[Ê¢¢: ÐãÊZ2gðI¼|º=k¡mÇ~Ž;¦½Ã¢R™zyA‘c%WÌK8Šú¶î+Ì÷ùí³ŠXXüjëW”—H×sÝòÚ-tÿÛ÷{äÔ¹Ugúðò©b9+ 'ùªð¯•¿Ò˜çÇиGÆÑ¼Uó<ÒørÌølÍ^6Û}Ó˜A_¾àª_½@¨ç]Dêög×ðÆjr»q!ûî¸-‡£¸8?׉uþÂO×xŠëÌöŽ|¦ßäÛurƒŽ× pÿ/ÿ"vû¶ðÞúË[”Xšèl bï݆œÅìm³%Ùe'_FÉÍ“éá/F`?7Ö:¥5½wÅ{4´ÅP™`+õƒú.ç;ºà¹ hЭƒèÎ×î¤ÙKg‹$ùþ¾ü}4gÙºü—Ë›zX§0`@µêä]ÇÆêÔ}µMýaBÙqŸ°þëÀiZTw…ÑÊ— ?ýio·$>TÿdQ™/ÒŸÆÃM=]/ÁíIpŽ®¢ô¥½/¥î-ºûlYÇ6 W‰ÿúå_K86ð´ÿ‰bóÇ}?ÊÇJÚ$·¡ †^@3¿›I/ÿ²<2íòi„7 š%4£™—ΤÉÿ7™ædÍq®õ²$“À”ðcKÁzjÑSôÄWOÈg¬õ3×Òm\‘õ‹ÖlòLL¤‰ E4ŠÀ»P”wAîàeû¼ò¨Šª¢¹[çJx7 e}´á#ºü•Ë=.aª0cÒ :+ý,‘*^^÷áÇE!`êÉވ?K 2ÁT†%0¹ÔØúï@ÛàËq¨êÍB˹uGCYé|Ôgz††û um)B{˜Çëß²?ukÞMàèï¦w»[NàÉaœò3í¾ ÇôÅy_Ðy½Ï“ä'õ8‰&ž8Q˜Fè¯v~E_žHûËjÖ ¼8éEÛi¬9ÆÚˆëxeXnbý¢#ëά»“™Ö30uL¤oó>PXŠ ÷‚…+,L<ï>õ(Kãú0½ÓÕÅ]or!Á8\$<ø(``tJ‡SB;ž û]çß9¯ôà?>8±×Dzü”Çi@ëûºLÄÌ,ž¼âIz輇ä¨.¤o³¾¥‹^¸Èã+BxŠlڦѸNãäÓdr¶é™i`~"3ÀÍB¼ &Ê\çþ(GT¤¯kà[0x8±Ãú?¬ ÀƒƒyqC4Þ#Üg Þy+ãP ñ†ª®=íZarBw®éߤWޏ’®:ö*çã$Ì–ä,¡ñϧœ¢7 >fòÌÅÏйÎu®(ã¼Nz¢°’„¥>k€é Lqcå_õèßC öþê‚æû ³ýýÅ«åxY°r; Lt]øT0g‡{×a¶ äÖ05ítÈÞ«E¯[3òø‘”—AYYT\MÝ›w˜ööso§7¾ƒŠ¢ŠdqeáJ÷ü8zçÊwäua$xnâsÿFÞ,®™”÷Wì§‚²ÚS¼‡RãS©Sj'yÔÒ$Šü²|AôÜ’\Ú]¼›²Š³hgÑNÑó6Ò†¼ ´¹`³<‘n/blD¸müR;LvÔÇW¸ú:­ia†QÕ›€KUEìíFæ™Æõço‡«]Mï4ÄžœrKpØè¼ãΣç—}׌RáÆâ€vDÿ¾ßï%ë²By´daæBù`Êʽ+å½C—(chÈŠh^6Z©MÅEíf…KrgÂ$eW7L—µèp™aeõ­´ ÐúfÐHÓ%Äâº}­Ù½†²ögQÖ†,úfÝ7Î P¹΂Oz·ï-L¡oç¾Ô¯k?:åèS(59Õ_UBöoÛ¬-ý¡ÿDãã)‹·/¦OÖ"7w•ìrÎR€43ÐQµS;›.¾Z~v¸4aF#¾¤±ÜóÀa#‰Ã÷/¬»á«vÓÌ kuUº “z{röÐôï§L.H‰«Ûx¸Ä eÂèѪ‡¤]ºi)mÚµÉͧy³æôîÿ{—ºuìæÆ™€˜N¼ˆ³é1T’ZB+sWÒ[+Þ¢{>¸‡~ÿèï©ã%éïÓÿîñÅc7ÓzZ°¸8¬Ë0ºÿ´ûiÅ”ôþ˜÷ib‰”Zêù"Q=óoŒÉêÍ”‹2mާöˆÉhª‡ÞQ¸£Î8دK?"¾É‹³÷ϹŸ¶çn÷›ÇŽ,Î+ÓxÃ×ÙÄŽØÌ zC0’&=0I>ü)üo~ðרmJ[ç4#ýÅ @÷²S'>ƒB80ÄŒ!:#šžüöI:÷¾siwînͪÁL,‚‚<6ê1Z}åj9qbËå}B÷y²@«ðõèŸúô©ÀØ_Y @ô¥a´z3€P U±Æ5hãVž¯öº˜v]â7†¸ø4W]¾à+¯ò¨Žm¹+ÞºÂ㤟ßÂÕ ¬æçÕO*}`ZqÚ±§ÑY·Ewnt“÷ÈèA¯_ý:%T$Hr&€×¢šóB4¿:݆u;ç¤ÜtìC‹òÑð†ÓÜÕsݼÚ‚#Í}1}üûiÁÄ4¥÷JªHrà‚ÇSð©²qa¸"¾¤1n¸Â~z¾¢¡á#¿°3- E €B‰Øã¬ÏY_çVwhÝÁyˆ•%œÈ[‘½‚&LŸàqÈ™î/~ô¢s7ŸòÂe%kÞœ]œí–=åÌ)´#w¾{´Çt`PÏAôâï_¤¨~¼·‘î4àn7áoÊ!|2Œ/ Ř¯É Æ/Ow¿sw½>LâV,ËmŽ F>@?^õ#Ýq”“á<¦ ‰'4 ¡”Ã'JxD,³Øô¸˜¢aÞ¦áŽÒ°[ánzËÏoìvïCA³ŒÖ¼‘ÓÌëyÙwaÖB:ùÑ“iúœé´¯`åäÒÿº‘–®[ê\Jâ-@¹ˆÀ°nÐZóhy=Ú÷ ÇŒ íyÛ震Ρ»7jsì9tשwQUŸÄsæ,yÈtBû1ëä3¹2Œ+Ï­¢hêâ©tægÒæÝ›ÝüÂei‘Ø‚n|#-»z=ñ»'¨SL'ù,º|=I§?‚g^¸ë›ÞaÊ|´<;<\0ùÖ›„$RCœ1¢ Zí¦ÇÃ_E"f}ÓùËï0ð¯HŒOtDJ#êʨÎ×ùÌÝôÑMÔíÆnÔéòNôÊœWœyòèŒW‹ä(/Ì èå3_¦´DÏ…þiÜŸ…v³$ðøhÚ¼g³‹ª7Œº.éwIÍ]b6ú/ñÎ"¶£ù‘”åEËiÈýCèùÿ<ïˆËn®á±`áðâc/¦%×,¡—Î|‰zÄ÷pÞ/d‰ÉcjhšP\”Ö€&4­ÉŸN»ÙT{0º8ÈÔ›Ô©PÓ¤ rcE©¿ÕX4Z5âª=bmÊÛD{ ÷8° ñr"ŸæáFžÃÃJøàK<"‚ó×€°R›{¸Ù‡¹:æí²ýÇ `\Ïq4¤Cíó#ޤϺQ$„%;iì3ciû¾šÆG&>B'·=™ªóÅù¹3w´úWúT*äÔI¾lĤ”6/¥[?½•F?à9ÅʇéÁØ£ÆÒWW|E÷¸¸æ; * x×;T7ê[—¸Vû@øáVáe¾nZ¤ÜÀQ2 |åÛüvó·Ì¯3N"Ùâ%ç& ï2ÁƒÈ–?Q&_õå¹:ÂÑúLð[Þ}—ßGÏ\ú ?\GÛŠ·ÑاÇRæ>g¡‹…3®šA]cy²€§X@üõêÄ/%ÉZnò­Â…ûÒÐ{‡ÒÃï=ìwáÒoåB Àöè¬%³èÑ7¥Ë¹Œ†þm(½:ûUª.t—ûN£¿z7„¿ÖÕW^&óÿ·÷pV×ÿ²ÀîRiÒ¤XEšÁ‚&T£,+ŠIò‘Ä‚ ¢ ±þ bCE( €"é JWŠôvéüÏwîýÞw÷Þ÷îÛ²¼Ù3sæL¹gÎ9SîÜyÅz(¦³ñ×ÊÞdó‚]´)×!dJ‰…Ÿ¯ý\z7ïÜóÙ|wgX # Jw¨œ¯8ƒÇ-E®kY³%ƒ°_Ç~‚›ˆúÿ«¿¬Ì^)—ŽºT>ôÔ̬)ÕÒ«ÉøÇK§';ÉÎÒ;̓3‹ÀÂ\¤¡ÑÃG¥Ë”–=9{ä¡éÉK³^’û.»Ozwìm.U—?(-wO®,[½L¯\,‹W-–E+ÉüåóeÝV}õ©ž†¸”Eon.­Ë ,óe#–](å8†ÉcââáIë‡ìâí:‹)\`WqÝÆšß±Ó‡Ñ=ßåÇÉ?¬} óð°!ŽuZ¥ Š# xB…pIu­üÈ<¯÷}‚5wýÕXcZëL/怾y Ç?ÍÇ÷ÿ}@àüSΗׯy]z?×[¾Ûþ\òÔ%ÆdedI“ÚMdìÕc¥çó=å`i=ª×‰™ÙEž (QQPJUFlZ–.[Zpâ¯üA†½;L®=ïZétF'©]­¶TI¯b~c!ww®lß©_nÙ(?üôƒ¬Û¼NV®[)Ë×-—å?.7÷â6$cäP6ŒœB¼@4¸¼ÄÔ‹S׊7¼ð‹ã„Jj–«xâ‚ pð®Q¡<›lîó34Åá l"5Æe‚axÏã¿da@aqÜ-—ÌÊÊ+)¨ »6ȼõó¤eø#3ŸwgÎN‡ç±„Nl]ö:iTµQPR îœfçȸ«ÆIŸçû˜/ø`þ}Û¿¥Zåjr^óóäþ.÷Ë_'ÿÕ½u[Â{ËSŠ/¢:jfª£øB¬Ü¹R†¼7D¾ªË ½òÌüÐ,ÞnP&P„Òc9Ae7ñLÙuFaê…Âë³ùˆ×” »¯?7F t(Ç.å3îBOV÷¥ÅÄ™Â8Àñ,'V,}¶¿ˆëÀ¸Ö0£â1"•æ€ù?\ýÇ;wïÙש( ÎWf¼øÒÍK<þv:­“<Ôã!óêoѦEÒóéž’ãüŠÑÀÎå’¦—èÏ„©  IQ6×P'ôw&âÎè%£fÏBï,]CãúÛ Ø30aü–‚:2›Øß­^±nö9êæíw˜kرñ‰2õF#s`I÷ÌMF8»ƒ ÿK‚g¡üDAa}àÔ’×7Ôâ‹ &cØô‚7EKˆ™†ò!}Ì53ŽL—Fš •ûï}û^ä>à/ú¨8;yBøƳIË&E® „×_t½\qúFÁçnœ+}F÷‘œ=9¦ŒÑFKÓ Mc7Cd ¦=È ]Ô‘™çð¶Âü†‚ÞGXFO–QŦ‡¢ãwp9æ ]™‹qS±Þkh®4æ'Î>`J­(JÅã¹>»ÉÃ¥BÿAm‘]2 r¡$Äh…´•žqìàŸ‰»ëƒS<Ö]üœMCÁ°q £^†K,T`=÷ǹds\¸cç“ÎkÅ“åË„¥dÓÎMqëð'ޏj„4®ÜØôûë¾¾ÿìk~Z¬R…JòÊM¯H…ÝúÛøCüb°Û÷‘ ¤BôÔLÝuÀ¼®ÄÔ^Ïx^×ô¥ªh¼¦AÉqÆo<Ìù¬íáõìöPž÷/™¶X´I¯ý(ÍJ‹65¯»?ƒ¨Aq¯†FHÑÅå jô¹?(^ñ¡ÂÀc¾! £B1I¶ð‚J@ Ö¥Oˆô${÷é@…‰0Rn‘œý92ò³‘©2|&<¢ß9¤÷  ^\C~Íóט/ÿpOÀè¾£ÍRÀ\[®n’îZ<6òt´6#7¦ë0ôˆsDÇú;]Jç©Ñþ!Ñ+_F¿«ˆ gúnaA @tƹMÃ<ˆ9›0?æ§ûaüQÖ½µø­HŸÒÆì€õae†áU^üß‹²zËjäŽìÎ=í\¹ ÑÎF*ßÄå妗o2}ÙY—ÉÍíov–ØÈÃQeNƒÃÚq4áù,‰ Ÿ \E˜G‚,fW `†ÿ ÃWXæÁÈÍC‹f:œx2¢ˆ`èÛ†"*?i%*êz•ësÖËÔeSöž}{ މm²mÑ\»õß  ƒLß%¬Ð"¸á¢Œ’c§ëë7—¼)w¾æü¬Ù}ÖY­7<$TLòpXû Ï…ÏJk¾Ï =¡Ë£?À%pQõ1¨LŽ’v¨Pùº,^fs}”v¾çÀuÈKeueÓIuÓ‰!àÇÒ2Ë€çþóœt>¹s\á&_oê >ûx73•»ð³~œ%ç—Á¿œ0 º´ë"u*Ô1ƪL}§Sôçêw«È=—Þ#ïÜñŽL]?èì°UDÉ * ¦ë]xK7.•“kžú|Þ&*8­×³¡/TKBéÀóãɈϟ”;/º3¡ág¸”ã·­+Ï|öŒR}.§tz`øgOHí*µåºó¯“Sj"}Fö‘nmºÊUç\-ƒ; –Ü}¹2cù§òþ’÷eâw¥´ÊÍ?z<%Ÿt1‹6ç÷›Tob|¿–ýdõÖÕòاÉk ^5íõÎ$ù¸1•8¢–‡bÜ‚F>­¸!¶ã ƒ÷p¦”§ª FöMœa- xÅU,¯_mEp®>‚’5EÈåÐÆFÎÂýû÷ï9pà€Q6£„ŽÊ¯\^¯bÂsÑcw_†!®åÔ?^:é,“®L‰G{L¥Ú{£?. u¼Ä³P¼Aéjµw•Ê‘¡ ­+(¡ûYÝÍgÁñ;…:lÒ!§”~ˆ4øßƒå9oHózÍeÌUcäÍOÆK›¿¶‘‹¿HÞùï;ұѹ2ú²gdéßÊ77ÏͧüAu5¨Ö@Fõ%“¯š"ÍÓõ‚SýÉÔ ¹9Ò²Ãú]èÉ5òÎtʾ¢+W€þ@?Â=ôúÄ(¸¨@›å¹CûöíËåHëaøAZ»ˆÍnüèƒÇ¤YqZ°ôc¯#Ûëó_»A‡ÑÓ±¶Êgô¢Åߤš#êÈÙ#å¯ÞЂ¢¹v§´“2ûÊ8w¸k}³{¯ËãÊ´…Óä´ú§ÉØ›ÇJãŒÆ2gѹñ¹¥ÙÍdп™c¾UÒb?ENTs»†í䓟Èà¶ú+É9:ëÁ׈9>*(¢æc=„ÈGÞ²,èpð6½¦G¹z}tKP`J‹ä¢ÆfÌÉÉÙË“È_ùx31£>F Cú`¢4—1ˆy1¬9ó„ÅåÅÞR{åáí ³`ñºÀøÈ®7±GIÇQŸnî+»O®zùª˜›€P|˜k^¿¹sí–Ið^uÁè;ú=åöÈsŸ='•Ò*ÉÇs?–—oyYðq‘™%èû|\C^wv“³åó;õ ʦ½å ö£ö*8Ò&Ë¿ B¦1¨E)‡yY7ãx8„Õy†À-û$‰ôú¨t(…¥¢„H.Y€‚nذᇽ{÷ŽÚöH^7£®óPl ¥qC§œÃ¿„Î"‰DŸ°ÀD Št ÌùÛÄ¿>T…òø¥NuïDÿº£÷öRÛ¥çèž²9;ï®À°›Õkæ\5î»n<£b†|pÃÒ³MO¹ì©Ëäâv˱Cä¥^’ž­zš<üxX±‘ñéiéòüÕÏËß»ÿ]ÊïÑÃ50T•°R,™ËG/Ĥ!$Þ†Hcº¯=0'TÑkÊBfÇÄC¡ZK°Kµk 'cPüyóæ}йúUuê…ÀÈO/·ØTB4Ù+Ý ÇG² ±–VÜðc §ìÂÚ|ꊩ2þ?ãóuIÌì©…åÊP#€+ÃVæ®”þÏö7Ç|sj72_íá^BoïGÛ1æ’1Ò¡aéиƒ<ØëA¹bøÒÿüþrÅãWÈÓýŸ–ιAÆÍ'M|,¬è¤ðל{|<ðcïþ?ï–¤Âòù)Ë„þ2£â-ºúÕê'|>]ÿË¢E‹V(aÐÜ"aþ(€‚¦¡’Ó§O_¡×ÕJ¯%iÇé« –àBc Ü{â<Æ¡$?câÇùã1Ÿ <Þ£6ÞéîúïÝ)k¶¬AÌsKV.qÂEÉ -FÇmg¯Ÿ-7¿t³1ô^¥¾@¬:ÎÛûÕ•#ö„ÚÕm']OêêQöjÛK®øÕòèøGåäº'K¯Ç{ÉÐK‡Êß ‘&< }Gô•-Ù[<ú‚°1cð 9·Ö¹æ¨rà’ÀRÂx2aä1-Óü}aã¶ú(M_¡cÈé@|è£>Z®tF7­’QZBW  ¥îW°×0 Aµ2kéÃ:3•FÜx3;ÐBèÚL 2/©5Í(z,4iø Zâpß$Ã%ª”âlEöÒïù~Þ×w蚯ÿÇé!ŒÚIò/.=êÄ#]aŒ_ô¦<úþ#N=³ªè’BÈaÌ ðô>­W>Ê;{Þ)5+×”V¨_.½žè)ƒ:’ü¿‘2ñ›‰ÒâÖòÄ›OÈÎ\ßùJЍž^]Þ¹õ¹úô«Õ¨ÜéGI¶L>7dü‹ZOOIãOƒ5Qœ3{uËô._LšÆùókñžú=T·+V€îƒG%¨lß®]»¶FÙÄ2à F{õ€xÿIÏwŸ._\þ楓Î{gêðÏä× ²yy6£ò>ÁýpŽ~΋#[ð:j›;YŠŠZ$ê}¥7lú#òÆìà׃™•3€JÏAnôA›ºm‘;Ÿ{ú–§eÞ²yÚÔ22kÙgÒûï½å÷çô•5cÖÈÒg–Êy-Ï“G^{Dî~înYþÃò|ù£"ðã¦#¯)w_xWV™ÓW””G#KZäâ[ÐÈ-ã¤óÑxò:Õ ÄM>Ð!®œ€tG‘A<´Ya>zâíòì|hÒ U Eô@aããõsêºýS=Ä wWXJä¢4ME%û.\8o÷îÝ +iU¿•ù †¯1Ý·=ðÆëÚtШ zxàí4ÐÑÙ84ÐŽ—ô°1éú½û¼-ó¤ûðîÎwñú=¼èV €r»èùáÞí¿·Ü^¹âÙ+d¹Nßmg®&w¥‡üÇs„¹›~{“¤—N7r‚½:Uëä#Å/½g¬ ê3H†½:LNêw’œqå2øƒeò““Z&ÜÒõÚe¨ùDùàn•)ü&”²I%d˜PñЈ:+ÍËgçg: %—ݙԺ´–´ÐZ®v½Œ?Z¦|1ÅÜ ¼-{›÷uÎîYºj©Œ›ð‰pA4¬›jЏ†!pÓN«wrÆu˜ýê@ÕЌžÀ£ºMõ¬Íž­[·®Ç:$‘kb{'7Kp”n¦Cjùæg>•m*»¼¨²š½Àï0tnÞ9PlÝ‚ÞAÿ´…0ÐGî°FE%vì’Ä”±c8*ÛûÒK/}¦¯ñ¸ ]‹z-<áõÚæÁ8ÒƒA®SS‘ï’l¬Gkå#.TøÅßÐÉCåŸSÿé\̉{ú \úÿûÍßÇmö0ׄøfå7qiíD|üôìÏÊUí®rTÓ{­×\õËAñ»‡¸HT•ÝŒþz‰(ÂæQ\Š%“æñŒ& ÏKbyfŒé„ÄÛª :—ÖÖ‡Sœj’ýQ½èŸÒÙÊOs’(»—žŒ@sQ”~îäjCvDù2ð‚f8#?3ºÊoâZBÒxŒrf3ËŸ×nÍc8Ÿ‚Å˾5k”Y_cm6"5í»Ÿ¾Ó¿á?åe”E%nÊÜ)á„)0O]û”\×ö:çÊ1÷Ъ1Jú:Ô[Á Ñé¿þ7òÁ±”²âÆŽþ¤gÈÍC˜žêjÁ O½ÐÅû}S½ÛýS:. “( µFvQ  ``– w¯X±b ¦#‰\§“:™Ÿ˜†b³c 3]†pI`+¹1œ(ô+9ÓýøT\{„½v¤ ô Š…‘×sãgÁ×Y@¢À–m[œö«lLž;YÖoÇr7ºÃ&ò“ž”ëÎrî" zñ2„.(ÍÆÙá°2ïɾÒ{FÄU~Ä3Ò2Ìô?ÑSBß wJ‡÷$\@/í'LTŒIj@ŒÇDðžxùå—'c:ÅáݦyǪïYÍñ_w/€£½aËpoY€©½ÅT*<¡†°m<˜æ1Û*‡i)¨=Wœ|¡ÀH‹õ56#Õá€R<·â‡N»”hï½2ô¡ñÈCÓ†_3\~Æïó.µU$ÞsS©}0F–˜†ÚQㄬ qzÒ¹qSÂJÛ®iâwÿJ‰Ñ_ w´ jƒGi‘]2…¢pXxXžÝË—/߸sçΟ1-1J« /;ó²<ÂæÒn¹qo£‡1ÜÙ•Ðc¦ËDÆ=fúðLOAí±#Á­Ö|ÙÙàè¯Sçc w_Àšîã¡Í©Aœ´NýñD ’I6´óÙøT8ÜP otˆôþ¡_õTç†JËœ…z¤ÒI¯çn}õVþîp“74c@ö^¼íEéX¯cÞ/Aþ0XAÞÂ-¦Ñ1ÐO<=Ò´^o©‹6 Ma³ºŽn4?=ûî»ï)ën蟽 ýLÊ%c8yñ€ÝœüóÏz˜:‚ûí¿uFv-ÅXTZAk&`¬%lÒhe‚žÞƇ…MùVþ0º>–χ…*Ms×ÿ¼M=Õý¹#¯בÝûÞ½ÒñOeú§G¶<’rÇ•“±·•Få}ìŸ @V(s>èÉ$å‰éŒû!Ò]“aKÆ‘F< nOŽâ g/¾øâ$¥ 2hERF €ö¡p> gý¦®Z òIDAT¹«W¯Þ”½5Ê¡ .§u‘º™uRP¼ŸyvœfÐò`Z"oӧ±üû%ðcÞó´QùݔϦHv®þª0N/êž9W SyÖ7 ó6Í“õ³nÕŽÍïF¾¢¿E¨#>ÞàëFï½¼Fз xw¿pëB¹~ÔõÒðò†róc7ËÌÿÍ4Óëü%æa×i,O xJé'ÀF} ~9ó)4–ùhâÉ#ªsË0y-å7rm)?ä¾k«¼‹QòZš?ý‚ži ”ßžà)PcÒ.Y@VḀ†ä¼ð ³tsb”5wßv}¥F¥¦É†!h:=j€cMÄèñœ¢R™X»m­Ì[; ˜8c¢|öÍgŽ¢ãÍŒ—x o†À!ý™ðìrÙò³þO:ÿ¥³4þ]cøè@óq>ö r½Ïë-W´½Â옠>t¶ü)Nç Ž,úðF>‘'YÞï-Y6†AãYYre‡+Ã÷!Ü=èô z¦%ÓØëÖªÉÑ]²%ã±h0÷2@aÎâÅ‹çG}%ØãÌÎÈÏ”îâ “4ê9>"hRîèç€JßËŸ¿ì=Ǧ­›dàC©?^ÂÃðh.)5Ÿ9O€t=_` {Ôwã¡æ:ñÞC{KÝ‹ëJ×A]å‘—‘9óçÈþyšþðµK¥}•œ¥n*‚LQ®\è)?ëeº?N< ÃbæÀÑ_ƒTzO¾uÛ­u7–B¯ _Jå§€þa f-LΕʧd¾ü_å©I66Y?ù|§YU}Mõu«V­ÚH7(î¯U«hº~cúɆŸ7xk=þŒ³9‘Ó„ŽvŽz¯„‚JÂ%¬=EðKàÀqŽ“nÿHŽÓŸ úÃÐ?È‚¥ Œâ{Ÿ2ãø.fa}ì*YBª~›‹>u\ÄÈnFw„qÛ*9~¨¦ãéå¼VçÉ¯Îø•<=áiyû›·£ÀjLŒTƒ)PVçÃ"ÔgC;ì¤:ð®7mBX.o‰‹6ê´Kß5äÛƒoQb‘„zóï¡ܳm›þˆ¢Èêñ5Õ6õØ}‡!Ègé¶æ1*˜ŒsÉTˆ)g»´qÛ׬Y³<==½I¥J•–‰ç?}Þ(9˜bŒÝÑÆ!f@í6 jŽÎŸF| þ"9°_»ëü‡Î—C;ôõXöA)]Ùý ŠoþvûŸDûÜ0r÷ •S™ÑߢôŒ6ûtœÜµo—LZ8I&}3ÉQ½K c(v?AO¨ü¨Ÿí!ÄìqõFɪéB.y{´éŠ„£?ô ú¥Ä8u‡Y7ôúÇÒÙEEwºÏZ ‡ÊP1¦h¦$hØÎÑ£G¿ûÈ# ŽbúžÝWï}›%ß®ÿV³ªƒòÂóQ±þƒcÓƒó"-Œ&(_ wd8€>ÂE%¸»¦ŠÂ5>ð‡pÛݧ‰ZéÎÍ^¾A8TV´ê¨‹oýÍM¹ª‡J»u@I•Ô9ízf<2Ý…ù¦ûõµ|ŽþMë4•þúk¡‰^ýA¯”·¡BÏ oлBMÿ5¿9fXvh^Gðí·ßþ°nݺ5ºa‘pcLêÕZo‡EçXÞXIÄQƒBcÉ­tÓHó1=_4¶ODŸJOÌÓ¢æ‘v‘yÍç^Èa¾ÌÃw:ú{Ò™lès8î`ÓP§ø¥Óœïþqñ‡Yb¤+¬¨8|ŸÍWgdõÙòE jéH£Ð(9ã_(¿-¿šÖ󬞑ôzôã?®^i«h oÐ;èj*°ƒ½,ˆ#‹ðX°BÜDw>ùä“o¢áQ¾~º¸ÕÅŽ¢»k#£ô:E2LÃãi0¦cP+ì¦çS~´Ðï ’Ç_F*žŸ¯…å‰êžy½‡M=5æ“\Jf2e³ýy(ˆîÁ(<–¨ uºG”=³óûˤ¼‚–ò¨a¯ ¤+ÞS~Ó0tkÓM:ŸÞ™­Š ¡G#FŒÀFÑ-…ÜäèÏ–Ä-',‘lKO„GåhÖ"h™­ç”\»víʨonï|»˜K"É0Ø52•5ñQÙAŒ3q¦ÇƒÉ¯¼TZÁ ƒv­€!ðÎ`œ\ya}Ï~¶ûåó. ›);iXaÞ_6ã€>¹¥ò§ëO~¾x°$vÐÕ£UªO¸EOFý‚žAß w¨©P®0lᣢAÞ2@Ã;uà µ^ ‰änºè&gBCåWèYO—™ÆºÚLf ØAŒ“ÆÆÇ “0]*í—ÅŸxýÆ4ŸÙx·¿½Q´..²<–cAO>!¯êcä×ÅÝØåÆHú"èêÑëºËlžþsµÂH¬¢ æ cP#؆Ðx³Ýظ`Á‚yQ¿øõi¿–î­ô8¤2Ôc¤/lÒx*‹µÛaÛ±³í´°0i ÃèRø#ÇD}ƒô G¼•ßÛð½'Žù-ú|›~XÂ"Ý’á.­»H×–]QJB½Ñ«÷çC”ØýmÀ$,/Œ °åÂÒ`/Ö ï&:tè;zvY0c¶’Øý±ë¥z¥ê±Ö“ Ä£ºÞ›®¡H²€0^5VñÈbÒì< Ǥ"ÅÎò0¨B¦úÓ€wÓ!Cù”?€Žô¦H¦ºåyòèâ½…jgÕ*U“?_ògSL¢?î™ÿ}÷ÝwßÛJktI!ô ú…Á–£¿ ç kÈ .`±pUØŽ·ß~{Ò®œ]‘v<ÁÈÛºÞæ,Pb˜§Q€éA ü­Š‘Çöñhýiv>;ì§KÅþI†6?ËÏtÀ ¦#Í Ç(,ñv Úù}8o¶jË*h츆]<(²@_&L˜0 ú£%A—àýÓÿCï¾û.ZV(WXÀÊùÈx5á-4œýúë¯ÏY³z͆¨‚í›¶—ËÛ_îÌpDÓÝ %õkï°v@x°%Yϼ„Éæ=ó¤Î_jžââ]nس“Æî Cñ=…eš¿ ä ÂÙx·|SõiØÃA>!¿šÖ«C/éxrG%LìÌÆßšµ^}õU½Á(>ŒFèô‹5j°ð®ÐÀµB`†¹> k…© ¿ãÞ{ï§q›Iw}§ë¥u£ÖFù a´dï<€k`<ÀN@ñðLgœ” d^&“¿ ´v]G{¸ ÏïÏÄ? ã6-pŒkJé)¦/Í(/h‰´ÃV9¦L7ÍÈå ² `XóžÙèL¹¹óÍŠLìÜÛ~ÞsÏ=ã”ÚèŽBèô z…ÒÑ¢"ýµï¨Â…u` XÁY€g6nܸAÃ<òçÂhÈ£}•Æ5›Çµß ³Ó´VÓ¹¨fȉž¸‚xæO Rö±˜§°|´ó“ÄiÜŒøØ4¶p1ýnã¶Ëð‡™®rçÉp®zéîÁŸF5É×<¡DÑ\NnŽ|üñÇ3 /šÃ6ý¡_¨µÈ\¡gh‰5 @ãìY€Ù PÜö1cÆ|¢lŒº@¹#®!µ3k†‚©Æë´Ê@Xuâ\ Nà4/º>CçÏã§)LÜ.;öFàBóÝÏK!ÝÆ‘ž8;nÓ2l§#ä év8Æ}rY³JMùÇuÿ€GrЋիVo|æ™g>Ñ 8óÀµ?Gc†ŠbíÏF‰@an£`íYÖ.x<Ðö?ÿùÏcõõÆ~½Ï\£‰]ÅòeX¿a΋*“iÉÁxg"¤e€%êÑQžGÑ5ŽÐÐù@âò°qÀß'a“ÎM§ˆ! œ6TN WpÌçÆa ’ÇŸr¨²Y½ruyôêGòÅA Ð¥§òCoìµ?ôê@Q*?ÚVd…¹¬à, Æìرã'ý\øýdÞ Ô­ZWîþÝÝRµBÕ¼=2"ÔHœÛ¦“FÚ8 @È|A0JþMžÂñ"ˆ¯6.(q>:{vaúÜO‡8òá‰# ”›a še0]åÏŒ : ¨šVUîîs·œPí„ØÙg!ú ×|ÿ[õW}Áà3_{ôWtѺ"5®u"‹0Ìó\µmâĉß|9çËù8ãÕ5¯Û\îêy—TI«’÷%™#Nq;áhu¤'ÀÔÛ˜ çÙdx‘ ïýåºy©øùú‘ô¬ñ 0pL³!ó»0Fù!k¶ü¹r—Q!Cþò»¿H‹-” šƒ@Þÿ}üÌ÷Võ¶òǼ÷/êÑ-,R€]¶A-a° AZ¶m<ðÀ{zÆys2û­µ2g¨«TT#À%;ÁU~v$Ò Ý¹ A«í¦`¤`ž’I^Ø}ðÕ*½7·ÒL#‡¸¿,;Î<Ò*ôd é”3…ž *áÌŠ™ò§^’¶MÚ*a4g^ù©@4õú½þ@P{±¸"7®• Á.<q)`fß~ÇwüK§<{£ü¬˜Òwv³³eH¯!Rµ’.`ÜN¡@ø;8F@PZȰ'ÞA“rEË?í¸¯&®é }ÉN”ùíD‡°í·i¨f.Γà]ï—5È!äñ®ßÝ%íOno×7 ¹‡üC”JÑSÿ˜#¿Å1úk]Å3Y p€ݪSŸŸî¿ÿþWuóãàž=XæDs˜ Ü×ç>ɪœ³'sc[eÓaÚ‘1›ƒìl@8B'þ×Η ;|+,B¸M%·ail;l"¶ 8;Làà©à¤UèÉ Ò€Wh †5à oºæÇ†ß½ýî•¶M£üwÈ=äz ¥PÈѿاþZ—qE>`Á.«¸!È¥f[ÔoÕ–ã¦ý^àÐþý˜éDsÍOh.õLjWq^Æì`f€¢ÐQ®‡a0Þ~ÍÃW;6Î~“` ƒ'D)œ£ …䃭ÜþpB^C¢èýíÓŽé„À# çâ(+”±ÔTe÷&㈫LÕªRK𨴨}Í9‡¼«Ü¿ùך¡üÐè^ûñ?ô†­Ó`ñ¸b3ÖR‡ñ/Œ˜:uêü·Þzëì„â$”_ Ââõ²êɘÆÈ‰ÇŸ˜×9®â£sb:Ðí\vr ô GX})¼Ñ€ì‚àbøïïö‡ mÏ0ÓŒ‚  ›žùˆWèásù<{ë³Ò°FÃÈ||CÎ!ï*÷ó´4[ùí©?•¿ÈNüi]®Ø j Y `?€kžÍÞ:nܸÏ'}8éK¾DÞ(ïYÿyã?¥õ‰­ð¬´ÛI&îv$-»YÃÙÂ5žÀ°ã)Q¡-|¶FÍ,Ñùy/¾¥Ûü²Ó‰÷ãЯĆý¬8#x¿Oœ )3fä§L©ìœÙäLyîÖç"¿ç‡,ÃPB¾Uο‚¼+ Êoä_!ôzqئþZ—qÅjX‰B°ªf¿àRÀ0áé§Ÿž6mê´o’y3Àò¹ò¹üœË=ëìu$:M;Ì6œÆqä2BA´…ÄŽAkû0º>ÇA¼°y˜ ÿQ–ŸqHñv\ÃF0 /¤“éšÇŒúÀ¹ž2Ô»Coy|Àãšœƒ\OŸ6ý•ó©š“ÊÏ©¿×­>,® ·Gnf—^z).`{1µã…L¸ó—¾ôðáç”+Wî¸sÏ=·næ5Í&G‚?×ýæ:i^¿¹<õï§dÓÏ›œ«ÄaÞй KÒ*Q+[â†Í­³Ã1a@ä§#ã)X0ØÔõÑÜ»v&ü7?kðæµ?½&Ý[w7#¿7€E‡¥GíèÔoFL)„ :W@ò Ó ír…p2|²ù”éìO„éüx¥1Ë?ìc°Ÿ™r 'ù»¶í*oy3iå7?ç¥rãüÊ,:Zk1÷¿k?4¢bP³Òàz4?4âáL“-õ§°°•8¬,ÐÑg§kØŒö(‹xB6@£@¼kÒÓÒåÆ7JçVÑnðEtÜðÓ5ÿ×XÞ*žÊã¾ý¡ü˜úC ‡]ùµNc*Ç%š†«bÇÉ?É]@é¡Õøí×JêÓÕWS_]} ×gõïß¿}Ïž=;ddd”Ò¥¢“w#Þ!¿œè,  ¼XpÒì H†§^ÃÞóGH¶1î¤ÿBœ³äbÉ¿°' K·ñvå0¨Þ›æ3ÍÅ:*>äa8£‚šOA·³ºÉ=ïtðIþÅÇ=xÕ§ºñ™žñŸ­Ù¡üP|*?F(?Fï´Ÿ;SVTt§úJœH·‘ñ°Tê®ýñƒøl*C}Uõ4YÎêÔ©Só[n¹¥{åÊ•KW¨PAQÉ»ió¦Éû_¾/‹×,Î3˜@%c¼U‘õù<#À¿‚ûã¤KÁX@!£8›ŽaBæ×¸éOàmt;ް*¼¡u—}PüSœ*Ÿ}±üúÌ_#gÒn÷îݸÍ÷ Žú§OŸ¾H ðüþ÷ý0;þʯ° ¹¹uÒ숛Çc€¶Úx]¦L\ ß d?øàƒ—gff–­X1Ú'–NÑÎß Ï¸Pà_ŸùºLüj¢lØ®÷- ·F Ž7íÞïQ”æ1´L3d±Ê™‰›€þmIvxöâr,›õ¸qÓÀ!NŽæÀSÁFzůUµ–tk×Mú^ÐÔr9998Þ»Ooô¯¿ä³J á†F~ŒúP~Œü<ìc”_ãGÌ‘žÖ èŸ `9PE=ff °šÎjè/]^¯^½jQ~wPó„ºW>yÅ‚Í?«qöünÜ3,ÅRzO©©Ü„ uÃf¦À¼€@›ÎNK…ó8`+³‹QtRRრ]††½¥ ‚ 1âg¥gI·³»É•^É’ Ý{¶þñoïåèOåÇn¿=í7ƒ`A¦þldagGÌàL%á¾ ÂUïºë®ß´?§ý)Ø,[V=²nÜ'ãdò'ˆm:#€âÃù BR†ùm%·ÃH³ׯ¥Ây ‘&ÐöŸiT|]÷cÄïܦ³ô¿°^á o\å5ûóÙKt§ÿc-ÊåÇ anøåù £üZ.t Ðýb÷ìÖìö¥©¯¬3î xF k×®§]{íµꬠLA–ZfŒƒø`Îòíß:xŸ0J eV³@'Dn;ì”–ú[P@amGŽa æSx*¾ ‘~Ò 'I÷³»K·¶Ýì’ Æ”_Gû/¼ð´I“&-ÔB0Å·•q*¿}ʯÐ#?|Ô•Ÿ£>âÙê1å/å×rþÎ2P;lNb~7˜ p_€³Ì2u&pv÷îÝÛè¾@é´4LŠÆáÍÁ§ó>•E«™³ÞRÀU|¯*·*AÌl,áõòÛ–aãJZ8ìçUZoý¼mGY,aäQ¥Çp6oÔ\Îoy¾\Ôò"P‰ÃwüºÞ?¨7[}­#ÿ-#üvõù¡üP|Äùš'üpÐÇpôÀ#'ú¸Ö§ò¶‹<´ ÆSÀzhÌìÙÏ (?Œ Â0x­˜¦o NéÒ¥K }˜ÍBÝDÔ¤”+‰ÀPzlîék¼ìÉ“'/Ð]ý%ú¬É¡ÔPn®é¡ô4~Å·×ú‡}Ô×vyî˜4xzßlZËÃCöÛÎÌ2@ih‡€¯P£F* hÕ¢E‹z:CHÃò÷¤Œrç(wPz|Ÿi¾Žð¹ ,X«¿Où¿M›6a3ï顸ðPrx(>ö⃖ë|ê9lk}­;г€Ü° –¶!Àl…xcE÷àAÚ uêÔÉÔ‹HZžzê©uõ"’Š:+0—‘à¨qjÏ@9ô wXÓã¨.”^GûCz1GÎâÅ‹;vìÜuëÖaŠ QŸÓy[ám¥ h9âSñ˿֛Ðó€r ½,€AàF¡QnsÔ‡ÒÛž‚t€åõ*²òZnÓ:4®Y³f¦Î Êcf€¯a0CHåÔrPvŒðPx|•çŽô{6nܸã‹/¾X¡ÓûeºÖ‡òÂSñ©ø€¶çl€´ñ¹ÁÇuþaÝäÓú㺔°Øã` ß@Á¡ôöì€Æ8Î0‹€ÇCYUþò;wnئM›ú:S¨‚‚âÊâÎBxÎ`è5oÊ€PpÛCÑ¡ðØÀƒW…߇^Göí_ýõš)S¦¬R”#5×V~Œæ\ës½H”a*}>Å״þɇ:ã¹”àNC`Y³pŸÀ^&Pñi`$lCÀÙËÀž|™–-[ÖÐ%C =kPõøãÏÐ}„ ºtPÛP®Œ†2j¸i™š1(ÔÝu‡TÑñsqT¡èT~¯®ßwÿôÓOÙúŽ~›Né7Í;w“ÒbT†²Ãã<<Øõ©ä€¶‡Ò“ùXÊõF| ÿâm‚;âÀiÆ/ö/Ž3ž!à†¡ýö€FÁ^Øa΂ _Ir‚ÐS|· ¦1ØÎ€¤‹ò´=à ™Í6*$•žJk+>•šSy?-gÌ#Â:ÌξÆáØ'výµ jh« }#PhÉ¿¼*Œ=GqŽêTnB*=!ð #â4&, ÊO€z¢%M9åÎV~*=G|@ŽÜTh[¹m 顸Èòé5èµá£Ö¥ @p×ÑÒPi©Ä4ˆÓ‡¸_ù™Æü,Ï6v½Á-KaýÊx˜òÛ#7•šiTx [áaHJÔh$:Q öXs~!ã¨â7Pbð‡JŽ0 8ÆI:*?¡¢R. Pù ©´µ³aǾe^@Žô¶(úØtØcÙÙB€0†J e¦GÜVrâýÐÎÏ‘_³šå`Ê…s€} „¡°„¶"G ÛùY6!ê8¦Ý±nìΧP2Œt*³½dŠ< q„ÀÓk0®ݱæl‡=;û#7! ð€Ä2âtÀ¥œ)àcˆµ…f+(•š 0 ãLá”KŽì*3 q;a:;L\ ú82>†„Dma²Ã¶bSámŠóÇCªH¡8`óɈӓÜOC| Fà@Â×€ÊH‘¤8âÀQÊN[Òæ§šâ@Š…á@ʆ{©¼)åH€£¼SÍOq 0H€Âp/•7Å£œ)p”w`ªù)†ÿì%´³W¹ IEND®B`‚ic09±…‰PNG  IHDRôxÔú AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs  šœ@IDATxì½ €eEy6\ÓÛ 30ÃàÀ0H73싆Å% .1"¢âï¯1*âÑhÜ~?—ßßĸä3ú¹"1D#Q4¢ÜAv˜fe˜fŸž}éîùŸç=õT×9}îíÛÝ÷vßî®ê>·ªÞzk{O÷y«Ns¦8pÀ%—$$$$$$0¹$Ð2¹º›z›$$$$$$@ $ ƒ$$$$$I(dL“žºœ$$$$$ €4’’’’’&¡’0 Ozêr’@’@’@’@’@2ÒHHHHH˜„HÀ$<é©ËIIIIIÉHc I I I I I`J “ð¤§.' $ $ $ $ $ $$$$$I(dL“žºœ$$$$$ €4’’’’’&¡’0 Ozêr’@’@’@’@’@2ÒHHHHH˜„HÀ$<é©ËIIIIIÉHc I I I I I`J “ð¤§.' $ $ $ $ $ $$$$$I(dL“žºœ$$$$$ €4’’’’’&¡ÚFÒç)S¦Œ${Ê›$P«Ò@«UR‰¯$p ‘Ú0±%pàÀȇو €‰-ÞÔ»Q’@-à^ä,>JMOÕLR 5o1^‹X†“§–rO’@ÍH@Í¢JŒ#”@´ãââ4…å‹Oñ¢¯ôj¾òTãIiI±jhñ}•UF'­Ò˜¿ò'?I aH@ÃD;© ®¤ÜD/úiEzWX‚U¼è+=ùI€ºè«.Ò‹iq\aò+ûÏ*/æ‹i)œ$0b $`Ä"œô”), Etú ‹ÓO1^)è±Ïð`Nõ Æ—Ò'Ÿăõ\|e>i¢³ÅE,çQ¸l̪<ò$—$0, Œ¹ðƒü`X O™ÆF_|q™2bcjn>u¢ü1¥°•ûÆ7¾ñˆ³à¦OŸ~ì´iÓŽkmm=²¥¥eüY؈:ÇA`œŠ£Õöt èŒË©^Å“Ÿ$PMØ>l¶b¸Ç{Ýcgooow__ßFøOîÙ³gÙ®]»VÞ ÷Ío~s=x•Ÿþ`XŒ§¸˜?£ ¤åÆ3ô¨êòÇ OÇ´•S²±=¼6Ôã)€d Oö£•k€ƒ8›Ç¸3ðÇvêÂ… _Š™ü9úãðspLc•\{{»;äCŒwÐA¹ŽŽGò; «v0?R [ ý$ SR²ôy`Æo€ÝØÝþýûݾ}ûÜîÝ»@Þmß¾ÝhÕªC9{plDþeX9øÃ²eËnúøÇ?þòðcŸE)NÐg˜.6ŠFAÆá“1GSE’n4Å€ô3D­<«Î×âï|ç;ŸúŒg<ãR€ö³Ø'˜gû´\Ÿ Ø3gδËüÆ<žàž\’Àx“ 4hìܹÓmÛ¶Í%Ž·¶À X câ7÷ÜsÏ÷¾ð…/¬Ÿ@¿ÌÅÉH`˜tŒ—Œ Ц$ c6k}»fûàÑpÞcñO|âg.X°à5ðg¸;ì\¾Ï9ü¬Y³Üa‡f³yÎäÈçD”"\4¸rÀUƒÍ›7›Q@¡è`ìï ¬ܾtéÒÿÀêÙ½à!Ð ì{– À—_¶R«"9qŒI$ÉÕ7 Зû ·üÍßüÍÑçŸþ›ê/ˆ/àç6•rÉž3û#Ž8Â͘1Öì9ÛO.I I /® pÅ€†À† Ì(ðç˜ÀÓƒ`)6Þ|ûí·ÿëW¿úÕ'À ƒ@FAÑ—À²dÐϹd äÄ1j‘d$ áƒm„ o`FšÿÅ/~ñÅGyä_cæ~Àü¸ñ|p|Þ«O3ûX:)œ$04 p¥€FÀºuëÌ Ø±cG®Û±’ð‡'Ÿ|òßßõ®wý‰±1 ° ?étŠ'c “ǘü&  x%À/ã³Þ°|ð€¾§µ^uÕU—Ι3ç2Ü“? ´0Ëçf<.çà °Mzivé$—$Ð p•€› ø®»»ÛöDUa¡çAúè£?Šeþ…ª„³ý®®.{¯¾hÉOH˜œàkŠ—/_nOHøÎÁÒU«V}›  2üôéÏbøM†@EÕ@2’P:@FüßøÆ7ÞŽ |ïÄ‹xžÂÂùú]~Lç¸ãŽ Ê)­4“’&¥¸W%²÷ àMƒ&¼ˆû7}éòË/¿iE Ž#$ÉÈ § À¯Ýü•–ú9ão»úê«ß…þ»´›Ÿ;ù¹©ï¨£ŽÊÕ‘"III•$°zõêܦA;ð®/^vÙe_Dž2ÊVÒfÁJ‚-¡' 6,þJÏîðÿË¿üË»0ãÿ[ÿ FàçN~>Æ—\’@’@’Àp$ÀÇ×®]ö ÀØ Úÿyó›ß\ÍÐí€dÔ ôd$ÀÀ_³}ùÚÔ'ßîïclñQ¾¿ÐÀ?‹cÀÏÙ>gýÉ% $ $ ÔC|„«üœ1 nG¯E´ÒŠ@EC í01ÚO2&±P~-ñkÆ/?€>xZ±K÷yÇüq.3øñ?{E/ãÉ% $ $ Ô[|å0ß) C{Ö=öØcïÂSFÿƒºt[@¾ ùñÓÖ´d8Nþ†}š¸oc¤nÊH ÁÌs¤õs·èˆËo”¿fû|ú}ÿ6|äãØ¼àÿâßÏoÀÏOíò˜Èn_ß>·e÷·³g§Û¾w»Û¹o§Û½·ÛÓ³ÇíÙ¿ÇííÙkßWï=ÐëzûpôR9·¯gbÎþøýu†‚«uèFYBÞh¸rçªÑµÎ1¿bÙÚÂËkZÛ\ë”V×ÑÖa´©SÝÔ¶ì˜Ö6ÍMï˜îftÌp‡L=ÄÜ~°›}Ðl×ÑÒÑèiù|ÝpüÊa~wà–[nyó×¾öµ•hXqE€#%9‰OfC “Ì(€?a(>´ÌŸ~|moÚÿ†Ãçv_ þ~v—ËüÇs ¢ÃmܳÑmÞ½ÙmÞµÙÀ¾{w·Û¹g§Û¹w§ã£JflzÐŽÃÖû˜‰£h 0v}¾(K 6‰fÄЇ ý6³±0à ã'ÊGZLg˜_Éœ1u†›yÐL7ë Yf6ã07ç 9vª·Q<*h›ýgŠûvîÜùƒ÷¾÷½ïÆ;ö SEC€@Ñ’œ¬F@2&‰P~^ô„-ùÇ~˜ñ#½íë_ÿúÛð!ž̦1?ÊÃÇùZ[³ iãÉm߿ݭ޾ڭ۾ÎmÚµÉmÙ¹Åuïì¶™»{JK†ÌŠg/*†À¸â6ã§DqÃÕ/ª»¤ºDj„DÔXø üá\V(.€9Òã°±Ge÷ –EF¢¸7˜Î•…Cgê;Á ¼ˆë#ÝÑ3v3;fZyã퇫m||"¢C÷ ü™·¼å-W!J# hPŠ2䃔¹Éf$`ð'Œèð ôç§wùö¾3Î9çœoèçñÒ˜5k–?>ÚÃè¸qkw®uË6/soyÜmÞ¶ÙíÚ·Ë@ÛÀ@o íUaKÓí%/)Kc¯c^‹fSì…´XH!ŽGª‡¥Ü«s¥Ôf—@Î \Ùy´ˆ÷¿CNK÷i —ÅEWšÅa(ˆÎ[ ‡Ï<Üû”cÝÂúù‡Ìå‡_3LC »»Ûš ù¬½ãŽ;^ýJ÷ƒÀÛ4(4†«Þ˜LF@2&°P~Œû0ã'TìuÈhà {:®¼òÊÆ2ÿ«>e¼=Ò··oÛºÜ-Ù´Ä­Ú´ÊíØ³#|öä9Ë·ÿ~# ?éÞ?eH‡`,¯ŒDL‰´3“£´8o`1¥Žg§ÄåÀ£$=‘šTù¡1èJ4»‚|!¬® èY ƤÆÃ7Ê'®(xÁg†„ç7:Œ‚¾Þ>wÈôC\çœNwÂá'¸³¸©­SÕ‚¦ö ÀmÿzÛÛÞöîíÛ·ïCË«4´ )X8ôo2ɘ @ü ):гþþÿøÿxÁÉ'Ÿ|Ëëý›õ‡+¢I\Ö_ѽÂ=²þ·|ýrtàÛ’¾uc…#IG`-Ÿt†ã8Å 8ë’3€öј®ôà÷g ¤\`°ôsŠŒ…†dŒZŠ®@3p.ò ž£Gyú"¬2Ÿf ^0 h$”¼U ¼–à•ÑE£¿àÈ§¸ãf7.np5€ß Cû»-Zô¶ÿõ¿þ×/€I¿ € f€ŸãŸp"Ð׌Ÿ>ŸËým§žzêŒ~ô£Wã+} n»ûyŸŸ¯ðmV·sÿN·b@Ý#nÙúeœÙ'„ðÜððé§D¸ÓºH³8gî;<üÅñ(œe&«g6âä)s2Û[‘·,¢5Œ#uÊˆŠŒŒ"ŸÅcÞ’€|emˆâ @Πàúâ=þÈãÝ©óNuÇzœ›Ñnïþ©’Ÿ¯¦! ÇñÕÁÿùû¿ÿû7=ôÐC;Q! Z Ðj€üЮ‰º € dÀŸ£C€fûòÛ?ÿùÏ_ÔÙÙùE€Ñ´©S§Ú&¿fÝÝÏÇñ–w/w‹Ö/rË×-·ewu°_>€˜k )àC Џ™‡Na*Ì8ñ2݃ºÒ}¦ÌóiŒˆÏ⟬š˜b¼,oÄ®EŒ¸ “¼€‘žÇ"¸ÇÃ".;æ aþcƒ ·AЧsYŸŽ|*ó@/B4bøO:@ž±ÆqÑc€<Œóº9~îñî´y§¹‡6ïm>-ÀM‚|šýÙ³råJ|gèÝ?„8öãÐ*€|JLÃ<ÌMD# Ä(ÿlŠÛÿ7œ €qlT¿Ž0ë­ý_ÿõ_?„/öý ӹß÷ú›éѾu˜í?¸þA·xÍ"{“Þ”VÎ̧¸–VÎî ÍÃÌß €;W˜ùàÉk†=Ãn}+‡ÐÍlÚ `Edå@¥eiw¥AhtÈ™²ˆ…³232óËÅôŒQ)õã64¶¦TúH% P.–èýÃ)x4Äúi(@ β8€Ù™óà¯¸Íæ‰é Ä+ø}–ÆUòùÍ‚0â8ŸËg~Þrà› ¹*ðôyOwGÎ8Ò7dì==2è÷ôáÃ_}Ó›Þô)´Œ«4Š«ECÀ:1V’0N €ð'à™bààÑEÍ}ýë_ÿ_xïBŽÞ¹sç6ÕÿUÛW¹»×Üí–>¹´¶ÐçL\fþÐ-ͯ( Õdy( ›Å{ðΌܢ™àÝÓ(›€ïÍ@ßg7æ%«÷-¢$±µ¸ÒüµdO­mB‘‰u0 ÔpúãóÀ¾¬Ü’²Ä/ß²žgÌñ*€xÌ'ǦçÓìðÓm†ïãGšîÿ‡Ya@+ôi˜Až“Ž:ÉûÔsݱ3-ëá˜Ð¸ApݺuV7^'¼ä[ßúÖ+~ô£‘@@FoÐ ¤ñ¿ €qhÀ_ÀODb8^îç.ÿv,q½è„NøÀf*žówO}êSm§?ÒÆÜ-޼؀í¦µ6Ëg8Û—úmö €^}Qôž x¼‘`À2´ô¿@ùèD§" |–`Éöc<Z–ñ„ô,Zñ·V¾Š #Á`ùR–ÆI >'±AP¬1ð˜cGº=Ð îüó ntÒ§#(›ïÓc> {#À@Þß&° 3ÛH¨¸ß#€Ÿ<¤õd†é¼=pî±çºSçœjmë®<þøãï  |ö>úè£oÅKÐnF»â•møS€ 7^W’0Ž €ðµtøuhÖßZû5×\óÿzè¡o"/–þmÖUDÇÎíîÙíÞô°»wÕ½®{Wwø x= øE +Lç}}üç@tã%°ó߃=ý8®°ùÙ¥S"ʤãËQœé¦pYÔ,_,2#$OÊÇPG(3Ÿ’bQþè™Æ€€z¹4_óÅt Gu0ÒAq„‹+(*¤“Ï@žÏ2àöbc ÎÅø9cÀ¯6{ÆlwN×9îôÃOwÓÛÇöqc~¨‹«üÚ E¼uëÖkÞð†7|a±!@Ð×aPZvÀŸ«É'@ð'à üí¹~ÄÛN:餃ñÌëûS88›aÉŸûüw­¸ËíÞ·;oÞÛ' Ã'sŸ~¿@<ôÅ'Ÿ4núøã[ù̓¿­ @–Ÿñ.6H²¸2†WZ¬sélP-®„ êµ–œ‰g"J :õÕÆAqÈ S$Š} «õ…86pG9pæ1 €8îgú6û÷t{lYf÷ÿ½±€Ÿ{h€ßòEFi|zàÙ ŸíΘ{Ƙ¿S pK`ÞrÑâÅ‹w@,º%@_Wxæt 8þŒ€dŒ ü ø„¿fý¶äÅWœôüç?ÿ€Ó,.ùwvv:~Áo¬Ÿß¿ýýîŽw¸½ûðe=ø±oa?A=“!@ðf:ÁÖ|„Ùû@G„tÒćiа¦Ô¢¸åâž=+‹m‰J†2ÉS`³ù|H¬¦ø‹yS||I`°s«±4h¯5Þó”Ås4êÌ.°Wº<é|K÷ãnëËà=Ÿni17”ÇŒíðF€ ŠÔq{ÎñÏqgy¶ëh»ÏãÕÁnùòåº%°íÖ[o½øË_þòbÈE+Ú C€Bc8ãév@2šÜüãûý¶äÿ¹Ï}îììÿ¦µží_´y‘»í±Û쳺Z‚zظA³ÿ° ã#0ãßfö ²lä1¶¤Ì`Àõ˜ô}ò„°§@Fš ‡@ï'X Gé ůëJ‰wT% 0e¥ÕÎmÍ ð’Ï¡zä+Õ@àœæè 1ß l ä ov…éÇ›™Ïʇo¼~öotÒ ³­˜1àÓfN›éžwÂóÜYGžš>ÚøèO/VÞÏ íÐ-í  /ð—oÍ/F@2šØ(€?ç­„'ù?gþßøÆ7ÞÏõ¾“|Gq„Ýï+ðXÒ½Äýjɝܿ›Ã²¾€^3÷çm€3ãì9ï#À®Ã€›@¯çú‹ O#‡1öƒ¼Ñ<ø›<òÞy 8“pìÃdaY‘o‘J?ª«Rº§Ç ¡òÉ’’ljxn ŒCr5°«Ìà‘颼Jqüˆ4ãC> ¬Éoc¾Œ€˜OÆiqX`O?vÅå3¥{?йR€ãðƒw/<ù…îÄÃN´.öûÅ[ëׯ7IáM‚_ºüòËÿ ½8ˆÆ€ H)g0ϸX H@“øBtüyÁ¿ýÚk¯½ Ëü/EÚ˜Þï_³cûíªßº•Væœ`.à·™=ãx6\`ïãFÓÒ?Ò)åW˜¾¥%g<*Ïüô)ñ3LÅ­œŒjt¥‹D^¹¯ˆð+Ñ%Êe AS¶!–MC:¿„“GP*s¢ °ÅcôBÒt>€uÌ«°ød˜QçGÙ¶¾¸¿ÏϰâsB£ŒÆã4†{{²W ›AÀtí@xá‘ Ý…Ç]莞y´š;ª~¼/o üï×½îuoCt; 6¸ UJÝ$ßì+Éh2 ~t†?}mökÇŒ:îQýïñ?­­­Íáq?{­/3¦Ûºo«ûãÚ?º{VÜ“-Ý ð¹ŒO '°3}økÖoùŠt;¤ÏôÓø_ðM–„\L“/ã"Ë÷<¿@EÄåy¢)c1 Óõ3Ê6ö00E3ê1Ô‚f™«TWà÷Ù´ä¯2ôd¡­ä‹€/ºÕƒ²èË8`á`~Ä5ËtÒdÀ‚þžGqã‡Apî‚sÝ3ŸúL7{Úl5{Ôüîîn‡Ç]OO¿'ð öX½ +»ÐÚß ´Ã‰jVC MdTÎøeðÁ ^pÄÛßþöŸµ¶¶Îå&¿ ŒÉüîZw—û͒߸ž¾žðš­èû™|K[ÿR¿fýä#ðc`Ê<ðPŒ„˜F…ʸ¾xäSKXØýá˜V䉕uà#“whà ί<ÉŸÜ0Ь—¬dÆekìÅ4ãòyD/õ#KGœ~|”ò@—!à»ÏÏ€2 üœ'“Œ¿rÀ÷øm€·xxz{K»{Á)/pçu~½$Ys9ü²àÒ¥KVØöuW^yåŸÝrË-¼?2èSš:¬žf4’Ð$@ àOà§!`›ýü'¿èE/º`4}¬^é»rûJw룷¸Í»pŸß–ó¹¬ï—ó9Ó@“îlÀÓø¤…×÷ì îvˆ öqN®ÍX ¡—/ùÉâFóaÑŒ™,(‡N<©‰>e5çgíè'ÅqSžýI)4É% P®‡4¶¦ý=ïyÏ™ú§ú}€NûìÙ³]WW—ãG}FËõèq·=~›»{åÝ®µ­5[âð{Ð׌ÞÀžÆy£sæ ‘îù ¸À¶B€ŽÅÿ˜@¹ôØCuä@?äAY1X‡0òÑ1èòXÃò×ÀšX&‰ê>&0D+Óò•D ïþ€1Ë•A…I‹^"Æç}ÝR0`ÞH>›Ñ÷P–úþ…[ÞPº­ \Û+€|ÌÏð3>Ó½pÁ WFËñ#B|LpË–-”Áþ_ýêW—à“ê÷ ~Ü ¨Z €ÂÞ›ks`2ÆØ¨ü9ûç(ïøÈG>òì³Ï>ûZS+wúwü‡ R„Ãum}ÌÝúØ­nÇžÙLž³y¼7lÉža-û{ð7žÜÅǶÛ4å±ûû¢Ë(ðq¶[ÆÀÞhHW•£Éăz,Ÿ˜žËçóP¬¾ +¼Êy«ðWMª±Îªe¤Ä¦@„:9ß e VŸòÒyEg±!ìž4[æWšèÞ€ ÎÜ&ÀGà‡Í ˜ûô°RpgZØÈtð1nÆ„Vüm™Ógº‹N½Èô”“ØÌQqì>!€pïÿøÇ×ýÃ?üÃoP9 Ý!-‘4© €14† þŸüä'_tê©§~ƒÌÀŸ_ò-Ç—ùülÙÏÜâÕ‹ïåÐ Øv_ß¾ÑøÞ{üŒ¿ü2 H' üÃl߃¾@Û|² ìåÃx [Ž'ÔÝrùð…ÑÅļ‹ÊdBYÞ|†›lhä˜eÇ¥rñ¢Ð#~–!>ùÆîá@M -Íû¤ y0O8À#gšÂú>€ñyC@+ÆÓPF%ÀŒO;öiîe'½lT_"=&ØûÐC½åÃþðÍ˸2’0F@àžñÿ§ú§‹?þøÿƒÖ¢güí*…ŸG·<Š{ý˜õïÍÏú ð¹±³wþ°e|€s7€'xûU3âY?Õföì 7¾:Ì8 è’t daKc’7,t(#–U”N2•aÈOBœžé;R+:æŠËÕ5”Œ‰·é%0”±¶Ž½ÊÕ Ëb]Æ¥³ îФ+Ÿ u£y_yÊhäå=|úvËK£ÀÏôåÓ€`ºñ€Ý€<0&Šà?`E@«Ít½§Ì±·Ÿ‡.42}=öØß¾ÿýïÿê£À½Úд·’0ÀÀß–ý¿ð…/üßü^õ¾Ó¿«« ÁÑqÿ½ô¿ÝC«ÊÍúyߟÛñô|nù_ïWd¸ûÙ}X/ÖŒö!Ž€åñ@latYÀ9 NðÇ?•Zà‘A@Qùr$5ñXÜçSÚÊ«èâü9…[dLñI#Ñ¡®’±Ò*IÞç!ŸvÌ•§´ØÃ̦Õî(N>[@sxV—€žwÅŽwüÍFGØŒ>,ºÝ&(Þ€1pV×Yî§¼"îUCüà?+|`ÅŠz÷»ßýmT¨•€¦6’0ÊÀ0Àÿ¯þÿ€5ªà¿iÏ&÷ãG~ì6toö¼à—ÿ9Ë'ÛŒ^÷þå“î p__gù~9Ÿ`*°çÌžaX‚6ÒìŸ|u’Æ¿\1§‘'䵈rQ7EZ¯Ÿl!«»@S´Z>ñ$bK ÇÛ$ Lú1_¶|Ñea€NP×µâ]Q» €tÆÅ«0Ûò1 3}Kp€4hÀòÆ[œá{@‚û3£€+ E£`Þìyî•g¼ÒÍ>w0Ô%½`|FÀ·PpÓÉE`¨à÷ú¿ÏöiTÁÿîõ´÷÷ó-_6Û ·r©ß–øû—ö3ð×-€~°7ƒÀÌc8~yÈðg0Ûü°¶‹/ûè°C]ä ^ÙJ+L£³ç^?dð‹Î+††ÁžžÅ-àÃ9C4€·ñÐ-|,'~»ù̃´>¦û%~­”Òüê@/xùaï~è®)­îÏO{‰;ïèó¬©þ‰¼3àÿÁ÷¾ƒ:›Úk€»Û'£#¶aþk°D_ùqÉß–ý?ûÙÏ^2àÓÒ›ÜO<ÍÜÛ[3ÐÇl}J[6ËýÌžËùaIŸ`¿ŸÉÇ{l Íò ø‘``MÉð ÇU 0ÂŒYÔÂFÊT*PY"¼ô=• œò~+dz•ð(  AeWaIIM$‰r¾*÷COÒ}ÅaÎëÍ'°G¦Œ”]«F÷Å‚‚´j×*ŸÅ˜ª»¦ƒ ËÿÔØUèK<`ï ág¼3»"‹÷MA~Þ+ Na),Œzƒ«¤˜Nð¾âðyÚƒÆÀ÷ÝèÖl[ã.9åP뺺º¬Ü˜ÝýiìÛÚ=ß«P+:fͤŸ ®ãD&O‰×P;+î¡æ?^Ì `CýhöËÑj'¿ü?ö±=ÿ¬³Îºš<£yÏÿ?úO÷ø¦Ç3ð×2?ža^„\ÚgœËÿðµ€çÁèäñ3ý¢¯}ì¹ÂEàgœ—‚ù<ˆÚ9¦´E=¹sîéY¢ýf?1="ç‚•xFx)J æêjÂÈxigŠ®©›4Ôó6öUëUtMج]xU ‡²@7½îÓæ>gô̪2¸ À¸í`é¶œŸa[àíƒ(¬[ºÿV¸À·—Å+>¼`îwÙÙ—UëeÝÒ¢•€¾{ï½÷-ÿøÇoFá•Vd@£ÿŽ€±^ðS¼ºÉ¾) *ÂO)øÿÝßýÝŸœy晣 þÛöms×Üw[µy•kŬŸ‡:€_aÞ °—þÐhÏ‹Ã0 ±¡àÃEÀq­„Oýú=Šð{CBF€í10‹’£ô<€A4O/Á€¨Äc—`YÎÁiT¼üK§6Ôâe;SÝÍ#]9úؼèÚ¿±èñ5ª @|ýêÚg¯uã÷“ ã׃:†‡tJäçô‘tÒM?Qo1ì}…_¶~™ûòí_vÝ{»‹½«{¼««Ë>Ȇ‚[žö´§}:a{‰|®ðjÅ—Iѹ+4ñÝ„¿ÐøDkЧ lÙŸ›<ù9ÏyÎâ"³Gý8ížØñ„ûé’Ÿº-;¶äœT˜ñ´ý-Òì(Ìúíâ&@cH[X+~Ön³z¤q©Ð” ¥Áá§8lø&ˆÅʆ˃±³< p™p0'^c)¾øR–2"ËM7ÚõfßR]#“ÀpÆF.¯I8›½gÁ¿à‰ó^Ÿ—x½i–oð†K„³x†§è¿U`¼ˆ‡µP\ÊÔçeƒ†gùFöaÒ'uñ^_ ™¬>L}AÓ;¥äLѬí^ë¾y×7ÝËO¹;v汬¾a®««Ëd€—µ@§wûöí/ÅçÚùÚ`º¢Òà] ¹ÄŒf{e°WoBøSn²vô9"cðo¿ð |ÉK^rtûh=ç÷º»ÝÍ‹nÎ磕ígçÿÖ–è1?îð nÖ;øyñ‰Æ0{¥Y€¥1Ýè/:IAqøTJSØÊ£âеBýÁ:¼#ÝÒŠ—’OÏñf7•u€êR™Psž í«\r–Rsùƒ”Ò'†3fË>’b.O4¾è“—×+þŒÆë×®-åëZ'KdÔÓ0  ×­ô|êN,Ýó™®¡!€§íyëù§ôe·"õ÷âë–æÓ`[Öo[ï¾zÛWÝ%g]âÎ=ê\cmÔ^Ô# ºŸ÷‹_üb-ꋤj—`i“ÅÈL³ ƒ‰(€?ûÉ!MŸ 6óŸ?þÁïxÇ;~‚Á?ý°Ãs]]]Hj¬ûåã¿t?_üó~ð§-ŸÙ3þyÎüý’—ÒlÙŸ¼\úçw|šV äË0Ÿ†W¼1@:£!Ý,v¤+ŸI‹ÁŸqä”qe?ª#"U ²ŒJåTÊTS^Â:*T «\ù…äM¨*¡Žãª…E‰e×®ä~ŽèšÌñz:iñ5­ ‹P>ÓÐÆO¿ [·É ÒäKg…eŸÇèÔO‘NcXeÜpÏ ¶òÙߑƄ¨Ë©ÓÑÇéÔñÔõ¨I·ˆšÆa)`Hc8Æ¥NÈM€…ÇKAÀ¯N€ƒÀŽë®»îgø˜ÏB~ÕoáÂ…®½vAãÜKnt‹Ö,ê\4¼øì""8ó""øóžãþÂa˜=±t„u1Ë'¶.z ãb5…)öŒíÕõ=)…Òöïßï–,Yâ¶mÛæð1¡%—^z韅›uð­\àÁ¥è}æy;X¥j†ì‡ó8äœý&ô-t“'ð—Ï>ámöÿÿñ×ü9ä×ÕÕÕpðÿÞ¢ëݲ Ë]›Ÿ½ó±½Vnê#èÛ‘Ýû·çþ͈,q‚¹·Ì ¸²ØFƒ€4òxŸ½ÇvüdK€è³9òÐxM™xc@ôŒÁ~s?ä+óÕIq %gÕ<á2­Þ’ÙªR‡^ÚPúªI¦–@|-ŒVCuÍqV?Ø  ¬YƇ óò@2c€×2tÁÛÊE¡f3ôa¹ž÷ô‡ö1ý`<sÏOv »-@ýÂÛ¢±F;PGKoöH ÛAUAzê#Êf<ÎÝ»ò^·gßn÷×g½ÔÆ8N躺º_Œ½ ¡ó¿õÚ×¾öõ¨ÍÄÕʸ\Îq¢ùÅ å¢Ù?Çû'Ÿ³‚¿ €Ž¯}ík˜1cÆs¦NjdÚ´iHnœûîÃß5ð·=7ùqfOð7c€Ëe¤á±ٿßMk;jÑt\8â³gý=…9óG:Ãô±½æEÇ8úà žÝâUÈt¦q5~Œ^¼!¼Œ{š®ú¸Ìó| Å郅•0>¥“¿b0QY‰w0ŸÝ¯Õ±—Õÿj¯w°v¥ôñ%KɊレÖs:Ò2ìzæõZ©Nçø"šéê¯ ÄM7xݰéÞ>¤n¡o+\ôz‹ºËLk¡¾â­J¦ß,­Àëy²|-nñÚGÜÕw]]ëå9,>êö.ÔõÐùÏ¢îGAº@LÐê°iLÄåOè'ØÉ ã àÑÀŸý”`3ÿO}êSãÿ·²óÜ,rÐA1Ø0÷í¿íVnZiàn‹.3²¥ü ôAã…åAZæv+4‹Û :üp‡«ï1b!ì!Ûâ zÉYYîð5“ ožfñ(,áéƒÅ¹¤hËŠQYÕòÔÄŸµtàou¨~ÕûJK~66&»šql`àÛuËs#§ó§W‰ç®sæ¥N`\ú#ǺÄtQ¬w"]DÝ$½e+ŒQ\ô ãü-MÓk ãX²~‰ûÆßPWâSÇkc uÿ§?ýi¾¨h åü…!Ö`g'„‹ÀŸýщcÿdÙð#Þñš×¼æø“N:éŸÈØÙÙéxï¿‘îÚ®uOly"¾]6óÇ,ôɬå üÃ&?\a# /:¿€½a~-ÿkÃNˆcÖ/ÃÀìoðâµ=쨤à èù¨Ã‚CzØ HÆÕ¿*ãCÚ² ËÜUw\•µ­A¿ÔõVú‰'žøb"ÚFŒ^;" MÌwL þ:q<‘ Ó牵¥ÿyóæÍxå+_y.–Ö9sæè…H®¿ãÌáßîÿ7·zëêÜnþlÙßÏô1ðx#,€·‹Ð÷@éôi-ÛJ.b^lö(HÄ6š†.|òq(“n”xr4Ò v DSä)‹suÁV å”7ägúêP䇼øSúÄ—€ÆB%´$P¸¤rÑ‘¶Á®õJcÜëA›Õ…WKHWÈ7:t ùMÇxýÂtãA\3ûœ~òºJúJ<ÁPð·:I·ƒ†h+6­p_¹ý+¶b˜J#|»+u?1€X@L@ñ#ޱ=7±°Æhãù‡§v"9ž,0ö'’‡îûOÅ~¾…™õ¡´»ººÔgàÿÀ¿9¾üBÜ.‚ö Ä5ð Üy±`E@ü‘ÆVÛÅ ù5,íÂóCÔòÓ¢goqð‚å…j6”†Âæ#fÝ|ß}¥Éâò©8®ä×ÂçÏ@Lô‹J}@þA[žrŒµŠç°Þñ±îßhÕ_éú õG†@ŽæõCl#ú…ºÅôõãÔUÞ7…°é9ÐM7Q·Aw1,gaÒb]¨Ð ?¾ùq÷•ßÅõôqs~c\WW—­ü ˆ ¨e* ôÆ4kA[6¦McQ*;8®]d‘ù!iC_'NÀÏ%ž©W^yå{¦OŸ~6ïq„%ñH€3ÿu[×…å0.çsàÛ²>7ËØãƒôâ‹Ø>f0Îå8\„ö2 Äq™Yœ]`˜t óBÅ_p†û+þ°ûƒ>œq _”ΰîéq¼ž˜?×”7t& (ü¸¼F†U_ò±QV‡p#ÏÛx(›ò¬G;íÅ>(ªìz6½ ë—RŽÇ_cÒ3ŒÆa3Ãô’t‘×SAG)îê9é7òØ-¯ÿbè0žØô„»òŽ+}kêï±ýÄb1᪫®zj¡ï ŽÄØ2¡öŒk Žž$(ö‹à €}èC`©çm ¹ÎÎN×Èÿ×Ü[× ðçnWZº\‚GK̦eì_îÃÁvýsI t£1ì­X(Æfø,=¤åÎÃü£uù’ŒÑ•–q„eúÀã龋Õ2£¯…'.SaÍðÌÏmÈ*ië`ù«¥«-ƒùÕÊHiIÕÀp¯¡Zê«v}›^à—¡?xXy^OXaúÔAäÍüòFƒ>2tõõ˜×sôMjùŸ«›ÔyŒc@ùÈÃ8€/Ýþ%ªì†8b±€îÈ#¼œ`l?ˆ%<Ð1;àMœýìØ¸tð× ¢¯å;Þ=÷œsÎù Ò¦ð5¿Üô÷o\öߊe¿¤o¸môÃÅ`ƒÜ;¿.¶‹ŠÏ[¤1 öp‘? GöyxÑÚ…É W‡hL%­ð'…£ º˜Î¸xÊÒ”>O1/ùõWL+‹×ôUo™_Vw¢% Œ†8G£žj׺tDàñz„qÓAh¡ôõ–èFó<ÒGÔ]t£QÏIß)Œ¸¸@ž0aòéÔ¡«6­r_¹ƒª»1ŽX@L€›BŒ V Ì[e·ÔKòOˆ•BÈxw<):1ì ‚¿ €©ï|ç;ÿKW³gÏv]]]HjŒ»ö¡kÝš-kÂ@¶e2€½À? pº @‹—Ö0é\ÖÇ ¸]hèUˆÃâæ2{lËq Ã1Lb’ðÝ_LóIÆç=ö­¼˜P–^`·:kÍ/-Ë©%ÎzÊþjÉ›x’FK££UëáuO=Sê¨N¼n 陊ÉÀß§I·H‡˜î¢#xó .óqé.úvx}g“!O‹u¤nÐ` }冕îª;÷t@WW—#6 /ÀŠkÑïx?q„˜BñðBh8vnܹhöÏ“¡“B_³Yp¸ïÿ>¼éoÞôרÎ~gÑwÜã›7‹Ö,_\fñzëÖVü…atZÃà -Fë`N€Ï0{fšO³¶køyŸ „<¦H`±ÓYø¶j`”üOœ'Ÿ’Ř>7ÿ`éªËî*Ò@¿Öö4° ©èI,z¿ZÊ©Æc3~î9(s^³Ê'*Sú…q£1wFQÙ óuÁ模áLBoÙÞ@D½óÀñuÁܨ?ÖÏý KÖá=w}Ã]þŒË³êüÛÕÕåzzzø¦ÀãˆoûÛ?‹*ô6@6>>ˆ5–F,jä«‚ëÜÍű#ãÊEàÏvkȱ<4û§Ðñæ7¿ùtÜ÷¿ awôÑG7ì5¿ßôûn9^ïkƒ8²r5Èm™‹àoÆÓÐÁž˜AÀù0/»È· Œ¡#œhôm Ñ_pvÑ2ñè–·,ÍÓŒÅ÷ù£|Zš¯Ä3X:ó‰‡>ûþ¢z*•_—[ WË—ÒJÆÌÏÅd•iqÜ)^y°¬z”cÊ€º„ç˜ñ¹öñ /üÕiq„Íy]hŒã ® Û ¡E éÔ…<¨ á›®DØV°R§-^»Ø]{'èõw|]01‚Ž˜OÃ? Áx?±E8C¶Ðó&1mÜ8vh¼:?ÔÂ:ÿvlð˜öçþçßDçZx‡+¹Áô„¶âgx•åbÀZº¢oƒ™»a¹ÜŃ;fý=/»5/ñbñ–É@ÉVxa ];qÍH@§ì²+­ß ͆eš…S[‰^`S” ¡’,­Z:ËdúotT©¶´9*+öK1IÀK + 'a›î(k0uÕ u‹œSWÑxSGáÏô’ŸØØíL‚9uixêDé>:RúéÒƒ¦S¡?íé)ÐïYyûáâ6D—#ü~€–¿øÅWCÐ=­&ëVq†‡— BãØ«[‘¥EáË£/ðglöÿõ¯ýK4³xR;;;A®¿»}ííweÛ[«ÌsðŒãâ0š,]\ l½]HcØ.Òño޾ÂRI±œØ7>‚¦çcÿ‹NùÊÒŠ¼Œ[9e #H«XnI{+Tmäjm«–o¸i£]ßpÛ™òM eLÆËIQÑiãÌ Ýcéô©`Tu’×KômâÂdÞæÄ…ÞXîçò¿7,Ì4èL–)zË,n>*¸íÑÛܬi³Üs}n±é#Ž+vïÞÍ[³ˆ!¯ýëߎB¹Ü¯ƒu°—ê鸾@ð.¶WË~løâŸø ìî¼Ë:<¡pïxÜýâÑ_dà/‹Öû¸²j5ˆ¹%Q†Í¦[/èÁ0°^°'¾g¶@aÞÛG8¾À‹Í.8òÐÉGPiJ7ߘ²Ÿ8½®´Y»æ‹üŒWK‹ùÕ^Üáȵ6æÎÂ*[þ@Ž¡QTN­þÐJOÜI•ÇmCk®)«%z*ÀÚÀ8þŠºI:,è4ê5Ð{±®3èi¦¹/Š“$®@?Ú!ÝʉéX%àJêïû¡[¶u™TJ]}b±ƒB,Aáe·¨quXýŒªk›UOËxs‚I?¤löÏÿcŽ9æÓO?ýÙ)ÜËiÈG~¶îÝênzì¦l0ì1HsK[ŒG‡\Þâmðs9ËV¦xë—~tpXYÜÆGÇ™÷ewÚuzgجqÒât/¦[ÞÒâ2ã<ñ˜V-ø­7YËøÅW©Þ²<1-Î_ Ç|)\ù$Ù4—l4ŽG뼘ΉtC¨—×n¬[â8±®ŠuZ6÷úŽ/? ú‘:’G¤Oc=žï{÷ÏmÞ³™-¨«ãˈtÄb ‚2ˆ5:b,"û¸sãˆ,+Y\l· -û›€¯ü} ƒm*ŸïÄËrB®_t½Û´cSör V³LãçþiÅÊšåòÃô½ek-gO8ŒÔúqï 3~YåÞ7`$ö+Ž+’ñì€eeÔþ´8½–4Í’c^…+•¥tù*#ǯ€¨Ý¥|¹¨Ä~?·û9š/·3…/æµ·(–Ní¹†ÆYÔqn¥Éi^ïniQÜt–tü ëb=‡0u¡tq;¤+¥?½Î´ýS^Çj€/[ûæ]ßd-uwÄb±„˜‚ dgˆ9±öö’ïàiij?Û)AÓgÛyx2xt¼ÿýïÎÁü,~ó¹³³¤ú»k¾Ö­ß¾>sZª~©Ê/W¸T¥AŒ8[(ð'­6k8ºD³Þù3R þDÞ³C1þ@RYð•„ÂÅ šÒbšÂ•Ò*Ñ•’U¸Ìgþ\}ú¾Mxª”(ÞØ/«w8´¸ÌF‡‡Ó¾”gøhôùldùÃïõsÐý_™> º|¦‹Ä­8}ê†Î¢´0uõ AßÓ‚éŘ&#ÁV`Xútõ–Õ {G1„XBL!¶ Õ4„72Ð)I !¸feÄ&ýegÆ‹“ 9|(|þܱyÞyç}Žá—ž² œŒÕÏÝöÄÿ¸Wà]Öä9€ÑŠøæƒÖâàþ0/ðré‹=ÀA_4ì†A˜]„ƒ6üdÿè›ãõÆÅ3ª]~ Zb±ã…\É•¥•ÑŠù«ñ H+T? ½X¸×ÊW!{ ׫œP` $ Œ+ .ÀÒ¶ÎCµc“b~¯«Bu¶Åñº£š¢`ê ô}°Ä?Ŧ*¡СMF>†`c J­?NÝÚ}›Q·R‰¢žGÖ>ân^ö3÷¢ãþ,[1„X²zõjGlAüY{öìéEÙlš| >®8‚Íï(Á¦u‘%EÁ²­:þ~.ÇØÒÿW¿úÕOâÞ:§˜ïz@IDAT6ýâŽ:ê(ëëVl_á~µä×Èb›%j÷«x Ã’¾-O1nGFêgq6ŸWž=B˜ÃØF éFÌÚ"îúLj¦ÇqÒúðÒ<ãqšâò™GùD£_F+¦Wâ©T&еr+¦GmO¥:â¶Äá8_1ó¥pÿXJ²H²ê0ý]¯!?Uu“Ò/øÔwÔSlæCˆÃt!ô hÔ™AWò¶€×›6Û§>ÍÙ¤ ßXA<ÐÁ÷“ûorK·.µëùC,!¦[€1Ü[VíVñ‰Š|ܬ°ÁãÁ é³Í2löÿÆ7¾ñ´Ã;Œ»5]gg'½ºº­û¶ºŸ<ú“ ôµäÏÁ kTëñrÃFgKqØ@¶ÁŽ8[îi*¶LF>†yyÀס¥6‹ƒ¬8ùøÇåGåM¾Ò—_‰Ît:ñýJùH¯˜†—•Ø K*–šõ¡Zeí¿ü"O³ÄÕ¾ä7NÍr®›±”z-í’îÉñb:ÿ‰G~¬‹ŒÆé»×]–/Š+¥Cיί–ÿch«˜Ô‡Ô‘^Æ~‡UWÔÉ0®»÷:·iöfÕÙ S€1/½ì²ËNGñ5Ý ¨s3REÝ”®0ûçÐb[ Ÿ: üïxÉK^ÂMö¡îଷ»þalúÛ¹)¨Õ–¨x”vï~¸ÏOqÖr jЋD×Åa ;v.¯Å/0]ÜÊ_¬J‹i ³H…‹~Y>Ò†D÷ _ øUfY¹em 1-ñ¸üz†k©;ñŒLõ<_µ”5²ÖŽ^nö¥Qµ•é«Ë !ÝÒiäašô¡èÁð^zSºS{ªb«° ò®Û¶Î]s×5TquuÄ}0/Ò†@Â#?µ³²—ãb ) €ð§@yHØaéÿŸÿùŸßˆg6lÔ nXrƒ[Û¯ûqI V§–žrà¯å*>ÞxΖ¨²<¢kx˜A#+ì}þ{?#â—óŒÅHü± ‰dŸ7$Di1-+o‘V¤3^¤1OE:®VpÊWVf1ËPx‹y‹ñ¸¬JábžO¨$Jc¨Œ^©ŒFÓÙ–F»2ÝcuRWI‘ °|’ ·¤ÿÌ@št¥Ò¤Cù&ÀäI·4®HÇÒ÷“1~åÛ|›5×ÕuvvÚ­`ÍÜÏþóoFáñ­ázbÚZ~ÓœE7³“ ýüÙ ¶™GNÊÌ®®®w±xäï¡Í¹ûV݇M¸ÏïÁÝ|† ¾h•rðIW«éÓù8­ràâAA“4^´(Õ|^¿F –]Ï(s0Àµº£Ÿ2Å0‹®ÖKggjpeí¨![Ž¥eä L‘$H`°ñÈë½Þn°:+ÕWz—\ºE>Åå‡ò}^ÒÕ¦àK¯y½H1X~ÅYˆÂðMgr²Ô‡ƒº—~á ‚¶ÁÆýß/ý½;åˆSÜÓç>=4§b Þè:;;ßã;+V¬àF@ì1Ãô%9ù 5§kº€’Ù þ´´þ¶€·4ýo ŽöY³f¹C=Ô‘ 8º{zö¸Ÿ>úÓ̲„uI€—õi¾§É 5šmbÁ€¥EÊU» ƒ`,ˆŸŽ<ìòEÓÅbLÅŸ,k‘jqæ+Ë[¤•ñ•ÑXh1¯Ñ¼|­Ò’ŸJeŬâ)+?æ+ Çy.ãK´$f•€Æm%¿ÖvÇùkÍS_=cù¥·1ýêóºx9iŠtõcÐyà1ê'^aåÕ6‚é~Öô1õ®§ý×}ÿåvïß=bˆq„C¬AÝíÄtW+ÑÄ$­¯(“B„i±„š"Üt@$ ¾„Kß„þªW½êx¼¨áÙä?öØcéÕÕݸôF·cïŽÜ’¨”la7*š iÚ å æ ç`8h6À™g<Êψå€ki–)„¨Ê\‘^Œ3O%Z)]|Ieä/Ë#V¥WãoÑIÞbY)ž$ÐìˆÇ{µp=úa:h˜UÌ›©9lì÷0é:塟ӑЗԩғôeÐû[ô^÷~Þ¢e:èÝ»»Ýwüî0{T9›°†ØóêW¿úDpʈ1Š=×Q¹°&Hi* ²”$<¶‚¥fþw¼â¯ 6…Ïiòe õt‹¶,r¯}8xþ^Sˆˆ«E6pÑ*3¶Ð¤sƒ‹¥‹®Á7~úÑ&ÒÛ¸Ã!UI”å%­H/ÆËê-Ëg|UvõWÊ£ö–.¾¢¯|ô‹i)ž$$0º¨¤ƒÐý†@ê¸Ü_¤ó”‡¾Ò•ð©;uH¯š^݆մÐöfùYC  »WÞíîßp=¡Á°æðÃg™S^þò—~¼€Å^³Ô³¦Ý À7£“àèK l+v¼•éyx)ÃB¼¡Éuvv‚T?·¿o¿»éÑ›²ÁÇ™¾,TJ5(9ÀØ2KŸ…9hÁOgàÏ`5/þ“‡ap›OšÅ=ݘõã'õÌÃõeÎÊ-$ÔB«…‡ÅÚý¹BùŠ–•¡4úƒ¥Ç¼ 'ò&?I I`x¨x{¤RðÅ:Šoë‘$¯sÓkqæ•ÞôºÓt.îù³^ÿŸ:ØhлÌciÜ@=LŒ¦|ïÞ﹓.<Éu´§ë㸠À/Â-üà?xÁg>ó™Ÿ#܃#Þ@A°< ’¥IÁµ)\…Ùüy;Î9çœÿ—ö÷cêÚþ›WþÌmß³ $p–%Â|ƒ•ÞêgoóƒAÞgA>:ø¶Ú%߬]ž{Ó6à¡p6.xps`FÍ|[jÏò‘'—fc*Ë[¤—ñiÅ8Ë(¥™Ñáûàëo¿Ú´jéâ‹ýáä‰ó§ðÀó”d’d2šcÀôX¤'BÝ^ÿ…8x¤ó2ßë?éLò{=*?èXêQ¦q¦ëeü¦³ÁC}ݽk«ûá#?Dáõs4Z¸€îÏxÆÇà.Á×$­³‰+}Óìð›r€ l6'±mœwó°™?üöüã‰G1æpö?þ|êç–n_êî\y÷#èóq“x÷?h Û¨¥ui€Ÿñé Uö&+Žf°ÙÛ,Ácüò‘FuDš©%$&-ŽpNU!ÂxàE0—Žx¶(ž§i Üûùjâñaoä‹ò©Œb~Ñé—Õ§—…‡“§¬œDë?ÇIIÕtë,K1Ó‰‘î‹y3˜äÌÊ“úG¬CƒŽE:Ãzk ß hºØÓ¹*`6{r eá–í¯ýµ{tË£lYÝ¿H "aCàËP°ö«„[h@¿P·ÊëX8æ®ÆÙ?ÛÏ3¾— ~ÊSžR÷vÿô±ŸÚà±¥$BœF[Ê÷§SKK´0ƒ}‡ îåÛ©¦Du  Ã' “Ÿ°py_›yÜ'ø¯ÏWvÿ»Ú°y0ëÏZÿeyeeŠ«Zšxb°òbÞNH# @WUý+I/Õk^ïÙɇY®éH¨J KgJ‡Ê÷tÓµžF}¬ZÓÓ¤G:[úšúüúû®Gb}÷ŸÑzê©«Z·ž=hºU6´™œ&_–­«ŽO~ò“¯Â;™¥ååßÌT·¶ÿîÉß¹ Û6¸~rˬHX“È' Ö« ´ˆÆÁ+švšóÍâÀFÎl€Óì%÷mЛ)œÏcü2òIY9ƒÐ¬Üˆ§gRUZ¡Me¼*¾Zšxb¨üqÞNHhœÜßWUE}`·'•?JËÈ…c&fQÈ+ ?*9 Rgê Îå>VèAG“Nú›ïà;h4¬Ý²Öýbå/Ü…Ç^8 èá¸pãÆnÇŽ‡›.ýð‡?ü(‹û¸€ØÅ0Z:ÎxS96nL]aö϶ð4³]1ø›pÒI']A¿ “Áº¸õ»×»[»%{Óf÷ñ£}2liÉúÞ°ÇpÑ8@Üz‚Ìí?¢)­¬Æ„²‹¡Z‘§gEã_Ì1½ÐØ\žBZYt¨üee$Z’@’ÀØK€ú®W/¤Q=zÝ(Ýgú’ú‡t'yÐ3MqÌð ô½î¶\Ш³í Ç÷ÞèÖì\SK³kæ›ÞL\Эá±LÂ2?¼šëic3­PPñAjI¥;-_‹ÙÿLÎþµôR/¡üê‰_Ù{w:Úl*ÌûM<…<<-ÄA#ÀqP H1,­‰FGØèWìY&{° y|þ`[ Ùx"R¨K´"Ï`qæËñÀ_åý\žbb!>ÞBÖMHE ”é«>Ò jNŽ7J/£çh(Àt‚tŸVD÷Çø¨[ÉC}ÔÁ,ƒ4¢à™Îö{ð¥¿é÷ôõ¸[–Üâ^ÿ´×ƒ±>ŽX´aîÌF½O|%ïÇAìÒSj)+mªU€±6xêèbŸÂ’õd3ÄÛ.\ø62Î;—^ÝÜòíËÝý«ï7 ÑjÕ`b+Ô>Щ`ˆãl,1±! aÑ8€eä 䓳AÎóqs {ÒD€_¤4΢‹hTÝ€úâ4Ë7¸˜8„x±CÈšX“’)ꦨT§SµI‡‰Ó,9Ó™ØMíe4î ººÖ—Å%}í°|¤óˆÀßÂüCXzôß/û½;ï©ç¹fŸ€ŒõqÄ$õV”x-®èu+€-âAg’à*À~ðß³,a,~ÇÚPŸ=¤ ZíÔüÙ¾öÏ~ö³Ùÿ ÎþgÏž]} ªÄý[—ßš´€nËGô}ØZ„Sfq‚?OŸ?l&Å`èqÁ0«ÞŠeº.&åɆE¾Ñ≩ßGg1eõ]Wž¯«Ì+Ö_Æ3­e VGJOH¨AU i€ž(ðæÒ£´Áèvý{~ã…N%ØÓ1MFî¥^¥A€?Ó^Ì"ÌÕ\–%=nßðúûÇ‹~ìÞsþ{¬¸zü“ˆM0f«>ð\r¹ @ £!Àƒ'©0ÞŽ+ÇSIûlOnéñö ¼~ÝgÿnyЭܼÒ‹>¼V’ƒ­±ýñ«)1s/[N`/l+‘/~KÄ ^F$%0ÆBÁ~OiœÅ”Õcô0V}euë/°Ô­G5U”˜’’ê+½5h%yLOzú‰èWòâæ„JaéoénÛÃ…—hbGÃà±'sw¯»{Ц…A+Ó«´€XÄ4b›zo~3ìh† ƒÂÑ‘3>ö±½³ÿYšýƒ¯nîçKnàÏÓ£¢0[CZhUÜ:†Ùj\’âàMÚÒx‹áÔûÖW¾2P.ò7—-+[ÕÅÊfK\H/I«•T2j­+ñ% $ Ô(^óçYfê»’‰I(¹Bz¥k=¦[Xu³œ¨Zöõ°}äõ:™zú@/ˆÒÑô‰"Xt7NŸOðµîx*À6>t£;kîY`ª‹Vf³ðn€ díÐ[Ù2¶^G}*A)ceðôÑÑסÓ&«É¬¨ÓN;»+Ýa‡F¯nîÞ÷ºM;6¹ÖöV¼GÂ?ú xs0Ë3¦«µ‘V6q””æ¨Å,PŽŸåp8x—Kóô |CŽ£ÎùmóÝ)SOqÇuçæ´Íq‹÷,v¿ÜöK·¡gC¨ßÚGƒídóå«mô‹uÇiµ„Gš¿–:O’@’À$é£b) €o.=JpÝ#-Ç‹Š,îéJS>úú ˆAÝÔÙ^W›.Þ-3"šMÖ`¬ë^çþ°öîœyç»8ì81Š{j5%Ä0ý1qce¨³Á_€VÚ/»ì²3;::æÎ˜1£®Ïýóú·,Ãc°s³wnæÓ *›ý³µl%|Íîu*mphm‚ȸ Bž[ð3l›[Ôsú,/rÌ\.EÀóÅaæ-Æo=ܽôà—ºÎŽN&wÆAg¸S§ênÛr›»uÓ­nþ¸2rÈ!ôêæîÜp§Ûº{kÿ½oè­Rfi92aÅIó¥õ€­÷=ø3N~s>lÑ3†ì7— ‹¬ÅxÅ2pÆÔ3ÜÛf¿mø+O+^¦}áaº+޹ÂÍé›ãöíÜçöïÞïzöô¸Þž^×ד¥¿µIùkõÙæjí®µœÄ—$$0¶z­B3K³Q_'uI½YCãf5&1Ýë\†MçF:Ùh^Ÿ›Ö„†>÷rù4†7îØè~»ú·¡ õ«ÍÒ=̀зÞ<2ÂÑ †AŽZÏA˜qgÄü™ÏÒ8øó<ÕãQñIÜéÓNw‡¶fŸ«ŒÓj ?÷èçºCÛu_{ø*×»¿Çµ„±Ëö ¡v‹W“]<º%… øã>”°%R’@’@’@†yEˆûò~EtóÌ0Þ z `¨—ù4“ñsò çÑÇ—¶Ùýÿ®{›zôÚŠ@+W3QŸà^'Üßt7=„U€ùçºí3êr6ˆY0øÁº?E|)Ð>ZÝÞiÕ¤ºDTE6ŽæÁúyÄàߎG(^‰“>•þa ’ëãîÞp·Û±oj¸ãЧ$-Î püÈ4év NúªÛŠã=;ssŒóìU;ú0òŠéêSŠieñâ§x‹qË'vØ=dÿisŸæÞx›ܞm{Ý^ì Ø·k¿Û¿—ûú\oöØ 8Êû: =ƒÈ¤¬‰V.Û$—$—fƒéºÁÒã>^èИ^6^êZsýº™têfÓÄ7Â~âB=Í2€8–Ž|Û÷lw¿_ý{_îÈ=b± ÖA,C‰\  #@¸Ç–ð3Ç–SGc_àŸ3N<ñÄײQúÐB=H ð·+î÷Û}Þ#â?}¶„-DD,» æß`‹éèSzòIWŸÞ­©ì¤NE|ZL@Ï}îsš:uêÉÊTX~±Ïºä“/çâ¨ãà–ƒUÔýÍÛ7»OßðiwÿúûÝ´™ÓÜ´ÓÌR–ÁD«™wÑÊÛ"zò“’ƱJô•zSÔQFøsé1 “.¦Àåâ §›~]eŸZ0æa‘¾¶"©¦âÅv²Po“/:¶ìÜbï8þù–m¤?Ä®5kÖ°˜y/zÑ‹žzóÍ7?†01Ž&[ŃaöX‚£ëúµøèÔ‰ÜÄ/!P<:^÷º×½“MáJ=ݯÿ5€ ç–÷˜O0C­Fç˜ >¶Ì‡yÓ(ð° KÃ9ãÍ$ÿ<ê|rèÒÌì—ñÄ´|ä.ŒŸq+'¢—ñÆümS†g×-[³Ì½á3op·?ð;·ŸKÿöXà><¸ßõîëÁc½°¼¹"€6Ú…W½]qS¸ö1d•dÕìc ’¾S»K¯¨«èJ•iªÖó™^¦N:›+±P¡>ô6u»×ÝÔùÄ"Žííòi7?r3•xÝœ0ìU¯zÕß PÞË&Æé0AÜ·Ö|DG× )†ÞFv’NeçyHl‡Ý'ÁƉg"ìŽ:ê(zuq‹·.vëw¬Ïžû·‘ÂÁ€¦0L_[ÇÒ÷üTI¡õä?ZúÏÒ³¥&ðR0Ž,Rò[–^ÌÁx‘/ŽÇaVÁ{ð»úv¹é-ÓKj¬LzbÃî-Ÿ}‹ëÞÝmO´ìëumû{±÷ýyïŸïÀ½ö‚-WrII“SE]U”BYz­4–x¡ƒÃ*+t³}ˆ‰¤Cñž¾Ìd:™Á`a$R§÷DqnD1à€÷_³u{`ãîô9§³¤»ùóçÛ‹<¦ ãö£`ážnPhÂz…tú£âFËPg ù£Û`Ç{ßûÞ °´<­Þ›ÿ~ýįC­|žßžéZ‚¡à ßL¦yG€µ%#Æ=4£g»NÄšó™nŽyJNgHri9K¤˜Gaùe<¤ñâèîévÓ;j7ö÷ìwüÊÝæm›íÕÈq{í³‹)«‘õ“Æ—ñýÉ% $ LP ”è­¸§E}eiQž\º§çôW¯hðãüVÔGöoÚ(k’t6ü\¤ûÃn_Ò(ÍOCm?§Ý²ä–ºÚ ˆ½ÓˆmŸûÜç~ŠÖïâ½l‰ï]ÖÑúM€"¦£ïEo–Ò~æ™grÄ;ôÐá=ÂÆ¼E·jÇ*·tÃR6.ñ³f›¥s D4ÛÜÇÁÁ–Å-DØi sÆo Y<›ñ£,¤) 󔸥Ńä"ãe´¨ÏqÀ­Û·ÎÍë˜'U _wëuîá•g+$QK{‹=ÿßÒ/¢ÏiØÙ¢ øˆ dUlOÕJRb’@’Àø’õW5X¢. Wp•ôC}­X6ãl «óa«[aèeêfÑL“—‡×é¶Š@ýÇ÷¨,ÃO{xõÃnE÷ ×9«GîˆeÜ lû+”v+á'Àl®СQÖ*‹ŒÆÏhì}ê4ý° k©ïü·ç×øNåz¹?¬ûC¸·Ïš³{>hˆo5ŽÆ[ƒ”>Œæf÷û'13ÿŒptÁ‰Ž §¹ÿ§Ÿ:` ¦~žŒÔÏçÉèyëõtÜ£_¹w¥{úÁO%W p—ÿ5?¹Æ½ ß °o›†·âE@íÓÛqÀG¸ †@+ Û^ 9U+8¥% $ L ôë©bg©cË Ÿ'R¡Asæhq‰Ìƒ#¤g· Ôa„˜>§'|³K §HÓqLñ îFµÀèµI Ò`üzÕ¯ëfËžxâ l;7uß¾}{Ñ ážo‘¡Ï˜Ü`FËñÔÅ–è·èCº³Ê6ÿüd]Ú´iÏ&wßêû²å}Üï±Ù>Îú¾‚q»ÄV±i8è aüs<Ù C<[ñçÌt¤‘ÇÂÆ“…4Çt8³x*ù}­qZü,}ÎÊËÚT‰Ÿmzl77œÖæî\t§Û¸m£É¦¥¯Øãå?í3Ú]ÇÁð;\ Ò±»CGÔï¸)<ðÜ$™$™Lª1õP¯þZx5Æ2c½ca_—Âò3^ð{}|è­L¿£(¦!nX`~–Æ•Í;–Þá6ìÂWRëàXžÇ´Ö|ä#— Hîu‹±/ÆD4btÝh¬°Gê}v8€mþóÿ/'ãœ9sèÕÅqóß¾>|å¬Ù ÷¥Ò*Å©·OP©³Q„ï›%K ­·×JÒÄdV,k€¥ ºfå*¿'=ÐT*ô™BzÄÓreízbï®{·›Õ>Ë—RÙ»÷±{³>عÔß çÛÿ:ü4¸ Ð6 ßè@:ßš(y¡½ÖßîÊ5¤”$$q-A®ñº/âAähž·Œf2£Î…‹Ó-Œ|¢Ñ·ûøª7òÅ“•’ýR‡I‡Æéˆ½½{݃t{AœmØa½`áÂ…‰B¾‹ƒ˜Ç· y €hBG_=0B#mÄŠ-¬¿ Ë#Ó:è Nv”ÏOÖËýaõòbek980 Ðãs€Óa÷Œ× üRÐWÃŧxÁ×à#9[œ†…wÒŒ»?Ýøãv‚À<ü»»ûnwÁœ TTEÕºUê÷Öv¬„å.û ü±üß25KËVP²¢â §bá)!I I`üK ¯rôg€.ˆø¤ùÜîyCœéQ~c/ðoDS^úvP2ì 2:9§ûY0õ¸­ L»mému3øm€åË—;`\±nçμ @ì“c#{ƃ-ö½D¨AŽ7ÚE/ðgçÍxßûÞ÷°ÊZø)Å0Ãa«Vn_éÖv¯Ífì¶lQ³mAÜê‘Ø -Ôf;%<ÙÐÂ¯Ý ï]ÑñÀœ >Åc?N‹ÃäáÎú˜7‹—b]4Åé[h×Ûî¬I‚Ûvm 2±ÌöiÐà1ej¶2À¯ÚÚ <öÛŽÐ’¸)œ$$$04 ˜®õk°œäõâeúZ::”/}N,°[&H·™´U›V¹%[—Ô¤Cc"Öxl›ò|€«†{ð‰jQ…+µ>élÈh9vP•åc‚8á„^ÆFàyɰ¬3ÒFÝñäò¾ÀÞ|´Âh8ù÷)Ì™½ÂÀ7¢mv°õÞ³ô ¶™ ¸ i¾*ó8Èc'+V´8=+½ÌgjÿÊ=+Ý»žpGO?ºŒ5ЦMËÞôÇcØ Vx€Ÿ¶§gûÌ?sù¦‡²R I I`‚J Ú5_–æiÔEÝfŠó(\ôÉÓJ¡übšKWS‡2lmAšé3b€½ ‹Sw?ðþfåoÜ‚Y êrB‰mÛ·ow¸ p ¼±O8(\ô ¶.UÖTH# u†¾:H_–ÚðíäN¶¶^ŸþåWÿî_{¿ëÃvO;éþ±5Ã/´À¬GœlΠ핶h!y6ßš‹±åþÐàÈ’ne‡š•Ë~Tre@.š|æÃŸÒäÇu‰fFúyÛÆÛÜkŸjOVÆl¹ðìCð¹eðò1?;0Ó·Ù>Þ[e>Ζ½;ÁÏús™S$I I Iº°ä½d¤—bA•ÑBzYyEš‡r§î¦^–~g›&:̾kB=†°½LH:¨¤|H,Ï+ît¯:ùUnz{íïT }(ˆm+V¬pëöMxÈVè ùÂ­Š‘z;VØhÇNèPÙi ¡íŠ+®x6€´®»ÿ¹ùoOÏ[Ú¦H5 ‚xÙµ¤F\ü9çËë6P ¢9ôúÿÊ–ãûS3c#Ž3¬<µ,ýÇy•/G‹n˜´Ñ¿ßuÿÎmß¿­ìµ ;;”ÎJxÞ_ò¡O™¤¿$$$&“€i¶X?yPu·ézéyï3]zRX`{œ¼¾cx×>L$7Ü_Yy!…“Eÿ4@Û{Þóžç!«á|b¡´-[§ÁÆ;VÜHÇÎÐy±[GÙaígŸ}¶íþŸ9s¦1ÖãçOþ1ˆ±ø.h–¯“ÒÐ:…ùœ+sæÛ€âVTe8âÉh„rÒr<1ÿ á¬¾ f uEy­ž(®úrß`;Ø>H¸§e¿ûåú_¨ðRÿôãN³þò~˜u#ÂdAŸ_ÞÈú7Ù¤¼:ÏÉOcaÌÆÀˆô[Î[¡ A?y¨8ýp˜ÖËôµt¼¥ùL¿ya¯óÈÇ4ú¿{üwVB=~fÍÊžÊ:ãŒ3¸ Òã€l ü,Ö _Z!pj<}ŠS‡€?øþSÙ€z}úwãžî‘õd³Öγ­ûývæIÃe„Á„aaC‡õþ8Lés+Y Åñ£Œ‡L‘c)ƒ¹2ž"MKhqi1Âòã:±ÒUpè ûŽ~ÿ|Ã-îs_覷•/cøÔ“Ü!Ógº½öf=AY,¯xÔÐÍBR4I I`BI`€ž‰{ç﯋”ã-¤OD¯|¤çtš§M<hYyâa²*óLoöû™…à 1\€v§©4¦>ðøîÉÓŸtGÎ8ÒZ=’>â¾zõjÌ;å ŒÂÂIúj>5¹o(Buv2ÔL6^GÜ9v¾íYÏzÖüÖÖÖéííxÑL+I#wl}¤ß܈kV˜>[âã4t/Ÿè’9IaUhËò®ÐÅ8ÙŠ´~ðÏŸç˜/Çe(¯¯>xäç2Öî)»ÝÍkovsqH‹-0sŸwÆóÜMÜd÷ñì>®"–k·&|8ΓÂIIIE ätub¤Îri…Œ!-Êh¯Ñ"&Å|J× ¯âE®t£ ,NLàŒÏ£”åe°ôÐÆ‡êbãˆupÓ‰}¿ýío—e5¨Ö™¬uäm¨cå‹ô½XÍ7ð­í’K.1T⽑z¹{ÖÝcEÙ’¶üO{„V°EjUäs ؉g l±ç˨þ—ËP çh>V¼7_Œ—å©D‹óÆaò+^iïÓÕWnäûÙúŸUÝ ðâ?yq}½8쳿™ Ò^WêA¢' $ L( xýXï>UÒ§µÔcy íRyÔ¡ ¯·ƒ^"Iÿ{}oXAÕÏGŹ÷‡Çñ>™:9a°o,Û äaYêTwY1\`ããƒ#øëh›7oÞùlT=—ÿ—m\f­Å5‡A€á`Ë<¬Žôâì>¤çÍ2ôVlà‹¬Z+„=ô4–»bœiEZq¯tù¥y|=żx½ô÷´ìqß_ù}÷× ÿš,ÜŸœð'î¨ÃŽrë÷­w}üü¯}Ÿîéu­}­f”Õ5  DHH˜ØÈ«¸\_興w@s–¥{ZŽ?âSž ‘f¼q>Òøg÷Pô Åý¯â¡ñq:óx½i>˜¯]ìžÜ…ÛÓG~€X·eËì;E…‡ôþq |ÏÚÇ ëíØx9uˆ¾ŽÐa¼ÉRÇÛ‘Ä?"ñ–Åvò4ã'h3»×»ÏCV4Õ‹Úx™NÑ,œQ³$ñD4Àôôb¼À^UùdŠÃq< îÒ’2"ûÉ7üñøŸMÿãÖîÄ‹‘Jûþêg½Úfþÿ¾ì„èÅ Vì‘^ Š% K¤$$q#ê‘z¹šËB•ÆWíi1á\Üë~ÑÍ/bKØñàúëÒ5aǾ€…(\øHŸ½¡/÷N´ºøq%u)0*DŽ;:|饗ž ¡·â¹Èܬ<Ê?äà½ë³÷ÚStw;ñÉg«p#€i&oOç VË} làT¿J ]ìÀ>Y¨EÆaÆså³ì›7¸çôß—ý{Å’_vÞËÜìi³m onðÀjÀ” CÀÞµ]1wJHH˜(èÆª} oÕ‚jO4]³{=h:Ýã‚ñÄt¶ÓÇ¥37FÚ]«ïŠKv˜å{Ìk%¢ €‰ÇXÉ:ز†:Vا†³|†éÇm{ö³ŸýbVL‹ˆ³Ù‘»{v»¥–ö׆¹„Ï—@ð/lôð- qÏg­DA”Œ[Hmó÷”n>ËgÙ…?öKNie|J‹ý˜/“Gñ²{ÿJ‹Ëb˜ý°ûYØ ðàÎÝëïTÓrþÔö©îµÏ~­-ÿ÷ìíq=ûü±¿'ÛÀúù®Ê#ý% $ $ AAŸÆy ?ëõgåÇå1Å™NWIßç3~¢éø[¼f±Û¾oûˆqŠúS«ÀÀ?G •n°v¶Ú·¡¸Fí`£Õ¿e0ÚðHÄ™ì_‘X÷ð–‡íDÙ›ýT Ä_ƒ³}žPùdÿ©Os.Š–é-é°/æWY-ð3 º÷­Œ8ìÂz™¦úsaÂ|^«¨¼%zÿúûÝ3zf®{Éó6lØÀ/ß>ù‰Á±@¬$fê l•ïBuv¬¬žŽ¥+ŠRbǬ³¸b;*¦NjFúÃ76Ù²> Bí ÛrŽ_'à«U1_6,ð ËéæG±|Q\Á"Ÿèò5ØÃJ/ó«ñ)M~<$­¬PÐLxÕ/|óÍîú¥×—rv´u¸w¼à®wo¯ëÙÃÜ`{xñ¢lØp,mV"& $ 4“¨Ýå†Rv5Þ8 aê@éÿ 2Ã-Ùc†ö0GHòݳ&{Âl¤]æy ŒWÆYߢà³JÒêîµ †ªCò­³çwÞ<œ<Ùž½‹_Ü#ð—mÂ#•ª¢"@ç€^q‰Ö‹™à©Á€Tî…/|á0°y-üÄJÖLŸ¯'qÀ1L7Pû³ («#€>ha©ã¨£Ž:›üõúúßÛÎIµk÷qž|­ ÈÚ 3{ð„0Ç8þ,f½½Z\q€)èò5æBÜ32^Fcr‘^‰æ‹ê÷ÐËëÏ÷¬Ú¹Ê]¿äz÷š^ÓÏçCÇqœ{Í3^㮽ïZ׺«ÕŒ3° À!I 6­ ["$ L P§Fàw<§§"¾=ÎàÃÕÒ‹iÅx(ŽºÎºMk¼¤cÖoôýaù|ÚÔôz\!>ðI³zľ͛7»ùóçs/\ÀF¦ÔX+}¤ Ž8VRo§Ë÷â lƒõÓÉJµr¤ X²yI8¹,‹'ªxPŒ¤™ó-³Ù>é¼çcrfæŒ%þµ.«çÿgï:¤*’vm`YX–%gQÁ@AÄŒ`Bïþó §g>õ÷ÎŒé wê¯ç™s:Ó¡¨œ0¡‚ DQI’a#›ÿúêu½íéy3;»;»ìÀëÝžê®®NÕýºªÃë§8…öCçã,ê,çC ¿²âúa#”Ïhsêþ§Rï6½å0`yI¹@”WõµÀFé’Ñe 1!B¤>ü1¶±«0†#KåõlzÐZ‘ @AvàÏ‘!Jûíªo“Rz¼ cd!&⪨¼ÔÒ)údÿ$sÀ°Ò/¢VĆRÉÌÌÌ\P%ëþÿ•ù|ÁÉBÚfì,êU õûÐZjðøëÖ þ‚Oây¹Dü*^¡J‘ i¸BЩ[¡·‹È-ÚAÇåÇkP°p×7wÑ­#n¥¬Œ¬ˆˆ-2ZÐ_ÿ+ýÌÙT^Ì[Y¼À+8™ÆÝéàJxš!¶-D_~Ýu^ƒð]þxæcV~<Å)äènXʆäAkèA+Vdpfi_ã ´Æ/õª[Ç7ø—­[†ÜlTöYè [fÚy¡¤Wì ú¹‘Q2²Ò†Z©ä1dz 4>Y3#o@ Ö—­§¢²"O!WÎM–~àfë»7‚÷}ÌOC§áÒðŒˆtŒM w¬÷ð]:ñ[Ð JÇÇYñ|œU7-ø£èX9‚® A޽ý•+hê·SjHÔ¿[š¼ÇdQ° Eõ­ÿ>«\Aeq!Bl…À2zÀŸ;¾Ñø¸iHx¼°€|5M̓š,õ+-ÒsÒTZÄÕEw‘Z*Lø K _œm¨ÁÄÉÈÀ4ÈDNÏUTò¸°¡YGÄOæ €&Œ«ÐWˆÊ‰{ï½÷–ûÿ“v0IÍ,4«Ð¸VzG„">óË»ÛÒ5Pp™ù³ C?@Cû~5À ‰ô¥)¯Ð ªÑj©á A§n…R6“€3þX õàÑ­€7~}ƒ†ñµ {tÛ#*™É#&ÓÜesi~þ|ï-Vä·¦œ€2ÁËj¡ 9r`ä@ôP(LðgìðY4þxdá4Ü/̰اµÓ·âI>ìW:…&ºÐøåá!L|¶1c¾ÈvCp/Z¿ˆ:õèdSÕË XRRBüVܾ/¿üòלd¤/+¸F`‘x2 ª…U7òЊetëÖm7dÈßDö–i0{l€ýiÓO^ŽšC4’] ø‡ŒM8üÒøˆ§nÛ¯x ú¦œèŒÕ!‰dPñÒiý± Àçdi?;îYpmܼ1*(MW~%åTçPE1ß € ‚°  çLÛ13Cr ä@È&á€?ž'š›=®·/bøEVx?ž\ÛÖýÐ ™¥ò2¦k×®‰ü¶ð7¹B¤’)¥ø“ö“ì-´ }âîÿ(½^†ÐКüZøkd\>ÌèÕ¨ ÔN£~ ‡à‚er]$’°[D<‰ìåeœQ ½­(BMÈöÑ+],hÇ Ñ:qëàn,¨( Ìû]3âáƒMß)·]6ú2ºâ+¼UýT&ÇϨæu>€e3áo Ûí$BwÈ[#t,qêfWöªdAá>ÎNÓ¸ý0MÐ ³â =ülu^¬`=·&)áˆ`àDX¸ù+,_ý*Y&vçTláïÊMŒª2²&Kp §¶+"NVVV;°Œ?4ج)Z-|Lî²ßÁdx'éä¡eã}?§á+Gö…œ¸ðÚqÝ`7LýngöñVçSœ¦©~…ŠãÒik¡u¸UÒ²x5 "¾*üŠž_ø<?àø¨d÷Ýa_š°Ëzqñ‹Þ¥@¬8ÈŽ¦…±šÐ8]4ª(!"ä@ÈæÂŒ%‘2SJ1þÐD„›ºá´š …ÙùÀÍFÇZÄ×?ŒSêv¡ÆrCÆ3“ޏyˆ½:÷’oЯÊ@#E>r‚fDˆÜµšü×àºÁäHa/O-(* W(•ã%,^R΂Õýøº7šzCÉz>Õnrä‹nxsŸ=€¸¬†O­KCâ…NO@qÖŒó è¥f.µžjq½¥B£™hl &8ކ+ÔT½n¨>FÓã#cÁœ·CgxÞqV|C`ue:=µä ÚµÃ.´[çN¢3GžIß­ù–}Ç+ÌQX°•ùž†„˜±¢l¡ 9r`æ€;~E²c° çšxqê†8Ïs×䋉!ãD>ðˆÉò‚ Ä~Ȭfbeœ WˆKP×®«)r\FfA6æç狜ä$U†ÚP¿  j@Î5Q“© U• €(<,*%î & fwÒÞÿ_Q¼‚Ê«*¼‹i¸¹ªù`Ÿ43:·4Ä>Ìf¸Ä]…6†e° øÅÍÐ3H̸B7(¦âÐÏÔh< %A¶_¥Õ¸± 7fÚjâã|oTóG/nýâ6ºó€;)/;/":^ ¼æðkéôgN§Â¢BVÒ©š·Zp|ð¯]âA§V–G$zB„Øú88àð˜9ÐEÕÛ6ñ}?(5M “ÁÜIBÃlZËô4MßÍéðypON Üø!<–ì?bs‘¤XCSYQAK –Òv¹Û9ª»wádã£>:›SP¹ ("É‚uÏ –ÉT´°ÈRÝZøÓwÚi§]˜¬ €V­ð–æ57@6rÊŸ‹ ‚ÈߟæÒÈR¾¡“RzQ@mšÚ l ô6ÎqÛÂÙv+™â" T¼M„C¸‹×86L„Ƨ×z1_äžÿ*ï<À†Š tã§7ÒMûßuã_§6èšC¯¡‹¦_De™eÞÓ]ñfÊ®ø\!¶=ˆ°„Ø4Ærú(_:{ ?NÂÏ6b\Ó´‚h‘”Æ ¯2šÒ0˜!íj–ð¾…ßXÐÃíÃJ–&Æ‚xøÙôKR#?äÒ«Ì4#ª/¥0ZÃjíÙÙp“L¥ÑBjEà–Uþ b_vËû€ 5¿–xu¯¿š—¢EØs1|ó Š€~ÎP”dÌ¥bj¯¦Ôƒòà™˜ñÓ1ä®hÅ)Ô”m¿ºº4.^Ãm˜M/-·–Þ Q•A Ð_>@g=3‚ž!½†Ð{œAÿšû/¹Tñt|öÏ€½‰³1*Ÿr äÀæ@âF„µMgÜ‚×â[áŠW(ð†k\LÁqÓ‡ £$ Aã}À+‰E Á-iaÖ_ÁÔˆ£J ãDðBè—3½â ü"€WÊ“uwÀÙhËLÛm$”&õ'™ €õ€(¼Z·2ø½Ç¤¾°¦xµä¢¡Ñµ^@#£Ñ¹4¼=€Ej@ ZvKè€ÆCâyâÿrÌ×ÀœO®…¥—X N:¬›†Gõ‘OTh„dÇ‚›—󱤟ÁUWðUÁË_¡íÐA}ŠŠ|âðiáêïè•ïxJ³+ÿ8À_ ïˆâZˆ9°…9P3´DÇ ŒAABЩ•ˆJy4Âxj¥¡Ã«Ž³~¸Mc¶?–iº6&¤aVžâ´ðÚŠ“?Ê¥B_ÝêgX%ŠË @( (ð¼5êÇcÿŠÉ}ÀÈF_Vr™e4e¨²Õ¡Žd™d(v¡´Ð( ®…7Ÿvl=ýwCÌ:>™ ¤ôoöo G ¬¸ð#q ôQ¦†4*7Žë 1Ú¹jÂÂE¤¡Ä0(ï²h”ÔüâÕ|2˜›-?œÁÀ_ÝA½Ûö¦~íûEÅ»tÌeôË¿—Ò’Â%¢@è‹å-\Þ†[Ql !’Ë8~„°  7t~˜ÆS¼ŽzŠçÚø³rÔLélAmטÑvTúv\?ÑÎ+Fº~zˆ¢r?"òõŠ'PÝ’…7þyÙ²[òðp’ÆH'…˜V¬ò ümÑ¢…¤À²±;¢d¦IÞÉ]JbÕ¬þ…H†€Ü•5ZPüðk¥ÒYðËpú1¢±êY~|Ø7&gb\œ èÓ¡%…S”³omˆ¿6ƳÝHSý cáâáf;-Ÿ°ü€a(ß à{ÿ3*3¨¼²œ¦Ì™Bÿ7êÿ¨MVÆüf·È¦¿‘N{þ4*)*‰ØÈäwÁWÿCKš~D ¡'ä@ȸˆ1 EŒŸ4~¸†1 Äé8gÑiy|z 4NÀJè„+:¾p6‰Zik>þx¦a 9ºŸ®…C²>cìtÔ ([ÄV=§x "MWãaŒÜT¼ÉÇk^õ#aX6b/À—•ìF¬-KÙ+8§æ@×Ï$K@îZ`Úb¹ï}| @2L~I>šÊoL¸…¡\Áó/ ܶÁ5ÀÒ¨ŠD©_Eâ0ίiÅÂ#\Ãj 3ÏS·ÂXtv:¶ÛŽgãëäV> yx1 ÿ°ªpÝôÉM4eÿ)Q‡»äv¡)‡L¡‹_¿˜ÊÓ˽eÓpÕ² äsÚ.u*OHr`kç€sìjªÀœî‡)žaŽ#FoŠÓŒ4>ü–;¡qÄ¢×äì4ç—K MüˆpMSÃ4A/I$@c§-uâ8>Äø‹4Ø­i‹[ "†‘¯† ~CÑ kèÊB##ä%§mËRu74ˈøÉ‘Ä^’( ŒÔ†é»í¶[G„%kùsåfÚ\¾™“ôZÆûC 6Éâ3 ,ÖÆ+f4¾¦à^ ü+‚+5aêF¾êvaÜ0NôñhÜôjó'--ÎHò⟠\Ì'ú3y+ E«Lš—?—ûú1)¹û3´×Pº`ÄTQÈ **§ª’Jª*åOË!|wÁ¤«¨­NaxÈ£­¢ Ï;VÞ13{˾›ý²çŒ=kÞc‹ƒjØ{ÆsdÛ2ãWh‡ùnÄ5ñ±—t‘§Z‚ƯnŒMNYýAÏ/7VSµ—Ž?n~ŠtÃ|?;à†Áä[ð€ê<Ë Á!ÔÐÛáŒÛ\ZB%¼ê™cdbš‘‘ÉÈØµÈÉ+\I2ÉZЂمŽÐføƒ;¢Ìz걡å_³ya‘—¥¯¹É‹è‰l8H qÛ³P:„i¤ˆôb±›+¤ÓØ¡¶Ô¯PßMWi*­ k wéãúQy®¸”þ©fE€¼ûô’§iûvÛÓÈÞ#£’8jàQ´tãRzvѳÞ9œà³™xEG$~4(Šm!"Õ9ððÉØz9ax‹ðƒ\±aˆ‰ëÒØiºã…‰•¯ojÆTÔ)†‰’XâÆÇ€£<‡óø@IDATDþðc\ãòàœ ‚Ų_Ý"ùÙçÓˆä%œM‡kè16Ô@&à£@;Ο?§gËNd®YÁb$Å$K@a´.”ÊôèÑ£ˆ²³³lÖmæÛ˜8'ÙËáFRˆ×øä+u†¹?ð"ø9GÿA ÙxB?š—ñ;m4½—š÷ëçÁ^Û­4ŠS¼ºÆ£Õ0…nÅ7þ ÊýÜó±PSÍ—ÝJÝrºQÿŽý£²8k¿³èç?Óœus¼.ŒtØfð›r(-" ATÔr ysÀyìý1"¯8†Bgü¶CxT9ó¹¶hš7üÒŬG¼:…a,qêžhÚ6ïæôÀ‘€ú§²~þ^[ c™XS>\CŸ 2 @Ïž={sÒ*ü572IòL²Æ-¬_¾ê°3ôÔ#Ü 1ùeù^t«SHƒ¢á¸AeŸ†öFXÄÆ„I#³[/0òWh"Q>;Üv+‘”…=v˜º‚6ˆNÓ°¡ÇÆ'ÍÍ-ŠCò½€ªtª¨¬ «?ºšîuuΑ&õ³‚¿öÐkéܗϥŅ‹=aÀi œ8¥Lø«=Æ:Blaèx`Š¡Ï ŒA8¦÷Ç 7iÙáZ;ŸN ü20 üuµy£•sãÆ£Ñ0m«Ó´ùî»9\Ý€ògdƒ?Ž*)—Ð;n¥ÝP’œsü€äÀ2߯ÈèËMãNGL…Œj¸AFÉ2vÁÜ ¤ó{Ž"-´² ÍtS™yÀÊ5®à†f§î5}ÔomeÒ†¯.V¸v¦†¦+ýÆÀË)~V ¼ñÕÀŒV´!m]ûáµ´¹g0" Þ ¸åð[¨kFW*ç3å|& bsUa¿{’ØëT…,2jè 9Ð4€ °¬ôIôKËÊ¥1xÁð><.…ñ-÷eß ¼ ÷öÜ9Þç=wIÃôw{LúvÞ}˜ 8`É@†Øá¶Qq@€Íúbï5tñ4àG'ÅFFš)S„" ©;%Qtýa²VìØ…ô^æ'ë ¬ 'Ëò£çÏ.á†AcÉ6ê’ŽÔñGÓ‹ͦ±ÝGq ãá•F¡ÒÚ0^˜MWo7x KaüVîHÇ™¾)ðû‚ïé–o¡+÷¿’9k79QûÖíé¶Ãn£?¾úG**,òôY$ÅéàÍÙVà­‰µÞE #†ˆâ€7øhWñT…\…°î»Ñÿ¡°Â¥ç…x¿N¸´­ºãQñ”_ñh ³éÔ ¨n¾0> ŽÇ$qi»saTv( `Ai³APe"2#¢ÊMM·ÑFɆ*(˜NÝ Q ø3XËÉ'#—5Ü•ù3I< úÚnÁóƒ)†¡øµÄÀëA}x¦nSLé Ù¦³ÝÕ/£“h]úX´š ÇKº[Z‘ùÅåõ@^ xíûôÀÜèŒÝψʮWû^tË¡·Ð…3.¤²BþfŒá;>„ë‚ñ‰6­íáQ…¿!êÆ÷yÕÛàu D§~….ÞÎ\ŸCçäåãC‡Ç‡?Qü•Eã‡[8IÈøýp;ž†iBW!²@P:ueú†®÷þƒx óFeËoâJùø'³Ù†VD=¡ÊD##! uD´W€S¼BSÃzfÌѪhÎZ8…Zp…xýONÿé{±¾°¤¬Øc‡ä>ØÂDùÂPY%½Õñk¸Éݧ9<5ñ²ÑtN’•â"'u+4eЉ÷Âkâ)}#Bf‰°ˆÒqï?_ÌO /™fг?=C]Zw¡ñ;*À.]w¡[ù]üæÅT!w0 }YNàú‰ÀPx.D%"BDrÀzLt0×G%ÂÏtþ@ŽñL\ÅkÂθ.}[ÃBØP¦×šL,ºXx$/Œƒ1¦pãbÌ÷û†ÁÕÄå4dLÒô\?sœ*¡A~5¶˜'¡É0*ŒD aUv*T<`ÒL²-]8»Ài\IQü·Æ¨',ª,æ¦ð„‡4 çˆLýW8LÚ’§†\¢i&blº á¬Ð Óx ‘W,Z»6½oT7Nð³Ág€Ó²x9¿š_ä}Í»¿¹›:µîDû÷Þ?*ûÁ=†ÐßD—ͺŒÊ¨\Ú탷Q‡P ˆbYrNÑ>%‰;auÊÐë~YÁñ}ìpÂí :¹2Jù-œïgœºJÇâÌ|¿flÅJÂ5,„‡å^è#N€ãõË ‚xaš€Ò(D$¸Õ¯¯öizâ7>&†Õbü™±«˜ïHFÒgˆedKΠܱ­Ÿ»:’ “¥ ÀjìÂÃ- /sH^ZY%®/,­(õZ„4ÿz³x/e4ÝHB rn]Ðã_¬G^3€ië+Þ‚ÏòijñZ—Ný %Ž™’Ø8àm/̦Kª<1-*ûøø|0oàÐÓõŸ\OÏþ;íÚeר,÷ì½']wÀutÕ{WQyZyñ–ôM?*…“V?ÅõËݳºS·¬nb;µèDm3ÚRÛ̶Ô.³µJoE­2ZÉk™™i™”íéäÒw‹*‹¨²ª’JªJ¨˜•ëÂÊB*¬($àá.¨, üò|ÚT±‰ò+ò)¿2Ÿ6Vlz¸âBF<ßÞc)EÀc…ÙÏŸ>'гýrß¼Ö—¡„Á¯nÉÉó«ÐOÃF†îÆá€¶I=&ï•ÎÀ(º ¼Çï$š™U%'¾ÛWdüdÅëxêú‘¢&.Dòò)Æ*tŒ>,#ña3ÂúOüöÓb»œ{2·@Z`òÅ{<â &Þ|ƒ ¾¹l³4& ‡Ë®ø{Íi,˜À2àà–&B†!iT¨&hL C©à¥a$®æú5ÈÆ«[Ê© }¼dêø8£XäâÔpß$~ôð‡ø¬óøfÀåï]N÷rõÊ“+"г¿ýé/¡)Lþ" ØŒjïº`yÕЬ0Äã}D¢Û¢Ç >ÞZ  Zï@ý²ûÑö­¶§î-»Kß®+[ð<´Éàï<ðîcÿÕÅ”U•Ñš²5´®l­-]ë¹ËÙ]î¹×W¬§‚Šï¹7Ï”Žv?–gýÝÔÏNøy7ð‡qûÁˆš-˧ b¶‰ÒE„×8ZC—ÆwÂDyD<ô'Ó§¼ùa ŽýŠ2¥±ÞàxŒ/-/Õ’4êóÀûÿAKþxrl‰·]ÛzçŸ ™kmèâë]Èx1p¸ äãµD.‘å×T-lµ-+‰mÇÉü”ÁšûŸ|4ˆ_Ä“Y•IEUEtɬKèÞCï¥v­ÚEñdLÿ1TZYJûøo‘Ý™)q0F. BD7«„o“?Ìܱ0 õÚ½Íî4(gíØzG™Éoi~d¥gQÏìžbc•¥´ª”~Ýü+-/YNË7³e¸´d©¸±Ê Ænsó âY“g~;^~ÆCr ñºÆíO‘yè1Ký1Ç 36•U˜ÃÍ1ÒI­ò‡¡+ü‘rÓÑÐv'š|\ºd)š‰~-¬@S¹¤­`Æ cks:‹ Cªªq½÷êš{¤ˆ‚ÀA»Ãh lœÙäÇoyecD„Ò`ÒNñ 5®úc r®ô[ ‚W¬³ÊX H¯L§UE«è’ÿ^Bÿû¨¯¢œGìr„|ÃáŽÏ﨩?æþJ®Æ*ø¤mˆÛšáúãÅ!m†Ðí =r÷ ÜÌÜ”äBKÞÚìÓºX·¸Ïã—¢_hYñ2ZR°„,¢%EKJúúºôôÓį mË}DyМ 3nÆÃäùF¹u’Þ¥Q¿ 5ŽíjÄ&(2]¥ßrPÚ«r4–•€lÖøõÀ¯ ¿¤kÞ¹š¦|½([n |+tûg·C{à`ÞF·R=%€¶±•(P{´Ý“Žét jS# ]¾m ~¬|lŸ»½Øq4Nª\ÁÏûü óéËõ_ÒÜõsiaÁBªä? —²m„G[-w'•¸Ðl1 be[¬P±2ÖááÚoºqbá]ººûí”á¶­¦fÓ(®^0 €flJÝ ýÒ05V=a9/¿@æÈR>ÿB^Ú¯sŠü48´«†ûrU[ á—Ü óãY¤ñ„±&rßmêw¡Gëaƒò‹H žæ`¤¸Ì,–ûx=0ý¼ó·VÓû«gÓã_ÇÅ[3I6ÚCµ#yŹî¤dL@ d¸Q Du KDzÔožz4’â $ L—ý¦nÄõ”¸"݆ûI i_ðz\âúùH׊tn»Å ZEæÁVÊÆî´lïÜ„ø}ßÞG#ûޤ>íúñè]¦¬Œ,ºþãë¥^-DÛáÏ;y¸=+0ÅAr}†æ¥ÓºŸ&'øS¤Ôͦ˜ÙÙ´g—=Åž¾óéôsÁÏôÞÊ÷è½UïÑ…?J”í>~ÅTô¶¡2ÐÈM¨ã•M"cVCh‰«rÅRz@×­8Ö’?â§î²Êä´XgÐ(„s¢ÕÏÛ €[^mLaêFªÍ˜¸›Úhˆ7rS|P:„.(ÐÁÅþYTzš¾B›^q ¦nÚñl:¿Eýh]f»ìaÖŽ¿–ž€·nøäºÿÐûcqÜ€qÔ2³%]=ûj¾*ˆ/ â?=O JÒÃÌn+Q:ev¢3zžAûåí“'a@Ý8Ð'·MÎL“ûO¦å…ËéíoÓô¥Óiuéêhe+&¼=D/ê–[H]è˜/NChêWébXá ^½ÿbLãÕ50Œ¨MbK@Ô¢"I¯4ÞéäÀ²Œä! £î ¿‹óbDÿ*]tHLŒ”Í ­k:u¥wóÛ~Uºôõ@á?·Ñ¢…ôÑòhDÏ1K5j‡Q¢üõÝ¿RE5Ÿ®EýÅ[x۽ȟÍÅL©™˜öÕ~ÝëljѺ™4õ‹Õ³MOQNÙéúä×O蕟^¡9ëæPU:¯bEOaD‚" } Õ.4 ç€;v¹~ä 8jîAxÅÅ¢ Wœ áf+ã¸ñÇÂùeE¾ Uc»×p¨½PmÃS‘Bc(ZÍÒõ+¾AP„,§¬š[UZ•?kDàbÍ5R%:ûwó²óµÝ6]mx7ÜŽ«UhvÐðe—Öúzà# ¡}zî#]¬rïÛg_º}ôírmðfò.zÂëHO·$m´oí+ŸFÇ›·íõÉîC}³ûRïìÞt`û©KV—FÏ>ÌÀãîNÑ}„Ø_‹~¥g?+«8½­Š€@sn@ÇfÝ·R°qƒÆ2·É I4 ›nûOËeãà†‰€o rSvýRždü4†Œr%œ†6"འm(ÑðLã%œ !¬‹ðGÍ3žÛ³éƒðn¸Mw³5¦«Vói@yWgp&`Qñ"úpŇ´_øËÞ»÷Üþ9îŸtÁÌ hSÑ&iS9ÈözÛ72X7ÚcQGî›øvk½휳3íÜzgêÓª¿ÌòX™Ñ<É»åt£ó†œG“L¦ißN£—~™*3*½>jVôm‚PHnenÉ ‰™?Ÿ¨n”Aý §åS¼Æq¡Ò¥*LýÑ ƒ¯Z8ùô¹,£E,¼¸m @l„³á_á¢Â‹]Ë/òKÄ$J—HZ[€F”/>Dƒ>øCYD~ÿ(íÛc_f{|æîÔi'zàðèü7Χ…+¤p–€øsRþJÒÆnü¤¯æÜ>í3ÛËA¾ám‡Ë…=²:5^~aÊIá@ûìötþ°óiâŽ鎹wÐ'k?‘‹¬DYÕípk a¼vÇ.×ÔçBÍ9¯¸X4AáÀ©EÄx@bÚ¤·¡‰]&Òû=L×ïx=í·w(üÂЉ‹Ë¨®u-Þëpª(¬ Š’ ªÚÌý }¬’;_ú¦ Eª3ä@­hò¨k-Vb*X]ˆØþ3?¶p+MPÊJ‹°xtAq]z×囹á 5Mø§PÃÜ4l|ª¸åC¸'˜{Ü’’%ôΊwèàžûÅoݲ5ýºáWêÖ¾›³˜_²ÿ%Ô½Mwºç›{„WX•l#àÛ8ÄUÏ=Û¼Œ<šÐeÓù˜ð}›ñÛãÀ£® âÅ4sÙLª®ôÞ<‘>–彊®Ô½Cgn*É ‰—†·ú£ÜÎ^¿†Ûe÷ý<ö¤²Iö @Óñ|·­³×öqqñüvZ¶;^œ0,²=l~01¸B8§gð*¯<²ø‘ˆU°ÂþÏómŽG¹3ô7týˆë)£(ƒ* ùs0X (åk:Ëù‘„åA[úOÚ"ú‡]Ë—žGgö8“øMê6)þQß¶P4¯s õÊì%+•ÅÜÇJ+©ºŒ¯ W¶­Î€qb+7M¾,~BƒPQMLÝš>ðõ1H'ÈÄZ¹°ó±ÝvŠ·ÓPèÔí 4l\ª¹u¬~.þYfYc·Q]{ïJoÍ}‹Ùý¼í½Ãhê’Ó…þ<ëÏTPX ç0K“}[éØw0«@ÁÍI-ÓZÊlR÷IÔ&£|èÞÆ9Ý"›.?èr:ã…3üñýIÏÈ*¦Nbbô¯mœ…1«¯c\,‚ÚÂOhâ ï±Ò°ñê7§§îXÐÏÛ”Aâ™Â&eW´‘À{u×ëB[[ZÇ놉й4õ禓R~^Z“Á=oð+¼€Ë›lƒÁuÿûÓc3³ÑQîAÝÑC‡?D=Ò{PyŸ (æ}ÛÍ|6 œWx¦e iFü±DÞÙã?½×é¡ðâlÓ!>ûî3ºüÞËéÝyïRyeyÓeœ@N{o¿7íÞiwÿÌ Î`%}«ªŠ-úVø—’°Ç™”Ô¡è:h÷­Å¤¬Õh“XÄv˜ë7a2û·éBw$ß’Áð³)Þ XV¶LN]e›VY­h¿ûÑmÏÞæî³-w¯¼^ôÐÑàÖƒ©¢€h^®Õƒ[Õ\XÜÂÅPÐ1ØvÎìL×ö»–®ÛáºðJ^‹[ʹû€ÝEøŸ|ÍÉ4pò@štÍ$ºýéÛiÖ¼Y´¾`ý–*–ŸïøAã¥_áP ô-Þj’í&Ó·dLIp«)büIÆs¦‘ü±)ˆ§è 6^{‡âÔŸ¢0u·x&g/׫V¦8õ'£]ì¥{;=7ׯ´Šwa¢á Ó¸'%¡.—šUjÁ·ò*À!ÛBi‘¯öëÖvè¹]ñÈtýÿ\󮀼ì<ºû°»éº÷®£7W¾émTñ÷Xðc«A_Ûi,Ûû\ÊÉÈIIÖ%«Ðè˲„¬–Ô3î7tÃc7Pai!½?ÿ}šýÝlycJbǶi‡î;Pï.½©gÇžb;·ë,xÀ¹¨UËV (Aü¨{n¿§¼q"+VÜ—p€Õ·Ü‡ñfKsáeüš4ŸÐÚÆ±ÚÂQ“Úhb…Ûxùr) qÅêŸÍ-Å)Ôüm¿MŸjîÔU¸¹°” a`àFÃ$ÛÄJÓÅ»~-‡â]˜h8è4®ÆIe(¶øäþ²’e4ã—tDŸ#¢ªtì~ÇÒìofÓŸïÿ3Ýrú-1ï À+\SFM¡žŸö¤G¾{Dú…¾!Y¿ËhdÇ‘Qéo ˆ‚âZ»q-­Ë_Gëó×ËÌyí¦µ»!­/\Oë6­£5ùk$|sÙfêж Ú~ Ü~ êçÁ¾Ýúnavܨãèæ'oö¾Ô‡79ØÊ»÷üFÇÆÊôùÒÏé³_>ó^õd¥NVtÌì n¼=Ò¶u[ÊÍÎ¥¼œvóñ4í¢iÔ9¯³CUãØu Á&ÛTTVÐÆÂ´fÃZ½qµ73Dz»™±ûœ9fê 6xE0ýÑà®wÐËYЃGè«&®ø]îÐùô*äA¤£J€ óÓÕne„ª Z=@¹®|}ðÃôÁ÷x³pV hqE3”¾]úRŸ®}¨O—>Ô»koÝ;vP0jkÙ~À%N°üv®âÅÌ[¯â¥EˇU] À!O{†GÄøŠÂC”Ö¸ nÆ€gr¹ΑàZ`†²">j;(q·-h7áÇ*yòl˰°É€äUûýòË·PüƒNl6x c†ÐÀ'ü&^ãÆˆâ§¢á¶¢àæSCãES¿–Í÷s°íö3Ie‡Tˆ¹ø-YE¯þô*Mè7!°V§Ž>•f/˜Mo~ñ&M¼e"=vþc"l‰ ™™‘Iò:QûÜöÔ2«%—öà¿ýù[úbñ´jã*ï`˜¼˜AJP! „úÑùŒõ…7øaŒ@—FãJÒÈPxhòôóQíÀV¿@,uA«Š€úUøn®ÚLóWͧù+æ{ƒ %„[d¶ îíºS÷ݽÃ{zR×ö]©K».Â?àk—ÓNöÚ322èÇU?zÂËîÌ3Ìþ± àßÉoøa—QÊÌe¨J€6Nª¨xTnSg? ~ñð‚™Æç#Î$`+ %ß3²¥ ã#è=Oøës@ùé#,‡†¹PI\¼ú58o»5܆pÃh<…A8MKi\¿Æ±!Ü)jRV€`eœk ¶âÕ__h o7xa Õp…6NÓÒ0ºáAq•&e!|ÈKÙ˜íáGõ=*p´7ýî&úüêÏi麥tÜߣ‡Ï~˜õ„ &5øvA¿ýÄ6â0?ïUëWÑÜÅsé“ï>¡9‹æÐ·Ë¿åÉ)KF¬Ò³S+~Ul” _4,Œø&]à\¼³ÓQ:àØøJ®à‚ÞRl¼Ì¸Í,\ñÜáE‰€Â€mŒ¥…KiiþR¾÷Ùàn _ãž@Èfó,›û€Zøe+³o,㸚‡¥lø8cÏÿb@cç‡põÃmÍö%ŽÆS:†Ú²€€–ž•-n'wy˜£„¦èX‹¬¶pÄ‹ ±ÚÍM3‚Ή§a Ýt×° h‡»ù¦’?e~šÑŒµÝÀÁï pnâiK!@3ÀË#0Ž"5®BÆ£\FýT¯^#øHE¤>ä*aEÆ\D«ËVÑ+K^¦‰;X·Ž¹é¦É7Ò™÷Ië ×Ñ)ÿw2ýëôûhßþûÒÛÈÅå¸Þæf‡%ËݵCW:l¯ÃÄ"ÍÂ’BúhÑGôÁÂÙôÞÂ÷è—õ¿xËʺÜͯ—cÅ€YE ÂÍ °FŒ„£Kƒ­ (ß-ø€8H@ã7È¥W™gI„¢­°Ä‘y–êþª€}„AA=Â…Öñsú¼„3‰ hY©žq¨‹œü—Y6 }†b±ô ¡ ~?HN·x/}8E&γÞX‡çôŸA R‚|tƒñà?²5í•ΊˆlYIy#k:ð†Æã@<ž Ña”F¡‡e|-á×¥Óø.ÐM‹ý@‰uÜ@úx¸ƒüŠ7P"اž;enߨn á÷† Ä ÷°ñe0‰C/M;®Mg»‘´ú]¨Ù*Þ¦Õ°­šFÂÛT„Á•—Xá{Žê{tÌÃ{c‡Jö™H/~þ"UÓižF·Ÿ|;>ôð¸,i׺-øe=ÿÁó4lûatÐàƒäõ°¸‘ˆÃЇ 9D,’Z¾q9½³ðš¹h&}ºüSo‰Õ#`|A…’GvŠü2Öö‹€ õ~<·H0áÆøqØï®Dì©Á1뉒ÀiAQ@¸Mcü~º"¼¹wCA`#õæÙ:–ÙqøOVr‹¾aT_gò¢<"N 8ßoáàô (XåYUœ…ü€Ÿà¡®âp[Ïòe`ÆÛQý8¡#&jãWmášp"t.íwÝêT‹¼Ô jyR¦¬ #}ä»ÿøf·? ™Vóqn+ÊhbZÙiA[ˆ;Aâõó´ãºQ6æBUoÓJÄ­éGÛmÁëÚ²µôâ’éÄOŒYË«N¸J^a[[²–ʪËè§/¤Uù«èFþOÌ8Àa³óΦÓo?Îùû9´çÎ{ÒèÝG‹Ð{@ܸÉìÙ®'²÷)bË*Ëháš…4kÉ,záÛhcùF„¶ ÑY¿B_Wjá„€rý(0pj‚Â5ÌôGd(ÞòÌè n¦Sáîã Ìï­xxôeU 4èÅmfY(¿®Èþ¿.û³ÐU¥F )¯(8Æí+ZY­ ‡K]Œ…·ÝvZ6Þ‹d~•wŒ7DÄßÖ<6¯ºû¾¦e Ocûáf+c«º¹-ðèËÆùsüÈRéíìSÑÒ @*2<,³ÃR,üõÔõ´¦ÑøíÇSË ï’'åµÎ£«&^EçN=W®Æ…P7L¿–®_J=ú¯1/ B:8Ä÷ìÕÏÒU]EÎx”>šÿ]ÿøõ´]×í|e`¿Ýö“KbÜ|“éÇë‰øžìy#Σ¢ò"Z´~½³ôš·f}Ÿÿ=•ó_ày[à3ÿìÙ¼ÊA)«£¶ÄÀá/ƒ$»Õê 'xk&¯¸án”I +šžG~¨·¿îµû§îuÅ(4^€ˆºrYÆ®›…öR&ßÇ'¾™|£òB`@™$NøÓü9ÔÖÍ¿ÔI-aÊ*z  ÜÈ…Æd‹CWxè1ˆÙaŠ·ä€Ó‡^Ü’Lüž5h8M­QM ÛkX¬‰Ê©Ôxl·¦½Õ@T“-Uá{ëkÊÖÐ ?¾@'ïtrÌ*±ûôâœéíïÞö–ŒyivÚÇÓd™ý'ÿƒZgy·¹%Ð"£ÝtÆMr Þ_þ a6¾lÃ2š:k*M›5M„ÿˆ]FÐØacé !Ñv· J&©¸œ94¬ë0±HémXD_®û’¾X÷}±þ YA˜ "è¾Ì7Å!\ŒLuî7*КäTÀÃ+«F˜« †6q5\žCç§ÉQe•J ¶Cxï×DËQ”ƒmmϜɹîéÛÆõ[a¼¬yD-Êm܇'~;*Be™ñGÑi8 Óøá^¼š¦“–ıÂÔè»1êÂLØh˜ !sÔ/D)ü“†ŠÔ×ð ƒÇ uP$ð7¦lÙlqA7.]Ç-¹ló^z饧Ò®»î Ð`3éµI2PÈÒ!ö ±OˆÁPÝð‹†¸ÍlÃp0ºp€¢µî­gÚyPÉ@·vLíd6´š#0nƒ9×LàzËCÅËðAŸ¼ŠKòìiÙýv}.Q·Ð¤LÛ•TÛ[Û߇Jìô‹ZÃ5 æë@ÍSŸg¡cûpª„áÀ+¶Ì9ynvµÞˆÁõЊ›qÆ »õv/X°@âŽ?~;6±-`[ȶˆm ÛÍlKÙâ³™l+¹^ZSöÖÏl™‘¬~eˆ%‰ÁØî"Ëê·»Ç/Ûm‘øN¥ó 8ì8‰¸‘¤Ò¹P³S¼M«a[DӘßúŠõôÌ÷ÏÐowùm̪voß.8ôºñµ½¸Ü›!ü¾ZóßñôàäiÇ®;ÆŒ€á; §×§¼NgÞ{&Íýy®(ªJyXX-Þ°˜¾ç{ºoæ}”Û2—Üí@=x42J>L7ƒ$ölÃÄa{dŸ#%Õ ¥è«u_Ñܵse…`Aþ¯OAÙµ¶ ’¢Ä¾PÿM»iUñ|Á`0·†3”gã–Áùáš>C)/C]Ùç@Ã5“¦$ì1-^’I§i)Ô|ÕÏ­á.ÔtR¦ì ÀI¯$ë²ohÏúm·µ ƒ f<0г~ ”¬¬éµ 6: Y-¯¨ ·ÓÁOqÐJ[ñnšV¶©íÔº2”º²ŽkV«Ëx „WªòhúQÓ©Ufì/¾áv¾±7¥Ÿ ~’‹cäÆ6V |r3réžî¡}vاV>•U”ÑÕÏ^MOÍyJî¤×Ãx23@ùt& giUi4¸÷`=d´¬ ì;Ð_Eª5ÃF ((+ OWJ¯þ˜>Yó --Yê•§1‚D˯m@4ñgû6}mÏ£Mº·<is¥Q¨¥6þ¨¾¡t´ÇHWcAŒ-†4ØÊ³ X•ŒšýëóîB¬”WÓg¾¡%o Wľ­/rDÇÞšªg=ÀRG~ðü‡‘y@ãA}ÙzzêÛ§è÷ƒ~“XŽ¿fÂ5ôÛKÕ-X(ãÂ(¬èVÒïŸú=ÝxÄ4~Øø˜i _»éd>À_É»î?×QEz…ŸÂ1 Éà ?üXüzõ×ôÕë_Ñí¯ÞNÛt¦1ƒÇÈ+†xÍ0'»i?=œ›•K÷:X,ʼ¢h}²êQ欙#‚ò+3kl@° €ÃË©¨Á8é ûeF9r .Hé-ÌÞEˆX5–=û]¼E×™ŒxvêVhg®8‚FqJïúŸ2PµnHx¸¡qc)Ø‚-8ØÆ‚üÑo¥w>‘pH.–¹ëH:xÀÁ4ëÇYr Pã"~eF%]:ýRZ²n ]0ú‚Zgè'8™t@ç>w.­)]ãHã•#¾žF²·•/•ôòtZ_¹žžþôizêã§øPL&í½ãÞ²U0fع7?Vù ß#§ÛïX±8¸ô݆ïèÃUÒ»+ß%»À¬ŠùÊÛ8^;(t‡¨+ÇêL‡1¥㦩~ºnøãýÕ’e³NY@8‹F·-¶ßvk˜h¦x‰ d=M]¢Æ£VÏ¢m±hZ†®°W¿´Pü g+JÚ‰eMôä‚'éô!§Ç­Æ¥G^J³n›EU-ø­¼GŽ•ÞÂñÔªŒ*ºwνôÚè¶ãn£ì±"“á}‡Ó‹g¾Hg?w6}³öÙ2ÂV“ I¹Ð¬TUð¶Ül}¥€W>úé#úð‡éºç®£>úÐÁƒ–­‚}vÙÇÿ}ÜJ%17 îÚaW±Øå´nó:zoù{ôþ¯ïÓÇk?–¯®à,Ë©¨†ä€>ûn â]¨t‰â•ά0à“i5ï†){à„×NðNõãºÐLó–~±ïo ìãZç P0ÈÉÌ¢ñ0¹ÃজB„%`DxYtÐÕØngojX4Q‡8¶[Óh¶P«ÎPÊm/ñgöÛ¤^†»¼jKîØgãómªÚÐŒñ3¨M^*‰m.žv1ýû›SF.M.‡-UNÚ–Ó«*ãDù\Á.y»Ðý§ÜO]Ûv Á¹€«f\E/.|1B©A©«º%€²²ÀVŒ’ §†±‚Ð:³5í·ó~4fÈ:xÈÁ„¯çmISZYJŸ®ú”Þ]ñ.½·ê=ZUê}ÔHž(xðì„ÊÀ–l¦ÔÊ›Ÿ¹ ã•®P‰ß§sðþX¡tŠ°Ó±Ýˆ1ˆŒ=&iZ{ÿ¾RÏϧ¸ñ\«Å³ · Ù³øožù¦—xÃ3õb 7‚…n"¹L˜Ëï’Šá‰7¿x~7 é+.´i\7üÍР*lù1ñª‡¥}<`ø7Pܱ„¾S%‘5PÌX†ç—çÓ §3‡žåPEz/<âBzå«W¨ª´’ªy :‹WðŠ(”>(‰œÞ·ßÒ±÷K÷t êÿCB8pó‘7ÓÀîéæÙ7ñu÷|ÇÒ²9–Ê¥;yå•! ÒY `.È«BÆ <+ ž‚PM›+6ÓÌ…oÑ[óߢêiÕ´[¯Ýä5ÃC†BÃv÷"£È'LJ —öﱿؿÐ_hþºoèÍ¥oÑ—Ϥ囗{uå:³àÕÊ€TÞäŸèc“œâ†©¤4x@HÈ$J§‰%B¯4‰@Ð(æ±õÁÔÝà¶YˆvÁcq7¸Ò ,¯q,˜è8†ll£2Mqv¸íöà RÃEp‚À ³Pp6/cU@´ê€ý|ÔÇ׿•>‘Z 7¾ g¾›J'ïrм†+z¯Ž½èÄ=N¤Ç?œÏ°°Æò¸‚{yZïâCh³][¼–&M›D·u+6¨æk~±ÒýÍðßPÿÎýé‚×/ð®ìE2œÊãýrYÍŒ!Mf ¬€°àO‡ð‡5ÛéfuÀS<¥àÛußÒ‚™ èîwS»Víè Ñ¡ü̓Ã÷:¼Éï€`ØqØ‹†^D Ö- ·–±²ÂVÞ*r¡œ¡âhŸpeÝ 46b<ëþX©á 5®ñût^ÇGšðúxir˜ÐÚi¨NãV:É‚qРS4¹à ƒr Sg!¾ð¬-MnDÄI˜>Fznüx~7 I*ΆêÖ,m¿íÖð-­AÊe/ñÛ (’F¨c‰UªBÐðì³°¢¦ÎŸJÚýOq:ë³èÉŸ¤Ê²JJ+ãÖf% #‹À¬·ƒä{îì.+.£s_:—Î[}{ð¹‘B, ‡½zïE/LzÎyõYE€ðóV8œ5`#çXkÁŠ”šUö‹2à)ºM€ƒƒ¢è¦É¯È§—¿x™^úü%êóï>4ãÚÔ¶uÛ€5 j׎|n€íùCΧ…Ò¿¼AÓ—N§•›Wz+Pt5n0FåTT·m$:–%J§ÜL„^i ±éÔ¯ùŠ;BóÐÒ¤Äðš:p@;E¢l¤ãFÀ«€“™- -h*ôDðC&ãá0 „ëã‹§üÒü¸üÄ*Àø¡ãå6ÁªRs8˜œ áÏËâ;ómøŒŸ¸ëã»èügΧÍå¸h+¾éÞ¶;=uâS4¡ßª,ám>Ÿ ¾¾2€3)¼ý€óò=ûÖìÆy“òÌÌãw`Û±mŸI-Ú·(~ k›)3îÓï;Ê+pù×–7Ú ó†œG3ŽœAŒ|„&ôœ@¹Õ¹r¾BA2/¤OhÛƒíj·|ñÄ9àp ÉWœüëí•}e 0˜…ª[ý˜}°Åò¤Ü)nðàòMxöÃíC/þ83—ˆ8&²+èlÛ­y)½†ª[‹äû9’íÖ4š*{À+Y“Âx³[à°·þ³Ñzy¾$ýj¸Mð^ÿ£_?Jçíq^ÜÄÏw=ÿùó"¤½mŽÌ=]–í1[ÍBwáƒ:ðßk?¾F?ÝÿÝwÊ}Ô½]üy-3[Ò co !]‡Ð”ÙSò柚%rP”^>1pqnàÒlU €K¯ðV€S… +¯ø˜þüäŸéŽÉwÔºJ—)I Ä,x—áb/¯¼\Þ&xuÉ«ôþª÷åFr—ù wù Oìüã<_6YèNaèsëTÁ#4\¡Ò©ß@ìsðJŽgÆOW<‚ªùÑñɯ8ž<—ˆÏápësäVZŸFÇÚ\RÒ±š‘Ї‚;¹< , TX‰p‚Ÿ­~<< ÃÑX†{©S³ °qóƸ9íÐm:`‡ø0 Ÿü‡5wwË`´XP§g³ `ÍÎ, £ï;š>[òYÜ´5ð„!'О .i]¨ª˜óàïH>d”xºpþÀ¬ @I@¾­Ìê@ŽY‰Àêl[ÏÊJV`yEàÕůÒ-3nѬ›ÄW ÇôCwx'Í:f]5ô*Öv˜Çw|Ô3è3:ƒ?Ê£fU›°0!¶-¤´ ‚'òãÿ%~vËu³ð¯aÛ:40{U% 3Þ—†@“×çE@iøjMáecòÄ—û`Ò^T]Dõp­Oéïú'„øÕ?Îx Š„f 8Àçìeú ´Nžv²œ!¨5&ÀG‡^œô"íÙaOª(ª ÊâJªÜÌ–ÏÈL_ò3ÊU du‚·$Ò²¹¬Œˆ…R`o¥àþÏï§f?H±¶M^Ë<:¾ÿñ4õ©²Mð§¢ÞY½©’ßʈèGè[¸òYû`cö¡0í¿èø³ú‚ -– €ß·‰ƒ‡ ~…J'ˆþIi !|ׯmH[E\ôiÅc–‹½\²Û_&3P“×{ª¬ðìýÉõ%ëã÷ó÷Îëí œ(5õ2BYW|%ÀÌÆ«[WÓo\AW¾t¥,ïÇÍ„;´î@L|„~¿ë喙˜•'V8ä[P6 ?í4°%åßU-ƒ Õ(\Xÿì+›ý7zôãGíäš­-:sð™ôŸ£þCOŽ~’&ôš@ÙÙç¤è‡j›m­Â‚…غ8² çò«94ÆöoónÕ‚Yb&&³2Çê,VfjFûÅïFÅó Z^5ƒÀ{êøüom«8çqÒ¾'Õlèr4”K À=þҼμy9þ‰¯Ÿ S:…Ö®«µjétÙA—чÜAÙåÙ²à@TeÊæVLDá:ɶBÐÒÛ*ÈhÍÛ°( ¼áýèéÏŸ®µL͉`pçÁtíˆkéÝ ïÒ5î¡[ï, VÂ-‚æÔRaY¶5¤¬`äº7k@«¹³õ‡°†7<Ó—WÓ°äª3|³G‹¯Lë>?hÄ‚¶¹ðP…& Ì'=)ïósébšã÷=žÒÊÓ<%{ôæ­Üà¥Ëy"ˆ9=WÈl“IŸ­þŒŽ¹÷Z°ÜûVwÌŒLÀ¸ãè¹ãŸ£>Y}¨ªˆóÃöòä·$O¬¤€—ÊS'AYàÃsþ V  °2àŸàÕ+ÿ{%=6ç1'vó÷¶nÑšŽë=wÄs4uÔTÓe ¥•zí£oTèê“Ï'åUséƒa9’;h·M&_‘f"éÕFŒ¦ïùRö7eÌâa¶ùÙ|"ÀŒ³}¾ÉΟícOßžñ󾿿' úæö‡3¬Tg0äýûÍi›éÁ/ŒûàuïÐöÛi?O0gä,ƒÖ•ë(/ M\Äo¤µ2ûñX‚ÏM§•å+鏇ޣWæ½7/ ܱӎr_À製sæL€œ?`@ö¾Á[ðØå3×gä¼V øé¬ÎôÊ&çÌY´œ4ºökéoÿC³M98¼ÛpºcÔ4ãètbß©Ey‹švÒ~‰s±xå…„¿!„ö }¦|ѸÏöÛn„«qiŸj°ÉàÓ°ž0ÕÝäåE_eë uÌø1Ûç%ib@f£ö,«É ZÇ ± €Y2/—?óý3´¦xMÜ&Ž˜èíÉC0+þ,õfãϼÍ|šÞ€¥w^v/mYJç¿t>]÷ &¸Š—j1mZ¶¡»¾›.ÞãbJ+æ®Y %ÀlAø+h§ uÕ3¼ çÌÖ ÞýéÝtÙK—Qe–lRÓôÈíAWޏ’Þšð¶ÓiÔ²¢¥§à …鯺e#ão,~¥fõÃR§8R]ž5¹´öæ@´0U àS7C~–ßsè"Ò¢O畤æ×ŠƒrÀjþ˜…Kžøµè|·†…%‚Ãò>fûØÛ癄ÌzuÆo ¿¿4SåÏ]HßL÷qÜ.5nø8>tŸé„ ¾˜Ù¸?#gÈI}¼E§óÍjâa5à‘yÐ)$v.‚ûÌ}Τ‡Žzˆr+s©¢˜ßàÕ= ¯ù ïãµVð‡ºã ^©P‡Ÿ_ø<õÔY ]d—Q[8°c«ŽtÑžÑ̉3éw;þŽZ”¶·ðF…ô_¬ „+©ò¤¦d9õ0Oœxm7¶îT7©«¤:ç“Y~ôCceÆ™=ö¹1ÛÔYp˜(‚.Õ fÆ88Ç‚úÙÅÏÒª¢U1k”Û*—ÜåÀšUkf)«NL¬.È+‚œ¶ì½ó­þ}¼0gÍ:òî#éË_¾tb{÷í»/½<éeÚ­Ínþ}ºß­ç1$f-í… Š('x}Qï`%àíeoÓqGË6, .D aÛg·§K÷¾”ÞšøÛûXÞëáE*^¹ñ šŸgµð-…ª5ä@“s TšœåĨ[Y=À̃£ú:Ëõ—ù·–Ò,‹‹0d% ,½Œîû⾸L=bøž"„WÙú«à+Fþ³IÅVdÙÂVOâójÀªªUtüÃÇÓ3Ÿ<7_ ì‘׃ž>éišØo¢wW_#,BͬDøù›öÔx>ä:ÃøJ”G ÀWq‘Ñ‹?ðˆSü·sNgºqäôôáOÓà6ƒ£·QBE Å[8,~sàSÒð°]3›Õ3ˆÚ‚F¡çKèWòu(]²k”F!•8o‡‰Û-¨I^â›ý{"ì¶qˆ»UÔBê+/Ù?÷ÃstÆ3¨[›n(2‚@IDATÕ=á€hÔQ´|Ãrzgñ;ôê¯ÒÒÍK%>^ÄI{9\¨Ê…¦‚ôñ„XX®‘fEz]úŸKi@÷4´÷Pâ á›ÆÝDC¿J×¾w­Ü1^Å_4{ûXÑ¥3}­Ÿ›š¶{:;àÆv|(ŸLd³±x#M~|2µÏYtÑØ‹(3=eo©~wLOš¦/šN7Ϲ™Ö–¬õVAx…m#|c§(G±øæ§:šŒ¦¯ºùé˜çi¾_ãè‹ÞO7/qBM ã2ÜÆJYl7‚°gè"ÜIþL¸ä´SÜ„+©Ò€vÇÅlk_æ×.<à‹áÞ PžVN÷λ7f ‡.y]hXßatᘠiæ3é–Q·P×Ì®þжJdÛ¼Å`Œ¾§ï¿&ˆ é}¼%ðØÜÇ”4!xâ驉OQçôÎ5÷èG…x‹&b5ÀMÑÔ[„Î*èJ€µM7þùÉ?é¸{£ŸÖü䦒~^ï #ûIožø&ÒïªÞÌ«8æõJ»Ý¤rúœ¤dMÃB‡hZ„ @Óò»î¹™M´Ñme™?A.©pÎl‘IÚt =‘¨˜Å»ë±4ý„étôvGû_”SúPlAÌ ú[x/ïä«Àåí€~ý(á|µlCz ¡WOy•öê°Wä}nÞAÂÌUp`QËenÄ¡Å/Ö}AcïK÷þ÷Þ„Þ\в5gˆ{®y%M7zföôÎTà|Îu¸Û9à]hB„ˆË”]#Ôe,ò\3kÓA“!”4°‚çË€À ¥gÏ 5 ¥Q¼Ògã%Œ…½ÒȬ½ºÌâ+Nˆ¶ÕæÝuà]´{§ÝëÌ…Ü–¹tËè[hØ×Ã躯£ÊŒJÙÀA;=(³m]XU—9_ÌJ¡H¬)YC‹Ö.¢Ô)\!üø ÓÜsiêWSé£ÕQþæüšõ0"¶·màç2ˆ›W`¤L² *+.£›þ{½4÷%ºú˜«ißþû ]ªÿìÕk/zõ„WéÖn¥'¾}Â{cƒÏDÈI^ÁvŽ(m6R½Ò©V~å½[nƒ×±ÏVzŸ^Ã5¢úºôðkCI~cÕ™@ó”ÑY—þ"¤‘â¦ÉejŠó­ñŠo:•/౯e@÷÷¾t¼d0°m‹¶ôðSÿ¶ý”ܤA“¨o^_:ëõ³¨¸¢Øû´/Ϫ…Ï®Øj€@Æ? . bËëôþÒ÷#€•VRûœö”•·\P.†÷äÏê²Åë¡ß¬ù†>Xñ}ðë4oý<ù(>©+yå#B°!u” çP”‰”Y”û.ÿ;:áþèÐþ‡Ò㯠í»l/¤©üƒÕ€«ºšFöI—ü÷Ê/aå JÎT`R€-ÓfÒŽÊŸT®tXöfÇT—gfXiv|M¸@ÞܹF"ªß…HÐÅ5¿j• åý}ýÞ}†…_o¯mø'Úù”ݧ4XøkGÑ{=vôcÔ¶¢-Uy_õóß`Ìïãã©Á4( -‰f¯ž­ÉìÞ¾;ýkÆ¿h隥øxmxûãÐ?Òãã§Oÿ”îqÓëÊã?ykw8À¢?àx«/ˆ`ÊdßaÞ†U¾Ã½ùã›tÐMÑS/ Å¿.ŽWœ” Õo½râ+´kήޙ \ùlîzðù„çÅâUøü„¨/ìi¤ºI]@yoCu£UàŽek /Ùxœà73|}}OÞÛ×»ãÍ;üþûûÉÎ?…Ó×cé>-™4ƒÏûN=v*å”çïÍãà¥á™l ðÓƒÙ÷ܵsis¿°n™“<™Ž¾öhzçËw,l|gYE™l€ 3ÜCûJ7ï{3Íž8›ž8ø :mÇÓ¨o˾ޗ qpýV_eDÙP&Üa ßàsþY ¨Î©¦ç¿zžºþ :ùΓéµÏ^£òJþD ›m{г'>KÇmœ(oró"+ß`À3—Âý~›)»öǦj+ä§yÙnÅ)tÃàOaÃs†Ô6®†}P—Ì¥íâ\?òWœ@t&6XöÕ¥}]æÇÌQü™×x·y€e÷ v» Qø0°û@švü4:åéS¨¸Š·Ì+vXVÆŒí'KËÈê3/5—V–Òœ_çÐÈ^#ý2á­ƒI£&щ7žH—Ÿp9?á|ïU5Ÿ"Ú‘•™E-2ZÐëó_§ömÚÓ>}ö¢Œ´ Þ•· Ø^2üúqã4ý§éôú/¯Óâ‚Åþ_.ÄÂ“Í ‚ãr¦gðpؾ`[ÅòÝŸÞ¥YßÍ¢ÙèØáÇÒa»Fûì¼á놩f²2²èæq7SŸ¼>tÛ'·QZ%·¯ÜH»¡ípXRÏSàù ·¶hëx˜h!’E念þxav¸íO´üÍ•CXêÕÊ…¨©ÒÚnÅ56Äìò&Ìøå |˜Áél8Cã—³±Ë”‚éïÕq/êÓ-Ø(fHÏ!4õø©”UšU3£4¯ÉÖJ€€Ÿ¢V~U–³8›:äu ëŸ¸žþç–ÿ¡¢ÍEQ4.Bê°Ý£ââb:êî£èᦂ҂²~íúѹCϥ׎~^=ìU:kÀYÞQF³j$¯‰r,yU}{A?+œ™›Im½ol¨Þ@}ðM¸}íú§]éœ{Ï¡gÞ}†~YýKD¾©àùãˆ?Ò­ßJĬ®*f~ð+ƒò|áC»áùBŸW˜‚ý?L6VÛ¡£»iÛ8¸a@“â&åWR‚ÿ¦£ˆàç½H_ €"€½I†b¶‚ÕèíÁ<:°ÛžÍðÞÃ鮣þ}ËüJžègp³Uñ¤ß»¼‡[Mf×:Þýëì¨2µÉnCç{>]ùÈ•ôŸOÿC‹þwM»tíØcÇ(Zqð.Sߎ}é÷þžnzå&¿Çx:uÄ©4¨Ç Òì…»_H_¯ùš^üáEzõ§WiSù&oöoVðUÁôtïÂ#̆«[pùqhŽmziºœ1Ì/˧æ¾@ÏÏy^”‰^í{Ñð†ÓྃiÐöƒh—Þ»P×ö]#ÊÐÜ<O ’òºâí+dF›‰Á¬üÀJ@hB„à2¤z~ð$a½PùHáès+¶9lÛ°Íe›÷ÒK/=Å ¨ÛëRˆdŽ}åXÿµYÖäRÈ2–úp*šŸy™ýÀ0œVˆ0]D Øú~d\ ƒß5Q82„ù‚Ÿß/·—ø5ž¯H4/¢Ý.Jçæ»Mú™=OŽ|’†wÞ$ÕŸöñ4úë[•ËðMÜÁ/‚“û™ô1îW²Ï3Ì÷Ç¿OÝr"o#Ü\¶™ö¼hOZ¹v¥”·mN[úç9ÿ¤q»K¨üE¥EtÞ£çÑô¯§ËÛ Ãú £É#&Óø!ã);3ø-ƒ²Ê2šùóLùZâG«>¢ª4LwA÷b¯}æDîÙÇ5É\q는®&˜wìõ¢¤ÖY­©_—~Ô»soêѱumוºuèFíÚ´“­ @¼‘Û:—232)/'Oso¸zÃjúvÙ·´`Ùúzù×ôͪohIá>HÁ<_Ú$÷6h»á-Œ xÆã<çRÐm)Qo‹®±ÁÛã›)½B©þúÆãtüñ•Ó|­Õ Ãó€Ið¸“2¬Æšû@Ä­Ï ÎÛèóÀGgf=KKÚ ¸páB‰?~üøIìØÄË~…l±lX‡ŒJÙâÀ>IZÉåäB6Ì¤î ª®Õ·¡ëV:6Œo±ck>(:’Yv”ÆavgôA×á\šmÑÏ|éÚªéf §îs*Í_1Ÿžœÿ¤Ïm™Qr9d&­Ï +•ï/ŸŽï¼OáÅ.¦KºDNaE!ýöîßÒG^@—{™÷Ê^DŒHONËzðŒéÎéwÒ­Óo¥¹ßÍ¥y?ΓO¿çñ„òíÐi‡ˆHØ?¼ßábW® /ú7=¿øyZV´Ìz(»(¾, ¥YÜWYà§•±BcoK©ˆÁíæÊÍ4Õ|š¿r¾×ŸÑW1@‚p«E©àfƒk‰sZåP¯N½è¤Q'ÑŽøáÌC]ÌúüõôÚG¯Ñ+~ åk–ËÅâå‹i}ÉzOÙÇjF–§¤áK‰8÷€•µ2àúâËŠç%êRˆ61˜v"V¼B%P¿Âúâi¸éØx ·ilœºGâl¨a) SwàeþR«/:ë—5{3|ø›j†¡-ìE`œÌü¬CH½H‰âü6o˜eóŽ™G9™X`jSZ^JGÞ{$}·é;’×êp f”ød°Î&Y'?¬Çar)‘[*œîßç’}héú¥5ý•»çèÝFÓ=¿¿Gî pãùÿûÕéì‡Ïö–÷1“5«]ûõßNÝûT· ú˜gÜANgý2‹¦ÎŸêWÀìý}³#àõÌø!øÕš™Ða†¡oÜÀVP&kÜÈo·Þ»ÑC†{"f/œMg<~íyóžô··þF+6­ˆJ÷ Œî3š¦>fL˜A'ït2µJk%Ï"¶¿D(bÍåÒoÈý8(˜Ç¶½±í2(³]¦Xà3óø0!ÂaÍ¡B½wwÈ+ˆ|5±(N˜•C ³ÿ»µßÑØëÆÒ>ûOTY]į<@'\u­/43}(?䬀‰"Æ‚PÜÀꂤ‚ÞM4ô‡H’!ËD IBYê“DÓŽ¤õ)a¬8¶@U· 5žsÝ qq‰ú¡5+BÂ@wg N÷•@—hº!]­¼*(<fllÓ¿[:g¿s¼ûøt9Þ5ǧ…1;ÖÅÆ²ôõÚ¯‹rÊÈS¨[;s>€Ÿ:¸K‹–Êiÿ>}!0ž‹Ä-~Óÿw:9øHécÚW寢;gÞIûümúÝÔßѬE³’ÚïDS˜BNú.~9õÊî%3›¾’"KéúÝ3‹a!o”_ø+ß¶,èÂßÇ%þ’%ô‡‡ÿ@×¼ñå2»Öen9l†Ù&ú›á‡Ó³‡=X6¼0ä’!´±r£·?ÍËÖRèØ. ü½{îM÷O¾Ÿ:·í˜†‹œñÕ :÷©s©¨ªÈ›![KÞ¾bÊÝ1+<œ~·ïïh¯¾{¹Éøþy¿Î£}ù/š¹t¦/0!|÷êº]6ü2Úi¨O›¨ŠÁ?}@ïüøÍX4ƒÖ­ñ¢BaÆÎà ÜcÀ«*þ§~±†-ðÏ,óX¾Yò—-ìùc P%@ŸwŒ 8 ã‡‹«Ê#¤šÆá@Í™¾ÁÛcž(½B¥~§c«ƒWr?- Bãb¼Æ? úÆm†þxÎýMÂuû´p›ó1â6Û¼p'ë À¢E‹¤HMý€Š@É<•~Ðpòh¬” l‡I‹3­ïwñ6 Ü Øú÷ñcßÕÜÉŽe~(°J‘‡›Vèlƒzð¼þz}ð2{SôßC‡JC» •³•Å•þ§„e€àú|±æ *(+, Þ8mÔi5çD˜^„/gòë'4öαôù’ÏÓp‘ã£ÿœ÷êӾᄻˆ…àCºP0Xè•U—Ñ‹_¾HÇüóuû(zô£G©`st9‡uF÷z½9ñM¹Z7£2ƒþ4ðOôÄØ'ê%üQ¨œ¬Û,Ý8îFúôÜOéÉIOÒqƒ£ìVÙÞ~=çµòê/÷ÌÒ¾,ã·6a8?`¾kå˵im8>Ó¤åxé ==ô§¯ Ë —'|F±°Ïa*òPDêoÌ·Ã$BM¯‰·Xtð6)«4:ÏM«` 33+Ñ`kéÎÏ$e€•šÙ+g')µú%ƒ­9À·ÌáJ]¹iý‚gÕôñÊc&|ÚèÓ¨ezËš³L)+X8Іýl~o}uåjšðàšöÁ´˜éغ ×Ï{Föé¡ù©ÆŒXÙÃr²7ã¿[ó]þâå4ìúatÉ —ÈkŽvzpïÐ~ºeÔ-4oò<¹dH¾0èÕÃkè{ýãˆЧgJ—t¹¬vˆ²‚·*T0_öôõ0!C]y¼9_ «0PðvVc Lñù…¨3˜ù‡³þz´Zekå@¨¸-[ÁïÆ ýMÂ%ùKèçüŸ›$¯ L|õÈéá \5k.Ѳ…ð½åïE\ÇÜŽ4iŸIÞ*J샳m”Ìt+³+é§ÿ/]ôôEä$’õÓ®u;zü÷Óéûœî-iBÖaûäæ„|„pd|qe1=>çqsÇ:òî#é¹ÏŸ£Ò Ü5RcÚü?{×`E‘´kwÉaÉ9 H8PDL(" &ô@Å„ î7žéôÌs> §‡ˆ'*P ‚• 'HÎ’$gv—Ý¿¾š®Ù~³/î›}ìÃéÝ~««kzºª«{ºËá,¯’1Õ+T§‘Ǥo†CwváþºÁÏeþºÉP7‚ñC@ÓÇ2Š~ Z[õÏŒ?DíÏÉ P2Ï4€š^Ho@™5ºÞ9ÂŒ5>\ØMÓòPõC¥«wy`–kEYݯë?H“õ"S/à{ëpaþAÔj)o/ž«¹q°Í2øÖþâ/vÔÿ¬Ø¿——xýkÙè#_­Ž,çgŒ ŒÜ §ŒYF’þ‰·Þ gU6ì[¿¼E}žíCë¶­‹Ù\¶s÷ÙwÓc½c­wYPÊÙçÂÌPáŠ`Ôã¸ÊX™åÌÕ3éšq×Ð÷Awt7-ݸ4f}~e¨X¶" =f(M1®=ñZ*[®láÒ/ˆjŸUüB³$éæ>YòÀ†EXeîLK´¿È_ð^†Œ‰)“¤?º4l2xÛ0"Ââ·_û=úVº›” .Q“í~Q^;”YëǦ#Ù”dTºº9x¦ôP`ü’ñ²óü@aÔë˜^…ëÿzt®é3ÐNDÓP4¯×œpÖ¿{I "X2ó‚&Àã[ÖÌÞ4›Î|ò̸÷ è4€ÞòÕ)WÇÙÐÄD ö`¶ U¹®³ë,šÞP·mï6zaú Ôå‘.´lÓ²”’{nî~3}1ü :¦É1ΦFà Ü ÅÀg‰˜ñ›Y¾´ Z{SŸ )Å<¨ìJRÇÏ|)Ä/rvø%ƒúáÂØáHq<™æŽÝ¸±ÓÓ ä²ó‚ÒŒZ·LoA¸(ÝKŠ&üèÖî^K-‰}ˆ ºCI˜–õ[R›ºmœÛæt/9v­³óÕª¯¢V{Å©W8ýM—ÐQ–¨î¡ 7kÚ6äo >ÿìCc¿ëdŠñ{T“£è£Ë>¢vÕÛ¹ûV¶Ù ·Ú€h }à<˜M{?ŒQ¥oÉ8ÚxüÅãé–n·P™ èò4„#ìꇣ\5èg0pР$ú@¤þ…ø46i+@ý¢ ¿úÕ 'iFó¢êÇ®~>QM7üIª°·”Q;ݹç>ûÓ³aºIÕûxJûSœe"Vÿër‘ô#îc±–N9ü:¤æ!…åÑyù@fº“ËPC`! ¯B]7á:ºuü­qi?UoDï]òÖô4ùrEú74Yxë›îT¥ŽeÔʼnã4| LVf]sâ5ôÖÀ·¨f¹š"Ä}ðVâþ øDôqô'¯k÷1I´~4¿•–Þ´¦¶‘ eÄÆ«@ÕŸ0 KK=³aѶE4nÞ¸†V§ÜoØeÙ›úŒÆè›5ßDeÒhÃ= W?3•>lÔÞ²3^壿ðß®ûVÎ ˆç|Âwûi·Ó¨ÓGÉ}ÂHUXa UOç laà׿FÅ?U‰8ãà½ÁïQËŠ-ÃÞÅ _R Ÿâ]/mý5À§ô?tdïsŠ'yÒܤ­ÀCnÈžƒÆˆªNüC]¨3~Ì̺¾h°ñù“~àž Æµ9w3Ý6å¶‚j|ZŸž†jÍLP¬}Õ*W£Þz»Zý’@û¨4 íô®Û³MÀšœ5Ôû…ÞôÑœøöB 8r0ŽªóŸ;›Æ»ÁF5î1»¼§–S¿j}{ÁXª—Y/T4¥åx¤!ÒVˆHkŒgá¿næ3ä LúR@–ŒðÁÒèý_ßOycªWaF !Lˆ±ØÈ‡>Æ&Ö>ärò„ù-‚ª·‘#»Ü±λ‹Ÿ÷àB+Æ]A~òh\Âì±ÍŽ¥/ù˜­t¨s˜‘Ö‰÷Æ>_ó9mÞ»Ù‰/¿ ª5 ×ú¿Fåö•!À{S°P R€BZQ ½ŒYÊÈUýÇ®Ìø13Ói˜aµLà¦/-ø1Š1;¡ ¸åË[hþ†ùš’wÿ~îP¦_ɬ£aB?ÃÍ€[ön‰ŠKç¶©E­…‡ á«£Mpû+CphlAÀˆ3ê«Q4ü_ÃioîÞ¨õ!±i¦ôÁ%P×z]åvÂ=\'êÅû‚öÀ0m÷ì£æ¼à„KÉïá§¿vý+åïä “»øÜûVFÆ]Þ}¼Û:ïyú¾çÉ<;»¿&Ç. ˜¶á§±?m®„ìîŽ`£ê×C|d ¶ÕýH7áž—¦núP@>Ãá/<;ÞÅ—¾)mÚµ)Üã-‘¸õ[Ö;KLè[Ш5} WØN[=-jÝ`샺rµÞ{&¦ö[~[å<{ë`9óÞôÁ¢èœgωëРªªÒëƒ^§þ­û“{§¾f0‡`¡@ðê¼Wiå¶•QÛêÄa' £#ëéàÍ.ºé—<Ö»ž>½9À4ÕÐ~+}Þú5]Ýpù4-]Ý” °ñ‚&iusÆ)eö˜½`ãÎd0 7ÀÓRI.pÓ—xŽºQŽgÆ«w¯¦þoö§­»·"¥ÄͼåóÚi?ÃìYýèWlâY8¿Ëùr2 ÌÂís°¬`Ãc˜d½àp›õplÜÃ=?oú™z>Ù“–nX*õGû)›U–;÷1úkggF¿›gÕØi¯ûX ÉÙŸC7}y“ ŽÑ`¥2 ›ïèy‡h/òw1óÞØD za ÀrèÚÁ ìÁK~¼bŠûŒQ8ZYoºTVX&Y>¦ålªÝ” ~6P^t ºP÷›ÙWÈÃô³²Vé¢Ôÿl\Õ¸91nÁötÁ˜ R¢ øä»O¼ÄÒï$TøÜ¢Ý  9ÕnD[uv/˜¯Z³è×€cÚ¬B{Þ½9 _vïó’Àºýë¨ç3=£~†èt~ÿrò_詳Ÿ¢¬}Y¢R—ëxa œåÛ5ßÒãßÏŽò1;’Ù??§ôà2™ñóÒ‰™L 4¬.©ñG|¶œîMÓ2!®7›Ö§‹:Bàáøèaž!fIJäœÛá–ï^Agÿólúl^É0­{^½‡vîÙÅÌ1CºñÁ=À³t§áx–Î=þ\9 ³VgçËî|–kF߆jÛîVÛQá˜\ÙÈí—Sý2iʲ©œ‹`5þþ|¨Ê¢›Zœ@†|@Ê6æ™5ã Ë\/êg!`ć#èÇU?F’ÂÔÛžèh€+,ö€nМÈR€Áݦ[àíGˆ:®†ôéh¸p¿âd÷„ËØèžn¶_€#9ؘ0òJ])‡$õ›4'Gzþ¦­ äæ)0p €á²Ñ¥¾Ͻ ïJ¤þ-Óäß”…_lJzzÉU‚á*0Ò›öLXÏЇ:œO³“óíyM|kÆVºîë¨óß;ÓóŸ>O›v$ö¹àœEs¨ï­}iäc#)· ×ùßl<”Kupf¿±r/=Þ,àÅv_þ>š±vFLŸyô™T¦ ŒÃð¡úgF&\uFIã¥ígW âå=+@O#¬V±Óú:ã¾3hþêù1q©T®ýkð¿è¼ÖçñžÆ…gÚðûþí4ðôáOÆ„S’öäìqvþc›qÄ·–Ü/Jv@4§@ ¤ù Ð7P&ˆÍVÏu…|&ÇÇç®Ü³’î˜pµ¿¾=õy =ñþ4å§)´ú÷Õ”“LJñ³Ù´}-Z½ˆ&~;‘þþòß©ëÈ®tÒÕ'Ñg³>s+=nÒƒ€{êqG=®Ñ…ÆÚ|¢g-ŸxöàdÁÚžàl#S!@Ö³9̳ˆí74P!¸L_3Ý-2ìäa´~÷z:ëž³hÚ/ÑÏ'@!|&øÌùÏÐÐNC5;„!ÜžÜÌ\ºâí+è¾î‹k‹„žåk—óþGPÆ [`†ÐÇêP: @i™–†_{Á;ƒwZÉÀ¨c#»<ür*{É¢´2 ä‰Óh½vvoœ=PkšëZƒ¸Æ9¨:Hh\8v?@F~®î9æÙ¢Oˆ`ÀÌ9³ _­»'¾ZþM]0ÕìçŒ`´:Ûæ ý 0»GyÌî…ÁCÓdž;XøY# Ëœêí_ðO]=•îà¿X¦Oç>4uþTQggäò•¼¬Ò† 3+g¸‚ÚÄUE4šÎE¦­™&×úâÛùzÙõ¨×1½è?_ý‡ú=Üž¹â:¿ëùÁ {îùó=T§rºÿ¿÷SAY:°-(S@ON’f¯œMOzšTo–߉3æ±V…É#B?79[¨ÿ3 I#°ø]w/ÐÃ7®Žw2NÛù=ùܤñö»—wó–†=~7²@í/MY”Aø 0x•Sj„˜f%J‘*K Æ(3pÌš^–ÌMz™|†~VÕ,‚›YÕXögà:ΣLݾqò½ŸÛ‰E£!€ß*Ù”¨TcœæoOëw­×˜ˆî§\@³ø{>¨³1ãÆ–¨¸™© 3C‹eT8`~N“¢º×žr-úó(ÊÌe À‰ÑQ-ËW+¾¢nu£wx7* ¿ßûê½PáhY¶ßõð x) ³Ëzá¦*œ¾¼èüÃüHd!Ú P¶vym‹‚¦¼Ì¦Ôø(&œäç³!Ms]k€Ò8à¡~× —/ ^A’‡xž`„°ÚËÙ/Œ3iŽËäOå_f´â•{F>gÄÌÒz¢VGyë,~]Pæ/›ï0ûÏäÊQ¯ö)ƒËÜs©^åzœÙ”+SŽÆß:žÎ}ø\ÊËÉ£ŒÄ+À5?+ß]Zب#’AlUûpXÃ$çÑÍŽ¦£[M?ÌÿAÚwÛØÛhÍ–5tÏà{B…–0p;˜jU®%—åä3R #[ÐakÎV6fýgÆèþþ÷SóºÍÃ@ð/ê×å¿Ò”YSd³£@E[Íó‚[äÝ÷¯êR<@ÿ g4Þ¸:޹ñäÓh7Ÿ¦›}öô¤…”á47/òyÂ’fÇk:\®ø‘/ÍMÊ5iN¯ýt¡€2GÌÆY†¯ãB´ªÈf­@µ,ʪΚöÃfes˜5p%Ìé™Õœ4Ñ@ƒÀZ @5îÎþv«–¯JêwŠ‹zÇ·=žô€³‰µ D mBÝx»Ùõî?Þ}¸C £yöógiÄ?GÄõ…Ä™íϤq£ìÌlG€Aà%ì…ølÉgtâ½'Ò}ïÞçë§—¨Æ6·¿t;“‚¥4m'ÚjÚëºvÀP  @ à•IO£ƒ\?,¨àœFé¡£>SvC–ÀøxÖêªøuIÀÂøÁü ÃÁB3Y:@>¨ÿ±ÀßÜËî/ó×~ØÜ~ÌíT½|u'Çïe§^FÏŸâûvµ°9P—´Žh.×õýúïC>C<»ÃÙT£j G›ûøêß·x›†<;„öæÄþ\ñ„–'л—¿K5ÊÔ MsÊæÐã_>NGÞr$=þáã´cÏŽ8Z–ÑŒ¦ÉßOæ/Âb²/Ãl¾¡‚šhô ÒJÏûê׳ÀsOV"åµ¥©›¾€<Þ§l?QÛoù _roÔ¤ŸlÆ3õ³jÞ9>—]slpŸ‰õûJìò­zξv«ÂŸÁ Ÿ™<ü&,yÿøØá þÞ°ˆ¿¿Ï€JõaôQ—ýmk´¡m¢ã%d¾ð!j[›»áïÜ äˆ`žñâs7rì%ûEímê 3êáÀ\V×·æ;·îòeÊÓyÇœç̘±<Âøg2óž¼ðSêÿÌùq1ìÃN†M Úåj >h3Úš8Çóç‚ÛéÞ‰÷Ða7´§¿½q -]·ÔÅ¡¸ž±Ÿ¥Ÿ¾ApÏîF³ƒ6Èsà‰òŒe&2]Ò¶?‡yÆA[ðœm“èsGY-cû5.’k×™žþ´"=o¼ýHm¿7_.| :Z0#”6‰Ê˜x¶ÈŸÜó2û™ùeðLžtGEžÕccŸZ„•<ÈËeP¶ÌK l]šqÐõ³ç†Ž7ru3åËV /{‰Êî/'ÇòæËá@¼Ã± Ga3HÈn}Û¸0ºÞk‰w,LTÔå@ _0p{¾Yõ-õ~º7mܱ‘#£›6õÛÐÃ? ²f©WŽ$MAK 2XS²3k½8í%:ú–£éŒ¿ŸA£?Mk69E¯¡0uݦu4òÑ‘tÅCWÐþ „Dpaø\—ìÅ@°h‡hcøy°7„ .œ4ОÂoFÂÏeµ_Ø~‹äjéìâ5J_Ï“Ao^“DóÆ-c‚ ;ÑʇK‹7.aD‚Ñ( kõæ™cã6޹ýíç¢}ÈÌnYG^Ûo*n]­5Ñô JÜiߤ=ÝpÚ ôÀdÞÀZ9é8p]Ìú N¡s¶)«¦„|†xD“#¨}ãö4wõ\gÏÃÐcŒùý:ç™sèÝ‘ïR½jÑ7-¶¬Û’& Ÿ@ç½t­Ú½JöÈž|¡8ó§ƒbY€ùaÍôý˜ïéÆ×n$'µ;‰Ú7mOíšµ£¦u›ÊÒD™¬2„Ë–p6ÃO‹¢O¿ÿ”>ùöÚ—·O–-Ü=X~áÍXÚaÁN÷¸ô‰H˜ ¡Ä(`¿;v%¯®¦E 'žÂ€«ùÔo»×6võÛéiêOo M‰ ] (À|B ^f0?0SÛØ/¹&©kç §é ãâ¶…­éqº×žy-ýç‡ÿÐâ‹eÃ]f3>Ãè°ËßetQpY°emصêV®ëÖÚïè~4wÕ\Ù­_GÈFFÖj,ܾz=׋Þþ.5®ÙØ-ÎÓ¬V3úàʨß?ûÑ’KD 8X`¦ì åXÀ~¸¼Ÿaá–…´` ß”íÎ_À9 ÖþwG6ÚÅÌ^žÏðeæÏK7ºC6bB B€)ß . @@‡)ÜO0’}擟"úOŒát¢tP‡ £®¦9±2ب·ˆ«õ†$( ’GÓŒ6˹ñ1ò…ÔJŒñ2}¼a)ˋҽé&%±(œÈw¿ûéügùÊ`fªb?°~,=`Ý›#€ â-Ó¨R#º°ÍEÔµÁ‰T½Bè&Ä¡' ¥%ëÓ„ÙhçþŽZË‹pÁÆò˨׳½è½ïÑ!µ± õ6ªÑˆ&\Éš€ûˆðDäL°Ì´±\RÀ{& ø Âþ¼Q?½”= ØfˆÀð¹-Ðô»›7vÀäÍÌ_öbð± ØÃ€ýØ‹!BòãbGèâ <)¡úb8ã×q¯H¼))^akººú°Ý0gT¿ë×Úqì—xã¢.à)ÖøMœoü ð€‰¥<<(ÅW%žŒ<'Ë çÍ„‹Ò- ‰ÿ4éÖèdªY¡&ºdÒ¦ûaÝéÄæ]Ýkzqí-® ÎÇ xÌ(ݱ‰k’gÉ?W~5Míû]sÄ5Ա[mƒóþŸ¼ð)šsÏOtù CyS3e.‡=²ÆÎ3êÕ{WÓŸŸù3-Z·È.Ö_7».Mñµ¯y˜s1˜9rB[Ù9ŽLÆ—8„É|j‰/+2àGo¸ÌÀ¦KÊÄ-3Ä…ß K<ò ^-Òx±6@×ÿ¿½š#ô`47 Aqúº°·œÆÁMg“¶€ûD@}<5Þ'„‹öÞ€&%Ofʧ59M{¥/î­çÞêÜ·kzÙBŽ]:ž+fÍì^ÓáúÛQ£ Yü™C S½Ruzèü‡èõ‹^§ŠüxÌ~EUûúœõ²ðËêØ×תR‹Þþu¨é\',ø'ÌÄY 3w¨î!0w¾º€àXýÌRÎ_0BÒìø3°Ù_qXªYÎ-`àöMéV?ð†íþ4;¬~»ŒGãÓÔM_ M  ýÇ¡À‰ Oôµ±Çµ>Žº·îîÜη—gþXOÇ!AÖý¨ðª‡Ð Gò§r šž‡÷¤1CÆPÙü²L.å0íMy›¨Ï }höŠÙ1¡B ?l<M>aħ‹,€1c)ÀݹoŽ^–3 @€³ôÀ%ã·Ãz@“{¾Î0kÿºù0&‚A†€„t„€%@z•êQ³ªÍ|‡|íY×:ŒÌÖ+è¸Æ‹xÍ¿l&O·‹aº¶êJ÷œy·ë±Q!`kþVêûR_únIᙑª€ðÎïP»êí¨Â ð„ ãŽÌØeYÀh ÀáJ°ª€k4nTþzgfþ^æMŒºN(øM%ÌcNe•A]Å£@Ê7Í¢¥x8UœùÍ~ïÙߢÎÁ €Î©Ôë­¦HL¸M‚‹•ÓΣi®‹EVAš– —Oã<Å‚`)¦@‡ZJ»“ÚŸD­j·¢EÛxM<ž-n7ÌÏä{ÌF¹œTÝ—u¹Œ&Ì™@_¯úZ¬¶ƒM†¼…`{Îv:ôùôïKþMÝÚt‹Z–  8÷ùsiÁöXT÷L³ubñJ Œ¥cå“Lê{Á^·}(#Ÿmâ3C9p‰Ópï‡ûb£ JX&,b”°×K{»:oš ÛÏY²k>uF¤°'>ž¦×MCØXé;ê×1šÃ’×vMÇra(^iꦭ¦ôÐþ#P€Œ6ÕÛ”HKÁä/ï~9Ý<îfg–ŽOêØÊŽ{£8$û¤ë¾ÿœû©Û£Ýdã–õ{°Ãÿ{s÷Ò ×Ñkƒ_£Ó;-j]µ«Ô¦÷®|ÎyþZ´£p#a¥Ê•¨CýtDÝ#¨EµÔ¨J#ª_¹¾—\µ\UªV¾ZÜ]¹»(/?väì ­{·Š ²eïZ»k-­ß½žÖíZG¿íúVl_!q*ˆF -^A Z¾hiZOàH ¤¯iM ü^‹4Íc§yãí0ü±ŒÂŒ–/ZžHiÞxo8Z}AZé¢?»–ÕZ–Nt»€þ>îï´oß>ç›z|®¬³€]Ž/êIÒà 3ZA“Lâ ·³R(j{#ääæÐ7†ÐK¼D½:FÿÔ±NÕ:ôþ•ïÓ_Þþ ulÞ‘z¶ïIíê¶£2™ñ?•ËV–A0h\µqÔÖa6·??ÿð¼§À:…qOÞÊÙŸ#‚ÄîÜÝ"HlÞ»™6íÙD¿ïù6îÞH«v®¢5;×К]khã>Ñ0|Õ°¸•‡ÂŹþ žhc—7MÃê*‰4¬®7ÞŽ–OÓ¹ˆ‹dQG¬4Å#MÝøßÀ4m`€v@AÆU¢3©dpÊ®”M=èIïÍyÏY[Çú:´û™û0¯†šÞ!`H—!4qÎDçzc|ËÏù ªçeœ;ÇWŒ½‚žÉ}†úÓ/j“ð‰àØ¡c£æñ+‹HÂEÅ2ü[¯†!RÝ–n]êÚÅ[Ó¢­‹hþæù´oÿ¾¢ÂF8! \\¤Jƒø€)¢@ÊßÖN"IfÞx¼xv«/)\uPÄßxpǬ#Äx‚Þd7o¼ùܧÔR€Ÿ%6–¤é{|_z÷ûwe€òÜë ð‘»`>kv¬¡ìZÉkºÞªfV•Ëpú Žõ•]ü `g?ŸÜsÕ®¢=¹{è¢.*É&ØÚ×n/ÖFË˶.£_6þBó6Î#Ÿ<ë÷Y"|‰À´ Ñp8ÄxÃ!‰iðŽevs¼iVWóF 'xZÆëjâm›@|<<àJ«I¹à!Š0Z¿G©N;Þö”†½®] Ò¼é¶aØeé¦@"Wÿ§%=:õ Š™e=^¿ÀUÁ˜¡Ïß8ŸÚÖj[°!epa—–]hÒ¼I"\ä—̲ͧÌùyÔm{Áä \÷þu´/w í64F¸À®}»hݶuÔ´VSBéh ahU³•Ø>­ûHðÎ.Þ¼˜f­›E³ÖÏ¢×ýHó·ÌçŽùD$0|¯P`7ü`ìvFðÛã]„, EGƒ.ÍŽ ç×8¯›R¥0sÚ ü®…Jvöº º‡MÃHƒA8o>+¬t †7ÞŽ¿ Oé ?»’flËU¤S;…&þUô˜ýã“@^€ð-ßèwn›s}¡EÇC:ÒÄÙ\k°{_\ìÐ%öbÆ›?º™vå좿œö—¨uW._™öîÛKínhGÕ«T§¶ÛR«ú­är ¸­ë·¦*ªD…Q±ô BÁ€vÅíû¶ÓŒßfÐ׿}M߬þ†ænšëFƒâj ¼€7\ §hc—7MÃê*ÌHáHñÞrv>õ‡sí8øã±¨KËi½iꦭæ*»“Ó”ðÚ1xpÀNö’6=ŽèAÏùØ9 W³Å>€/–|Atª?µcÓž6„‡XÐ ytðƒ `>?„ ðÏþA¹ûséÆ3oŒŠn9{õXê}oZ¸|¡3CÖ ¿q­ÆÔºAkG0hÔ†Z7lMjò'ª][s¥…›]>›NkqšX ¼mß6¦¬˜B_®ü’–o_î´Ý+x[—η-A¸ÔP mP0JM? ñP Âi÷ŽÝ‰^æ÷ªëHà•[VÒÌ53騆Gy°J<ؼ~s/B„ Ü=€}øŒ_.!Â`Pl!<ô߇èÊ“¯Œ9‹?úУiìuc©ï½})7qyÇ pðê «éËŸ¾t8âúpF@õÊÕ©MÃ6Ô¦ ZS›Æìg¡i½¦²ãŸs•jƒÍ‡§·8],]¾u9M]9•¾\ñ%M[5vçív÷W- ]Cfœˆ L@(Ö€í@( 0›,q U‹†-¨^v=Ú°oƒ;KÏÈcîÀ³òWg½ê‹=/„ 9Ò—ï À’¶ØÊéÌU$D×츘ÌßÉIÔíðnôúõ¯Ó ‡ÉaFB7k“¡3ðã €‹gÐŒE3Ü8L°$-A«F¼”ÀÂìÚèP*W&ô$­»4¸‡T?„`/îp1íËÛGÓVN£O—~J“—O¦õ{Ö;‚•ÒØhZBð„rÄ(¶ üã{ßÌLg ³.xeýÓÝÂÔoò¤¤ÒSÇ4ɘžDÁʳÃv~·ã´Ò4>\>Óü[Ê)À} Öøñ)^¬–â~\ç‹ |T €úïÎ}—nëv5¨Ú ˆ¨éÕªTsfüÌô1óÏÏcNÌueðÍbù>ÌTñ…€¼’ü~u9´KT˜ÞijŽ;‹^¸ööÌ0axrÊŸÙg rƒÃU£N9òq ŒÝ“¿‡~Zõý´â'€ Òp@³ºÍdùàÜÏ¥~'õ£²eJçÆÃòeÊÓ©-Nû0=L³×ΦI‹'фŜ¥^aÀl?g=`FŸW8¼i&¬ãŸ[$B>y®n&öÄ“ó|o]Z®ÇöK’“QÇa–J:úÑSÊ)Á&0éE|— sT+Vóƒ9[êy0Hvóä7O&‚¨¡™™©ªÿ…ƒñ:ã¢0mQWót‡Þàðz1cež<¹üapî…Azk Þ WÃ5÷dTá»ÔÏwàáL¾ (Wsy|¹°ló2úxöÇtÅSWÐñ9ž®æ=¥ÜàïÔ ÝÖõ6úþÒïé‹_Ð_:þ…šWjNÄ«%ö’ŒAx¶-åíKKô´¿§%òá‘>(•ÌÂ71ˆ (z È!1)¨¶cKÞ¤‡5yhT=oÁ¿fÿ‹m,<~·8èìÞÃkÒ`þŒ_™?ÂjXFU! eÍ–+î¡õ¥Æ?.0¼çpº¾÷õÎ,„¹,(ƒ¯üÕK‚2ª²ß(Ö à7‚äSÁB.â ‡nZH'ßz2½ÿíûáP(µq‡×;\„—ΠÉ'ӰÆQ²u …Ý›a?ÓJm£Ä8R.` ñú³íäá\W©pé ĹjÇÊ„HäA¹ÐÊANœSŸ sXóÜ5yÕ`C ÖèÙÉÍÏ¥&Þ@ùà Å3«6¬ eüÊ`àªÕgÉQ˜¹ÖªX+¤2\ ´píBº{ÌÝ!ñáðwêlÿÂ÷–G¨"7š[eö¯ÚÛUA@]MceveŸ¿˜ný÷­”·RSz™Žõ;Ò½Ý寧‡ýLoóõmÙ—Êç•'⃠]ÍúA´g¥Ï,p¾æ¥º„7aËõƒ—‰pí@NùoÊ€’ja ()Êp‹C\N“ S§zªQ¹F¡ÀfÊ<+Ç·çÏû|±QY¸Ê¨Ë# † ™ëÃn¥²•4Öu‡œ2„}÷QºûõèB¾,xvè³ÔõЮÀ6Ë ø ª}Ñ @Õϳz\,ªñcY@™¾­!€Öav!<;õYêõP/Z·55ÏÊ%†OìoèÞ¼;=öó4÷ʹôÈ)P‡êäsMhƒTpÔ«ÏÑ'0éMôD%iD1UOj\B.^ †“2‹úÔ¦²Þ ®Ô=ãZ¿‹wp§Èà38žæ;kôf/Â0Ø8þ/ï¦/~Q,lfÌåõ{€ÖŽé]A:§•Í,ºÉ®[»n²ïS;æ@IDAT‘·¦;_¹3*.صÿö5oÓQ:9Ì Kh®þÍä¯+p,oîÏà‰o& 8\‘ÃX2€P –ò€e¶ÔeáÛß¾¥“î9‰¾žÿuTœJ{"θ¸ãÅôùÏiÊàÿÒÅm‡PåÄpHTN> l±tÄóƒ«6ÒóLi¼v/ƒ_²ué«6|ã7ý5®qAò¢ãÇx%œ¦?i+Øô×çÀ]Ü}.šËÅs‹•ÇÏt»Ÿø 7€•Úç‹Þ+·­´u‰ú›ÔiÂ;ã¹ýfËUî8Åoøþ¬|:~(Í[;/!< šœôÝ$æªN1ÞðOE,'yi/ ¼·ò 9uÃÊ Q;_.à³¾·FŒ£æÙÍ)ŸO9̇`ƒ6j}ü©c¾a⯠oàK?ˆ÷ ˆëj ˜,ˆ…@ÀZb ƒ— €Ý°õ~ª7=1ñ ¦jHoÓ¾ÞaôÈÒÿFüBü0µÉnKùø¬ˆ|>ÐÉ¥%7Uè WýÜt‰K±«/©ºmøð‹ênVÊáç 2ü6\Æ®6­I? ,ß¶þðŸÿð9­X·BÀ@ÿ–îur¸¿á$>y0e•ad¸ü¨ñ£èŽ×îpË„óÔ®Z›ÞùÕʪE{ùÍfA@>u4mU|p/|9À€ìà/Ô…` › !ÀB;€/DKà,!`ƒ`~Å|ºëã»hÀShóÎÍáÐI»¸*åªÐ¥.¥i—M£wû¾Kg49ƒ2rùÁ± ËЬØ}ý60 àUL ˆY n1ð ’K/pmlªLÃZ ‹0·Ï‚Q3σ\»g-ýâÙ4má´˜¨åæåÒßžû›Ãä•éó/»ý£8¬'œiT«Öé43íÇ?xœnãöpYݸu[Ð[ÃÞ¢ y(ëøpçÏbåÓG¨°mƒ¶*^poá@„WCàØC;yÉdêò.ôÍ‚olÈiï?©ùIôï~ÿ¦—Ï KÚ]B *ÈòŠ|>ªËFJN¸êOû– ˆF¼&ékÐIí™ülÝû&ìêyì°úãqõ…çÆS>Èã<§? ¸Ÿ,Ú¼ˆpel*LÝêuM€<›“eìÇÌÎÌî L #ä™ñ¦ÜMÔgtº}üí´kï®°èAx¸á©hÞòy.³×ÛÿÀTÁd¢ü¹Z<[®ï‚6P›Z¼'!‚¹ø´‹fÖ€ùäÇOÒíÿŽ.Ýâh}áh">Z¡`7 { µ* ¸šàî=E­ˆg#B ×-í€Ö€— 2˳6› ٮݷ–z=Þ‹šð4æ”:8~›×hNœùý:òWºë„»¨j~UѮȲ_€‰„n«ýG]?Þ]ÀJŽ>ÛDáxË! ‘\;Më²a¨ŸA¤³Io )à~PSñ,Ù²$%m¬]/ÈáÉ= Ç X^-aãÏ|q8γ_?KíomOwŽ»“f,˜A[vl‘ë|¿ÿõ{:ï¶óhôGÌpe˨Jßåƒa‚yBÇ.CcFvIOöx’*–áxLÏczR½õ¤¬0`†ýÔä§èÖ7oP‰>ûȳéΞw:Z,Èš67š™Š+ð#+æH¨*ºÀ]µh—jxŸ¾,ȯ”O|òõz¸­Ú¸*Ä´¯R¾ ]}üÕ´èÿÑÇ|L=÷ ÌfÖò€œ/¡ô„«6m[ î¥^ñ”wPJ¶VíŒê*<Æ  ƒ“ޗߣŒÆiyËC'¦0³-‘‹:@ìtÛ¯U„‹Ó´À-½0Ïíëÿu6ìWjT©QدÁüu¦<´†!@g>Ûvo£'¿|’žø˜7¿AµÎLU¯ cV¬KÂÁ$  Z—™r±³šŸEïò÷˜M*“U†.ì~!z”óî/†ûì—ÏRVVÝ3àžˆ0®ëy­Ú´Š^ýáÕÂ÷–ë–ã¾Ë0μ<áâŠIàrbŒ6£åQ˜ÿÅbjÄþoV}C'Þ}"=yÑ“tî±þ\±ìT\:~³2³è¸&ÇјóÇÈUÎS–M¡|(—mÏÝN8–YÈ¢´}”vð‡3šîM ïÓ°º ÃGò#¯¦aƒëõëL_Ó¹€£FÓfL åJ©›rÀO:„cÎx‰Ýx<¬$ + œpiv\$¿‚Òt¸¶ß›Ž°¦kZà–r ðà8{Ýlê×®_‰#š]%["='ƒ’ LÖ`æX€Ïè4μîz>fôl…ò•ÂbئϳcªÀ1üÉì¶Ç¨¼€Ç¦vÅÚ4ê”Qüæ™rùgÈiCè±÷sp£E|ø@Äâ8#`̈1Ô®F;Ù €µkœ/çãëÞô»xfvÈc\aúÜ6z ñ0éACãf£Î·w¦)¿L‘bã–9ˆ®9þÊÎȦÿ­ømÞºÙýCïœpé/ÑÊFŠ÷ÂÐàO4 8áÊ(|oº†íô4õ§¯àx˜–ñJoV’¯^[bôp,ý(À¼rΆ9´7oo‰ãŽÛ01€Ù«íw`œtý^>S&‡ïã± ‡äà¸\sÞ¾„! BÖɱ ÀûtÖ\³BMÜn°[E¼žWn|…Žkuœ³yï+ƒ”Óþ§‡&?D|ÌE0˜9–j•©U¸'_ðæ5Y·ñŒNd˜_Ô ú°&AhÄZ ¡‘ž:Èt€@ôÛ¾ßèœ'ΡþuíܳÓ)wþÖ«Z;ç1šrÅêR¿‹ó¦Y"’}r8“i8è/­‹C«xa{óyÉÖ£|ªøJ¢h'’?}<œx,¨ÁùBÄ8Ê%š?.\â¨7€çs-Í´4}.'/‡f®™‰P‰š å Ÿgš0ós7†£gQõvÈL×l~S!À½aBoŠ“oç!0毳ÿÓ9-ìÑ¿@'š©\¡2MúÇ$t ¹ÉPf”\@4\Ï}ŸÞGO|úDDÍê4£±ÃÇRÙܲs2C„C¸Þ)Ô„ü0ÌFG]áÇœÀè¯GÓ±·KŸÿô¹Sæ ým× ½h,]Òá÷ë ýò"j? ×÷t\$Í‚ÆÛÏPqÕ4 {]»LúÓz@¢ôV‰‡±¨EÄLªâ¹ 1=(€.ÆöëU_S—¦]Jçreù´˜P“úáÚ8!Ž]Ø•µL3ëÕõWøE>¨ù¡C4kõZ Oiz œb¨ó_ñòþ!2ëWÜtyó”Ë*G#Oþ±‡K÷œ®{á¤Ay­ ÎÒ.àÌÿ.ܰP¬Hä…Qqyìs K–ýmïotÞçÑÇ^@÷º—êTãÛùÒÜìÍÙKóVΣ9ËæÐÌe3iÖÊY´`ÓùrK"vßQz‹ëC»èøç}Wbµ'Ñü±à ôôð "Y}ù5ÝY;v‹*SãP|OBaDÍ«“xÓc…£V$–* ˜gùÕò¯è¯]þZò¨ißk[Ì`ìY 0ѼÏ ““ “óÊ{3ÉuÂî¯fàxÍ«¸«Ýb zz´ïAc†Ž!rY¨1š¸×û?YxüÀ"Pñ ÛëW¾NÝî=‰–íXÆøñÆE“ ïžËÔ÷"bD ¡ 3}‰ `eù„ãÏö¿ÿLç>rukÓîx7Õê(M™Ù°yÍ]6—~]þ+Í[:æ-›G¿®˜GÛvnsð¼ù.è ¯aþh ß0ìŒìf¨†t|ò‰20 ‡×J‚ù1ô²£Äï/6Eâ=âM×|á\{Ý4ã yg8Ñàn>öÚy<¨¥[8¥&.Õy囇€çâôKíá #UŸaøñÇFjƒ ßÎcÇÛµh|,e4]>ð—b ˜îÙtâ¢I%*Èf,‹è+òzÄÛi¢¿:ä¢Þ]¹»¨rÙÊEŠ!à•‹_¡ _¾Ç]yÁØîç«G¾9’Ê—-O}ŽîS:¾ wõÛÔý!ç;ö|Ìfa1sç?Ù÷Fš$Ú^ä×rRÖÑóg˜€ <1š²ÅFÉ©K¿¢“ÿ~2ukÝ®ìy%uìYÎ>Î’¬Ùºc+-^µ˜–ü¶„­ZD‹W³ã·=Ú.mάÊ?p…iðkX÷K€ñÃxÓl„”Ï?áb(ÒÙʼ‹½!&Þ>RÈ $Q4 ´èQn]Æ£auQÚöG‚fó‘ò”æø” ¾ODzxò’ëS³]͇Êíxt^ #-^“h™Hù½ñ±Âñâä+0Ïó³%ŸÉ™ò˜©–„Ù±›¯ßÕ¾£.*‚ßkýD€ùó¦Ý›¨r5ÿ wVdzèéOÓUo^å0Um> Ã^FåË”—<Þ¦´nØš^¹ìêÿ|Q× ÃãLBÖªA/ãò‹6euYÄÑ00f˜ˆÓ}* L]:•¦>>•šTkB½éM]Úw¡CJõjÖ£Ê+‹@ƒªÀÔ÷çï—#™á߸u#ý¾õwZ»q-­ß¼žV®[I+7°]¿’¶î,¼l)„É3X³—¶¡}ðbφaò!aÄœ%~eü*€îýÌüE@<à‹c<  ŒºN(ô×›o8Þ|Z›æÇE;Ÿ†ÕÌXéZoºé+„!¶Hcü°D“^’Q1é.9&ÒÖ?r^ Ð÷n¤Vÿ@›v.RäíÇí-ƘñXB¶_Ó}v±C¼iµ¦>C嫃» ¦•WÒƒŸ>è¼Ï`:l±IðâW.–{Ö£H½§q:Ý|æÍôà'2>07hìã‚ñº‡>(£eÙ/Âot-ð43gÔWP–-³¼j÷*zæ³g虉Ï8Ÿ=ÚgžZö†ÅÑr… ƒÃ0yÄÁ‹ö"Îø5^9âGI®Èk3~4`Â<Èoûµ>Ž.5t LÜÀ#L_c¿4êg×U‰jgÐ4´TýÅtv1Ë&[wP>ùç—rš·kâ‰Æç¿#·úa`?ýrÖšYþ7È@¼¥÷-Ô»}oçŽlDƒa”›‘Kƒÿ9˜¾šÿ•çù½åœ[茶g8ß­ã|½B8ÓM”nZÊ1Ý!\ƒãÇ®y˜„ƒ“pÀÎW0‡éÉŠ¸qéâb‡=,ÊIJš°Ù¯·†Ô…3Øêé…nÝU9g:°+‡=™CŸÄÏ=i>·œÁÑ= íò%ÚÐ"Qú%“_×ã†7¬ñpÕÀ|jì<ìáZ.œ‹¼h¬¦)¼4vÓ[ˆBxÕDÉ$(Y €)Ãò[öéâOK¬®œœ…ËuÁÁúnŠÌ´ÓJ¬&´ãÅ¡/Rû:íC…f´{ùï‚/ —þX¤~”=l4µ¨ÖÂ9$ˆ9.Še(•ì@®d6ÏXI²…äå$E0Y>e XNZĉ‹†ñª  .˜»ZðA®Ê&ÏBº{p“2ölÃä³9[© ~OÝÊøCp0õÊ¡O¡ÄÙÀ} ˰ªaPê+-4\ZÜDžq"yKKû’Ä#}<,}`áüÉÎÏ»Ÿ°wÅ;pgyÒ‡KZ¼y1-Ú¸(É×5|qù ´S£~Û-!ÚþðÛ´aç­Ùw·RùJôÚ•¯QEþ“蔳&`Wþ.êûl_š»zn‘z±)pÌUc¨b—Ûc´zÛaqî ˆD?­ÙЇ0G˜1€Ìö #Wæ-LØš‰Ë,ŒZ-4ê7®0}sT³¤Y…=»WÆ.u¡^¸÷¡ `ôF›YžÃªy®leÿÖü?«þ]ëeúÚv¸‘è£ñúÜ4ËÕüêÆÊ+]q OÓlÈ+¿“+mÓWH€ä¢¶A~<àxL˜|ÑÖì]øñÀòüñ(€ÙÛ~ý DÚ¾{ïîB¸öLLýêæòÇÇpó òè_Þñ^(ØÜ÷Ø ÇœÙ<ÎüÇû‰61“Ý–·z?Ù›–¬_R¤t»&í蹋Ÿs. Ò¥ÃüC4„aÞ÷"ÀbE(áò¨ !@4|H£Ë`¡€z^gþª’Ç쌜gï^‹Y¼0vä1³zÉ«e!@À0ÅZZW“À ßÕÛ3{0{ÆO6øõ¾Ìî ã—½à¦M⯖½Å6~Ð<žÊ‹SOqÊăK)Ì“¾€~çÄ®ó2óS³â‰´0.??Ÿ“Yœ ÉS˜-^ÊEqcÂä'N%6¾:½øà3\o\.-ÝøŽ/!F™›Ç§ç¡si?d?Æh7¬ñ%ár]¯ÍzUvè£Ê’2ƒº¢óŽ<ϸh$ ›r6ÒŸŸø3­Þ´ªHõçwì6’Ëñû¿ÏØ\Xp.²è–,}œÜ¡;üüÌåSDÖVoÌaÛŠ,'•{F%ó‡™ „Lݤ!]—PNÊò¶å™|¦Ìì9u©Å Ž\¿Xh&Ô2^øî_Îïü9¶Áë&K›å µ«žç¡xÄ(Ÿ\_çfƒ5°ÆX êB½Æq\å3HBš±N‰´ýM¥rúfÊòùçú|Tý®ËÈõ›Zæ!@¬ÍüÑÒÃ¥y˘êÅ —?ˆ óü˜Z]˜I9ßKgÐ|Þ1?oý<»;øâß¹{§Ô¡õÀum Ó\xñ–%4q~ÉmrT"=2äªY¾¦ì`ŃŒÁ2KåëšÝkXèEë·­×ì®{÷€»éئÇQ>kò±!·Lä³&€Œã w6ßú›ÒpáÇ(‹]ô¼v^f,3oƒY‹:ž3°ŸØÑ cwòK^ä‡e¦_h¹.™Ñsê`ºˆåz ¿ßwðQ¼Ü~ÂY\?ð.ŽM‚†\˜bÕË%“)gªv…%@M,âÔhº§i鿦RÚ`¶î‡eÅWR´f,Bþl`vŠÎ/Ú‡p A\@›<À¢Ëþçÿ±c}ñãûøˆõ–´á:ýêÑ×à²;Ï»ÓÙÕÏëù2ƒGÛ0‹e†‡SÏ}ê\Ú¼ssH‹qéЫ#^¥šåjb÷ ³¡Jþ² Xׇ@í•þpùùëÒ€¬¯ ƒæxht>œËmCº¨ëÁà1³‡šÞ¶Ø˜gÖëås= °¦^Wm°ZöT& Ž\œq¼L™2¾ð²âÔí×sCI‰ñ»‘r¨Š-Š%ñðA€D˜~JTrpQÀ Ä~ ƒ†ŸÃ¥.!uÙÆ¶Ó’õ›vý¼þgzkö[ÉB‹Y~È)C¨M6…L\eÌçmšGýžíGÛ÷lÕ¸Vc=t4eäð,Zý4BT¿:~¨R:Éhäµy³2n¸°^¦®ñ`îšÚ.+ Þfòê÷Ö•$ú¥¦¸÷ÙxÃ^D½éÞ°7¿7ìÍï —‘³’½…’ {jH V\…S&06Ò8¿—ø.^f[—ÇQnšú‘7° RÙÐ÷ØðNË·.§WýtÍÉQ¼ßýû¹ãÛFÛ†8õ—„kêD»ðï÷Ò®}»lL|÷ã¦=Ü(3yQçsÃøÝ—Ý÷`<[ž¹v& |n íα6G2&§v8•n8ó÷Ó@ðe€_çÄCãpñ2ìHápe5.žºƒ<Ñߦ¥h„@'ÛU>cÓÐɕֿ~ J²pD‰–.Ô¸ÌÌȨël>*ãf¬V¯Àü)€»í›sÞô•»öXL×f\ c‰TÁ3Òµ;×Ò]“î*ñêÎ=þ\j^£¹³_È~v™¶2ƒf!àëU_ÓE/^D9y挃խçÝJ'z’« ^ (ÐÏ1Èï©C‡õ륿7ì^IÂ-ÇûÐü4ÌO’Ä(ql"sÑÄaE-ÁmÓ×+j¾xËe1ñ•\á\Žz"­¬«6ôÀ.É:K¢Ì’éaéŠÎÍÌrüÜñ´+ÇbÚˆOÂìÙ·Çéã`Äè¶Ñþ‰8õûí6×5è—|™¾^ò5bJÌ`ùoøÃ…‰.B„%Ú< Fg!àóÅŸÓЗ‡ÊûŠ Ê¾<üeªS¡IYÖ"È!AxS  'ÜŒð[b4ˆ9vêCôëÃrÇr.òŒ5ÞãB凑v;€Ð²H&ZZ¤21ãKZ(¤CZ…ìZl¿$9ú€2A  @ª)æ æÄ3ò¹;é½ÿ½ç">Œºâµ’X?¨‚­hx4)È* o ­» /¬)Zip÷ÁTÿ °Ðð#ãðÁÚºÙ87aÞºúõ«Cö]Ô«^^ú Èøšò*Da%üÁÓ3î†4Ñ›+R8Î@,˜ÞôX`­üÒ'4?âMšLB5Þ—{’laàð üÂ!kÇðwø²PiI;PŠ/ºBYþ6’ÑšÕå|"˜/"‹7Þ¯6Ä[_ï ¢€aPoÌ~÷Fa ëðøcß*ˆ2^Ö¬Ú¹ŠFŒÂtã‘HžêUªÓÙΖÙ?˜7Ôø¢ÊçwÞÝio„€7g½I·þçÖð=ïA9ý/îR€ qíRJÓÕõ³r¦úÕ SOùrüù†Fù »ªÇR¨Qj×,ɹ~ 1±`Þø6(T,Ë'iØ&©¼ñÁ•è6ˆXþXå døi¼ë·îïg%¬ÔRŒ’-ŽÐ¿~¾/uïܳÓc`K?1~• |©(®Oú+v§³ftÒ¢Iôòô—£•H:­_×~ŽúŸ—ùu/›™G6] À±·ÏMŽûä±:ï:ÿ.ÚðÜZxßBšþÓéõ¯Ó'ßI}Ûô¥Ù- ?İmI j„†¯L¯õæñwH‰€Ü0Ú¦«íF ÍgÜJåø”&Œò"ÞÌ+<2HÅ"F¶ø’ýYĈ£®¼¼¼ÜråøðŸö9@X ‡±r’EaØM~xÑ îh~ƒaË ¥ƒò…1ñâV°—nÃÔxÓ0PÑ8EËNÓ¸ÀM? à~úç¿}žž<÷ɤ‘Ç€ô Ó·µHßÑþ§nÒµE`à£]ò‰ Ó–M£¡]‡F(|ôéÇœN•³*Ë~ŠÌœLÊ/›O™e2 ¯ýÅûޏ±½ëã»(»B6 =ÙÁ)“ÀÛ²s ûv è2€ktXRwm¤«fÐôåÓé‹%_Т-‹DxƒPUÈ‚ðÃu¶ªÕŠÎjuunÔ™ÚÔnC5*Ô *å«ÐŽ};h펵´xÓbšùÛLš¾b:ÍZ;ËyŽöxX 0m?¥ŀƑŒ7-BXû­[8™>œÿ!}»ò[ÊÏÀøƒ6ã‡3¨åºŽnx4ÝÞí:©ÙIR÷§z…êû§:¢^m{IòšíkèŸß¡Wg¾"Ÿ‹JÂÁW`¨¯4óì#¢âMËü0LÞz-â瀖Õw Æ;CoaX  'V®À<¨Èøì$'ò žÃ<’©£µ˜`‘j|Ò.^“’0h€ZÀ/ÈÍÍu?*¬R¡ŠK­HÝ|~(Þ£i!.ðüBâ,ĉ÷ÿ›HÙ ¯?Ï mèÈ7Ž‡Ý“¿—^™ñJүöÖA@€mÛböç„i‰:Q»Äá0ã]¶}9 ~}pÈ.ü¤ëpj§Óx÷>×+ûØ•oúÙed„Lgà"Gâòž€ýe÷Ó°7†ÑÔùS]H=ìI×÷¼&þ0‰>=ÚÝÖŽîúð.Z¶q™›ž5[ÐðÎWÒG—|Ló®û•9ãQêÜàx©G çóWÕËÕ —Ïy…&ù,"ójf7¤kO¼–f^;‹^ï÷ý©F;ޤȓ&n`çËí¦¦m\NÚˆvÂÿG´‰´ÝÎ ¿¶žG»´D´V¿ÆW­XÞ¤ Ì#qpªÑê4ìÄúü[R€¦4dïÞ½²P©µ3Ç_µß&„( ÃÏ*µ’†xÍç“«ª!¿áðüVœ¦¦ÿ© ùÕ_¥¼|æZI˜={E¶.„€~ c\ïÒX‰ÑÀªSgà_-ÿŠ0ë.)ÓµCW9@6ï™Í€ðËç|ü¾£ír=/4æ  œ¬êÿbúqiáLwô½ƒúÙG Z³n ú`qÇÔë©^ôöoÓ¾<þÞÐ2õªÖ£¡Ç¥I—O¢YWÏ¢›N¸‰º5êFS.›B}þÔÇÊ™¸K½Ú÷¢¯¯úšFŸ7šê—¯/Ÿ,âsEtôsEŒgxÆêú4žùÚ?¼¸Å Gkƒ·¬æUk8œ‹<Þx…‡4õ«‹8ìý°Ëhš‰«V¡r%m”'îÙ³g‡†RbJB‹üÎ¼ØÆ¦È©eÅlfJ5+©2±RAî€%C™)­ÙÁjß9É]§»'‡Àƒ…ñºNlê~¹~Q‹óè¦ûòŒ—éù)Ï—Hým›µ¥ÚUk;_€ñ‹ÀüeðF­ÀÇçò²„l äsõ÷dì¡ó_8Ÿæýæ\Î|ÿuí¿¨g‡žÎõÁ|>@>ß8åSèò^N­nnE}û¯4wÍÜ"íh^«9Ývêm4áÒ Ô´zÓ"éÅNý:ö£™×Ϥk;_K™¹LP¬c©ƒ…Y³S‚9Pã[ØÑÞA)m~‹Ù†:UêøÒDå‰;vìÀ%á° çKÝ~ 6’ê‡+þÍ›7oÆÚØd±¯]©¶#µá°­-µÙñð ÞøpaÀ ï‰s_BO¼Î@FÄ|Þr1Âù<ÅȤÇ÷ì(¸/ÊÌœç#_<’”š|×î]… @ájAŸW*\­«-Fž}ßúá­4ñ§’¹1ð˜VÇ8ŒŸ5Ê å=‡0€sþÑnv\¡„…&›r6ÑyÏœG«7¯æ X¹È¤·nx‹Îï|¾3N€Ñ⌞yoÙº…žŸü¡•[ˆ–‡‰F§bLÓñJÝT<ë’®#‘¶Øy™$òÌ5aõÛ8#^ÓÔoúŠö™8vûkVâË¥|0Ê·nݪ·X)6€¿Û¯qI¹~6RЏºŠ\ÁªU«Ö"Àë—” \4ãÝ’טåhù I#PÜrq€²ì`¦/oÛ%[—Ðø9ãMdâÎöÝÖÅ7 ®íOlñKh½¦}`¶ùYù4lÌ0š»znñáF(yT›£œžy÷4?¬õ]7ôåhpF[\#|öãgÓNg…R„„—¯~™†Ÿ6Üœ¼K|?.ù‘®yíjù-éê×®.rñP4“Ž>¶ù±4ý†é4¨Ã ç>s’œ ‚jñ޾I×€Ò6Br¼ÑKÅ$/‘¼D¤>-¯.òxü.^žò¬—i¾X®òDæ‘ë8¯ ÷izãc+Ý@+²D®ýþûï—"2'‡ÅiLãj:^NHù®Õݨµ›@^b{Pp1sò À2¶sÇä•n× FJÓ?,=˜ :+}äËGŠ}îö–€~ªÆÓÇSNgÆCÛü޼Ôï¹~ôûößC_Üv‡ðf9¨Ä±6ŽY?üöùþJÔÆ‚€‹ &XX¶uM˜5A„hvïÝM£.E·ö¹ÕÁ ªF@íËÙG%õ•ƒ©1ÄÁ·çÏ~ž^ðUʯäh0¤šew¦‹6GïRÞô×õ»- ª‡FÂ#”äzpŒ.¶Å»¨Ö¦hÄ4s¿`œVm_EU*U¡‘¯¼p_ÀÒuKiÄ™#hôðÑ|CŽ6û:4ëhÄ´ªßŠ>¿ásºü˜Ë©`oæb#Y€ Zg›ûa箳¤á+]àÂ(à×8/4ãqµFÆdxc”¥6M÷£jᇤÔ(‚^W'«:x»2ÓÚ'-€» Ckób°'Mçõ’i)0¨Ó6úÐí¸H~QWz ‡ éã#ÂA2ü&®Ýµ–žþïÓ µFÕ‡!…F]'”ú_­ÌŸÏ°wáÿy<Ýóþ=¾àT¶LYjÙ°¥;ˆ‹@tvCÞ?Å .ãuáÑÒŒfÈ¡.ÝÚt£·g¾M·¿}»lÌÊÊ¢%ë–È)o^ó&¹ÇcÔ„Vƒmnêo ¡îDyì‚Çè_ÿ‹²3²Cµº/@‡uC Ø€ûl¢áæMó†‹ÓÀÇŽ·ýZ‡)S£J‚_¡iy«¼ðF@^iüŠºZÚ`¡Áâ»èÊ~!EV]·A|€,VB&˜¬­›]·èCôbâmIGÇ“?UŸj9uQÎö{á„ 'š?Œ îG0#ÃPžüêIZ³uMÜ4a@€c38ŠÆÛq©ðk½ìÚ3nlÀõù(9†×4Z4äÝñx—1ëÓ·™ÞKûÝ48 ?n8=sÎ3Ô¦NzøÜ‡éÄCO¤ÌÌLzjòS4êÃQÔ¬N3únÁw´â÷„Â޻î=9JX`?³ï—ïúIÃèsTšzÓTj_«½sͱù"†´ýê&S£0’©?ZYÅÍv½~ +p(5š¦.âm¿ 7¨Ö iþ…þj”âÄg€7¢&X—gZqìãÅFã‹åú%hå6rÚuó·mÛ¶ùÈCÍŸ”Û¨z£ÂòZKaLQŸªe#¥ÛyÃùµ|¸´ . @, €9-À®ý»è¯ïþ5V 7]g.ãwS,axVLê½ÀG]{§rf{Õ›WÑ÷‹“g¢Mê5q?„ Ÿ*Øï¦õ~ßôxºïôû\:T(SAÖu‡v*qw½}›>Ž4ˆî{—ì èÒ¦ MºqÉ÷ßÖ˜ïǸ0´§EÝôùŸÓy‡ú•6Eª@$mš”Ò­¥ŠXao^;ÍëO$¯]Ö[ÎF^;~+ܸ&oB÷Á(/äOÁSÆøu¿%ºÚuŸ¿aÆßPqXµ¥b”€Û¸zcG 3ëû¢Q€ß¶X “Ú°; Ã…Ñ|ÀZ­Çë#ÌJ¼å|§ìt7puéÀ*ìƒJ íwpñ6²ýpÞ‡ôñÏ#&¦KŒqB hÚRŠŸ-ð¦ÀÜÌ\øÂ@Zº~iê‰Öjè¼³¬(²Ðóžfò9Ìœþee@íjì÷ õøSqåsWÒäÙ“éŽþwЀ‡Ц›¨CÓ4ùÆÉÔ4»©hÆÿ8ž¾]òm(ªT¾½:ôUºïÏ÷QÖ¾,GÀÞ¿¾-ýîO‰ÀŒ–7ZZqpÆsL®ñ7©É§Fy¡áaj ©][áC͈d!õ«‹ÆÀ ,й_ýu1"üú°yæÑèਅkn`eŒæÓpˆ«­ ç†d ’ 3FÑ0OÂ,ùúw®§Í»ô\ÈpcjÀpKƒQ<ÐNì@;ù3.&Ž÷´÷ŸzÓ Žpò{~q Ðë#_§Cë*ãÔ…^(Œ¿ïñ}©ïƒ}Ç–õZÒä›&SÛÚm)Ÿ/ùÆÈ”àA7bðšÓ¯¡ WM Zeø¢)þLP42ŸHº,¥­q0"°Jˆ:îjÑð‹–†òaÒ‹Ôiçß„Cx…âb¹-k·´BÅ÷*/4¼<¼R±² ;I×<ůœK&+„«ÜF pñÉ'Ÿ,Bmt¸Â‰ÄRó*›YÖYûC­nMìWrY®hŒ:LTbVšKr `ÇÇ€’×.Çþ’šýG«3H󌒙ãºÝëèê1W#&ªÁšµ´“»A´4¶*žXò0B¾ ˜·q]ôüEÅ>±vuëdP™np]:ú¨‹ºÙá‘“ˆ&»R6¿yÕð !{âãüÊ N´´xût,Þt‹`à…ïÍÇéÓËd•¡µ[øò4•Þ¨ fX5ˆ/ã§`#© iÐîÝ»sxÓC®0b¬Õù`jgó‹/µ8U9ÒTkÅK&„-€ë„ øHaÔV¼§¸~>I<¤.…ƒúÔ¸æ9ùLû´¥+_ ¾ˆ««¡þxÞG4zêhŽˆlÜM€('FiʉÓp)q¹ò|ÐFŒ>YìòR@kþ»ôKºqÌ ÒŠDDÀ˜b¬#à[aÓǪUȦ“9)&ø– ZÒ3#žáùXmÜö;õ»¿Ý=ènúaÑ÷ÔrŽ®þè†è”Ö'Ó׿N§3ï;“–oXv*34ªÙˆ>½éS:³õ™,ðXÇ÷6ºûÌóñØøý~#ÂVJÄYoD8\Þ›¦auÝ6¡Î0mư¬ñØ/!Æ+<i€ÅÿuªÕ1éÉ9ÊÁÁ°€åZÄj˜ƒbï«ñKPÄquµ‹ß¾};ÐWu™dsU㵿Hµ…‹WLBÒ‰R±«°ñÒ¼qº"Pę׎ùƒ}üŠA·RYý ma£Kølî–wo¡ïç$„ù]¸b¡kÊJ@ý¥•6@RÛj-@ðò×/Ó‹Ÿ¿è´)ßìÊÙLqàÚšC‹›He³XâˆÃôíÚ—úuá{>¼ïí{éÒ—Ñ´yÓhàcioî^9§ÿëÆÓ9Ρ9KfS—›O g|ôÔeÁ½õc¯KWŸtµ« (À]¸=‘Ç<®~öjÚº»•“•™E÷x€žø4eå–‘=ù|z`ï È—‰¡£+tƒ[ šÇQ޳ˆ É­l´4†äÂ)N>æLÒ?G˳GaÂ#~Ñ´V3ù$•žÂ'í&yüIÖZÜ/¤1$×Û ó…K‘¿{„“´i]·µ»ëß­5)&ðâaÊÅCåMSX¨.Œºðjùn žñNcç³íø0ÅܬÞ|A8ôY¦=̃ÕϱQnã¾Ôçé>´n+î 5SfO1ª~Žãgëî°³–6:(nгuPP~™|ºìåËhîªø/ªR¹J\Ͻu­ÖZs\.6ÞÔï&w–å«W¯OTê{]ÅÄÆÌ‡Ú~ €f#h# ?%ÊþéÓ§ÏaW6ÆËX£å;¬þa ¸L6 6"xÚ×$ªF‘Dù h)¤˜"¿™zz–paÍ©œJ‹×.AxÖ¢Yηõx“ 3uÝœ¥8 íå¯ÐV|°#õ¦?mt†1‘Ç%>®ñŽ>:p†&Õ›¸ÙâõŒ8gÕ­Z×Q—3¬_WÿêlŸæ*?šó]úÂ¥²yïâ=ƒî¡ï줕o¬¤×oyVnXI=®ëAo|òÆ?5PÛÛ³cOúàÿ> j™Õ O„ êq›éi!?]ó"îI!òG²ºpÚ´ià‰ÂÙµ±°±ã$Å^ŒõÖ$ ÐFVýhLˆ:uêJ&H~ÿ˜l­x1³ycOÙ”„ê*6\û ‰µœºÊ…tžyPG"ùƒ¼Ü3bÐô O7 ]>—ãeëÛWP÷û»Ó· œïÎÛøíÁ ¢`š¼iP„ì"D9Û”v:*®À›G$mïÊ+éü§Îë~ÌÀCúC„w·V¥ZZ[Ü.¾­qö™)»ã —†€†O6?œó!ý´â'lN>¹ÃÉtßå÷Ñç}Î{îöÓéÿw:=9îÉR±4p\«ãds`ƒò|¢~!ÀÛÐBnQŒ@C—αғíw‰À÷æ;EýÆÆÉ«_]»œ–á8,5ÕÏ6Ÿœ"o<¼<‘Á F¯Õšm7‰‹õK‚0Ѝ’ao£òYòÙ̺ þdL“Z,ÕkÍ6&ªñÆï2bMƒËF¥QÑHH9éÉü*ìd`eÿ`PæY±~.ÇÇçnÉÝB=êIwŒ¹ƒ¦Ï›N¼f.wÛó:l¢SA@µa—J#)½íE{¸½?þö#]ý*o^ƒÅà"÷]7YCÞuS¶zÅêQ DNzöPVL°j‚‹lFVŒžülúׇ:5ï±0î*¸¤ç%4é±Iòõ@ûí骇¯¢¿ÌˆX& íš´£‰H +6,ÔèAöž(2ÞGå 3o8l¡ÐH©SËÁ5Vú Ú £ñê—ÈÂøfu›iLR®ò>à ‹ðÈÂ]˜Á¨ë„’üõC°‚_ÃÚ(„Õ/j>öp-ðVüɘŽM:ʑϟ؉åÏû@àüýƵüxy‘^]`-~ç4ž+ùQ& ‰äò&F߃š^Ü)ñf^ÀŸËÉLŸ5yeòè±O£Ëž½Œ¨¿9Ì—ÄBËounò—@Ÿ=`4ÐÞq3ÇÑýïßÏ ‹nÜöš¶‚tÒ¼ÓÆW ªU­õêÜ‹ ÌÎygž ÎáÇT(WþvÑßèË群9 çP·áݨãàŽôè¿¥kWÄÂ÷<‡Ö?”&ÝC-xÅ ì‹ñCPD)E^‘FãÐuó/^<…tüɘc›+/ºK&Å@ ãGp¸§cÄÂÁ`þ";_Ä<ÀÃ'ìð‰¥Œ=3fæ.³}Ìú+°­h\ø9N„|á4x»Q> ðe¼uÿ´hÛƒ“¤qߌ‹Ø’ýù^Øèk¥®ëËo¿“ú9*r^/—Ñ u0¾Íj7K~›¦mèË翤ç ù+æÓí/ÜNmû·¥®ÃºÒcŸ ¥¿-M^²™[ÔkAožHµÊÖòW1‹#å‰öü¢¥E‚Çñ`ênÿG‚A”á vó˜t £N¶Çz¼dKöGyßòåËq8ž2{å‘pM’?ŒºNȇ_?EÐF CØnàþ‰'þˆÌ~iÚÕoG8”#„<Š*‚‰B:‘ „çvJͯ®%ä×fô¶?$S(,ÀÙêE:E„ `ÀhÒŽù+¼íE›XËqÕWÑ‹Ð\!îÎÝ;…F!‘a»rv…‰/ªÇÑ=¨ ¾WTÀ0‘úÕ_._¶<=þÓ˜{ÆP•*ü #ŒôfxË‹·P»Aí¨Ó%è®ÑwÉ2+Üćf±rµ¬ß’Þ»þ=ªTPÉÙ€¯"-D‹Œ³ÑòÚ˜FË—Hòj~Ûo×Éoç·ýÈÏáêÙÕéðF‡G*P<û/ù'Mš„ †¯ÌßË3¸¾?EHª_¿ºÒйsçþÎjø<½ØVÖð0§V­ÉÑ•úÂa„8“ÏŘãlÕ—ï—¿N¨S¥PÅÓã‡þX½ÊC¿žK©…£/„=8Ç0EÙ`4 ˆ5"( /6¤#½Ì ÛËŸCîËØGç?}¾\Ïk’Cœ°¶×ûns8w?sµblëØ’—± €ãtÍ‘ºUËW-&D¢¾§ô¥/žù‚ÕoT¸×ƒŸ-¾4xpìƒÔíÚnÔ¨w#ºàŽ èå^¦+»®X;µìD/^þ¢»)Pî'(}u½Ï#Rùhù¢¥E‚‡x»œúáªqŽj 4Íä?¼‰?Ìc=xóÀýsæÌYÏUz­Y[$h5xü4~ ÀKVW¢®6tÿÎ;7¡€†2¦Ë¡]¤8^Ⱥ;£2ÃGØü±ãÅ!Ó$¯fÀÄ×q5 Å”ûcR¼ êq¨÷Áè™á»›1ûG‚. ºà‹öâÒ ,m°Ý”³IÎÝ÷^”“Ë[Ø1šÅÑ6îÚÈ™ŠoNhw‚3\C Ë#[• ¼1 sÄ¡GÐôç¦S§6¼‘ÚÓV}¾Ûò¶Ñû3Þ§«ŸºšŽ¸ôjrnxû@zìÍÇhÊÌ)´mç¶$jwŠb\úäûOè¹ ÏÉù¸@È=€Gí¦©6ÏØéKíb!ã ·\HF;àñ{ËyÚ]ãáÚ~M‡‹xp)O:x…ÆØúDäLÚ(Ï3<Ðå‰ Xù¤ºÀƶI×í€îæ—QÒ)mW‰8ñó@‹Û·o_Ï@¦jÕª%ÃqÍŽã#Ô38ƒG-<Ôt„ )Ñ™1[€ÚMòè ÁùÝYÊ ¿–c7¤Ó"IgXȇñ–ZD©5Sa¢´Z„Àüà¾M€ Nè»xìÚWÿ¿½÷´«¨öÆ'½CzHB ABH# !@M@AiŠ>±‘Œ!öíÓ×àV ~?bñ‹ÍÛòëìØQÀ×$çýkžY¼bqΉ”%ëˆ:Xg36çHÒ¤±…ç™Nkeu:/¤æ1ͺ4»ù¹rØÑQëØ°,(ò•n'9¹víýÁÀ—¤µ&Øèz Z·=qžÕ®8då ³¼äÐ)¤9š“µtîܹа[VÏôîÖÛŒ1ó{G@IDATÞ<ófãû¸èz‰2o =e¯µª-„ÁPÉ ˆ?©‚fz¾ùÐjØ#fO5u<ð@axßáfüp÷Û4™£þ`r´k=9½â/М4ú_Õ¢Yö,ª¢¢¬V- @aÕº±ËFsÜEÇ™»Ü[ýª!ógÂW?xµ"cb› awùÜìönî»fÕƳ çtž9vú±¹Ù ØÝæÃ~å€^"ï-»½:ÚÞFÈ%Bnu–݃<iD·³àwèÀî@ ÐRæØR‚ÖÓ|X¶P^¨«Óa9&cˆ i. Â#w0#úÈ%*üK¬ì[ Ué$a%eìm…­7-žµÀŽjÊA`°:®¿îºëD—²zuÍØn†=˜öàé^ iÊtš2G½C NA^’¹*´; WA.Á YVdOÄ´Ìr»ãQ ?fE ´z 80²«Uç,ß°Ü\öÐe¹!a»Ûå^V3g9)ûÚ‡¯Un\æ9O¼ôžåÊ>À 8ÿ[ç›c÷8¶quñceŽm{8;x`¯‡ðØòGt`îo8Ç€N@ÇÞâ $E:pÜíkGî ¤=ð\lÊ+–Ÿd¶BeÂ<¦IYP‡2ÐO’¡,åŠÎ79™bݵ×^û€THð'.+ÃÞ£mŽ “~°lôdÐAœž z0ä9P;ð… .•-|¡.¦,l§­vÊyÌÒ[§l‘Ù‚‰½Do$èÛV†|ÉÖ?û⟕ò”ÙÂ)2YÕWr¨+)›2¦(ލ; ðzÆ &ç¼ÀV1à àZÆŠÙ= `óEoÙªeæ£U™~=e+¿Œ°²ae㼂yDê\øVõÞÍǯžâùv|WßžÑѩ瀘† —·NZÁBW®Ó—ß/ßxó½7s×:êRᚇ¯Q©ê±];w5—Ÿ|¹™¹ìr®–Á`'?Ü#3)~› ÉÊ<ì „†zRUªÍõüXHÏåYç„zº¬æ‘@=Ð0?Lk]Ík=ò¤¬—m‰ÜÎçÈtöØa³Y÷Í Yq ¶9¬æa ¤!c/H+n·XY;0/‚>4¹ÿ<<ñÄØ1¼G¾Ò°ÿ¸ým/pòmÜ ¿mÂhHzhÐV4¯-"zî_žNJB;šOQÏ£¢¢R,@0Ãl¦#央ø+K_I©¨¸ø¥EòÄ?êcpußþÌí¦¯²Má\ýëÍÔSw;À?Pî”Q¬\R~(Si ®ì¼’S”G å‡y…Ò’gÛ¥Ž¦!4#X…N:0¯{•$ˆm‚uJ=vá«(±‘ÀÏ‘¢i𙇬vÅà80T{?ëþüç?ÿSØ&ÞÀÁ«4Ž:ÎŒ4º±uöBS×{ÐÑCöÎõÖî`‡‘Þµ õà4¸èGJ½ ©ï[ õØ‹¿½¬ûëSgx´ãÕ^K[pÆ‘Ca§KÊÙI¿¼øej5›>ÿêó€Áº¥–µÖš³ÿ‘û,q³+-£@Ïn=ÍœSç˜Ñ}G›M Ò¹½¼iÐuBùlç:޽m®~R}Í©öKª²Bõ¤åAμ°n'®Ø6µ.x賬Э‡lmú·Rby‡m›ë‘–ä(Ù¨q0©GèbÕBµJ €‡”ƒÌ¸gíÇœémXì Iäz@S µ'A‚Ü›:ÔEZ‚=˜n‡ 'iúW\¼M5J— ¦¢¢ʰ€^¥Å?Yý‰Y²|I --ù¯ÿj|-NfO{ÛÁ½&wé}—šW—¼ZZEh Ü| ¹ù§7›a½‡ånV0³b¶åÌ[êRŠ^’N’ÌÍϳH'éiYŸVV˃²vÞ ÇQ^‚í£–»ºÚÉaGN­¢¿ÜþŒ[¬“Ê€ƒyèd³ç¤®G’S…€GeªØq „‘€6€õ†üñGgÍšu(¶JºwïžIŸvÞjgÓ½SwÓ°¡!·m‡^HÀ³ve ÷½tr»}>Í-‚®›XüÉ-é¼§ŒEE‡ÄåʇåRU†ï“’E6Z Z@YÀÍJ/¼÷‚Üg°Ê(ξ½ømû+zö#<} ö3áp$½zÃjsÒÿ=ÉÜúÃ[ý¯¯µ2­oen<íF3óŒ™fùjù²¼û¸©‹|@ð³sºZhÚáL]¨+I:¡,H7™‚ü<§@ç¥ñºœ³!ƒ>#X¬òUÚ­KÛy<Ê#B•»àe×£sóéQÙ|úWZð·¶q’ WÿÙ+Ž=­jHƒºJÕv&öæFZØ{A]tÑCr 6æ¤Jšo,‹OÏ?³ñdp=Ë;ABŠë°:-Ó<ÔÕ- ª§Q{)ÿÒʧÉí˜Ò2£¨31ɲ¤PÒ<¡b=ˆ‹Md’µçÄ=͈# ™I¦I;ã” =æ ¯±=EdïTÏóF$*Ù…j8ìBŠéÓÖ#’/$­[ºt©}Ç&«¡#N9¤e/=@O¨{ ^å{¯‘rê&¤¡Ëè¥Ö¯Ÿ×¿*Ô_«qÄv伋ǯú63c ¹áo÷ü­±_¨Ýt·Ξ{¶¹`îº5àfLœa®úþU¦ÓÚNöYÿf€<¿dg]Ìgṕ$ uÒÒaY•NœT¾[Y¯–S¦)l§Óà1‡kê@YžÓ“T7d:²>‘Ù~ =dÊ!¶º,þË€mÀ8©“‘ø§1‘=ӣˢ©uTÛ@à Šsð0†çï¼óÎû$éGÆn1Öì4Ê}­»Þð`3í{ÈÞêC@žå éPW(ÚÐѶ¥ò³HÛqd\gýŠu¸s-›Ü5Wgvxæ­g0Õ”Ö¬]cî~ôn«OÀÇê€o)n `6Å·DvÊ_N1¿¸þ_­U8èÓ™Ù_šíô @7š9ÙkX—á1 ea¦.h˜¯óB¾XY]WÈ3ÖÁ> Ÿ:Bíê_¥ÑçÉÛL6ã†C ™~àÎa›Æ;âh¸,EHs©*ü­¦À`ˆ4?¨v`kù(Ð3ëׯ_‡-|39«ðÅ¿ØhJš”½A´=! OˆØ¶÷A±V¦½b>ƒúósšŸÊªžæ·KD ´~ Ì{¾Y¿SOiáÞÇï5ø ò2kÚ‡ÿx³¨Žx²Jâ™7ŸiùŸCÌ¢%‹Jk$­“;Ù³û1²Š’ÊdVåy žç+=åù®)›7OúBŠÑå5O•$ó@Ã|•ömCF`weüÜŽ´šó‘ôuJ¹#v=вø –ÓðÁ;©Ócðt’À#P#Ë¢7Éuà´­F`çAanF 6Œ4„¥¯¿þºÝ›[±bEfýÂ[ ÜÊoñØHÏüê™' {É^ƒ2jP–¤Oªw4ïÛ Êißï@'­l”«ãmÖxN·W[Èé°zÝjóü;¥?pÉœKró‘,ôí} ø” åî€}Oœ€{^¸ÇLùþsæµgš†5 ¹:ªü÷œoŸc¦šÖø|(HfW¿=ι¬Ðñ/E啞Y%Óù©<û¡ËuÛ9 È‘¤‹rºlÈë|—çûêàsêˆA#ÌgÆ|&³£C s˜|³çhˆƒ®'v$ú‚W-TË`‡ÙyN L\ÄèÒK/½…³|õ}yšüOžÔz‘º×J×{˜¨:à3 \Ù‡4Ã&bUÑÑbG^Á+ÙÅÛï¾iþqÿ?rÀ°'ø»í~›ÖàÛÈÃçwå· 65˜Ù×Î6“Oœl.ýÇ¥fí:¼ V½€]ù£+Í ƒü·x£Õ:œÓÒº6·…ò0ú´Lóim¥ÉòaZ·%y~ÞÖÐét|ê`=Ô£Lè‘»™Ö›²äÄ0‡it4æi,DØ+´Çž–Õv©…ªíp 43‰c;„["4Îú ,ÏéclŸ44dç1ï=voûÚ]=«^Ø ‚‡rð¤ä©Š‘â9âHs6‹vˆv¨—s@.a„{Þki±?ç_s¾Ù°Q&€¼€»ý–>¾¡ —ÔRamEÄÌ*;öljܯò½¹ìMóó¾c&?Áœãùfù*ùeÁ*…¡†š+x¥é¸®cî¡@÷‘ ;ãêy-<&znÓy¡qïOftBçKŸG9tbˆˆh]¾ïÅûÌšõ¸YžÞ]ú®¹èú‹r î^õ³?˜£y‚>(‚P:Ö € ~ŽŽÀ.úsÄó£sd¾±0W.ã¿»OØÝüèó?²·ðV€=PÏÏk¥´‰¹®@ð;£Z/g=…òuõAµ\ñ~…9yB›Ì×ZzN÷°]3]:Ék”ê9­Jx~ú÷Á–ak±M(°ŽØG,EÏÕDZÅPM ì6Årà4†ÞYwñÅ?"ÞÓúuëÖeú0à~;ìgúõî×ä¤hr’hó“çh˜eĨ´œº‘F D Ô­ðEÀyÏÍ+Ø¿ŸüïOÌŠUò<fJD¿{ÈÏhÛýx @;t ßE²àÐ è!¼Äå›–›sþ~Ž™tü$³ç·ö4Þp¡ùð“¥@vá´/Ÿf¦l5%÷}8ø¤¹Ìº~Ìy Mjž](G–T†õ…턺iiÊIu=…r¦™çh8×#Ý·w_“åwÿ±òwصþ / ?ýK¬#öiðg¯µµªÊ×ÂAž@#€ÒC²·^}Ý6fùòì¶ÉútïcŽÚõ¨ÜÉö*HûHʃyNNÿF D Ô¥ÐÚW<|Ej÷ž}ñYsÕ-WùÕ¼ßúw?­kW÷xÀΤNfç4àv€‘œvèžsà vìÞÑ<öÊcæäóN6£>?ÊýÓ£Ííßž»íÚ»Ò2ºtîb.;å2Ó«C¯Ü +³¬uvš÷ߟ3#a¾ñ¾anyà³zíj]s³øm·ÜÖœqÌ~ÀB’†ÌÈ¥„`.óà¯åi|RýZ7Ì/5/ÔÓcAžŠáô€Í˜ƒ§¶^Q˜…ºÃn‘Šò¶’Ö;ÄAiE})V˜§n1½Jó9PíÀÚ ÞX‹-úH¾žô¦G¾ÒнKwsÔgŽÊõ½)›xÈJמLè eäA g )å‘F D ´Œ8o”éhöM³óúðñòÍa§fž~ùéÜ–?¶øÝýö¡>€8wdõÛÿyµ¸„kN‚Ý ÀíÜàsn@;ä?Zó‘¹â®+Ì~ò3üÀáæèŸm®¹ã³lŲ¤– ʾuè·ÌöC·÷Ÿ öÏà#AIód:é²À_סy´¦Ù6å!EÙ¼¾ü!ÖÏ9 ¬.ϴУ÷8ÚôìÚ“­UL‰UÀ.`˜TÈ…­^ýCFð§+¦{Xq?J­ VúƒjOG€F¥°öª«®ºq?%Ëpð¤ƒÍ›oÑø]×+{Òè²Ç¤ÈïbžäQ'‘†m¨:õc¾·y´Oãùm‘-¤Š[ž¹Å\r×%fyÃr3÷_sÍîßÝÝ<þâãù /€ïWþqlëÜõ švŠŸð»tàL„Î@p‹· VÉ¿ºÁ|õÿ|Õ:3¿5ÓüæÿýÆ<½ð颡SÇNæ‚ï_säûP ¾ ÒöyÎICÒ\†ºÝø<ðj½4ž6)”¯ó¨öB9Óè À_¥=ò”ƒºèõ™apßÁæ²û쯴æ±Êa—Ç2d©¨±OõÒZÕÔ,tð VF“Öó-­œòƒí¥ƒ´®»Iìá¢Ü¤2}$ö–¸™‹}Ä?îÕ«×f}úô1={fç©Í[0Ïüòo¿ÌÝßÃÅŒ ^º{µ‡i+ãg>9 Eó¼ÈHCÞfø£ËP‹YÑÑXÀî‰ÛoçË ›„_- é>¡kWîXµ˜´íJž_,õÚE› ý¢Ã­m›,€Æƒ{¡ +\WfH¿!fÖ.³Ì¬i³ÌŒf˜AýÙ&’þrÚ!fÞ¿ç5ŽCL´ã€ƒƒ1¤ý• V!“£9a#ßÜ´«.¿I¨£¨_áCrê Áyy2±Ò§~šÙoâ~l¥bŠ'ÿ± ßÿÿäè£þ•TˆØ>q_¶CZ>'ið~;"^A¡“àŽ¦ G*Ùé¡ìf­Ú¥¬ZT ‡ ƒæCzõïùüãw¢CüMeðY„™ãfšýGäŸ8Q¸uÄR¦ÒþɈü‰Å“PÓGºPLi£`™BõżÂöŽö‰öq“‰uüÝÃz~‹ÞݯÇ2ÅÞ·GZ¢¿÷¯Á²ÔsIO^R>mGÀ·î¨­3"¾dùsÅW˜cgkF~v¤™zôTó_gý—¹ù¾› ngèpäÞGÚ×q À:>ι ³cgåp,˜—Dfç:ä¹tYóRX Û*PF}EýͲaÒŒì7ÓBáÄ ë?,SðGWˆQ³<†I–æ‰w|ôŒ£®iÀFT-ˆÃñ€´ÃÀPÚX¸ ðäÁ| È{àáŠnݰiMøÚŒ¯™Ù7În<ÙôI‡2æxhpÑ“‡AO9IåuÕ¨¿òÆ¢Z·ܵ ÞÔiSî=ö&åÚÛÔAÒX#ð®ú!‡Œ¯þå´š÷—×4û€ºÐnGù#3d‡M’ÆL©a‚3¦¦˜5uZÊÌk¾™ÿÆ|û±¡Ž2ÕŽ5Îì6y7³ëÄ]-oç/Ö­ëG_uÐó䕤òIõé¶“xÔÁz@1ÊK¤_ß÷ë¹rý6áVµÐ`–TË•=)pà¯GZóP+ƒÃ©ÅÃæOA‚?)ŒÆ¸N>¦ðÀÌ™3gá§³töÜnO3eÔóäk8^œô–/ç$ØÉ‚“)õ)+ÐDÁ,”×õjY䣢ʶ®asRj±Nvûÿ›:眀4À?q;Ü–(㾦±!MÛ>qîÁü9gN™);l”>¸Ÿûí°Áñ’¯ù7šù‹rÁE—I}ØÅð;—tÐû!˜wšl9ùMÊè|Í[Ŧõ[1ÆÇÀ2¤’gm®Ò¶H£œP?.—†Üßfq²I£'™½ÇíÍV2¡üÙ_Áª¥B.b=†‰ŒØJ«£Gì)GE*YÕ<ÔÕo)×§#Oc€Ò`yôÜsÏ}@¾«¼·YrÕUþ÷kÓ¿–ß#éßêR=õ2}¸4]ò¤kžzåRÔÅXn±\´@´@ôøô-<”g·àÝý~ËãA=·ýoŸ X0³²#êÃŒì"Ú±íº§¦ìƒ’Æö¿ïcø&¼VرgGûÿÌîõËSWƒmƒýNšK‚ù*sðgÛšb>e`û¤”“&èú9šãš'CY‘}m/™ó3 À$`0J^ý»_ªÎÃ/•ÖX¢GÚH3ìiÓªjµ [Æ@1x§:yxFô’Bjí=÷Üsï~ð E–»x5ïÞüäÍÒ|J@ÝEi5Ðc\¬*Ú]lÛA†@Šr ¨‡rÊ*¥ái“uý•ö/–h%°«~<].×uxmášÂuL¹u´,+^]˶?˜wdÀî  ›x`íCž1›†rÙrn©Î'èÙ9Yë3ŸÔÕ}Ü>Ç™-ûo‰dˆE›ÒÀ?m€#ʬ?Í­¨ÖŒÀƒr”N€6$ß•\ûç?ÿù1ñ¸Va€†GeY„/ìü3rÐȼž5{Ýë$^:â˰SÐC MâY—U¬Ò¶¡ûQ¥¦bµÑ­ÒyÌŠ`-ÕéZ Œ×k¡öè°B­Ó"o)ðË…öÙ{ï ¸•¿uÜÛ cøFƒÇ’ÚÖóGÏr:²0­eÈc>©Ë÷}¡N 4oý-miŽÜõHÔ˜Y¹éUÀ&©˜¸å1ËɈkëô(Ð'¤kpê´Dààé·Ñ00ï™Ð˜¤Ö¨·ÜrËèp֢Γö9©Ñ EϤWþ Rö2÷<#r£ñexH9ZM9òPyRžÖ«”g¤•ÖËç.ßh‡¶e¹í´\ËãZÎ5Éùý¥ã¨ßp;Ü!°Tž'°ù~[#7ÞÄ•?lÀvBi„BvÒe©G)å¬Kä¾/Z¼‹ys­–a¾F}NvÒ2·gˆA“€S!ðCF<¶EØ3=âŒ{WZu-å w<'ŒC#ÑÈÉ_så•W>)]¬€çÅW/PYaçÑ;›ý'ïßx¢£R}ÈØc¡¡‡éGêë4yP­«åÌcùBza¹rÒµj§œ¾Å2ÑíÁ¼›;Ö´¹!Ü CÀ7 @nmøWÃ~èv4O½P¦Óšõ™GŠ|ðIi-ÞÏÁ”ƒMX¤÷Ýi_3mÌ4H2 À``ÑJ`’TLð'%økLš°‡ìuf}*§¢–p0p€‡PK ”^•6êZ1øßQ¼v‘; È(|kæ·LÿÞý_—÷2yèHÙó„´÷\©ÃÑB—|s(Û(·|©mÕªRûõÊ;_¢ÝZ‡Ýx½5÷x5·æG½;.¨ì_ÒüÊÂ4ÚbyM©GŠ<ÅçÍ»ÌC>uHU^8ïöëÝÏ|wÿï¢™Ø Øƒ ýq¡â•Æ2â›î5zŽ@šKÕðoK8zxêÐÙÃJ#q€N€6ìùÔâÂ÷ßÿ=x`üõ%]i%|ïn½Í·g};wHÔ¡òdÒó¼“ÍÉlžûãË„yúpk^.Ä£ c!½JóØi¥õÅòÑÑ9 ”{M5§\š.äA°sU kK åÊÖa]¤h›¼Ð&ýQyÐós/ʹyÚÏ·Ð…LâIdzwÇÏËd€9À`Э·ÞŠß’Æ•‘ÎÁŸ;zõïzœ]ŸÊ­©¥€àpÚC£ÀH0XèhãZþ׿þõõrÀ7á>̆ (–]˜±ý ³ÛØÝr¢§aT‡/ï¤ õPïC-Ó|¨W,²:Ó¯$¿VíTÒÇX6Z ^-PÉõò¥Ž úaH¨ó“£’tµ,­¾rtXiP‡ïûPŸrœ‹Ì‰ÓÆM3ûŒßG×^1¬æH6ýæ7¿™#6Á&‘Á Ѐ°·èzÞb¡¥=`†a,Å XûÊ+¯¼ÿ /,@EYï ÎS>Õ è5 wx\ϼ×É“MNÍ3ßZ{ÂR†Ê\¾MjžùåP¶“U}i}ÐíT»­´>Dy´@½[@_'åô•åK-›¦Ÿpæ©®?Ô ÓÐ ea:M‡z¤li‰¾O.mÛ!Ÿ6Ç¢>Û¬òq÷ôÃOgí™Qb °ç¥—^Z"sů4ðGÙËÌúTIE-éà°"h ãРi`PÙÒÙ³gÿM<²õ¸ƒcÈ2ôêÖË|{w+=tÑž ú0Š<ñ¤EgXŽ Ó”“"?ËÀö²®7©º-òIzQ-ÐÖ-Àó¿’ëŽu”j«4ý9æ+?g…õë>'”µêZ‚0$K«‹ºº­KÞåÛ~Sææá<òDþíÏ~Û`Ï2c€5ÀÁÜûÏÃ#Ik¬~q7˜†ÞºQäèM7ÝÄ´dµLhI@˜JJ'€¤aµÁ×ÊVLüyóîCEø#Oì¬èôí¦›™gæ{–B½Š|wjšw’RGëOJS^) û]i}¥”ÛÔã.¥|ÔÉÑõm‡ð¼bÅŠåx(C¨ˆ² §|šùÔÐOålþDu'/&/ǧG%|Þ/Y1ÝÕ|R²¬Úd̺îBõ±Í*ó¢êÅáy‹t%A××ÜzX6,— ÇÜcçè†}.–fý¥è%éhY/2?72ÑÍ¥~nU2ä[9ç[¡c†1?9ü'ìqfØŒ‘×ÿ–«Oþæ-H¥1U:è9‚¥õ°úGgZÚ@pu„á´'Eð·À/yp¬#pÞyçÝ€_fÊú@iÃüô°Ÿš-n™×;ëòТ׎÷^*G¹Š¾\p"óD·§G˜‡t5#ûJZͶÒêfÛi4­\”W÷ÜhöM;!Ϻþrêcù°lŠÜƒgR>da="Ê“%• Ë ÖÅ4êC`ZëŠÌƒ8òÃ(ºMæTèÈœjåà]}Ã7?ûÒÏDm¦[ÐOùeÚ¤v`Ç—&.ø‰[òF%ÙõZÜPž#OÂ& š¶`=°Gyä—_~y! ó! ðY…¡}‡š“<9×3ôÎõÐ_X”‘ꓘ2E­·«N\±Q]Ò\ªvU_}ßj×zrKI}*&K®)JÛ£Š+:¿ö©´þBå™ô;·æG¦Gr —eÔÓrÍû®|sÒ˜ÛX§Ð¼•?äad¹@îÔéòN>äd3¼ÿp¶’%¦c€5R±Å¡X”úÝh—&^¿8«Kvî((̃¬E~Kªž7>YA‚¨òáJûekôÙý:6ËtùéOz“| è¿o­GÂf&œdŽÝóXsŽWä¼T¸Nú¤D‘º©ã¦ÆokCŽˆ@w :DÌ#…žæu:”#¯¥B=õ¥¥lÛH³æ‚,B¡zRò,¨²í$$ôCy˜N«3Ô+”æ /:yນ§ Ó=ê¤\SǽÏÑfÇQ;²‡™Q~ïýúõë€1R1Á”àÎo»Ð;%Y_Ô¢½R³>Ô0$·S@idP{ðPÆÕW_}«È«v+à+Ó¿bv³S®‡®§yÛPª÷MvÐ1œ , <iÈë´+ÇòÈj±ö…éëPl8Z …,Às_ÓJºR¬æ'´áÁ?I'IÆ:§C˜f^(oNZÍÍ´ƒ(u„sëŽcv4_Ûûkìaf”[ÿ¨ØâüËÃÉÒ˜¤± ØEðgïÂ:TÛâ¡.€À 4ŒGO †åÖŠ @n¼ñÆ¿õÖ[oâÀUã@ôóÌ£Î4£·ÝxhqBòTnGóäzTŠOôp‘:¨—”¦,h3¯Œ._+>ìÓµj?¶“ÞD{dgžË!ÍÊÆ¬7­¾ù˜Gü\½¤:Dœ(OÒOÒMÓ£n˜¯Ó˜ÉÑ'‘ù~²Ô#yÞÜ ¹‹¾¬Ko½ÅÖæwÇÿ=È<C€%À`‹4@¬Ñ¸˜D|V·ÔˆDZ‡¡nåéÓ„1éYÑÛÒ€Û06ï´ÓN»Nšý6¶oªf1ÛŒ4"¤ý ËÞ;jåàõ©@tNxï »4ˆ ÐÓ!Lë<ò¬›”ò–¦ìO!ÚÒ}ŒíG ÔúüÔí¥YŸ: ù˜;ìü<è a~z›Ô–Õí$Õ£õ1÷!ˆ¬É\Dz¤PgƶO¨Ô‘'—4~â÷Çü5g€|ç˜" páI'€¸CùÄ)`FÈQÔÝê_úfêíô Fs‡Þ;xžŒç`ü®ŽÇX:‹×¶â/ùË?Ž9æ˜CðÞf×®]M§N(–]°t²9ùRy0÷ÄÑc¸U QN>‰RWÔmÐiÍ#3LçJ¤ÿ…¾ì–Õ öµÔ~Õó˜JCÔËÞåžOÙ÷¤±ÆrûT œÆÆšrIe“d(™$O’iÝ0_§ "÷}…ŽŽÐqi¿hBš0Šlì´*Ù÷ù¾ÖoJf°êç;ÿÀ`Š4ÀÇŠ2 øI!ø»Ñ$ZTÔë#ÔÍÌ‘² Àí˜Û,pCoÌœ9sæü[žØ|eãÆUy+@Ú5GN4ßÜï›'(ÎÍàM<¡õiA^êóÞ-*G@ƒæ! ÓÔ+…²MMK)WÏ:z,‘ÏÑõsÆêcÑÜ^±lB9ÌPò­åu(P_â¼–g]”“&ɳW8·þÇÿavýCžúvÈçæ_–ˆ8ÃŒ¡@".£0jî ÷v ÛDT?¡®€À,4( ÃÒØ< ¤<0ÖK;õÔSo‡6VWãÙÏ#v=Â|~×Ïç9öpëž;ÞŸÀ y¼ðjæp¤aŸ(4Z Z ù¨ôzÒåZ/øQaºPû uȳÒ$¹ÎÞ;*눲.]tŽt»‡îv¨9j£Øj¦‹}`°ãG?úÞù®SÂÕ?q‡xÄ…*h8BÕg¨;@yJ4¢;ìþÁŠp'€ˆ€=0²³úw¿ûÝurâÙ_ ÄA­FøÎ~ß1{MØË;y'1zÎQÍËSr¯uÞÿbg¡ÇÀ2iiÊ+¥lGÓJëŒå£Ú¢ô5B¾Üq)¹ÁÎ…êOª#IÆ:’ò K Ô×:”¡Œæ]Ú÷™y¤J¿ÉܨæN›çP`ú¤éæ??ûŸ(™yFàÞ?ú ì†H#zâ )Vÿ`╥´Ìû\i…õú ÇcÂIÅ^7õq@ñ< ¿`Ÿxâ‰'ÞzðÁßc=v‘O8š>}ú˜Ž³÷yN?ìt³¼a¹yâå'¤ ¸ÜwtÏÑk‰>Ï¥íh'`‡"„§ùRÒÐÉ: IA÷+)?Ê¢Ú‚ÒÎÿJÇV¤^žÅÚI«'MŽúš›ý°ŒNkõˬ×ÌâÔuÑê02ð,´Ä)ÛN1g|éŒü:­bå°åŒ@Ìx Ø!,Á^S:ÜþøÓp=µ#_÷!{4Ì`ÈǤNïeÑóâAÐHo×4œuÖY÷|ôÑG»Ë=Ë‘AªøõÑ¿6GM̼r蛜Ôó˜N¡¶<ò4Y±4ËU›¦ôŸwµ›õG dfBçrfHEº”zqýÛ9 %?OÎÈdyŠ*‘T†ÙIyIõi=Í£Îs¬pHÖ%´É< =–GZâøÑãÍoÿ­ÍªÆný+€Ò·ü5žgˆ;Ä!®þÕÈr½ °¬]¯¨Îºt0"e8§ Ê[8ôÊx€H!_-¯qüE¶s6ൎj:¿?î÷fÜ–ãš:î$ö¥¤=ÀstšJ§¡ëuF€ŽÅÒZ·¥x=®b|Kõ1¶Ûv-PìœÓùÕ´B‰íàš·×})}aZ7IÖÜ|­>©NÈ4ç7æcþ£ëjÇÉ<ÈÁ#°<ÒÇŽkþ÷?þ×fUã0Á½ò·áôÓO¿FÚ~Xìp¼ÆÈ9®ü‰Kè1G¨1LÄõêÖÌE£ò4 €$'€ÜêÅ‹tñÅÿ 'œ<ÛaòêÏ,ùǯÿÑŒ>6w2ãDÞ ]v'²u_È#/åBVßÔêèÓ <ë 5@ue­…²ï‘6ãh‹ÊlÑRç~xÜ ô×8£¿Ž èç]ÿ¡g²PŽ4ú”$g^R~©2Ö!ó“v¶ƒùм²IâÜçêÐyÛßÖœwâyUæÔ=ðgû Œxçw>”FøCDÆE¦^ýÓ­”y?«Ua];Á.€:},”Âøá.)àš;î¸ãE<Câ^lT˦æÜÿ8×l7l»Ü~…œÔö„Ö;Ñqaä],ÔQù¸h­z 9‚Ö£nx êt®Tü--P- „×d‘vpM3QmÌf’¦\’N’L—D~tækôuÚñ2ªÆy sõ¨#c·2=G1O½J ð¿àÛäê¨Â_`ïû?ôÐCO#¤®ü‰ÄÐpõ¯Œ†#j«˜´®tPžF44<Í ÀÁ ãjÜÛyûí·ß•v°·<°ªF²bÿðµ?˜O û”_½äíè¯=ÞDïÞéx=m ò ¨7)Íö’¨Ö|¾ý¢=¢=ÒÎðZJÓSr\¿ŒyשÒI”³­Bzi:+WJ~XN oÇ`§\Sð.ú9 ³w ãçHÉ3lŒ9çÄsäÙçê€6ªðÊáy'œgÆ]Ïõ‰N/{!q„¤èxÖA'@Ës¹¿º,åÔeºei´Xù˜-ÐZ,vŽ7÷š‘ñìI›mÝ—b…©êëwZ¾–³n-C;L»ü‚s–ªÃê9°÷u$€ÿØ­ÆÚmÿN³ý|»6žC”>mœ={ö_€ ’Oðט¡±0¦  °J7Y·|«pëñ4…ÀˆÛôÒxàô–Žç.\¸X¾ñ<õòõðÕ x0pâÖòŠ /uŸ‹2KeDÞA€®)ytRòìåx_M¸?¨C×¾•ͳ®B´ìÊcÁh -Pè¼ ó*h סŽeWÅ>•RAšnšœu¦åk9yP(‡ÌåÙ9ˆzÌ'å|%i;§©´­Ö¥ý|'i¼êWÍþЮÞù<ÿüó‹E¬Á_óÀ ` q…÷ü‰9h« ­Æ<+žf 0>½3¬$€tõu×]÷ì<`¿Ü' šJ{æ÷_ý½™2zŠu}â{ w£ò G¦G A('^”[Ê?,Ë4(ëвjðl;+Z>–RgVýõäνZØ¡”ãZ†¯9Ò2ªh,¢íÐ(Mç¨j¤Éµt’‚–³-CÞrP ‹Ðåb'!ßç‰þä1“ÍÿžP½Wý0 Ìñ˜ë0÷„õ Cáó0ÂåÑ ¾kÔ­`”¨Õh5L© ŒÓ %íÀÔ,Þûúë¯/â‰Qm'à7ÇýÆì²í.~ÏÂ?ô‚QhŸRÒyN@8ZŽÚÑT]^tR}Þªë£Nk Á¸ýѯ¶¼5Ø&ö±é9^Mr!Å¥”Êiƒçk©e‹é³Ciõ¡|˜ÖIÔE]­ãø¼¹†ùš¢,uõ+ÐZGx;÷9(ºÝTsÖ×ÏBËU zŽÇœ¹_KÅ—§ÁŸøB€#ˆ56!ÙjB«r«ò4%t‚â ÑS+i'àûßÿþœ>øÀ)Ÿ„¬føå1¿Ìýv€»PpAÙ‹Š£AóŽ—œÜV¿’1ÏözBíDåôm9Ís›²ðŸËËUÿF ´ 4¹Ôµ‘h^£š&*&+)“P]žˆuç %‘$O“±,òHomÅgt>ë#•¹ŠN“oŸyBý|ç¦Ùé§›3¿z&j¬ZÀœÎ[½˜ë1çKcÿ$€r þú¾?ñ†£ªZ¿kQq¬rƒý^}¹…]9YÕ7»†Ï}îs|7N (ž±¿ ´«‹Ý…öØÓÅ^B{»ÞÆnݺõ¹ì²Ë¾ÞSB×®]íoH^UÃ…s/47<(?6ÅÞË:tÄi–QçAH9)zò”iªyè Åò]Ùj½žS¨k1/Z R™…,ª*·ŽRË5G¯˜®ä<º2#XhÈ;™×MX´ä-tDÿ°Ý3'tRf‡,­"ü¼/¾ô·JÂñÇÿgyø{¹èâÃÿŒ¸/€ˆ4äCpôý>€Ñr„­þˤªò‚·uyÅm©V¹p+€„ÞY±]`{ÏGNˆ•'Ÿ|òUò€Èºj.˜ÇêÄY'šïü¿]† Ê^ <­8"Pæ9Þ^|ZOËÉ£!ð ”“RR]&ÌSéB«§RòTUuÇ–Òÿ¨Shö‰Äk!‰6»2)ÖÓÜ:X¾”rÐ-X_!]ä鹄uŠÜa®úu]äu9ès1É|RÑ ÁÿÛ‡~»&à•?ætÌí˜ã1×Ëõ½~i«â GLZøÓÔ-I±bníAfv=Œƒ…ç†khò Ø)ÐiËËç‚?üùÏ~í/~ñ‹£ä$éˆÝ^½°AP½p跚уG›?Üü³hÉ"Û«Mä—7É2½Âj§¨D\þ—ÜæÛ dJ„(BH™—«ª1?§û[(OëUÀs,T‹F 4µÏݦ9µ•”ÚRõØûRõ¡WH—y¡ž“ç9ÚÖzäõ×2aQç‹ÌÖåd#4ÿù¹ÿ4“FM∪Fñ®¿ÌåFnlÄÜŽ9^+ü±ýÏm®ú1:=ªõ»–fZeP»è? (½µ´çÒN€†çž{îÝ3ÏtX¦}u½7Q×õ@‘Aòìü4w°)˺2ÞÙ@¾Î nž0z‚¹ø»›!ý†°ÕªQ,Üþ]tÑ­<òÈÒ˜ž÷9ß“"/tˆjTöhØ~ØSµ±T»âVíÀ8ê@ð$Å :áÉ O„ü(ÄUW]5 Z«Œå·_ý­™5eVã…$#È{.#Âþ†;%ñ*Ïw2æ¥^˜ú"‡¥´µBžù¤º Ê"mœ¤£-Ú®-ô¹¾œc-Ål(¥,Û+¦ =îy&éêzÈ»nðÚ÷sHXú±œKÛÅÞï§œí»´­u‰læŽ3ÍÙ'œÍV«Jø›«¯¾zÞí·ß¾Pä|йž1~½ìàiP9H¶êОÐ@vyw¿q0q7œx¦I‘Gy‡9sæü»S§N<òÈ}à Tû™´qÊçN1Û ÙÆüéŽ?™upJ®A< Ï$øçx:¢·:@ÎP®eŽ·»VÕUÀz€´æ­0øS,?PÉhVcžÛYv¸Ô:›£WHWçicri ÔzŒ3RD`™¤ˈ.ç@gçNÍ×øºùâî_ÌÕQå¿ü¯½öÚ»¯¿þúK“ ú\ðab×Nïû.M«Ty$µ«¾M8ØP¯â”˜ã "Öò ŒZžÇËIôl—.]:~øá{ÖÒ 8l×ÃÌŽÛìhΜs¦yù—]\hè!GâxûZdÔ¡^Šm?BÖL§âÛÍ•hü[,¿Q3rÑõcž·ÕîQ¹í¤•+&óuÚñ¤1væè)ƒœy¤x©KP'³u ?zøhsêO5c†ŽAUüo¸á†û®¹æšg¤Q‚?(‚¿~ì üA¨]ÛZýËØ,Œ€¶ú n`,<5yq q`ùN'¶zàýÑÔ'ßµ'Ï•W^ù¤x’÷âÄ®åí€QƒG™ OºÐnŸa4~[ #â)©xôÏëpôšRWËÀ#’å4u˜©®#Ì‹éhZY@Ÿ‡…øjöG·ÛÜvXV—£ 4 :OçS}ÇÛ9+x%ósI(c],ëž3²°Y8ŸˆÈÎ?"ß{ÊÞæ’ï]Ò"à¹s¶t‡à¹s:çy‚?ænûÓ VÐp£‰„crÂÚYÍW&šIDATVþ·Mìð¨}úâTÅ4-rMæã^ÒS ëŽ;â ¿&·ÐÎi‡Ÿf>3ö3æü[Ï7K—/µ½·¯ ê^¢ç2jÜ.Àý«‚¹œÜ¨y:Û0ÃQÈh5fiËhʨOJ´|êµGJ۴DZ·Õ1gqL“êH’цÈKÊ×2ÇÛU¹.žz x[6I‡2¡Ôéß§¿9é“r_:e{U¦jå¿éòË/Ÿ÷׿þu¾4©ÁŸ J9®þ üMÜ›¶þ84mÊÀ€'ðŠH*C¤mÀ‰'à›ßüæµv¦ï0Ýì¼íÎæ¬›Î2÷>{oî™ !FCªF柀 y¹T®ŒðÖa`>)ê“`ˆ›+òNÏÖÍË<=QÇéRg {˜S¾pŠéÕ½ºßNáA5øËÓþ·ü…«~:…ÀŸFG' M®üiÇ6çp`Žò@RŒÌ !‘¼¦ZÏò8Áäk’ø¢ÔÁâtÄÉß»7¾,\ýУkó“#~b¦Ÿn.¸åóþ'ï[PõŸäÅHƒgòvÐEèÈýĀѦ¥g”E@ÍCÆ4xÖ©e¡ŽÖC´@½[ <Ÿ+鯮Kó…ê„^¨«ÓŠ÷×7ê£<‰j™â ê¶,卋އPê Ü| 9éà“Ìžö„F;ð‡üH?6ž}öÙ7ßÿý¯Iã\áìµ ·ýápË?iõïÁ¿fj¡†Zåo”b+õP Ô¹½Êß åotž¿Àß°¿ rüŽxPäõ˜:uêÈÿøÇŸÇ[øí¼б#ª®MhXÛ`.¾ãbsó?ont¼…"ºFp¦^(+”Fž¿+ÀºrâÆº™n ëjNÙ¨-µ4èeY7ë%-V7õHµ>eŽæ>ô‚ü‚ièJôu¸´m޼¢ÿƒv=Èœxà‰¦g7Lµ øa¬üñy_ù…¿òá¶›{ì±7¤u þ~M™Þ÷Ç¢o‰…«; joý·ôo´YG/Å ð3b¤‹D8pàÐÀY­Á?Ï 7nÜÐÙ³g.o X'@)R»ðä«Ošsþ~ŽysÉ›€ý}|E÷¸ÌeIi-Cx-1åò—õ{ALu”Ñl,ÒŽ,P«vહÔvtŸ4Ïò”9êAùÌÓ ´û/ùËä¶À(áM·nÝjöš ÚÓaþóÍåw_nžzù)+Nsü$Às±$GµjÔ¼m±1ß;aê’S'©~æE-Pª0½W#¤Õ›&gÒò•ܯÐY&lÊY¦•<ÍCOë2­(Ûž¼ídó•™_1¶žÀÖjJ±å‡ýd»ÿµÿþïÿ¾MX¬è¹òàƒ×À_*øÃ¢ˆyMÁ_Ú;²Õ;Ô$NÀðRÌ àÃ!øs'À;ßûÞ÷>³×^{íÐmI'Æ|ðùÍŸnÿ“y{éÛv”Œ1R |;  Ë:¨„ÀLªeà\~ž3€<]Žº¤…ò¨ÒrÊ„uÄt뱬Ö=.ÔnZ^š}ò,HkyPòs(ÓùÌZð»¾pÅ?tÀPsÂA'¼‚ÜRà>ÝsÏ=Oýñ|Xú¢ÁŸ+ÿÐ €CÀ‡ý@yÏ_¯ü ü¤5ص¥wÚúk€°qRÀåHM ú’¢e yQNЇÞyç:ê¨âµvÀ«={ö4µ~8Ý}ûÝm¼ù±›Í•w_i>\.?…‘(ÑsðŒ‰¤ùmÿÁ!ê’J±&õhK"àÊøIÈÉmÝ9Ü_곌Πy­Ë<´Ó’¡¥Ûoɱ·ç¶qÜ›sì]]h¹æõ5¥íL¹ÖE>Ò.æÕM=•ïû-2?>æsÔÌ£Ì禕ÿpšîf9<ŸôÇÖ¿ð›äCl÷Êo³<'u%?R‚?€’À¿œ~¶…2mþ!Àð ©]dJŠíà;ÀÕ>Wÿš2¯ûöÛo?äç?ÿùçd +„ÚRaåꕎÀõ\o>YõI#èHA1AWù©»ÔÇà¨_ˆóTºÉ.òt½9IùÑßRB–m–Ò^Ô©ŽJ=ÞÍi½X)ùy€¬Û õ‘eЧŒàÖ!ùܺ·Y¬‡åÒþÍzmf¾0ý æÐi‡Öôc>zàõÃ~²ˆZ+óèMÏ?ÿübÉ*þ¼%Š{ú+Wþ¢Û"«´ÛÒ;íÎpF×Ó;øR};€ŸäXG G=eGà°AƒõG›-}K}À.Àܧæš9Ì1ËVÊ´¹Ž˜ ˜FÞ;Ì×<Ê2¤ñÈ×yÔ'Uy‰Î'¶}Š"¨ØáyV¨ò=ÈCGÉÃ"Mò´n_H&y¶]èP¯ï¿wø÷Ûi?3 Ï€&ݬ¥€[þhóý÷ßÿPžôÿ«È¸½¯ž«}PÈI¹êoàqF †ÏÀà ÍØ àk‚ØÐß Ð@È# Ýî§žzêÓ¦MÛÏà£AØ ¨åGƒ8^M?^ù±¹óé;Íßþ›YüÑâF W€›þ¶êMu8 QÓø0Ï6èSVMtʨ'i_Èò¤¡k€MʧŒ×Ó ¡L§‹ñÌêA_׉|¥cy•&ðé?ĺۡfß÷5ýz÷C -°å/_Xµ÷AÿäÃ> ~õ«_Ý/ '­ü ú~®úéð5¿º]ùÓØÑh! D'_ ? ×àÊ@­Ã0kÖ¬må7ö‘g:ÕÃ-é—w?{·¹ñ¡ÍÂ76:È%`kªù@'hC=¶F¹.›”WHVJu8ñ1i´@%H:Ÿ’dl#)/”é´æQÓŠ¦‚>õ•®–ÛnËíÌç÷ø¼™9y&{Ù¢ïõüAeûƒ|Óÿ®¹sç¾$Â*^ƒ¿} üüü¼ç¯ßóÇMX†TØ–Ûö·»?ÑhAÇ L'€»¼%@'@S:v'@nlþë_ÿúàôE»õpKý`xò•'Íœç˜Ç_x<üCÐf:‰:Y¢3€†Â2lœr¦IÓäÈçDWH‡õD-PŽxŽ*[H'-/”3MŠöoWí”QžD™.·óØí=þÆìTh45ÍÓ[þ|ðÁ²ÓN;íï²õû„+‚¿¦à©Ç-ÿVþ0vtZØpAÃø¤gð­ìp7€r°#`G»É í:}úô rK CK~=Pú“^|çEsË£·˜ûŸ¹ß¬\ƒÛohPÆP¦]™Tg@ë‡<Ò l›éH£ZÚZ‚mZ_Òòµ\ó¨‡i¡þdJn›KJSuÙFG™^Ýz™é“§›ƒv9ÈŒ1Ö­‡?úA?éë¦xàß¿ÿýqÕO`'àsÅOJð‡>ÁÛýpøqP®øIET+Ûù€:pp0vu~8¸~0(É HÚ€ Ž€Ý9˜(§W'åWT "îû ]#»¢·=ýôÓïJ÷útð:jàOÞïÇÖ?¬ÃoûÃB´b‹=í/}H ѨG§'Rž à-€Z'@€¿›<è2k»í¶‰¶ñùà–úfÚ/¾µÐÜùÔæž§ïɽFHe‚®¦ä¡Cž”åtÔø[)ùZìëÌÆD´@•-à!$h‡rÒ Û&ƒ<ÖÈÔyäIu]Q®(ëÂk|3&Ï0³¦Ìª«Õ>‡€U?îõãÝ~„_|ñMYÝ!ŽATƒ~Oýð~?ïù·ð‡¢PG€; ®À3b@ïÀ à-€:ä–¿~Þ  Ì:(sÈ!‡|ê¸ãŽÛSntÂnž W%«þÂòUËÍc/>fîzú.óØóyËä­êi½4Ša!“õ(u!¯^ Iu9Ê Q¶§uš[‡.ùÖo¤s¢”Q•RN`ȯêYgR9ÈÒä(Ç~w³óv;›áì:¡® ¶ûù#>ø¢Ÿ¼ÞwïÝwßýštš+x½òOrüÔC9Æüa9‚¿wÁêüq£PÇ€;@FÀÓÐ;tø†œ»\íøIµ2[Ïüìg?›1iÒ¤m°šÆ›¸-€µ†°¢a…ytá£æŸ/üÓ<ûʳ¹ß @Ç•ïAX[]çƒ×!ÔÓy‘(dn!´¼´²¡¼PšyB½Óìdø&ÿøÑãÍ®ãv5Ó¶›fz÷ìÖ“º’¯]»Ö?ÞëǮųÏ>ûÊìÙ³ïu÷ú5øà¹ÚGšŽy®ú üXñëU?Wþ°kÖþèhtêÜpIà xíÐÐÒ €×àÏ¹Þ °»'NrÊ)§ÌêÓ§Ýà„Z⇅¤e‡‹X‡ÎÀ¢Å‹Ì' ò[ ΪÞ)Àe¬-è1ii’^ž‚J4GWËŒu“zfõÅŠªkæ¯$ÝB2É ÁƒÙ¬ÇffÄ#ÌÄm&šOý´ÙaäÕcƵó!??ÂòåËWuÖYwÊþïI’ÀÏ-R‚¿~:ü ü¨`ßêÁ_Æ€Zþ0 ^nnR±ú‡€H'€Ï`ÙÎÝ:x þz'€ŽËt=þøã'tÐASð ”óŸö÷Ú!lEañÇ‹Íü×ç›—ÞyÉ:ø¹â%-1ë7ÈuÔ”qRe:mÌÅòÓÊEyÛ·Ï¡rFZ¬l˜¦]›;v6ƒû6à 3#‡Œ4ÛßÖŒÛjœÖX9½jñ2Xåó3¾è ò»õÖ[Ÿ¼ì²Ëž‘$ÀNàç _S?õPàOà'øÓ€•…­ß‡ýlçþÄ€V°ÀãVÀ   w° ÀH@Àä5ðÃ9`šù Öðï.·¦O˜0a”¿ý€vêõméw³Ãk‹_3¯¿÷ºyké[N~£?^ôá'šÕk1'”²ÿ¬ê)¡ËQ¥ÊHâ²Z̓šôºwínúõégúoÖß é7Ä 8ÜŒ4ÂŒ<Òl3t›ô‚­,ÏòaÅï¶û7=÷Üsoȯ÷Ý+i\°p‚>i¸ÚGšy ˆ~½òçŠàÏíþ¼#ÒZ¶ý¥ÿ>D 98j@H«uDîð–€v¸#@ªðÐEžw¶Þzë~òãB{ :Ôþlœ€Öô|€Œ¥¬°jÍ*óæûošV|d–|¼ÄÒe+–ÙÛ «V¯2+Vè¬]/÷×®1ë6¬3ëÖcî™dÝZ³a#探J³@§ŽL×θürßçèÜ©³éÞ¥»éÒ¹‹éѽ‡éݽ·ýÉÜ>=û˜¾½úš¾½ûšÁý›þ½û[ ïÙ­þÜ-ÍÉZú>?4Þ}÷ÝÎ<óÌ{^ýõ$?ÒäC@¯øCðÇŠ/£~ð>´FðGç£ÐÊžq#@ð'ÕŽo h'€ŽžN@¥.[Çž{î9ò„NØ£wïÞp샂øš >&C´@´@´@5,€øà+~Xñ#¬X±bõ%—\rÿ}÷Ý·H’ð¸özpO‹ÐÓàOÇAoùkà'ø“JñÖ·åo;­þD •:8† N€Þ €@G€;¤uFíäõN@˜Ç2 ]¾üå/;ôÐCwðG::0B ÑÑ™Z ~qÖʇ|þuõÕW?/ ¸I5°àAõ.uX”ÀO ðØ3r»ßßÔi­«~“ÑhÅŽb'€»¼@Še: æ~Æpr:ÔaYÔÕåßøÆä™3gNWí@{¹5 c!Z Z J_¶þ×Í›7ïß_|ñÓÒ$€‘ Ε?ÁTïh–Å–ê⊟”«ý6 þ2Þx  µ¼€ƒU($8Xý#øÃÝ€b·ðÚ(ä@×:'žxâŽ{ï½÷xíà¶nÄ---PаÍðçV?€_>â3ÿ /|Jʬ5€k`׫~‚?t)×å¸ÚGˆzÕN€M´…U¿ˆûwZù@p0±êgàíî€r€4i7€Î•¾~½ žz t@;Ë«ƒöÝwßñòA‹üøvvZÃW¥ÿ1D D ´€ð:@ïô#Hzµ¬øç_zé¥ÿ–$à®ú5¸sÕ¯) üà ú~®ú±Ú'èså/¢Ö¿ß"ø€6äàØ;i€;úÙ½‡€€ð:ig€: (Ï::ï·ß~[éK_šÚ¿ÿ>"·¿:ˆŠ!Z Z }[?ÐàÇŠŸáÃ?\~íµ×>qÇw¼.2 ü€:@œàŽÕ½vôjŸº, ‚?ŸQ;"Î…¶¶ò縢ÐÆu`ü à¼à¹ @ÊÝ â÷$g2¡ËÈ:lòUÁAòœÀ®Ã‡ÈaGŸÆk„1D D ´/ à;ýxÛüø ÏÛo¿½Tîï?"Ÿï}_¬X3êÔÛeРA=¿÷½ïM;vìÙ @›6ÀÀs­í3Ãì¤ÑÑÅ-€­}Üßð3ÈÊà /¼ðæ¹çžûèâÅ‹WŠœ+t‚6A”«y|Õú¬ƒu èsÅJÐïC[]õû €6ìð@ŽwèèÝ8k€³]½  '9ôµ@¹.—çH}?üð1pÀøl®wâCƒb¢Ú‡ú°Úÿàƒ–ÝvÛmóo¸á†—e¨\™“°ä¤øéü™iÖGÐ×´Ý®úÅ.>D 88Ú‘v¸3îØÕ»ÈAêaÔàO^;¡# ëë¼Å[ô–ÛSÆ¿•ì φø*!-i´@ë³VùØæç?F ²õóçÏC¶ùŸ|ï½÷VˆM&pøCp/útXë%ðsµRQÉ…ö°êçXA£ÐNôÀлtÒn ¸¹š/¶+: ttyÔé£ìl-?<´Ã°aÃÈC‚è Ñ %"¨_ $¾<ä·é]ùTï-·Üòœ¬ø_—Þk`&Xð äš~–#Õõkàèø¹åjC{~Ž;:íÌÀœˆ´#ÀÝì„;I·è|½ ™NÓi ¥SáÑï$௠n7cÆŒO 8·òœÜ&ÀsJ,Åbˆˆ¨¥°•Ð×ïì£}‘oZºté2ùDïKòµ¾Ä 8Œ58C†4€¼¦à¹íOG@§ ö,GG‚mhàŸºÝ/y¦½‚?Æ€vèàÀ#$8îò¶©n:¤tŠQê“ê:ÑÒdõßùˆ#ŽØn=ö3dÈ~zg¯bwÎh ÑÑÕµ¶ôú x…+}yˆï£xàåë®»n¡ä”5 ¤IC'Тº xÖŶü \í“Ò `—Û5ðÓÑhÇ€: ü [dàuä-Ríu5ü!#ªÓ!z ÓÔ;"·íî¿ÿþ[í³Ï>ÛŽ9r¼B}øÁ!8pâ7Md¢šm¬ðò|~ ‡‰|Ýo¼±ô®»îzñöÛoCä€ Ê¤5hè!Kâ!Óy¬‡u ÍÈvö:ê­þv¿Ý/¶i¢{R$ìh'<ÒBŽAM 'ÕŽe¤ºx¦u[ä;ŠÐGÞ&;nܸáò6A}ôͽCç :Þ4‘‰hb>@ž€¯WøP–ôFyzù‚ Þ–§÷_X´hÑrˆ%€Èä5PƒgZ;åt’òXŽ” ¯ÛÒ >øEWý0‚ ш€:o hG«€1d kP€9)2C'€€ÖÏò¬i¶£íÃŽ;î8pÖ¬Yc$ ‘¯öÐÏsDß~k· ðw ¢cËÄÐ^, çêž÷ïÃÕ=l!²òU¾¯¾úêbYá¿üÔSO-…X¢}~Ìl‚<)Aiò¤Ô!EàÑ)Ÿ} øs‹_ƒ¿Ë…ö|ŸŸ6H¢Ñˆ@Òy‘ô|ú¡#@'€€L &Xk0Ai:Iy¨ƒåY/R¶O yÇQ£Fõ‘Ï–m1xðàÍ{ôèÑUÀãhà b§@;)êMÊGA´@=Y€ O Àã¶|îÖ|ÓžŠÞ¦†††µK–,Y&æyO>Ãûêk¯½¦Wø\:bMÁ#¬I 暦¾.‡vX( ¶¿¨øûþàmˆÀOK$ÓèD ùÌpÒ”[ZP:à5Ó HÄÁÌIþyÈ’"óéhÊúÙû ûýì4yòäþ»í¶ÛÈÑ£GË 7ëÕ«W7~”M pàÀ1`„LGŽ-i–3€×[õŒx­Ë2šŠÎ†•+W®‘'õ?‘ÕýÒ‡~øMYÝ :W®¤5Ð’E$ k€&¯A\ƒ¾æ¡ 'Të£n¤ul” Ê~ F('D :%7e:c6Zƒ7x:I4I¦ËüY'Û eûtBjyh°Ó´iÓ¶Øa‡m¹å–}Å1è#¡;2ÀïA½¤S$*Õ‰àˆC°A>ijnùòå«è—¿õÖ[?ÿüóï Ø¿'÷ø ¦Q ¬ä©£<”i â!¨ÊÓu±>Ö Š¾²_ì³dEà‡* ш@³ÎŸG@ÊHµ+n‘3MP&h‡`YúðužÖe]Ð%ŠˆöICië8=ò‹¥òúaI“& :thoùráf›o¾yÞ½{w—[ ]ÄyÇ ºàuE|¿ "‚«7>x(†ˆ¡ùP«xa7m@·Q¶ò7Àñ¾lÙ¯[±bÅêeË–5È—õ>‘î¬xæ™g–Êëx Ò"€RG(Á“” -A‘àLÀ¦Œ«õ4‡¾Î ËézÙ(û^÷U¼q«ß›¢YL»wše­¨¬-Ó G‚+Ò`‚³¦\Åk§S ­—Ä£NÖ¡ë¯ÛgHÑoðI”c ©¨[ý$ Y ÑYY€€—DC`d: ô‘G€%%ø"M^S ÔÚ ¸SJÊk^ëèº5Ïþ²¯©Tíd1´€”“Zv똨chà…PDàÅID<.fP-.x‚1d!H#M`gÓvÖ<Ë&QÖÅ6ÙÈÁ£àu_Á3M>¤¢bu’(d1D Tj^kI”צ¸æ˜Ö`ŠkrÈÀ3<(#|Õ`Nžº:­e¬WÓ°}¦Ù÷Jw|@^ ­Ü˜¼chÝà…`DàE«’r\àc k@&H'Q‚?óüHë¼49ËišÔÊÐOð!‘—ƒÇ ä1D Tj^_¬‡×å ¸®@™)Á×yP È!¯ÁŸ¤µ <Á¦#mcˆ@; ÁpxÖ2È™&؆@«ÁXókRäg:‰RÆzŠ¥¡§û}¤u„eä­0þ‰ÈÀ¼FôõC@¥   Ê< ¾àCPNJSFÊrHk™–‡íè´îy©ÊÏ…!IêÄt°@tÚÀA,aú‚P"@F9dà™GàEš¼¦à“b1@ó“ê L·?t¯£$}ÿ!×!Lë¼ÈG „àuA9Óš‚gà’PƒR®¹ŸðZ?Ì×yàÃ6Ù'ä!0 †$Y¨ÓmÌÑhc´„áè ÀȉA§É'-eæ´™.DQ±òÐa[à“Ò!¤Ñ\nü-Pžx½$Q^7 `ʘe¤ó´£@$Šr¡n(c»¤¨iòVèþ /†vlè´ãƒ/C×”iRÊ4¸1‘" ]ˆê<ð:]¬Q÷úÐ #ò!cÐ|!ó" xî3 ªeäA“"ù¥Pèh=ͪƒyRÜ—¯û…´È‹!ZÀZ :ñD ôÄ@åD‚.&'ð¤Ô% # ²RGSða:¬‡: a:'ÍÉÉSO§#-PÈúZ€^RZ_äIqm È!×¼Nk9yM“êŒm‘jx C´@ D ‰I¢@, ' ‚­žh`¤|1iQÆüBÝRóµ.Ûe L§ÉG-P©ôõ^LS‡à6Ékð#”š]]GR2Ø-‹|´@ž¢gŽ˜H°@8‘x9!±A˜ù‡2î„yZOó¡^Rš²$ Y Ñ•Z€×@HQ/¯GY˜OyH©GÇ@ç#!I–ËÉýE~ ÑͲ@tše®¨,'>'(‰r:äxv€é0?-rIe(×|¡À6 éļökðÜN³õ’hx0­u)Cý䙯eäAàõü˜Ž(ÉÑ(ÉLQ©€’&"-夨‚Ræ…r&]¦CšË£ªcžÏ!ek‡y:MúäCʺH™Ït¤Ñ™X :™˜1VX iÂPSNÊbq¤É“†:”“2?–ª—V>ÊÛ§Âs4Í Ô )õ“ä”QGÓByZ/òÑ[ :›0VP¢Ò&6´ÎÓ<«A¼Xšå"¨†Âs´X:©a™$(‹¨ª¢PUóÆÊK°@9a9eJèJT‰ÈÄñüÌÄŒ±’j[ Ã¦Mñ\­¶‘cýÑÑÑÑÑõf¾‡]oýŠý‰ˆˆˆˆˆ¨¢¢PEãÆª£¢¢¢¢êÕѨ×#û-----PE D ŠÆUG D D D D Ô«¢P¯G&ö+Z Z Z Z Z Šˆ@«Žˆˆˆˆ¨W D ^LìW´@´@´@´@´@-€*7V-----P¯ˆ@½™Ø¯hhhhh*Z :U4n¬:Z Z Z Z Z ^-ðÿ•36¹IEND®B`‚ic12"Þ‰PNG  IHDR@@ªiqÞ AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs%%IR$ð;IDATxÍ[ xUÕµþï˜éÞ„ „ ‘)A@E&eR[ŒJAD¥TK'èóÓòZÑZÔ ¥ôµÔÚ§µVH±LÅ2Hʳ 2  $1óxç÷¯}ワ$ Aßëî}ö9gíµþ½ÖÚÓÁ´zõj|Å4ŽïO% ¥¢If’‰t5S€Ìü¤ÒYÒ^ÒRÒ‡¤+NÖ+|s(ß{‰4$!!Á–””‡Ã›Í³Ù “éj뮤4‹ßïwz<g}}}²²²{***<¼»“ô,)W=y?— Àíäý'§ÓÙ-%%¢ø5Rö¼*H[‹EQdd$APlååå·9{f{mMm>_œAúçyœ§²­ÄòÝ5±q±#R:¤¨†5/  ‹ßX.@ˆngKÎ~TS]ó1…Oªº”PmàN2ù[zzzTçÎ[ñ«l¬Äþ3ûQTY„ª†*Ô7ÕÃëóÂãË ¦€é @’WB¯ù~X­VXÍVÄDÄ >&éñé¸!ý$F'êfÄ©S§†󆀰)üÀy ¦KÁ§øÎ¢ž={šèëÍ^ϯÈÇžÂ=È/ˇÕn…-ÒKÍÓjÉb‚ÉÜ<´6͸´íB¬ÌïóÃçóÁçñÁãòÀÕà‚»ÉÌäL ̈ží{6cÆØ€#GŽ„³I¿nvÓpq1$wHþqZjÄßt:SwûˆpF Ê[” ÖH+,6 ÌÖ`”^—€hLW ‚(/øùüÀKÜxšB½ Õ Šz$õÀYw c\Çp“.— EÅE(-)]ÄÊgÂ7 … ð4•ÿuçNUÀÑÏçžÌEî±\DÆF"ª]"‘°GÛUÏ‹èžW‘ ä•*®ÛÄ¿×¯Ç wƒMõM €úòz4T5à[½¾…Ñ=FëWÁQ'O¢Y:_ H¿05%µ™òkóÖâ@É8:8GDPùÈ`Tåeô¥µÏ+(8¢Y£m½ÐÀ™AKLò÷Óº|f˜#ͰD³}Ê V(ù¦#›PÑPIý&©fÄ E°IŒí·@¢ý‡Ý»w7EDD(Äåá÷½‡cUÇàLu•§é«iòà?ŸÙžöh¡Õè x“V°$~ ­‚Ò‹ÛÙív"زÄ|×™]¨w×cÚÍÓTë¢K=LG]ÅŠ4Rxth ÀšÔÔÔ(cÀ[“·G«ŽÂ‘ì@TbìN»òwiÜköª¤GŠ+[‹½ÊÚ³¥–<åÚo&vbÃ@l²!Ú­Ì~ÿÙýxgß;˜Üo²’1>>iiiQÅÅÅ2s¼MUòÇÀ(g¬sDÇŽÃ=¿íä6ì+݇ؔXD&DÂæäLf'è+aB~éW3Ô …4–uƒW;W Hû6*e…=`G¤/^¿Ÿ~ g¤czŽQÍr(Gm]í­œ0‰›«É’€7’Û'‡•?]{[ ¶"&9¶vŒò>J¤¥×żÕ_Ëœµ:}Êë¶$W@ˆ5D§ÞD»£±îÐ:d&e"#>C=.:€×xÑU*4Cc1b&:m>¹–X—8öz {Ýî‡ÇäÁw£¿‹xs<Þ,|uö:X#¬*è6–5¿kž‹5òÏo¢u2ˆÌÖ8Í ¬Ë[‡Ç?®DNÇuuµuÃYñ±àEcï®8Œ#UGàLsÂèËàâ5ÑßÙHÈ(¯/Gþ¾|غØàHq¨±_¸#Š+µTãjtëTq– ØbmØ_´Ÿ—|޾É}ÕÓí“Úƒ¼Ì‹!€¡íÚµ ›ÿ®â]°88©‰b¸¥o ª2þŠ‚«¢˜³Ì¢ÓEjx‰ôGÂä#HüûF“X€¸¤ƒ²Ž2LŠûn;¾ }Ú÷Q"Š®LIœ\wÇÅÅÙô¤¥¬± ‡*!&5š¦Ä ‡Õ €Ê SNHÖ•¬ÅÔŽß#º&CÜÇAá÷ ' €ŒHªÌN³Rnê`Š6a÷éÝ(®-Bš3]ÍU¨³¥ººzœ0MüB“ôÙÙψ$Î~ý6μ¨¼·Dy)Ÿà‹š/pGï;±Ëµ V/c„%8QQ ¾É"¯ühÁ¦HNÅÂÎÓÿ„¬ JBê ÀT`@TTT€“5ŒöÀJ…é÷2 ÅN@°yñöÙeøÏÌŸàðžC¨¯®‡=–ÃÕMö®.\€X€ÈLy½4O?u11&+?Ö3´¾ ¤ÈNŽNe®/ás2â[¨¼Ìn9 Uh†U–ãÃïŽý3ûϼ½óà¡›ÈbèkA+*VË‘O)¬ìž—\8‰ò/àšÁçæâ©Þ7WŵÅZMµ{Å‹@Œš¿‡\ Ò]œj’³Z}A² º€ I d*Zb/Á²üe˜Ýg6^8ø|I>µ( ·p J‘Poê^U®J½Ï›êÑÌ ¸R ä²w¡]=ó¢³®¦ þDÐ^¸àTSJ©ÄÿµȵLЏ ¶8Ï]ÿæœ K&ܸP’EÑÀ˜æ†Ñ=`O€ÍlC•« Uî*|Ùô% ë q¼ö8ö×ìG™¯,8ĶսBh«• €!C¸ÏäƒËç ’Ñ$4«tù›@°ùý‚ ú?è-@ ïq±¥f3ú4\û¾ˆÙÿž s’ f;M$$t¯¨^äŒ^1½ÐÝÑf:c‹¡ëœ×a`{‚)¯<ï{[+·¨•žZqê›çË[ -Hv¨¼~=MÍt%‹Ö£¾Omk©>¥{žãb $º.>þ[¼qóŸ±pÀBÌÙý,ãÑ?±?N{==å±6'Øl Ž*™‰™x>ñyd}ž…ÿÊû-ìñvJ|qsPÖÌa9ì2Œ€ÚG &Fk¡”¥óÒÔ…L/,Z@¨Çµ #ÒÓGï¼á Ãñ»Á¿ÇášÃ¸-ý6ØÍv4õ/khÚ¥…Øw|öŸ i×–¡ÞU”„tïÐ=Ó{¢[J7¤%¦!w.½¿3ÐÎÙqŽ8µÈ©/m€?* V}Fy[•u9C²Jzé¢CËÔÊd%ˆÉìNöàÂLÄù,@1d‡­­\‹{>ˆ…ëbÖí³0ûÝÙØ´oº¶ëЉ7MĘcpS›P×X‡M7A6Xv•íÂÎÂðçSÄFòo”®ã¿ÕÖj˜Üœa–°‚IæõÒ‹ââIQ <©{0˜Ë~¢Ìf Š1µ@òÐ_¤!Aº˜ 3rd³òݼwqÇõw`ê«SñÆß@¯Ô^øã¿ÿˆÅcñg‹qoï{1gìL4ãn§ÚÙR°oxõáT‰!²ìVÖEEDÙd•™vK£ÍÊòxÑAÊÒ‘Ú . € ÅG“—ÁÌkVæ.n Ô̈¬ßCŸòÑ!—ŸXŽõc×£.P‡{Þº¯Lz};÷Åìg£!¡+KV¢fM MX„h»œ ßÉúFgŒÆ©êSØpjV®Bƒ…æ.;>âî¡AE¹ÛàÌæâÉYj‘V­æ-,@Eeæ!Ÿ Pn ®p’Yw®<x½Á#þUÉ¿5GÖ »6÷œªðàßDae!ÖL\ƒnQÝ`Ž5c}íz<¹êI4¹›ÂŠÄFÆ¢O‡>˜5`^ì÷"n´Þˆ(O”ÚøT[á”Iäj3QÏ‹KȵQW nâý%ü²XCÈ"¼.vÔpvPG¥Ý!¥[%+°RO)žó6ÿb3îtŸÚjSÒÆ¶/$ŸÖA ¡X§h€¬žüD‹PÇRAí2hké<¸âû8pêêë±ì£eð7ù°5+¦ž W™¿Ìýv|Š~° ƒÛÆÞy¥5¥3åB?ósxJÜêÝËi¿ù³Ôæ/u4ß >-häa¿Ÿç{ÌõV—6}_,Ȱµµz+6ýy¼¥Œ%nNb’-È«þ‰ÈÉ¿ŸýËóV ´º ¯O~O­ú ÿÍpå|¼öÐk˜ôÖ$”XJ€8 ÔUŠIoO”ÿ‚g²ŸA§öP^]ŽÓe§‘W”‡Cg!²*þZÊÍévx%¡C¬€‹5![X€À¨‹ò™Ð"Èå«[Àfå&¬Yž-˜Ê‘Ó+Žžø,¦ýf–ܳSVL×Á¥9·µ¥«Vœ\e¿ä°ZEyš¨èÊkŠ *nfÐUŠòq1yQ> €Ä‰ -R+Åܵé(ß ½¬Á¹’üÃ#ç¾g”¨FxS );¢DKp&`föL¼üÁËxnÄsªWeÅ©”uò3¹4žôtãQx– ¶ž<´eÙÒ…§Xí© GŸóÊ«Á mþ’Kj€5ÀÃNAŠ=¤LFÊ!$¿J~¢úvžØ©•ÑD%‘!Ä{áVù€#˜¾=ðÛˆ5Ǫ1kÐ,<Ñï LËœ†Gû=м§ò°í±mȾ>[gv°çy(V ö <•²|¦.¢“ÝÄ)¨¸&ÞQßžpxþ?îî{7rnÈÁg?Ã_gü{ïÅ¿yË6,ÃÙò³¸µ×­X|÷bø+ØËî`´W»T²S%$üCåÔ˜T­¦*yQ*£Àn·ÛÝ]¾Á•”Ù>Ÿ¢¢kÀBTU”P·‚¢»k.ÿ·È]„+gÀŒìB8±­Cµ‡ððëcù“Ë•›È^^ÿŒþ(ljj/Q)-. C; U[Ô^Vû\Üàv˜Z&ëMPm^Wšl=YÑæÎdã+Ÿ¾Sœ ù¥ùÈ+Ì£Àã¯=Ž¥›—Âíá!>~¶é<ï—8dž $æE¥U€äǰ®Ã‘”T’¿ÔYàY#HÚa´‚»zÝüo ²oé"I`1(«Ð –kR¦hʬ£ÍØ~d;^]÷ªæ*=•xléc¸îÁëðÄ¢'°7o/^˜ðD‡²ŠŒËõº*Ë5ïë7®eïÆ;~ý©ì‘o5~8oíÊûˆqñbÁ„æx-ò üгV¦™òr_û½¬]øFgŽÆÌ13ÃÒȸOÝ$¬g‡+Yh €ÌQ¿SSS³_Ž™ôähvöl8ì¬Þ»Z Þ2:‘ãµ,k $7–µò2„rÛ,~”ý£pÏËL—_„Éò‰X…QDË”)SŒ×RÎ'ÕéoÉgèúTf`׈¶Dc÷ÑÝá™–šxHãÂÚ`‚ç-‹^ê™KÝ×Aø1k–êzŸ¹·ƒ/8y6T¬@ƒÐ+½néz‹ÚÍ9Yr2XôZ[!`h2*¤ë¾JnäGåõÚCz}h÷¡x&çŒê3Jë¦ö4$°»]îŬœ¾a(èy€¡ªYQþ›Éþ§H“Xƒ1í9¾k÷®Å'_|¢>@RãI(@2fýª1BÀ’ÊUàÓ °ÎÌó‹aYÃ}c6nêvSðÙÐ/‡uÔÖª ÄV½Ôì¦áâRÈ£w’þÆ)%^ O—ŸFîá\äÎCqe1ÊëÊáòºàòÈòê¥k„‰HiÇOkR»cdß‘è”Ô©U#2«%IÀ›HZ×êCE[Çåëâ9:Ü*_X¶´¿o´(‘žs|9RßAA$Ú‡6.,VËQàBO £ÛÈøNÎþD ®“aòÿ ¢¸Ìð(_åœAú©M©­hf›XèʆF‘æ1ºáÂ*`è`©¦~ájçÕ…dhÅI2ÈfãÏH[.·½Ë@ó—†„Ì 69¤ï±ÜŸÔ$"Yºz‰aO…CYÈ—>'½CZI’ÐxEéÿæ­dà­yIEND®B`‚ic07G³‰PNG  IHDR€€Ã>aË AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs  šœ=IDATxí}€Eöþ·9'ØÀ²° »dQA‚'* zˆ ¢' *fEÎó çù7ÝõÎŒ`:T\Á€‚¢ ’T²‚H’$-lÎñÿ¾7]³=³3t9­ÙÚ ]ÝUõÞW¯^½®îö©¬¬Äî÷Kßßo×ÿè9)ð~ç8øàwNßy÷ÿàwNßy÷ý=õßÇÇÇS¶Ç¼Ù³g{Ì?žÌK/½Ô硇ŠèرãH??¿þÒž¾¾¾‰r͉JHÉU÷FOcêw.×Ô²´.‘0·¢¢â Ä7•——/Ú¸qã{<òH®Ðë„®»…Võj¡û²ßÇ=ƒW"×ù¢'d¸Tè÷î»ï^0J˜~¦´!&>>Þ'** ¡¡¡ „äkÛêÓ¾:wä$=é…é())AAA²³³qôèQæeˆ_SZZšvå•W¾%U–/ NYXL÷>}z¯°°°Ge„Ÿ# ˆExx8'ˆ% ç2Âxäåå)Ž9R*by~~þ×^{í·ÒÊŠ_†Sd|ïÞ½n»í¶¿ÝݤIñ ydŸhQJP*:t999YÅÅÅÏ>ÿüóóÍ7¥õÂ)kÄû¥¥¥ý?2>111¤Y³f*ÚO4qOµëqªØ¿?099Ù­éUÉ=Ù{°+s¾ßý #)À¾þ¾ðôXÌ÷Æ“Ùüó0☧£ÓJ;rå¿çë<|<§4°ê0 “õ*+*Ä †R€¤ËJÊQZRŠrI3Di%Îju6R§â´˜Ó¼6eïÞ½œJ×3æ])XM48XÌ”¹þõ¦IM¯j’à}Ôo9¶+v¯ÀѼ£@@PüýŒðSpä õ:ò… ²b@¥OeµÑNfy:x‚ò\$€0œà#ãÕ— ÊdºbXR¦(+*CIQ J Kž€>­û S|'­áòÐáC8ð󢌕B%v%±A@ã{ÁDÜpà ˓’’ÚŸvšgtïÌÚ‰EÛ!³0¡Êxe~ü„ñ*Œ'³éiú©’2Ü…Èîâß#%ó×ÑG£ßŽ©@PZ†²bñBq)J KÅň ŽÅE/Bj£TÝØµk~þùçÍS§N=gþüù4(é”p¼ðh ôØ‚Z2Éü»îº«iŸ>}¾oÚ´ilË–-=ž±xÏb¬Þ½Zæù2ú9òÕ 8ïsÔÛ¯Àštþ—«ü öÔ{½¾•4NŠ`ª. *Á € 4ÝÀ¯LÀì¯@ð/ö×¾û‰â(yYùYøïÊÿª4¸ õǵlÿ9˜¤¿íoºé¦íb!í*ô>`@`+Vïè €4ÆïÞ{ïmÕ³gÏ52ß«–ïÞ’ÝÙ»1oË<V"$&!2ò…ñì|@`|EM2Œ§Øçû1ÆUaµ–®fZÓÛYÔkdi«ÒÍŠ›å.i±dÛìÏܱgŽu©‰t@E‘îâÚ¯X±"S ¨NàR°‰ã‘œôBfÍšõvÚ´hÑ¢ZuÓ×OÇá‚ÃÖÑ £_G½,ñ|dÉÇÕðe´D¾s„ð"¼²8wBVK kçÞ¦šÚc/K00­@ Ê+U1¤@W\y2ä¡H¦aMqk¯[«U±{÷nìØ±cÖèÑ£ÿ"‹Ä×H˜²(Pæžk»œÑejëÔÖÕõæú7q¸PF~d°ƒù\ê…ˆÂG±O…‡Ö=ŠDÊzqF‘3„rYÆäÕÜE–t8gy“ñ…îí0i‚% Ú ÔXdI‚Ò‚Ra¾@ô¢ì"4‹h†[Ï©‚mÛ·aýºõ7ˆ.6]ºÈ½^Aà€_¢ø >—…|ðÁ^9XæR †D}§Ž×0Ù¸±PDQü\.½pÏB¬Ø·BG~PDˆÿ pÞבo­ïÙAu”#ôâ Q¼†nâÞ”sœ}êüwo·I+8X^%uƒbÙT"ÖB]ˆ> ÓL R`p›Á.çÝÄ;w®ka9/Þ£>p<€ì xì±Ç.IHHèÁåžýb;²wà›=ß(óÂĬ+Þ/XF¾ Ù‡v|Ñv+|+„ç%OCŠ?¢_œ#V×<7©`Ê1ü_pξ[ýs‘S^=1~b<*÷W)À¥#ýü-óÕFжq['Ȃ‚.“'O5iÒ¤·ä@±xA¥ªGê3p솷k×îÙ¹SíJŸlýDG»ŽxŠ}9<0ŸóE¾Sr€•!+²Ç=¥«5¦fðÆUë‘pRDé"Ó£*Æ\"r¥D£P&F³²]5Ìø~þyþ?Í%5Œ‹G«V­ž–ÄGâ9 Ô:P¤×űõAS¦LyX6rDÇÄĸœ³`ÏäWæë\¯£^¬[l8¸}S`Ñ_á#¶p¹½K”3´ûÒJ¹¿ï–W^)±•g3éSÍ›¾ÔÖ~ÒGB3£Ž ‘¨Ô§èsÊsðñÖ]øÀ[íŸáÓƒä—xò­FWW à'[·¢dä— \DÿîœÝX¶{B¢Cà"Ö¼`a~ Ô+â‹(&ãÕI@äÛG¸¦¹.ù,ÏcîÎSž{™†œ®I °»J’^ýBOŸ ÙQ*4.%±Ä_lþ­µFûØöÎn“?²³èzÉxB<§¥@]$QòÄOüU6t¹oÖüø§á*â^OQ¥ÌXUø Ž…ù2Vu´Ê˜wŽÚ8ß8\y=Æ„Axv8 ó QZîf´ÛG¸=ö¼S1núáM pä“^&Ô>2-t¬ôd]I_•²Bo®°>Øð°§Ê‘?§ÐgŸ}öNÉ _£¨ tî—‹ŽáŽ»[—¾G‹Ž:æ{Š}iœŠ~Ê©VlDšÌý†i—E\†„À$'áÖ–·"òp$ s QVî çAzSÞ¤W¡E7CGe£p‚z•Þ@¢^ S¼Øpdƒ-%²B£é0B<ùçÕÕ¢'è¾ûî,ó~$ÑE1eü’}K´1ýl”Š}?9.ëYçè+òeŸ1þU:ļ•ó°rõJäeäéÆ Ãto£Äÿ=„:,  R€´¯’ H¦¡91wë\'OÈÙtË­w‘÷ÜsÏòO¼W)À±Z“#@Âäþó²§Ï¥Ü¶ìm8”Hç~3ç³aýt¾>rª´•âŒNA#L,<ˆf¡Í_˜§ßÑ¢áìX&šrzÒïéŸÐŠŽýw×4OXHÚ)DPÅP$.ß®c»°5c+Ú6ªZ’_;w¾KJ.O±Ç;†µ @žÊ‰’7Ú‰èhœ\‰nó±ÍŠ>Žz2ž£ÞüôÖ'S\Θ%‡õ[›±Vp$ë*Ã*Þ,‘Ž%˜D·Î”ùTÅH¤û ùqL«}… )°îà:´‰iã$ìÅ„ìÂ>C2ÂÅg‹÷ŽpoŽb#XÄÿ¨Æû[½)¼tÏRù:Ãp°‹hârOE·Ô¥K;Š}Ë—VÈ(Ë/Ë]†’ò4iÜA¡Að óÓóyÜ”ÿ#¬¢Ò‚Ë_þd ¬Ëj.9È Oqá¶…†5’_ä›—z‚GzÎûÒ(.uŒ7#Þ¤U„ z‹ŠñÙžÏpi«Kѯ}?l(Ü ûý¹ ìwí:JÊ7W“HMM2‚O»ØÝÞì½ð­Ù–R߇?øjX–¨¥SPXó¿U„U`êOSq·û1´ùPÌ;2OŸ¤ùC (Ù\F=Éi„º*°$Âöô펓­ÿäù'û5˾C’MeÐÅy“œ/‚d“Á*öŠÊúIÌKb`ô™yߌþò ǃ é9wÙãšæ 9Æ)c‹ß|òÓ'¸öœk‘P€‚ŒÇRÐ:ßœûGè˜ût ÀŸˆÌòû*Š+бéè&~‘òˆÙ%ä§øjz€ëЮÂ…K°~ÎM²*Wb¼ëGæ—û–ƒûøò²~>bäü¯PuHé"ÒšEœÓ…iièиþÖço¸ké]( .Ò›JÕ›ê<ë?bv%¥5íš8;¯´”) \¤®*„´ºÒûW`ë±­h߸Ê4Lþ Ï–ÓòÕE¨ !²ükL²ÊÌ?¨#Ÿ£Ÿ?©Ö¹ZW Ãl†ücþT’0CœcQ‰ÿÛôxºÇÓ¸»óÝx|ÓãKSë¢üþÇ¥’ÈñgžŒ(ŒÊóLë4 cMÓV~E‰XKeÏ@Y¾cW1Ÿ8ÚstPµùG> CÅ×¼"–¿FœG´r‹ÇŠŽ9Ö÷TúDëçd.çÃp; Ó¶Ño@%&3"­y žó(FeŽBÚá4„&†êÃ!Vµ§\àd®µÉCÓd¤éÞzE\â\Ê |Ø„ÒUÊéà¢R(ƒÙ™sy>ù'ÏÐô*òV­6¼Aät5I€`@°îØu²Š³TÔm”bˆ›J c ´‘ i¨SÆ\ÖGÌš[K·bòªÉ¸ïœûpø›ÃX”¾ÁqÁº‘Ä”kp!E‹ñJC7#ú—6˜×50ײò4Ÿqùé â"a¾zÑ«2ò3\j%ÿd>§€jü®–aMQá/'ëqÓ+(-)€è“ùGž~!ð¤µ* ¬63C§(ešhÕÊøñ›ãñàyâá%ƒfãÀè@Ç.bO'Õ1/. ÝB»¡mH[4nŽØ X„ú…"È/eÈ,ÎDfI&²J³Qœ¡~ì³Ë߉ƒÅu÷²îd®c}ÇU¬ rë4 `,—é œ >•¸®ô¨—‘Ò2Ÿ¡‹« \"VÛ4Ê¥†<Ì%ª¤C™$C©è³pl8›­ÿÓ j—2~Ñ~xiÿKhÝô{ý8–d,q€€ûäê麄uÁðØáèÕUzïùüPÿPÐ'…U¬Õ–‚O4ÿñ¾Ëø?äý ÖÏ“ Ãh©_%IÛBJUýq9hýø-ïJ'v\ùéšíaNp/àž¦­_ >R!-~‘º¤xç ´šcñöOpêÛÈ“ÖMÂ{QïáþsïGèòPÌ͘‹À‘µ€ Ú/§‡žŽ” ôkÜ ÁÕ·®{«Ú[~ˆL¡c;ª¿W"£ nÿŸúy~yeÕ3¶¼]²ö|£Ý 4'•…Þæ¶¸ùSçMð»D±ÃJ¹o PÅÎ!ýõÚ`æ~-'%j”æ ŸÆ>˜øíD¼~þ븻×Ý_ŽGf °±€€&h›‹ô‹ÄÀèØh RÃS½ŽtÛ)ÇmÚ×w¾W¶»Ï®~ó2æéîœÚÀY¯JÝ s¾dšÇEä+})e /¼WâJ4«\MÐ"Š>ÛEUÛ6Ü£F4ÒñÊòöß/ë•eoÈ^ÌÛ1ç·<7œu’¶$á©O©„à-P2~düH K† _*¹¿® Ãß{ÿXÌÍš‹€è€Z%T}Zh,&n Íè7¼qçYMuÖ ÷“ÉP2ŸÓCÃpÕ„ùt¦a 1x J¼þóëøÓiBf^&·ŒÄðDÜ·þ>ô8­&¦NDŒ.qµZ¯ÿJJK‘“c9Ç™›©kã D‡G£I#¹%à<·þûVÄ6ŽEJR cÑ8¢1"B#‚ðp}¸uÂÙ6- aað¨7I=·›#œô$Imq“gèÎ|0|!êãjm­Vh»"§æ1$Ó)4.2À4ŠÅ `Yùé9õl¯“¶} âvÃî èÖ²Þ{ÁÁj~æu‹K‹QP$š¼0w÷¡Ýøq×X¹m¥>Z}¬à˜.])ž9uð®™QÞ(BÙþ¦M‘ŸŠÔ„T´Œk‰„è$6JTߨq#ÌØ0þ{Å V&}ë[E©ôGâ<Ÿ]ⵃƒùÌ;ÎÆt¯Ë?[¨ô–þ³ Œ›ã¯cj€ûuir³FÅ?ÁFùS¦³!âN¸x™þót k5 ’;à­/ßÂ裑[˜‹æ¾€Fá0 ó´iÖ"éHØ} d÷ÑÝø|ËçHÛ”†,ß,Ý9£@àƒ©l£ÅÀ¬ò,¬*Z…ûW ü'MÅÂdza6÷Ý'Ë» â ¨±ØNÂK”SM-¼asBœƒŒ. 7 6!ÛOÏèô"¡ëãj€;šã)ØjÅ’v2Ÿ1„œá ëÓ8S6Ã'ooz7œqz´íÛ^¹ O{ñ7Lž=>}!šÅ4Cÿ¶ý1 ãôj× þ8-î4Lˆ›€ }&è‹&×Y‹Ù»gcmÎZ”ø•8$±À6Ó¸Ã.OèVÊkÜ £¹„ö • Ožy¨MÉc¿)ŽOˆ30#Û µ­¶<à 3 0íγšÚS+ÜOvXyß_¤)Ti`+È8ÿ%P#(n9Ò¦ïü/F¶½íš·CLD4F½8¯Œ™Š{/»§§œŽûþïýüÞÝ>i8·ù¹¸¨óEÔm8ßGGa@òõ$ÒöÌíøbÏøêðWØS²[§n´ô•=vTiÝ{QÏÁå~‰ú¥ (¥øg…¤…2ØÊÓ‘ÏAI)@] žˆÆ2“ µ¼Z¥BZžghâö´É¯W((•ר•äÊ òd¡ÄÕÊ%½Î ÈÇ´õ¯j[oºp~<²—½~6ìÛ€‹;_Œ´+ßCr|2“ÅtÜÆK+—bÒÒIèøpGÜñÆúà‰é(w,·iÔ·u½ ]ø>ê;7&Ý„V¾)UuZýªWûƒs Í’€ÃÎÃ/‹é¸‡°V¸ŸcæŽP>©ªs_z^oiæ ã³JôÖ&_’à~=v-moŽäARã$\ØæB‘ßU³¯ÂœusжI[¼?ü}ôŽì­KÈ€„·’T´ÆE_à–™·¸€ÀÞ¯Ñ-0¾óx̼`&fõž…Ñq£Sƒò"i‡L îmù-Ò¤·ÖË‘îFk•– "%TRØ;WK¼VØ‘d;ç9&^¯P:Á—&–ÊHçýìryGŽýúÕâ€âÀb¼ôýKÚ¥á݇£¼@l‘Q嘴|þõù¿Ž)—LÁÍoDEžÈJ±%øÇȵ‰øºükLœ3Qw)ÕD“6±m0±ÇD,¸dž:ý)töïŒòBЫµÉ&Íc:%Ô£îšú[+ÜO®ÖQiMyæ¸rN'ãÊdÄWɼJ嫎?1=àÃbOæôéØaEa:üãýÕ^ðÑú]Ûν /ô|Á9²4Mžçqゼ?s<²ó¹M¾fÇÝN|aã[½…WÏ~­*Z©Dоֱ½uí×ñ–cOx {¨‰:ü«?¤"çH·/?j‰SÌ—ÊÜnF»™JêÊ{aË è/Ÿ½rõ+ÍÕ©È/ÆŸúK~Z‚÷üˆ~­ûáÓK?Ũıˆ-‹UeÒ'Tn9—|‹!oÁ’MKê@G‘žÉ=ñþ%ïãŽwÀ/W¶Á‰´rŠãZú]¯þÕóZ:ýò¡‹Æ­°Î“‚µ®ˆx»3£•rùgB] JA'š-EbñβÇãþÜüÏx¬ûcÎKp¹—†kæ^ƒ¬ð,¬._Σž…«Îº #zÀ„3' ÝövÜ… 0wï\ì(ßë>¿½¾î…1gAßN}TÎ {ˆð[4G÷kÑãçÇ¡€CŽç!«/<œý ²,²+ýÝã’6ùÊ|¡5Cõ\­¸ñ¬¦Úk€ûɼ8QÍ¥Ÿ†ß k;˜V° ÷«Yóº6Ò’î׫OzlêØjÅÛ4iƒ7/~Ã?Žü˜|¬9¸“.™„áÏLJ~ÀC—>„‹;\Œ©‹¦bGÆü«×¿ô.æû[ÞÇ'›>Á˜OÆ èÝ ôhÒí›´GRL"B"¥KÎ -œuî9´{îA߈¾xçÀ;ðoìxס³À‰Œ¦›åÓ¶% ‰~Œ×‡ùln­p¿ ™iF¾ð´Êd5P™NCŠÅp÷ðxhäí~}û¦íñϳþ‰{V܃Å{ãþÞ÷£OÛ>xcóØ”± SFNÁ ýoP±?rÊH´nÖãzŽÃ¤±“0óÇ™xãû7€(àŠ~W 5.YyYX·kžýôY´kÚ#ûŒÄï ©¼ßXÞýë~gòxúçr.é)NéϸåÝÓfÔkhIwžé…¼ü«·  ±FæêŸ ”š2çwµ“[HdCN¤?˜wÐK7€Ë{\ŽÓ}NÇ’޹ýŽw¨eoMÉ\ôÆEøN>Fq^‡óðéÍŸ"+7 ·~|+¼4ùyùøpÔ‡xýϯ£]B;ýìKld,Îïr>žû †3 ÷L¿¯­| A­ƒÜIÌÂ)¢ƒÈÆÝ}‚ûø‹é%Œ¨ã !k€{ƒi–¸áY·$‹rÇ‘¯bHÀÀðdø»ù¤³gG“íµ]¯Å;Äìèݦ7:…wR¢<ŠŽÀÌ•3‘’‚¹7ÍEß–}‘gÖ>ƒ^/ôr<ÎîáÒ Q ˜6a¾êaø6–· 4’·¡D Ùd·tMêŠù }y(~Ü÷#Îk{Þ½ü]Ýî~Ó¼›0è©AxwÉ»øùèÏú¡ÊW`Ò«“à&$“éä¤öÑеž¡± ¸ó¬¦t­vO'³ó´p°Rõ”td$º‡,"œXß|Ãe Î÷ãĈŠŠ¨8MËÆ î"2Ï-0ßßÏ/]þz=× …¾…¸õÌ[õ¹ƒu[‡)K§`økÑv]z´ê÷F¾‡‘ïÄúòõ¸ãË;P>KĽ(~ÜÏû þM`ò(ipR¹¼„ZÓÆÛ BFñ˜³\=f±Íû¦—Œåïdˆ±º^“=æ™Óýbåyâ}#¥;rm;#ïGªrÜçwK·[PžYŽ»ºÞ…¿ý¼ëÄ?MÄðNÃ1|êp¬Ø¶ÝN놙£f"Â'~ñ~lˆ Žò­£Nò̓6òl©G%@]Ûy2ËQB˜ëk¯mi“/aM®Þ@+´D“sôS XN³1l€{XKcÌ5NDØ%¾KµËŒë?O-zJŸ mÝÜyüêWã•e¯àŠ·¯À[£ÞÂyíÏÃüëæƒ¯Áí˜ØñañªìòûÅ|¹?öHÇø¡ÜCØ—³›nÆ–Œ-ø>ý{lÉÝ¢º†‡EÎ:k˜Ñ.#Ûä ÀÐâ…3¬'kéâl•ÖÃ|;ܯårá›hÒ¸ÚißïŸÔï®|ôWçñÖI­Qž]ŽÂ¸BŒþh4¾ŒþmÛêNã©ó§¢}R{tLꈔ&)*9̉~HŽNVß;Y6¢XŽÄä«óçïšû€›NyKº^€0Ì–Óª@ŽižäI5ž™†yk€û9Ü|(WGõã…ßΊ­±ïX"Z0¶j÷ë¬4™ãÉÙòLLþ|2†t‚I|’l=ÏL×]À´ìGÉ÷y5Å7›¿Aïö½±óàN\ûµúH<¿ÞAsqûÄözÖP >{°Þ–v¯'&$CÚ QÏ×â,Û¹ 37Ïħû>E±¯<žÏ;ˆµÝE´€Ǥm¡JYÒ×x)$ p÷æÔ˜®·à2êYWõ|À“;³õ™(È/Àe¯]†oúV BÏÍzNçu2…Ï „„`ù¶åX°v†ž=“¯¬F$´”doƇ>À_Òþ‚ÀcDêl Ûïæ>Üð!îìËmT¹Ð P¼2á ytÞ¾ûm¼rÅ+õÎ(T6‹¨yWŒš‰KýK1yÍd<ùÅ“¨ÌJPÙ£p‘F?¨!ÖKZ}šùèWÓÍ«öõ š6zÕÚéÏ8•J–¯‡«÷ £YjÑ;R¼ÅŸ5ßèÝ([Z¢ÎcŦìIeI7{óìj¤à7 ô9zÛioËó«žÇ±¼ê+ˆ¤Ø$Ü|á͸dò%úÌá¤Þ“P‘-ýçSÂæZì°èT©$ú·ßNtŒvò=Ñ3üSäkj-eÝ\¬–‰2êãdê‰0Ƚ žçlõsM Ýéh?Fú;þsüªuº†ŒZàR™4†âß>WQª¢È‘’®mþr‘"ÎÿÅÇ….s~šƒüb¾$»Êñ]tBvW fÕÍ—DÝüÞÍU'Øb£ûFIQ †üg®îu5.n~1*ó¤"ûÜ-I^š:…š©¹ƒHîW¨˜—{ |ÐTG»õ„2™Wï>º-´§^#?wžÙºP-ZÛ`u§ê¼ßù8­lŠÑ¯F ê„K2 b2ƒD2 ­¸øþñÓjikÓ0®×8gmy…yÊ Ó瑾Ðz·dËœ×î<“«!2Ôafwß¼öM$­JB | »c“ŽØŸ½ ¶/@ÿ”þwæ8ðU2[oÁ;ß½~L[@¤•¬Fç ¡ÒÏСzÕwÑäßzæÁ™+V;ÄæxuB$º*æIœJ•Î7¬\´y†Nóh'¨ç²í¤”J½²ú—gö ‹ «à©ì¯|ÿ`tÚhUÔ܉ӻmo]Fî,؉»>¼ Ý›wGVznóv,Z¿/}÷õ»ñáñºœì”Ø O ~__ÿ5º…w«Óº¿FZ~˜i‚!—ŠVH ¨;Ï”‰î±Ò5 Ræùr^Ìî"üååÑd>—R¢P«âA‘dyùŒ‹XtÆmÇM¹_%œòíæ´ý—“—ãAIÞÚ%]ËõÉÅå¯^ŽÌ©vha-¥ _·éð&y¢¸÷þé^¬Ùµ‰‘‰.åM‚›QçÝ<:LDy¢¶‡Ó‰E?gû˜çÍ»õ!<Ÿ¨räùX•ã« ()))Ö'€ ê$¤Û8 pþRôYeœâ‰¸iž¦ÝG¿zTß1Ä®sÏ¿óÆL íãy+bøËòÀIQ•‘œŒÊ"9QÒ«U/Œ>g4òŠó0kÕ,<9üILùjŠ+…m)JÏ'F<鞎ðâpÇ>Ñ[;x¬ÇIÇFa\$ùG>ZµØZãˆz›TQPPKmßîbÃb¢Ÿ5•;ÑjiïªÍÀ-¯ÞJP}Ηž*>„;Òä9)_6¥s°ö½ôâå8 E› 6cÔK£Tç!ÔÄ¥à¯}þŠÖq­1¸Ó`aòg“õ]CwL¹‡Žñû žÝÐîC±è–EhZÞT§¥ÛAÚ¹µÇI_·|oå8õØùG>ZWf¯]\M(ÏÈÈ8TZJ9_åxûÓhö:ÿóùy¾VÅ&%,±S%8?Ñ›2&ý+…ñoÿÌ|úU Ë6¤mª© Ò^nþXzd)î~ënmdX¤2Š4èžÔ] seß+ZŠýYûާÆ?…9+æàæ§oÆÒï—ê’¹Š‚ŽXjb*–MZ†Î¡«ôô!£½¶“s?½eÙd¼Eã.U‘ä£d^ÕàmÀÂe;vìØÚ¥K—®!!|Ù´ÃuHè  ×9‰Æ •ê˹ö1¥¡4M#d<{¨™¿Ö?aúó+ŸW“«O„,•ds¨Ž¢ºÔ/ç¾¾þu´Šm…±ýÇJ¯ä'ÀáÍ:Zï¸ÙäÎïĹ­ÏUEyüàñØÚy+?0Xï8žßù|ôîÐ]ÛtÅiMOÓZñNá¸ãpËû·¨í@¿ºjXÄÐòJ7J[ž‘ i ÙË6ujêx†í¢+..ÆöíÛ·HÔhlšoþÕ€¢Y³f}sÑEâgGŒëœÔ!¾!úþ\µ‚±b!¦~(Òƒ<1Lçù\6*(Ø‘ßÀ©ÙU^G§m¯G;¸®¿ÿ‹û‘W§›N öÂÒB½uÌëõëÒ•Ó+]ö´mÞKŸ^ŠAÿofm™…™g:ôy¶ÅÉ Ãd^”£ŸƒÇäÙCK2˜iƒ@à˯»&;îfòtºÂÂBÌœ9ók‰R *éâ<°LÓZRxìØ±t¹@¡»"Ø&®ÃF+˜M ©Ṳ­Ð)Â$mPK ˜ø¯J§Èx§ù–£ª®^ŠÒˆóÄ’'ôñ0ŽÖ£¹G%×áš'4GE¾|5ó ÉÒ°ilS|ùð—Hj”¾ÃÀ?Éa ä]Hzµ Ê^FJQÃLme°½mL{óÖ OJ0Æ“oä_ff&M›²þU) A•óVÅrŽ9ò³»pnʹŠ`}Ÿ¯z€m>5§X2ñS>‚¨%/R@$Ø™¾ÓII~™CìcXµm•3ÏDb°ð¾…h$?Þ0w Õ:Hæ[w"•>6Æsp9™î d<Ë[aÿýM•’oäŸ$dí ¹ ¢¥õ˜ùWDP!÷ûï¿ÿN@dÊk8¬ó0} XŸ²Þ𩆠+n—¬Ò®¤8;ĆŸŠ^x¢£UÂ퇷;ér4C¤0éå/^vê:΃i× _LúÁ¹ÁŽi ¦¾[#Ú+}ä¸Ò”¡5Ež`ØÃìUªøþ­•L®8°Vç Ò==!úôé‹e!o#«-Œì>² ÖJÀX¹ô ø1VBw-ÖØÜóOµ4?Úl܆íÀÊÝ+q÷ïVÅÏ3!u‚nÿY²j’¥¤³¿œ.)=­i“¡“F¶<ûqdœ‚­iøÒn—:E¿áU~~~Åo¼±Xê§éÉ£-ÀØfjyÂÈ #‡‹Š(ªÜY-Îr” ZY’¡àË4È¥ÖÔÀÂüS~*°Äñ¶ÃÛœùlÙgúL§†WW¼Šž÷ôDÚ—iúT‘³DzwêøwÕŽI^τֵ½æYtÖòŒ[ôïÙº§$ªùõóÏ?ï—~Dˆ–,r©š« ¼4‘slîܹ D ¸ ¬Kó.Pe"ˆëP)íÂ\ÊñN”Xù5ÛSìØš=k”&Ücðþâ÷usL¡f¿½x;ƽ1©×¥â®gïÂê«Ä¿æük0´õPÇDÃpöÝŠ“f&î)T:s°Q:í¹…Ú¿ù eôãã?žOþ‰'ÉÏj®&“œü³æÌ™³2''GÍÂö+Œì1Òeô+*y–Aó)ÆÐú‚2=?sÖÎÁý¯ÜôÂtÝBë!§‚€ZFH¦­ž†ó8)W¥`üã1{ñlôLé‰F¾b¶•ý‰Z/™Ï¨0Ïžv€´4teYÆ-É;úÜÑ’¨rœ~sss‹¾üòËï$WLŸž@žÁ•§7Ç*)÷ÅxŽôo¿ývÕ!CúØ¿$Ú¯m?ÌøvvdíÐÍ æ^´g !\œ{Úåà©™¸jÊU¨È”[ãò…~™›:”i쇗äñþ?w .9Œ?ÌÀ;«ÞQÒ.á#+ ›¤œêég÷F:p ¥´ÉË/ÄæÛP쎣ñâÅÜyX<ùG>òjÕ\M€…‰1.!¿øâ‹ŸŠ(#ºì¢æ–óoql{bIã)lèíˆ5¨ež{¾Õ9'ÚO¡4ç|î⦵/xj»0—åøžB³ÿ;’¹H÷’5B#Ú•>†Nî!éJ:KHEòÆ7ºðƒüÉÎÎ.2eÊ<)•.Þ«ø—cŠQ†Þ»Câ¨\øÀ7ß|³–è²»ÎÍ:ãšs®qhµÖMÕ Øp;˜¶ǽcöc§RÜ0×ì ôÔvÓWfSBê¾@žÃ‘/Ç=2Ÿåy®5˜œº5¡õç^)=¤@•#–/_Î¥-R´T‘a¼’GW› 6¹|à¯`<›a¼É3¡É7¡É?UCÓ†¦îqI%ÙIsÏ1q–3¢Ÿ ·H€øˆxÜ4ð&)Tåä¶/ÄêWB>I.@ñïqùgΪ ,G RŒðŽÒ~YW~š_ +Ýì/šè˜ X Éâ  ‚]D›‘&4£Ä„&ß=4ÇRèÞF¦MûìǘǴáS’ÒËyJGҔ瑮2ÿO*ôvãAAaíþ ¤­œÿÉ7ÖêÕÕÄ"W\Nì›?þò;vvŸ º¶ìª%ÕÀa)(l°6Þà ڌ{h޹‡ö2Œ»oiÓFOm±·™t2Ê8÷¥ž§kHy3òÉFcõuî(œÙêL¹X•#?vïÚþá‡.•\³þ'ßxe¯®.àÉl:͉+{yä‘we™Qá~`Ìycôk^l(_K櫤Qg:ïL[öw4;Óæø©ÚG¤½½ÌgZBZI«õÝ^ÖÄI3zÒPB}§Ðµ{«îþxaC•#È|p†äîO>Qy'ßjtuQDáN¥bïÑ£G·½õÖ[_zš ù8NO<Ý¡P)4RÀ.ÞØ,÷ÑÂÕ8÷Ëquu ³iœSˆ®³gÏ^²rÅÊyyÌruÏ\ûŒ¾YÃÌW. °Á0’ðªÉ›r )ôÔ^·öÙGºöÏí¸‚€×1ù†ùѯë}D|ò³×?ëJhI‘þ«W­Þ)V¿Å’Ü%ž»Xkû¥Œºj‡f®óù4Gû&L|sñ2ÌqÆ´iÓ&$''Gñuìînâô‰øaß9-dr+” O½›Æåñî'ž‚iÔU­¶EíÙÕâ¦C‚@B‚ÆH#:5ï„ÿ\ÿŸªë[1Îû{÷îÍ?~üË’µN¼Ü‘Â>ñ^—~œ†ì®¾à¹´F‰o%¾KPPЯ½öÚ¸¸¸¸àÐÐPÉruÌx«vÊ=r9K-„=™O81¤3¡#ujüw¥¥k›íǼÅÉt:K(s,)`$@÷”îxò/O:ÊÙþóÞLzzzѸqã^“e9™¿^üNñÙâ)g=º²*P|cñ©â»ÄÇÇw{î¹ç®nÔ¨Q€}ÿ S÷æWoâebþÆ«µÌ,e`BÇ©§Î;“í­¶ç›8C›·z‚ÁŒü+û]‰qg¿šÆ¹?Cì1¥·ß~û;r§–ö~2»x®Ô¸`45IÔÕðŠdS°xîAn#¾sRRR×§Ÿ~úŠ˜˜˜O’€ïßêã§p8ç°ýÆójFØ`K‘Z×n×zæ‰-àÞÃlÖbâ*㙦àÈ·˜{þ|º¥t“LWÇ‘/ÆžÒ‰'Δ۽ßËQ™cAåfßZ—}' R—²Lnu A|[ñ§Ë4púþóŸ7ò¤H¼¶à5¤-KsL$ö©ÀƒSÿ ó H$çE’cÛ¼92Ö8–³¼2Çl^E¾€`dß‘¡ë2Ï\‚s¾húÅwÞyç,ÿœïé·Š§Ñ‡Ì·×(ÉêîD€W'Û¨ý‰­Åw L#D1Œô‚µ;ÖbêS±ëÈ.}³*…vi`1_,æUŒ70¡Tö«»š˜mcÍ´)/¡“鿏Å|•Âø– -qã…7‚/±òä,…/WÄþL™ó9â¿M<-´^•>9æâN4xqŽcju‚ xà‹{žÓ39$8’UÝ-þq1f~=ÛH?æ^ºÂŠÅ- 8G¿âá·D@õ>8sìÌ&çmi3ò5$ãyز ð‘+ú^þû;/eÐÈ÷Œ¬X¾bï£>*ÛŽt®ßd…d~xN ur'bÀ¥—^j@'­HßN|êàÁƒÏ;vlÏððp_OÊ¡i1õƒ5ÛÖཥï9d ÁÀmÒt Œ× +mlòBÈ6ÙÛeÒVèTö#Îmz k«®^[NeOÖù¯¿þúŠO?ýt¤¢·EüñœóëÅ|)ïDŒXî—,͹t‚%+¾…x*‡)¢´zøá‡ÿÔªU«˜àà`¯Ò@ʪ›³r¾Þôµ¾G‡^¨³à2%8Ž4¬ÿ†ùÂ`§]€#^\p@0Ú5k‡s;‹a=‡92½üç¨çž¾;wf>ôÐCóEéÛ%EÉtŠþ=âié+Ú— Ý%ZwwR$€©^Ù:Í㛣crGt>­s­­!s8êeCG™˜Ú×ʨçú~¯x2§øŸÅóÖ|±0_¡Õ  £$àx¥ \,·3_Ò¤5ƒ:»“:¸·BÇám¤uƒDñÍÅszàª!¦OŸ>)#FŒèЬY³(‘>àcVu™"äüSÊ‘øeee|aG|åþýû³åÜMË–-£ˆ§h稧˜ß'ž7Ý8×›Qoi’cs l§4ÐGJê‘â)È|J‚+‡h‘ ‘C‡M=çœsÄ„àƒŸŸ¼ÇWÁ6^Ê7hGFÏMšÊty;™¼¤º”7oV¬X±÷“O>Ù.£=G:’%ž£ž çh'8âyŒ·t«zÉsºÓR8-P? ¢H©@= `hР–:tˆMLLŒ'6¦ ºûR°@\5,g‰×Jax¥kÊø,Å¡C‡r7nܘþÅ_ì–9ž£™K7†dÔñIEND®B`‚il32 -¤°Ìâè‰éèâˉ°É‘éȆ°Ïèèˇh_\\ƒ[ ZZ[c€Éèèϰ°€°Ïææˆdt~ƒ†„‚xjUææÍ°°°°Çåå}m‰„ŽŒˆ€s]rååǰ°°ääƒiæ…ƒ„ƒƒ‡‚€}pXzä䀰 ÉãÄ^uÃhnxw‰vutqeLÂãɰ°Ûázer’_hjŠihgcTwáÚ°°ßà^chbŠuZ^†_!^]\[ZXVMKàß°°ÞÞP\\YR…mQST¤æûõàÀ‹NM€N|MKG=ÞÞ°°ÝÝGQQMIE¦tt³Ôæéñ÷¾Àˆ>CDDCA?3Ýݰ°ÛÛ@IGDA?T±¥¥ÆÃE $(-39;;:97.ÛÛ°°ÚÚ8?>9530”yœ.gíÿá.-/12210/&ÚÚ°°ØØ2840-,,ÖºO¨`W·â—'+€,+*)"ØØ°°ÖÖ*/-)&%%ëâm “Uãæy$€%$$#ÖÖ°°ÕÕ'+)%"!!€æx)“Ôß €! ÕÕ°°ÓÓ#'$ GÃNamh‚ ÓÓ°°ÑÑ# €üÄÒ—‘Ë÷âš4ÑѰ°ÐЂóö¯ær>CØûê'Ðа°Î΂Èü Ú»N Îΰ°ÍÍ‚ vñ <ï [Ûêb € ÍͰ°ËË&‚"Œ } ¡cºî˜ !Ëʰ°ÇÊO€„  í âU SÊÆ°°¼È¤ ‡ › Îì9 ¥È¼€°ÇÇ\Œ ‚Ÿ WÇǰºÆÆHŠ €  @ÆÆ¹°€°»ÅÅTŽ  NÀÅ»°°°ºÃãN"‡ !N¢Ãú°°°°°°¸‘¸°°€°°€°¹À‹ÂÀ¹€°°°‘°ƒ¤°Ìâè‰éèâˉ°É‘éȆ°ÏèèØª”ŒŠ„‰ ˆˆ‰¤Öèèϰ°€°Ïææ¬—±Ä͆ÐÏÌÁ¬¦ææÍ°°°°Çå娭Îáêï†ñðîéßÈ¢žååǰ°°ää­°öÜåëìŠëå΢¤ä䀰ÉãÔ§ÓìÁÓæ‹çåßÇ—Ñãɰ°Ûá®ÃߨÒÈÝ‹áßÝÔ´¨áÚ°°ßà©ÏÝÕ×ÍÐÙ†ÛØÖÓÒÏËÆ²àß°°ÞÞ¯ÔÙ×ÍÕÎÏÕ×è÷þûòåоÅÈÈÇÅÀ¶“ÞÞ°°ÝݱÐÒÑÎÅßÌÒæíòñõúÖÛð¾ÁÀ¾¹²’Ýݰ°ÛÛ®ÍÍÌËÉÁÛÓÓàØ¯|hr¥·½¼º¶¯’ÛÛ°°ÚÚªÈÇĽ¹±Î·Çƒ¢ôÿ캘2£¬´·¶´°«ÚÚ°°ØØ¥¿¹´²²±íٗΩ °ÒíÇž¯²²±¯«¦‰ØØ°°ÖÖ™°¯®€¬öǥïï¥o¥¬¬«©¥¡„ÖÖ°°ÕÕ’«ª©€§Ã聾ÄÂãéo¤§§¦¤ œÕÕ°°ÓÓŽ¥¤£€¡ –|Ý¥®­ cu”€¡ ž›–|ÓÓ°°ÑшŸžœ€š˜‹ýÜäu¾âûðË”—”wÑѰ°ÐЃ™˜–‚”“øùÆf𪊌æüòÀЉrÐа°ÎÎ|‘‘ƒàýHcéÒŠti]ZdtlÎΰ°ÍÍx‹Š‰ƒ‡²õMmôYêò›mx|{iÍͰ°ËËx‚‚ƒ€ƒ´Wpz­[ÄžÐó¼nvtlËʰ°Çʇx{{ƒzwkeqyohô\ëM_kj„ÊÆ°°¼È³hp‚qnloqom¿UÝñmYc^²È¼€°Çljh‹j bYa£¶Q[„ÇǰºÆÆ|`Ša ^\ZPFIpÆÆ¹°€°»ÅÅY[‡Z YYXXUOvÀÅ»°°°ºÃï{`VSS…RT^x®Ãú°°°°°°¸‘¸°°€°°€°¹À‹ÂÀ¹€°°°‘°ƒ¤°Ìâè‰éèâˉ°É‘éȆ°Ïèèˇh_\\ƒ[ ZZ[c€Éèèϰ°€°Ïææ‡ds~‚†ƒ~wiU€ææÍ°°°°Çåå}m‰„ŽŒˆ€s]rååǰ°°ääƒiæ…ƒ„ƒƒ‡‚€}pXzä䀰 ÉãÄ^uÃhnxw‰vutqeLÂãɰ°Ûázer’_hjŠihgcTwáÚ°°ßà^chbŠuZ^†_!^]\[ZXVMKàß°°ÞÞP\\YR…mQST¤æûõàÀ‹NM€N|MKG=ÞÞ°°ÝÝGQQMIE¦tt³Ôæéñ÷¾Àˆ>CDDCA?3Ýݰ°ÛÛ@IGDA?T±¥¥ÆÃE $(-39;;:97.ÛÛ°°ÚÚ8?>9530”yœ.gíÿá.-/12210/&ÚÚ°°ØØ2840-,,ÖºO¨`W·â—'+€,+*)"ØØ°°ÖÖ*/-)&%%ëâm “Uãæy$€%$$#ÖÖ°°ÕÕ'+)%"!!€æx)“Ôß €! ÕÕ°°ÓÓ"&#FÃNalh‚ ÓÓ°°ÑÑ# €üÄÒ—‘Ë÷âš4ÑѰ°ÐЂóö¯ær>CØûê'Ðа°Î΂Èü Ú»N Îΰ°ÍÍ‚ vñ <ï [Ûêb € ÍͰ°ËË&‚"Œ } ¡cºî˜ !Ëʰ°ÇÊO€„  í âU SÊÆ°°¼È¤ ‡ › Îì9 ¥È¼€°ÇÇ\Œ ‚Ÿ WÇǰºÆÆHŠ €  @ÆÆ¹°€°»ÅÅTŽ  NÀÅ»°°°ºÃãN"‡ !N¢Ãú°°°°°°¸‘¸°°€°°€°¹À‹ÂÀ¹€°°°‘°ƒl8mk–áúÿÿÿÿÿÿÿÿÿÿÿÿúá–©ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý¨#îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿí#(÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷!îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý—ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿˆâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜ—ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ§èÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿç÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿö#îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿì!§ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý¦–àúÿÿÿÿÿÿÿÿÿÿÿÿúà”ic11 ‰PNG  IHDR szzô AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs%%IR$ðfIDATX ­W{L•çÿ}ß¹_ÎY¹ÊU× E`ÒdÕ‘Ö•ÉRbÔ²tþAÓÙŽº–hZ3×EÛ¦ÆhÖÎh»%µSY £‰mmœSÑBlD®äp¸8×ï²çy§9 LÝö~çù®ïó<¿÷÷\¾ïH­­­Xe4;„ÞH/Ò‹ÓÑèƒgÔ³Û,X`¼=ʈiè\’OB×?»Ð?ÕwØ'…ãØåv»mí·Ûaɶ@uª¸à½€ ® è\èDÄl”ƒÕ5‚A¢%i°æXÑv« õõp¹\ {@¦Ñh±‰ŽÀä4! 0£ÎÀar Í”†Qÿ¨ÈI~pêjÌ¡8«|Ô ZTCX £{¼[ø2™D_ËeF¦ŸeÎ<§É‰°†*«¸¸‚­Ö­…C Œ@6Ë`5®T&W"Õ’ŠˆÁdpƒþA\›¼†K¾KÐ-D{¼b8o˜  Á6³CÃÄ„s>å $…VIé¡è IÁW3_¡.«7¦nÔ¶»¶£ÀTP£õE|°­H·¦£¤eŽ2¨~í“í0­1Å@$`&zà;ìSà²áVÃUšJµ¬«B4£†–áìÏÚùÐ<æ¦æ0—4‡éÐ4®ÞºŠŽÎôz{a´aL2Âä2Áœj†ÙbŒqÞŠ<àPÝ(mqìs !%= GTB +"~³¡Yx’<Åú”õx¹õeTäUàøîãx­æ5 O ã⹿ºC‡b!=r&EˆÍ8…ì’„¢äƒÂKˆD#¢?BôS#áÖKjbne^%F#hü²‡wFGoêÏ×£0¥ÛÖmCÝÖ:¤%¥áÔ­S0:©kj±P.@‹S·È8^ 4‚:«‚Û)ç@"€T[*œ©Nä:sñzÛëhxªû/âÅí/Â@Û{íï¡éj̹1ú% à±È¿™^d"ÑýâU †U±r^ýriìl„Q2Â!;`“mxçò;Ø–· ­ß´Â7ïçPîÒfˆ_®¿æÐÄý1¾% ( ¥v„Ú'%àrÎ|óGüáóFlqmÁ™Ú3x÷Ê»è¾× §î@O>½ô) n4#éRÂqňÁ¤}C@‹Kd`)êÛ Ä@qRr@¼ˆ“ÐíAE~釰ƺ;NïÀ±ŸCQnžøþôæ+Æä¤ȑ3]gà zD9 %J!NÈ¥! ‡œ€ü¹OJH#ÅÐA0DIN ú†û Ì*xvÓ³ò¡álªOW# nKÚ÷¶ãâ7J† •‡cqÕp ÄŒÑF(YâU°H¨8ôŒ÷ 4§Ï¿ù< k ˜Ï£ª° wïàæøM”ÿ¾úy¥ëJñÅÍ/ðdÑ“èü]'úû°ï'û Û1'šér£[΀BˆD.$! ¾ ¬ TŠbâb7wçÿuir$;•šèº×…“ŸŸ,;°oö6ž+y'jO ¼ ÿz’5ÖR )1fcÍ(Ê90ÆÍ%! f&­!DÙrñÎ{qôoG!¯!u.w"âÔÅS’$To®ÆÙ/Ï¢pm!^:ù^=ý*´Y çÙ è(É(¾Ø'aж°° Pí-Þ u†Óä¸+éÁeB ÄÛÎBÚ\b!®5Âb’Ðr­zX‡w΋÷ó>6ço ¹5¯a÷¦ÝÂ'*s†ÚÚÚ¿Ó7ÚA‡Ã!¹ínøçüøÖû­0,j™ëy%á÷×b‹ç‹×7:„nóåf*i rS%Ú®¶‰/åêÂjTW±cLOO³F Çžƒ~Þï÷ïs:¨ÿq=¼~/¾ù:F/=|ØA< °ÌÎlxo5¿%hçë²¼2¼RùŠ Ÿ|±É¿ÐW±OôºØO”Lp(8ŽTÁ3Ï@ Q((Dýr ?@8âmJ ‡CÃ!‘lžÞø4ŽÖ¶ÙG0gŸŒ"ñŸQ]ß¶ÛíV›ÍÆÏ0èĹëçÐ=Ú _À'¾ăXÈÅéJ;³l‡scÖFì)߃‚Ô1s“¢÷-§ÕòÍïÐ Ð'ºøkfµZ]D(ý¿vœt¡PhŠì•‘¯¸ÝxÄ5=裓4šxÖçóiŒ8±kÅ•öȺlƒm‘ÍOH/#Ñ9Û (Ñ Màý±ñkR>Nò3ºÎ"ùoþžß%½ÏH~KvWü{þo»_;nDÙÕIEND®B`‚is32·‰°€°°Òçƒè çÒ°°°°Ü¨iX€UTTb£Ü€°С—eln€m j^KŸÎ°°ßa{lei€hhgcTXß°°ÝJTbO âΈHF9ݰ°Ú;@aªçê³M+24+Ú°°×-0Aµ\•¹•%' ×°°Ô#$VºÊÔ°°ÑH引›Ñkΰ°Î&w”,/Ȱ°Ë. aÌßœ'ð°¿~  »j¶€°Â2 &k²¬°°°»ƒÃ¾¸¶°°€‰°‰°€°°Òçƒè çÒ°°°°ÜÁ•‡†€…„½Ü€°о½±Á€Ç ÆÂ°¼Î°°ß¡ÆËÕ߀àyÝÕ¶˜ß°°Ý§È×ÎÏæõìѼ¶Ý°°Ú©ÆËÝôõÖ˜Ž¤­Ú°°×Ÿ´³Ü¥¿Ñ»„Ÿ§‰×°°Ô¦¢“¢ÖÝoƒ›žÔ°°Ñ„™—’£ðÓ¹Æç²oΰ°ÎyŒŠŠ‘°¶m|ljaȰ°Ëyz{zxn—]Þê¼bð°¿œf€jh`]ÑLF‚¶€°šo\ZZYWSU²¬°°°»ƒÃ¾¸¶°°€‰°‰°€°°Òçƒè çÒ°°°°Ü¨iX€UTTb£Ü€°С—eln€m j^KŸÎ°°ßa{lei€hhgcTXß°°ÝJTbO âΈHF9ݰ°Ú;@aªçê³M+24+Ú°°×-0Aµ\•¹•%' ×°°Ô#$VºÊÔ°°ÑH引›Ñkΰ°Î&w”,/Ȱ°Ë. aÌßœ'ð°¿~  »j¶€°Â2 &k²¬°°°»ƒÃ¾¸¶°°€‰°s8mk0ÐûÿÿÿÿÿÿúÍ0kþÿÿÿÿÿÿÿÿÿÿýj5þÿÿÿÿÿÿÿÿÿÿÿÿþ,ÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊûÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊ3ýÿÿÿÿÿÿÿÿÿÿÿÿþ*eþÿÿÿÿÿÿÿÿÿÿý_.ÊùÿÿÿÿÿÿùÊ&ic14±…‰PNG  IHDRôxÔú AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs%%IR$ð@IDATxì½ €eEy6\ÓÛ 30ÃàÀ0H73싆Å% .1"¢âï¯1*âÑhÜ~?—ßßĸä3ú¹"1D#Q4¢ÜAv˜fe˜fŸž}éîùŸç=õT×9}îíÛÝ÷vßî®ê>·ªÞzk{O÷y«Ns¦8pÀ%—$$$$$$0¹$Ð2¹º›z›$$$$$$@ $ ƒ$$$$$I(dL“žºœ$$$$$ €4’’’’’&¡’0 Ozêr’@’@’@’@’@2ÒHHHHH˜„HÀ$<é©ËIIIIIÉHc I I I I I`J “ð¤§.' $ $ $ $ $ $$$$$I(dL“žºœ$$$$$ €4’’’’’&¡’0 Ozêr’@’@’@’@’@2ÒHHHHH˜„HÀ$<é©ËIIIIIÉHc I I I I I`J “ð¤§.' $ $ $ $ $ $$$$$I(dL“žºœ$$$$$ €4’’’’’&¡ÚFÒç)S¦Œ${Ê›$P«Ò@«UR‰¯$p ‘Ú0±%pàÀȇو €‰-ÞÔ»Q’@-à^ä,>JMOÕLR 5o1^‹X†“§–rO’@ÍH@Í¢JŒ#”@´ãââ4…å‹Oñ¢¯ôj¾òTãIiI±jhñ}•UF'­Ò˜¿ò'?I aH@ÃD;© ®¤ÜD/úiEzWX‚U¼è+=ùI€ºè«.Ò‹iq\aò+ûÏ*/æ‹i)œ$0b $`Ä"œô”), Etú ‹ÓO1^)è±Ïð`Nõ Æ—Ò'Ÿăõ\|e>i¢³ÅE,çQ¸l̪<ò$—$0, Œ¹ðƒü`X O™ÆF_|q™2bcjn>u¢ü1¥°•ûÆ7¾ñˆ³à¦OŸ~ì´iÓŽkmm=²¥¥eüY؈:ÇA`œŠ£Õöt èŒË©^Å“Ÿ$PMØ>l¶b¸Ç{Ýcgooow__ßFøOîÙ³gÙ®]»VÞ ÷Ío~s=x•Ÿþ`XŒ§¸˜?£ ¤åÆ3ô¨êòÇ OÇ´•S²±=¼6Ôã)€d Oö£•k€ƒ8›Ç¸3ðÇvêÂ… _Š™ü9úãðspLc•\{{»;äCŒwÐA¹ŽŽGò; «v0?R [ ý$ SR²ôy`Æo€ÝØÝþýûݾ}ûÜîÝ»@Þmß¾ÝhÕªC9{plDþeX9øÃ²eËnúøÇ?þòðcŸE)NÐg˜.6ŠFAÆá“1GSE’n4Å€ô3D­<«Î×âï|ç;ŸúŒg<ãR€ö³Ø'˜gû´\Ÿ Ø3gδËüÆ<žàž\’Àx“ 4hìܹÓmÛ¶Í%Ž·¶À X câ7÷ÜsÏ÷¾ð…/¬Ÿ@¿ÌÅÉH`˜tŒ—Œ Ц$ c6k}»fûàÑpÞcñO|âg.X°à5ðg¸;ì\¾Ï9ü¬Y³Üa‡f³yÎäÈçD”"\4¸rÀUƒÍ›7›Q@¡è`ìï ¬ܾtéÒÿÀêÙ½à!Ð ì{– À—_¶R«"9qŒI$ÉÕ7 Зû ·üÍßüÍÑçŸþ›ê/ˆ/àç6•rÉž3û#Ž8Â͘1Öì9ÛO.I I /® pÅ€†À† Ì(ðç˜ÀÓƒ`)6Þ|ûí·ÿëW¿úÕ'À ƒ@FAÑ—À²dÐϹd äÄ1j‘d$ áƒm„ o`FšÿÅ/~ñÅGyä_cæ~Àü¸ñ|p|Þ«O3ûX:)œ$04 p¥€FÀºuëÌ Ø±cG®Û±’ð‡'Ÿ|òßßõ®wý‰±1 ° ?étŠ'c “ǘü&  x%À/ã³Þ°|ð€¾§µ^uÕU—Ι3ç2Ü“? ´0Ëçf<.çà °Mzivé$—$Ð p•€› ø®»»ÛöDUa¡çAúè£?Šeþ…ª„³ý®®.{¯¾hÉOH˜œàkŠ—/_nOHøÎÁÒU«V}›  2üôéÏbøM†@EÕ@2’P:@FüßøÆ7ÞŽ |ïÄ‹xžÂÂùú]~Lç¸ãŽ Ê)­4“’&¥¸W%²÷ àMƒ&¼ˆû7}éòË/¿iE Ž#$ÉÈ § À¯Ýü•–ú9ão»úê«ß…þ»´›Ÿ;ù¹©ï¨£ŽÊÕ‘"III•$°zõêܦA;ð®/^vÙe_Dž2ÊVÒfÁJ‚-¡' 6,þJÏîðÿË¿üË»0ãÿ[ÿ FàçN~>Æ—\’@’@’Àp$ÀÇ×®]ö ÀØ Úÿyó›ß\ÍÐí€dÔ ôd$ÀÀ_³}ùÚÔ'ßîïclñQ¾¿ÐÀ?‹cÀÏÙ>gýÉ% $ $ ÔC|„«üœ1 nG¯E´ÒŠ@EC í01ÚO2&±P~-ñkÆ/?€>xZ±K÷yÇüq.3øñ?{E/ãÉ% $ $ Ô[|å0ß) C{Ö=öØcïÂSFÿƒºt[@¾ ùñÓÖ´d8Nþ†}š¸oc¤nÊH ÁÌs¤õs·èˆËo”¿fû|ú}ÿ6|äãØ¼àÿâßÏoÀÏOíò˜Èn_ß>·e÷·³g§Û¾w»Û¹o§Û½·ÛÓ³ÇíÙ¿ÇííÙkßWï=ÐëzûpôR9·¯gbÎþøýu†‚«uèFYBÞh¸rçªÑµÎ1¿bÙÚÂËkZÛ\ë”V×ÑÖa´©SÝÔ¶ì˜Ö6ÍMï˜îftÌp‡L=ÄÜ~°›}Ðl×ÑÒÑèiù|ÝpüÊa~wà–[nyó×¾öµ•hXqE€#%9‰OfC “Ì(€?a(>´ÌŸ~|moÚÿ†Ãçv_ þ~v—ËüÇs ¢ÃmܳÑmÞ½ÙmÞµÙÀ¾{w·Û¹g§Û¹w§ã£JflzÐŽÃÖû˜‰£h 0v}¾(K 6‰fÄЇ ý6³±0à ã'ÊGZLg˜_Éœ1u†›yÐL7ë Yf6ã07ç 9vª·Q<*h›ýgŠûvîÜùƒ÷¾÷½ïÆ;ö SEC€@Ñ’œ¬F@2&‰P~^ô„-ùÇ~˜ñ#½íë_ÿúÛð!ž̦1?ÊÃÇùZ[³ iãÉm߿ݭ޾ڭ۾ÎmÚµÉmÙ¹Åuïì¶™»{JK†ÌŠg/*†À¸â6ã§DqÃÕ/ª»¤ºDj„DÔXø üá\V(.€9Òã°±Ge÷ –EF¢¸7˜Î•…Cgê;Á ¼ˆë#ÝÑ3v3;fZyã퇫m||"¢C÷ ü™·¼å-W!J# hPŠ2䃔¹Éf$`ð'Œèð ôç§wùö¾3Î9çœoèçñÒ˜5k–?>ÚÃè¸qkw®uË6/soyÜmÞ¶ÙíÚ·Ë@ÛÀ@o íUaKÓí%/)Kc¯c^‹fSì…´XH!ŽGª‡¥Ü«s¥Ôf—@Î \Ùy´ˆ÷¿CNK÷i —ÅEWšÅa(ˆÎ[ ‡Ï<Üû”cÝÂúù‡Ìå‡_3LC »»Ûš ù¬½ãŽ;^ýJ÷ƒÀÛ4(4†«Þ˜LF@2&°P~Œû0ã'TìuÈhà {:®¼òÊÆ2ÿ«>e¼=Ò··oÛºÜ-Ù´Ä­Ú´ÊíØ³#|öä9Ë·ÿ~# ?éÞ?eH‡`,¯ŒDL‰´3“£´8o`1¥Žg§ÄåÀ£$=‘šTù¡1èJ4»‚|!¬® èY ƤÆÃ7Ê'®(xÁg†„ç7:Œ‚¾Þ>wÈôC\çœNwÂá'¸³¸©­SÕ‚¦ö ÀmÿzÛÛÞöîíÛ·ïCË«4´ )X8ôo2ɘ @ü ):гþþÿøÿxÁÉ'Ÿ|Ëëý›õ‡+¢I\Ö_ѽÂ=²þ·|ýrtàÛ’¾uc…#IG`-Ÿt†ã8Å 8ë’3€öј®ôà÷g ¤\`°ôsŠŒ…†dŒZŠ®@3p.ò ž£Gyú"¬2Ÿf ^0 h$”¼U ¼–à•ÑE£¿àÈ§¸ãf7.np5€ß Cû»-Zô¶ÿõ¿þ×/€I¿ € f€ŸãŸp"Ð׌Ÿ>ŸËým§žzêŒ~ô£Wã+} n»ûyŸŸ¯ðmV·sÿN·b@Ý#nÙúeœÙ'„ðÜððé§D¸ÓºH³8gî;<üÅñ(œe&«g6âä)s2Û[‘·,¢5Œ#uÊˆŠŒŒ"ŸÅcÞ’€|emˆâ @Πàúâ=þÈãÝ©óNuÇzœ›Ñnïþ©’Ÿ¯¦! ÇñÕÁÿùû¿ÿû7=ôÐC;Q! Z Ðj€üЮ‰º € dÀŸ£C€fûòÛ?ÿùÏ_ÔÙÙùE€Ñ´©S§Ú&¿fÝÝÏÇñ–w/w‹Ö/rË×-·ewu°_>€˜k )àC Џ™‡Na*Ì8ñ2݃ºÒ}¦ÌóiŒˆÏ⟬š˜b¼,oÄ®EŒ¸ “¼€‘žÇ"¸ÇÃ".;æ aþcƒ ·AЧsYŸŽ|*ó@/B4bøO:@ž±ÆqÑc€<Œóº9~îñî´y§¹‡6ïm>-ÀM‚|šýÙ³råJ|gèÝ?„8öãÐ*€|JLÃ<ÌMD# Ä(ÿlŠÛÿ7œ €qlT¿Ž0ë­ý_ÿõ_?„/öý ӹß÷ú›éѾu˜í?¸þA·xÍ"{“Þ”VÎ̧¸–VÎî ÍÃÌß €;W˜ùàÉk†=Ãn}+‡ÐÍlÚ `Edå@¥eiw¥AhtÈ™²ˆ…³232óËÅôŒQ)õã64¶¦TúH% P.–èýÃ)x4Äúi(@ β8€Ù™óà¯¸Íæ‰é Ä+ø}–ÆUòùÍ‚0â8ŸËg~Þrà› ¹*ðôyOwGÎ8Ò7dì==2è÷ôáÃ_}Ó›Þô)´Œ«4Š«ECÀ:1V’0N €ð'à™bààÑEÍ}ýë_ÿ_xïBŽÞ¹sç6ÕÿUÛW¹»×Üí–>¹´¶ÐçL\fþÐ-ͯ( Õdy( ›Å{ðΌܢ™àÝÓ(›€ïÍ@ßg7æ%«÷-¢$±µ¸ÒüµdO­mB‘‰u0 ÔpúãóÀ¾¬Ü’²Ä/ß²žgÌñ*€xÌ'ǦçÓìðÓm†ïãGšîÿ‡Ya@+ôi˜Až“Ž:ÉûÔsݱ3-ëá˜Ð¸ApݺuV7^'¼ä[ßúÖ+~ô£‘@@FoÐ ¤ñ¿ €qhÀ_ÀODb8^îç.ÿv,q½è„NøÀf*žówO}êSm§?ÒÆÜ-޼؀í¦µ6Ëg8Û—úmö €^}Qôž x¼‘`À2´ô¿@ùèD§" |–`Éöc<Z–ñ„ô,Zñ·V¾Š #Á`ùR–ÆI >'±AP¬1ð˜cGº=Ð îüó ntÒ§#(›ïÓc> {#À@Þß&° 3ÛH¨¸ß#€Ÿ<¤õd†é¼=pî±çºSçœjmë®<þøãï  |ö>úè£oÅKÐnF»â•møS€ 7^W’0Ž €ðµtøuhÖßZû5×\óÿzè¡o"/–þmÖUDÇÎíîÙíÞô°»wÕ½®{Wwø x= øE +Lç}}üç@tã%°ó߃=ý8®°ùÙ¥S"ʤãËQœé¦pYÔ,_,2#$OÊÇPG(3Ÿ’bQþè™Æ€€z¹4_óÅt Gu0ÒAq„‹+(*¤“Ï@žÏ2àöbc ÎÅø9cÀ¯6{ÆlwN×9îôÃOwÓÛÇöqc~¨‹«üÚ E¼uëÖkÞð†7|a±!@Ð×aPZvÀŸ«É'@ð'à üí¹~ÄÛN:餃ñÌëûS88›aÉŸûüw­¸ËíÞ·;oÞÛ' Ã'sŸ~¿@<ôÅ'Ÿ4núøã[ù̓¿­ @–Ÿñ.6H²¸2†WZ¬sélP-®„ êµ–œ‰g"J :õÕÆAqÈ S$Š} «õ…86pG9pæ1 €8îgú6û÷t{lYf÷ÿ½±€Ÿ{h€ßòEFi|zàÙ ŸíΘ{Ƙ¿S pK`ÞrÑâÅ‹w@,º%@_Wxæt 8þŒ€dŒ ü ø„¿fý¶äÅWœôüç?ÿ€Ó,.ùwvv:~Áo¬Ÿß¿ýýîŽw¸½ûðe=ø±oa?A=“!@ðf:ÁÖ|„Ùû@G„tÒćiа¦Ô¢¸åâž=+‹m‰J†2ÉS`³ù|H¬¦ø‹yS||I`°s«±4h¯5Þó”Ås4êÌ.°Wº<é|K÷ãnëËà=Ÿni17”ÇŒíðF€ ŠÔq{ÎñÏqgy¶ëh»ÏãÕÁnùòåº%°íÖ[o½øË_þòbÈE+Ú C€Bc8ãév@2šÜüãûý¶äÿ¹Ï}îììÿ¦µží_´y‘»í±Û쳺Z‚zظA³ÿ° ã#0ãßfö ²lä1¶¤Ì`Àõ˜ô}ò„°§@Fš ‡@ï'X Gé ůëJ‰wT% 0e¥ÕÎmÍ ð’Ï¡zä+Õ@àœæè 1ß l ä ov…éÇ›™Ïʇo¼~öotÒ ³­˜1àÓfN›éžwÂóÜYGžš>ÚøèO/VÞÏ íÐ-í  /ð—oÍ/F@2šØ(€?ç­„'ù?gþßøÆ7ÞÏõ¾“|Gq„Ýï+ðXÒ½Äýjɝܿ›Ã²¾€^3÷çm€3ãì9ï#À®Ã€›@¯çú‹ O#‡1öƒ¼Ñ<ø›<òÞy 8“pìÃdaY‘o‘J?ª«Rº§Ç ¡òÉ’’ljxn ŒCr5°«Ìà‘颼Jqüˆ4ãC> ¬Éoc¾Œ€˜OÆiqX`O?vÅå3¥{?йR€ãðƒw/<ù…îÄÃN´.öûÅ[ëׯ7IáM‚_ºüòËÿ ½8ˆÆ€ H)g0ϸX H@“øBtüyÁ¿ýÚk¯½ Ëü/EÚ˜Þï_³cûíªßº•Væœ`.à·™=ãx6\`ïãFÓÒ?Ò)åW˜¾¥%g<*Ïüô)ñ3LÅ­œŒjt¥‹D^¹¯ˆð+Ñ%Êe AS¶!–MC:¿„“GP*s¢ °ÅcôBÒt>€uÌ«°ød˜QçGÙ¶¾¸¿ÏϰâsB£ŒÆã4†{{²W ›AÀtí@xá‘ Ý…Ç]莞y´š;ª~¼/o üï×½îuoCt; 6¸ UJÝ$ßì+Éh2 ~t†?}mökÇŒ:îQýïñ?­­­Íáq?{­/3¦Ûºo«ûãÚ?º{VÜ“-Ý ð¹ŒO '°3}økÖoùŠt;¤ÏôÓø_ðM–„\L“/ã"Ë÷<¿@EÄåy¢)c1 Óõ3Ê6ö00E3ê1Ô‚f™«TWà÷Ù´ä¯2ôd¡­ä‹€/ºÕƒ²èË8`á`~Ä5ËtÒdÀ‚þžGqã‡Apî‚sÝ3ŸúL7{Úl5{Ôüîîn‡Ç]OO¿'ð öX½ +»ÐÚß ´Ã‰jVC MdTÎøeðÁ ^pÄÛßþöŸµ¶¶Îå&¿ ŒÉüîZw—û͒߸ž¾žðš­èû™|K[ÿR¿fýä#ðc`Ê<ðPŒ„˜F…ʸ¾xäSKXØýá˜V䉕uà#“whà ί<ÉŸÜ0Ь—¬dÆekìÅ4ãòyD/õ#KGœ~|”ò@—!à»ÏÏ€2 üœ'“Œ¿rÀ÷øm€·xxz{K»{Á)/pçu~½$Ys9ü²àÒ¥KVØöuW^yåŸÝrË-¼?2èSš:¬žf4’Ð$@ àOà§!`›ýü'¿èE/º`4}¬^é»rûJw룷¸Í»pŸß–ó¹¬ï—ó9Ó@“îlÀÓø¤…×÷ì îvˆ öqN®ÍX ¡—/ùÉâFóaÑŒ™,(‡N<©‰>e5çgíè'ÅqSžýI)4É% P®‡4¶¦ý=ïyÏ™ú§ú}€NûìÙ³]WW—ãG}FËõèq·=~›»{åÝ®µ­5[âð{Ð׌ÞÀžÆy£sæ ‘îù ¸À¶B€ŽÅÿ˜@¹ôØCuä@?äAY1X‡0òÑ1èòXÃò×ÀšX&‰ê>&0D+Óò•D ïþ€1Ë•A…I‹^"Æç}ÝR0`ÞH>›Ñ÷P–úþ…[ÞPº­ \Û+€|ÌÏð3>Ó½pÁ WFËñ#B|LpË–-”Áþ_ýêW—à“ê÷ ~Ü ¨Z €ÂÞ›ks`2ÆØ¨ü9ûç(ïøÈG>òì³Ï>ûZS+wúwü‡ R„Ãum}ÌÝúØ­nÇžÙLž³y¼7lÉža-û{ð7žÜÅǶÛ4å±ûû¢Ë(ðq¶[ÆÀÞhHW•£Éăz,Ÿ˜žËçóP¬¾ +¼Êy«ðWMª±Îªe¤Ä¦@„:9ß e VŸòÒyEg±!ìž4[æWšèÞ€ ÎÜ&ÀGà‡Í ˜ûô°RpgZØÈtð1nÆ„Vüm™Ógº‹N½Èô”“ØÌQqì>!€pïÿøÇ×ýÃ?üÃoP9 Ý!-‘4© €14† þŸüä'_tê©§~ƒÌÀŸ_ò-Ç—ùülÙÏÜâÕ‹ïåÐ Øv_ß¾ÑøÞ{üŒ¿ü2 H' üÃl߃¾@Û|² ìåÃx [Ž'ÔÝrùð…ÑÅļ‹ÊdBYÞ|†›lhä˜eÇ¥rñ¢Ð#~–!>ùÆîá@M -Íû¤ y0O8À#gšÂú>€ñyC@+ÆÓPF%ÀŒO;öiîe'½lT_"=&ØûÐC½åÃþðÍ˸2’0F@àžñÿ§ú§‹?þøÿƒÖ¢güí*…ŸG·<Š{ý˜õïÍÏú ð¹±³wþ°e|€s7€'xûU3âY?Õföì 7¾:Ì8 è’t daKc’7,t(#–U”N2•aÈOBœžé;R+:æŠËÕ5”Œ‰·é%0”±¶Ž½ÊÕ Ëb]Æ¥³ îФ+Ÿ u£y_yÊhäå=|úvËK£ÀÏôåÓ€`ºñ€Ý€<0&Šà?`E@«Ít½§Ì±·Ÿ‡.42}=öØß¾ÿýïÿê£À½Úд·’0ÀÀß–ý¿ð…/üßü^õ¾Ó¿«« ÁÑqÿ½ô¿ÝC«ÊÍúyߟÛñô|nù_ïWd¸ûÙ}X/ÖŒö!Ž€åñ@latYÀ9 NðÇ?•Zà‘A@Qùr$5ñXÜçSÚÊ«èâü9…[dLñI#Ñ¡®’±Ò*IÞç!ŸvÌ•§´ØÃ̦Õî(N>[@sxV—€žwÅŽwüÍFGØŒ>,ºÝ&(Þ€1pV×Yî§¼"îUCüà?+|`ÅŠz÷»ßýmT¨•€¦6’0ÊÀ0Àÿ¯þÿ€5ªà¿iÏ&÷ãG~ì6toö¼à—ÿ9Ë'ÛŒ^÷þå“î p__gù~9Ÿ`*°çÌžaX‚6ÒìŸ|u’Æ¿\1§‘'䵈rQ7EZ¯Ÿl!«»@S´Z>ñ$bK ÇÛ$ Lú1_¶|Ñea€NP×µâ]Q» €tÆÅ«0Ûò1 3}Kp€4hÀòÆ[œá{@‚û3£€+ E£`Þìyî•g¼ÒÍ>w0Ô%½`|FÀ·PpÓÉE`¨à÷ú¿ÏöiTÁÿîõ´÷÷ó-_6Û ·r©ß–øû—ö3ð×-€~°7ƒÀÌc8~yÈðg0Ûü°¶‹/ûè°C]ä ^ÙJ+L£³ç^?dð‹Î+††ÁžžÅ-àÃ9C4€·ñÐ-|,'~»ù̃´>¦û%~­”Òüê@/xùaï~è®)­îÏO{‰;ïèó¬©þ‰¼3àÿÁ÷¾ƒ:›Úk€»Û'£#¶aþk°D_ùqÉß–ý?ûÙÏ^2àÓÒ›ÜO<ÍÜÛ[3ÐÇl}J[6ËýÌžËùaIŸ`¿ŸÉÇ{l Íò ø‘``MÉð ÇU 0ÂŒYÔÂFÊT*PY"¼ô=• œò~+dz•ð(  AeWaIIM$‰r¾*÷COÒ}ÅaÎëÍ'°G¦Œ”]«F÷Å‚‚´j×*ŸÅ˜ª»¦ƒ ËÿÔØUèK<`ï ág¼3»"‹÷MA~Þ+ Na),Œzƒ«¤˜Nð¾âðyÚƒÆÀ÷ÝèÖl[ã.9åP뺺º¬Ü˜ÝýiìÛÚ=ß«P+:fͤŸ ®ãD&O‰×P;+î¡æ?^Ì `CýhöËÑj'¿ü?ö±=ÿ¬³Îºš<£yÏÿ?úO÷ø¦Ç3ð×2?ža^„\ÚgœËÿðµ€çÁèäñ3ý¢¯}ì¹ÂEàgœ—‚ù<ˆÚ9¦´E=¹sîéY¢ýf?1="ç‚•xFx)J æêjÂÈxigŠ®©›4Ôó6öUëUtMج]xU ‡²@7½îÓæ>gô̪2¸ À¸í`é¶œŸa[àíƒ(¬[ºÿV¸À·—Å+>¼`îwÙÙ—UëeÝÒ¢•€¾{ï½÷-ÿøÇoFá•Vd@£ÿŽ€±^ðS¼ºÉ¾) *ÂO)øÿÝßýÝŸœy晣 þÛöms×Üw[µy•kŬŸ‡:€_aÞ °—þÐhÏ‹Ã0 ±¡àÃEÀq­„Oýú=Šð{CBF€í10‹’£ô<€A4O/Á€¨Äc—`YÎÁiT¼üK§6Ôâe;SÝÍ#]9úؼèÚ¿±èñ5ª @|ýêÚg¯uã÷“ ã׃:†‡tJäçô‘tÒM?Qo1ì}…_¶~™ûòí_vÝ{»‹½«{¼««Ë>Ȇ‚[žö´§}:a{‰|®ðjÅ—Iѹ+4ñÝ„¿ÐøDkЧ lÙŸ›<ù9ÏyÎâ"³Gý8ížØñ„ûé’Ÿº-;¶äœT˜ñ´ý-Òì(Ìúíâ&@cH[X+~Ön³z¤q©Ð” ¥Áá§8lø&ˆÅʆ˃±³< p™p0'^c)¾øR–2"ËM7ÚõfßR]#“ÀpÆF.¯I8›½gÁ¿à‰ó^Ÿ—x½i–oð†K„³x†§è¿U`¼ˆ‡µP\ÊÔçeƒ†gùFöaÒ'uñ^_ ™¬>L}AÓ;¥äLѬí^ë¾y×7ÝËO¹;v汬¾a®««Ëd€—µ@§wûöí/ÅçÚùÚ`º¢Òà] ¹ÄŒf{e°WoBøSn²vô9"cðo¿ð |ÉK^rtûh=ç÷º»ÝÍ‹nÎ磕ígçÿÖ–è1?îð nÖ;øyñ‰Æ0{¥Y€¥1Ýè/:IAqøTJSØÊ£âеBýÁ:¼#ÝÒŠ—’OÏñf7•u€êR™Psž í«\r–Rsùƒ”Ò'†3fË>’b.O4¾è“—×+þŒÆë×®-åëZ'KdÔÓ0  ×­ô|êN,Ýó™®¡!€§íyëù§ôe·"õ÷âë–æÓ`[Öo[ï¾zÛWÝ%g]âÎ=ê\cmÔ^Ô# ºŸ÷‹_üb-ꋤj—`i“ÅÈL³ ƒ‰(€?ûÉ!MŸ 6óŸ?þÁïxÇ;~‚Á?ý°Ãs]]]Hj¬ûåã¿t?_üó~ð§-ŸÙ3þyÎüý’—ÒlÙŸ¼\úçw|šV äË0Ÿ†W¼1@:£!Ý,v¤+ŸI‹ÁŸqä”qe?ª#"U ²ŒJåTÊTS^Â:*T «\ù…äM¨*¡Žãª…E‰e×®ä~ŽèšÌñz:iñ5­ ‹P>ÓÐÆO¿ [·É ÒäKg…eŸÇèÔO‘NcXeÜpÏ ¶òÙߑƄ¨Ë©ÓÑÇéÔñÔõ¨I·ˆšÆa)`Hc8Æ¥NÈM€…ÇKAÀ¯N€ƒÀŽë®»îgø˜ÏB~ÕoáÂ…®½vAãÜKnt‹Ö,ê\4¼øì""8ó""øóžãþÂa˜=±t„u1Ë'¶.z ãb5…)öŒíÕõ=)…Òöïßï–,Yâ¶mÛæð1¡%—^z韅›uð­\àÁ¥è}æy;X¥j†ì‡ó8äœý&ô-t“'ð—Ï>ámöÿÿñ×ü9ä×ÕÕÕpðÿÞ¢ëݲ Ë]›Ÿ½ó±½Vnê#èÛ‘Ýû·çþ͈,q‚¹·Ì ¸²ØFƒ€4òxŸ½ÇvüdK€è³9òÐxM™xc@ôŒÁ~s?ä+óÕIq %gÕ<á2­Þ’ÙªR‡^ÚPúªI¦–@|-ŒVCuÍqV?Ø  ¬YƇ óò@2c€×2tÁÛÊE¡f3ôa¹ž÷ô‡ö1ý`<sÏOv »-@ýÂÛ¢±F;PGKoöH ÛAUAzê#Êf<ÎÝ»ò^·gßn÷×g½ÔÆ8N躺º_Œ½ ¡ó¿õÚ×¾öõ¨ÍÄÕʸ\Îq¢ùÅ å¢Ù?Çû'Ÿ³‚¿ €Ž¯}ík˜1cÆs¦NjdÚ´iHnœûîÃß5ð·=7ùqfOð7c€Ëe¤á±ٿßMk;jÑt\8â³gý=…9óG:Ãô±½æEÇ8úà žÝâUÈt¦q5~Œ^¼!¼Œ{š®ú¸Ìó| Å郅•0>¥“¿b0QY‰w0ŸÝ¯Õ±—Õÿj¯w°v¥ôñ%KɊレÖs:Ò2ìzæõZ©Nçø"šéê¯ ÄM7xݰéÞ>¤n¡o+\ôz‹ºËLk¡¾â­J¦ß,­Àëy²|-nñÚGÜÕw]]ëå9,>êö.ÔõÐùÏ¢îGAº@LÐê°iLÄåOè'ØÉ ã àÑÀŸý”`3ÿO}êSãÿ·²óÜ,rÐA1Ø0÷í¿íVnZiàn‹.3²¥ü ôAã…åAZæv+4‹Û :üp‡«ï1b!ì!Ûâ zÉYYîð5“ ožfñ(,áéƒÅ¹¤hËŠQYÕòÔÄŸµtàou¨~ÕûJK~66&»šql`àÛuËs#§ó§W‰ç®sæ¥N`\ú#ǺÄtQ¬w"]DÝ$½e+ŒQ\ô ãü-MÓk ãX²~‰ûÆßPWâSÇkc uÿ§?ýi¾¨h åü…!Ö`g'„‹ÀŸýщcÿdÙð#Þñš×¼æø“N:éŸÈØÙÙéxï¿‘îÚ®uOly"¾]6óÇ,ôɬå üÃ&?\a# /:¿€½a~-ÿkÃNˆcÖ/ÃÀìoðâµ=쨤à èù¨Ã‚CzØ HÆÕ¿*ãCÚ² ËÜUw\•µ­A¿ÔõVú‰'žøb"ÚFŒ^;" MÌwL þ:q<‘ Ó牵¥ÿyóæÍxå+_y.–Ö9sæè…H®¿ãÌáßîÿ7·zëêÜnþlÙßÏô1ðx#,€·‹Ð÷@éôi-ÛJ.b^lö(HÄ6š†.|òq(“n”xr4Ò v DSä)‹suÁV å”7ägúêP䇼øSúÄ—€ÆB%´$P¸¤rÑ‘¶Á®õJcÜëA›Õ…WKHWÈ7:t ùMÇxýÂtãA\3ûœ~òºJúJ<ÁPð·:I·ƒ†h+6­p_¹ý+¶b˜J#|»+u?1€X@L@ñ#ޱ=7±°Æhãù‡§v"9ž,0ö'’‡îûOÅ~¾…™õ¡´»ººÔgàÿÀ¿9¾üBÜ.‚ö Ä5ð Üy±`E@ü‘ÆVÛÅ ù5,íÂóCÔòÓ¢goqð‚å…j6”†Âæ#fÝ|ß}¥Éâò©8®ä×ÂçÏ@Lô‹J}@þA[žrŒµŠç°Þñ±îßhÕ_éú õG†@ŽæõCl#ú…ºÅôõãÔUÞ7…°é9ÐM7Q·Aw1,gaÒb]¨Ð ?¾ùq÷•ßÅõôqs~c\WW—­ü ˆ ¨e* ôÆ4kA[6¦McQ*;8®]d‘ù!iC_'NÀÏ%ž©W^yå{¦OŸ~6ïq„%ñH€3ÿu[×…å0.çsàÛ²>7ËØãƒôâ‹Ø>f0Îå8\„ö2 Äq™Yœ]`˜t óBÅ_p†û+þ°ûƒ>œq _”ΰîéq¼ž˜?×”7t& (ü¸¼F†U_ò±QV‡p#ÏÛx(›ò¬G;íÅ>(ªìz6½ ë—RŽÇ_cÒ3ŒÆa3Ãô’t‘×SAG)îê9é7òØ-¯ÿbè0žØô„»òŽ+}kêï±ýÄb1᪫®zj¡ï ŽÄØ2¡öŒk Žž$(ö‹à €}èC`©çm ¹ÎÎN×Èÿ×Ü[× ðçnWZº\‚GK̦eì_îÃÁvýsI t£1ì­X(Æfø,=¤åÎÃü£uù’ŒÑ•–q„eúÀã龋Õ2£¯…'.SaÍðÌÏmÈ*ië`ù«¥«-ƒùÕÊHiIÕÀp¯¡Zê«v}›^à—¡?xXy^OXaúÔAäÍüòFƒ>2tõõ˜×sôMjùŸ«›ÔyŒc@ùÈÃ8€/Ýþ%ªì†8b±€îÈ#¼œ`l?ˆ%<Ð1;àMœýìØ¸tð× ¢¯å;Þ=÷œsÎù Ò¦ð5¿Üô÷o\öߊe¿¤o¸môÃÅ`ƒÜ;¿.¶‹ŠÏ[¤1 öp‘? GöyxÑÚ…É W‡hL%­ð'…£ º˜Î¸xÊÒ”>O1/ùõWL+‹×ôUo™_Vw¢% Œ†8G£žj׺tDàñz„qÓAh¡ôõ–èFó<ÒGÔ]t£QÏIß)Œ¸¸@ž0aòéÔ¡«6­r_¹ƒª»1ŽX@L€›BŒ V Ì[e·ÔKòOˆ•BÈxw<):1ì ‚¿ €©ï|ç;ÿKW³gÏv]]]HjŒ»ö¡kÝš-kÂ@¶e2€½À? pº @‹—Ö0é\ÖÇ ¸]hèUˆÃâæ2{lËq Ã1Lb’ðÝ_LóIÆç=ö­¼˜P–^`·:kÍ/-Ë©%ÎzÊþjÉ›x’FK££UëáuO=Sê¨N¼n 陊ÉÀß§I·H‡˜î¢#xó .óqé.úvx}g“!O‹u¤nÐ` }冕îª;÷t@WW—#6 /ÀŠkÑïx?q„˜BñðBh8vnܹhöÏ“¡“B_³Yp¸ïÿ>¼éoÞôרÎ~gÑwÜã›7‹Ö,_\fñzëÖVü…atZÃà -Fë`N€Ï0{fšO³¶køyŸ „<¦H`±ÓYø¶j`”üOœ'Ÿ’Ř>7ÿ`éªËî*Ò@¿Öö4° ©èI,z¿ZÊ©Æc3~î9(s^³Ê'*Sú…q£1wFQÙ óuÁ模áLBoÙÞ@D½óÀñuÁܨ?ÖÏý KÖá=w}Ã]þŒË³êüÛÕÕåzzzø¦ÀãˆoûÛ?‹*ô6@6>>ˆ5–F,jä«‚ëÜÍű#ãÊEàÏvkȱ<4û§Ðñæ7¿ùtÜ÷¿ awôÑG7ì5¿ßôûn9^ïkƒ8²r5Èm™‹àoÆÓÐÁž˜AÀù0/»È· Œ¡#œhôm Ñ_pvÑ2ñè–·,ÍÓŒÅ÷ù£|Zš¯Ä3X:ó‰‡>ûþ¢z*•_—[ WË—ÒJÆÌÏÅd•iqÜ)^y°¬z”cÊ€º„ç˜ñ¹öñ /üÕiq„Íy]hŒã ® Û ¡E éÔ…<¨ á›®DØV°R§-^»Ø]{'èõw|]01‚Ž˜OÃ? Áx?±E8C¶Ðó&1mÜ8vh¼:?ÔÂ:ÿvlð˜öçþçßDçZx‡+¹Áô„¶âgx•åbÀZº¢oƒ™»a¹ÜŃ;fý=/»5/ñbñ–É@ÉVxa ];qÍH@§ì²+­ß ͆eš…S[‰^`S” ¡’,­Z:ËdúotT©¶´9*+öK1IÀK + 'a›î(k0uÕ u‹œSWÑxSGáÏô’ŸØØíL‚9uixêDé>:RúéÒƒ¦S¡?íé)ÐïYyûáâ6D—#ü~€–¿øÅWCÐ=­&ëVq†‡— BãØ«[‘¥EáË£/ðglöÿõ¯ýK4³xR;;;A®¿»}ííweÛ[«ÌsðŒãâ0š,]\ l½]HcØ.Òño޾ÂRI±œØ7>‚¦çcÿ‹NùÊÒŠ¼Œ[9e #H«XnI{+Tmäjm«–o¸i£]ßpÛ™òM eLÆËIQÑiãÌ Ýcéô©`Tu’×KômâÂdÞæÄ…ÞXîçò¿7,Ì4èL–)zË,n>*¸íÑÛܬi³Üs}n±é#Ž+vïÞÍ[³ˆ!¯ýëߎB¹Ü¯ƒu°—ê鸾@ð.¶WË~løâŸø ìî¼Ë:<¡pïxÜýâÑ_dà/‹Öû¸²j5ˆ¹%Q†Í¦[/èÁ0°^°'¾g¶@aÞÛG8¾À‹Í.8òÐÉGPiJ7ߘ²Ÿ8½®´Y»æ‹üŒWK‹ùÕ^Üáȵ6æÎÂ*[þ@Ž¡QTN­þÐJOÜI•ÇmCk®)«%z*ÀÚÀ8þŠºI:,è4ê5Ð{±®3èi¦¹/Š“$®@?Ú!ÝʉéX%àJêïû¡[¶u™TJ]}b±ƒB,Aáe·¨quXýŒªk›UOËxs‚I?¤löÏÿcŽ9æÓO?ýÙ)ÜËiÈG~¶îÝênzì¦l0ì1HsK[ŒG‡\Þâmðs9ËV¦xë—~tpXYÜÆGÇ™÷ewÚuzgجqÒât/¦[ÞÒâ2ã<ñ˜V-ø­7YËøÅW©Þ²<1-Î_ Ç|)\ù$Ù4—l4ŽG뼘ΉtC¨—×n¬[â8±®ŠuZ6÷úŽ/? ú‘:’G¤Oc=žï{÷ÏmÞ³™-¨«ãˈtÄb ‚2ˆ5:b,"û¸sãˆ,+Y\l· -û›€¯ü} ƒm*ŸïÄËrB®_t½Û´cSör V³LãçþiÅÊšåòÃô½ek-gO8ŒÔúqï 3~YåÞ7`$ö+Ž+’ñì€eeÔþ´8½–4Í’c^…+•¥tù*#ǯ€¨Ý¥|¹¨Ä~?·û9š/·3…/æµ·(–Ní¹†ÆYÔqn¥Éi^ïniQÜt–tü ëb=‡0u¡tq;¤+¥?½Î´ýS^Çj€/[ûæ]ßd-uwÄb±„˜‚ dgˆ9±öö’ïàiij?Û)AÓgÛyx2xt¼ÿýïÎÁü,~ó¹³³¤ú»k¾Ö­ß¾>sZª~©Ê/W¸T¥AŒ8[(ð'­6k8ºD³Þù3R þDÞ³C1þ@RYð•„ÂÅ šÒbšÂ•Ò*Ñ•’U¸Ìgþ\}ú¾Mxª”(ÞØ/«w8´¸ÌF‡‡Ó¾”gøhôùldùÃïõsÐý_™> º|¦‹Ä­8}ê†Î¢´0uõ AßÓ‚éŘ&#ÁV`Xútõ–Õ {G1„XBL!¶ Õ4„72Ð)I !¸feÄ&ýegÆ‹“ 9|(|þܱyÞyç}Žá—ž² œŒÕÏÝöÄÿ¸Wà]Öä9€ÑŠøæƒÖâàþ0/ðré‹=ÀA_4ì†A˜]„ƒ6üdÿè›ãõÆÅ3ª]~ Zb±ã…\É•¥•ÑŠù«ñ H+T? ½X¸×ÊW!{ ׫œP` $ Œ+ .ÀÒ¶ÎCµc“b~¯«Bu¶Åñº£š¢`ê ô}°Ä?Ŧ*¡СMF>†`c J­?NÝÚ}›Q·R‰¢žGÖ>ân^ö3÷¢ãþ,[1„X²zõjGlAüY{öìéEÙlš| >®8‚Íï(Á¦u‘%EÁ²­:þ~.ÇØÒÿW¿úÕOâÞ:§˜ïz@IDAT6ýâŽ:ê(ëëVl_á~µä×Èb›%j÷«x Ã’¾-O1nGFêgq6ŸWž=B˜ÃØF éFÌÚ"îúLj¦ÇqÒúðÒ<ãqšâò™GùD£_F+¦Wâ©T&еr+¦GmO¥:â¶Äá8_1ó¥pÿXJ²H²ê0ý]¯!?Uu“Ò/øÔwÔSlæCˆÃt!ô hÔ™AWò¶€×›6Û§>ÍÙ¤ ßXA<ÐÁ÷“ûorK·.µëùC,!¦[€1Ü[VíVñ‰Š|ܬ°ÁãÁ é³Í2löÿÆ7¾ñ´Ã;Œ»5]gg'½ºº­û¶ºŸ<ú“ ôµäÏÁ kTëñrÃFgKqØ@¶ÁŽ8[îi*¶LF>†yyÀס¥6‹ƒ¬8ùøÇåGåM¾Ò—_‰Ît:ñýJùH¯˜†—•Ø K*–šõ¡Zeí¿ü"O³ÄÕ¾ä7NÍr®›±”z-í’îÉñb:ÿ‰G~¬‹ŒÆé»×]–/Š+¥Cיί–ÿch«˜Ô‡Ô‘^Æ~‡UWÔÉ0®»÷:·iöfÕÙ S€1/½ì²ËNGñ5Ý ¨s3REÝ”®0ûçÐb[ Ÿ: üïxÉK^ÂMö¡îଷ»þalúÛ¹)¨Õ–¨x”vï~¸ÏOqÖr jЋD×Åa ;v.¯Å/0]ÜÊ_¬J‹i ³H…‹~Y>Ò†D÷ _ øUfY¹em 1-ñ¸üz†k©;ñŒLõ<_µ”5²ÖŽ^nö¥Qµ•é«Ë !ÝÒiäašô¡èÁð^zSºS{ªb«° ò®Û¶Î]s×5TquuÄ}0/Ò†@Â#?µ³²—ãb ) €ð§@yHØaéÿŸÿùŸßˆg6lÔ nXrƒ[Û¯ûqI V§–žrà¯å*>ÞxΖ¨²<¢kx˜A#+ì}þ{?#â—óŒÅHü± ‰dŸ7$Di1-+o‘V¤3^¤1OE:®VpÊWVf1ËPx‹y‹ñ¸¬JábžO¨$Jc¨Œ^©ŒFÓÙ–F»2ÝcuRWI‘ °|’ ·¤ÿÌ@št¥Ò¤Cù&ÀäI·4®HÇÒ÷“1~åÛ|›5×ÕuvvÚ­`ÍÜÏþóoFáñ­ázbÚZ~ÓœE7³“ ýüÙ ¶™GNÊÌ®®®w±xäï¡Í¹ûV݇M¸ÏïÁÝ|† ¾h•rðIW«éÓù8­ràâAA“4^´(Õ|^¿F –]Ï(s0Àµº£Ÿ2Å0‹®ÖKggjpeí¨![Ž¥eä L‘$H`°ñÈë½Þn°:+ÕWz—\ºE>Åå‡ò}^ÒÕ¦àK¯y½H1X~ÅYˆÂðMgr²Ô‡ƒº—~á ‚¶ÁÆýß/ý½;åˆSÜÓç>=4§b Þè:;;ßã;+V¬àF@ì1Ãô%9ù 5§kº€’Ù þ´´þ¶€·4ýo ŽöY³f¹C=Ô‘ 8º{zö¸Ÿ>úÓ̲„uI€—õi¾§É 5šmbÁ€¥EÊU» ƒ`,ˆŸŽ<ìòEÓÅbLÅŸ,k‘jqæ+Ë[¤•ñ•ÑXh1¯Ñ¼|­Ò’ŸJeŬâ)+?æ+ Çy.ãK´$f•€Æm%¿ÖvÇùkÍS_=cù¥·1ýêóºx9iŠtõcÐyà1ê'^aåÕ6‚é~Öô1õ®§ý×}ÿåvïß=bˆq„C¬AÝíÄtW+ÑÄ$­¯(“B„i±„š"Üt@$ ¾„Kß„þªW½êx¼¨áÙä?öØcéÕÕݸôF·cïŽÜ’¨”la7*š iÚ å æ ç`8h6À™g<Êψå€ki–)„¨Ê\‘^Œ3O%Z)]|Ieä/Ë#V¥WãoÑIÞbY)ž$ÐìˆÇ{µp=úa:h˜UÌ›©9lì÷0é:塟ӑЗԩғôeÐû[ô^÷~Þ¢e:èÝ»»Ýwüî0{T9›°†ØóêW¿úDpʈ1Š=×Q¹°&Hi* ²”$<¶‚¥fþw¼â¯ 6…Ïiòe õt‹¶,r¯}8xþ^Sˆˆ«E6pÑ*3¶Ð¤sƒ‹¥‹®Á7~úÑ&ÒÛ¸Ã!UI”å%­H/ÆËê-Ëg|UvõWÊ£ö–.¾¢¯|ô‹i)ž$$0º¨¤ƒÐý†@ê¸Ü_¤ó”‡¾Ò•ð©;uH¯š^݆մÐöfùYC  »WÞíîßp=¡Á°æðÃg™S^þò—~¼€Å^³Ô³¦Ý À7£“àèK l+v¼•éyx)ÃB¼¡Éuvv‚T?·¿o¿»éÑ›²ÁÇ™¾,TJ5(9ÀØ2KŸ…9hÁOgàÏ`5/þ“‡ap›OšÅ=ݘõã'õÌÃõeÎÊ-$ÔB«…‡ÅÚý¹BùŠ–•¡4úƒ¥Ç¼ 'ò&?I I`x¨x{¤RðÅ:Šoë‘$¯sÓkqæ•ÞôºÓt.îù³^ÿŸ:ØhлÌciÜ@=LŒ¦|ïÞ﹓.<Éu´§ë㸠À/Â-üà?xÁg>ó™Ÿ#܃#Þ@A°< ’¥IÁµ)\…Ùüy;Î9çœÿ—ö÷cêÚþ›WþÌmß³ $p–%Â|ƒ•ÞêgoóƒAÞgA>:ø¶Ú%߬]ž{Ó6à¡p6.xps`FÍ|[jÏò‘'—fc*Ë[¤—ñiÅ8Ë(¥™Ñáûàëo¿Ú´jéâ‹ýáä‰ó§ðÀó”d’d2šcÀôX¤'BÝ^ÿ…8x¤ó2ßë?éLò{=*?èXêQ¦q¦ëeü¦³ÁC}ݽk«ûá#?Dáõs4Z¸€îÏxÆÇà.Á×$­³‰+}Óìð›r€ l6'±mœwó°™?üöüã‰G1æpö?þ|êç–n_êî\y÷#èóq“x÷?h Û¨¥ui€Ÿñé Uö&+Žf°ÙÛ,Ácüò‘FuDš©%$&-ŽpNU!ÂxàE0—Žx¶(ž§i Üûùjâñaoä‹ò©Œb~Ñé—Õ§—…‡“§¬œDë?ÇIIÕtë,K1Ó‰‘î‹y3˜äÌÊ“úG¬CƒŽE:Ãzk ß hºØÓ¹*`6{r eá–í¯ýµ{tË£lYÝ¿H "aCàËP°ö«„[h@¿P·ÊëX8æ®ÆÙ?ÛÏ3¾— ~ÊSžR÷vÿô±ŸÚà±¥$BœF[Ê÷§SKK´0ƒ}‡ îåÛ©¦Du  Ã' “Ÿ°py_›yÜ'ø¯ÏWvÿ»Ú°y0ëÏZÿeyeeŠ«Zšxb°òbÞNH# @WUý+I/Õk^ïÙɇY®éH¨J KgJ‡Ê÷tÓµžF}¬ZÓÓ¤G:[úšúüúû®Gb}÷ŸÑzê©«Z·ž=hºU6´™œ&_–­«ŽO~ò“¯Â;™¥ååßÌT·¶ÿîÉß¹ Û6¸~rˬHX“È' Ö« ´ˆÆÁ+švšóÍâÀFÎl€Óì%÷mЛ)œÏcü2òIY9ƒÐ¬Üˆ§gRUZ¡Me¼*¾Zšxb¨üqÞNHhœÜßWUE}`·'•?JËÈ…c&fQÈ+ ?*9 Rgê Îå>VèAG“Nú›ïà;h4¬Ý²Öýbå/Ü…Ç^8 èá¸pãÆnÇŽ‡›.ýð‡?ü(‹û¸€ØÅ0Z:ÎxS96nL]aö϶ð4³]1ø›pÒI']A¿ “Áº¸õ»×»[»%{Óf÷ñ£}2liÉúÞ°ÇpÑ8@Üz‚Ìí?¢)­¬Æ„²‹¡Z‘§gEã_Ì1½ÐØ\žBZYt¨üee$Z’@’ÀØK€ú®W/¤Q=zÝ(Ýgú’ú‡t'yÐ3MqÌð ô½î¶\Ш³í Ç÷ÞèÖì\SK³kæ›ÞL\Эá±LÂ2?¼šëic3­PPñAjI¥;-_‹ÙÿLÎþµôR/¡üê‰_Ù{w:Úl*ÌûM<…<<-ÄA#ÀqP H1,­‰FGØèWìY&{° y|þ`[ Ùx"R¨K´"Ï`qæËñÀ_åý\žbb!>ÞBÖMHE ”é«>Ò jNŽ7J/£çh(Àt‚tŸVD÷Çø¨[ÉC}ÔÁ,ƒ4¢à™Îö{ð¥¿é÷ôõ¸[–Üâ^ÿ´×ƒ±>ŽX´aîÌF½O|%ïÇAìÒSj)+mªU€±6xêèbŸÂ’õd3ÄÛ.\ø62Î;—^ÝÜòíËÝý«ï7 ÑjÕ`b+Ô>Щ`ˆãl,1±! aÑ8€eä 䓳AÎóqs {ÒD€_¤4΢‹hTÝ€úâ4Ë7¸˜8„x±CÈšX“’)ꦨT§SµI‡‰Ó,9Ó™ØMíe4î ººÖ—Å%}í°|¤óˆÀßÂüCXzôß/û½;ï©ç¹fŸ€ŒõqÄ$õV”x-®èu+€-âAg’à*À~ðß³,a,~ÇÚPŸ=¤ ZíÔüÙ¾öÏ~ö³Ùÿ ÎþgÏž]} ªÄý[—ßš´€nËGô}ØZ„Sfq‚?OŸ?l&Å`èqÁ0«ÞŠeº.&åɆE¾Ñ≩ßGg1eõ]Wž¯«Ì+Ö_Æ3­e VGJOH¨AU i€ž(ðæÒ£´Áèvý{~ã…N%ØÓ1MFî¥^¥A€?Ó^Ì"ÌÕ\–%=nßðúûÇ‹~ìÞsþ{¬¸zü“ˆM0f«>ð\r¹ @ £!Àƒ'©0ÞŽ+ÇSIûlOnéñö ¼~ÝgÿnyЭܼÒ‹>¼V’ƒ­±ýñ«)1s/[N`/l+‘/~KÄ ^F$%0ÆBÁ~OiœÅ”Õcô0V}euë/°Ô­G5U”˜’’ê+½5h%yLOzú‰èWòâæ„JaéoénÛÃ…—hbGÃà±'sw¯»{Ц…A+Ó«´€XÄ4b›zo~3ìh† ƒÂÑ‘3>ö±½³ÿYšýƒ¯nîçKnàÏÓ£¢0[CZhUÜ:†Ùj\’âàMÚÒx‹áÔûÖW¾2P.ò7—-+[ÕÅÊfK\H/I«•T2j­+ñ% $ Ô(^óçYfê»’‰I(¹Bz¥k=¦[Xu³œ¨Zöõ°}äõ:™zú@/ˆÒÑô‰"Xt7NŸOðµîx*À6>t£;kîY`ª‹Vf³ðn€ díÐ[Ù2¶^G}*A)ceðôÑÑסÓ&«É¬¨ÓN;»+Ýa‡F¯nîÞ÷ºM;6¹ÖöV¼GÂ?ú xs0Ë3¦«µ‘V6q””æ¨Å,PŽŸåp8x—Kóô |CŽ£ÎùmóÝ)SOqÇuçæ´Íq‹÷,v¿ÜöK·¡gC¨ßÚGƒídóå«mô‹uÇiµ„Gš¿–:O’@’À$é£b) €o.=JpÝ#-Ç‹Š,îéJS>úú ˆAÝÔÙ^W›.Þ-3"šMÖ`¬ë^çþ°öîœyç»8ì81Š{j5%Ä0ý1qce¨³Á_€VÚ/»ì²3;::æÎ˜1£®Ïýóú·,Ãc°s³wnæÓ *›ý³µl%|Íîu*mphm‚ȸ Bž[ð3l›[Ôsú,/rÌ\.EÀóÅaæ-Æo=ܽôà—ºÎŽN&wÆAg¸S§ênÛr›»uÓ­nþ¸2rÈ!ôêæîÜp§Ûº{kÿ½oè­Rfi92aÅIó¥õ€­÷=ø3N~s>lÑ3†ì7— ‹¬ÅxÅ2pÆÔ3ÜÛf¿mø+O+^¦}áaº+޹ÂÍé›ãöíÜçöïÞïzöô¸Þž^×ד¥¿µIùkõÙæjí®µœÄ—$$0¶z­B3K³Q_'uI½YCãf5&1Ýë\†MçF:Ùh^Ÿ›Ö„†>÷rù4†7îØè~»ú·¡ õ«ÍÒ=̀зÞ<2ÂÑ †AŽZÏA˜qgÄü™ÏÒ8øó<ÕãQñIÜéÓNw‡¶fŸ«ŒÓj ?÷èçºCÛu_{ø*×»¿Çµ„±Ëö ¡v‹W“]<º%… øã>”°%R’@’@’@†yEˆûò~EtóÌ0Þ z `¨—ù4“ñsò çÑÇ—¶Ùýÿ®{›zôÚŠ@+W3QŸà^'Üßt7=„U€ùçºí3êr6ˆY0øÁº?E|)Ð>ZÝÞiÕ¤ºDTE6ŽæÁúyÄàߎG(^‰“>•þa ’ëãîÞp·Û±oj¸ãЧ$-Î püÈ4év NúªÛŠã=;ssŒóìU;ú0òŠéêSŠieñâ§x‹qË'vØ=dÿisŸæÞx›ܞm{Ý^ì Ø·k¿Û¿—ûú\oöØ 8Êû: =ƒÈ¤¬‰V.Û$—$—fƒéºÁÒã>^èИ^6^êZsýº™têfÓÄ7Â~âB=Í2€8–Ž|Û÷lw¿_ý{_îÈ=b± ÖA,C‰\  #@¸Ç–ð3Ç–SGc_àŸ3N<ñÄײQúÐB=H ð·+î÷Û}Þ#â?}¶„-DD,» æß`‹éèSzòIWŸÞ­©ì¤NE|ZL@Ï}îsš:uêÉÊTX~±Ïºä“/çâ¨ãà–ƒUÔýÍÛ7»OßðiwÿúûÝ´™ÓÜ´ÓÌR–ÁD«™wÑÊÛ"zò“’ƱJô•zSÔQFøsé1 “.¦Àåâ §›~]eŸZ0æa‘¾¶"©¦âÅv²Po“/:¶ìÜbï8þù–m¤?Ä®5kÖ°˜y/zÑ‹žzóÍ7?†01Ž&[ŃaöX‚£ëúµøèÔ‰ÜÄ/!P<:^÷º×½“MáJ=ݯÿ5€ ç–÷˜O0C­Fç˜ >¶Ì‡yÓ(ð° KÃ9ãÍ$ÿ<ê|rèÒÌì—ñÄ´|ä.ŒŸq+'¢—ñÆümS†g×-[³Ì½á3op·?ð;·ŸKÿöXà><¸ßõîëÁc½°¼¹"€6Ú…W½]qS¸ö1d•dÕìc ’¾S»K¯¨«èJ•iªÖó™^¦N:›+±P¡>ô6u»×ÝÔùÄ"Žííòi7?r3•xÝœ0ìU¯zÕß PÞË&Æé0AÜ·Ö|DG× )†ÞFv’NeçyHl‡Ý'ÁƉg"ìŽ:ê(zuq‹·.vëw¬Ïžû·‘ÂÁ€¦0L_[ÇÒ÷üTI¡õä?ZúÏÒ³¥&ðR0Ž,Rò[–^ÌÁx‘/ŽÇaVÁ{ð»úv¹é-ÓKj¬LzbÃî-Ÿ}‹ëÞÝmO´ìëumû{±÷ýyïŸïÀ½ö‚-WrII“SE]U”BYz­4–x¡ƒÃ*+t³}ˆ‰¤Cñž¾Ìd:™Á`a$R§÷DqnD1à€÷_³u{`ãîô9§³¤»ùóçÛ‹<¦ ãö£`ážnPhÂz…tú£âFËPg ù£Û`Ç{ßûÞ °´<­Þ›ÿ~ýįC­|žßžéZ‚¡à ßL¦yG€µ%#Æ=4£g»NÄšó™nŽyJNgHri9K¤˜Gaùe<¤ñâèîévÓ;j7ö÷ìwüÊÝæm›íÕÈq{í³‹)«‘õ“Æ—ñýÉ% $ LP ”è­¸§E}eiQž\º§çôW¯hðãüVÔGöoÚ(k’t6ü\¤ûÃn_Ò(ÍOCm?§Ý²ä–ºÚ ˆ½ÓˆmŸûÜç~ŠÖïâ½l‰ï]ÖÑúM€"¦£ïEo–Ò~æ™grÄ;ôÐá=ÂÆ¼E·jÇ*·tÃR6.ñ³f›¥s D4ÛÜÇÁÁ–Å-DØi sÆo Y<›ñ£,¤) 󔸥Ńä"ãe´¨ÏqÀ­Û·ÎÍë˜'U _wëuîá•g+$QK{‹=ÿßÒ/¢ÏiØÙ¢ øˆ dUlOÕJRb’@’Àø’õW5X¢. Wp•ôC}­X6ãl «óa«[aèeêfÑL“—‡×é¶Š@ýÇ÷¨,ÃO{xõÃnE÷ ×9«GîˆeÜ lû+”v+á'Àl®СQÖ*‹ŒÆÏhì}ê4ý° k©ïü·ç×øNåz¹?¬ûC¸·Ïš³{>hˆo5ŽÆ[ƒ”>Œæf÷û'13ÿŒptÁ‰Ž §¹ÿ§Ÿ:` ¦~žŒÔÏçÉèyëõtÜ£_¹w¥{úÁO%W p—ÿ5?¹Æ½ ß °o›†·âE@íÓÛqÀG¸ †@+ Û^ 9U+8¥% $ L ôë©bg©cË Ÿ'R¡Asæhq‰Ìƒ#¤g· Ôa„˜>§'|³K §HÓqLñ îFµÀèµI Ò`üzÕ¯ëfËžxâ l;7uß¾}{Ñ ážo‘¡Ï˜Ü`FËñÔÅ–è·èCº³Ê6ÿüd]Ú´iÏ&wßêû²å}Üï±Ù>Îú¾‚q»ÄV±i8è aüs<Ù C<[ñçÌt¤‘ÇÂÆ“…4Çt8³x*ù}­qZü,}ÎÊËÚT‰Ÿmzl77œÖæî\t§Û¸m£É¦¥¯Øãå?í3Ú]ÇÁð;\ Ò±»CGÔï¸)<ðÜ$™$™Lª1õP¯þZx5Æ2c½ca_—Âò3^ð{}|è­L¿£(¦!nX`~–Æ•Í;–Þá6ìÂWRëàXžÇ´Ö|ä#— Hîu‹±/ÆD4btÝh¬°Gê}v8€mþóÿ/'ãœ9sèÕÅqóß¾>|å¬Ù ÷¥Ò*Å©·OP©³Q„ï›%K ­·×JÒÄdV,k€¥ ºfå*¿'=ÐT*ô™BzÄÓreízbï®{·›Õ>Ë—RÙ»÷±{³>عÔß çÛÿ:ü4¸ Ð6 ßè@:ßš(y¡½ÖßîÊ5¤”$$q-A®ñº/âAähž·Œf2£Î…‹Ó-Œ|¢Ñ·ûøª7òÅ“•’ýR‡I‡Æéˆ½½{݃t{AœmØa½`áÂ…‰B¾‹ƒ˜Ç· y €hBG_=0B#mÄŠ-¬¿ Ë#Ó:è Nv”ÏOÖËýaõòbek980 Ðãs€Óa÷Œ× üRÐWÃŧxÁ×à#9[œ†…wÒŒ»?Ýøãv‚À<ü»»ûnwÁœ TTEÕºUê÷Öv¬„å.û ü±üß25KËVP²¢â §bá)!I I`üK ¯rôg€.ˆø¤ùÜîyCœéQ~c/ðoDS^úvP2ì 2:9§ûY0õ¸­ L»mému3øm€åË—;`\±nçμ @ì“c#{ƃ-ö½D¨AŽ7ÚE/ðgçÍxßûÞ÷°ÊZø)Å0Ãa«Vn_éÖv¯Ífì¶lQ³mAÜê‘Ø -Ôf;%<ÙÐÂ¯Ý ï]ÑñÀœ >Åc?N‹ÃäáÎú˜7‹—b]4Åé[h×Ûî¬I‚Ûvm 2±ÌöiÐà1ej¶2À¯ÚÚ <öÛŽÐ’¸)œ$$$04 ˜®õk°œäõâeúZ::”/}N,°[&H·™´U›V¹%[—Ô¤Cc"Öxl›ò|€«†{ð‰jQ…+µ>élÈh9vP•åc‚8á„^ÆFàyɰ¬3ÒFÝñäò¾ÀÞ|´Âh8ù÷)Ì™½ÂÀ7¢mv°õÞ³ô ¶™ ¸ i¾*ó8Èc'+V´8=+½ÌgjÿÊ=+Ý»žpGO?ºŒ5ЦMËÞôÇcØ Vx€Ÿ¶§gûÌ?sù¦‡²R I I`‚J Ú5_–æiÔEÝfŠó(\ôÉÓJ¡übšKWS‡2lmAšé3b€½ ‹Sw?ðþfåoÜ‚Y êrB‰mÛ·ow¸ p ¼±O8(\ô ¶.UÖTH# u†¾:H_–ÚðíäN¶¶^ŸþåWÿî_{¿ëÃvO;éþ±5Ã/´À¬GœlΠ핶h!y6ßš‹±åþÐàÈ’ne‡š•Ë~Tre@.š|æÃŸÒäÇu‰fFúyÛÆÛÜkŸjOVÆl¹ðìCð¹eðò1?;0Ó·Ù>Þ[e>Ζ½;ÁÏús™S$I I Iº°ä½d¤—bA•ÑBzYyEš‡r§î¦^–~g›&:̾kB=†°½LH:¨¤|H,Ï+ît¯:ùUnz{íïT }(ˆm+V¬pëöMxÈVè ùÂ­Š‘z;VØhÇNèPÙi ¡íŠ+®x6€´®»ÿ¹ùoOÏ[Ú¦H5 ‚xÙµ¤F\ü9çËë6P ¢9ôúÿÊ–ãûS3c#Ž3¬<µ,ýÇy•/G‹n˜´Ñ¿ßuÿÎmß¿­ìµ ;;”ÎJxÞ_ò¡O™¤¿$$$&“€i¶X?yPu·ézéyï3]zRX`{œ¼¾cx×>L$7Ü_Yy!…“Eÿ4@Û{Þóžç!«á|b¡´-[§ÁÆ;VÜHÇÎÐy±[GÙaígŸ}¶íþŸ9s¦1ÖãçOþ1ˆ±ø.h–¯“ÒÐ:…ùœ+sæÛ€âVTe8âÉh„rÒr<1ÿ á¬¾ f uEy­ž(®úrß`;Ø>H¸§e¿ûåú_¨ðRÿôãN³þò~˜u#ÂdAŸ_ÞÈú7Ù¤¼:ÏÉOcaÌÆÀˆô[Î[¡ A?y¨8ýp˜ÖËôµt¼¥ùL¿ya¯óÈÇ4ú¿{üwVB=~fÍÊžÊ:ãŒ3¸ Òã€l ü,Ö _Z!pj<}ŠS‡€?øþSÙ€z}úwãžî‘õd³Öγ­ûývæIÃe„Á„aaC‡õþ8Lés+Y Åñ£Œ‡L‘c)ƒ¹2ž"MKhqi1Âòã:±ÒUpè ûŽ~ÿ|Ã-îs_覷•/cøÔ“Ü!Ógº½öf=AY,¯xÔÐÍBR4I I`BI`€ž‰{ç﯋”ã-¤OD¯|¤çtš§M<hYyâa²*óLoöû™…à 1\€v§©4¦>ðøîÉÓŸtGÎ8ÒZ=’>â¾zõjÌ;å ŒÂÂIúj>5¹o(Buv2ÔL6^GÜ9v¾íYÏzÖüÖÖÖéííxÑL+I#wl}¤ß܈kV˜>[âã4t/Ÿè’9IaUhËò®ÐÅ8ÙŠ´~ðÏŸç˜/Çe(¯¯>xäç2Öî)»ÝÍkovsqH‹-0sŸwÆóÜMÜd÷ñì>®"–k·&|8ΓÂIIIE ätub¤Îri…Œ!-Êh¯Ñ"&Å|J× ¯âE®t£ ,NLàŒÏ£”åe°ôÐÆ‡êbãˆupÓ‰}¿ýío—e5¨Ö™¬uäm¨cå‹ô½XÍ7ð­í’K.1T⽑z¹{ÖÝcEÙ’¶üO{„V°EjUäs ؉g l±ç˨þ—ËP çh>V¼7_Œ—å©D‹óÆaò+^iïÓÕWnäûÙúŸUÝ ðâ?yq}½8쳿™ Ò^WêA¢' $ L( xýXï>UÒ§µÔcy íRyÔ¡ ¯·ƒ^"Iÿ{}oXAÕÏGŹ÷‡Çñ>™:9a°o,Û äaYêTwY1\`ããƒ#øëh›7oÞùlT=—ÿ—m\f­Å5‡A€á`Ë<¬Žôâì>¤çÍ2ôVlà‹¬Z+„=ô4–»bœiEZq¯tù¥y|=żx½ô÷´ìqß_ù}÷× ÿš,ÜŸœð'î¨ÃŽrë÷­w}üü¯}Ÿîéu­}­f”Õ5  DHH˜ØÈ«¸\_興w@s–¥{ZŽ?âSž ‘f¼q>Òøg÷Pô Åý¯â¡ñq:óx½i>˜¯]ìžÜ…ÛÓG~€X·eËì;E…‡ôþq |ÏÚÇ ëíØx9uˆ¾ŽÐa¼ÉRÇÛ‘Ä?"ñ–Åvò4ã'h3»×»ÏCV4Õ‹Úx™NÑ,œQ³$ñD4Àôôb¼À^UùdŠÃq< îÒ’2"ûÉ7üñøŸMÿãÖîÄ‹‘Jûþêg½Úfþÿ¾ì„èÅ Vì‘^ Š% K¤$$q#ê‘z¹šËB•ÆWíi1á\Üë~ÑÍ/bKØñàúëÒ5aǾ€…(\øHŸ½¡/÷N´ºøq%u)0*DŽ;:|饗ž ¡·â¹Èܬ<Ê?äà½ë³÷ÚStw;ñÉg«p#€i&oOç VË} làT¿J ]ìÀ>Y¨EÆaÆså³ì›7¸çôß—ý{Å’_vÞËÜìi³m onðÀjÀ” CÀÞµ]1wJHH˜(èÆª} oÕ‚jO4]³{=h:Ýã‚ñÄt¶ÓÇ¥37FÚ]«ïŠKv˜å{Ìk%¢ €‰ÇXÉ:ز†:Vا†³|†éÇm{ö³ŸýbVL‹ˆ³Ù‘»{v»¥–ö׆¹„Ï—@ð/lôð- qÏg­DA”Œ[Hmó÷”n>ËgÙ…?öKNie|J‹ý˜/“Gñ²{ÿJ‹Ëb˜ý°ûYØ ðàÎÝëïTÓrþÔö©îµÏ~­-ÿ÷ìíq=ûü±¿'ÛÀúù®Ê#ý% $ $ AAŸÆy ?ëõgåÇå1Å™NWIßç3~¢éø[¼f±Û¾oûˆqŠúS«ÀÀ?G •n°v¶Ú·¡¸Fí`£Õ¿e0ÚðHÄ™ì_‘X÷ð–‡íDÙ›ýT Ä_ƒ³}žPùdÿ©Os.Š–é-é°/æWY-ð3 º÷­Œ8ìÂz™¦úsaÂ|^«¨¼%zÿúûÝ3zf®{Éó6lØÀ/ß>ù‰Á±@¬$fê l•ïBuv¬¬žŽ¥+ŠRbǬ³¸b;*¦NjFúÃ76Ù²> Bí ÛrŽ_'à«U1_6,ð ËéæG±|Q\Á"Ÿèò5ØÃJ/ó«ñ)M~<$­¬PÐLxÕ/|óÍîú¥×—rv´u¸w¼à®wo¯ëÙÃÜ`{xñ¢lØp,mV"& $ 4“¨Ýå†Rv5Þ8 aê@éÿ 2Ã-Ùc†ö0GHòݳ&{Âl¤]æy ŒWÆYߢà³JÒêîµ †ªCò­³çwÞ<œ<Ùž½‹_Ü#ð—mÂ#•ª¢"@ç€^q‰Ö‹™à©Á€Tî…/|á0°y-üÄJÖLŸ¯'qÀ1L7Pû³ («#€>ha©ã¨£Ž:›üõúúßÛÎIµk÷qž|­ ÈÚ 3{ð„0Ç8þ,f½½Z\q€)èò5æBÜ32^Fcr‘^‰æ‹ê÷ÐËëÏ÷¬Ú¹Ê]¿äz÷š^ÓÏçCÇqœ{Í3^㮽ïZ׺«ÕŒ3° À!I 6­ ["$ L P§Fàw<§§"¾=ÎàÃÕÒ‹iÅx(ŽºÎºMk¼¤cÖoôýaù|ÚÔôz\!>ðI³zľ͛7»ùóçs/\ÀF¦ÔX+}¤ Ž8VRo§Ë÷â lƒõÓÉJµr¤ X²yI8¹,‹'ªxPŒ¤™ó-³Ù>é¼çcrfæŒ%þµ.«çÿgï:¤*’vm`YX–%gQÁ@AÄŒ`Bïþó §g>õ÷ÎŒé wê¯ç™s:Ó¡¨œ0¡‚ DQI’a#›ÿúêu½íéy3;»;»ìÀëÝžê®®NÕýºªÃë§8…öCçã,ê,çC ¿²âúa#”Ïhsêþ§Rï6½å0`yI¹@”WõµÀFé’Ñe 1!B¤>ü1¶±«0†#KåõlzÐZ‘ @AvàÏ‘!Jûíªo“Rz¼ cd!&⪨¼ÔÒ)údÿ$sÀ°Ò/¢VĆRÉÌÌÌ\P%ëþÿ•ù|ÁÉBÚfì,êU õûÐZjðøëÖ þ‚Oây¹Dü*^¡J‘ i¸BЩ[¡·‹È-ÚAÇåÇkP°p×7wÑ­#n¥¬Œ¬ˆˆ-2ZÐ_ÿ+ýÌÙT^Ì[Y¼À+8™ÆÝéàJxš!¶-D_~Ýu^ƒð]þxæcV~<Å)äènXʆäAkèA+Vdpfi_ã ´Æ/õª[Ç7ø—­[†ÜlTöYè [fÚy¡¤Wì ú¹‘Q2²Ò†Z©ä1dz 4>Y3#o@ Ö—­§¢²"O!WÎM–~àfë»7‚÷}ÌOC§áÒðŒˆtŒM w¬÷ð]:ñ[Ð JÇÇYñ|œU7-ø£èX9‚® A޽ý•+hê·SjHÔ¿[š¼ÇdQ° Eõ­ÿ>«\Aeq!Bl…À2zÀŸ;¾Ñø¸iHx¼°€|5M̓š,õ+-ÒsÒTZÄÕEw‘Z*Lø K _œm¨ÁÄÉÈÀ4ÈDNÏUTò¸°¡YGÄOæ €&Œ«ÐWˆÊ‰{ï½÷–ûÿ“v0IÍ,4«Ð¸VzG„">óË»ÛÒ5Pp™ù³ C?@Cû~5À ‰ô¥)¯Ð ªÑj©á A§n…R6“€3þX õàÑ­€7~}ƒ†ñµ {tÛ#*™É#&ÓÜesi~þ|ï-Vä·¦œ€2ÁËj¡ 9r`ä@ôP(LðgìðY4þxdá4Ü/̰اµÓ·âI>ìW:…&ºÐøåá!L|¶1c¾ÈvCp/Z¿ˆ:õèdSÕË XRRBüVܾ/¿üòלd¤/+¸F`‘x2 ª…U7òЊetëÖm7dÈßDö–i0{l€ýiÓO^ŽšC4’] ø‡ŒM8üÒøˆ§nÛ¯x ú¦œèŒÕ!‰dPñÒiý± Àçdi?;îYpmܼ1*(MW~%åTçPE1ß € ‚°  çLÛ13Cr ä@È&á€?ž'š›=®·/bøEVx?ž\ÛÖýÐ ™¥ò2¦k×®‰ü¶ð7¹B¤’)¥ø“ö“ì-´ }âîÿ(½^†ÐКüZøkd\>ÌèÕ¨ ÔN£~ ‡à‚er]$’°[D<‰ìåeœQ ½­(BMÈöÑ+],hÇ Ñ:qëàn,¨( Ìû]3âáƒMß)·]6ú2ºâ+¼UýT&ÇϨæu>€e3áo Ûí$BwÈ[#t,qêfWöªdAá>ÎNÓ¸ý0MÐ ³â =ülu^¬`=·&)áˆ`àDX¸ù+,_ý*Y&vçTláïÊMŒª2²&Kp §¶+"NVVV;°Œ?4ج)Z-|Lî²ßÁdx'éä¡eã}?§á+Gö…œ¸ðÚqÝ`7LýngöñVçSœ¦©~…ŠãÒik¡u¸UÒ²x5 "¾*üŠž_ø<?àø¨d÷Ýa_š°Ëzqñ‹Þ¥@¬8ÈŽ¦…±šÐ8]4ª(!"ä@ÈæÂŒ%‘2SJ1þÐD„›ºá´š …ÙùÀÍFÇZÄ×?ŒSêv¡ÆrCÆ3“ޏyˆ½:÷’oЯÊ@#E>r‚fDˆÜµšü×àºÁäHa/O-(* W(•ã%,^R΂Õýøº7šzCÉz>Õnrä‹nxsŸ=€¸¬†O­KCâ…NO@qÖŒó è¥f.µžjq½¥B£™hl &8ކ+ÔT½n¨>FÓã#cÁœ·CgxÞqV|C`ue:=µä ÚµÃ.´[çN¢3GžIß­ù–}Ç+ÌQX°•ùž†„˜±¢l¡ 9r`æ€;~E²c° çšxqê†8Ïs×䋉!ãD>ðˆÉò‚ Ä~Ȭfbeœ WˆKP×®«)r\FfA6æç狜ä$U†ÚP¿  j@Î5Q“© U• €(<,*%î & fwÒÞÿ_Q¼‚Ê«*¼‹i¸¹ªù`Ÿ43:·4Ä>Ìf¸Ä]…6†e° øÅÍÐ3H̸B7(¦âÐÏÔh< %A¶_¥Õ¸± 7fÚjâã|oTóG/nýâ6ºó€;)/;/":^ ¼æðkéôgN§Â¢BVÒ©š·Zp|ð¯]âA§V–G$zB„Øú88àð˜9ÐEÕÛ6ñ}?(5M “ÁÜIBÃlZËô4MßÍéðypON Üø!<–ì?bs‘¤XCSYQAK –Òv¹Û9ª»wádã£>:›SP¹ ("É‚uÏ –ÉT´°ÈRÝZøÓwÚi§]˜¬ €V­ð–æ57@6rÊŸ‹ ‚ÈߟæÒÈR¾¡“RzQ@mšÚ l ô6ÎqÛÂÙv+™â" T¼M„C¸‹×86L„Ƨ×z1_äžÿ*ï<À†Š tã§7ÒMûßuã_§6èšC¯¡‹¦_De™eÞÓ]ñfÊ®ø\!¶=ˆ°„Ø4Ærú(_:{ ?NÂÏ6b\Ó´‚h‘”Æ ¯2šÒ0˜!íj–ð¾…ßXÐÃíÃJ–&Æ‚xøÙôKR#?äÒ«Ì4#ª/¥0ZÃjíÙÙp“L¥ÑBjEà–Uþ b_vËû€ 5¿–xu¯¿š—¢EØs1|ó Š€~ÎP”dÌ¥bj¯¦Ôƒòà™˜ñÓ1ä®hÅ)Ô”m¿ºº4.^Ãm˜M/-·–Þ Q•A Ð_>@g=3‚ž!½†Ð{œAÿšû/¹Tñt|öÏ€½‰³1*Ÿr äÀæ@âF„µMgÜ‚×â[áŠW(ð†k\LÁqÓ‡ £$ Aã}À+‰E Á-iaÖ_ÁÔˆ£J ãDðBè—3½â ü"€WÊ“uwÀÙhËLÛm$”&õ'™ €õ€(¼Z·2ø½Ç¤¾°¦xµä¢¡Ñµ^@#£Ñ¹4¼=€Ej@ ZvKè€ÆCâyâÿrÌ×ÀœO®…¥—X N:¬›†Gõ‘OTh„dÇ‚›—󱤟ÁUWðUÁË_¡íÐA}ŠŠ|âðiáêïè•ïxJ³+ÿ8À_ ïˆâZˆ9°…9P3´DÇ ŒAABЩ•ˆJy4Âxj¥¡Ã«Ž³~¸Mc¶?–iº6&¤aVžâ´ðÚŠ“?Ê¥B_ÝêgX%ŠË @( (ð¼5êÇcÿŠÉ}ÀÈF_Vr™e4e¨²Õ¡Žd™d(v¡´Ð( ®…7Ÿvl=ýwCÌ:>™ ¤ôoöo G ¬¸ð#q ôQ¦†4*7Žë 1Ú¹jÂÂE¤¡Ä0(ï²h”ÔüâÕ|2˜›-?œÁÀ_ÝA½Ûö¦~íûEÅ»tÌeôË¿—Ò’Â%¢@è‹å-\Þ†[Ql !’Ë8~„°  7t~˜ÆS¼ŽzŠçÚø³rÔLélAmטÑvTúv\?ÑÎ+Fº~zˆ¢r?"òõŠ'PÝ’…7þyÙ²[òðp’ÆH'…˜V¬ò ümÑ¢…¤À²±;¢d¦IÞÉ]JbÕ¬þ…H†€Ü•5ZPüðk¥ÒYðËpú1¢±êY~|Ø7&gb\œ èÓ¡%…S”³omˆ¿6ƳÝHSý cáâáf;-Ÿ°ü€a(ß à{ÿ3*3¨¼²œ¦Ì™Bÿ7êÿ¨MVÆüf·È¦¿‘N{þ4*)*‰ØÈäwÁWÿCKš~D ¡'ä@ȸˆ1 EŒŸ4~¸†1 Äé8gÑiy|z 4NÀJè„+:¾p6‰Zik>þx¦a 9ºŸ®…C²>cìtÔ ([ÄV=§x "MWãaŒÜT¼ÉÇk^õ#aX6b/À—•ìF¬-KÙ+8§æ@×Ï$K@îZ`Úb¹ï}| @2L~I>šÊoL¸…¡\Áó/ ܶÁ5ÀÒ¨ŠD©_Eâ0ίiÅÂ#\Ãj 3ÏS·ÂXtv:¶ÛŽgãëäV> yx1 ÿ°ªpÝôÉM4eÿ)Q‡»äv¡)‡L¡‹_¿˜ÊÓ˽eÓpÕ² äsÚ.u*OHr`kç€sìjªÀœî‡)žaŽ#FoŠÓŒ4>ü–;¡qÄ¢×äì4ç—K MüˆpMSÃ4A/I$@c§-uâ8>Äø‹4Ø­i‹[ "†‘¯† ~CÑ kèÊB##ä%§mËRu74ˈøÉ‘Ä^’( ŒÔ†é»í¶[G„%kùsåfÚ\¾™“ôZÆûC 6Éâ3 ,ÖÆ+f4¾¦à^ ü+‚+5aêF¾êvaÜ0NôñhÜôjó'--ÎHò⟠\Ì'ú3y+ E«Lš—?—ûú1)¹û3´×Pº`ÄTQÈ **§ª’Jª*åOË!|wÁ¤«¨­NaxÈ£­¢ Ï;VÞ13{˾›ý²çŒ=kÞc‹ƒjØ{ÆsdÛ2ãWh‡ùnÄ5ñ±—t‘§Z‚ƯnŒMNYýAÏ/7VSµ—Ž?n~ŠtÃ|?;à†Áä[ð€ê<Ë Á!ÔÐÛáŒÛ\ZB%¼ê™cdbš‘‘ÉÈØµÈÉ+\I2ÉZЂمŽÐføƒ;¢Ìz걡å_³ya‘—¥¯¹É‹è‰l8H qÛ³P:„i¤ˆôb±›+¤ÓØ¡¶Ô¯PßMWi*­ k wéãúQy®¸”þ©fE€¼ûô’§iûvÛÓÈÞ#£’8jàQ´tãRzvѳÞ9œà³™xEG$~4(Šm!"Õ9ððÉØz9ax‹ðƒ\±aˆ‰ëÒØiºã…‰•¯ojÆTÔ)†‰’XâÆÇ€£<‡óø@IDATDþðc\ãòàœ ‚Ų_Ý"ùÙçÓˆä%œM‡kè16Ô@&à£@;Ο?§gËNd®YÁb$Å$K@a´.”ÊôèÑ£ˆ²³³lÖmæÛ˜8'ÙËáFRˆ×øä+u†¹?ð"ø9GÿA ÙxB?š—ñ;m4½—š÷ëçÁ^Û­4ŠS¼ºÆ£Õ0…nÅ7þ ÊýÜó±PSÍ—ÝJÝrºQÿŽý£²8k¿³èç?Óœus¼.ŒtØfð›r(-" ATÔr ysÀyìý1"¯8†Bgü¶CxT9ó¹¶hš7üÒŬG¼:…a,qêžhÚ6ïæôÀ‘€ú§²~þ^[ c™XS>\CŸ 2 @Ïž={sÒ*ü572IòL²Æ-¬_¾ê°3ôÔ#Ü 1ùeù^t«SHƒ¢á¸AeŸ†öFXÄÆ„I#³[/0òWh"Q>;Üv+‘”…=v˜º‚6ˆNÓ°¡ÇÆ'ÍÍ-ŠCò½€ªtª¨¬ «?ºšîuuΑ&õ³‚¿öÐkéܗϥŅ‹=aÀi œ8¥Lø«=Æ:Blaèx`Š¡Ï ŒA8¦÷Ç 7iÙáZ;ŸN ü20 üuµy£•sãÆ£Ñ0m«Ó´ùî»9\Ý€ògdƒ?Ž*)—Ð;n¥ÝP’œsü€äÀ2߯ÈèËMãNGL…Œj¸AFÉ2vÁÜ ¤ó{Ž"-´² ÍtS™yÀÊ5®à†f§î5}ÔomeÒ†¯.V¸v¦†¦+ýÆÀË)~V ¼ñÕÀŒV´!m]ûáµ´¹g0" Þ ¸åð[¨kFW*ç3å|& bsUa¿{’ØëT…,2jè 9Ð4€ °¬ôIôKËÊ¥1xÁð><.…ñ-÷eß ¼ ÷öÜ9Þç=wIÃôw{LúvÞ}˜ 8`É@†Øá¶Qq@€Íúbï5tñ4àG'ÅFFš)S„" ©;%Qtýa²VìØ…ô^æ'ë ¬ 'Ëò£çÏ.á†AcÉ6ê’ŽÔñGÓ‹ͦ±ÝGq ãá•F¡ÒÚ0^˜MWo7x KaüVîHÇ™¾)ðû‚ïé–o¡+÷¿’9k79QûÖíé¶Ãn£?¾úG**,òôY$ÅéàÍÙVà­‰µÞE #†ˆâ€7øhWñT…\…°î»Ñÿ¡°Â¥ç…x¿N¸´­ºãQñ”_ñh ³éÔ ¨n¾0> ŽÇ$qi»saTv( `Ai³APe"2#¢ÊMM·ÑFɆ*(˜NÝ Q ø3XËÉ'#—5Ü•ù3I< úÚnÁóƒ)†¡øµÄÀëA}x¦nSLé Ù¦³ÝÕ/£“h]úX´š ÇKº[Z‘ùÅåõ@^ xíûôÀÜèŒÝψʮWû^tË¡·Ð…3.¤²BþfŒá;>„ë‚ñ‰6­íáQ…¿!êÆ÷yÕÛàu D§~….ÞÎ\ŸCçäåãC‡Ç‡?Qü•Eã‡[8IÈøýp;ž†iBW!²@P:ueú†®÷þƒx óFeËoâJùø'³Ù†VD=¡ÊD##! uD´W€S¼BSÃzfÌѪhÎZ8…Zp…xýONÿé{±¾°¤¬Øc‡ä>ØÂDùÂPY%½Õñk¸Éݧ9<5ñ²ÑtN’•â"'u+4eЉ÷Âkâ)}#Bf‰°ˆÒqï?_ÌO /™fг?=C]Zw¡ñ;*À.]w¡[ù]üæÅT!w0 }YNàú‰ÀPx.D%"BDrÀzLt0×G%ÂÏtþ@ŽñL\ÅkÂθ.}[ÃBØP¦×šL,ºXx$/Œƒ1¦pãbÌ÷û†ÁÕÄå4dLÒô\?sœ*¡A~5¶˜'¡É0*ŒD aUv*T<`ÒL²-]8»Ài\IQü·Æ¨',ª,æ¦ð„‡4 çˆLýW8LÚ’§†\¢i&blº á¬Ð Óx ‘W,Z»6½oT7Nð³Ág€Ó²x9¿š_ä}Í»¿¹›:µîDû÷Þ?*ûÁ=†ÐßD—ͺŒÊ¨\Ú탷Q‡P ˆbYrNÑ>%‰;auÊÐë~YÁñ}ìpÂí :¹2Jù-œïgœºJÇâÌ|¿flÅJÂ5,„‡å^è#N€ãõË ‚xaš€Ò(D$¸Õ¯¯öizâ7>&†Õbü™±«˜ïHFÒgˆedKΠܱ­Ÿ»:’ “¥ ÀjìÂÃ- /sH^ZY%®/,­(õZ„4ÿz³x/e4ÝHB rn]Ðã_¬G^3€ië+Þ‚ÏòijñZ—Ný %Ž™’Ø8àm/̦Kª<1-*ûøø|0oàÐÓõŸ\OÏþ;íÚeר,÷ì½']wÀutÕ{WQyZyñ–ôM?*…“V?ÅõËݳºS·¬nb;µèDm3ÚRÛ̶Ô.³µJoE­2ZÉk™™i™”íéäÒw‹*‹¨²ª’JªJ¨˜•ëÂÊB*¬($àá.¨, üò|ÚT±‰ò+ò)¿2Ÿ6Vlz¸âBF<ßÞc)EÀc…ÙÏŸ>'гýrß¼Ö—¡„Á¯nÉÉó«ÐOÃF†îÆá€¶I=&ï•ÎÀ(º ¼Çï$š™U%'¾ÛWdüdÅëxêú‘¢&.Dòò)Æ*tŒ>,#ña3ÂúOüöÓb»œ{2·@Z`òÅ{<â &Þ|ƒ ¾¹l³4& ‡Ë®ø{Íi,˜À2àà–&B†!iT¨&hL C©à¥a$®æú5ÈÆ«[Ê© }¼dêø8£XäâÔpß$~ôð‡ø¬óøfÀåï]N÷rõÊ“+"г¿ýé/¡)Lþ" ØŒjïº`yÕЬ0Äã}D¢Û¢Ç >ÞZ  Zï@ý²ûÑö­¶§î-»Kß®+[ð<´Éàï<ðîcÿÕÅ”U•Ñš²5´®l­-]ë¹ËÙ]î¹×W¬§‚Šï¹7Ï”Žv?–gýÝÔÏNøy7ð‡qûÁˆš-˧ b¶‰ÒE„×8ZC—ÆwÂDyD<ô'Ó§¼ùa ŽýŠ2¥±ÞàxŒ/-/Õ’4êóÀûÿAKþxrl‰·]ÛzçŸ ™kmèâë]Èx1p¸ äãµD.‘å×T-lµ-+‰mÇÉü”ÁšûŸ|4ˆ_Ä“Y•IEUEtɬKèÞCï¥v­ÚEñdLÿ1TZYJûøo‘Ý™)q0F. BD7«„o“?Ìܱ0 õÚ½Íî4(gíØzG™Éoi~d¥gQÏìžbc•¥´ª”~Ýü+-/YNË7³e¸´d©¸±Ê Ænsó âY“g~;^~ÆCr ñºÆíO‘yè1Ký1Ç 36•U˜ÃÍ1ÒI­ò‡¡+ü‘rÓÑÐv'š|\ºd)š‰~-¬@S¹¤­`Æ cks:‹ Cªªq½÷êš{¤ˆ‚ÀA»Ãh lœÙäÇoyecD„Ò`ÒNñ 5®úc r®ô[ ‚W¬³ÊX H¯L§UE«è’ÿ^Bÿû¨¯¢œGìr„|ÃáŽÏ﨩?æþJ®Æ*ø¤mˆÛšáúãÅ!m†Ðí =r÷ ÜÌÜ”äBKÞÚìÓºX·¸Ïã—¢_hYñ2ZR°„,¢%EKJúúºôôÓį mË}DyМ 3nÆÃäùF¹u’Þ¥Q¿ 5ŽíjÄ&(2]¥ßrPÚ«r4–•€lÖøõÀ¯ ¿¤kÞ¹š¦|½([n |+tûg·C{à`ÞF·R=%€¶±•(P{´Ý“Žét jS# ]¾m ~¬|lŸ»½Øq4Nª\ÁÏûü óéËõ_ÒÜõsiaÁBªä? —²m„G[-w'•¸Ðl1 be[¬P±2ÖááÚoºqbá]ººûí”á¶­¦fÓ(®^0 €flJÝ ýÒ05V=a9/¿@æÈR>ÿB^Ú¯sŠü48´«†ûrU[ á—Ü óãY¤ñ„±&rßmêw¡Gëaƒò‹H žæ`¤¸Ì,–ûx=0ý¼ó·VÓû«gÓã_ÇÅ[3I6ÚCµ#yŹî¤dL@ d¸Q Du KDzÔožz4’â $ L—ý¦nÄõ”¸"݆ûI i_ðz\âúùH׊tn»Å ZEæÁVÊÆî´lïÜ„ø}ßÞG#ûޤ>íúñè]¦¬Œ,ºþãë¥^-DÛáÏ;y¸=+0ÅAr}†æ¥ÓºŸ&'øS¤Ôͦ˜ÙÙ´g—=Åž¾óéôsÁÏôÞÊ÷è½UïÑ…?J”í>~ÅTô¶¡2ÐÈM¨ã•M"cVCh‰«rÅRz@×­8Ö’?â§î²Êä´XgÐ(„s¢ÕÏÛ €[^mLaêFªÍ˜¸›Úhˆ7rS|P:„.(ÐÁÅþYTzš¾B›^q ¦nÚñl:¿Eýh]f»ìaÖŽ¿–ž€·nøäºÿÐûcqÜ€qÔ2³%]=ûj¾*ˆ/ â?=O JÒÃÌn+Q:ev¢3zžAûåí“'a@Ý8Ð'·MÎL“ûO¦å…ËéíoÓô¥Óiuéêhe+&¼=D/ê–[H]è˜/NChêWébXá ^½ÿbLãÕ50Œ¨MbK@Ô¢"I¯4ÞéäÀ²Œä! £î ¿‹óbDÿ*]tHLŒ”Í ­k:u¥wóÛ~Uºôõ@á?·Ñ¢…ôÑòhDÏ1K5j‡Q¢üõÝ¿RE5Ÿ®EýÅ[x۽ȟÍÅL©™˜öÕ~ÝëljѺ™4õ‹Õ³MOQNÙéúä×O蕟^¡9ëæPU:¯bEOaD‚" } Õ.4 ç€;v¹~ä 8jîAxÅÅ¢ Wœ áf+ã¸ñÇÂùeE¾ Uc»×p¨½PmÃS‘Bc(ZÍÒõ+¾AP„,§¬š[UZ•?kDàbÍ5R%:ûwó²óµÝ6]mx7ÜŽ«UhvÐðe—Öúzà# ¡}zî#]¬rïÛg_º}ôírmðfò.zÂëHO·$m´oí+ŸFÇ›·íõÉîC}³ûRïìÞt`û©KV—FÏ>ÌÀãîNÑ}„Ø_‹~¥g?+«8½­Š€@sn@ÇfÝ·R°qƒÆ2·É I4 ›nûOËeãà†‰€o rSvýRždü4†Œr%œ†6"འm(ÑðLã%œ !¬‹ðGÍ3žÛ³éƒðn¸Mw³5¦«Vói@yWgp&`Qñ"úpŇ´_øËÞ»÷Üþ9îŸtÁÌ hSÑ&iS9ÈözÛ72X7ÚcQGî›øvk½휳3íÜzgêÓª¿ÌòX™Ñ<É»åt£ó†œG“L¦ißN£—~™*3*½>jVôm‚PHnenÉ ‰™?Ÿ¨n”Aý §åS¼Æq¡Ò¥*LýÑ ƒ¯Z8ùô¹,£E,¼¸m @l„³á_á¢Â‹]Ë/òKÄ$J—HZ[€F”/>Dƒ>øCYD~ÿ(íÛc_f{|æîÔi'zàðèü7Χ…+¤p–€øsRþJÒÆnü¤¯æÜ>í3ÛËA¾ám‡Ë…=²:5^~aÊIá@ûìötþ°óiâŽ鎹wÐ'k?‘‹¬DYÕípk a¼vÇ.×ÔçBÍ9¯¸X4AáÀ©EÄx@bÚ¤·¡‰]&Òû=L×ïx=í·w(üÂЉ‹Ë¨®u-Þëpª(¬ Š’ ªÚÌý }¬’;_ú¦ Eª3ä@­hò¨k-Vb*X]ˆØþ3?¶p+MPÊJ‹°xtAq]z×囹á 5Mø§PÃÜ4l|ª¸åC¸'˜{Ü’’%ôΊwèàžûÅoݲ5ýºáWêÖ¾›³˜_²ÿ%Ô½Mwºç›{„WX•l#àÛ8ÄUÏ=Û¼Œ<šÐeÓù˜ð}›ñÛãÀ£® âÅ4sÙLª®ôÞ<‘>–彊®Ô½Cgn*É ‰—†·ú£ÜÎ^¿†Ûe÷ý<ö¤²Iö @Óñ|·­³×öqqñüvZ¶;^œ0,²=l~01¸B8§gð*¯<²ø‘ˆU°ÂþÏómŽG¹3ô7týˆë)£(ƒ* ùs0X (åk:Ëù‘„åA[úOÚ"ú‡]Ë—žGgö8“øMê6)þQß¶P4¯s õÊì%+•ÅÜÇJ+©ºŒ¯ W¶­Î€qb+7M¾,~BƒPQMLÝš>ðõ1H'ÈÄZ¹°ó±ÝvŠ·ÓPèÔí 4l\ª¹u¬~.þYfYc·Q]{ïJoÍ}‹Ùý¼í½Ãhê’Ó…þ<ëÏTPX ç0K“}[éØw0«@ÁÍI-ÓZÊlR÷IÔ&£|èÞÆ9Ý"›.?èr:ã…3üñýIÏÈ*¦Nbbô¯mœ…1«¯c\,‚ÚÂOhâ ï±Ò°ñê7§§îXÐÏÛ”Aâ™Â&eW´‘À{u×ëB[[ZÇ놉й4õ禓R~^Z“Á=oð+¼€Ë›lƒÁuÿûÓc3³ÑQîAÝÑC‡?D=Ò{PyŸ (æ}ÛÍ|6 œWx¦e iFü±DÞÙã?½×é¡ðâlÓ!>ûî3ºüÞËéÝyïRyeyÓeœ@N{o¿7íÞiwÿÌ Î`%}«ªŠ-úVø—’°Ç™”Ô¡è:h÷­Å¤¬Õh“XÄv˜ë7a2û·éBw$ß’Áð³)Þ XV¶LN]e›VY­h¿ûÑmÏÞæî³-w¯¼^ôÐÑàÖƒ©¢€h^®Õƒ[Õ\XÜÂÅPÐ1ØvÎìL×ö»–®ÛáºðJ^‹[ʹû€ÝEøŸ|ÍÉ4pò@štÍ$ºýéÛiÖ¼Y´¾`ý–*–ŸïøAã¥_áP ô-Þj’í&Ó·dLIp«)büIÆs¦‘ü±)ˆ§è 6^{‡âÔŸ¢0u·x&g/׫V¦8õ'£]ì¥{;=7ׯ´Šwa¢á Ó¸'%¡.—šUjÁ·ò*À!ÛBi‘¯öëÖvè¹]ñÈtýÿ\󮀼ì<ºû°»éº÷®£7W¾émTñ÷Xðc«A_Ûi,Ûû\ÊÉÈIIÖ%«Ðè˲„¬–Ô3î7tÃc7Pai!½?ÿ}šýÝlycJbǶi‡î;Pï.½©gÇžb;·ë,xÀ¹¨UËV (Aü¨{n¿§¼q"+VÜ—p€Õ·Ü‡ñfKsáeüš4ŸÐÚÆ±ÚÂQ“Úhb…Ûxùr) qÅêŸÍ-Å)Ôüm¿MŸjîÔU¸¹°” a`àFÃ$ÛÄJÓÅ»~-‡â]˜h8è4®ÆIe(¶øäþ²’e4ã—tDŸ#¢ªtì~ÇÒìofÓŸïÿ3Ýrú-1ï À+\SFM¡žŸö¤G¾{Dú…¾!Y¿ËhdÇ‘Qéo ˆ‚âZ»q-­Ë_Gëó×ËÌyí¦µ»!­/\Oë6­£5ùk$|sÙfêж Ú~ Ü~ êçÁ¾Ýúnavܨãèæ'oö¾Ô‡79ØÊ»÷üFÇÆÊôùÒÏé³_>ó^õd¥NVtÌì n¼=Ò¶u[ÊÍÎ¥¼œvóñ4í¢iÔ9¯³CUãØu Á&ÛTTVÐÆÂ´fÃZ½qµ73Dz»™±ûœ9fê 6xE0ýÑà®wÐËYЃGè«&®ø]îÐùô*äA¤£J€ óÓÕne„ª Z=@¹®|}ðÃôÁ÷x³pV hqE3”¾]úRŸ®}¨O—>Ô»koÝ;vP0jkÙ~À%N°üv®âÅÌ[¯â¥EˇU] À!O{†GÄøŠÂC”Ö¸ nÆ€gr¹ΑàZ`†²">j;(q·-h7áÇ*yòl˰°É€äUûýòË·PüƒNl6x c†ÐÀ'ü&^ãÆˆâ§¢á¶¢àæSCãES¿–Í÷s°íö3Ie‡Tˆ¹ø-YE¯þô*Mè7!°V§Ž>•f/˜Mo~ñ&M¼e"=vþc"l‰ ™™‘Iò:QûÜöÔ2«%—öà¿ýù[úbñ´jã*ï`˜¼˜AJP! „úÑùŒõ…7øaŒ@—FãJÒÈPxhòôóQíÀV¿@,uA«Š€úUøn®ÚLóWͧù+æ{ƒ %„[d¶ îíºS÷ݽÃ{zR×ö]©K».Â?àk—ÓNöÚ322èÇU?zÂËîÌ3Ìþ± àßÉoøa—QÊÌe¨J€6Nª¨xTnSg? ~ñð‚™Æç#Î$`+ %ß3²¥ ã#è=Oøës@ùé#,‡†¹PI\¼ú58o»5܆pÃh<…A8MKi\¿Æ±!Ü)jRV€`eœk ¶âÕ__h o7xa Õp…6NÓÒ0ºáAq•&e!|ÈKÙ˜íáGõ=*p´7ýî&úüêÏi麥tÜߣ‡Ï~˜õ„ &5øvA¿ýÄ6â0?ïUëWÑÜÅsé“ï>¡9‹æÐ·Ë¿åÉ)KF¬Ò³S+~Ul” _4,Œø&]à\¼³ÓQ:àØøJ®à‚ÞRl¼Ì¸Í,\ñÜáE‰€Â€mŒ¥…KiiþR¾÷Ùàn _ãž@Èfó,›û€Zøe+³o,㸚‡¥lø8cÏÿb@cç‡põÃmÍö%ŽÆS:†Ú²€€–ž•-n'wy˜£„¦èX‹¬¶pÄ‹ ±ÚÍM3‚Ή§a Ýt×° h‡»ù¦’?e~šÑŒµÝÀÁï pnâiK!@3ÀË#0Ž"5®BÆ£\FýT¯^#øHE¤>ä*aEÆ\D«ËVÑ+K^¦‰;X·Ž¹é¦É7Ò™÷Ië ×Ñ)ÿw2ýëôûhßþûÒÛÈÅå¸Þæf‡%ËݵCW:l¯ÃÄ"ÍÂ’BúhÑGôÁÂÙôÞÂ÷è—õ¿xËʺÜͯ—cÅ€YE ÂÍ °FŒ„£Kƒ­ (ß-ø€8H@ã7È¥W™gI„¢­°Ä‘y–êþª€}„AA=Â…Öñsú¼„3‰ hY©žq¨‹œü—Y6 }†b±ô ¡ ~?HN·x/}8E&γÞX‡çôŸA R‚|tƒñà?²5í•ΊˆlYIy#k:ð†Æã@<ž Ña”F¡‡e|-á×¥Óø.ÐM‹ý@‰uÜ@úx¸ƒüŠ7P"اž;enߨn á÷† Ä ÷°ñe0‰C/M;®Mg»‘´ú]¨Ù*Þ¦Õ°­šFÂÛT„Á•—Xá{Žê{tÌÃ{c‡Jö™H/~þ"UÓižF·Ÿ|;>ôð¸,i׺-øe=ÿÁó4lûatÐàƒäõ°¸‘ˆÃЇ 9D,’Z¾q9½³ðš¹h&}ºüSo‰Õ#`|A…’GvŠü2Öö‹€ õ~<·H0áÆøqØï®Dì©Á1뉒ÀiAQ@¸Mcü~º"¼¹wCA`#õæÙ:–ÙqøOVr‹¾aT_gò¢<"N 8ßoáàô (XåYUœ…ü€Ÿà¡®âp[Ïòe`ÆÛQý8¡#&jãWmášp"t.íwÝêT‹¼Ô jyR¦¬ #}ä»ÿøf·? ™Vóqn+ÊhbZÙiA[ˆ;Aâõó´ãºQ6æBUoÓJÄ­éGÛmÁëÚ²µôâ’éÄOŒYË«N¸J^a[[²–ʪËè§/¤Uù«èFþOÌ8Àa³óΦÓo?Îùû9´çÎ{ÒèÝG‹Ð{@ܸÉìÙ®'²÷)bË*Ëháš…4kÉ,záÛhcùF„¶ ÑY¿B_Wjá„€rý(0pj‚Â5ÌôGd(ÞòÌè n¦Sáîã Ìï­xxôeU 4èÅmfY(¿®Èþ¿.û³ÐU¥F )¯(8Æí+ZY­ ‡K]Œ…·ÝvZ6Þ‹d~•wŒ7DÄßÖ<6¯ºû¾¦e Ocûáf+c«º¹-ðèËÆùsüÈRéíìSÑÒ @*2<,³ÃR,üõÔõ´¦ÑøíÇSË ï’'åµÎ£«&^EçN=W®Æ…P7L¿–®_J=ú¯1/ B:8Ä÷ìÕÏÒU]EÎx”>šÿ]ÿøõ´]×í|e`¿Ýö“KbÜ|“éÇë‰øžìy#Σ¢ò"Z´~½³ôš·f}Ÿÿ=•ó_ày[à3ÿìÙ¼ÊA)«£¶ÄÀá/ƒ$»Õê 'xk&¯¸án”I +šžG~¨·¿îµû§îuÅ(4^€ˆºrYÆ®›…öR&ßÇ'¾™|£òB`@™$NøÓü9ÔÖÍ¿ÔI-aÊ*z  ÜÈ…Æd‹CWxè1ˆÙaŠ·ä€Ó‡^Ü’Lüž5h8M­QM ÛkX¬‰Ê©Ôxl·¦½Õ@T“-Uá{ëkÊÖÐ ?¾@'ïtrÌ*±ûôâœéíïÞö–ŒyivÚÇÓd™ý'ÿƒZgy·¹%Ð"£ÝtÆMr Þ_þ a6¾lÃ2š:k*M›5M„ÿˆ]FÐØacé !Ñv· J&©¸œ94¬ë0±HémXD_®û’¾X÷}±þ YA˜ "è¾Ì7Å!\ŒLuî7*КäTÀÃ+«F˜« †6q5\žCç§ÉQe•J ¶Cxï×DËQ”ƒmmϜɹîéÛÆõ[a¼¬yD-Êm܇'~;*Be™ñGÑi8 Óøá^¼š¦“–ıÂÔè»1êÂLØh˜ !sÔ/D)ü“†ŠÔ×ð ƒÇ uP$ð7¦lÙlqA7.]Ç-¹ló^z饧Ò®»î Ð`3éµI2PÈÒ!ö ±OˆÁPÝð‹†¸ÍlÃp0ºp€¢µî­gÚyPÉ@·vLíd6´š#0nƒ9×LàzËCÅËðAŸ¼ŠKòìiÙýv}.Q·Ð¤LÛ•TÛ[Û߇Jìô‹ZÃ5 æë@ÍSŸg¡cûpª„áÀ+¶Ì9ynvµÞˆÁõЊ›qÆ »õv/X°@âŽ?~;6±-`[ȶˆm ÛÍlKÙâ³™l+¹^ZSöÖÏl™‘¬~eˆ%‰ÁØî"Ëê·»Ç/Ûm‘øN¥ó 8ì8‰¸‘¤Ò¹P³S¼M«a[DӘßúŠõôÌ÷ÏÐowùm̪voß.8ôºñµ½¸Ü›!ü¾ZóßñôàäiÇ®;ÆŒ€á; §×§¼NgÞ{&Íýy®(ªJyXX-Þ°˜¾ç{ºoæ}”Û2—Üí@=x42J>L7ƒ$ölÃÄa{dŸ#%Õ ¥è«u_Ñܵse…`Aþ¯OAÙµ¶ ’¢Ä¾PÿM»iUñ|Á`0·†3”gã–Áùáš>C)/C]Ùç@Ã5“¦$ì1-^’I§i)Ô|ÕÏ­á.ÔtR¦ì ÀI¯$ë²ohÏúm·µ ƒ f<0г~ ”¬¬éµ 6: Y-¯¨ ·ÓÁOqÐJ[ñnšV¶©íÔº2”º²ŽkV«Ëx „WªòhúQÓ©Ufì/¾áv¾±7¥Ÿ ~’‹cäÆ6V |r3réžî¡}vاV>•U”ÑÕÏ^MOÍyJî¤×Ãx23@ùt& giUi4¸÷`=d´¬ ì;Ð_Eª5ÃF ((+ OWJ¯þ˜>Yó --Yê•§1‚D˯m@4ñgû6}mÏ£Mº·<is¥Q¨¥6þ¨¾¡t´ÇHWcAŒ-†4ØÊ³ X•ŒšýëóîB¬”WÓg¾¡%o Wľ­/rDÇÞšªg=ÀRG~ðü‡‘y@ãA}ÙzzêÛ§è÷ƒ~“XŽ¿fÂ5ôÛKÕ-X(ãÂ(¬èVÒïŸú=ÝxÄ4~Øø˜i _»éd>À_É»î?×QEz…ŸÂ1 Éà ?üXüzõ×ôÕë_Ñí¯ÞNÛt¦1ƒÇÈ+†xÍ0'»i?=œ›•K÷:X,ʼ¢h}²êQ欙#‚ò+3kl@° €ÃË©¨Á8é ûeF9r .Hé-ÌÞEˆX5–=û]¼E×™ŒxvêVhg®8‚FqJïúŸ2PµnHx¸¡qc)Ø‚-8ØÆ‚üÑo¥w>‘pH.–¹ëH:xÀÁ4ëÇYr Pã"~eF%]:ýRZ²n ]0ú‚Zgè'8™t@ç>w.­)]ãHã•#¾žF²·•/•ôòtZ_¹žžþôizêã§øPL&í½ãÞ²U0fع7?Vù ß#§ÛïX±8¸ô݆ïèÃUÒ»+ß%»À¬ŠùÊÛ8^;(t‡¨+ÇêL‡1¥㦩~ºnøãýÕ’e³NY@8‹F·-¶ßvk˜h¦x‰ d=M]¢Æ£VÏ¢m±hZ†®°W¿´Pü g+JÚ‰eMôä‚'éô!§Ç­Æ¥G^J³n›EU-ø­¼GŽ•ÞÂñÔªŒ*ºwνôÚè¶ãn£ì±"“á}‡Ó‹g¾Hg?w6}³öÙ2ÂV“ I¹Ð¬TUð¶Ül}¥€W>úé#úð‡éºç®£>úÐÁƒ–­‚}vÙÇÿ}ÜJ%17 îÚaW±Øå´nó:zoù{ôþ¯ïÓÇk?–¯®à,Ë©¨†ä€>ûn â]¨t‰â•ά0à“i5ï†){à„×NðNõãºÐLó–~±ïo ìãZç P0ÈÉÌ¢ñ0¹ÃজB„%`DxYtÐÕØngojX4Q‡8¶[Óh¶P«ÎPÊm/ñgöÛ¤^†»¼jKîØgãómªÚÐŒñ3¨M^*‰m.žv1ýû›SF.M.‡-UNÚ–Ó«*ãDù\Á.y»Ðý§ÜO]Ûv Á¹€«f\E/.|1B©A©«º%€²²ÀVŒ’ §†±‚Ð:³5í·ó~4fÈ:xÈÁ„¯çmISZYJŸ®ú”Þ]ñ.½·ê=ZUê}ÔHž(xðì„ÊÀ–l¦ÔÊ›Ÿ¹ ã•®P‰ß§sðþX¡tŠ°Ó±Ýˆ1ˆŒ=&iZ{ÿ¾RÏϧ¸ñ\«Å³ · Ù³øožù¦—xÃ3õb 7‚…n"¹L˜Ëï’Šá‰7¿x~7 é+.´i\7üÍР*lù1ñª‡¥}<`ø7Pܱ„¾S%‘5PÌX†ç—çÓ §3‡žåPEz/<âBzå«W¨ª´’ªy :‹WðŠ(”>(‰œÞ·ßÒ±÷K÷t êÿCB8pó‘7ÓÀîéæÙ7ñu÷|ÇÒ²9–Ê¥;yå•! ÒY `.È«BÆ <+ ž‚PM›+6ÓÌ…oÑ[óߢêiÕ´[¯Ýä5ÃC†BÃv÷"£È'LJ —öﱿؿÐ_hþºoèÍ¥oÑ—Ϥ囗{uå:³àÕÊ€TÞäŸèc“œâ†©¤4x@HÈ$J§‰%B¯4‰@Ð(æ±õÁÔÝà¶YˆvÁcq7¸Ò ,¯q,˜è8†ll£2Mqv¸íöà RÃEp‚À ³Pp6/cU@´ê€ý|ÔÇ׿•>‘Z 7¾ g¾›J'ïrм†+z¯Ž½èÄ=N¤Ç?œÏ°°Æò¸‚{yZïâCh³][¼–&M›D·u+6¨æk~±ÒýÍðßPÿÎýé‚×/ð®ìE2œÊãýrYÍŒ!Mf ¬€°àO‡ð‡5ÛéfuÀS<¥àÛußÒ‚™ èîwS»Víè Ñ¡ü̓Ã÷:¼Éï€`ØqØ‹†^D Ö- ·–±²ÂVÞ*r¡œ¡âhŸpeÝ 46b<ëþX©á 5®ñût^ÇGšðúxir˜ÐÚi¨NãV:É‚qРS4¹à ƒr Sg!¾ð¬-MnDÄI˜>Fznüx~7 I*ΆêÖ,m¿íÖð-­AÊe/ñÛ (’F¨c‰UªBÐðì³°¢¦ÎŸJÚýOq:ë³èÉŸ¤Ê²JJ+ãÖf% #‹À¬·ƒä{îì.+.£s_:—Î[}{ð¹‘B, ‡½zïE/LzÎyõYE€ðóV8œ5`#çXkÁŠ”šUö‹2à)ºM€ƒƒ¢è¦É¯È§—¿x™^úü%êóï>4ãÚÔ¶uÛ€5 j׎|n€íùCΧ…Ò¿¼AÓ—N§•›Wz+Pt5n0FåTT·m$:–%J§ÜL„^i ±éÔ¯ùŠ;BóÐÒ¤Äðš:p@;E¢l¤ãFÀ«€“™- -h*ôDðC&ãá0 „ëã‹§üÒü¸üÄ*Àø¡ãå6ÁªRs8˜œ áÏËâ;ómøŒŸ¸ëã»èügΧÍå¸h+¾éÞ¶;=uâS4¡ßª,ám>Ÿ ¾¾2€3)¼ý€óò=ûÖìÆy“òÌÌãw`Û±mŸI-Ú·(~ k›)3îÓï;Ê+pù×–7Ú ó†œG3ŽœAŒ|„&ôœ@¹Õ¹r¾BA2/¤OhÛƒíj·|ñÄ9àp ÉWœüëí•}e 0˜…ª[ý˜}°Åò¤Ü)nðàòMxöÃíC/þ83—ˆ8&²+èlÛ­y)½†ª[‹äû9’íÖ4š*{À+Y“Âx³[à°·þ³Ñzy¾$ýj¸Mð^ÿ£_?Jçíq^ÜÄÏw=ÿùó"¤½mŽÌ=]–í1[ÍBwáƒ:ðßk?¾F?ÝÿÝwÊ}Ô½]üy-3[Ò co !]‡Ð”ÙSò柚%rP”^>1pqnàÒlU €K¯ðV€S… +¯ø˜þüäŸéŽÉwÔºJ—)I Ä,x—áb/¯¼\Þ&xuÉ«ôþª÷åFr—ù wù Oìüã<_6YèNaèsëTÁ#4\¡Ò©ß@ìsðJŽgÆOW<‚ªùÑñɯ8ž<—ˆÏápësäVZŸFÇÚ\RÒ±š‘Ї‚;¹< , TX‰p‚Ÿ­~<< ÃÑX†{©S³ °qóƸ9íÐm:`‡ø0 Ÿü‡5wwË`´XP§g³ `ÍÎ, £ï;š>[òYÜ´5ð„!'О .i]¨ª˜óàïH>d”xºpþÀ¬ @I@¾­Ìê@ŽY‰Àêl[ÏÊJV`yEàÕůÒ-3nѬ›ÄW ÇôCwx'Í:f]5ô*Öv˜Çw|Ô3è3:ƒ?Ê£fU›°0!¶-¤´ ‚'òãÿ%~vËu³ð¯aÛ:40{U% 3Þ—†@“×çE@iøjMáecòÄ—û`Ò^T]Dõp­Oéïú'„øÕ?Îx Š„f 8Àçìeú ´Nžv²œ!¨5&ÀG‡^œô"íÙaOª(ª ÊâJªÜÌ–ÏÈL_ò3ÊU du‚·$Ò²¹¬Œˆ…R`o¥àþÏï§f?H±¶M^Ë<:¾ÿñ4õ©²Mð§¢ÞY½©’ßʈèGè[¸òYû`cö¡0í¿èø³ú‚ -– €ß·‰ƒ‡ ~…J'ˆþIi !|ׯmH[E\ôiÅc–‹½\²Û_&3P“×{ª¬ðìýÉõ%ëã÷ó÷Îëí œ(5õ2BYW|%ÀÌÆ«[WÓo\AW¾t¥,ïÇÍ„;´î@L|„~¿ë喙˜•'V8ä[P6 ?í4°%åßU-ƒ Õ(\Xÿì+›ý7zôãGíäš­-:sð™ôŸ£þCOŽ~’&ôš@ÙÙç¤è‡j›m­Â‚…غ8² çò«94ÆöoónÕ‚Yb&&³2Çê,VfjFûÅïFÅó Z^5ƒÀ{êøüom«8çqÒ¾'Õlèr4”K À=þҼμy9þ‰¯Ÿ S:…Ö®«µjétÙA—чÜAÙåÙ²à@TeÊæVLDá:ɶBÐÒÛ*ÈhÍÛ°( ¼áýèéÏŸ®µL͉`pçÁtíˆkéÝ ïÒ5î¡[ï, VÂ-‚æÔRaY¶5¤¬`äº7k@«¹³õ‡°†7<Ó—WÓ°äª3|³G‹¯Lë>?hÄ‚¶¹ðP…& Ì'=)ïósébšã÷=žÒÊÓ<%{ôæ­Üà¥Ëy"ˆ9=WÈl“IŸ­þŒŽ¹÷Z°ÜûVwÌŒLÀ¸ãè¹ãŸ£>Y}¨ªˆóÃöòä·$O¬¤€—ÊS'AYàÃsþ V  °2àŸàÕ+ÿ{%=6ç1'vó÷¶nÑšŽë=wÄs4uÔTÓe ¥•zí£oTèê“Ï'åUséƒa9’;h·M&_‘f"éÕFŒ¦ïùRö7eÌâa¶ùÙ|"ÀŒ³}¾ÉΟícOßžñ󾿿' úæö‡3¬Tg0äýûÍi›éÁ/ŒûàuïÐöÛi?O0gä,ƒÖ•ë(/ M\Äo¤µ2ûñX‚ÏM§•å+鏇ޣWæ½7/ ܱӎr_À製sæL€œ?`@ö¾Á[ðØå3×gä¼V øé¬ÎôÊ&çÌY´œ4ºökéoÿC³M98¼ÛpºcÔ4ãètbß©Ey‹švÒ~‰s±xå…„¿!„ö }¦|ѸÏöÛn„«qiŸj°ÉàÓ°ž0ÕÝäåE_eë uÌø1Ûç%ib@f£ö,«É ZÇ ± €Y2/—?óý3´¦xMÜ&Ž˜èíÉC0+þ,õfãϼÍ|šÞ€¥w^v/mYJç¿t>]÷ &¸Š—j1mZ¶¡»¾›.ÞãbJ+æ®Y %ÀlAø+h§ uÕ3¼ çÌÖ ÞýéÝtÙK—Qe–lRÓôÈíAWޏ’Þšð¶ÓiÔ²¢¥§à …鯺e#ão,~¥fõÃR§8R]ž5¹´öæ@´0U àS7C~–ßsè"Ò¢O畤æ×ŠƒrÀjþ˜…Kžøµè|·†…%‚Ãò>fûØÛ癄ÌzuÆo ¿¿4SåÏ]HßL÷qÜ.5nø8>tŸé„ ¾˜Ù¸?#gÈI}¼E§óÍjâa5à‘yÐ)$v.‚ûÌ}Τ‡Žzˆr+s©¢˜ßàÕ= ¯ù ïãµVð‡ºã ^©P‡Ÿ_ø<õÔY ]d—Q[8°c«ŽtÑžÑ̉3éw;þŽZ”¶·ðF…ô_¬ „+©ò¤¦d9õ0Oœxm7¶îT7©«¤:ç“Y~ôCceÆ™=ö¹1ÛÔYp˜(‚.Õ fÆ88Ç‚úÙÅÏÒª¢U1k”Û*—ÜåÀšUkf)«NL¬.È+‚œ¶ì½ó­þ}¼0gÍ:òî#éË_¾tb{÷í»/½<éeÚ­Ínþ}ºß­ç1$f-í… Š('x}Qï`%àíeoÓqGË6, .D aÛg·§K÷¾”ÞšøÛûXÞëáE*^¹ñ šŸgµð-…ª5ä@“s TšœåĨ[Y=À̃£ú:Ëõ—ù·–Ò,‹‹0d% ,½Œîû⾸L=bøž"„WÙú«à+Fþ³IÅVdÙÂVOâójÀªªUtüÃÇÓ3Ÿ<7_ ì‘׃ž>éišØo¢wW_#,BͬDøù›öÔx>ä:ÃøJ”G ÀWq‘Ñ‹?ðˆSü·sNgºqäôôáOÓà6ƒ£·QBE Å[8,~sàSÒð°]3›Õ3ˆÚ‚F¡çKèWòu(]²k”F!•8o‡‰Û-¨I^â›ý{"ì¶qˆ»UÔBê+/Ù?÷ÃstÆ3¨[›n(2‚@IDATÕ=á€hÔQ´|Ãrzgñ;ôê¯ÒÒÍK%>^ÄI{9\¨Ê…¦‚ôñ„XX®‘fEz]úŸKi@÷4´÷Pâ á›ÆÝDC¿J×¾w­Ü1^Å_4{ûXÑ¥3}­Ÿ›š¶{:;àÆv|(ŸLd³±x#M~|2µÏYtÑØ‹(3=eo©~wLOš¦/šN7Ϲ™Ö–¬õVAx…m#|c§(G±øæ§:šŒ¦¯ºùé˜çi¾_ãè‹ÞO7/qBM ã2ÜÆJYl7‚°gè"ÜIþL¸ä´SÜ„+©Ò€vÇÅlk_æ×.<à‹áÞ PžVN÷λ7f ‡.y]hXßatᘠiæ3é–Q·P×Ì®þжJdÛ¼Å`Œ¾§ï¿&ˆ é}¼%ðØÜÇ”4!xâ驉OQçôÎ5÷èG…x‹&b5ÀMÑÔ[„Î*èJ€µM7þùÉ?é¸{£ŸÖü䦒~^ï #ûIožø&ÒïªÞÌ«8æõJ»Ý¤rúœ¤dMÃB‡hZ„ @Óò»î¹™M´Ñme™?A.©pÎl‘IÚt =‘¨˜Å»ë±4ý„étôvGû_”SúPlAÌ ú[x/ïä«Àåí€~ý(á|µlCz ¡WOy•öê°Wä}nÞAÂÌUp`QËenÄ¡Å/Ö}AcïK÷þ÷Þ„Þ\в5gˆ{®y%M7zföôÎTà|Îu¸Û9à]hB„ˆË”]#Ôe,ò\3kÓA“!”4°‚çË€À ¥gÏ 5 ¥Q¼Ògã%Œ…½ÒȬ½ºÌâ+Nˆ¶ÕæÝuà]´{§ÝëÌ…Ü–¹tËè[hØ×Ã躯£ÊŒJÙÀA;=(³m]XU—9_ÌJ¡H¬)YC‹Ö.¢Ô)\!üø ÓÜsiêWSé£ÕQþæüšõ0"¶·màç2ˆ›W`¤L² *+.£›þ{½4÷%ºú˜«ißþû ]ªÿìÕk/zõ„WéÖn¥'¾}Â{cƒÏDÈI^ÁvŽ(m6R½Ò©V~å½[nƒ×±ÏVzŸ^Ã5¢úºôðkCI~cÕ™@ó”ÑY—þ"¤‘â¦ÉejŠó­ñŠo:•/౯e@÷÷¾t¼d0°m‹¶ôðSÿ¶ý”ܤA“¨o^_:ëõ³¨¸¢Øû´/Ϫ…Ï®Øj€@Æ? . bËëôþÒ÷#€•VRûœö”•·\P.†÷äÏê²Åë¡ß¬ù†>Xñ}ðë4oý<ù(>©+yå#B°!u” çP”‰”Y”û.ÿ;:áþèÐþ‡Ò㯠í»l/¤©üƒÕ€«ºšFöI—ü÷Ê/aå JÎT`R€-ÓfÒŽÊŸT®tXöfÇT—gfXiv|M¸@ÞܹF"ªß…HÐÅ5¿j• åý}ýÞ}†…_o¯mø'Úù”ݧ4XøkGÑ{=vôcÔ¶¢-Uy_õóß`Ìïãã©Á4( -‰f¯ž­ÉìÞ¾;ýkÆ¿h隥øxmxûãÐ?Òãã§Oÿ”îqÓëÊã?ykw8À¢?àx«/ˆ`ÊdßaÞ†U¾Ã½ùã›tÐMÑS/ Å¿.ŽWœ” Õo½râ+´kήޙ \ùlîzðù„çÅâUøü„¨/ìi¤ºI]@yoCu£UàŽek /Ùxœà73|}}OÞÛ×»ãÍ;üþûûÉÎ?…Ó×cé>-™4ƒÏûN=v*å”çïÍãà¥á™l ðÓƒÙ÷ܵsis¿°n™“<™Ž¾öhzçËw,l|gYE™l€ 3ÜCûJ7ï{3Íž8›ž8ø :mÇÓ¨o˾ޗ qpýV_eDÙP&Üa ßàsþY ¨Î©¦ç¿zžºþ :ùΓéµÏ^£òJþD ›m{г'>KÇmœ(oró"+ß`À3—Âý~›)»öǦj+ä§yÙnÅ)tÃàOaÃs†Ô6®†}P—Ì¥íâ\?òWœ@t&6XöÕ¥}]æÇÌQü™×x·y€e÷ v» Qø0°û@švü4:åéS¨¸Š·Ì+vXVÆŒí'KËÈê3/5—V–Òœ_çÐÈ^#ý2á­ƒI£&щ7žH—Ÿp9?á|ïU5Ÿ"Ú‘•™E-2ZÐëó_§ömÚÓ>}ö¢Œ´ Þ•· Ø^2üúqã4ý§éôú/¯Óâ‚Åþ_.ÄÂ“Í ‚ãr¦gðpؾ`[ÅòÝŸÞ¥YßÍ¢ÙèØáÇÒa»Fûì¼á놩f²2²èæq7SŸ¼>tÛ'·QZ%·¯ÜH»¡ípXRÏSàù ·¶hëx˜h!’E念þxav¸íO´üÍ•CXêÕÊ…¨©ÒÚnÅ56Äìò&Ìøå |˜Áél8Cã—³±Ë”‚éïÕq/êÓ-Ø(fHÏ!4õø©”UšU3£4¯ÉÖJ€€Ÿ¢V~U–³8›:äu ëŸ¸žþç–ÿ¡¢ÍEQ4.Bê°Ý£ââb:êî£èᦂ҂²~íúѹCϥ׎~^=ìU:kÀYÞQF³j$¯‰r,yU}{A?+œ™›Im½ol¨Þ@}ðM¸}íú§]éœ{Ï¡gÞ}†~YýKD¾©àùãˆ?Ò­ßJĬ®*f~ð+ƒò|áC»áùBŸW˜‚ý?L6VÛ¡£»iÛ8¸a@“â&åWR‚ÿ¦£ˆàç½H_ €"€½I†b¶‚ÕèíÁ<:°ÛžÍðÞÃ鮣þ}ËüJžègp³Uñ¤ß»¼‡[Mf×:Þýëì¨2µÉnCç{>]ùÈ•ôŸOÿC‹þwM»tíØcÇ(Zqð.Sߎ}é÷þžnzå&¿Çx:uÄ©4¨Ç Òì…»_H_¯ùš^üáEzõ§WiSù&oöoVðUÁôtïÂ#̆«[pùqhŽmziºœ1Ì/˧æ¾@ÏÏy^”‰^í{Ñð†ÓྃiÐöƒh—Þ»P×ö]#ÊÐÜ<O ’òºâí+dF›‰Á¬üÀJ@hB„à2¤z~ð$a½PùHáès+¶9lÛ°Íe›÷ÒK/=Å ¨ÛëRˆdŽ}åXÿµYÖäRÈ2–úp*šŸy™ýÀ0œVˆ0]D Øú~d\ ƒß5Q82„ù‚Ÿß/·—ø5ž¯H4/¢Ý.Jçæ»Mú™=OŽ|’†wÞ$ÕŸöñ4úë[•ËðMÜÁ/‚“û™ô1îW²Ï3Ì÷Ç¿OÝr"o#Ü\¶™ö¼hOZ¹v¥”·mN[úç9ÿ¤q»K¨üE¥EtÞ£çÑô¯§ËÛ Ãú £É#&Óø!ã);3ø-ƒ²Ê2šùóLùZâG«>¢ª4LwA÷b¯}æDîÙÇ5É\q는®&˜wìõ¢¤ÖY­©_—~Ô»soêѱumוºuèFíÚ´“­ @¼‘Û:—232)/'Oso¸zÃjúvÙ·´`Ùúzù×ôͪohIá>HÁ<_Ú$÷6h»á-Œ xÆã<çRÐm)Qo‹®±ÁÛã›)½B©þúÆãtüñ•Ó|­Õ Ãó€Ið¸“2¬Æšû@Ä­Ï ÎÛèóÀGgf=KKÚ ¸páB‰?~üøIìØÄË~…l±lX‡ŒJÙâÀ>IZÉåäB6Ì¤î ª®Õ·¡ëV:6Œo±ck>(:’Yv”ÆavgôA×á\šmÑÏ|éÚªéf §îs*Í_1Ÿžœÿ¤Ïm™Qr9d&­Ï +•ï/ŸŽï¼OáÅ.¦KºDNaE!ýöîßÒG^@—{™÷Ê^DŒHONËzðŒéÎéwÒ­Óo¥¹ßÍ¥y?ΓO¿çñ„òíÐi‡ˆHØ?¼ßábW® /ú7=¿øyZV´Ìz(»(¾, ¥YÜWYà§•±BcoK©ˆÁíæÊÍ4Õ|š¿r¾×ŸÑW1@‚p«E©àfƒk‰sZåP¯N½è¤Q'ÑŽøáÌC]ÌúüõôÚG¯Ñ+~ åk–ËÅâå‹i}ÉzOÙÇjF–§¤áK‰8÷€•µ2àúâËŠç%êRˆ61˜v"V¼B%P¿Âúâi¸éØx ·ilœºGâl¨a) SwàeþR«/:ë—5{3|ø›j†¡-ìE`œÌü¬CH½H‰âü6o˜eóŽ™G9™X`jSZ^JGÞ{$}·é;’×êp f”ød°Î&Y'?¬Çar)‘[*œîßç’}héú¥5ý•»çèÝFÓ=¿¿Gî pãùÿûÕéì‡Ïö–÷1“5«]ûõßNÝûT· ú˜gÜANgý2‹¦ÎŸêWÀìý}³#àõÌø!øÕš™Ða†¡oÜÀVP&kÜÈo·Þ»ÑC†{"f/œMg<~íyóžô··þF+6­ˆJ÷ Œî3š¦>fL˜A'ït2µJk%Ï"¶¿D(bÍåÒoÈý8(˜Ç¶½±í2(³]¦Xà3óø0!ÂaÍ¡B½wwÈ+ˆ|5±(N˜•C ³ÿ»µßÑØëÆÒ>ûOTY]į<@'\u­/43}(?䬀‰"Æ‚PÜÀꂤ‚ÞM4ô‡H’!ËD IBYê“DÓŽ¤õ)a¬8¶@U· 5žsÝ qq‰ú¡5+BÂ@wg N÷•@—hº!]­¼*(<fllÓ¿[:g¿s¼ûøt9Þ5ǧ…1;ÖÅÆ²ôõÚ¯‹rÊÈS¨[;s>€Ÿ:¸K‹–Êiÿ>}!0ž‹Ä-~Óÿw:9øHécÚW寢;gÞIûümúÝÔßѬE³’ÚïDS˜BNú.~9õÊî%3›¾’"KéúÝ3‹a!o”_ø+ß¶,èÂßÇ%þ’%ô‡‡ÿ@×¼ñå2»Öen9l†Ù&ú›á‡Ó³‡=X6¼0ä’!´±r£·?ÍËÖRèØ. ü½{îM÷O¾Ÿ:·í˜†‹œñÕ :÷©s©¨ªÈ›![KÞ¾bÊÝ1+<œ~·ïïh¯¾{¹Éøþy¿Î£}ù/š¹t¦/0!|÷êº]6ü2Úi¨O›¨ŠÁ?}@ïüøÍX4ƒÖ­ñ¢BaÆÎà ÜcÀ«*þ§~±†-ðÏ,óX¾Yò—-ìùc P%@ŸwŒ 8 ã‡‹«Ê#¤šÆá@Í™¾ÁÛcž(½B¥~§c«ƒWr?- Bãb¼Æ? úÆm†þxÎýMÂuû´p›ó1â6Û¼p'ë À¢E‹¤HMý€Š@É<•~Ðpòh¬” l‡I‹3­ïwñ6 Ü Øú÷ñcßÕÜÉŽe~(°J‘‡›Vèlƒzð¼þz}ð2{SôßC‡JC» •³•Å•þ§„e€àú|±æ *(+, Þ8mÔi5çD˜^„/gòë'4öαôù’ÏÓp‘ã£ÿœ÷êӾᄻˆ…àCºP0Xè•U—Ñ‹_¾HÇüóuû(zô£G©`st9‡uF÷z½9ñM¹Z7£2ƒþ4ðOôÄØ'ê%üQ¨œ¬Û,Ý8îFúôÜOéÉIOÒqƒ£ìVÙÞ~=çµòê/÷ÌÒ¾,ã·6a8?`¾kå˵im8>Ó¤åxé ==ô§¯ Ë —'|F±°Ïa*òPDêoÌ·Ã$BM¯‰·Xtð6)«4:ÏM«` 33+Ñ`kéÎÏ$e€•šÙ+g')µú%ƒ­9À·ÌáJ]¹iý‚gÕôñÊc&|ÚèÓ¨ezËš³L)+X8Іýl~o}uåjšðàšöÁ´˜éغ ×Ï{Föé¡ù©ÆŒXÙÃr²7ã¿[ó]þâå4ìúatÉ —ÈkŽvzpïÐ~ºeÔ-4oò<¹dH¾0èÕÃkè{ýãˆЧgJ—t¹¬vˆ²‚·*T0_öôõ0!C]y¼9_ «0PðvVc Lñù…¨3˜ù‡³þz´Zekå@¨¸-[ÁïÆ ýMÂ%ùKèçüŸ›$¯ L|õÈéá \5k.Ѳ…ð½åïE\ÇÜŽ4iŸIÞ*J샳m”Ìt+³+é§ÿ/]ôôEä$’õÓ®u;zü÷Óéûœî-iBÖaûäæ„|„pd|qe1=>çqsÇ:òî#é¹ÏŸ£Ò Ü5RcÚü?{×`E‘´kwÉaÉ9 H8PDL(" &ô@Å„ î7žéôÌs> §‡ˆ'*P ‚• 'HÎ’$gv—Ý¿¾š®Ù~³/î›}ìÃéÝ~««kzºª«{ºËá,¯’1Õ+T§‘Ǥo†CwváþºÁÏeþºÉP7‚ñC@ÓÇ2Š~ Z[õÏŒ?DíÏÉ P2Ï4€š^Ho@™5ºÞ9ÂŒ5>\ØMÓòPõC¥«wy`–kEYݯë?H“õ"S/à{ëpaþAÔj)o/ž«¹q°Í2øÖþâ/vÔÿ¬Ø¿——xýkÙè#_­Ž,çgŒ ŒÜ §ŒYF’þ‰·Þ gU6ì[¿¼E}žíCë¶­‹Ù\¶s÷ÙwÓc½c­wYPÊÙçÂÌPáŠ`Ôã¸ÊX™åÌÕ3éšq×Ð÷Awt7-ݸ4f}~e¨X¶" =f(M1®=ñZ*[®láÒ/ˆjŸUüB³$éæ>YòÀ†EXeîLK´¿È_ð^†Œ‰)“¤?º4l2xÛ0"Ââ·_û=úVº›” .Q“í~Q^;”YëǦ#Ù”dTºº9x¦ôP`ü’ñ²óü@aÔë˜^…ëÿzt®é3ÐNDÓP4¯×œpÖ¿{I "X2ó‚&Àã[ÖÌÞ4›Î|ò̸÷ è4€ÞòÕ)WÇÙÐÄD ö`¶ U¹®³ë,šÞP·mï6zaú Ôå‘.´lÓ²”’{nî~3}1ü :¦É1ΦFà Ü ÅÀg‰˜ñ›Y¾´ Z{SŸ )Å<¨ìJRÇÏ|)Ä/rvø%ƒúáÂØáHq<™æŽÝ¸±ÓÓ ä²ó‚ÒŒZ·LoA¸(ÝKŠ&üèÖî^K-‰}ˆ ºCI˜–õ[R›ºmœÛæt/9v­³óÕª¯¢V{Å©W8ýM—ÐQ–¨î¡ 7kÚ6äo >ÿìCc¿ëdŠñ{T“£è£Ë>¢vÕÛ¹ûV¶Ù ·Ú€h }à<˜M{?ŒQ¥oÉ8ÚxüÅãé–n·P™ èò4„#ìꇣ\5èg0pР$ú@¤þ…ø46i+@ý¢ ¿úÕ 'iFó¢êÇ®~>QM7üIª°·”Q;ݹç>ûÓ³aºIÕûxJûSœe"Vÿër‘ô#îc±–N9ü:¤æ!…åÑyù@fº“ËPC`! ¯B]7á:ºuü­qi?UoDï]òÖô4ùrEú74Yxë›îT¥ŽeÔʼnã4| LVf]sâ5ôÖÀ·¨f¹š"Ä}ðVâþ øDôqô'¯k÷1I´~4¿•–Þ´¦¶‘ eÄÆ«@ÕŸ0 KK=³aѶE4nÞ¸†V§ÜoØeÙ›úŒÆè›5ßDeÒhÃ= W?3•>lÔÞ²3^壿ðß®ûVÎ ˆç|Âwûi·Ó¨ÓGÉ}ÂHUXa UOç laà׿FÅ?U‰8ãà½ÁïQËŠ-ÃÞÅ _R Ÿâ]/mý5À§ô?tdïsŠ'yÒܤ­ÀCnÈžƒÆˆªNüC]¨3~Ì̺¾h°ñù“~àž Æµ9w3Ý6å¶‚j|ZŸž†jÍLP¬}Õ*W£Þz»Zý’@û¨4 íô®Û³MÀšœ5Ôû…ÞôÑœøöB 8r0ŽªóŸ;›Æ»ÁF5î1»¼§–S¿j}{ÁXª—Y/T4¥åx¤!ÒVˆHkŒgá¿næ3ä LúR@–ŒðÁÒèý_ßOycªWaF !Lˆ±ØÈ‡>Æ&Ö>ärò„ù-‚ª·‘#»Ü±λ‹Ÿ÷àB+Æ]A~òh\Âì±ÍŽ¥/ù˜­t¨s˜‘Ö‰÷Æ>_ó9mÞ»Ù‰/¿ ª5 ×ú¿Fåö•!À{S°P R€BZQ ½ŒYÊÈUýÇ®Ìø13Ói˜aµLà¦/-ø1Š1;¡ ¸åË[hþ†ùš’wÿ~îP¦_ɬ£aB?ÃÍ€[ön‰ŠKç¶©E­…‡ á«£Mpû+CphlAÀˆ3ê«Q4ü_ÃioîÞ¨õ!±i¦ôÁ%P×z]åvÂ=\'êÅû‚öÀ0m÷ì£æ¼à„KÉïá§¿vý+åïä “»øÜûVFÆ]Þ}¼Û:ïyú¾çÉ<;»¿&Ç. ˜¶á§±?m®„ìîŽ`£ê×C|d ¶ÕýH7áž—¦núP@>Ãá/<;ÞÅ—¾)mÚµ)Üã-‘¸õ[Ö;KLè[Ш5} WØN[=-jÝ`샺rµÞ{&¦ö[~[å<{ë`9óÞôÁ¢èœgωëРªªÒëƒ^§þ­û“{§¾f0‡`¡@ðê¼Wiå¶•QÛêÄa' £#ëéàÍ.ºé—<Ö»ž>½9À4ÕÐ~+}Þú5]Ýpù4-]Ý” °ñ‚&iusÆ)eö˜½`ãÎd0 7ÀÓRI.pÓ—xŽºQŽgÆ«w¯¦þoö§­»·"¥ÄͼåóÚi?ÃìYýèWlâY8¿Ëùr2 ÌÂís°¬`Ãc˜d½àp›õplÜÃ=?oú™z>Ù“–nX*õGû)›U–;÷1úkggF¿›gÕØi¯ûX ÉÙŸC7}y“ ŽÑ`¥2 ›ïèy‡h/òw1óÞØD za ÀrèÚÁ ìÁK~¼bŠûŒQ8ZYoºTVX&Y>¦ålªÝ” ~6P^t ºP÷›ÙWÈÃô³²Vé¢Ôÿl\Õ¸91nÁötÁ˜ R¢ øä»O¼ÄÒï$TøÜ¢Ý  9ÕnD[uv/˜¯Z³è×€cÚ¬B{Þ½9 _vïó’Àºýë¨ç3=£~†èt~ÿrò_詳Ÿ¢¬}Y¢R—ëxa œåÛ5ßÒãßÏŽò1;’Ù??§ôà2™ñóÒ‰™L 4¬.©ñG|¶œîMÓ2!®7›Ö§‹:Bàáøèaž!fIJäœÛá–ï^Agÿólúl^É0­{^½‡vîÙÅÌ1CºñÁ=À³t§áx–Î=þ\9 ³VgçËî|–kF߆jÛîVÛQá˜\ÙÈí—Sý2iʲ©œ‹`5þþ|¨Ê¢›Zœ@†|@Ê6æ™5ã Ë\/êg!`ć#èÇU?F’ÂÔÛžèh€+,ö€nМÈR€Áݦ[àíGˆ:®†ôéh¸p¿âd÷„ËØèžn¶_€#9ؘ0òJ])‡$õ›4'Gzþ¦­ äæ)0p €á²Ñ¥¾Ͻ ïJ¤þ-Óäß”…_lJzzÉU‚á*0Ò›öLXÏЇ:œO³“óíyM|kÆVºîë¨óß;ÓóŸ>O›v$ö¹àœEs¨ï­}iäc#)· ×ùßl<”Kupf¿±r/=Þ,àÅv_þ>š±vFLŸyô™T¦ ŒÃð¡úgF&\uFIã¥ígW âå=+@O#¬V±Óú:ã¾3hþêù1q©T®ýkð¿è¼ÖçñžÆ…gÚðûþí4ðôáOÆ„S’öäìqvþc›qÄ·–Ü/Jv@4§@ ¤ù Ð7P&ˆÍVÏu…|&ÇÇç®Ü³’î˜pµ¿¾=õy =ñþ4å§)´ú÷Õ”“LJñ³Ù´}-Z½ˆ&~;‘þþòß©ëÈ®tÒÕ'Ñg³>s+=nÒƒ€{êqG=®Ñ…ÆÚ|¢g-ŸxöàdÁÚžàl#S!@Ö³9̳ˆí74P!¸L_3Ý-2ìäa´~÷z:ëž³hÚ/ÑÏ'@!|&øÌùÏÐÐNC5;„!ÜžÜÌ\ºâí+è¾î‹k‹„žåk—óþGPÆ [`†ÐÇêP: @i™–†_{Á;ƒwZÉÀ¨c#»<ür*{É¢´2 ä‰Óh½vvoœ=PkšëZƒ¸Æ9¨:Hh\8v?@F~®î9æÙ¢Oˆ`ÀÌ9³ _­»'¾ZþM]0ÕìçŒ`´:Ûæ ý 0»GyÌî…ÁCÓdž;XøY# Ëœêí_ðO]=•îà¿X¦Oç>4uþTQggäò•¼¬Ò† 3+g¸‚ÚÄUE4šÎE¦­™&×úâÛùzÙõ¨×1½è?_ý‡ú=Üž¹â:¿ëùÁ {îùó=T§rºÿ¿÷SAY:°-(S@ON’f¯œMOzšTo–߉3æ±V…É#B?79[¨ÿ3 I#°ø]w/ÐÃ7®Žw2NÛù=ùܤñö»—wó–†=~7²@í/MY”Aø 0x•Sj„˜f%J‘*K Æ(3pÌš^–ÌMz™|†~VÕ,‚›YÕXögà:ΣLݾqò½ŸÛ‰E£!€ß*Ù”¨TcœæoOëw­×˜ˆî§\@³ø{>¨³1ãÆ–¨¸™© 3C‹eT8`~N“¢º×žr-úó(ÊÌe À‰ÑQ-ËW+¾¢nu£wx7* ¿ßûê½PáhY¶ßõð x) ³Ëzá¦*œ¾¼èüÃüHd!Ú P¶vym‹‚¦¼Ì¦Ôø(&œäç³!Ms]k€Ò8à¡~× —/ ^A’‡xž`„°ÚËÙ/Œ3iŽËäOå_f´â•{F>gÄÌÒz¢VGyë,~]Pæ/›ï0ûÏäÊQ¯ö)ƒËÜs©^åzœÙ”+SŽÆß:žÎ}ø\ÊËÉ£ŒÄ+À5?+ß]Zب#’AlUûpXÃ$çÑÍŽ¦£[M?ÌÿAÚwÛØÛhÍ–5tÏà{B…–0p;˜jU®%—åä3R #[ÐakÎV6fýgÆèþþ÷SóºÍÃ@ð/ê×å¿Ò”YSd³£@E[Íó‚[äÝ÷¯êR<@ÿ g4Þ¸:޹ñäÓh7Ÿ¦›}öô¤…”á47/òyÂ’fÇk:\®ø‘/ÍMÊ5iN¯ýt¡€2GÌÆY†¯ãB´ªÈf­@µ,ʪΚöÃfes˜5p%Ìé™Õœ4Ñ@ƒÀZ @5îÎþv«–¯JêwŠ‹zÇ·=žô€³‰µ D mBÝx»Ùõî?Þ}¸C £yöógiÄ?GÄõ…Ä™íϤq£ìÌlG€Aà%ì…ølÉgtâ½'Ò}ïÞçë§—¨Æ6·¿t;“‚¥4m'ÚjÚëºvÀP  @ à•IO£ƒ\?,¨àœFé¡£>SvC–ÀøxÖêªøuIÀÂøÁü ÃÁB3Y:@>¨ÿ±ÀßÜËî/ó×~ØÜ~ÌíT½|u'Çïe§^FÏŸâûvµ°9P—´Žh.×õýúïC>C<»ÃÙT£j G›ûøêß·x›†<;„öæÄþ\ñ„–'л—¿K5ÊÔ MsÊæÐã_>NGÞr$=þáã´cÏŽ8Z–ÑŒ¦ÉßOæ/Âb²/Ãl¾¡‚šhô ÒJÏûê׳ÀsOV"åµ¥©›¾€<Þ§l?QÛoù _roÔ¤ŸlÆ3õ³jÞ9>—]slpŸ‰õûJìò­zξv«ÂŸÁ Ÿ™<ü&,yÿøØá þÞ°ˆ¿¿Ï€JõaôQ—ýmk´¡m¢ã%d¾ð!j[›»áïÜ äˆ`žñâs7rì%ûEímê 3êáÀ\V×·æ;·îòeÊÓyÇœç̘±<Âøg2óž¼ðSêÿÌùq1ìÃN†M Úåj >h3Úš8Çóç‚ÛéÞ‰÷Ða7´§¿½q -]·ÔÅ¡¸ž±Ÿ¥Ÿ¾ApÏîF³ƒ6Èsà‰òŒe&2]Ò¶?‡yÆA[ðœm“èsGY-cû5.’k×™žþ´"=o¼ýHm¿7_.| :Z0#”6‰Ê˜x¶ÈŸÜó2û™ùeðLžtGEžÕccŸZ„•<ÈËeP¶ÌK l]šqÐõ³ç†Ž7ru3åËV /{‰Êî/'ÇòæËá@¼Ã± Ga3HÈn}Û¸0ºÞk‰w,LTÔå@ _0p{¾Yõ-õ~º7mܱ‘#£›6õÛÐÃ? ²f©WŽ$MAK 2XS²3k½8í%:ú–£éŒ¿ŸA£?Mk69E¯¡0uݦu4òÑ‘tÅCWÐþ „Dpaø\—ìÅ@°h‡hcøy°7„ .œ4ОÂoFÂÏeµ_Ø~‹äjéìâ5J_Ï“Ao^“DóÆ-c‚ ;ÑʇK‹7.aD‚Ñ( kõæ™cã6޹ýíç¢}ÈÌnYG^Ûo*n]­5Ñô JÜiߤ=ÝpÚ ôÀdÞÀZ9é8p]Ìú N¡s¶)«¦„|†xD“#¨}ãö4wõ\gÏÃÐcŒùý:ç™sèÝ‘ïR½jÑ7-¶¬Û’& Ÿ@ç½t­Ú½JöÈž|¡8ó§ƒbY€ùaÍôý˜ïéÆ×n$'µ;‰Ú7mOíšµ£¦u›ÊÒD™¬2„Ë–p6ÃO‹¢O¿ÿ”>ùöÚ—·O–-Ü=X~áÍXÚaÁN÷¸ô‰H˜ ¡Ä(`¿;v%¯®¦E 'žÂ€«ùÔo»×6võÛéiêOo M‰ ] (À|B ^f0?0SÛØ/¹&©kç §é ãâ¶…­éqº×žy-ýç‡ÿÐâ‹eÃ]f3>Ãè°ËßetQpY°emصêV®ëÖÚïè~4wÕ\Ù­_GÈFFÖj,ܾz=׋Þþ.5®ÙØ-ÎÓ¬V3úàʨß?ûÑ’KD 8X`¦ì åXÀ~¸¼Ÿaá–…´` ß”íÎ_À9 ÖþwG6ÚÅÌ^žÏðeæÏK7ºC6bB B€)ß . @@‡)ÜO0’}擟"úOŒát¢tP‡ £®¦9±2ب·ˆ«õ†$( ’GÓŒ6˹ñ1ò…ÔJŒñ2}¼a)ˋҽé&%±(œÈw¿ûéügùÊ`fªb?°~,=`Ý›#€ â-Ó¨R#º°ÍEÔµÁ‰T½Bè&Ä¡' ¥%ëÓ„ÙhçþŽZË‹pÁÆò˨׳½è½ïÑ!µ± õ6ªÑˆ&\Éš€ûˆðDäL°Ì´±\RÀ{& ø Âþ¼Q?½”= ØfˆÀð¹-Ðô»›7vÀäÍÌ_öbð± ØÃ€ýØ‹!BòãbGèâ <)¡úb8ã×q¯H¼))^akººú°Ý0gT¿ë×Úqì—xã¢.à)ÖøMœoü ð€‰¥<<(ÅW%žŒ<'Ë çÍ„‹Ò- ‰ÿ4éÖèdªY¡&ºdÒ¦ûaÝéÄæ]Ýkzqí-® ÎÇ xÌ(ݱ‰k’gÉ?W~5Míû]sÄ5Ա[mƒóþŸ¼ð)šsÏOtù CyS3e.‡=²ÆÎ3êÕ{WÓŸŸù3-Z·È.Ö_7».Mñµ¯y˜s1˜9rB[Ù9ŽLÆ—8„É|j‰/+2àGo¸ÌÀ¦KÊÄ-3Ä…ß K<ò ^-Òx±6@×ÿ¿½š#ô`47 Aqúº°·œÆÁMg“¶€ûD@}<5Þ'„‹öÞ€&%Ofʧ59M{¥/î­çÞêÜ·kzÙBŽ]:ž+fÍì^ÓáúÛQ£ Yü™C S½Ruzèü‡èõ‹^§ŠüxÌ~EUûúœõ²ðËêØ×תR‹Þþu¨é\',ø'ÌÄY 3w¨î!0w¾º€àXýÌRÎ_0BÒìø3°Ù_qXªYÎ-`àöMéV?ð†íþ4;¬~»ŒGãÓÔM_ M  ýÇ¡À‰ Oôµ±Çµ>Žº·îîÜη—gþXOÇ!AÖý¨ðª‡Ð Gò§r šž‡÷¤1CÆPÙü²L.å0íMy›¨Ï }höŠÙ1¡B ?l<M>aħ‹,€1c)ÀݹoŽ^–3 @€³ôÀ%ã·Ãz@“{¾Î0kÿºù0&‚A†€„t„€%@z•êQ³ªÍ|‡|íY×:ŒÌÖ+è¸Æ‹xÍ¿l&O·‹aº¶êJ÷œy·ë±Q!`kþVêûR_únIᙑª€ðÎïP»êí¨Â ð„ ãŽÌØeYÀh ÀáJ°ª€k4nTþzgfþ^æMŒºN(øM%ÌcNe•A]Å£@Ê7Í¢¥x8UœùÍ~ïÙߢÎÁ €Î©Ôë­¦HL¸M‚‹•ÓΣi®‹EVAš– —Oã<Å‚`)¦@‡ZJ»“ÚŸD­j·¢EÛxM<ž-n7ÌÏä{ÌF¹œTÝ—u¹Œ&Ì™@_¯úZ¬¶ƒM†¼…`{Îv:ôùôïKþMÝÚt‹Z–  8÷ùsiÁöXT÷L³ubñJ Œ¥cå“Lê{Á^·}(#Ÿmâ3C9p‰Ópï‡ûb£ JX&,b”°×K{»:oš ÛÏY²k>uF¤°'>ž¦×MCØXé;ê×1šÃ’×vMÇra(^iꦭ¦ôÐþ#P€Œ6ÕÛ”HKÁä/ï~9Ý<îfg–ŽOêØÊŽ{£8$û¤ë¾ÿœû©Û£Ýdã–õ{°Ãÿ{s÷Ò ×Ñkƒ_£Ó;-j]µ«Ô¦÷®|ÎyþZ´£p#a¥Ê•¨CýtDÝ#¨EµÔ¨J#ª_¹¾—\µ\UªV¾ZÜ]¹»(/?väì ­{·Š ²eïZ»k-­ß½žÖíZG¿íúVl_!q*ˆF -^A Z¾hiZOàH ¤¯iM ü^‹4Íc§yãí0ü±ŒÂŒ–/ZžHiÞxo8Z}AZé¢?»–ÕZ–Nt»€þ>îï´oß>ç›z|®¬³€]Ž/êIÒà 3ZA“Lâ ·³R(j{#ääæÐ7†ÐK¼D½:FÿÔ±NÕ:ôþ•ïÓ_Þþ ulÞ‘z¶ïIíê¶£2™ñ?•ËV–A0h\µqÔÖa6·??ÿð¼§À:…qOÞÊÙŸ#‚ÄîÜÝ"HlÞ»™6íÙD¿ïù6îÞH«v®¢5;×К]khã>Ñ0|Õ°¸•‡ÂŹþ žhc—7MÃê*‰4¬®7ÞŽ–OÓ¹ˆ‹dQG¬4Å#MÝøßÀ4m`€v@AÆU¢3©dpÊ®”M=èIïÍyÏY[Çú:´û™û0¯†šÞ!`H—!4qÎDçzc|ËÏù ªçeœ;ÇWŒ½‚žÉ}†úÓ/j“ð‰àØ¡c£æñ+‹HÂEÅ2ü[¯†!RÝ–n]êÚÅ[Ó¢­‹hþæù´oÿ¾¢ÂF8! \\¤Jƒø€)¢@ÊßÖN"IfÞx¼xv«/)\uPÄßxpǬ#Äx‚Þd7o¼ùܧÔR€Ÿ%6–¤é{|_z÷ûwe€òÜë ð‘»`>kv¬¡ìZÉkºÞªfV•Ëpú Žõ•]ü `g?ŸÜsÕ®¢=¹{è¢.*É&ØÚ×n/ÖFË˶.£_6þBó6Î#Ÿ<ë÷Y"|‰À´ Ñp8ÄxÃ!‰iðŽevs¼iVWóF 'xZÆëjâm›@|<<àJ«I¹à!Š0Z¿G©N;Þö”†½®] Ò¼é¶aØeé¦@"Wÿ§%=:õ Š™e=^¿ÀUÁ˜¡Ïß8ŸÚÖj[°!epa—–]hÒ¼I"\ä—̲ͧÌùyÔm{Áä \÷þu´/w í64F¸À®}»hݶuÔ´VSBéh ahU³•Ø>­ûHðÎ.Þ¼˜f­›E³ÖÏ¢×ýHó·ÌçŽùD$0|¯P`7ü`ìvFðÛã]„, EGƒ.ÍŽ ç×8¯›R¥0sÚ ü®…Jvöº º‡MÃHƒA8o>+¬t †7ÞŽ¿ Oé ?»’flËU¤S;…&þUô˜ýã“@^€ð-ßèwn›s}¡EÇC:ÒÄÙ\k°{_\ìÐ%öbÆ›?º™vå좿œö—¨uW._™öîÛKínhGÕ«T§¶ÛR«ú­är ¸­ë·¦*ªD…Q±ô BÁ€vÅíû¶ÓŒßfÐ׿}M߬þ†ænšëFƒâj ¼€7\ §hc—7MÃê*ÌHáHñÞrv>õ‡sí8øã±¨KËi½iꦭæ*»“Ó”ðÚ1xpÀNö’6=ŽèAÏùØ9 W³Å>€/–|Atª?µcÓž6„‡XÐ ytðƒ `>?„ ðÏþA¹ûséÆ3oŒŠn9{õXê}oZ¸|¡3CÖ ¿q­ÆÔºAkG0hÔ†Z7lMjò'ª][s¥…›]>›NkqšX ¼mß6¦¬˜B_®ü’–o_î´Ý+x[—η-A¸ÔP mP0JM? ñP Âi÷ŽÝ‰^æ÷ªëHà•[VÒÌ53騆Gy°J<ؼ~s/B„ Ü=€}øŒ_.!Â`Pl!<ô߇èÊ“¯Œ9‹?úУiìuc©ï½})7qyÇ pðê «éËŸ¾t8âúpF@õÊÕ©MÃ6Ô¦ ZS›Æìg¡i½¦²ãŸs•jƒÍ‡§·8],]¾u9M]9•¾\ñ%M[5vçív÷W- ]Cfœˆ L@(Ö€í@( 0›,q U‹†-¨^v=Ú°oƒ;KÏÈcîÀ³òWg½ê‹=/„ 9Ò—ï À’¶ØÊéÌU$D×츘ÌßÉIÔíðnôúõ¯Ó ‡ÉaFB7k“¡3ðã €‹gÐŒE3Ü8L°$-A«F¼”ÀÂìÚèP*W&ô$­»4¸‡T?„`/îp1íËÛGÓVN£O—~J“—O¦õ{Ö;‚•ÒØhZBð„rÄ(¶ üã{ßÌLg ³.xeýÓÝÂÔoò¤¤ÒSÇ4ɘžDÁʳÃv~·ã´Ò4>\>Óü[Ê)À} Öøñ)^¬–â~\ç‹ |T €úïÎ}—nëv5¨Ú ˆ¨éÕªTsfüÌô1óÏÏcNÌueðÍbù>ÌTñ…€¼’ü~u9´KT˜ÞijŽ;‹^¸ööÌ0axrÊŸÙg rƒÃU£N9òq ŒÝ“¿‡~Zõý´â'€ Òp@³ºÍdùàÜÏ¥~'õ£²eJçÆÃòeÊÓ©-Nû0=L³×ΦI‹'фŜ¥^aÀl?g=`FŸW8¼i&¬ãŸ[$B>y®n&öÄ“ó|o]Z®ÇöK’“QÇa–J:úÑSÊ)Á&0éE|— sT+Vóƒ9[êy0Hvóä7O&‚¨¡™™©ªÿ…ƒñ:ã¢0mQWót‡Þàðz1cež<¹üapî…Azk Þ WÃ5÷dTá»ÔÏwàáL¾ (Wsy|¹°ló2úxöÇtÅSWÐñ9ž®æ=¥ÜàïÔ ÝÖõ6úþÒïé‹_Ð_:þ…šWjNÄ«%ö’ŒAx¶-åíKKô´¿§%òá‘>(•ÌÂ71ˆ (z È!1)¨¶cKÞ¤‡5yhT=oÁ¿fÿ‹m,<~·8èìÞÃkÒ`þŒ_™?ÂjXFU! eÍ–+î¡õ¥Æ?.0¼çpº¾÷õÎ,„¹,(ƒ¯üÕK‚2ª²ß(Ö à7‚äSÁB.â ‡nZH'ßz2½ÿíûáP(µq‡×;\„—ΠÉ'ӰÆQ²u …Ý›a?ÓJm£Ä8R.` ñú³íäá\W©pé ĹjÇÊ„HäA¹ÐÊANœSŸ sXóÜ5yÕ`C ÖèÙÉÍÏ¥&Þ@ùà Å3«6¬ eüÊ`àªÕgÉQ˜¹ÖªX+¤2\ ´píBº{ÌÝ!ñáðwêlÿÂ÷–G¨"7š[eö¯ÚÛUA@]MceveŸ¿˜ný÷­”·RSz™Žõ;Ò½Ý寧‡ýLoóõmÙ—Êç•'⃠]ÍúA´g¥Ï,p¾æ¥º„7aËõƒ—‰pí@NùoÊ€’ja ()Êp‹C\N“ S§zªQ¹F¡ÀfÊ<+Ç·çÏû|±QY¸Ê¨Ë# † ™ëÃn¥²•4Öu‡œ2„}÷QºûõèB¾,xvè³ÔõЮÀ6Ë ø ª}Ñ @Õϳz\,ªñcY@™¾­!€Öav!<;õYêõP/Z·55ÏÊ%†OìoèÞ¼;=öó4÷ʹôÈ)P‡êäsMhƒTpÔ«ÏÑ'0éMôD%iD1UOj\B.^ †“2‹úÔ¦²Þ ®Ô=ãZ¿‹wp§Èà38žæ;kôf/Â0Ø8þ/ï¦/~Q,lfÌåõ{€ÖŽé]A:§•Í,ºÉ®[»n²ïS;æ@IDAT‘·¦;_¹3*.صÿö5oÓQ:9Ì Kh®þÍä¯+p,oîÏà‰o& 8\‘ÃX2€P –ò€e¶ÔeáÛß¾¥“î9‰¾žÿuTœJ{"θ¸ãÅôùÏiÊàÿÒÅm‡PåÄpHTN> l±tÄóƒ«6ÒóLi¼v/ƒ_²ué«6|ã7ý5®qAò¢ãÇx%œ¦?i+Øô×çÀ]Ü}.šËÅs‹•ÇÏt»Ÿø 7€•Úç‹Þ+·­´u‰ú›ÔiÂ;ã¹ýfËUî8Åoøþ¬|:~(Í[;/!< šœôÝ$æªN1ÞðOE,'yi/ ¼·ò 9uÃÊ Q;_.à³¾·FŒ£æÙÍ)ŸO9̇`ƒ6j}ü©c¾a⯠oàK?ˆ÷ ˆëj ˜,ˆ…@ÀZb ƒ— €Ý°õ~ª7=1ñ ¦jHoÓ¾ÞaôÈÒÿFüBü0µÉnKùø¬ˆ|>ÐÉ¥%7Uè WýÜt‰K±«/©ºmøð‹ênVÊáç 2ü6\Æ®6­I? ,ß¶þðŸÿð9­X·BÀ@ÿ–îur¸¿á$>y0e•ad¸ü¨ñ£èŽ×îpË„óÔ®Z›ÞùÕʪE{ùÍfA@>u4mU|p/|9À€ìà/Ô…` › !ÀB;€/DKà,!`ƒ`~Å|ºëã»hÀShóÎÍáÐI»¸*åªÐ¥.¥i—M£wû¾Kg49ƒ2rùÁ± ËЬØ}ý60 àUL ˆY n1ð ’K/pmlªLÃZ ‹0·Ï‚Q3σ\»g-ýâÙ4má´˜¨åæåÒßžû›Ãä•éó/»ý£8¬'œiT«Öé43íÇ?xœnãöpYݸu[Ð[ÃÞ¢ y(ëøpçÏbåÓG¨°mƒ¶*^poá@„WCàØC;yÉdêò.ôÍ‚olÈiï?©ùIôï~ÿ¦—Ï KÚ]B *ÈòŠ|>ªËFJN¸êOû– ˆF¼&ékÐIí™ülÝû&ìêyì°úãqõ…çÆS>Èã<§? ¸Ÿ,Ú¼ˆpel*LÝêuM€<›“eìÇÌÎÌî L #ä™ñ¦ÜMÔgtº}üí´kï®°èAx¸á©hÞòy.³×ÛÿÀTÁd¢ü¹Z<[®ï‚6P›Z¼'!‚¹ø´‹fÖ€ùäÇOÒíÿŽ.Ýâh}áh">Z¡`7 { µ* ¸šàî=E­ˆg#B ×-í€Ö€— 2˳6› ٮݷ–z=Þ‹šð4æ”:8~›×hNœùý:òWºë„»¨j~UѮȲ_€‰„n«ýG]?Þ]ÀJŽ>ÛDáxË! ‘\;Më²a¨ŸA¤³Io )à~PSñ,Ù²$%m¬]/ÈáÉ= Ç X^-aãÏ|q8γ_?KíomOwŽ»“f,˜A[vl‘ë|¿ÿõ{:ï¶óhôGÌpe˨Jßåƒa‚yBÇ.CcFvIOöx’*–áxLÏczR½õ¤¬0`†ýÔä§èÖ7oP‰>ûȳéΞw:Z,Èš67š™Š+ð#+æH¨*ºÀ]µh—jxŸ¾,ȯ”O|òõz¸­Ú¸*Ä´¯R¾ ]}üÕ´èÿÑÇ|L=÷ ÌfÖò€œ/¡ô„«6m[ î¥^ñ”wPJ¶VíŒê*<Æ  ƒ“ޗߣŒÆiyËC'¦0³-‘‹:@ìtÛ¯U„‹Ó´À-½0Ïíëÿu6ìWjT©QدÁüu¦<´†!@g>Ûvo£'¿|’žø˜7¿AµÎLU¯ cV¬KÂÁ$  Z—™r±³šŸEïò÷˜M*“U†.ì~!z”óî/†ûì—ÏRVVÝ3àžˆ0®ëy­Ú´Š^ýáÕÂ÷–ë–ã¾Ë0μ<áâŠIàrbŒ6£åQ˜ÿÅbjÄþoV}C'Þ}"=yÑ“tî±þ\±ìT\:~³2³è¸&ÇјóÇÈUÎS–M¡|(—mÏÝN8–YÈ¢´}”vð‡3šîM ïÓ°º ÃGò#¯¦aƒëõëL_Ó¹€£FÓfL åJ©›rÀO:„cÎx‰Ýx<¬$ + œpiv\$¿‚Òt¸¶ß›Ž°¦kZà–r ðà8{Ýlê×®_‰#š]%["='ƒ’ LÖ`æX€Ïè4μîz>fôl…ò•ÂbئϳcªÀ1üÉì¶Ç¨¼€Ç¦vÅÚ4ê”Qüæ™rùgÈiCè±÷sp£E|ø@Äâ8#`̈1Ô®F;Ù €µkœ/çãëÞô»xfvÈc\aúÜ6z ñ0éACãf£Î·w¦)¿L‘bã–9ˆ®9þÊÎȦÿ­ømÞºÙýCïœpé/ÑÊFŠ÷ÂÐàO4 8áÊ(|oº†íô4õ§¯àx˜–ñJoV’¯^[bôp,ý(À¼rΆ9´7oo‰ãŽÛ01€Ù«íw`œtý^>S&‡ïã± ‡äà¸\sÞ¾„! BÖɱ ÀûtÖ\³BMÜn°[E¼žWn|…Žkuœ³yï+ƒ”Óþ§‡&?D|ÌE0˜9–j•©U¸'_ðæ5Y·ñŒNd˜_Ô ú°&AhÄZ ¡‘ž:Èt€@ôÛ¾ßèœ'ΡþuíܳÓ)wþÖ«Z;ç1šrÅêR¿‹ó¦Y"’}r8“i8è/­‹C«xa{óyÉÖ£|ªøJ¢h'’?}<œx,¨ÁùBÄ8Ê%š?.\â¨7€çs-Í´4}.'/‡f®™‰P‰š å Ÿgš0ós7†£gQõvÈL×l~S!À½aBoŠ“oç!0毳ÿÓ9-ìÑ¿@'š©\¡2MúÇ$t ¹ÉPf”\@4\Ï}ŸÞGO|úDDÍê4£±ÃÇRÙܲs2C„C¸Þ)Ô„ü0ÌFG]áÇœÀè¯GÓ±·KŸÿô¹Sæ ým× ½h,]Òá÷ë ýò"j? ×÷t\$Í‚ÆÛÏPqÕ4 {]»LúÓz@¢ôV‰‡±¨EÄLªâ¹ 1=(€.ÆöëU_S—¦]Jçreù´˜P“úáÚ8!Ž]Ø•µL3ëÕõWøE>¨ù¡C4kõZ Oiz œb¨ó_ñòþ!2ëWÜtyó”Ë*G#Oþ±‡K÷œ®{á¤Ay­ ÎÒ.àÌÿ.ܰP¬Hä…Qqyìs K–ýmïotÞçÑÇ^@÷º—êTãÛùÒÜìÍÙKóVΣ9ËæÐÌe3iÖÊY´`ÓùrK"vßQz‹ëC»èøç}Wbµ'Ñü±à ôôð "Y}ù5ÝY;v‹*SãP|OBaDÍ«“xÓc…£V$–* ˜gùÕò¯è¯]þZò¨ißk[Ì`ìY 0ѼÏ ““ “óÊ{3ÉuÂî¯fàxÍ«¸«Ýb zz´ïAc†Ž!rY¨1š¸×û?YxüÀ"Pñ ÛëW¾NÝî=‰–íXÆøñÆE“ ïžËÔ÷"bD ¡ 3}‰ `eù„ãÏö¿ÿLç>rukÓîx7Õê(M™Ù°yÍ]6—~]þ+Í[:æ-›G¿®˜GÛvnsð¼ù.è ¯aþh ß0ìŒìf¨†t|ò‰20 ‡×J‚ù1ô²£Äï/6Eâ=âM×|á\{Ý4ã yg8Ñàn>öÚy<¨¥[8¥&.Õy囇€çâôKíá #UŸaøñÇFjƒ ßÎcÇÛµh|,e4]>ð—b ˜îÙtâ¢I%*Èf,‹è+òzÄÛi¢¿:ä¢Þ]¹»¨rÙÊEŠ!à•‹_¡ _¾Ç]yÁØîç«G¾9’Ê—-O}ŽîS:¾ wõÛÔý!ç;ö|Ìfa1sç?Ù÷Fš$Ú^ä×rRÖÑóg˜€ <1š²ÅFÉ©K¿¢“ÿ~2ukÝ®ìy%uìYÎ>Î’¬Ùºc+-^µ˜–ü¶„­ZD‹W³ã·=Ú.mάÊ?p…iðkX÷K€ñÃxÓl„”Ï?áb(ÒÙʼ‹½!&Þ>RÈ $Q4 ´èQn]Æ£auQÚöG‚fó‘ò”æø” ¾ODzxò’ëS³]͇Êíxt^ #-^“h™Hù½ñ±Âñâä+0Ïó³%ŸÉ™ò˜©–„Ù±›¯ßÕ¾£.*‚ßkýD€ùó¦Ý›¨r5ÿ wVdzèéOÓUo^å0Um> Ã^FåË”—<Þ¦´nØš^¹ìêÿ|Q× ÃãLBÖªA/ãò‹6euYÄÑ00f˜ˆÓ}* L]:•¦>>•šTkB½éM]Úw¡CJõjÖ£Ê+‹@ƒªÀÔ÷çï—#™á߸u#ý¾õwZ»q-­ß¼žV®[I+7°]¿’¶î,¼l)„É3X³—¶¡}ðbφaò!aÄœ%~eü*€îýÌüE@<à‹c<  ŒºN(ô×›o8Þ|Z›æÇE;Ÿ†ÕÌXéZoºé+„!¶Hcü°D“^’Q1é.9&ÒÖ?r^ Ð÷n¤Vÿ@›v.RäíÇí-ƘñXB¶_Ó}v±C¼iµ¦>C嫃» ¦•WÒƒŸ>è¼Ï`:l±IðâW.–{Ö£H½§q:Ý|æÍôà'2>07hìã‚ñº‡>(£eÙ/Âot-ð43gÔWP–-³¼j÷*zæ³g虉Ï8Ÿ=ÚgžZö†ÅÑr… ƒÃ0yÄÁ‹ö"Îø5^9âGI®Èk3~4`Â<Èoûµ>Ž.5t LÜÀ#L_c¿4êg×U‰jgÐ4´TýÅtv1Ë&[wP>ùç—rš·kâ‰Æç¿#·úa`?ýrÖšYþ7È@¼¥÷-Ô»}oçŽlDƒa”›‘Kƒÿ9˜¾šÿ•çù½åœ[茶g8ß­ã|½B8ÓM”nZÊ1Ý!\ƒãÇ®y˜„ƒ“pÀÎW0‡éÉŠ¸qéâb‡=,ÊIJš°Ù¯·†Ô…3Øêé…nÝU9g:°+‡=™CŸÄÏ=i>·œÁÑ= íò%ÚÐ"Qú%“_×ã†7¬ñpÕÀ|jì<ìáZ.œ‹¼h¬¦)¼4vÓ[ˆBxÕDÉ$(Y €)Ãò[öéâOK¬®œœ…ËuÁÁúnŠÌ´ÓJ¬&´ãÅ¡/Rû:íC…f´{ùï‚/ —þX¤~”=l4µ¨ÖÂ9$ˆ9.Še(•ì@®d6ÏXI²…äå$E0Y>e XNZĉ‹†ñª  .˜»ZðA®Ê&ÏBº{p“2ölÃä³9[© ~OÝÊøCp0õÊ¡O¡ÄÙÀ} ˰ªaPê+-4\ZÜDžq"yKKû’Ä#}<,}`áüÉÎÏ»Ÿ°wÅ;pgyÒ‡KZ¼y1-Ú¸(É×5|qù ´S£~Û-!ÚþðÛ´aç­Ùw·RùJôÚ•¯QEþ“蔳&`Wþ.êûl_š»zn‘z±)pÌUc¨b—Ûc´zÛaqî ˆD?­ÙЇ0G˜1€Ìö #Wæ-LØš‰Ë,ŒZ-4ê7®0}sT³¤Y…=»WÆ.u¡^¸÷¡ `ôF›YžÃªy®leÿÖü?«þ]ëeúÚv¸‘è£ñúÜ4ËÕüêÆÊ+]q OÓlÈ+¿“+mÓWH€ä¢¶A~<àxL˜|ÑÖì]øñÀòüñ(€ÙÛ~ý DÚ¾{ïîB¸öLLýêæòÇÇpó òè_Þñ^(ØÜ÷Ø ÇœÙ<ÎüÇû‰61“Ý–·z?Ù›–¬_R¤t»&í蹋Ÿs. Ò¥ÃüC4„aÞ÷"ÀbE(áò¨ !@4|H£Ë`¡€z^gþª’Ç쌜gï^‹Y¼0vä1³zÉ«e!@À0ÅZZW“À ßÕÛ3{0{ÆO6øõ¾Ìî ã—½à¦M⯖½Å6~Ð<žÊ‹SOqÊăK)Ì“¾€~çÄ®ó2óS³â‰´0.??Ÿ“Yœ ÉS˜-^ÊEqcÂä'N%6¾:½øà3\o\.-ÝøŽ/!F™›Ç§ç¡si?d?Æh7¬ñ%ár]¯ÍzUvè£Ê’2ƒº¢óŽ<ϸh$ ›r6ÒŸŸø3­Þ´ªHõçwì6’Ëñû¿ÏØ\Xp.²è–,}œÜ¡;üüÌåSDÖVoÌaÛŠ,'•{F%ó‡™ „Lݤ!]—PNÊò¶å™|¦Ìì9u©Å Ž\¿Xh&Ô2^øî_Îïü9¶Áë&K›å µ«žç¡xÄ(Ÿ\_çfƒ5°ÆX êB½Æq\å3HBš±N‰´ýM¥rúfÊòùçú|Tý®ËÈõ›Zæ!@¬ÍüÑÒÃ¥y˘êÅ —?ˆ óü˜Z]˜I9ßKgÐ|Þ1?oý<»;øâß¹{§Ô¡õÀum Ó\xñ–%4q~ÉmrT"=2äªY¾¦ì`ŃŒÁ2KåëšÝkXèEë·­×ì®{÷€»éئÇQ>kò±!·Lä³&€Œã w6ßú›ÒpáÇ(‹]ô¼v^f,3oƒY‹:ž3°ŸØÑ cwòK^ä‡e¦_h¹.™Ñsê`ºˆåz ¿ßwðQ¼Ü~ÂY\?ð.ŽM‚†\˜bÕË%“)gªv…%@M,âÔhº§i鿦RÚ`¶î‡eÅWR´f,Bþl`vŠÎ/Ú‡p A\@›<À¢Ëþçÿ±c}ñãûøˆõ–´á:ýêÑ×à²;Ï»ÓÙÕÏëù2ƒGÛ0‹e†‡SÏ}ê\Ú¼ssH‹qéЫ#^¥šåjb÷ ³¡Jþ² Xׇ@í•þpùùëÒ€¬¯ ƒæxht>œËmCº¨ëÁà1³‡šÞ¶Ø˜gÖëås= °¦^Wm°ZöT& Ž\œq¼L™2¾ð²âÔí×sCI‰ñ»‘r¨Š-Š%ñðA€D˜~JTrpQÀ Ä~ ƒ†ŸÃ¥.!uÙÆ¶Ó’õ›vý¼þgzkö[ÉB‹Y~È)C¨M6…L\eÌçmšGýžíGÛ÷lÕ¸Vc=t4eäð,Zý4BT¿:~¨R:Éhäµy³2n¸°^¦®ñ`îšÚ.+ Þfòê÷Ö•$ú¥¦¸÷ÙxÃ^D½éÞ°7¿7ìÍï —‘³’½…’ {jH V\…S&06Ò8¿—ø.^f[—ÇQnšú‘7° RÙÐ÷ØðNË·.§WýtÍÉQ¼ßýû¹ãÛFÛ†8õ—„kêD»ðï÷Ò®}»lL|÷ã¦=Ü(3yQçsÃøÝ—Ý÷`<[ž¹v& |n íα6G2&§v8•n8ó÷Ó@ðe€_çÄCãpñ2ìHápe5.žºƒ<Ñߦ¥h„@'ÛU>cÓÐɕֿ~ J²pD‰–.Ô¸ÌÌȨël>*ãf¬V¯Àü)€»í›sÞô•»öXL×f\ c‰TÁ3Òµ;×Ò]“î*ñêÎ=þ\j^£¹³_È~v™¶2ƒf!àëU_ÓE/^D9y挃խçÝJ'z’« ^ (ÐÏ1Èï©C‡õ륿7ì^IÂ-ÇûÐü4ÌO’Ä(ql"sÑÄaE-ÁmÓ×+j¾xËe1ñ•\á\Žz"­¬«6ôÀ.É:K¢Ì’éaéŠÎÍÌrüÜñ´+ÇbÚˆOÂìÙ·Çéã`Äè¶Ñþ‰8õûí6×5è—|™¾^ò5bJÌ`ùoøÃ…‰.B„%Ú< Fg!àóÅŸÓЗ‡ÊûŠ Ê¾<üeªS¡IYÖ"È!AxS  'ÜŒð[b4ˆ9vêCôëÃrÇr.òŒ5ÞãB凑v;€Ð²H&ZZ¤21ãKZ(¤CZ…ìZl¿$9ú€2A  @ª)æ æÄ3ò¹;é½ÿ½ç">Œºâµ’X?¨‚­hx4)È* o ­» /¬)Zip÷ÁTÿ °Ðð#ãðÁÚºÙ87aÞºúõ«Cö]Ô«^^ú Èøšò*Da%üÁÓ3î†4Ñ›+R8Î@,˜ÞôX`­üÒ'4?âMšLB5Þ—{’laàð üÂ!kÇðwø²PiI;PŠ/ºBYþ6’ÑšÕå|"˜/"‹7Þ¯6Ä[_ï ¢€aPoÌ~÷Fa ëðøcß*ˆ2^Ö¬Ú¹ŠFŒÂtã‘HžêUªÓÙΖÙ?˜7Ôø¢ÊçwÞÝio„€7g½I·þçÖð=ïA9ý/îR€ qíRJÓÕõ³r¦úÕ SOùrüù†Fù »ªÇR¨Qj×,ɹ~ 1±`Þø6(T,Ë'iØ&©¼ñÁ•è6ˆXþXå døi¼ë·îïg%¬ÔRŒ’-ŽÐ¿~¾/uïܳÓc`K?1~• |©(®Oú+v§³ftÒ¢Iôòô—£•H:­_×~ŽúŸ—ùu/›™G6] À±·ÏMŽûä±:ï:ÿ.ÚðÜZxßBšþÓéõ¯Ó'ßI}Ûô¥Ù- ?İmI j„†¯L¯õæñwH‰€Ü0Ú¦«íF ÍgÜJåø”&Œò"ÞÌ+<2HÅ"F¶ø’ýYĈ£®¼¼¼ÜråøðŸö9@X ‡±r’EaØM~xÑ îh~ƒaË ¥ƒò…1ñâV°—nÃÔxÓ0PÑ8EËNÓ¸ÀM? à~úç¿}žž<÷ɤ‘Ç€ô Ó·µHßÑþ§nÒµE`à£]ò‰ Ó–M£¡]‡F(|ôéÇœN•³*Ë~ŠÌœLÊ/›O™e2 ¯ýÅûޏ±½ëã»(»B6 =ÙÁ)“ÀÛ²s ûv è2€ktXRwm¤«fÐôåÓé‹%_Т-‹DxƒPUÈ‚ðÃu¶ªÕŠÎjuunÔ™ÚÔnC5*Ô *å«ÐŽ};h펵´xÓbšùÛLš¾b:ÍZ;ËyŽöxX 0m?¥ŀƑŒ7-BXû­[8™>œÿ!}»ò[ÊÏÀøƒ6ã‡3¨åºŽnx4ÝÞí:©ÙIR÷§z…êû§:¢^m{IòšíkèŸß¡Wg¾"Ÿ‹JÂÁW`¨¯4óì#¢âMËü0LÞz-â瀖Õw Æ;CoaX  'V®À<¨Èøì$'ò žÃ<’©£µ˜`‘j|Ò.^“’0h€ZÀ/ÈÍÍu?*¬R¡ŠK­HÝ|~(Þ£i!.ðüBâ,ĉ÷ÿ›HÙ ¯?Ï mèÈ7Ž‡Ý“¿—^™ñJүöÖA@€mÛböç„i‰:Q»Äá0ã]¶}9 ~}pÈ.ü¤ëpj§Óx÷>×+ûØ•oúÙed„Lgà"Gâòž€ýe÷Ó°7†ÑÔùS]H=ìI×÷¼&þ0‰>=ÚÝÖŽîúð.Z¶q™›ž5[ÐðÎWÒG—|Ló®û•9ãQêÜàx©G çóWÕËÕ —Ïy…&ù,"ójf7¤kO¼–f^;‹^ï÷ý©F;ޤȓ&n`çËí¦¦m\NÚˆvÂÿG´‰´ÝÎ ¿¶žG»´D´V¿ÆW­XÞ¤ Ì#qpªÑê4ìÄúü[R€¦4dïÞ½²P©µ3Ç_µß&„( ÃÏ*µ’†xÍç“«ª!¿áðüVœ¦¦ÿ© ùÕ_¥¼|æZI˜={E¶.„€~ c\ïÒX‰ÑÀªSgà_-ÿŠ0ë.)ÓµCW9@6ï™Í€ðËç|ü¾£ír=/4æ  œ¬êÿbúqiáLwô½ƒúÙG Z³n ú`qÇÔë©^ôöoÓ¾<þÞÐ2õªÖ£¡Ç¥I—O¢YWÏ¢›N¸‰º5êFS.›B}þÔÇÊ™¸K½Ú÷¢¯¯úšFŸ7šê—¯/Ÿ,âsEtôsEŒgxÆêú4žùÚ?¼¸Å Gkƒ·¬æUk8œ‹<Þx…‡4õ«‹8ìý°Ëhš‰«V¡r%m”'îÙ³g‡†RbJB‹üÎ¼ØÆ¦È©eÅlfJ5+©2±RAî€%C™)­ÙÁjß9É]§»'‡Àƒ…ñºNlê~¹~Q‹óè¦ûòŒ—éù)Ï—Hým›µ¥ÚUk;_€ñ‹ÀüeðF­ÀÇçò²„l äsõ÷dì¡ó_8Ÿæýæ\Î|ÿuí¿¨g‡žÎõÁ|>@>ß8åSèò^N­nnE}û¯4wÍÜ"íh^«9Ývêm4áÒ Ô´zÓ"éÅNý:ö£™×Ϥk;_K™¹LP¬c©ƒ…Y³S‚9Pã[ØÑÞA)m~‹Ù†:UêøÒDå‰;vìÀ%á° çKÝ~ 6’ê‡+þÍ›7oÆÚØd±¯]©¶#µá°­-µÙñð ÞøpaÀ ï‰s_BO¼Î@FÄ|Þr1Âù<ÅȤÇ÷ì(¸/ÊÌœç#_<’”š|×î]… @ájAŸW*\­«-Fž}ßúá­4ñ§’¹1ð˜VÇ8ŒŸ5Ê å=‡0€sþÑnv\¡„…&›r6ÑyÏœG«7¯æ X¹È¤·nx‹Îï|¾3N€Ñ⌞yoÙº…žŸü¡•[ˆ–‡‰F§bLÓñJÝT<ë’®#‘¶Øy™$òÌ5aõÛ8#^ÓÔoúŠö™8vûkVâË¥|0Ê·nݪ·X)6€¿Û¯qI¹~6RЏºŠ\ÁªU«Ö"Àë—” \4ãÝ’טåhù I#PÜrq€²ì`¦/oÛ%[—Ðø9ãMdâÎöÝÖÅ7 ®íOlñKh½¦}`¶ùYù4lÌ0š»znñáF(yT›£œžy÷4?¬õ]7ôåhpF[\#|öãgÓNg…R„„—¯~™†Ÿ6Üœ¼K|?.ù‘®yíjù-éê×®.rñP4“Ž>¶ù±4ý†é4¨Ã ç>s’œ ‚jñ޾I×€Ò6Br¼ÑKÅ$/‘¼D¤>-¯.òxü.^žò¬—i¾X®òDæ‘ë8¯ ÷izãc+Ý@+²D®ýþûï—"2'‡ÅiLãj:^NHù®Õݨµ›@^b{Pp1sò À2¶sÇä•n× FJÓ?,=˜ :+}äËGŠ}îö–€~ªÆÓÇSNgÆCÛü޼Ôï¹~ôûößC_Üv‡ðf9¨Ä±6ŽY?üöùþJÔÆ‚€‹ &XX¶uM˜5A„hvïÝM£.E·ö¹ÕÁ ªF@íËÙG%õ•ƒ©1ÄÁ·çÏ~ž^ðUʯäh0¤šew¦‹6GïRÞô×õ»- ª‡FÂ#”äzpŒ.¶Å»¨Ö¦hÄ4s¿`œVm_EU*U¡‘¯¼p_ÀÒuKiÄ™#hôðÑ|CŽ6û:4ëhÄ´ªßŠ>¿ásºü˜Ë©`oæb#Y€ Zg›ûa箳¤á+]àÂ(à×8/4ãqµFÆdxc”¥6M÷£jᇤÔ(‚^W'«:x»2ÓÚ'-€» Ckób°'Mçõ’i)0¨Ó6úÐí¸H~QWz ‡ éã#ÂA2ü&®Ýµ–žþïÓ µFÕ‡!…F]'”ú_­ÌŸÏ°wáÿy<Ýóþ=¾àT¶LYjÙ°¥;ˆ‹@tvCÞ?Å .ãuáÑÒŒfÈ¡.ÝÚt£·g¾M·¿}»lÌÊÊ¢%ë–È)o^ó&¹ÇcÔ„Vƒmnêo ¡îDyì‚Çè_ÿ‹²3²Cµº/@‡uC Ø€ûl¢áæMó†‹ÓÀÇŽ·ýZ‡)S£J‚_¡iy«¼ðF@^iüŠºZÚ`¡Áâ»èÊ~!EV]·A|€,VB&˜¬­›]·èCôbâmIGÇ“?UŸj9uQÎö{á„ 'š?Œ îG0#ÃPžüêIZ³uMÜ4a@€c38ŠÆÛq©ðk½ìÚ3nlÀõù(9†×4Z4äÝñx—1ëÓ·™ÞKûÝ48 ?n8=sÎ3Ô¦NzøÜ‡éÄCO¤ÌÌLzjòS4êÃQÔ¬N3únÁw´â÷„Â޻î=9JX`?³ï—ïúIÃèsTšzÓTj_«½sͱù"†´ýê&S£0’©?ZYÅÍv½~ +p(5š¦.âm¿ 7¨Ö iþ…þj”âÄg€7¢&X—gZqìãÅFã‹åú%hå6rÚuó·mÛ¶ùÈCÍŸ”Û¨z£ÂòZKaLQŸªe#¥ÛyÃùµ|¸´ . @, €9-À®ý»è¯ïþ5V 7]g.ãwS,axVLê½ÀG]{§rf{Õ›WÑ÷‹“g¢Mê5q?„ Ÿ*Øï¦õ~ßôxºïôû\:T(SAÖu‡v*qw½}›>Ž4ˆî{—ì èÒ¦ MºqÉ÷ßÖ˜ïǸ0´§EÝôùŸÓy‡ú•6Eª@$mš”Ò­¥ŠXao^;ÍëO$¯]Ö[ÎF^;~+ܸ&oB÷Á(/äOÁSÆøu¿%ºÚuŸ¿aÆßPqXµ¥b”€Û¸zcG 3ëû¢Q€ß¶X “Ú°; Ã…Ñ|ÀZ­Çë#ÌJ¼å|§ìt7puéÀ*ìƒJ íwpñ6²ýpÞ‡ôñÏ#&¦KŒqB hÚRŠŸ-ð¦ÀÜÌ\øÂ@Zº~iê‰Öjè¼³¬(²Ðóžfò9Ìœþee@íjì÷ õøSqåsWÒäÙ“éŽþwЀ‡Ц›¨CÓ4ùÆÉÔ4»©hÆÿ8ž¾]òm(ªT¾½:ôUºïÏ÷QÖ¾,GÀÞ¿¾-ýîO‰ÀŒ–7ZZqpÆsL®ñ7©É§Fy¡áaj ©][áC͈d!õ«‹ÆÀ ,й_ýu1"üú°yæÑèਅkn`eŒæÓpˆ«­ ç†d ’ 3FÑ0OÂ,ùúw®§Í»ô\ÈpcjÀpKƒQ<ÐNì@;ù3.&Ž÷´÷ŸzÓ Žpò{~q Ðë#_§Cë*ãÔ…^(Œ¿ïñ}©ïƒ}Ç–õZÒä›&SÛÚm)Ÿ/ùÆÈ”àA7bðšÓ¯¡ WM Zeø¢)þLP42ŸHº,¥­q0"°Jˆ:îjÑð‹–†òaÒ‹Ôiçß„Cx…âb¹-k·´BÅ÷*/4¼<¼R±² ;I×<ůœK&+„«ÜF pñÉ'Ÿ,Bmt¸Â‰ÄRó*›YÖYûC­nMìWrY®hŒ:LTbVšKr `ÇÇ€’×.Çþ’šýG«3H󌒙ãºÝëèê1W#&ªÁšµ´“»A´4¶*žXò0B¾ ˜·q]ôüEÅ>±vuëdP™np]:ú¨‹ºÙá‘“ˆ&»R6¿yÕð !{âãüÊ N´´xût,Þt‹`à…ïÍÇéÓËd•¡µ[øò4•Þ¨ fX5ˆ/ã§`#© iÐîÝ»sxÓC®0b¬Õù`jgó‹/µ8U9ÒTkÅK&„-€ë„ øHaÔV¼§¸~>I<¤.…ƒúÔ¸æ9ùLû´¥+_ ¾ˆ««¡þxÞG4zêhŽˆlÜM€('FiʉÓp)q¹ò|ÐFŒ>YìòR@kþ»ôKºqÌ ÒŠDDÀ˜b¬#à[aÓǪUȦ“9)&ø– ZÒ3#žáùXmÜö;õ»¿Ý=ènúaÑ÷ÔrŽ®þè†è”Ö'Ó׿N§3ï;“–oXv*34ªÙˆ>½éS:³õ™,ðXÇ÷6ºûÌóñØøý~#ÂVJÄYoD8\Þ›¦auÝ6¡Î0mư¬ñØ/!Æ+<i€ÅÿuªÕ1éÉ9ÊÁÁ°€åZÄj˜ƒbï«ñKPÄquµ‹ß¾};ÐWu™dsU㵿Hµ…‹WLBÒ‰R±«°ñÒ¼qº"Pę׎ùƒ}üŠA·RYý ma£Kølî–wo¡ïç$„ù]¸b¡kÊJ@ý¥•6@RÛj-@ðò×/Ó‹Ÿ¿è´)ßìÊÙLqàÚšC‹›He³XâˆÃôíÚ—úuá{>¼ïí{éÒ—Ñ´yÓhàcioî^9§ÿëÆÓ9Ρ9KfS—›O g|ôÔeÁ½õc¯KWŸtµ« (À]¸=‘Ç<®~öjÚº»•“•™E÷x€žø4eå–‘=ù|z`ï È—‰¡£+tƒ[ šÇQ޳ˆ É­l´4†äÂ)N>æLÒ?G˳GaÂ#~Ñ´V3ù$•žÂ'í&yüIÖZÜ/¤1$×Û ó…K‘¿{„“´i]·µ»ëß­5)&ðâaÊÅCåMSX¨.Œºðjùn žñNcç³íø0ÅܬÞ|A8ôY¦=̃ÕϱQnã¾Ôçé>´n+î 5SfO1ª~Žãgëî°³–6:(nгuPP~™|ºìåËhîªø/ªR¹J\Ͻu­ÖZs\.6ÞÔï&w–å«W¯OTê{]ÅÄÆÌ‡Ú~ €f#h# ?%ÊþéÓ§ÏaW6ÆËX£å;¬þa ¸L6 6"xÚ×$ªF‘Dù h)¤˜"¿™zz–paÍ©œJ‹×.AxÖ¢Yηõx“ 3uÝœ¥8 íå¯ÐV|°#õ¦?mt†1‘Ç%>®ñŽ>:p†&Õ›¸ÙâõŒ8gÕ­Z×Q—3¬_WÿêlŸæ*?šó]úÂ¥²yïâ=ƒî¡ï줕o¬¤×oyVnXI=®ëAo|òÆ?5PÛÛ³cOúàÿ> j™Õ O„ êq›éi!?]ó"îI!òG²ºpÚ´ià‰ÂÙµ±°±ã$Å^ŒõÖ$ ÐFVýhLˆ:uêJ&H~ÿ˜l­x1³ycOÙ”„ê*6\û ‰µœºÊ…tžyPG"ùƒ¼Ü3bÐô O7 ]>—ãeëÛWP÷û»Ó· œïÎÛøíÁ ¢`š¼iP„ì"D9Û”v:*®À›G$mïÊ+éü§Îë~ÌÀCúC„w·V¥ZZ[Ü.¾­qö™)»ã —†€†O6?œó!ý´â'lN>¹ÃÉtßå÷Ñç}Î{îöÓéÿw:=9îÉR±4p\«ãds`ƒò|¢~!ÀÛÐBnQŒ@C—αғíw‰À÷æ;EýÆÆÉ«_]»œ–á8,5ÕÏ6Ÿœ"o<¼<‘Á F¯Õšm7‰‹õK‚0Ѝ’ao£òYòÙ̺ þdL“Z,ÕkÍ6&ªñÆï2bMƒËF¥QÑHH9éÉü*ìd`eÿ`PæY±~.ÇÇçnÉÝB=êIwŒ¹ƒ¦Ï›N¼f.wÛó:l¢SA@µa—J#)½íE{¸½?þö#]ý*o^ƒÅà"÷]7YCÞuS¶zÅêQ DNzöPVL°j‚‹lFVŒžülúׇ:5ï±0î*¸¤ç%4é±Iòõ@ûí骇¯¢¿ÌˆX& íš´£‰H +6,ÔèAöž(2ÞGå 3o8l¡ÐH©SËÁ5Vú Ú £ñê—ÈÂøfu›iLR®ò>à ‹ðÈÂ]˜Á¨ë„’üõC°‚_ÃÚ(„Õ/j>öp-ðVüɘŽM:ʑϟ؉åÏû@àüýƵüxy‘^]`-~ç4ž+ùQ& ‰äò&F߃š^Ü)ñf^ÀŸËÉLŸ5yeòè±O£Ëž½Œ¨¿9Ì—ÄBËounò—@Ÿ=`4ÐÞq3ÇÑýïßÏ ‹nÜöš¶‚tÒ¼ÓÆW ªU­õêÜ‹ ÌÎygž ÎáÇT(WþvÑßèË群9 çP·áݨãàŽôè¿¥kWÄÂ÷<‡Ö?”&ÝC-xÅ ì‹ñCPD)E^‘FãÐuó/^<…tüɘc›+/ºK&Å@ ãGp¸§cÄÂÁ`þ";_Ä<ÀÃ'ìð‰¥Œ=3fæ.³}Ìú+°­h\ø9N„|á4x»Q> ðe¼uÿ´hÛƒ“¤qߌ‹Ø’ýù^Øèk¥®ëËo¿“ú9*r^/—Ñ u0¾Íj7K~›¦mèË翤ç ù+æÓí/ÜNmû·¥®ÃºÒcŸ ¥¿-M^²™[ÔkAožHµÊÖòW1‹#å‰öü¢¥E‚Çñ`ênÿG‚A”á vó˜t £N¶Çz¼dKöGyßòåËq8ž2{å‘pM’?ŒºNȇ_?EÐF CØnàþ‰'þˆÌ~iÚÕoG8”#„<Š*‚‰B:‘ „çvJͯ®%ä×fô¶?$S(,ÀÙêE:E„ `ÀhÒŽù+¼íE›XËqÕWÑ‹Ð\!îÎÝ;…F!‘a»rv…‰/ªÇÑ=¨ ¾WTÀ0‘úÕ_._¶<=þÓ˜{ÆP•*ü #ŒôfxË‹·P»Aí¨Ó%è®ÑwÉ2+Üćf±rµ¬ß’Þ»þ=ªTPÉÙ€¯"-D‹Œ³ÑòÚ˜FË—Hòj~Ûo×Éoç·ýÈÏáêÙÕéðF‡G*P<û/ù'Mš„ †¯ÌßË3¸¾?EHª_¿ºÒйsçþÎjø<½ØVÖð0§V­ÉÑ•úÂa„8“ÏŘãlÕ—ï—¿N¨S¥PÅÓã‡þX½ÊC¿žK©…£/„=8Ç0EÙ`4 ˆ5"( /6¤#½Ì ÛËŸCîËØGç?}¾\Ïk’Cœ°¶×ûns8w?sµblëØ’—± €ãtÍ‘ºUËW-&D¢¾§ô¥/žù‚ÕoT¸×ƒŸ-¾4xpìƒÔíÚnÔ¨w#ºàŽ èå^¦+»®X;µìD/^þ¢»)Pî'(}u½Ï#Rùhù¢¥E‚‡x»œúáªqŽj 4Íä?¼‰?Ìc=xóÀýsæÌYÏUz­Y[$h5xü4~ ÀKVW¢®6tÿÎ;7¡€†2¦Ë¡]¤8^Ⱥ;£2ÃGØü±ãÅ!Ó$¯fÀÄ×q5 Å”ûcR¼ êq¨÷Áè™á»›1ûG‚. ºà‹öâÒ ,m°Ý”³IÎÝ÷^”“Ë[Ø1šÅÑ6îÚÈ™ŠoNhw‚3\C Ë#[• ¼1 sÄ¡GÐôç¦S§6¼‘ÚÓV}¾Ûò¶Ñû3Þ§«ŸºšŽ¸ôjrnxû@zìÍÇhÊÌ)´mç¶$jwŠb\úäûOè¹ ÏÉù¸@È=€Gí¦©6ÏØéKíb!ã ·\HF;àñ{ËyÚ]ãáÚ~M‡‹xp)O:x…ÆØúDäLÚ(Ï3<Ðå‰ Xù¤ºÀƶI×í€îæ—QÒ)mW‰8ñó@‹Û·o_Ï@¦jÕª%ÃqÍŽã#Ô38ƒG-<Ôt„ )Ñ™1[€ÚMòè ÁùÝYÊ ¿–c7¤Ó"IgXȇñ–ZD©5Sa¢´Z„Àüà¾M€ Nè»xìÚWÿ¿½÷´«¨öÆ'½CzHB ABH# !@M@AiŠ>±‘Œ!öíÓ×àV ~?bñ‹ÍÛòëìØQÀ×$çýkžY¼bqΉ”%ëˆ:Xg36çHÒ¤±…ç™Nkeu:/¤æ1ͺ4»ù¹rØÑQëØ°,(ò•n'9¹víýÁÀ—¤µ&Øèz Z·=qžÕ®8då ³¼äÐ)¤9š“µtîܹа[VÏôîÖÛŒ1ó{G@IDATÞ<ófãû¸èz‰2o =e¯µª-„ÁPÉ ˆ?©‚fz¾ùÐjØ#fO5u<ð@axßáfüp÷Û4™£þ`r´k=9½â/М4ú_Õ¢Yö,ª¢¢¬V- @aÕº±ËFsÜEÇ™»Ü[ýª!ógÂW?xµ"cb› awùÜìönî»fÕƳ çtž9vú±¹Ù ØÝæÃ~å€^"ï-»½:ÚÞFÈ%Bnu–݃<iD·³àwèÀî@ ÐRæØR‚ÖÓ|X¶P^¨«Óa9&cˆ i. Â#w0#úÈ%*üK¬ì[ Ué$a%eìm…­7-žµÀŽjÊA`°:®¿îºëD—²zuÍØn†=˜öàé^ iÊtš2G½C NA^’¹*´; WA.Á YVdOÄ´Ìr»ãQ ?fE ´z 80²«Uç,ß°Ü\öÐe¹!a»Ûå^V3g9)ûÚ‡¯Un\æ9O¼ôžåÊ>À 8ÿ[ç›c÷8¶quñceŽm{8;x`¯‡ðØòGt`îo8Ç€N@ÇÞâ $E:pÜíkGî ¤=ð\lÊ+–Ÿd¶BeÂ<¦IYP‡2ÐO’¡,åŠÎ79™bݵ×^û€THð'.+ÃÞ£mŽ “~°lôdÐAœž z0ä9P;ð… .•-|¡.¦,l§­vÊyÌÒ[§l‘Ù‚‰½Do$èÛV†|ÉÖ?û⟕ò”ÙÂ)2YÕWr¨+)›2¦(ލ; ðzÆ &ç¼ÀV1à àZÆŠÙ= `óEoÙªeæ£U™~=e+¿Œ°²ae㼂yDê\øVõÞÍǯžâùv|WßžÑѩ瀘† —·NZÁBW®Ó—ß/ßxó½7s×:êRᚇ¯Q©ê±];w5—Ÿ|¹™¹ìr®–Á`'?Ü#3)~› ÉÊ<ì „†zRUªÍõüXHÏåYç„zº¬æ‘@=Ð0?Lk]Ík=ò¤¬—m‰ÜÎçÈtöØa³Y÷Í Yq ¶9¬æa ¤!c/H+n·XY;0/‚>4¹ÿ<<ñÄØ1¼G¾Ò°ÿ¸ým/pòmÜ ¿mÂhHzhÐV4¯-"zî_žNJB;šOQÏ£¢¢R,@0Ãl¦#央ø+K_I©¨¸ø¥EòÄ?êcpußþÌí¦¯²Má\ýëÍÔSw;À?Pî”Q¬\R~(Si ®ì¼’S”G å‡y…Ò’gÛ¥Ž¦!4#X…N:0¯{•$ˆm‚uJ=vá«(±‘ÀÏ‘¢i𙇬vÅà80T{?ëþüç?ÿSØ&ÞÀÁ«4Ž:ÎŒ4º±uöBS×{ÐÑCöÎõÖî`‡‘Þµ õà4¸èGJ½ ©ï[ õØ‹¿½¬ûëSgx´ãÕ^K[pÆ‘Ca§KÊÙI¿¼øej5›>ÿêó€Áº¥–µÖš³ÿ‘û,q³+-£@Ïn=ÍœSç˜Ñ}G›M Ò¹½¼iÐuBùlç:޽m®~R}Í©öKª²Bõ¤åAμ°n'®Ø6µ.x賬Э‡lmú·Rby‡m›ë‘–ä(Ù¨q0©GèbÕBµJ €‡”ƒÌ¸gíÇœémXì Iäz@S µ'A‚Ü›:ÔEZ‚=˜n‡ 'iúW\¼M5J— ¦¢¢ʰ€^¥Å?Yý‰Y²|I --ù¯ÿj|-NfO{ÛÁ½&wé}—šW—¼ZZEh Ü| ¹ù§7›a½‡ånV0³b¶åÌ[êRŠ^’N’ÌÍϳH'éiYŸVV˃²vÞ ÇQ^‚í£–»ºÚÉaGN­¢¿ÜþŒ[¬“Ê€ƒyèd³ç¤®G’S…€GeªØq „‘€6€õ†üñGgÍšu(¶JºwïžIŸvÞjgÓ½SwÓ°¡!·m‡^HÀ³ve ÷½tr»}>Í-‚®›XüÉ-é¼§ŒEE‡ÄåʇåRU†ï“’E6Z Z@YÀÍJ/¼÷‚Üg°Ê(ξ½ømû+zö#<} ö3áp$½zÃjsÒÿ=ÉÜúÃ[ý¯¯µ2­oen<íF3óŒ™fùjù²¼û¸©‹|@ð³sºZhÚáL]¨+I:¡,H7™‚ü<§@ç¥ñºœ³!ƒ>#X¬òUÚ­KÛy<Ê#B•»àe×£sóéQÙ|úWZð·¶q’ WÿÙ+Ž=­jHƒºJÕv&öæFZØ{A]tÑCr 6æ¤Jšo,‹OÏ?³ñdp=Ë;ABŠë°:-Ó<ÔÕ- ª§Q{)ÿÒʧÉí˜Ò2£¨31ɲ¤PÒ<¡b=ˆ‹Md’µçÄ=͈# ™I¦I;ã” =æ ¯±=EdïTÏóF$*Ù…j8ìBŠéÓÖ#’/$­[ºt©}Ç&«¡#N9¤e/=@O¨{ ^å{¯‘rê&¤¡Ëè¥Ö¯Ÿ×¿*Ô_«qÄv伋ǯú63c ¹áo÷ü­±_¨Ýt·Ξ{¶¹`îº5àfLœa®úþU¦ÓÚNöYÿf€<¿dg]Ìgṕ$ uÒÒaY•NœT¾[Y¯–S¦)l§Óà1‡kê@YžÓ“T7d:²>‘Ù~ =dÊ!¶º,þË€mÀ8©“‘ø§1‘=ӣˢ©uTÛ@à Šsð0†çï¼óÎû$éGÆn1Öì4Ê}­»Þð`3í{ÈÞêC@žå éPW(ÚÐѶ¥ò³HÛqd\gýŠu¸s-›Ü5Wgvxæ­g0Õ”Ö¬]cî~ôn«OÀÇê€o)n `6Å·DvÊ_N1¿¸þ_­U8èÓ™Ù_šíô @7š9ÙkX—á1 ea¦.h˜¯óB¾XY]WÈ3ÖÁ> Ÿ:Bíê_¥ÑçÉÛL6ã†C ™~àÎa›Æ;âh¸,EHs©*ü­¦À`ˆ4?¨v`kù(Ð3ëׯ_‡-|39«ðÅ¿ØhJš”½A´=! OˆØ¶÷A±V¦½b>ƒúósšŸÊªžæ·KD ´~ Ì{¾Y¿SOiáÞÇï5ø ò2kÚ‡ÿx³¨Žx²Jâ™7ŸiùŸCÌ¢%‹Jk$­“;Ù³û1²Š’ÊdVåy žç+=åù®)›7OúBŠÑå5O•$ó@Ã|•ömCF`weüÜŽ´šó‘ôuJ¹#v=вø –ÓðÁ;©Ócðt’À#P#Ë¢7Éuà´­F`çAanF 6Œ4„¥¯¿þºÝ›[±bEfýÂ[ ÜÊoñØHÏüê™' {É^ƒ2jP–¤Oªw4ïÛ Êißï@'­l”«ãmÖxN·W[Èé°zÝjóü;¥?pÉœKró‘,ôí} ø” åî€}Oœ€{^¸ÇLùþsæµgš†5 ¹:ªü÷œoŸc¦šÖø|(HfW¿=ι¬Ðñ/E啞Y%Óù©<û¡ËuÛ9 È‘¤‹rºlÈë|—çûêàsêˆA#ÌgÆ|&³£C s˜|³çhˆƒ®'v$ú‚W-TË`‡ÙyN L\ÄèÒK/½…³|õ}yšüOžÔz‘º×J×{˜¨:à3 \Ù‡4Ã&bUÑÑbG^Á+ÙÅÛï¾iþqÿ?rÀ°'ø»í~›ÖàÛÈÃçwå· 65˜Ù×Î6“Oœl.ýÇ¥fí:¼ V½€]ù£+Í ƒü·x£Õ:œÓÒº6·…ò0ú´Lóim¥ÉòaZ·%y~ÞÖÐét|ê`=Ô£Lè‘»™Ö›²äÄ0‡it4æi,DØ+´Çž–Õv©…ªíp 43‰c;„["4Îú ,ÏéclŸ44dç1ï=voûÚ]=«^Ø ‚‡rð¤ä©Š‘â9âHs6‹vˆv¨—s@.a„{Þki±?ç_s¾Ù°Q&€¼€»ý–>¾¡ —ÔRamEÄÌ*;öljܯò½¹ìMóó¾c&?Áœãùfù*ùeÁ*…¡†š+x¥é¸®cî¡@÷‘ ;ãêy-<&znÓy¡qïOftBçKŸG9tbˆˆh]¾ïÅûÌšõ¸YžÞ]ú®¹èú‹r î^õ³?˜£y‚>(‚P:Ö € ~ŽŽÀ.úsÄó£sd¾±0W.ã¿»OØÝüèó?²·ðV€=PÏÏk¥´‰¹®@ð;£Z/g=…òuõAµ\ñ~…9yB›Ì×ZzN÷°]3]:Ék”ê9­Jx~ú÷Á–ak±M(°ŽØG,EÏÕDZÅPM ì6Årà4†ÞYwñÅ?"ÞÓúuëÖeú0à~;ìgúõî×ä¤hr’hó“çh˜eĨ´œº‘F D Ô­ðEÀyÏÍ+Ø¿ŸüïOÌŠUò<fJD¿{ÈÏhÛýx @;t ßE²àÐ è!¼Äå›–›sþ~Ž™tü$³ç·ö4Þp¡ùð“¥@vá´/Ÿf¦l5%÷}8ø¤¹Ìº~Ìy Mjž](G–T†õ…턺iiÊIu=…r¦™çh8×#Ý·w_“åwÿ±òwصþ / ?ýK¬#öiðg¯µµªÊ×ÂAž@#€ÒC²·^}Ý6fùòì¶ÉútïcŽÚõ¨ÜÉö*HûHʃyNNÿF D Ô¥ÐÚW<|Ej÷ž}ñYsÕ-WùÕ¼ßúw?­kW÷xÀΤNfç4àv€‘œvèžsà vìÞÑ<öÊcæäóN6£>?ÊýÓ£Ííßž»íÚ»Ò2ºtîb.;å2Ó«C¯Ü +³¬uvš÷ߟ3#a¾ñ¾anyà³zíj]s³øm·ÜÖœqÌ~ÀB’†ÌÈ¥„`.óà¯åi|RýZ7Ì/5/ÔÓcAžŠáô€Í˜ƒ§¶^Q˜…ºÃn‘Šò¶’Ö;ÄAiE})V˜§n1½Jó9PíÀÚ ÞX‹-úH¾žô¦G¾ÒнKwsÔgŽÊõ½)›xÈJמLè eäA g )å‘F D ´Œ8o”éhöM³óúðñòÍa§fž~ùéÜ–?¶øÝýö¡>€8wdõÛÿyµ¸„kN‚Ý ÀíÜàsn@;ä?Zó‘¹â®+Ì~ò3üÀáæèŸm®¹ã³lŲ¤– ʾuè·ÌöC·÷Ÿ öÏà#AIód:é²À_סy´¦Ù6å!EÙ¼¾ü!ÖÏ9 ¬.ϴУ÷8ÚôìÚ“­UL‰UÀ.`˜TÈ…­^ýCFð§+¦{Xq?J­ VúƒjOG€F¥°öª«®ºq?%Ëpð¤ƒÍ›oÑø]×+{Òè²Ç¤ÈïbžäQ'‘†m¨:õc¾·y´Oãùm‘-¤Š[ž¹Å\r×%fyÃr3÷_sÍîßÝÝ<þâãù /€ïWþqlëÜõ švŠŸð»tàL„Î@p‹· VÉ¿ºÁ|õÿ|Õ:3¿5ÓüæÿýÆ<½ð颡SÇNæ‚ï_säûP ¾ ÒöyÎICÒ\†ºÝø<ðj½4ž6)”¯ó¨öB9Óè À_¥=ò”ƒºèõ™apßÁæ²û쯴æ±Êa—Ç2d©¨±OõÒZÕÔ,tð VF“Öó-­œòƒí¥ƒ´®»Iìá¢Ü¤2}$ö–¸™‹}Ä?îÕ«×f}úô1={fç©Í[0Ïüòo¿ÌÝßÃÅŒ ^º{µ‡i+ãg>9 Eó¼ÈHCÞfø£ËP‹YÑÑXÀî‰ÛoçË ›„_- é>¡kWîXµ˜´íJž_,õÚE› ý¢Ã­m›,€Æƒ{¡ +\WfH¿!fÖ.³Ì¬i³ÌŒf˜AýÙ&’þrÚ!fÞ¿ç5ŽCL´ã€ƒƒ1¤ý• V!“£9a#ßÜ´«.¿I¨£¨_áCrê Áyy2±Ò§~šÙoâ~l¥bŠ'ÿ± ßÿÿäè£þ•TˆØ>q_¶CZ>'ið~;"^A¡“àŽ¦ G*Ùé¡ìf­Ú¥¬ZT ‡ ƒæCzõïùüãw¢CüMeðY„™ãfšýGäŸ8Q¸uÄR¦ÒþɈü‰Å“PÓGºPLi£`™BõżÂöŽö‰öq“‰uüÝÃz~‹ÞݯÇ2ÅÞ·GZ¢¿÷¯Á²ÔsIO^R>mGÀ·î¨­3"¾dùsÅW˜cgkF~v¤™zôTó_gý—¹ù¾› ngèpäÞGÚ×q À:>ι ³cgåp,˜—Dfç:ä¹tYóRX Û*PF}EýͲaÒŒì7ÓBáÄ ë?,SðGWˆQ³<†I–æ‰w|ôŒ£®iÀFT-ˆÃñ€´ÃÀPÚX¸ ðäÁ| È{àáŠnݰiMøÚŒ¯™Ù7În<ÙôI‡2æxhpÑ“‡AO9IåuÕ¨¿òÆ¢Z·ܵ ÞÔiSî=ö&åÚÛÔAÒX#ð®ú!‡Œ¯þå´š÷—×4û€ºÐnGù#3d‡M’ÆL©a‚3¦¦˜5uZÊÌk¾™ÿÆ|û±¡Ž2ÕŽ5Îì6y7³ëÄ]-oç/Ö­ëG_uÐó䕤òIõé¶“xÔÁz@1ÊK¤_ß÷ë¹rý6áVµÐ`–TË•=)pà¯GZóP+ƒÃ©ÅÃæOA‚?)ŒÆ¸N>¦ðÀÌ™3gá§³töÜnO3eÔóäk8^œô–/ç$ØÉ‚“)õ)+ÐDÁ,”×õjY䣢ʶ®asRj±Nvûÿ›:眀4À?q;Ü–(㾦±!MÛ>qîÁü9gN™);l”>¸Ÿûí°Áñ’¯ù7šù‹rÁE—I}ØÅð;—tÐû!˜wšl9ùMÊè|Í[Ŧõ[1ÆÇÀ2¤’gm®Ò¶H£œP?.—†Üßfq²I£'™½ÇíÍV2¡üÙ_Áª¥B.b=†‰ŒØJ«£Gì)GE*YÕ<ÔÕo)×§#Oc€Ò`yôÜsÏ}@¾«¼·YrÕUþ÷kÓ¿–ß#éßêR=õ2}¸4]ò¤kžzåRÔÅXn±\´@´@ôøô-<”g·àÝý~ËãA=·ýoŸ X0³²#êÃŒì"Ú±íº§¦ìƒ’Æö¿ïcø&¼VرgGûÿÌîõËSWƒmƒýNšK‚ù*sðgÛšb>e`û¤”“&èú9šãš'CY‘}m/™ó3 À$`0J^ý»_ªÎÃ/•ÖX¢GÚH3ìiÓªjµ [Æ@1x§:yxFô’Bjí=÷Üsï~ð E–»x5ïÞüäÍÒ|J@ÝEi5Ðc\¬*Ú]lÛA†@Šr ¨‡rÊ*¥ái“uý•ö/–h%°«~<].×uxmášÂuL¹u´,+^]˶?˜wdÀî  ›x`íCž1›†rÙrn©Î'èÙ9Yë3ŸÔÕ}Ü>Ç™-ûo‰dˆE›ÒÀ?m€#ʬ?Í­¨ÖŒÀƒr”N€6$ß•\ûç?ÿù1ñ¸Va€†GeY„/ìü3rÐȼž5{Ýë$^:â˰SÐC MâY—U¬Ò¶¡ûQ¥¦bµÑ­ÒyÌŠ`-ÕéZ Œ×k¡öè°B­Ó"o)ðË…öÙ{ï ¸•¿uÜÛ cøFƒÇ’ÚÖóGÏr:²0­eÈc>©Ë÷}¡N 4oý-miŽÜõHÔ˜Y¹éUÀ&©˜¸å1ËɈkëô(Ð'¤kpê´Dààé·Ñ00ï™Ð˜¤Ö¨·ÜrËèp֢Γö9©Ñ EϤWþ Rö2÷<#r£ñexH9ZM9òPyRžÖ«”g¤•ÖËç.ßh‡¶e¹í´\ËãZÎ5Éùý¥ã¨ßp;Ü!°Tž'°ù~[#7ÞÄ•?lÀvBi„BvÒe©G)å¬Kä¾/Z¼‹ys­–a¾F}NvÒ2·gˆA“€S!ðCF<¶EØ3=âŒ{WZu-å w<'ŒC#ÑÈÉ_så•W>)]¬€çÅW/PYaçÑ;›ý'ïßx¢£R}ÈØc¡¡‡éGêë4yP­«åÌcùBza¹rÒµj§œ¾Å2ÑíÁ¼›;Ö´¹!Ü CÀ7 @nmøWÃ~èv4O½P¦Óšõ™GŠ|ðIi-ÞÏÁ”ƒMX¤÷Ýi_3mÌ4H2 À``ÑJ`’TLð'%økLš°‡ìuf}*§¢–p0p€‡PK ”^•6êZ1øßQ¼v‘; È(|kæ·LÿÞý_—÷2yèHÙó„´÷\©ÃÑB—|s(Û(·|©mÕªRûõÊ;_¢ÝZ‡Ýx½5÷x5·æG½;.¨ì_ÒüÊÂ4ÚbyM©GŠ<ÅçÍ»ÌC>uHU^8ïöëÝÏ|wÿï¢™Ø Øƒ ýq¡â•Æ2â›î5zŽ@šKÕðoK8zxêÐÙÃJ#q€N€6ìùÔâÂ÷ßÿ=x`üõ%]i%|ïn½Í·g};wHÔ¡òdÒó¼“ÍÉlžûãË„yúpk^.Ä£ c!½JóØi¥õÅòÑÑ9 ”{M5§\š.äA°sU kK åÊÖa]¤h›¼Ð&ýQyÐós/ʹyÚÏ·Ð…LâIdzwÇÏËd€9À`Э·ÞŠß’Æ•‘ÎÁŸ;zõïzœ]ŸÊ­©¥€àpÚC£ÀH0XèhãZþ׿þõõrÀ7á>̆ (–]˜±ý ³ÛØÝr¢§aT‡/ï¤ õPïC-Ó|¨W,²:Ó¯$¿VíTÒÇX6Z ^-PÉõò¥Ž úaH¨ó“£’tµ,­¾rtXiP‡ïûPŸrœ‹Ì‰ÓÆM3ûŒßG×^1¬æH6ýæ7¿™#6Á&‘Á Ѐ°·èzÞb¡¥=`†a,Å XûÊ+¯¼ÿ /,@EYï ÎS>Õ è5 wx\ϼ×É“MNÍ3ßZ{ÂR†Ê\¾MjžùåP¶“U}i}ÐíT»­´>Dy´@½[@_'åô•åK-›¦Ÿpæ©®?Ô ÓÐ ea:M‡z¤li‰¾O.mÛ!Ÿ6Ç¢>Û¬òq÷ôÃOgí™Qb °ç¥—^Z"sů4ðGÙËÌúTIE-éà°"h ãРi`PÙÒÙ³gÿM<²õ¸ƒcÈ2ôêÖË|{w+=tÑž ú0Š<ñ¤EgXŽ Ó”“"?ËÀö²®7©º-òIzQ-ÐÖ-Àó¿’ëŽu”j«4ý9æ+?g…õë>'”µêZ‚0$K«‹ºº­KÞåÛ~Sææá<òDþíÏ~Û`Ï2c€5ÀÁÜûÏÃ#Ik¬~q7˜†ÞºQäèM7ÝÄ´dµLhI@˜JJ'€¤aµÁ×ÊVLüyóîCEø#Oì¬èôí¦›™gæ{–B½Š|wjšw’RGëOJS^) û]i}¥”ÛÔã.¥|ÔÉÑõm‡ð¼bÅŠåx(C¨ˆ² §|šùÔÐOålþDu'/&/ǧG%|Þ/Y1ÝÕ|R²¬Úd̺îBõ±Í*ó¢êÅáy‹t%A××ÜzX6,— ÇÜcçè†}.–fý¥è%éhY/2?72ÑÍ¥~nU2ä[9ç[¡c†1?9ü'ìqfØŒ‘×ÿ–«Oþæ-H¥1U:è9‚¥õ°úGgZÚ@pu„á´'Eð·À/yp¬#pÞyçÝ€_fÊú@iÃüô°Ÿš-n™×;ëòТ׎÷^*G¹Š¾\p"óD·§G˜‡t5#ûJZͶÒêfÛi4­\”W÷ÜhöM;!Ϻþrêcù°lŠÜƒgR>da="Ê“%• Ë ÖÅ4êC`ZëŠÌƒ8òÃ(ºMæTèÈœjåà]}Ã7?ûÒÏDm¦[ÐOùeÚ¤v`Ç—&.ø‰[òF%ÙõZÜPž#OÂ& š¶`=°Gyä—_~y! ó! ðY…¡}‡š“<9×3ôÎõÐ_X”‘ꓘ2E­·«N\±Q]Ò\ªvU_}ßj×zrKI}*&K®)JÛ£Š+:¿ö©´þBå™ô;·æG¦Gr —eÔÓrÍû®|sÒ˜ÛX§Ð¼•?äad¹@îÔéòN>äd3¼ÿp¶’%¦c€5R±Å¡X”úÝh—&^¿8«Kvî((̃¬E~Kªž7>YA‚¨òáJûekôÙý:6ËtùéOz“| è¿o­GÂf&œdŽÝóXsŽWä¼T¸Nú¤D‘º©ã¦ÆokCŽˆ@w :DÌ#…žæu:”#¯¥B=õ¥¥lÛH³æ‚,B¡zRò,¨²í$$ôCy˜N«3Ô+”æ /:yນ§ Ó=ê¤\SǽÏÑfÇQ;²‡™Q~ïýúõë€1R1Á”àÎo»Ð;%Y_Ô¢½R³>Ô0$·S@idP{ðPÆÕW_}«È«v+à+Ó¿bv³S®‡®§yÛPª÷MvÐ1œ , <iÈë´+ÇòÈj±ö…éëPl8Z …,Às_ÓJºR¬æ'´áÁ?I'IÆ:§C˜f^(oNZÍÍ´ƒ(u„sëŽcv4_Ûûkìaf”[ÿ¨ØâüËÃÉÒ˜¤± ØEðgïÂ:TÛâ¡.€À 4ŒGO †åÖŠ @n¼ñÆ¿õÖ[oâÀUã@ôóÌ£Î4£·ÝxhqBòTnGóäzTŠOôp‘:¨—”¦,h3¯Œ._+>ìÓµj?¶“ÞD{dgžË!ÍÊÆ¬7­¾ù˜Gü\½¤:Dœ(OÒOÒMÓ£n˜¯Ó˜ÉÑ'‘ù~²Ô#yÞÜ ¹‹¾¬Ko½ÅÖæwÇÿ=È<C€%À`‹4@¬Ñ¸˜D|V·ÔˆDZ‡¡nåéÓ„1éYÑÛÒ€Û06ï´ÓN»Nšý6¶oªf1ÛŒ4"¤ý ËÞ;jåàõ©@tNxï »4ˆ ÐÓ!Lë<ò¬›”ò–¦ìO!ÚÒ}ŒíG ÔúüÔí¥YŸ: ù˜;ìü<è a~z›Ô–Õí$Õ£õ1÷!ˆ¬É\Dz¤PgƶO¨Ô‘'—4~â÷Çü5g€|ç˜" páI'€¸CùÄ)`FÈQÔÝê_úfêíô Fs‡Þ;xžŒç`ü®ŽÇX:‹×¶â/ùË?Ž9æ˜CðÞf×®]M§N(–]°t²9ùRy0÷ÄÑc¸U QN>‰RWÔmÐiÍ#3LçJ¤ÿ…¾ì–Õ öµÔ~Õó˜JCÔËÞåžOÙ÷¤±ÆrûT œÆÆšrIe“d(™$O’iÝ0_§ "÷}…ŽŽÐqi¿hBš0Šlì´*Ù÷ù¾ÖoJf°êç;ÿÀ`Š4ÀÇŠ2 øI!ø»Ñ$ZTÔë#ÔÍÌ‘² Àí˜Û,pCoÌœ9sæü[žØ|eãÆUy+@Ú5GN4ßÜï›'(ÎÍàM<¡õiA^êóÞ-*G@ƒæ! ÓÔ+…²MMK)WÏ:z,‘ÏÑõsÆêcÑÜ^±lB9ÌPò­åu(P_â¼–g]”“&ɳW8·þÇÿavýCžúvÈçæ_–ˆ8ÃŒ¡@".£0jî ÷v ÛDT?¡®€À,4( ÃÒØ< ¤<0ÖK;õÔSo‡6VWãÙÏ#v=Â|~×Ïç9öpëž;ÞŸÀ y¼ðjæp¤aŸ(4Z Z ù¨ôzÒåZ/øQaºPû uȳÒ$¹ÎÞ;*눲.]tŽt»‡îv¨9j£Øj¦‹}`°ãG?úÞù®SÂÕ?q‡xÄ…*h8BÕg¨;@yJ4¢;ìþÁŠp'€ˆ€=0²³úw¿ûÝurâÙ_ ÄA­FøÎ~ß1{MØË;y'1zÎQÍËSr¯uÞÿbg¡ÇÀ2iiÊ+¥lGÓJëŒå£Ú¢ô5B¾Üq)¹ÁÎ…êOª#IÆ:’ò K Ô×:”¡Œæ]Ú÷™y¤J¿ÉܨæN›çP`ú¤éæ??ûŸ(™yFàÞ?ú ì†H#zâ )Vÿ`╥´Ìû\i…õú ÇcÂIÅ^7õq@ñ< ¿`Ÿxâ‰'ÞzðÁßc=v‘O8š>}ú˜Ž³÷yN?ìt³¼a¹yâå'¤ ¸ÜwtÏÑk‰>Ï¥íh'`‡"„§ùRÒÐÉ: IA÷+)?Ê¢Ú‚ÒÎÿJÇV¤^žÅÚI«'MŽúš›ý°ŒNkõˬ×ÌâÔuÑê02ð,´Ä)ÛN1g|éŒü:­bå°åŒ@Ìx Ø!,Á^S:ÜþøÓp=µ#_÷!{4Ì`ÈǤNïeÑóâAÐHo×4œuÖY÷|ôÑG»Ë=Ë‘AªøõÑ¿6GM̼r蛜Ôó˜N¡¶<ò4Y±4ËU›¦ôŸwµ›õG dfBçrfHEº”zqýÛ9 %?OÎÈdyŠ*‘T†ÙIyIõi=Í£Îs¬pHÖ%´É< =–GZâøÑãÍoÿ­ÍªÆný+€Ò·ü5žgˆ;Ä!®þÕÈr½ °¬]¯¨Îºt0"e8§ Ê[8ôÊx€H!_-¯qüE¶s6ൎj:¿?î÷fÜ–ãš:î$ö¥¤=ÀstšJ§¡ëuF€ŽÅÒZ·¥x=®b|Kõ1¶Ûv-PìœÓùÕ´B‰íàš·×})}aZ7IÖÜ|­>©NÈ4ç7æcþ£ëjÇÉ<ÈÁ#°<ÒÇŽkþ÷?þ×fUã0Á½ò·áôÓO¿FÚ~Xìp¼ÆÈ9®ü‰Kè1G¨1LÄõêÖÌE£ò4 €$'€ÜêÅ‹tñÅÿ 'œ<ÛaòêÏ,ùǯÿÑŒ>6w2ãDÞ ]v'²u_È#/åBVßÔêèÓ <ë 5@ue­…²ï‘6ãh‹ÊlÑRç~xÜ ô×8£¿Ž èç]ÿ¡g²PŽ4ú”$g^R~©2Ö!ó“v¶ƒùм²IâÜçêÐyÛßÖœwâyUæÔ=ðgû Œxçw>”FøCDÆE¦^ýÓ­”y?«Ua];Á.€:},”Âøá.)àš;î¸ãE<Câ^lT˦æÜÿ8×l7l»Ü~…œÔö„Ö;Ñqaä],ÔQù¸h­z 9‚Ö£nx êt®Tü--P- „×d‘vpM3QmÌf’¦\’N’L—D~tækôuÚñ2ªÆy sõ¨#c·2=G1O½J ð¿àÛäê¨Â_`ïû?ôÐCO#¤®ü‰ÄÐpõ¯Œ†#j«˜´®tPžF44<Í ÀÁ ãjÜÛyûí·ß•v°·<°ªF²bÿðµ?˜O û”_½äíè¯=ÞDïÞéx=m ò ¨7)Íö’¨Ö|¾ý¢=¢=ÒÎðZJÓSr\¿ŒyשÒI”³­Bzi:+WJ~XN oÇ`§\Sð.ú9 ³w ãçHÉ3lŒ9çÄsäÙçê€6ªðÊáy'œgÆ]Ïõ‰N/{!q„¤èxÖA'@Ës¹¿º,åÔeºei´Xù˜-ÐZ,vŽ7÷š‘ñìI›mÝ—b…©êëwZ¾–³n-C;L»ü‚s–ªÃê9°÷u$€ÿØ­ÆÚmÿN³ý|»6žC”>mœ={ö_€ ’Oðט¡±0¦  °J7Y·|«pëñ4…ÀˆÛôÒxàô–Žç.\¸X¾ñ<õòõðÕ x0pâÖòŠ /uŸ‹2KeDÞA€®)ytRòìåx_M¸?¨C×¾•ͳ®B´ìÊcÁh -Pè¼ ó*h סŽeWÅ>•RAšnšœu¦åk9yP(‡ÌåÙ9ˆzÌ'å|%i;§©´­Ö¥ý|'i¼êWÍþЮÞù<ÿüó‹E¬Á_óÀ ` q…÷ü‰9h« ­Æ<+žf 0>½3¬$€tõu×]÷ì<`¿Ü' šJ{æ÷_ý½™2zŠu}â{ w£ò G¦G A('^”[Ê?,Ë4(ëвjðl;+Z>–RgVýõäνZØ¡”ãZ†¯9Ò2ªh,¢íÐ(Mç¨j¤Éµt’‚–³-CÞrP ‹Ðåb'!ßç‰þä1“ÍÿžP½Wý0 Ìñ˜ë0÷„õ Cáó0ÂåÑ ¾kÔ­`”¨Õh5L© ŒÓ %íÀÔ,Þûúë¯/â‰Qm'à7ÇýÆì²í.~ÏÂ?ô‚QhŸRÒyN@8ZŽÚÑT]^tR}Þªë£Nk Á¸ýѯ¶¼5Ø&ö±é9^Mr!Å¥”Êiƒçk©e‹é³Ciõ¡|˜ÖIÔE]­ãø¼¹†ùš¢,uõ+ÐZGx;÷9(ºÝTsÖ×ÏBËU zŽÇœ¹_KÅ—§ÁŸøB€#ˆ56!ÙjB«r«ò4%t‚â ÑS+i'àûßÿþœ>øÀ)Ÿ„¬føå1¿Ìýv€»PpAÙ‹Š£AóŽ—œÜV¿’1ÏözBíDåôm9Ís›²ðŸËËUÿF ´ 4¹Ôµ‘h^£š&*&+)“P]žˆuç %‘$O“±,òHomÅgt>ë#•¹ŠN“oŸyBý|ç¦Ùé§›3¿z&j¬ZÀœÎ[½˜ë1çKcÿ$€r þú¾?ñ†£ªZ¿kQq¬rƒý^}¹…]9YÕ7»†Ï}îs|7N (ž±¿ ´«‹Ý…öØÓÅ^B{»ÞÆnݺõ¹ì²Ë¾ÞSB×®]íoH^UÃ…s/47<(?6ÅÞË:tÄi–QçAH9)zò”iªyè Åò]Ùj½žS¨k1/Z R™…,ª*·ŽRË5G¯˜®ä<º2#XhÈ;™×MX´ä-tDÿ°Ý3'tRf‡,­"ü¼/¾ô·JÂñÇÿgyø{¹èâÃÿŒ¸/€ˆ4äCpôý>€Ñr„­þˤªò‚·uyÅm©V¹p+€„ÞY±]`{ÏGNˆ•'Ÿ|òUò€Èºj.˜ÇêÄY'šïü¿]† Ê^ <­8"Pæ9Þ^|ZOËÉ£!ð ”“RR]&ÌSéB«§RòTUuÇ–Òÿ¨Shö‰Äk!‰6»2)ÖÓÜ:X¾”rÐ-X_!]ä鹄uŠÜa®úu]äu9ès1É|RÑ ÁÿÛ‡~»&à•?ætÌí˜ã1×Ëõ½~i«â GLZøÓÔ-I±bníAfv=Œƒ…ç†khò Ø)ÐiËËç‚?üùÏ~í/~ñ‹£ä$éˆÝ^½°AP½p跚уG›?Üü³hÉ"Û«Mä—7É2½Âj§¨D\þ—ÜæÛ dJ„(BH™—«ª1?§û[(OëUÀs,T‹F 4µÏݦ9µ•”ÚRõØûRõ¡WH—y¡ž“ç9ÚÖzäõ×2aQç‹ÌÖåd#4ÿù¹ÿ4“FM∪Fñ®¿ÌåFnlÄÜŽ9^+ü±ýÏm®ú1:=ªõ»–fZeP»è? (½µ´çÒN€†çž{îÝ3ÏtX¦}u½7Q×õ@‘Aòìü4w°)˺2ÞÙ@¾Î nž0z‚¹ø»›!ý†°ÕªQ,Üþ]tÑ­<òÈÒ˜ž÷9ß“"/tˆjTöhØ~ØSµ±T»âVíÀ8ê@ð$Å :áÉ O„ü(ÄUW]5 Z«Œå·_ý­™5eVã…$#È{.#Âþ†;%ñ*Ïw2æ¥^˜ú"‡¥´µBžù¤º Ê"mœ¤£-Ú®-ô¹¾œc-Ål(¥,Û+¦ =îy&éêzÈ»nðÚ÷sHXú±œKÛÅÞï§œí»´­u‰læŽ3ÍÙ'œÍV«Jø›«¯¾zÞí·ß¾Pä|йž1~½ìàiP9H¶êОÐ@vyw¿q0q7œx¦I‘Gy‡9sæü»S§N<òÈ}à Tû™´qÊçN1Û ÙÆüéŽ?™upJ®A< Ï$øçx:¢·:@ÎP®eŽ·»VÕUÀz€´æ­0øS,?PÉhVcžÛYv¸Ô:›£WHWçicri ÔzŒ3RD`™¤ˈ.ç@gçNÍ×øºùâî_ÌÕQå¿ü¯½öÚ»¯¿þúK“ ú\ðab×Nïû.M«Ty$µ«¾M8ØP¯â”˜ã "Öò ŒZžÇËIôl—.]:~øá{ÖÒ 8l×ÃÌŽÛìhΜs¦yù—]\hè!GâxûZdÔ¡^Šm?BÖL§âÛÍ•hü[,¿Q3rÑõcž·ÕîQ¹í¤•+&óuÚñ¤1væè)ƒœy¤x©KP'³u ?zøhsêO5c†ŽAUüo¸á†û®¹æšg¤Q‚?(‚¿~ì üA¨]ÛZýËØ,Œ€¶ú n`,<5yq q`ùN'¶zàýÑÔ'ßµ'Ï•W^ù¤x’÷âÄ®åí€QƒG™ OºÐnŸa4~[ #â)©xôÏëpôšRWËÀ#’å4u˜©®#Ì‹éhZY@Ÿ‡…øjöG·ÛÜvXV—£ 4 :OçS}ÇÛ9+x%ósI(c],ëž3²°Y8ŸˆÈÎ?"ß{ÊÞæ’ï]Ò"à¹s¶t‡à¹s:çy‚?ænûÓ VÐp£‰„crÂÚYÍW&šIDATVþ·Mìð¨}úâTÅ4-rMæã^ÒS ëŽ;â ¿&·ÐÎi‡Ÿf>3ö3æü[Ï7K—/µ½·¯ ê^¢ç2jÜ.Àý«‚¹œÜ¨y:Û0ÃQÈh5fiËhʨOJ´|êµGJ۴DZ·Õ1gqL“êH’цÈKÊ×2ÇÛU¹.žz x[6I‡2¡Ôéß§¿9é“r_:e{U¦jå¿éòË/Ÿ÷׿þu¾4©ÁŸ J9®þ üMÜ›¶þ84mÊÀ€'ðŠH*C¤mÀ‰'à›ßüæµv¦ï0Ýì¼íÎæ¬›Î2÷>{oî™ !FCªF柀 y¹T®ŒðÖa`>)ê“`ˆ›+òNÏÖÍË<=QÇéRg {˜S¾pŠéÕ½ºßNáA5øËÓþ·ü…«~:…ÀŸFG' M®üiÇ6çp`Žò@RŒÌ !‘¼¦ZÏò8Áäk’ø¢ÔÁâtÄÉß»7¾,\ýУkó“#~b¦Ÿn.¸åóþ'ï[PõŸäÅHƒgòvÐEèÈýĀѦ¥g”E@ÍCÆ4xÖ©e¡ŽÖC´@½[ <Ÿ+鯮Kó…ê„^¨«ÓŠ÷×7ê£<‰j™â ê¶,卋އPê Ü| 9éà“Ìžö„F;ð‡üH?6ž}öÙ7ßÿý¯Iã\áìµ ·ýápË?iõïÁ¿fj¡†Zåo”b+õP Ô¹½Êß åotž¿Àß°¿ rüŽxPäõ˜:uêÈÿøÇŸÇ[øí¼б#ª®MhXÛ`.¾ãbsó?ont¼…"ºFp¦^(+”Fž¿+ÀºrâÆº™n ëjNÙ¨-µ4èeY7ë%-V7õHµ>eŽæ>ô‚ü‚ièJôu¸´m޼¢ÿƒv=Èœxà‰¦g7Lµ øa¬üñy_ù…¿òá¶›{ì±7¤u þ~M™Þ÷Ç¢o‰…«; joý·ôo´YG/Å ð3b¤‹D8pàÐÀY­Á?Ï 7nÜÐÙ³g.o X'@)R»ðä«Ošsþ~ŽysÉ›€ý}|E÷¸ÌeIi-Cx-1åò—õ{ALu”Ñl,ÒŽ,P«vહÔvtŸ4Ïò”9êAùÌÓ ´û/ùËä¶À(áM·nÝjöš ÚÓaþóÍåw_nžzù)+Nsü$Às±$GµjÔ¼m±1ß;aê’S'©~æE-Pª0½W#¤Õ›&gÒò•ܯÐY&lÊY¦•<ÍCOë2­(Ûž¼ídó•™_1¶žÀÖjJ±å‡ýd»ÿµÿþïÿ¾MX¬è¹òàƒ×À_*øÃ¢ˆyMÁ_Ú;²Õ;Ô$NÀðRÌ àÃ!øs'À;ßûÞ÷>³×^{íÐmI'Æ|ðùÍŸnÿ“y{éÛv”Œ1R |;  Ë:¨„ÀLªeà\~ž3€<]Žº¤…ò¨ÒrÊ„uÄt뱬Ö=.ÔnZ^š}ò,HkyPòs(ÓùÌZð»¾pÅ?tÀPsÂA'¼‚ÜRà>ÝsÏ=Oýñ|Xú¢ÁŸ+ÿÐ €CÀ‡ý@yÏ_¯ü ü¤5ص¥wÚúk€°qRÀåHM ú’¢e yQNЇÞyç:ê¨âµvÀ«={ö4µ~8Ý}ûÝm¼ù±›Í•w_i>\.?…‘(ÑsðŒ‰¤ùmÿÁ!ê’J±&õhK"àÊøIÈÉmÝ9Ü_곌Πy­Ë<´Ó’¡¥Ûoɱ·ç¶qÜ›sì]]h¹æõ5¥íL¹ÖE>Ò.æÕM=•ïû-2?>æsÔÌ£Ì禕ÿpšîf9<ŸôÇÖ¿ð›äCl÷Êo³<'u%?R‚?€’À¿œ~¶…2mþ!Àð ©]dJŠíà;ÀÕ>Wÿš2¯ûöÛo?äç?ÿùçd +„ÚRaåꕎÀõ\o>YõI#èHA1AWù©»ÔÇà¨_ˆóTºÉ.òt½9IùÑßRB–m–Ò^Ô©ŽJ=ÞÍi½X)ùy€¬Û õ‘eЧŒàÖ!ùܺ·Y¬‡åÒþÍzmf¾0ý æÐi‡Öôc>zàõÃ~²ˆZ+óèMÏ?ÿübÉ*þ¼%Š{ú+Wþ¢Û"«´ÛÒ;íÎpF×Ó;øR};€ŸäXG G=eGà°AƒõG›-}K}À.Àܧæš9Ì1ËVÊ´¹Ž˜ ˜FÞ;Ì×<Ê2¤ñÈ×yÔ'Uy‰Î'¶}Š"¨ØáyV¨ò=ÈCGÉÃ"Mò´n_H&y¶]èP¯ï¿wø÷Ûi?3 Ï€&ݬ¥€[þhóý÷ßÿPžôÿ«È¸½¯ž«}PÈI¹êoàqF †ÏÀà ÍØ àk‚ØÐß Ð@È# Ýî§žzêÓ¦MÛÏà£AØ ¨åGƒ8^M?^ù±¹óé;Íßþ›YüÑâF W€›þ¶êMu8 QÓø0Ï6èSVMtʨ'i_Èò¤¡k€MʧŒ×Ó ¡L§‹ñÌêA_׉|¥cy•&ðé?ĺۡfß÷5ýz÷C -°å/_Xµ÷AÿäÃ> ~õ«_Ý/ '­ü ú~®úéð5¿º]ùÓØÑh! D'_ ? ×àÊ@­Ã0kÖ¬må7ö‘g:ÕÃ-é—w?{·¹ñ¡ÍÂ76:È%`kªù@'hC=¶F¹.›”WHVJu8ñ1i´@%H:Ÿ’dl#)/”é´æQÓŠ¦‚>õ•®–ÛnËíÌç÷ø¼™9y&{Ù¢ïõüAeûƒ|Óÿ®¹sç¾$Â*^ƒ¿} üüü¼ç¯ßóÇMX†TØ–Ûö·»?ÑhAÇ L'€»¼%@'@S:v'@nlþë_ÿúàôE»õpKý`xò•'Íœç˜Ç_x<üCÐf:‰:Y¢3€†Â2lœr¦IÓäÈçDWH‡õD-PŽxŽ*[H'-/”3MŠöoWí”QžD™.·óØí=þÆìTh45ÍÓ[þ|ðÁ²ÓN;íï²õû„+‚¿¦à©Ç-ÿVþ0vtZØpAÃø¤gð­ìp7€r°#`G»É í:}úô rK CK~=Pú“^|çEsË£·˜ûŸ¹ß¬\ƒÛohPÆP¦]™Tg@ë‡<Ò l›éH£ZÚZ‚mZ_Òòµ\ó¨‡i¡þdJn›KJSuÙFG™^Ýz™é“§›ƒv9ÈŒ1Ö­‡?úA?éë¦xàß¿ÿýqÕO`'àsÅOJð‡>ÁÛýpøqP®øIET+Ûù€:pp0vu~8¸~0(É HÚ€ Ž€Ý9˜(§W'åWT "îû ]#»¢·=ýôÓïJ÷útð:jàOÞïÇÖ?¬ÃoûÃB´b‹=í/}H ѨG§'Rž à-€Z'@€¿›<è2k»í¶‰¶ñùà–úfÚ/¾µÐÜùÔæž§ïɽFHe‚®¦ä¡Cž”åtÔø[)ùZìëÌÆD´@•-à!$h‡rÒ Û&ƒ<ÖÈÔyäIu]Q®(ëÂk|3&Ï0³¦Ìª«Õ>‡€U?îõãÝ~„_|ñMYÝ!ŽATƒ~Oýð~?ïù·ð‡¢PG€; ®À3b@ïÀ à-€:ä–¿~Þ  Ì:(sÈ!‡|ê¸ãŽÛSntÂnž W%«þÂòUËÍc/>fîzú.óØóyËä­êi½4Ša!“õ(u!¯^ Iu9Ê Q¶§uš[‡.ùÖo¤s¢”Q•RN`ȯêYgR9ÈÒä(Ç~w³óv;›áì:¡® ¶ûù#>ø¢Ÿ¼ÞwïÝwßýštš+x½òOrüÔC9Æüa9‚¿wÁêüq£PÇ€;@FÀÓÐ;tø†œ»\íøIµ2[Ïüìg?›1iÒ¤m°šÆ›¸-€µ†°¢a…ytá£æŸ/üÓ<ûʳ¹ß @Ç•ïAX[]çƒ×!ÔÓy‘(dn!´¼´²¡¼PšyB½Óìdø&ÿøÑãÍ®ãv5Ó¶›fz÷ìÖ“º’¯]»Ö?ÞëǮųÏ>ûÊìÙ³ïu÷ú5øà¹ÚGšŽy®ú üXñëU?Wþ°kÖþèhtêÜpIà xíÐÐÒ €×àÏ¹Þ °»'NrÊ)§ÌêÓ§Ýà„Z⇅¤e‡‹X‡ÎÀ¢Å‹Ì' ò[ ΪÞ)Àe¬-è1ii’^ž‚J4GWËŒu“zfõÅŠªkæ¯$ÝB2É ÁƒÙ¬ÇffÄ#ÌÄm&šOý´ÙaäÕcƵó!??ÂòåËWuÖYwÊþïI’ÀÏ-R‚¿~:ü ü¨`ßêÁ_Æ€Zþ0 ^nnR±ú‡€H'€Ï`ÙÎÝ:x þz'€ŽËt=þøã'tÐASð ”óŸö÷Ú!lEañÇ‹Íü×ç›—ÞyÉ:ø¹â%-1ë7ÈuÔ”qRe:mÌÅòÓÊEyÛ·Ï¡rFZ¬l˜¦]›;v6ƒû6à 3#‡Œ4ÛßÖŒÛjœÖX9½jñ2Xåó3¾è ò»õÖ[Ÿ¼ì²Ëž‘$ÀNàç _S?õPàOà'øÓ€•…­ß‡ýlçþÄ€V°ÀãVÀ   w° ÀH@Àä5ðÃ9`šù Öðï.·¦O˜0a”¿ý€vêõméw³Ãk‹_3¯¿÷ºyké[N~£?^ôá'šÕk1'”²ÿ¬ê)¡ËQ¥ÊHâ²Z̓šôºwínúõégúoÖß é7Ä 8ÜŒ4ÂŒ<Òl3t›ô‚­,ÏòaÅï¶û7=÷Üsoȯ÷Ý+i\°p‚>i¸ÚGšy ˆ~½òçŠàÏíþ¼#ÒZ¶ý¥ÿ>D 98j@H«uDîð–€v¸#@ªðÐEžw¶Þzë~òãB{ :Ôþlœ€Öô|€Œ¥¬°jÍ*óæûošV|d–|¼ÄÒe+–ÙÛ «V¯2+Vè¬]/÷×®1ë6¬3ëÖcî™dÝZ³a#探J³@§ŽL×θürßçèÜ©³éÞ¥»éÒ¹‹éѽ‡éݽ·ýÉÜ>=û˜¾½úš¾½ûšÁý›þ½û[ ïÙ­þÜ-ÍÉZú>?4Þ}÷ÝÎ<óÌ{^ýõ$?ÒäC@¯øCðÇŠ/£~ð>´FðGç£ÐÊžq#@ð'ÕŽo h'€ŽžN@¥.[Çž{î9ò„NØ£wïÞp샂øš >&C´@´@´@5,€øà+~Xñ#¬X±bõ%—\rÿ}÷Ý·H’ð¸özpO‹ÐÓàOÇAoùkà'ø“JñÖ·åo;­þD •:8† N€Þ €@G€;¤uFíäõN@˜Ç2 ]¾üå/;ôÐCwðG::0B ÑÑ™Z ~qÖʇ|þuõÕW?/ ¸I5°àAõ.uX”ÀO ðØ3r»ßßÔi­«~“ÑhÅŽb'€»¼@Še: æ~Æpr:ÔaYÔÕåßøÆä™3gNWí@{¹5 c!Z Z J_¶þ×Í›7ïß_|ñÓÒ$€‘ Ε?ÁTïh–Å–ê⊟”«ý6 þ2Þx  µ¼€ƒU($8Xý#øÃÝ€b·ðÚ(ä@×:'žxâŽ{ï½÷xíà¶nÄ---PаÍðçV?€_>â3ÿ /|Jʬ5€k`׫~‚?t)×å¸ÚGˆzÕN€M´…U¿ˆûwZù@p0±êgàíî€r€4i7€Î•¾~½ žz t@;Ë«ƒöÝwßñòA‹üøvvZÃW¥ÿ1D D ´€ð:@ïô#Hzµ¬øç_zé¥ÿ–$à®ú5¸sÕ¯) üà ú~®ú±Ú'èså/¢Ö¿ß"ø€6äàØ;i€;úÙ½‡€€ð:ig€: (Ï::ï·ß~[éK_šÚ¿ÿ>"·¿:ˆŠ!Z Z }[?ÐàÇŠŸáÃ?\~íµ×>qÇw¼.2 ü€:@œàŽÕ½vôjŸº, ‚?ŸQ;"Î…¶¶ò縢ÐÆu`ü à¼à¹ @ÊÝ â÷$g2¡ËÈ:lòUÁAòœÀ®Ã‡ÈaGŸÆk„1D D ´/ à;ýxÛüø ÏÛo¿½Tîï?"Ÿï}_¬X3êÔÛeРA=¿÷½ïM;vìÙ @›6ÀÀs­í3Ãì¤ÑÑÅ-€­}Üßð3ÈÊà /¼ðæ¹çžûèâÅ‹WŠœ+t‚6A”«y|Õú¬ƒu èsÅJÐïC[]õû €6ìð@ŽwèèÝ8k€³]½  '9ôµ@¹.—çH}?üð1pÀøl®wâCƒb¢Ú‡ú°Úÿàƒ–ÝvÛmóo¸á†—e¨\™“°ä¤øéü™iÖGÐ×´Ý®úÅ.>D 88Ú‘v¸3îØÕ»ÈAêaÔàO^;¡# ëë¼Å[ô–ÛSÆ¿•ì φø*!-i´@ë³VùØæç?F ²õóçÏC¶ùŸ|ï½÷VˆM&pøCp/útXë%ðsµRQÉ…ö°êçXA£ÐNôÀлtÒn ¸¹š/¶+: ttyÔé£ìl-?<´Ã°aÃÈC‚è Ñ %"¨_ $¾<ä·é]ùTï-·Üòœ¬ø_—Þk`&Xð äš~–#Õõkàèø¹åjC{~Ž;:íÌÀœˆ´#ÀÝì„;I·è|½ ™NÓi ¥SáÑï$௠n7cÆŒO 8·òœÜ&ÀsJ,Åbˆˆ¨¥°•Ð×ïì£}‘oZºté2ùDïKòµ¾Ä 8Œ58C†4€¼¦à¹íOG@§ ö,GG‚mhàŸºÝ/y¦½‚?Æ€vèàÀ#$8îò¶©n:¤tŠQê“ê:ÑÒdõßùˆ#ŽØn=ö3dÈ~zg¯bwÎh ÑÑÕµ¶ôú x…+}yˆï£xàåë®»n¡ä”5 ¤IC'Тº xÖŶü \í“Ò `—Û5ðÓÑhÇ€: ü [dàuä-Ríu5ü!#ªÓ!z ÓÔ;"·íî¿ÿþ[í³Ï>ÛŽ9r¼B}øÁ!8pâ7Md¢šm¬ðò|~ ‡‰|Ýo¼±ô®»îzñöÛoCä€ Ê¤5hè!Kâ!Óy¬‡u ÍÈvö:ê­þv¿Ý/¶i¢{R$ìh'<ÒBŽAM 'ÕŽe¤ºx¦u[ä;ŠÐGÞ&;nܸáò6A}ôͽCç :Þ4‘‰hb>@ž€¯WøP–ôFyzù‚ Þ–§÷_X´hÑrˆ%€Èä5PƒgZ;åt’òXŽ” ¯ÛÒ >øEWý0‚ ш€:o hG«€1d kP€9)2C'€€ÖÏò¬i¶£íÃŽ;î8pÖ¬Yc$ ‘¯öÐÏsDß~k· ðw ¢cËÄÐ^, çêž÷ïÃÕ=l!²òU¾¯¾úêbYá¿üÔSO-…X¢}~Ìl‚<)Aiò¤Ô!EàÑ)Ÿ} øs‹_ƒ¿Ë…ö|ŸŸ6H¢Ñˆ@Òy‘ô|ú¡#@'€€L &Xk0Ai:Iy¨ƒåY/R¶O yÇQ£Fõ‘Ï–m1xðàÍ{ôèÑUÀãhà b§@;)êMÊGA´@=Y€ O Àã¶|îÖ|ÓžŠÞ¦†††µK–,Y&æyO>Ãûêk¯½¦Wø\:bMÁ#¬I 暦¾.‡vX( ¶¿¨øûþàmˆÀOK$ÓèD ùÌpÒ”[ZP:à5Ó HÄÁÌIþyÈ’"óéhÊúÙû ûýì4yòäþ»í¶ÛÈÑ£GË 7ëÕ«W7~”M pàÀ1`„LGŽ-i–3€×[õŒx­Ë2šŠÎ†•+W®‘'õ?‘ÕýÒ‡~øMYÝ :W®¤5Ð’E$ k€&¯A\ƒ¾æ¡ 'Të£n¤ul” Ê~ F('D :%7e:c6Zƒ7x:I4I¦ËüY'Û eûtBjyh°Ó´iÓ¶Øa‡m¹å–}Å1è#¡;2ÀïA½¤S$*Õ‰àˆC°A>ijnùòå«è—¿õÖ[?ÿüóï Ø¿'÷ø ¦Q ¬ä©£<”i â!¨ÊÓu±>Ö Š¾²_ì³dEà‡* ш@³ÎŸG@ÊHµ+n‘3MP&h‡`YúðužÖe]Ð%ŠˆöICië8=ò‹¥òúaI“& :thoùráf›o¾yÞ½{w—[ ]ÄyÇ ºàuE|¿ "‚«7>x(†ˆ¡ùP«xa7m@·Q¶ò7Àñ¾lÙ¯[±bÅêeË–5È—õ>‘î¬xæ™g–Êëx Ò"€RG(Á“” -A‘àLÀ¦Œ«õ4‡¾Î ËézÙ(û^÷U¼q«ß›¢YL»wše­¨¬-Ó G‚+Ò`‚³¦\Åk§S ­—Ä£NÖ¡ë¯ÛgHÑoðI”c ©¨[ý$ Y ÑYY€€—DC`d: ô‘G€%%ø"M^S ÔÚ ¸SJÊk^ëèº5Ïþ²¯©Tíd1´€”“Zv똨chà…PDàÅID<.fP-.x‚1d!H#M`gÓvÖ<Ë&QÖÅ6ÙÈÁ£àu_Á3M>¤¢bu’(d1D Tj^kI”צ¸æ˜Ö`ŠkrÈÀ3<(#|Õ`Nžº:­e¬WÓ°}¦Ù÷Jw|@^ ­Ü˜¼chÝà…`DàE«’r\àc k@&H'Q‚?óüHë¼49ËišÔÊÐOð!‘—ƒÇ ä1D Tj^_¬‡×å ¸®@™)Á×yP È!¯ÁŸ¤µ <Á¦#mcˆ@; ÁpxÖ2È™&؆@«ÁXókRäg:‰RÆzŠ¥¡§û}¤u„eä­0þ‰ÈÀ¼FôõC@¥   Ê< ¾àCPNJSFÊrHk™–‡íè´îy©ÊÏ…!IêÄt°@tÚÀA,aú‚P"@F9dà™GàEš¼¦à“b1@ó“ê L·?t¯£$}ÿ!×!Lë¼ÈG „àuA9Óš‚gà’PƒR®¹ŸðZ?Ì×yàÃ6Ù'ä!0 †$Y¨ÓmÌÑhc´„áè ÀȉA§É'-eæ´™.DQ±òÐa[à“Ò!¤Ñ\nü-Pžx½$Q^7 `ʘe¤ó´£@$Šr¡n(c»¤¨iòVèþ /†vlè´ãƒ/C×”iRÊ4¸1‘" ]ˆê<ð:]¬Q÷úÐ #ò!cÐ|!ó" xî3 ªeäA“"ù¥Pèh=ͪƒyRÜ—¯û…´È‹!ZÀZ :ñD ôÄ@åD‚.&'ð¤Ô% # ²RGSða:¬‡: a:'ÍÉÉSO§#-PÈúZ€^RZ_äIqm È!×¼Nk9yM“êŒm‘jx C´@ D ‰I¢@, ' ‚­žh`¤|1iQÆüBÝRóµ.Ûe L§ÉG-P©ôõ^LS‡à6Ékð#”š]]GR2Ø-‹|´@ž¢gŽ˜H°@8‘x9!±A˜ù‡2î„yZOó¡^Rš²$ Y Ñ•Z€×@HQ/¯GY˜OyH©GÇ@ç#!I–ËÉýE~ ÑͲ@tše®¨,'>'(‰r:äxv€é0?-rIe(×|¡À6 éļökðÜN³õ’hx0­u)Cý䙯eäAàõü˜Ž(ÉÑ(ÉLQ©€’&"-夨‚Ræ…r&]¦CšË£ªcžÏ!ek‡y:MúäCʺH™Ït¤Ñ™X :™˜1VX iÂPSNÊbq¤É“†:”“2?–ª—V>ÊÛ§Âs4Í Ô )õ“ä”QGÓByZ/òÑ[ :›0VP¢Ò&6´ÎÓ<«A¼Xšå"¨†Âs´X:©a™$(‹¨ª¢PUóÆÊK°@9a9eJèJT‰ÈÄñüÌÄŒ±’j[ Ã¦Mñ\­¶‘cýÑÑÑÑÑõf¾‡]oýŠý‰ˆˆˆˆˆ¨¢¢PEãÆª£¢¢¢¢êÕѨ×#û-----PE D ŠÆUG D D D D Ô«¢P¯G&ö+Z Z Z Z Z Šˆ@«Žˆˆˆˆ¨W D ^LìW´@´@´@´@´@-€*7V-----P¯ˆ@½™Ø¯hhhhh*Z :U4n¬:Z Z Z Z Z ^-ðÿ•36¹IEND®B`‚olive-continuous/app/packaging/windows/000077500000000000000000000000001370472574300206125ustar00rootroot00000000000000olive-continuous/app/packaging/windows/nsis/000077500000000000000000000000001370472574300215665ustar00rootroot00000000000000olive-continuous/app/packaging/windows/nsis/install icon.ico000066400000000000000000001353661370472574300246570ustar00rootroot00000000000000 hV ˆ ¾  ¨F00 ¨%î `v–D(    rirg[g…†…Xz†z¯rƒrÇrƒrÇrƒrÇrƒrÇz†z¯…†…Xg\grjrgegkYkˆ’ˆzR{Rñ"b"ÿ]ÿ]ÿ]ÿ\ÿ_ÿQxQñˆ‘ˆzl[lgeg¨®¨š›šAV‡Vî i ÿ j ÿ j ÿ j ÿ j ÿ"t"ÿ1z1ÿfÿU‚Uîš›šA¨­¨  ã ‘£‘„-…-ÿ~ÿ~ÿÿ*ˆ*ÿ11ÿ±ÿ–¿–ÿ!ƒ!ÿ'{'ÿ „›Ø› ÿŽªŽ–-•-ÿ’ÿÿ&™&ÿ‰À‰ÿ|·|ÿuµuÿ{º{ÿ&•&ÿ#‰#ÿ‹¥‹–ÿ)ÿ)”²”—6¦6ÿ£ÿ"¤"ÿc¸cÿŽÆŽÿ˜Ç˜ÿU²Uÿ6®6ÿ£ÿ,™,ÿ¬—ÿYÿY›»›—E»Eÿ.º.ÿB¼Bÿ›Ð›ÿ”É”ÿžÑžÿC´Cÿ*±*ÿ+±+ÿ9¦9ÿ–²–—$ÿ$—ÿ˜¤Á¤•[Ë[ÿJÐJÿeÒeÿ‚Ù‚ÿ§à§ÿ£Ý£ÿjÊjÿDÂDÿBÁBÿL³Lÿž¹ž•dÿdÆ÷Ƶȵ{{Õ{ÿwÞwÿrÜrÿdßdÿg°gÿj°jÿhÞhÿeÝeÿcÚcÿnÇnÿ±Ã±{¼ë¼ÐÕÐÌÌÌ1§Ö§ãçÿ‰í‰ÿy¼yÿmsmÿmsmÿy¼yÿ„í„ÿâÿžÏžãÌÌÌ1ÏÔϽÂÞvÞÎ×Î\²Ü³â’Á’ÿ{‚{ÿyxyÿyxyÿ{‚{ÿŽÀÿ¬Ø¬âÌÕÌ\÷‰öþÃâÍ⬫¬WŒŒË‡†‡ñˆˆˆÿˆˆˆÿ‡†‡ñŒŒË¬«¬XèÑè666€~€wuwŒ‹Œ–––º———ÿ———ÿ–––ºŒ‹Œwuw‚‚111¥¥¥¥¥¥¥¥¥µ¥¥¥ÿ¥¥¥ÿ¥¥¥¶¥¥¥¥¥¥²²²²²²²²²µ²²²ÿ²²²ÿ²²²¶²²²²²²¼¼¼¼¼¼¼¼¼µ¼¼¼ÿ¼¼¼ÿ¼¼¼¶¼¼¼¼¼¼àÀÀÀÀÀÀÀÀÀÀððøøø(0   ‘‹‘747tqtS‰ˆ‰ŒŒŒ¥ŒŒŒ¥ŒŒŒ¥ŒŒŒ¥ŒŒŒ¥ŒŒŒ¥‰ˆ‰tqtS747‘‹‘ÿÿÿmkm0“–“¬zŽzðUyUþGqGÿGpGÿGpGÿGpGÿGpGÿGpGÿUwUþzzð“–“¬mkm0ÿÿÿœšœvsv,–ž–ÊMzMÿYÿVÿWÿWÿWÿWÿWÿVÿTÿUÿLvLÿ––Êvtv,œ›œHHH0*0ž¢ž P‚Pÿ c ÿ g ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿhÿgÿgÿ [ ÿO}Oÿž¡ž 0*0HHH˜‘˜2… …èsÿuÿ t ÿ t ÿ t ÿ t ÿ s ÿ t ÿyÿq¤qÿ³ÿR’Rÿ n ÿhÿ…œ…蘒˜2Ö×Ö­©­\f™fý€ÿ‚ÿÿÿÿ"Š"ÿC“Cÿ†ÿ|³|ÿ¹ÿ¿×¿ÿb¦bÿ~ÿ t ÿb‘bý­ª­]Ö×Öëëë³±³j__ÿÿÿŽÿŽÿŒÿa³aÿ‡º‡ÿZ©Zÿ¦Ë¦ÿI Iÿ€¹€ÿNžNÿ‹ÿƒÿY“Yÿ³±³jëëëîïîµ´µjd¥dÿ›ÿ›ÿšÿšÿ—ÿ}Å}ÿ°Ò°ÿˆ¼ˆÿx´xÿv½vÿŠËŠÿJ®Jÿ™ÿÿ\›\ÿµ´µjîïîòòò¸¶¸ji®iÿ%§%ÿ!¦!ÿ¥ÿ$§$ÿzÃzÿ†¿†ÿz½zÿ Î ÿÃÿ&¥&ÿ¥ÿ¤ÿ¤ÿšÿa¡aÿ¸¶¸jñòñõöõº¸ºjq¹qÿ1º1ÿ-·-ÿ)²)ÿ9µ9ÿ§Ø§ÿÈÿ‰Æ‰ÿ¸Ú¸ÿ…Ç…ÿ*­*ÿ)°)ÿ)°)ÿ)®)ÿ#£#ÿg¨gÿº¸ºjõöõùúù¼º¼jyÀyÿ@Ç@ÿ=È=ÿ8Æ8ÿbËbÿ¢Ó¢ÿ¨Ñ¨ÿ¬Ó¬ÿ˜Ï˜ÿg½gÿG¶Gÿ6¸6ÿ7¹7ÿ6¸6ÿ0­0ÿn­nÿ¼º¼jùùùøùø¿½¿i…Æ…ÿRÑRÿOÓOÿVÒVÿuÖuÿe×eÿ‰á‰ÿ´é´ÿ½ë½ÿ£á£ÿgÌgÿGÄGÿHÄHÿGÂGÿ@¶@ÿx´xÿÀ¾ÀiøùøßßßÅÁÅR™Ë™úfØfÿhÞhÿ|Ø|ÿfÛfÿ_Ý_ÿ^Ü^ÿa²aÿb²bÿ`Ý`ÿ_Ü_ÿ`Û`ÿ`Ú`ÿ^×^ÿVÇVÿÀúÆÂÆRßßß¾¾¾Ã»Ã"¹Ñ¹Ü}Ø}ÿˆéˆÿ‘ß‘ÿtåtÿuçuÿoºoÿgpgÿgpgÿoºoÿuçuÿuçuÿuçuÿsãsÿoÌoÿ´Ì´ÜŽÅ"¾¾¾ŽŽŽÑÓѩթýŒåŒÿ‘ñ‘ÿŒñŒÿ€Æ€ÿpypÿnmnÿnmnÿpypÿ€Å€ÿŠñŠÿˆïˆÿ~Þ~ÿ Î ýÐÒÐŽŽŽÌÊÌÉÄÉÓÙÓ£²Ù²ü›ä›ÿ‘Í‘ÿzƒzÿvuvÿvwvÿvwvÿvuvÿzƒzÿÌŽÿ“á“ÿªÔªüÑØÑ£ÊÅÊÌËÌonoÚÖÚÐËÐÙÚÙy±¾±ë„Š„ÿ€€ÿ€€€ÿ€€€ÿ€€€ÿ€€€ÿ€€ÿƒŠƒÿ¯½¯ëÙÚÙyÒÌÒÛÖÛoooŽŽŒ‹¦ˆˆˆÂŠŠŠæŠŠŠÿŠŠŠÿŠŠŠÿŠŠŠÿŠŠŠçˆˆˆÂ‹¦ŒŽŽ‹‹‹‹‹‹‹‹‹ ”””ž”””ÿ”””ÿ”””ÿ”””ÿ”””Ÿ ‹‹‹ ‹‹‹‹‹‹žžžžžžžžžšžžžÿžžžÿžžžÿžžžÿžžžœžžžžžž¨¨¨¨¨¨¨¨¨š¨¨¨ÿ¨¨¨ÿ¨¨¨ÿ¨¨¨ÿ¨¨¨œ¨¨¨¨¨¨°°°°°°°°°š°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°œ°°°°°°¸¸¸¸¸¸¸¸¸š¸¸¸ÿ¸¸¸ÿ¸¸¸ÿ¸¸¸ÿ¸¸¸œ¸¸¸¸¸¸½½½½½½½½½š½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½œ½½½½½½ü?øðààààààààààààðøü?ü?ÿÿÿÿÿÿÿÿÿÿ( @   HGHDjijqtrtƒusu„tst„tst„tst„tst„usu„trtƒjijqHGHD a`aO•”•±¢ç›ø‡—‡ü†–†ü†–†ü†–†ü†–†ü†–†ü†–†ü‡–‡ü›ø¢ç•”•±a`aO 444 ƒ‚ƒ}¢§¢ël‰lÿ-b-ÿRÿ P ÿ O ÿ O ÿ O ÿ O ÿ O ÿ O ÿ O ÿQÿ-_-ÿl‡lÿ¢§¢ëƒ‚ƒ} 444‰ˆ‰u © ô?r?ÿ V ÿYÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ Z ÿ Y ÿUÿ Q ÿ?m?ÿ ¨ ô‰ˆ‰u¾¾¾sqs=¨­¨äByBÿ _ ÿ e ÿ f ÿ f ÿ f ÿ f ÿ f ÿ f ÿ f ÿ f ÿ f ÿ d ÿ d ÿ a ÿ ` ÿXÿAsAÿ¨­¨äsrs=¾¾¾¦¥¦™u˜uÿ h ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ p ÿ o ÿ o ÿuÿLŠLÿ:‚:ÿd™dÿqÿ h ÿ ^ ÿu”uÿ¦¥¦™mmmhfh­²­Ö:;ÿxÿ{ÿzÿyÿyÿyÿyÿyÿxÿ y ÿ{ÿN”Nÿ°É°ÿÅÕÅÿ–¹–ÿ'}'ÿ u ÿ m ÿ8x8ÿ­²­Öhfhmmm¦¦¦””9£²£î%€%ÿ…ÿ„ÿ‚ÿ‚ÿ‚ÿ‚ÿ ÿLžLÿN•Nÿ € ÿq²qÿ•»•ÿ‡µ‡ÿÈÝÉÿ¥Ì¥ÿ..ÿÿzÿsÿ¡¯¡î•‘•9¦¦¦¹¹¹¢¢BŸ³Ÿô#‰#ÿÿŽÿŒÿŒÿŒÿŒÿŽÿ¨Ó¨ÿi¨iÿ.–.ÿÎäÎÿ{³{ÿ1–1ÿ_©_ÿJ™Jÿ ‰ ÿŠÿ…ÿzÿœ°œô£ž£B¹¹¹»»»¤Ÿ¤B¡·¡ô'‘'ÿšÿ—ÿ–ÿ–ÿ–ÿ•ÿ)Ÿ)ÿÕêÕÿšÂšÿj¬jÿ¥Ê¥ÿZ¦Zÿƒ¿ƒÿÎåÎÿ¨Ò¨ÿF¤Fÿ“ÿÿ‚ÿž³žô¤ ¤B»»»¼¼¼¥ ¥B£º£ô,™,ÿ#¢#ÿŸÿžÿžÿžÿÿ4¢4ÿµÛµÿ“È“ÿ•Ä•ÿºÿ`­`ÿ\º\ÿC°Cÿ$£$ÿŸÿÿ—ÿ‰ÿ ¶ ô¦¡¦B¼¼¼¾¾¾¦¡¦B¦¾¦ô2¤2ÿ)«)ÿ#¨#ÿ § ÿ § ÿ$¨$ÿ‘Ï‘ÿŸÇŸÿ|º}ÿqºqÿ—Ì—ÿÐäÐÿS®Sÿ¤ÿ¦ÿ § ÿ § ÿ ¥ ÿŸÿ$%ÿ£¹£ô§¢§B¾¾¾ÀÀÀ§¡§BªÂªô9±9ÿ2»2ÿ+µ+ÿ(°(ÿ'®'ÿ4³4ÿ»ã»ÿžÑžÿ‘É‘ÿ{¿{ÿªÐªÿÂÚÂÿU±Uÿ&­&ÿ(®(ÿ(®(ÿ(®(ÿ'­'ÿ%§%ÿ+–+ÿ¦¼¦ô¨£¨BÀÀÀÁÁÁ¨£¨B­Å­ôB¸Bÿ<Æ<ÿ7Ä7ÿ4Á4ÿ1½1ÿMÀMÿšËšÿ‰Ã‰ÿz¿zÿ±Û±ÿ¯Þ¯ÿpÇpÿ8µ8ÿ/³/ÿ1µ1ÿ1µ1ÿ1¶1ÿ0´0ÿ.­.ÿ2œ2ÿ©¾©ô©¤©BÁÁÁÃÃ餩B±È±ôM¿MÿIÎIÿDÌDÿAÌAÿBËBÿ‰Ù‰ÿÛÿÀåÀÿÏáÏÿ´Ó´ÿ§Ñ§ÿ¡Ì¡ÿŠÄŠÿ[¹[ÿ;¼;ÿ=½=ÿ=½=ÿ<¼<ÿ:µ:ÿ<¢<ÿ­Á­ôª¥ªBÃÃÃÃÃ짬A¶Ì¶ôZÅZÿWÕWÿRÔRÿOÓOÿkÔkÿtÖtÿPÓPÿ^Ø^ÿ‰ã‰ÿ¹ðºÿÁòÁÿ¯ë¯ÿ‹Ý‹ÿXËXÿJÆJÿJÆJÿJÅJÿIÃIÿF¼FÿF¨Fÿ±Å±ô­©­AÃÃô´´«¦«/ÁÏÁékÈkÿfÜfÿaÜaÿoÚoÿ|×|ÿ^Ú^ÿ^Û^ÿ]Û]ÿ\Û\ÿ]µ]ÿ]µ]ÿ\Û\ÿ[Ú[ÿ]Ú]ÿ]Ú]ÿ]Ù]ÿ]Ø]ÿ[Ô[ÿWÌWÿZ´Zÿ½Ë½é¬§¬/´´´‰ÎÒÎʼnˉÿsßsÿvåvÿžÞžÿs×sÿmãmÿnãnÿnänÿj¼jÿepeÿepeÿj¼jÿnänÿnãnÿnãnÿnãnÿnãnÿlàlÿdÓdÿ|¿|ÿÍÑÍÅŽŠŽGGGÿÿÿÏÍÏv·Ó·þ~×~ÿ‡ë‡ÿŸìŸÿ‚æ‚ÿ}ê}ÿ}ë}ÿvÅvÿkwkÿihiÿihiÿkwkÿvÅvÿ}ë}ÿ}ê}ÿ}ê}ÿ|ê|ÿyäyÿnÊnÿ°Í°þÐÎÐvÿÿÿHHH¾¾¾·µ·ÖÙÖÈ¥Ò¥ÿ‹á‹ÿ‘ð‘ÿ‘ò‘ÿòÿ„΄ÿrrÿonoÿoooÿoooÿonoÿrrÿ„΄ÿòÿŒñŒÿ‰î‰ÿ|Ø|ÿšÊšÿÕØÕÈ·µ·¾¾¾```ÿÿÿÍËÍ?×Ý×ܬլÿ”ß”ÿšðšÿ“Ö“ÿ{‡{ÿutuÿuuuÿuuuÿuuuÿuuuÿutuÿz‡zÿÕ‘ÿ“î“ÿ‰Ú‰ÿ£Ï£ÿÖÜÖÜÎÌÎ?ÿÿÿ```“““ÿÿÿÐÎÐ<ÛÝÛÂÆÛÆü›Ã›ÿÿ|{|ÿ|||ÿ|||ÿ|||ÿ|||ÿ|||ÿ|||ÿ|{|ÿ€Œ€ÿ–À–ÿÁØÁüÛÝÛÂÑÏÑ<ÿÿÿ“““dddûøûÉÇɼ»¼˜“““ÿƒ‚ƒÿ„„„ÿ„„„ÿ„„„ÿ„„„ÿ„„„ÿ„„„ÿ„„„ÿ„„„ÿƒ‚ƒÿ“““ÿ¼»¼˜ÉÇÉüøüddd‡‡‡‡‡‡ˆˆˆ‚‰‰‰¶ŠŠŠ³‹‹‹Ù‹‹‹ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÚŠŠŠ³‰‰‰¶ˆˆˆƒ‡‡‡ˆˆˆŽŽŽ‘‘‘ŒŒŒ“““€“““ÿ“““ÿ“““ÿ“““ÿ“““ÿ“““ÿ“““‚ŒŒŒ‘‘‘ŽŽŽšššššš~šššÿšššÿšššÿšššÿšššÿšššÿššš€ššš¢¢¢¢¢¢~¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢ÿ¢¢¢€¢¢¢©©©©©©~©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©€©©©¯¯¯¯¯¯~¯¯¯ÿ¯¯¯ÿ¯¯¯ÿ¯¯¯ÿ¯¯¯ÿ¯¯¯ÿ¯¯¯€¯¯¯µµµµµµ~µµµÿµµµÿµµµÿµµµÿµµµÿµµµÿµµµ€µµµºººººº~ºººÿºººÿºººÿºººÿºººÿºººÿººº€ººº¾¾¾¾¾¾~¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾ÿ¾¾¾€¾¾¾ÿÿþü?øøðððððððððððððøøü?þÿÿÿÿÿÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿ(0` $  (@LN N N N N N N N NNL@(888Vlll• Ÿ Ú§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã§¦§ã Ÿ ÚÂlll•888V 888O‚‚°¯®¯ì·¹·þ¢«¢ÿŠšŠÿ}‘}ÿ{{ÿ{{ÿ{{ÿ{{ÿ{{ÿ{{ÿ{{ÿ{{ÿ{{ÿ{{ÿ}‘}ÿŠšŠÿ¢«¢ÿ·¹·þ¯®¯ì‚‚°888O DDD^^^v¨¨¨á·º·ÿ€•€ÿ—>ÿÿ „ ÿ‰ÿ‰ÿ…ÿÿpÿ™¯™ÿº¸º½""""""»¹»½œ¶œÿ†ÿ”ÿ•ÿ“ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ”ÿºÞºÿêîêÿ77ÿ‰ÿ¨Ô¨ÿÃÙÃÿu²uÿÿ-–-ÿмŠÿ®É®ÿ™º™ÿaaÿ‹ÿÿ‹ÿ†ÿuÿ™±™ÿ»¹»½""""""¼º¼½ž¸žÿ"Œ"ÿ › ÿœÿ™ÿ˜ÿ˜ÿ˜ÿ˜ÿ˜ÿ˜ÿ—ÿ,¡,ÿÝðÝÿàéàÿ–¿–ÿƒ²ƒÿ{¹{ÿ­É­ÿRžRÿcªcÿÏäÏÿöûöÿÙïÙÿœÓœÿK®Kÿ˜ÿ–ÿ’ÿŒÿ{ÿ›³›ÿ¼º¼½""""""½»½½ º ÿ%%ÿ$ $ÿ"¡"ÿžÿÿÿÿÿÿÿšÿ+¤+ÿÚðÚÿ¶Ö¶ÿ©Ò©ÿšÄšÿŠÂŠÿp³pÿj±jÿ|Å|ÿsÄsÿP´Pÿ,¥,ÿœÿœÿÿ›ÿ—ÿ‘ÿÿµÿ½»½½""""""¾¼¾½¢½¢ÿ(•(ÿ'¥'ÿ%¦&ÿ!¤!ÿ£ÿ£ÿ£ÿ£ÿ£ÿ)¤)ÿ]¬]ÿ=–=ÿ¤Ó¤ÿW­Wÿs¾sÿ›È›ÿ†À†ÿ´Ò´ÿc¤cÿœÿ¡ÿ¡ÿ¢ÿ£ÿ£ÿ£ÿ¡ÿÿ—ÿ„ÿŸ¸Ÿÿ¿½¿½""""""¿½¿½¥Á¥ÿ- -ÿ,­,ÿ*¬*ÿ%©%ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ#©#ÿ•Ó–ÿüüüÿšÃšÿ‹¿‹ÿb°bÿ‹Æ‹ÿv¿vÿêõêÿêóêÿe·eÿ¥ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¦!ÿ ¢ ÿœÿˆÿ º ÿÀ¾À½""""""Á¾Á½§Ä§ÿ2¨2ÿ2»2ÿ0¸0ÿ*²*ÿ&®&ÿ&­&ÿ&­&ÿ&­%ÿ0±0ÿÍìÍÿäòäÿ‚Ä‚ÿ°Ð°ÿ—È—ÿe²eÿx·xÿ«Ë«ÿ­Ë­ÿZ¤Zÿ&§&ÿ&®&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&«&ÿ%§%ÿ# #ÿ"Œ"ÿ£¼£ÿÁ¿Á½""""""¿½©Æ©ÿ7¬7ÿ8À8ÿ7Â7ÿ2¿2ÿ/»/ÿ-·-ÿ-³-ÿ,²,ÿ2³2ÿ Õ ÿw¿wÿŽÌŽÿxÇxÿV¸Vÿ®Ø®ÿêñêÿëôëÿÆèÆÿfÂfÿ-°-ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,°,ÿ+«+ÿ)¥)ÿ''ÿ¥¾¥ÿÂÀ½""""""ÃÁý¬È¬ÿ=±=ÿ?Æ?ÿ>Ç>ÿ9Æ9ÿ6Å6ÿ6Ä6ÿ6Â6ÿ2¾2ÿ^Æ^ÿ©Î©ÿ•Õÿ{»{ÿr·rÿ±×±ÿÏëÏÿ Û ÿeÄeÿ9´9ÿ-´-ÿ/µ/ÿ1¶1ÿ2·2ÿ2·2ÿ2·2ÿ2·2ÿ2·2ÿ2µ2ÿ0°0ÿ.©.ÿ,”,ÿ§À§ÿÃÁý"""###ÄÂĽ¯Ë¯ÿD¶DÿHËHÿGÌGÿBËBÿ?Ê?ÿ?Ê?ÿ?Ê?ÿBËBÿ©à©ÿ·Þ·ÿÅãÅÿåíåÿÑÜÑÿ¢Ä¢ÿz¶zÿq¶qÿ‰Á‰ÿt±tÿ^¯^ÿg²gÿE®Eÿ:¼:ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ:º:ÿ9µ9ÿ6®6ÿ3˜3ÿªÂªÿÄÂĽ######ÅÃŽ²Í²ÿLºLÿQÐQÿPÑPÿKÐKÿHÏHÿHÏHÿFÎFÿrÔrÿžÞžÿTÏTÿd×dÿ™å™ÿËñËÿõûõÿüûüÿþüþÿÿÿÿÿò÷òÿßîßÿ¯Þ¯ÿS¿SÿBÀBÿCÀCÿCÀCÿCÀCÿCÀCÿB¾Bÿ@¹@ÿ>²>ÿ9›9ÿ¬Ä¬ÿÆÄƽ###%%% ÇÅÇ»·Ï·ÿU½UÿZÕZÿZ×ZÿVÖVÿRÕRÿPÕPÿiÔiÿŠÖŠÿXÓXÿQÕPÿPÔPÿOÔOÿZ×Zÿ‚á‚ÿ¡ê¡ÿ¥ë¥ÿ˜æ˜ÿ…à…ÿkÖkÿQÌRÿLÊLÿMÈMÿLÇLÿLÇLÿLÆLÿLÆLÿKÃKÿI¿IÿF·Fÿ@Ÿ@ÿ±Ç±ÿÇÅÇ» %%%ÅÃŦÃÔÃÿa¿aÿcØcÿdÜdÿ`Û`ÿ\Ú\ÿgÚgÿ‘Ø‘ÿcÖcÿZÚZÿ[Ú[ÿ[Ú[ÿ[Ú[ÿ[Ú[ÿYÛYÿY½YÿY½YÿXÚXÿYÙYÿZÚZÿ[Ú[ÿ[Ù[ÿ[Ø[ÿZ×ZÿZÖZÿZÕZÿYÔYÿXÑXÿUËUÿQÁQÿN§Nÿ¿Ï¿ÿÅÃŦÿÿÿº¹º|ÓÚÓÿtÀtÿk×kÿoáoÿlàlÿiàiÿ—Ü—ÿvÔvÿdßdÿfßfÿfßfÿfßfÿfßfÿfáfÿdÂdÿctcÿctcÿdÁdÿfáfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿdÜdÿb×bÿZÈZÿe±eÿÑØÑÿ»º»|ÿÿÿãã㥥¥CÛÛÛñ™È™ÿoÑoÿzäzÿwåwÿˆéˆÿ¸Ù¸ÿjÌjÿqåqÿpäpÿpäpÿpäpÿqåqÿmÈmÿfyfÿedeÿedeÿfyfÿmÈmÿqåqÿpäpÿpäpÿpäpÿpäpÿpäpÿpäpÿpãpÿnßnÿkÙkÿ]Á]ÿ޾ŽÿÛÛÛñ¥¥¥Cããã„„„oooÓÒÓ¼ÈØÈÿzÇzÿ€â€ÿƒêƒÿíÿ¹î¹ÿàÿzézÿzézÿzézÿzëzÿvÏvÿkkÿhghÿhhhÿhhhÿhghÿkkÿvÏvÿzëzÿzézÿzézÿzézÿzézÿzézÿyçyÿwãwÿpÖpÿh¹iÿÄÔÄÿÔÒÔ¼ooo„„„ÿÿÿ¼»¼Zßàßö¦Í¦ÿÓÿ‹ê‹ÿŒîŒÿŠïŠÿˆîˆÿ†î†ÿ…î…ÿ…ï…ÿÖ€ÿp…pÿljlÿlllÿlllÿlllÿlllÿljlÿp…pÿÕÿ…ï…ÿ„î„ÿ„î„ÿ„î„ÿ„í„ÿ‚ê‚ÿ}á}ÿmÆnÿœÅœÿßàßö¼»¼Zÿÿÿ’’’{|{ ÒÒÒ£ÛáÛÿ™Ë™ÿ‡Ù‡ÿ“í”ÿ•ò•ÿ”ó”ÿ’ò’ÿ’ó’ÿŠÜŠÿv‹vÿpnpÿpppÿpppÿpppÿpppÿpppÿpppÿpnpÿv‹vÿŠÜ‰ÿóÿòÿŽòŽÿŒðŒÿ‡ç‡ÿxÏxÿÁÿÚßÚÿÓÒÓ£||| ’’’ÊÊÊ«««$ÛÛÛÄÚáÚÿŸÍŸÿŒ×Œÿ—ë—ÿœóœÿ÷ÿ–â–ÿ}’}ÿtstÿtttÿtttÿtttÿtttÿtttÿtttÿtttÿtttÿtstÿ|‘|ÿ“á”ÿ™ö™ÿ•ò•ÿçÿÏÿ”Å”ÿØßØÿÜÛÜÄ«««$ÊÊÊ565ÿÿÿº»º.ÜÜÜÁßãßÿ³Ó³ÿ’Ï’ÿ“Þ“ÿ—Ü—ÿƒ˜ƒÿxwxÿyyyÿyyyÿyyyÿyyyÿyyyÿyyyÿyyyÿyyyÿyyyÿyyyÿxwxÿ‚—‚ÿ’Ú’ÿ‹Û‹ÿˆÊˆÿ¬Î¬ÿÞâÞÿÝÜݺ»º.ÿÿÿ565MMMêêê²²²×Ö×™äääòÖáÖÿªÇªÿƒ“ƒÿ}}}ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ}}}ÿ€’€ÿ¥Å¥ÿÔßÔÿäääò×××™²³²ëëëLLL«««–—–ÊÊÊGÐÏл¡ ¡ÿ‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚ÿ   ÿÐÏлÊÊÊG———«««IIIˆˆˆ‡‡‡¸‡‡‡ÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿˆˆˆÿ‡‡‡ÿ‡‡‡¸ˆˆˆLLL–––ŒŒŒN‹‹‹š‹‹‹™‹‹‹™‹‹‹—ŒŒŒµüÿÿÿÿÿÿÿÿýŒŒŒ¶‹‹‹—‹‹‹™‹‹‹™‹‹‹šŒŒŒN”””ŽŽŽ“““———‘‘‘‘‘‘G‘‘‘ù‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ú‘‘‘I‘‘‘˜˜˜”””ŽŽŽ––––––G–––ù–––ÿ–––ÿ–––ÿ–––ÿ–––ÿ–––ÿ–––ÿ–––ÿ–––ú–––I–––œœœœœœGœœœùœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœÿœœœúœœœIœœœ¡¡¡¡¡¡G¡¡¡ù¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ú¡¡¡I¡¡¡¥¥¥¥¥¥G¥¥¥ù¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ÿ¥¥¥ú¥¥¥I¥¥¥ªªªªªªGªªªùªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªÿªªªúªªªIªªª®®®®®®G®®®ù®®®ÿ®®®ÿ®®®ÿ®®®ÿ®®®ÿ®®®ÿ®®®ÿ®®®ÿ®®®ú®®®I®®®³³³³³³G³³³ù³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ú³³³I³³³¶¶¶¶¶¶G¶¶¶ù¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ú¶¶¶I¶¶¶ººººººGºººùºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººÿºººúºººIººº½½½½½½G½½½ù½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½ÿ½½½ú½½½I½½½¿¿¿¿¿¿G¿¿¿ù¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ÿ¿¿¿ú¿¿¿I¿¿¿ÿü?ÿÿðÿÿàÿÿÀÿÿ€ÿÿÿÿÿþþþü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?ü?þþþÿÿÿÿÿ€ÿÿÀÿÿàÿÿðÿÿøÿÿøÿÿûÀßÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿÿÿÀÿÿ‰PNG  IHDR\r¨fv'IDATxÚíwœÕÕ÷¿wŠê®¶ïºâޱ ÆÆ4ƒMÓ¡™–À !!OOB O Ï é$$Ä”ÐB-€ &\À6n˜bã¶Þõö¦63÷ýc4ÒH«-fm¯úésw¤ÑhöÎ-¿{ιçž+¤”ðéñÚk¯íé[¶%ƒý\{bOÞìØcìçÉk(ƒ (`ð  vò ª€|FA( €Ï1 ÀQ Èg$€ ø£    €|FA( €Ï1 ÀQ Èg$€ ø£    €|FA( €Ï1 ÀQ Èg$€ ø£    €|FˆÏ(¨ð9FA @ùŒ ( ŸQP (àsŒ‚0@$€ò P@>£ PÀç `€(Hä3 0@ €|FˆÏ(Ø (àsŒ‚0@$€ò P@>£@D Èglð9FA @ùŒ ( ŸQ €¢@ä3 0@ €|FˆÏ(ÌPÀç `€(Hä3 0@ €|FˆÏ(ÀQ €ò P@>£@D Èg`€(@ùŒ ( ŸQp* €Ï1 ÀQ Èg`€(@ùŒ ( ŸQ €¢@ä3 0@ €|FˆÏ(ÀQ €ò P@>£@D Èg`€(@ùŒ ( ŸQ €¢@ä3 0@ €|FˆÏ(ÀQ €ò P@>£@D Èg"PÀç `€(Hä3 0@ €|†(4àì¸ãŽ;~|mþu) ûù÷"šáÞýÍo~ó{ƒý่‚Ф”·À/v^>c(ÛÇÿï^à¦Á~è\EAè¿úÕ¯Tà¯Àeƒ—>.ýÖ·¾evFrè·ß~» <\0Øy)`·ð8ðÅoûÛÆ`g$—‘S Dnª¾¿øÅ/<ÀÃÀ9ƒ—ú…ç~÷»ß vF²!§ú\Ne&G àç?ÿ¹x8m°óR@¯ø7pÖ÷¾÷½È`g¤'äTŸË©Ìä0üìg? O'v^ Ȋ׀Óoºé¦®ÁÎHoÈ©>—S™ÉqøéO^fv^ HÃ`ÎÿüÏÿ´vFúBNõ¹œÊLî€Ä·¿ýí’ÒÒÒç#;C°¼¥¥å”Ûo¿½‰”³È©>—S™É]®d꺮_z饗Œ;öv!Då`gîó )eÓæÍ›¿³`Á‚ñx<¨¤H wwzž; I —츎–¢(Ú!CJ/¹ä’ËÆwñìÙ³'ù|¾À /¼@SSÓ`çõs‰ÒÒRN?ýt"‘H×âÅ‹×ôÑG>ðÀ vîÜÙbY–½ØÍià9ÓÐsªÏåTfrƒœL(€©i£GžtÙe—uÈ!‡|}Ô¨QC‡ †eY!èêêâÉ'Ÿ¤¥¥e°óý¹BII çœsÁ`)%Š¢°cÇ>ùä“ÚwÞyçÎ <½yóæõ†a€-X‰ŸzƒÏ©>—S™|pÄ|ˆO›6mÜ 'œpñgœquuuõÈÊÊJ¼^/‰F•DGGO?ý4­­­ƒÿÏB¡gŸ}6EEEiç5M#ÒÐÐ@}}ýÖýë_~õÕWÿ±råÊ0ÉÕ §ú\NefðÀ­ã ]×=×\s͵'žxâ•S§N=Ðï÷0 £ÇÊëèèà‰'ž ½=çÐy¢¢"Î9çB¡PÖï…hšFWWáp˜Õ«W¯yå•Wþv÷Ýwÿ1ÇH· JãÏ©>—S™$Ä}Ç£ŸvÚi'œþù?š>}ú•••¨ª €eY}Þ¨½­ÇŸxœŽŽŽÁxŽÏ<‚Á çÎ=—PI¨ÏkÅŽucš& ¬\¹òíGyäÖçŸþ•X,æ -rªÏåTfö-8ÿLbûï¿ÿ˜K.¹ä+§vÚ7‡ªø|> •¥¯ê¥ÓèdÓöM¼ú«Ä"9é…š·Ð½:ÇŸz<ãFŒ#¨‰™1LÙ÷!A8¦¶¶Özþùçïxà~¿qãÆM€ˆ'.Ýg!§ú\Nef߀3ê«@ìÔSO=÷†nøÁ˜1c¦—––¢iZ¿F|E(hŠFS¤‰?â“–OØÞ¾ƒp[Þ½PX†²G UIÛè6ü%~F`\ÙX&TíOE Ã4°d?êJQ0 ƒ––6mÚ´ò®»îúÉ /¼ð86 ˜ìCi §ú\Nefï€ÛÈgVVVV|ík_ûúñÇÿõ &麎eY½V"¡`I‹ÚÎZVÕ®b[ë6Úãm˜ÒÄçõ¡{=б1d° äTŸË©Ìì]p:¿Ć~àm·Ývû´iÓN6lŠ¢ô:ê ^ÍK—ÑÅÎö,Û±Œ-Í[0„¦ix¼T]EÕUUAÑd«¤íõ¶ |JMà›åC–H,ÃÂŒ›˜q#f‰F0c&šÔS1†£÷;ša¡aôQ#Šì¥;u½cÇV®\ùÂ~ðƒooß¾} ¶4`°—I §ú\Nefï@RäB˜'tÒ ×]wÝï9ä EEE˜fﺤ®è˜Òä“ÖOXµs6~ˆPºOGóh¨šŠæÑP4EU’$ „ Þ§ñÅF¤‘;圚 ääÔ*Ó4m0L;%HÀŒ™Äcq¢á(Ò’LªšÄŒá3W1U¨ÄÍx¯ÿCUU:::x÷Ýw?øÃþðÕÿû߯J)I`¯©9Õçr*3{žÜN=ªªªÊ5×\óÅóÎ;ïŽñãÇ—ƒÁ^;¿U¨loßÎÊ+ÙаCøü>to¢óë*Š® j©‘_Ql"PT¡¢;¢ì|zgú ¡ *ΨÀ3ƒ´$¦abY¦i¦È fbÄ Ì¨MÑh”®®.<ÒÃÔ!S9|äáŒèS-PU•®®.>üðæG}ô›wß}÷æiZ¤Hö0äTŸË©ÌìYpn¦BÓ4ßw¾ûN;õ´Ž=Úã÷û{íüš¢aX«ëW³xóbÂV׃×çEõ¨Éίê*Šf€ªª `w~Åîü[äìÚÜÅŽ'v ÍÜ)ï\„PÕgWãã·í1–IJ,;™öÑ‘Œ˜aKQ#)Dº"D£QJ€“'œÌŒa3иճ4 ª*áp˜Í›7Ç^xá…Ÿü⿸Ó0ŒvÇwÉ«¸œês9•™=O*€ßïÞtÓMß?ïüó¾]ZÒ»•_OóñIë',Ú´ˆ-m[ðø¢Ø÷íØØÁön/@O0ôÜ¡ØÄ"¤%±L[°,Û&`ÄíŽï$#j‹ÄˆD"DÃQƕ㴉§1¶l,a#ÜcçSÓ4iniæ±G»ýg?ûÙOÃá°ãÐá÷rªÏåTfö ¸Å~Åëõÿà?øÑ\ðÕ’’!„è±T¡³b¼W÷oo›Žxþ"?ºWGÕ£¾ÇîøªšùEA¨ÂN K³Óé…Ió£‚Öµ­lûç¶”pY€ †ÍFñÅH)í:’vg±dJpHÀ- ˜ñ$¤x,Ž3ˆ‡ãtutÒC3úfŒ˜Gõ`ZÙ%?§m´¶¶òÈ#üî¶Ûnûa4mÇ®­=¦äTŸË©Ì œÜb¿ª(JðÖ[o½å¢‹.ºÁqíéy=ª‡æH3ÿþè%Þo܈îÓ ¨^»ãÛ?!ök "¡ã«ªŠ@QÓG~gÓµ$@Ò2ݶªíOî(€CÎBhZqò”$Ed:HS¦lÎ AÜVŒˆA<ÇŒ˜ttv Ç8¨æ@Κ|6þ ¢f4{Vm°­­ü㿹õÖ[oµ,«[ Ø#ê@Nõ¹œÊÌž!P|>Ÿï»ßýî÷/¼èÂï”—•=¼Wó²£}O¿ÿ4»Â»ð|x|4Ÿ†îÑ:¿jöºŠPªjÝ^Q”Ôd#®#vƒN>Ÿ„–wZ¨}º6Ö¦ 2ÔœYCÉ¡%ÉSRÊôi< VrrβL,)SBÓÂ2¬„qÐÀpf ¢&ñHŒxÄ ŽéŒP¬áâƒ/fdÉH"Fö°N=577óüã—¿øÅ/þ7‰D°){Àê@Nõ¹œÊÌÀÀéüšÏçS®½öÚ¯^yÕ•ÿ[S]£÷$ö !P•MÍ›xæýgè’]vç÷zPý*š®¥Œ} pD}MhHE"T!Hõ%à~È:/Ýüv3;ŸÛù¹&ªS«(›Ù}¯Iw¤TKZH –aÚ–þxÂHhZI•Àˆ¶0aˆ…ctu„ ©Å\8íB&TLÀ°ŒÛ†”’ºúºøßþú·ïÿñü]$±°ýD¹Ôç>+;9óüšB\pÁóæÎ{syY¹.„Èjðs<úÖÖ¯åÅ_ JŒ`qÍ«£ûÜ"¿’²ö+*BMtvE&F~gdO4W™øìªc+‹_‰J/ÁŒ›Ô¿X?Øå7(¨<¹’Ò#KY¦é²¦û:›`%Šª€B³ëÔFÒö"\k<¥}‚¶ö6î[±€¹ÎeÚÐé˜Òì6UèÄ(/+×çÎ{sSSÓÎûî»ï1)¥†]}ƒ²hOã³@n?9}úô£.½ôÒß5ªØãñdíü"ñZ¹s%/ô2¦j(  ùt4¯†æÕmK¿ÇžãW4¡* ³¢!ö)º7V7ÃgmÈ®s¥G•bÆM^iìrܧ(?®œÒ£K±dïå“~>õ½DÚÒ– ú $ŠP01QPBEu_‹]_A‚t¶wòèêLjšqqÒ”Ýþ¯eYx<FU|饗þnÍš5Ûßyçÿ`·µ}¾ˆho ßUç 2dìÿýßÿ=~ä‘GN=v~UQY±s¯nz©I¼/ºÎïˆüŽwŸPPì–=À•÷nDÐÇçÄI^m qQã`WÁ>AÙì2*Oî;”boåç¶HK&§ -˶HSbZ¶Ðñp ƒ±pŒx8N¤3‚W8sò™Ì9Ó2³Ö‘¢(tuuñÖ[o}pã7ž»sçα ÀHfm7K}Nì ìh€^SSºåÖ[~räÌ#'ƒÁì?¡ó¯¬[É+›^ÁÔL<Z@Cõ©h^ Å« x„&ì¤&,ú ‘_ ‰ +9]%‘I1Ò’¦4{ýlI Ó2í”ø®ìø2J*ì²Üë(™YBùIåie‘-e–WfrìR&ê"Q/B±ë ä{E·ëTõÚu¬ùíä x14ƒ§Ö=ÅÒíKQ5ë dYÁ`#g9á–[oùIMMM{yÞKÐùüI½sæÌ¹|ö¬Ùg=ütEgmÃZ^øøLÅ$ØÁk€ÐEZç—ªD*2)fŠtË^ÒF§ÞF~™ý€²SÊ0M“¶·Ú»l÷ Š+¦lN&}¯ãïKu‚„øË8˜šf@4m©OQ,,[¶b`aá^:Û;y|íãø4Ó‡N'jtŸ"4M»½Ìž5û¬9sæ¼µ`Á‚»°Ûžã#;Ãún Ÿ ÀÉ¿2mÚ´c®¼òÊï‡B!%)fÀ«yÙÔ²‰g6>ƒ©˜ø‚>TŸŠêM¤„¡Ïõ…"P„’ld‘íÝF¾¤ºÐÛJµ²S˰bí+>[¡ÅЦQ~Fyj:o7Ñ/Bpœ‡P@H‘LŠ® H)%š¥aI Ÿôn óЪ‡(Ò‹˜P1°Fd°¼´$¡PH¹òÊ+¿ÿÞ{ï­~÷Ýw_'±ºt°Ë÷Ó"mn½ß …Šÿûß?zôÑGÏìiô÷(j;kypíƒtšø‹ýh~ ݧ'Wô9ª&zPŠHˆý2ayΘÛwŽÎ;ç¯p_c¹Þ÷"9$aAÓ t®ìì*Ù# r^e¯ g·Î–eÖ$³u¸¯±,ieÝ@Â& ̈́πiaÄãX±„qÄ ‰ë²m]í]”j¥\sø5  'fvï×Îâ¡%K–,¹öÚkÏokkkÂì†= —ú\>Úd"߀‹.ºè«“'OžÙÓâMÑhŽ5óôOÑoÁ[äEKèûšWEñ( KBçW$8b?‰)"aÙBcR5ÓŽÒ­Ÿ:ç-ÛgÝÂL$÷oM×=2Î “ò³Ëèì²0ü“ý”Ÿ[Ž%¬>ô~³—rI/ßl‰ÄýmuÍö´„ÂVã¡HM è‰äØ|*šOÃôQ©çÁUÐiBWônÏcš&~¿Ÿ8`æE]ôÕÄié{ä òQpô~ë¨£ŽšyÑÅ]3tèÐçú-iñʦWØÜö Å¡bT¯Š’˜ÞºmáGTÛ‘G*¶niÏìÛlm;…ô.îgýn7¦»A@ÉÜR̸EdCÎntÛ+|ûû(™W‚)LlágÏ-öÊî'ÔËRvĵR±¥8ª@HÅ”(–‚bª¨–DµT‚fðìúg¹xÚÅÉ6ä†eY :”‹.¾èš÷Þ{ïÕ7ß|Ó™tüòù&$ ~¿¿ôÄO¼aô¨ÑÙ.”HtEgcÓFVÖ¯$Ø‹zœ)>¯Mvç'ií—J¢Ñ$,ý$æù-¬nG3ù>ù’–LÌ ôñêöÛÌïUIé¥xÆ{R3y’<ã<”~±Ô”NÞWyìÎKöñJyeJ—¯@bf@vëÂ6üz¯í÷¡ûtE–l]ÂÚºµèªÞ#Q5ºâÄO¼Áï÷—’°GÁd¹}€|"G×qÔQGÍ™7oÞÇÙ'³*RaGçžûè9{%ŸOKV²=ú ÐD2€‡ãTb7T™tPI®FK­´£kúÏY³.¥K„•YDYÙ‹(+»%©@éËðŒÉÐGé”^X†TÉúL½§¾T…žË*Û½IÀÊpjbŠPKyzª •Ðã³Ã»=ºæ1¶µm³Š2žÑqš7oÞœ£Ž:jŽ»m’G$O _ÿ@ 0üÒK/½®¸¸ØãÄwC ð¨n^HCt¿Çîø%¥ÿ©Eú¡•Ðñ%RšHl]Ô”©£ÙMOM|gu?'3ôZ™ÐcÍ,×¥’™5¡Y”^\‚g”g°Ë¿Oè#uÊ.)­ççé=YýL½ÜƒD¹%è!‘Ò¶ÃH,¤bŸC‘¶ ±j· UWP½¶]Àã÷°³cÿÚð/¼š7«ú¢( ÅÅÅžK/½ô+@`8Iy2/àý=§œrʱS¦L9¼§x~ºª³¬nš6àõûìŽïU"Ÿš@ªŽ¾¦b,‘9D’ 3`òeb¦–VòÓ% ºß;Ÿ3ÏíN’:”\\‚6\ô¾§¤ Ó(½´éáS=ã@“ôþ]¢neÂÖƒ"ì6 šÝ6ÜNCþ ŸU;WñÆ–7еìÁ¢¢"¦L™rØ)§œr ¶10¯¤€|!°ÙÕ …BçœsÎ7ª««³w~E§1ÒÈÂ- ‰‰˜íן´ô+)トnj Ûf“Ôß]–~·_¶÷öÈß݃­›×_^mýMÒ+)™_‚:DôΞ™Ô•ÐüÒ»;bü¾KIë€LÙ ,Ç^—°  ÐmEWм:Qå¹÷Ÿ£¡³¡ÇYêêjÎ9çœCvÐ yd\Ïp,ÿâôÓO?wÒ¤Iû{½Þnº?€a,ݱ”úp=^¿%aèqÜCCŸcJêä–•<&Ýt3RÌŠµ¢D­(q+žFNÊöû¤} —{÷7Y‹âK‹QkrGÒT«TŠç#½rÀÏ7àò±Ru™üì¼—VZ]'g)ÙÊ4Û@¨è ¾€íÛy}óëɈ2m^¯—I“&íúé§ŸKjaZ^ô­|`*g¿î÷û‹§M›6w¿ýöS{ZèÓkåío£éZRœªíÖ‹ –b[öa×´çŒpæý2ƒQ¸­õû{öçÿèè¼Üü2ï‡ßGóhèšžM² ×é¾OƒÍ/¢ýoí˜ }»ÕîM¨*Eó‹ @¿vèÙëp;]&<Ýï3ëÆß @á(q]ÓY´i³FÍ¢ÜWÞ͕ٲ,öÛo?uÚ´isŸzê©GÃá°7 ç]„ó¥F5§OŸ~êœ9sfôÐSWt^ÛöVšWCx£¾Nҽ׎Lrñˆ3Ý—íåhûqgšw—\ÌxÏxFyFqYåe§G¤1B$I8üô|=ý"ÁË‚ˆ21hb¿(/B1{å?ÕK¤Þ;*ž›ÄÝ×$¥@!“Å9Ó„ŽÔ¨x4ŸF{¼—>z©ÇiA˲˜3gÎŒéÓ§ŸŠ0D#ìù@ ¶å¿|Ö¬YÇ–——ûEIŠüT¡RÛUËÚúµöèïÖûUת>g~Xfè„Ò¥dèï~ÅϬÀ¬4K°®êœ>ütæUÌ£eG ±pÌv9͸Ï^í€Å‚¢Ë‹PJ÷}5*!…¢ËŠŃG@}&º¿wKyn»@Òl§¤¦¤x4]cŶlk߆¦¤ ÎR&‚‡”—ûfÍšul ('OÔ€\Ï #”©åååSÎ>ûì3ðÍÝæž·w¼M³ÑŒæÑRÆ>gbFMéþ «¿LŒÐ®ÎžI¦´·ŸªÒªºe®±µ‘—_™†èlê´ãÓeÌùïõQ8$ÎîÓŽ(Šì‘_”æpçÏBu"\Gç¥H[]TH- ÓªG¥1ÚÈë›^Ç£t÷É0MEQ8ûì³Ï,//Ÿ’hu9O99RSþ#BÉe½™bšh؃Èn`³Ò†t†;¹åž[øç¢k·“–‘]äÜË/Ê!pY‚ìõÎD ñ¿ÊsHìïç«›˜õA`ûdx ¢”"½çû;ÞekûVÿÖó¼¼òeʇ”¨ ÛAB{ºÇÞNT@`~Ü{íMø…Ýù+ôi½O;Øí¼«-È„C I£±[ðø=lëØÆÚkQ•î³0¦i …8çœs.Êm7auÊMäò,€cüóŽ9²ºªªjR¶ªPi‰¶°ºaur[®¤Á/AoÉÑKÚÆ‘Xâë^ÓïvK¶s΢ÓêdmÇZFúF&ï÷þ–÷Q*%û•P<¢=¤' `ÐP¾K|„ÿFFö¬ñYx¾K|PÅà>cáŽ×à…åZ´%%ÒJ-Âr" §Ô„Ë(¨ ÕŽ±lû2y8A=˜¶Éˆ”¿ßOUUÕ#GŽ¬Þºuk3©¥Â99Ë€‚-B)óæÍ›;tèPO6Ÿ ±«‘›?Äëõ¦-ìqû~;.¥Lö®¹ygóIiÉ´ùdiI¢f”µ]k‰¶ „ݼ!/ªÞR¯½¸{»AJTƒ÷b/»}O†0èÏ·»©·:‘–LßzÌÝù¡û""MàóùX_¿žúöú× :Ô3oÞ¼¹î6<Ø©'ä²à¬ùWkjjfVTTdy Ëà݆w‰ãzªÄR,U±çüË{¡d 8’f &]pÎ+ŠÂ¦È&Þke3V5 ©J„O`iV¿Â\í3 íBرTìÚO <z#dn=ãnÀ©Og Hžs|?é3CÂnC–°°+Ù¦¤"Aƒ˜ŒñöŽ·U:ªûÿ’’ŠŠ jjjf’RaÃ]=!W™)iý3fÌØÑ£Gɶ¹‡¦kmÃZt]O:pHU&;ÇŸ¤Hß“Ë.=¸ûJ{-{—èbqóâä–R“GO¦ª¤Šh,jä– ,#m@ßí²OAí öËCŸ,ïéá{×¹äÔa¢ý$„ç U y4ÞÙþ–´ºG2’vüˆÑ£G3fÌXr|6 '3EÊú/?üðã§N:,kÀEáã¶ièj°—øª"}Î?q'‹Ô2Ü;ªËx—Íwß«{Y^Å»Mï0mÜ4~mÍmQcÐŒ½’À(PÏSÁ0v3)už cò°ógÿ²øwt;ç´Rë’Ñ'2lª®R×^ÇÆ¦IR7,ËbêÔ©Ã?üðã±uÿœ ÈUHøe!TUU\\¬dk¤šÐXµkqOÎó'}@– nß 2\CÒÎ[Øä£úTž¬{’ÎX'º¦ó…é_@éTèjë²í9øbœM»µHUõ\&0èùÐK üÉÖèjWBĉ³bû tEÏJ ÅÅÅŠ®ë£qíW9Ø*rÑÜã/ VŒ7nhö‹q3ΖÖ-É©¡Ø$+…­¯ E$E´¤þš%šo¦þŸ|¹ B`O7ng;myŒËÇ_ÎqSŽãå/óNý;øJ}è=7y~ˆ³ÖãýˆÈ+@9[AN”ÝT®¼„SßV* «Äµópk’m@qµGP–bñQÃGĬX{?Ž7nH0¬èìì܅ݦsn6 YÉ!1räȉÇ{ì”ä4ž 𢱵s+ ±†ä´ŸãÅe´;’¾á.q/›ˆßÓÒßL1Qõ©,l[Ȫ†U àêÙWSÔQDGS‡½Uuˆ¼YÅàIq–è“ Ä™99·ì{äùEï>™*ÄµŽ aL¶­Äts]¸ŽÍ­›»-vÚë¬Y³¦Œ9r¢»MvçÊD.KŠ×ëZ^^>LQ”n3ªPÙÙ¹“N£áÉ%–°ìxþÎnÉäf‘i`zžHŠ«Ç$öŒ@§·“·<ÈÈÀHFUâòi—sçš;Ñ‚þVsbAÏöðýé §Ê£ˆ´-\ušé'¹4±1‰­É“êD‚„*h¶³½m;û—ïŸ Ô™9ª¨¨æõz‡âRi»82‘‹@rQ¦eYÅ~¿;SÇR„BcW#]FWšÑO"ÓV|%ϹFú¤AÐ=›!H«û5N x|`}ÀC?À©“Oåäê“iØÚ`/ lß÷ÞÒÁ9'KDÝ“%rzäo°’åRûܾ¸ 9H¨]F»:vÙ; eºL~¿˲ŠI-2ιþ–‹€¨Bÿ¸q㪜Ñ; Âfç¦HqOzö9n¾ÂÞ²!†eoí¢›!Ðm$„Ä:ñ,£¿Áâ ¯4½Â¸Íã˜3z—v9¿ú1[ë¶R:¬E˹ºNáqòŠGë y¨Ì³€Ö ¤v`éî0á‰v‘Ôù;€•’,+QÿŽ“i§dБ„dGihoHóLf+Ñn÷ßÿê5kÖø¥” Ð'û½êñxJŽ9映»ë©ŠJ§ÑIs´9i1…™ÜüÓÞ‚´N³g³úZ2%9¸“–QE †Tl_Àˆà¦TMáÆ™7rÓâ›h÷µ¬Ú’I®âP ,0ÌÙÇy+ó´ëÎÎLV÷Ý„“¢¿ãì¿•¸Þ˰w2MÓÞQÈ0’^£õõ´ÇÚñ¨ž4"pÚììÙ³'þë_ÿ*‰D"m¤ærFÉÊ5€ èº^4dÈÑšÖ=‹B:b´ÄZlËÆú~G§³¤Õ£îï>º;|6ë6 ¯Ä^ýÕækã÷Ï?bÿšý¹áàøéªŸ"t?äOÎLä"Œ£ çaI¢Î¢³CºÅ¾ÛgÙý³ë&©ú—)HžwüX×$HÀ2,¬¸M–iÙŸ¥-i6‡›i¶S¨êæ)©iÕÕÕ£5M+"G§s’S€Š¢B¡P•ªªI?íäERÐë¤-Þ†¢(iÓ5)ï,!S¢6‘~ à  ðqìc~¿þ÷|wÚw9vü±liÛÂß·þ¡ ¼EÞÁ.ÓÜ‚+üdìæãzŸüÎ=ç®÷~‹®ßdvþ´ÿ‘ùÞL´ ÑœÎï¨n[‘Ä>§( -á:¢TªÒîmYªª …ªE "€‚Ð ’*€¢(>¯×[”m@AÔˆ6Ã)Ë?JòèLá)–‹pw~HUºã ÖßÎï丨´˜% K¸gí=|åà¯pÑÁQ×YÇsµÏQ:¢ÔOÖ¿OóÍ»ÛÈmÉ´ói`eïÌiSÀÙ:ºóÝÙ?g#œ$¹XtkYUÅ„½I(ö@އ»y:3§XQ)PÈ!kKΠëºîËÖq‚˜³·pö¹:¸S˜öâi/þq¤žÀmL3º®í‰Í_êç™]ÏP½¡šó8fÞ@ÖÖ.¥lx)Š®ê$P¦|& ÷K¤Þ+B PzÞ×/³³'ÎuëØn1=ËhŸöû,÷îý¼¶'rOS ³-Oq¶‹wŠ#3bY ^®ë^lWà‚ Ð8 !4!„Èæ3cÄÌ(¼.ÑÝB `UJ{H’®`%Z¡¤;™"€Ôµ}CQZ©Ê½Ûî¥ÒWÉq£ã{G[߸…U;WQ6´ ¡*ûŒ¶j“1b2F@ Pª–R¬PƒxšÐP…šœþŒZ1bV”˜ŒµbD¬a³‹.+LLFQ„‚ŠýE¨Ñ¤-Z§æ×]‹¸¤tö-úP9Ò<]R†cñ·Û‰m5t¦‡…€¨%nÆÓïGê ›œ)ÀœÛ;0×R¥dLÀ²,â¦Gz1¥‰ŠÝÞ’–]À²;¹âz°w‹I{¥©}Žÿé…éõÐêä®î¢Ì[ÆÁCæŽú>?~óǬٹ†’êTMÝ«  MZQ+Š_ñs*åÍP}z¥j)^µ»m"nÅ ›aÂf˜.«‹£ƒ6³ÍNF±Fê#»hˆïbG×ZV¡ )*"stOs/¥¹úC6°2ÞËD.Ï!,g†,KbYi¹Õˆq ÓÈúBEA‘lÓûæaû\#§û,,+±|Wâ8ñ˜˜–°=ÿ,{ÔQ¤‚Lø¸‚2i‹…änˆÿÝ2/ðûý´ÅÛ¸mÕmüDû TÀŽþ7ÿçfÖÕ­#TJúìîý{û¿‰! $’*½ŠãÊŽãèÒ£âBH õë>º¢£+:!½‡ë%„0fmñ6ê#õ|Ôñë[׳®}]V—m ¶§¦*ÔnjFÖ›î ôA–e%g!RÒ€ÛÍBZ©UƒŽÐ´ÌÔ FÏp·ç‚ÐDÆ1Ë˲0,#©“9Z ©Å’Vr9p¶YËEn›€ûšÝs} (@£ÑÈOVü„_õ+†††rÛ¬Û¸åÍ[XU¿ŠâêbTuÏíìcbïZT¥WqjÅ©œQqåzù^©¿îǯû©òU1®x3«fbXF'ëšÖñzýë¬m_K]´ŽvÙŽßãGjÒ¥vÐÐ׬ƒtµÙ] p/%wèQ}—\Ú1g‹†l6§sÉi?!ìQPCKéó‰€!™ ) ¤¹ 'ð…||b~–ÿˆŸÎü)åÁr~tÔøÉ[?áíº·)®*FÕÕ¾FŽìe‚Ö,nʼnË8šÐ8´øP®~-ãüãöyiŠF‰§„™Cf2sÈL:¢¼¶ó5^¯eÍË«aüÿ>ÏWOe—í½ûsæyËUXZiŸïÀžÚi®#W  ½"ÁΊ¥ØGiO K`mEÖJíF2}Í@êöŸ¾…Kƒ¬lXÉã=Ηü2åÁrn9ên_z;‹ê¨  ëz¿þCNNþFxG098™ñþñÔxj˜R4…R­tVQÏ(òqƨ3˜3bÿ©ý÷}pëÚ×á÷ùíÀšƒ1 Þ‡ æä–,Òcºý¤Ü©&çFÈ]ènÚ)išIˆýŽ#P¶ß9ï3=Ÿ&BøËü<½ëiNn=™Q%£(õ—òã~HpYgëŸÅ_éÇãõôøÿ i`HŸâ£J¯â¨’£8¶äX†û†S¬£‰Ü­BMÕ8vıL¯šÎoÞù ÏÖ>‹7äEÕoJ´?@Ö÷"½ÍÁ «4{¹ÛzÈô·aÆeÀ“2¹È#¹Ø#‹ÏU7' R¢[æû=æ¡Qoäñ­scÉH)ñê^n:ò&ÊÞ)ãÚ0Ê |~_Z§HºÌ.J´->”cK娲c ¨Á®’ÝFÈ⻇}k±ÅµOª ¡èûnJ4 ™1Ê»ÞC†Ÿ‚mH“Üm-SZȦäCøôœ'€Þà6ä)RÁ”&ŠTì) 8¶ç7=­p,¼îïöü>?/6¿Èܶ¹Œ*E4Å«{¹nÆuTo¨æ®î¢ÓêÄð!„À–´˜U2‹³ªÎâ¨Ò£»¨“ˆÆ£Ô6ÔRUVEÐì÷ï4MãÚC®åݧÞeÓ®M„ªC}ß‹ý–2ŒÁV¶—k¨|EÞ@ÒÊ/]º»Ã扤ÈÄrWÙó ûû½EhWÛ¹oÓ}Ü|ðÍhŠF[g¡`ˆy“æQé¯ägk~fïkШñÕð¥á_â„òð+{ÞxæŒV†i¯jÓ5MÕú5"KKò»ÇÇ[Þ¢ºªš¡åCY9’ª’*ÊŠÊBùŠðy|ù‹ðz½xu/ÍCUqøàÞÁ_ìï÷ÿÜsžzþ4]¿ïÓâ8« ån'ƒ€ü$gT·R@R4“®ÊÉ\Ö‹€û³ûš=EUx³íMÖ4®áÀŠ1LƒÍ;73zÈhŽ},þ ~¶úgTx*øïýÿ›QþQYïãtÜh’kä¯Çÿ!ÝÓã}¤”DcQvµìbgÓN>Üþ!oox›·Þ‹æ®fÂF˜H4bÇ+ÐTû¨«ö6ך½Ñ¥ª«(E ¢Ìsm`°:¾š•®ÄXk‹Äðácxh8ÕÅÕ )BuY5åEåT—T³~Ûz*‡WR±žr½#f"ã—X¦&©ÑÒ’öÊ;@Ñò*޽î=jbE, ԆkY¾}9±cQ#jàõz©Y‰^®ã©ò èŠÝé-{€;ÐFrÔµRåªê*Š×Þg/9·/ЇГDœþsOZ©`¢ `f•ÍýÝ¢œëúä{÷KÊn„°7@UTšiæ‰mOpPùAùŠ¸è„‹¸ú7WSßQϵs®EÁ„!XýÁj¾üÿ¾Œ×çå˜ÉÇpÒ´“˜6n!ÈÞ)Ò¢R™p‡L8°§ [#­´GÛÙмU «XÙ¼’Úh-Q%LChª†¦i((©Ù§±':±Ïð! ™LVܲß[Õ§¢…4{'&E&Ÿdõè«þömƒqýßÞ€ôï²ÅtîãÄÌWä<ô&Z¹2]S‘JÚçÔzVÒ‚ìiH¶'»1ùtÏí|ŽóFœÇ”Ê) +Æ×Îü×þõZÚbm|ã´oP(åKs¾ÄÈê‘ÜüøÍüqÙ¹åý”ie1æfOšÍA£b¿Êý¨(­HûwšÐ¨ðWPá¯`téhNs*u]u¬j\Åò¦å|ÐþµÑZv„w#†_ó£+º½ðJ%¹‰ˆãRÔ…ÝEØdHöñ(¾'ꢯQŸôïÜ#¿)ÍÔz€Œ£à ¸à8ý˜‰ª,l?€lz›ñÚ[€s §ó˜ö1&cüiÝŸ¸ë˜»8uÆ©œ·î<~ñò/¨ÖóƒÓ~@i°”S¦ŸÂ˜ac¸íß·±hÛ"¢ž(/5¾ÄÏúª!+D¬3Ʋæe¼þîë¿SÌðÀpö+ÙÃÆƱSŽåàq“-ž"€ªªL©˜Â”Š)\ /`[ç66wlfqíbÕ/bglgrSUMI¨ äLjÖ{¥zŽþéפô®ïóYȹõÉýE¦è•-õF{%®¼i[À­x"Å)ž$™/-tÐÁ‚ ’‘dGUbþáó‘Ròzãë\õøU,ùp !_ˆø#n:ô&2@Ä!0,@ÅÄ †M†ïÛCÛy­õ5î|ûN.øÓwËqügýú.H#ŠF0kÈ,nšvOœø¿ñ[ά<“êˆCk¤•¨íW™Ònµ—„Ä™¯Èyè­à»¡$­Á–• mFídE]QdM+ÍDJ‰îÑYÒ´„Å['Ÿuîô¹L NDQ6«›¹þ…ëytù£Éï¯<äJ~=ë׌ci ·!|­TÃWã#4.DÅä ‚QÇ«l náÚ^Ë›¾ÙÿÂÐÌ6›Ÿñ38æ¾?ùûœ3äªE5­­Dâ‘Ï6dy®´¨@º?ÐkYä:òZèiz&é„Bj1[LËTÒÖx÷Wp cŽˆo¦FŽl3™PPh6›ylÓc>ôpž£‡ŒæÄ±'r÷ú»)*/¢ÝÛÎÿ¼ñ?lnÞÌÇ߈¦i7ö8Æ”ŽáÇÿù1‹á/ñ£éš½?¢G 4SÃS顳­“¯ÿûëÜ¥ÜÅ̱3w»ˆËýåœ7î<Îwë×±´~)O}òkÛ×¢{tTEͯ`§=¨Éº²R×% ›NT W„àäú'rpA$™w_F"¾KŒø1Óñ ËŽ‡çrí-ùŠx¹öeVÔ¯H>ÓÙ‡œMY¼Œh{_À‡Z­r×{wñÍ'¿Ic[#£ÊGñ›9¿áŠQW`4„»Â©Æ«€Ðj@¥¸º˜æ¢f®ñzž_óü€ÊzrÅd®˜t=î¯üê_1Q›ˆ6ÇÂýzÖ¼Kôã®cž"§  _âÚÞ~eè÷fÜõÝ>M´ßÍ—@ ½’¿®ÿkÒ0}ütöóïGCmñxO±‡â‘Å<±ó ®zä*ÞÛúO€›»™Ïø1%ášÛší‘ÉM†Bâ/ñÓVÜÆ oäw‹~G8P”ùÊ8kÜY<<ça~xàÙ_ߟŽÎbf,µægø•l›™m¤7›B#§  /$Å2¬¤h–ö>KrB89ƒiß;a³Ï¦…i$tûÄhït|Ó0Óÿç§|éšÎ›oò¦’ÏuÓÙ71o¬ÿ0yýŒá3øÃÉàOGÿ‰oŒÿG–‰Oú0ã&1à ®úUІñÜ®ç¸âá+¸ýÙÛ©k®p=Ô×ðíÿ͟ŽùãÅxºÚ»0MsðEø}­.ä)rÞ˜MŒêmÚ¦§Êq:»#²¹Ï§Y{M’Vû¤‘o/"jEùÞ”ïñÅ _L;ïÕ½œ2þö íÇõÿ¾ž- •„U„ØÑ²ƒeõË_=ž®ho€b1§Ž?•¢Š˜œLUIµ±ZÕ.bEà êbu´ŠVþtÎ?ò|FVޤ¼¨ÜŽÖó)pÔÈ£x¸úa~´øG<¿óy Ÿ1¨‘²Â=wŸÙVÈâГmÒÕÐÄý\ÿ! '¸C€9Á?v‹#¯#ò›‰o†•îöºpĈ0½|:ç:ÏŽœ›TÀoOú-×TTFVäÛç~›f$óöòò—¹ûé»ièh 9ÒL£ÕˆYfâáÅ X¹µEúž )ÓíΊÀzÌÝAÞ€»R,ìˆÀ™@¦¨Ÿ¦*$D}ËL_Ö™é#°7aXÅzq¿®=bì\ðõÜòæ-(šÂc ›Û6shõ¡œ}ôÙÌÿ¿ùljÞÄ/ü1ÝÃáãçé¯>Í÷žø\üGþ¹úŸLªœÄ…Ó.ä‚C.àÔ‘§R©å¾õ÷ñ̦ghô7¢T*øã~|†=®CÚbm4ÄèŠt±ä£%,»gß>ùÛœ=íl~õa~ùÐ/©ë¬ÃWîÃòà)¶XŠ•[^r½@FT`÷w™Ž@ɈÀÒÊ 1¿7ä<ôhÈVY½h$©9zÇiǒݯ݇õ)„ãýŸ–»ê¨«ø×{ÿâ톷±Ê-–×/çÐêC9qÚ‰œxȉÜþïÛù¤ën?ïvFTŒ 2TÉŸ/û3SFNá—oü’åËYóò~ùê/9{ÊÙÌ›6oü-n:ì&þºæ¯<þñãT«˜?q>‡UF¥¯’°fkÛVVîXÉ›[ßdé–¥|Ñ÷ùÎãßAk×AIͨÔJ5¤¢x„.^a›˜s©ô5¿Ÿí»~ølƒ„4±>cž6ñEºÇ–™zŸŒÿ'IÎ_gÞsoCS4>hý€ˆÁ§ùú¼^Q®Ÿ}=o>ø&ZPãõ¯óåÉ_FS4®8î ^ûä5žÝô,ÛïÛÎOOÿ)³öŸ…‚O¸‘Q•£¸õµ[©7ë‰áž5÷°à=êhN›tó¦Î㢠áÑ<õT°Ï€`bùD&–Oä‹~‘­m[yù£—ypùƒ,ÿd9~ŸO‰%¤ ø”äö—BˆtU*Ç-_Î&3Ù®í©­¦ ‰ÎmÉÄ|>søVb®ÞñØKxë™Fb'+%Îõæ7°7“Gxx»îm¶vlí÷c5á(&x'`4¼S÷M‘&Ž?èxy>¯uñu|éÉ/ñ×ÅMþîÜ©çrÏÙ÷0¥l ]zÅ#‹ñ ÷ðjý«|ûùosÜ]DZhâ´ÎŸ #C#¹rú•&iqÞs!ihÔEêxæ£gú]&~ŸŸS'J¸>LGGoÕ¾eW¤¢pÙÌË0ÛM‚ ­E­|ÿïsóÓ7‰E8l¿Ã¸÷ ÷2§f‘N”BÙ¨2B£Cl´6ò^ã{ýÎGuQ5ß?îûüö¤ßR+&ÜN•qŽ•óKd¼ïo;Íaä4ô…¤a„ß½7î²ì[®Å>9öòë~¼¿€OZ>é÷sO1…Hs„x8ΫÛ^Mž?éà“O´-Š/èC¢ñ»u¿ãÚ‡¯e{ÓvF–äî3ïæêñWoÛáÁJ4*FW°6²–ÎXçnÕÁYœÅí³nÇÛâ%ÒÙw.Úƒðú,"o m9®a{ìɘLF¦ÅLý’£R&…ºx·¼q Ñx´_Ïî÷ø1;L¬°Åʺ•tÆíNô™ä|Úv¶!£ͧQ2¬„'w>Éÿ¸‚›ìEGA_ŸžüS¾?íûèí:‘p„ /È›Mé.ÉýÅ“Ïà‚ý.ÀØe`…­tI Ÿ“ìù|²]å¹/@Î@_«ó¤™êôÎç¤Ño°×–÷'YîáÙ­Ïò“E?î×vR›¶oB5T„!¨ïªg宕ÉïN8ð†(Cˆ¶D‘†ÊjÊX]Îå\Î+ë^ìˆÀ_=ê«Ü1ëJ»JélëD Émo߯{;û¯ 8˜È|‚mâ­q;pè`—ëŽ Õû”¾¯Ïuä<ô Ò°£ÔbJp¹GJÞÝù}—!ùùÓº?ñͧ¾ImsmÝÔÚÄý/ÞÏïCQã,«[šü~Ì1Ì5“¶ú6d,1Dé’’ê›=›Y°v--I¢9gê9üùÔ?3–1D:"ÔÆvpísÿÅ{Ûv&ŸˆÖ®oŽcÅóÁÀnžï­]å/ò“a¬¥Ab ;H™xŸÑ¥“p½O\+3¯„¤(*Ò >\ÀE .âž…÷ðñŽ“l‹W.æš_\ÊM+ð–xQ}*QeUãjâf€€/ÀÑãFtŒNi$ÊCBå%,ïXÎöÎí,Ù¸„ö®vŽw4÷žõw¦û¦ëŠó~×F.{ü2žXñD¿«dWë.¢­1¬NË6Àryö•’õm¥· cIo¿KªîsyмõȤënÒí7Ññ…šˆdÑ-"#®%ß“ØL$!ÒíKOÀnP¡¨²ˆU«XùâJƽ:ŽjO5ÓC{{;íøˆí-Û ¡V©ˆ À«{Y×¼Ž[>fbÅDNž~2c^öæm„ŠBà$hªÊöØv>îø˜*QÅ»‘_Îÿ%å¡rr?çï\÷ôu¼Ñô›ÙÌמÿ¯¬…oŸümFÕŒê5ëÿ\ôOšÛšñVy“†×œCÆŸÑ3ìMgÜß9KÏ‘t»Ç óÀ ëƒû:i’`eÿ~~>ò|ÄkM¯ñâ¶ùOÃh*j¢ô€R<£<(U Âgoæ¬ÿw0aøΙvñ–8Fİm#‰ûëªÎ­ ™>n:-Ѿø«/&—+ƽçÝË©5§"LA´8Ê}ÝÇIwÄÍßÌÆméèêH¯Kòæê7ùÝã¿#.â¯@*9PŽ9’ry+$!³¼ïK,“Y>˾E 5мEÈ iÏn$öÖº/(©ØvsǟˤŠIi÷¸ù¼›YQ»‚·šÞ¢È[‰Í„tUgá¶…èšÎÇ_Á¼;æqÉ/áOWý‰q5ã( –ñ§¹â›Ï~“G6=‚¿ÒOk¸•ÿ÷Îÿã/ÿù 3‡ÏäýaXù0¤)YýÁj{í1b ,B Ù®À¹PŽÝMÅÏüœÙž²] }·±…ÕfAÌvO(*+B«ÔPB ¨äæèד ¥£g¶¥4ëžò½!g @Ñc!§u|虀ôNŸÜ÷e ó_‹ìßKK2­b#‹Ff½ÍŒñ3¸tê¥Ü±â*|Äô“Ê'ñÕ¿Ê”Š)ùЏêè«Xß°ž¥ K¹ú±«¹{ÞݼßÁùŠøõÙ¿Æó¬‡¿½ÿ7<åôJP(DñÐb¬ˆí{P JPO¢ìr±_dŒâY ñ¹GÈrϾÚi.GNÎYè’ ­?³6=½wÎU±®‡<©Bå¨!GõúÓ/öEYñ;v2nô8îœu'Ó«¦'¿Ÿ?{>Õ%Õ\ýäÕ¬ïXÏ•\ÉŸÏû33FÏÀ«{ùå~‰‚¿lø j©Š¥YÄ}qLÍL†ÄV„‚P**V4=NžÀÑ®E(¨BE*š¢õe¯—cOâ|oŸ3ÏgJyŠü&7ë:3R¤³·ëZHÍ©U€.ñ?'$€~B‘ “Ë&÷zÍA£bö¨Ùü}ýß7i\Zçw0gêþ»î¿¹éÕ›øXù˜Ë¾Œ?Ïû3G? MÓøß3ÿ—¸ç¥í/qÐȃدl?J½¥ö F Q3JØÓm§ÈSD‘§UØ{ÄÌQ#JK´…–H M‘&êÂuìèÜAK¬MÑÐ ]Õ»ïI¸§Ñ›`e\—!$CĹ,ÿÉðïyŒœ'€^E++5õ—DægGúÊVOVÆw¹*d+$ #ŠGôzªªœ8éD~÷aÌ.³Çëæ<—¿¼ö¶[Ù¢láÊG¯äî¹wsìÇâóøøù~ÎWZ¾BM¨†2ïŒzÈ0]ñ.:ã´ÆZi‰¶°£cë›Ö³º~5«WS©GŠÄT¬ )-ìÁBK?Z½|Î2矼ÆÕÆ"Íë4íßå9ä<ôI2,ST€L½ß9—ÍÓ¹.—!‘H!)Ò‹ú¼ö„©'Põhõ»êiŽ4SæëÞ‡• cFÕ 6lÜ@ùørv;¹êŸW±à‹ 8züѼ¨9€çW>Ϧ†M4â F” è Rä+"à ôž aïeð¨ V%OŸÅYÄÌ#ÂÍðæÖ7y£ö 6´l )ÚDs¸EUði>TEA÷&d3%€ €ùÐÉ{CþìVgM›ÈxŸùêï=õÙÄןm©‡W g\ù8V}²Š··¼Í©ûŸÚíM×V2 £ÉÀŠYøC~ê;êyo×{=þh$öF&‡=Œ?<ý¾ºä«””—0¦j c*Ç0¶f,cjÆ0¼b8CJ‡P]VÍȪ‘èºÞgþ<ªêaÆÌ2ƒ¯ñ5v¶ïdñ¶Å¼]û6k×°ºq5Má&ÞÕ³çʰŸ×ek3Ÿä-¤Ø½i’×% ‹ÎX'å¾ò>¯?lôa,zm¯|œƵy…ºÀŠÚ1ñÃac£3ÜÉæ†ÍL9…ÊP%ûú߸ĺ„üo޾ϺÍ눭A¡0¤xCBC¨UsìÇrÃ97ô-!d`HñΟt>çO:Ÿ¦®&Þ©{‡·v¼Åó›žç½¦÷P5MÕR{@ö¯ÐÒŽ}INrb&%€Œ™£|FÞzö:õ÷9Hޱ³!ÜЯrœéã‘wáå^ÎzM[G›½”× 9…Zâ-Áçõ±påB^ô0%ü톿1sÒLd©$4>DÅTL« 4)Dke+k͵¼°ínþ×Í\t×ElÚ¹éS·ò@9'9‰ýž˜ûñ_þ‚2H<' 'ݹ÷jêaS>{æ<ô…þ.ßü,&˲ØÚÖ¿pbûUï‡b*†Áwžÿ«¶¯Jû¾+ÜŻߵ= ûK‹¶hª¢2{Êl~rÿOxüÇZ>”{.¿‡ñÅãé2»lÀrV£áé§x\1•“+)šXÄK /qæïÏäÙϸ¾«ƒÕœ2€E_\Ä×ú:“‹' Gh´§vzî›n×¹Orß RçܳIùŒü&—(— ?Ý×\­Lí!ïÉ”&ï7½ß¯¢V9 â [:[:·pÙ×ñøòÇ1 {fàÞÝË’uK’nÃHˆv’ƒÇÌ”ÑS¸ê7WñÜ;Ï0qØDþ0ïTÕ„;ÂEØ=áˆ"^¦S4¼ˆ-ú.èrn~ôfÚ:ÛöHõ.Í­ÇÞÊÓóžæŽcî`vålº:ºˆÅbŸ®Lù”çó9M}²¸³BËJmç•Äê9¥]Ÿ§É4LVׯîWY–K†ÀŠ[x<>Š~Ä5_Ã)¿<…Ó~p?\ðC‚Z¬"<‚öX;O¼˜©ÕS“÷¸æŒkË0—þåRž_eo7>kâ,þ÷äÿÅÓê±C‚2½„ ü¥~Ì “_¾õKæýnK6,Ùcí¤º¨š«g\ÍCsâÁ3dfÙL¬ˆ•^Çf–2”ý/k$i÷IngõÝNs9MЇ‘ÅñõwD9G$Ëý÷™ûäy’Rò~ãûÉQº7x=^[·Oè÷þ"?FÈ`qãb^Üþ"]e]xGxQ*âjœQ¡Q|mÚ×Ò¢Ÿ8ýDþgîÿÐïä²—ñò:Û–pñQóßGþ·,b¥ëÊÎrZ!у:EC‹x½éuæýy?{âg´v´ö™÷þ¢,PÆãÏàÿðÿ8©ò$âmqûyw7> ý¼×µYëòxÈ“MZ2)âw³äË>Þg«Ü†ŠJc¸‘wjßaæÈ™}^/¥LsbÑý:¡¡!d…´;Š ŠW¡Sv2­j“+º{ÞrÑ-Œ9†Ÿ¼‘Kï½”‡®|ˆã&ÇMgÞÄÖæ­Ü³öJ†”¤Ôˆ (…âšbº:ºøÑ¢ñïµÿæ'ƒ3fœ±Û“647°³i'Ûë·óIÝ'lز÷w¼ÏûMïSGz•ŽÔ$Âçš%Ȭww÷äÔ9ä1ržzôt‰q€íl%Ö¢[öœurUëw@Òã~ŸoÓ€`ÝÕµ‹·¶¿Õ'dŠ»N°¡ »³:“ƒr9šš½y\6ë2Jƒ¥\~ßå\rï%kúYÜcÞÃŽ˜Kÿv)^õ Gï4wœ[ÿ¼•µ k)ª(ê5Ox XÄ(2xìãÇxeã+T?RÏô! aÄ8Ñx”H“;ì\#¯ -tsfåô°„¶ò˜|ŠÕu«Ùظ‘‰U{¼.sÙ úÐcut¶·n§©«‰ò@ÏNFçz.?«ÿß|â›\ñ÷+xèË1cÌ ~~öϹôï—ià)òôjiŠ@/Ò)õ”늱©uf§‰ŒJ„iW¢P…½Ü¸DÁ«{ñ{ü(%/Á}DÔÄÖdn Pf9fëð=}—-¸s>‘óFÀ>ḳˆ#ª9»¹¬¸iâ›E2„x¿bÁçhÒÍYº})½¡3’Úð#Í%yU/+kW²bÇŠ>‹ÿÚ¯åŠC¯àú¹üÞËY½u5§| 7Ÿ|3ñÆ82jKh=–kÂ#ÐC:!ŠÆQ<¾˜à„ Á AãøÇúñŽò¢Ðцh(U J…‚(ˆb;hŠðÚ#¾PDªã÷·NûºÆi;γ¸Ú^>#ç  §©‘xY–•&Ê9.²î=Ü3_ÉEDÎÿp½2?çú˱u¼ôÑK½ÎtEºì)¹Ä¨ØÛ=U¡Òmá•ô9Ãà÷ú¹åœ[8 üÖî\ËU ®býöõ|í´¯qÅ´+h­oµ7n±zøonýYA ”RÅN%ŠÝɋё|Øv 5‘œçÉæ–P³½v·®öè &–´’±òq ò€zͼ´³Ÿå¡÷i³ÏØ4 “z€—?z™m­Ûz,«¬*@/©Ø[Ìãëçµ_ë³F׌æ’—à“>V6¬ä𮡮¥Ž_]ô+fÕÌ¢yG3mmtÆ:‰±¬îÛ1#F[¤æp3-áÚcíĬXw1>›.¾'Ê1›:™íÞ.½ˆþ-ÈÊUä4ôÆ ª¢¢)z²"’–ý,{ì^²Fùä-¨ Ðoãñ5÷X^ξ‰Âê3 iïö{óK7³³egŸu5ÿØùTR‰_ñ³¬aóÿ6ŸÎx'w|ñN{—x)':‰ ­]­´EÚ0L)%íÑv† cîĹ\=ýj®œz%§Ž9•¡¾¡´t´Ç¿>•Ñ-þ›¶ ¦*ZRBØ6œ ÈU# L §/í(2ŠŠiš¨–jOZR„ ’{ÕC¦íÆ%-dˆŽ°òh*Ц¨<°ê~®=âZŠ}Åݾû]Qú‚®j¼»ë]~±ðüßÜÿëõÚQCFqô¨£yjÓ“ø‡ûXXû*×=x-÷_õ¹ì/ü嵿pîÔ¹Œ¬Ü÷ÞgñæÅ¼ôÁ‹lëØÆWû óžÏ!CIަ‘x„5ukxõãWùÛò¿ñqûG¼AEì^­È,Ÿêïi%©óÙå-çZ™ØtF&lN&º¢¡©=Ç)H¨’~•ø¾G.KÒ0Œ¸£ã§-‚‘ÕƒWõaZ¦ËE3a°\É´Ià„¡0µspúü¸ÕO×Ð\KB(|Ôü1­z,kaªŠíd³[÷• ê*O½ÿïly§Ï ;눳ˆ¶Ä°¢q€Ç?x‚뼞ʢJF•â»ÿ·îǼpÙ ,¾j1¿>å×Ì:#M”öé>q(ß9æ;ÍG@ Ø{:b¿³”µKn®ï<$,AÌŠqïŠ{Ó,þ’ÑtäîÝ×§úØÚ±•o=ù-v6÷® ºÿ¡x£^¬;ž@¨$Ä‚U øþßç™òÝÓ¿ËŠ Ë9ógrè÷åßeÆðC“äÔÆTŽáçý‘?áÏŒ÷§½µ˰ölšÇL»€Ej™tâ:iHZ¯æíQÔÅb)¥IZúÜA®@R3M3ÞÞÞÞœ-¬²…EФÄ[‚i˜HÓ^Ü“\nfé<”ãɧùX¶}¬x {E+ʧ{F È_Äâ­‹¹þ¡ëéŠöì T^\Î5ëˆ%÷ (*-âW‹ÅýoÝÏÌ 3ùõ¥¿fÚèilÚ¶‰e›—íVã8ÿÐóyòÊ'¹hâEDÛ¢Q£÷g’}œswzÈÞéÝ×H—@‚iš”Ê(ö'·”sà„µoooo6M3Fºr‘3È5€DцٵkW]6À´LнŔúK1M3Ms¦|èMëJšÒ/pôd÷ç|‚" apÏÒ{ØÙ–>Z{tOªtw‰r, ñäÆ'ùÞcßë±\þc‡Œ%ÞO® ŒÉ7žz#1+Æo?€‚Âmç߯Ó`ÑÇ‹¨o¯ß­ìŒ¯ÏŸ/ù3??ùçx£^¢áhÏÏ”yÞ­×Ë^¾³2Îg$g6É4MÊýåûŠmU4Ë4à®]»ê ÈÐÍó!7käàp8ܱzõêMBˆî€eQâ+¡"Pa[’Ý#|o,>à‚ÜOAowëÞå7 “Vf—Kì§¹7àù¹{ÙÝüüÙŸg­¼€7ÀˆÊÈ. qèwpîäs¹ýŒÛùòì/cÆM–¼¿„%ë–pçEwR(ãÚ{¯¥±½q·‰Ïãã'ƒG.{„±Þ±t¶ub™Ö§¶î§eŸ3Ï%ÚUeQ%¥þÒn›¡:mvÍš5ŸD"‘ÎŒ;ä r Õe#«V­Ú©(ݳhI ¯î¥º¨œuÙ¦L[ŽtIöJ,ÙYò4¼~~÷æoyêݧ’e¶~Óú´ØvŸ&iª†TùÅŸóÀÝÕ T—TCŒHœ _9O»U¨èªÎ§ßHk[++>\Î]ÏÞÅó~³0›>ÕvÑN˜|ÿüò?9q؉t4w`Å]Ï×[‡NZõ³|Ÿ9xdª‰ÁÄYpVªÁ¯û»©`«]ï¾ûî)e8õËÜB®MºÍ-†”2Fñz½Ý.4-“ªâ*ZÃ0QU,‘J$¨V€®éÒÞâ(ÎLMæjÀ\ŸÇÍ!15Æ×û:eþ2Ž9à®Xˆ)ͤnúi›¢Çã!bFøîÓßaDùŽ|lÚ÷%ÁˆA,c¿’Q:üÐäw¡ nºà&.¹ýbÞúøm:Œn¿äv^]ý*í<õæShhœ1ó ‚þ`¿ò3qØD\µ€ï>úî[}?’Š&HV›»úÜj¡$û4 û½«ó§ÿ0%–aâ×}T…ª0,#kÞ¢Ñ(‰ÎïDbÈ95 ×$€„ ˆ‡ÃáæÖÖÖÎlºU܈3,4Œ ÄŒ›H“äôŒ´ì©Âd$—Œ”¦Ïõð>Ÿ“” ëjcµ\þ×˹ÿµûYþñrobúé%iI|>õÖ.®}ðZÞßž’̧û FܤÄS’¶Àøáã™7ó<‘0O/}še/ãÚS®å†³nàÄé'2vøX~p÷øÖ]ßbéÚ¥©UŒ½ ª¤Š?^þ'¾zØW±:,¬˜ìý9ú#¸;¿s­K0 ‹"O1È7âYõÿ¶¶¶ÎH$Ò ÄIŸ_Èä@Šd]]Ý–uëÖmVUµ› fƘX3‘Ê`%q#ŽeÙ! œäÌéZ–EO¾–´’×ôæË=ØÁ??mòù}ÔYu\sÿ5|ýO…üØÎ@ FêøÙر‘/ýýKÔ·¤ yÝ“lê%{üþ/Ÿöe††€¿ßŸ<_SVáåG_þ¡¢'|ý&_6™¯ýß×øç²òý•l¯ßN$Ò}vØ£{øÞéßãð²Ãéhê°UÁÌðq™AÝóþd¹>Ó/ÀuÃ4¨,ªdÒ°IÄŒXZ^„¨ªÊÚµk?Ù¹sçÖD›v$€œB®©.ó fsssýêÕ«kO>ùä)†‘.fYÒ¢,PÆøªñlhØ`ÿBµ „ŠTìÑ_\–O^}{ºOÇR,Hô3ů°§&7‚ÅA–ìXÂWïû*ýò_)öc˜F²3 cÊŠË8ýàÓùÃ+ àé¾_@(â‡Wý‰c'rý¯ç·/ý–ß>÷[Bþ‡NdtÍh†•£¼¸¿Çi™4·5³ö“µ¬Þ¶o‘—©%Án$šAZ,çØ“Ú·“«GMÛUzüñ”ÊéŒfñ»PUÞ{ï½Úæææzí™”r eˆ±p8܉DP¥›>7ãÌØo/®Ë´PLJâ:A*bp>Ý=¸Û—y EWìUsŠÒ³žI †‚<±á †=6Œ;çßi¯9HÈ•áXÃ2Дôf&„àˆýàÿ!ëhîà‹Ç}‘¡UC¹æîkø ébjŒ­+XV» Â@,‘,ìÿéo¹×Ždäˆën÷›žôüžÎ¥ G$[¦4%ááð±‡7âÝò-„ ‰ÐÕÕÕD±ÛrAè'ˆæÆ×lÛ¶íôQ£Fe@̈1kì,J½¥4ÆmÝ6AŠP’Qr¤%Aéç¼þg€”²·‡ŸE¯ØÇŸÞú“†N²WðylŸ„ŽHÔ„jºýnxÕpC]S]¯÷?fÊ1Üwý}\uÏU¬mZKQy‘­—2Ù¥Üñù…–I®¸8_'ºŸ;Œ\Z™¸?gŒúîX–aQá¯à˜ý!fƺ LB¶mÛÖ±qãÆ5Ø¿Š‘£³¹lˆÖÊ•+×ðÁ Ù¦‘àÕ¼L9 #n¤ûpûq»7p½ì[ÈÏ­z°§ ª*j@å–çnáËÿV¥¡é-‘–—({u/˜ð·ïôYþ‡M8Œ¿_ów®:˜ÎH§ÝÁ‹… ¤L TØÁA”òD€¯HI'ÛsÞ°FÄàø‰ÇSSRCÜŒg"miiiÙ°aƒ#DÉQýr—$‰Yl{o뫯¾úf<'Ó`I UQ9rì‘TW‹ÆRÞÝ;¾kå eYÉxIÏàbû<¹bü}¼ëãnóä‘h„Å+£ym[A»ÕÎWïÿ*?~èÇl¯ßÞgã˜9i&¼ê”¥Ä:b½ªxÉ:·¬¿ËzÎÕ~ß’X4FeI%Gî$ª¢vsÿU…x<Î+¯¼²h!5W‘³1r•œ™€(–R¶¾òÊ+«¢ÑhÖ(Aáx˜é#§sÄè#0cfÊñÒ2c˜©”FiÐGÔ¯N:¹õ©[9ãÇgpË=·°¥vK¯ ä¤é'qÇEw [%fØì¦¿wÕ3Ï™=œ3²Ɉ1ö¦žN8î–')%ÑhT¾òÊ++¥”­Ø%G§!w ì‹cb¸¡¡aËòåË7hšÖÝ(íi¿S:…b½+jAÜ¥8L}¯öjòª^ÖÕ®cksúæxøÄd̶Öë€Ý£(°ºy5?}æ§ÌüúL.úáE<óú3ìlØI¦#Àe']ÆuÇ^G×®.d<£~]õœæÊÛS~q]ïV M{ºÑŠ[ëÅÌ™6U¨Y§þ4Mcùòå¶8í6цs²óC~@wttìx饗V: !S÷êŠu1kÜ,Ùï{ç7ëgœsìU(B¡#ÚÁ¢ ‹’ç^}ëUžYø ª_µC|»öT< ÁŠ Þ!^š¼M<öÞcœõã³8òÚ#¹öç×rß¿îcé{KinmNþæþ€#GIWc—=ÎBZ‡–ÈôNNï3‡Î1aº‹ÇãL3ÙgÓíÊê2n/½ôÒÊŽŽŽØß1æ,ä¢#IJ èÄ^¼béÒ¥ÇuÔQÃâñxVÏÀKg^ÊŠÍ+0 ÃvRd2t³$±}–Ó A"óX ‡=† 7ȽoÞË•G_IíÎZ¾þ˯ÓiÁ?ÜPR “ éº-|Å£ iÈrImg-÷,¾‡{^¼‡!åC˜4b“GMfú„éØñ\8óBV?´3b¢úU»-ì}Ü]Ïyïù×¦Íød -çú˜Ì|ÛÕ9Îèÿæ›oîXµjÕ ìŽßIJüÏÙ•ëàÌ„®†††O–-[¶fúôéÃt]ϺãA#b渙ü{ý¿ñ+þô]bk’‡: ³zò+PNCAaKóNüßißÑζÛðUû%öÞ}Ý\u{· ¡ ¼>/ž+fÑØÙÈÂ²ð½…ø¼>†– EÓ4KÁŠYà!µöÃÊrïL‘?³ó»Gþ„ê‰D8é “˜ºßÔ¬ëþ…„Ãa–-[¶¦¡¡á ‹”þŸ“Ór™ 5:€è3Ï<³pΜ9GO˜0¡Û‚qKZøt—u)Ë7-§5ÒŠWñ¦72Ç^d¤Ìÿê @†¦illÚø†ùº½ËTeÿº† (öš߃§ÌƒŒK̨ɖðDL {ô4·ïûdûœèôIÝß5‹Ä(õ•2ö|¼º—H–8µB>ùä“Îgžyf!v§ï ¥ÿçlç‡Ü¶@úl@ÐÖÜÜ\û /¼ÙÕÕ• náNÑx”ý‡ìÏþÂö¨àXt3-½ý ff¹6 lù–|>¾Rj™ŠRìmÉE?~ë.ó„ð¿‚ÒñWùñUùPCª½è R;@eZùÝ÷tô=ÌȸMgz&ûÛŸh,Ú}‹:!èêêâùçŸÿOsss-Жh«9mýwëvưŪ6 å©§žz­®®®Ã²¬îñ¥…*T®>þj¦ B4EÆeÒš‹™aÎF=‘BL­åm[Þô’;z¿ÄNÀ艤¤[ð»Hæ=ÜŽ?R¦¹û:¢ÿ䓹ö¤kÑ„–5ò¯eYÔÕÕu<óÌ3¯cÏý·%Új̕ӜE>€c ŒÚÚÚ¶.X°àEQÈæ3c½A®˜}A5ˆŒI{ZÐ!ƒô9þÞ:wo£R_×Ò§KÙÊ5[™gHeÉ‘?[ÝôÖù3ÛEbôè®8þ ‚¾ 13Ý™ lP… ¼ÒÚÚº•Ôè!Çò…c`'v!·¾ýöÛË–/_^«©Ýý‚H,Âìf3Ö|"ÑHº?€›õÿà>fþwIßUÙßë è»S~uÖk]f¾—¿sAâD™Ì|Ž|,‘X¤ÛRr'êÏòåËk—.]º hÅn›Žõ?§ò e cr[CCÃG?ü𦖦¸,$[ȯ ޏ€i#§ÑÕÙÕÝ`ºFl¸7}4[cíi´’ œ {Tî+}ÚçÈëéå»,:¼D¦×a¶Qßùm6‰!ÓÆc@¤3ÂA£⋳¾˜:ÎE¡¥¥%þðÿºk×®v™h£9¯û;È€”1°hº–,YòÖ¢E‹>0 #«*7â„ü!®;é:ª‹ª‰„#) ¯ËÅ3ùÙm ìM¬Ï%3L}© æ§HƒÝÁûJý}ŽÞȱ7ckæÊ’¿wêܰ’F?˰¸î´ë˜;s.‘N²û{σûî»ïå–––ÍN;$5õg’GÈuG 7œÚpƒÚ€F ð /¼>~üøÑ—\rÉ´ž"цca.™} --,X¼ÕRQ5 ¡%ÜQU›0Òì=éŸ{2.9ØÇ¡¼#ö"úÒ’]ß»ãþõêß/3~ï>ïèþnw_Ãöá7ã&óŸÏüãæÓéyTUUy衇V>ÿüó¯c·¿FRº^þ€S1l½«h”RÖ?ô‡ž_µjU½¦Ùœ–-Pƒiš\uÂUÌ=t.±h 3n¦Ô€Ä‘¶ÝxoÆ¿þêû…)ÂO=Åš¸%Û½2‚îÏf÷{¦© ñߌ›Ä#qÎ9ü¾tÒ—0L#«ÑlÆÕï­®øá‡_RîÂîü͉¶#ròùFª>ÇÐ4ïjØõñÝwßýB]]™mCQ° éªÎus®ãìCÎ&‰#cvà‡dØF‡2c ¤c¶>Ø©¿å‘‘§§Nÿ)Td:6Ÿ„*ÆùÂa_à+g|¯æµÃšgÀiOuuuæŸþø§êëë?"%ú;ºÞXþÝÈGpÖoű=®Z€]@óŠ+–ýö·¿}1‰ÍKÀ0 ‚Þ ×Ÿv=sŸ‹7°âVÒûËÿ­×ð`}5ÄÁus%õQ6Ù" uÛŠ«?’XõàDøIJx‰@/–aaÄ Î>âlnøÂ ùŠzìü–e‰DøíoûâŠ+–aú»m¯‹” ™w+GòÉàÀ±ÜktÀø^|ñÅEǯ¸üòËPÕîÀ&’@ _?ãëx4¼ùª¥¢¡!•ÄF" j”Šì¾Ÿ€{%a_¹, ýÚlUörNf9ÒϹ|’:¿ FÜÖùÏŸu>×~Ao°[Ø2Üÿýo¿øâ‹‹°;=醿¼ðúˆ|$7ç hÀö4×xà***‚çÌ=ç@EQ²nQ3bxu/ןz=EÞ"î]t/q+Žîµ— E$WJ‘0 *t_Fœ ~m:ò9CÖxÿ²×ô}Nöp´RÇ´¨ÎÎÈŸæâÑ8Ò’\yÒ•\yÒ•x4O_Q$’gŸ}ví<ðö¨¿»­µ“rúÉ[ä38Õk`‹a*6x£Ñ¨vÏ=÷<_QYQ<{ÖìQ}ä‰q„üלÿ¢4XÊ^øÑp׃a‰Ô‚“ÌQ?c±»1ô4«ðy„ìãsO×ÈŒ÷™ê€ÛøgÚu‹Æðª^®;û:.<æB¢ñh¯#¿”’Åo,þäž{îy.nÃùH‰þ†ë¿å%ò™8 ¬`‹g 555i·ÿòö'¼ïù‡~øpÈNÎâK޹„ÊâJîzö.v4íÀëó¢h‰=õ,R£¿sLDÊO /a @=?_Ùù!5Eèö)«¿eXÄÂ1†T ᆳoà´CO³çù{PG£ßÒeK·ÿê—¿z²©©écìÎ_GÊêŸW=AôK'ÛW™ŸJŒvº Ž½n)P Œ†ÔÔÔLþÁ~p:Ô ž ŠPðé>Öm]ÇÝ/ÞÍ’K°„…Çã5±Ë°«ó'Éz,òy× v§iÉ^Îg#×ù´ƒ 8",C‘ GìÿuÆ1eÔ¢±hÖÈ>`‹ýŠ¢°|ùòÚÛn»íñºººuØbÿvlha€sþ9Õçr*3ŸŽ Õ=¤H ›j†:é¿¿õßg}ÔÑÃMÓìµ4ECUTZü÷¾z/MmMx^;E& ()Ñ?z,›ðóNnô× {9JרŸMäOÌ*ĺb”—rÅIWpÑña™†Õó -„½¡É[KÞÚ~ûí·?Y[[»»Ó;¿™T¬ÿO-úçTŸË©Ì|z€teØ$0 RUU5á†n8söìÙcTUíõFŠPÐ55[Öðà¢yeÕ+¨ºŠ¦kÝ ›4ö Ý›Éç™ú"€žT·q/ñÙ­ó»cqÓ09áà¸äÄK8hÔAÄx£¾˲xã76Ýyçÿª¯¯ßˆ=òï eõwúøÔ'§ú\Nef`v×R±íEØ$P jÀè/ùË'Ï;÷ ]×{Tì ‚¾ í]í<¾äqžYú ›ê7¡¨J’„ÝmN.Üvwî2sûyÀFý4·_÷4ŸkÔ—Òñ˜eYŒ©ÙGœÉ¼YóBt†»ûõ»áìèóÄO¼wÏ=÷ü»³³s3©‘¿{äï å6 N“S}.§2³gR’@)›À0l‰`èE]tÂUW]uD0}©ª¢¢©µMµ<²ø®^HmS-B¶} “ܶwnp‘AODЗoA®` MFöþ>ÙY]S{™zR"0íÅ92&R9„ã¦Ç…Ç^ÈЊ¡¦iõ¼6Ç êÑÙÙ)ÿö·¿-}ðÁ_j±;ÿfØßâ«@{%3'èNAl¨†C€ÊãŽ;|å+³†4;p)B!à °në:^~÷e^|÷EjkmÕÀ£¥Dÿl$>¯þ™|dÖóÙ:|šƒ´·ê2c&C*†pÊ!§pòŒ“™2j ]‘®>Å}°ölß¾½ó÷¿ÿý-Zôì)¾Ø$àL÷uÚÝ×ÃO_¹Ôçr*3{†’·#Ý&PTbÀP |ÿý÷?ðšk®9îðÃ֓ÉßãG ·mäuoð¯¥ÿbkÃÖä^õŠ¢¤Œ…dYŽŸg¸‹»'cŸË-ØÙÄÕÙ´udÕHÎ8ü f8‹‰#'bYáX¸ORuêzéÒ¥;î¾ûîE7n\ƒ­ã;£¿{®/òÉ©>—S™Ùó)›@ت@ Påóù†]zé¥ÇΛ7ojYY™’mÇ¡î7ø<> Ó ¥³…w>|‡ç–?dž­hélÁ4L„G kzê™×óeÎä‹è¿'ЗS.^ìNo–aï],á€ýàôÃOgƸ”•¢©‘X¤W=ìò×uææfëŸÿüçêûï¿ÿµH$âˆúu‰Ô„ßÏqôÙc#ò‘s©ÏåTfö,@º:à¬(ÊIIÕ@ŬY³>ï¼óŽ<üðÃ+åÃ}(ÂŽL¬©ïo{Ÿ7×½ÉÚOÖ²aÛê›ëíæ£ÛKIUéæ<”üœ‰|Ÿ9èO³’Ýõ})íÑÝ0ìÈM¨P]VÍ#`òèÉ=åh&Ž˜ˆaÉØýª§Dé¥K—6<öØco½ñÆ«°—óÖ“rïu¯îsïé·G;INõ¹œÊÌž'€ä­±I@¼ØÆAG%¨N¤ÒP(4â¼óÏ›yîÜs§–””¨ÎBþ–‘®êø½~º¢]¬ûd›ë6³~ëz>Øöµ-µ4¶6Ú÷$¤£"¸¥ƒ~Ùr§Úú w9:¢½;^¦½ñGE¨‚¡eC?|<“÷›Ì~5û1eô‚¾ áH8몽lp:¾”’ÖÖVóñ'_ýØ£½ÕÖÖ¶[į'åÞÛJ÷ =öJ)çTŸË©Ìì=€Ô¸«b“@€”4P…Må@å~ûí7æê«¯>zÆŒ#KKK“ÁDú E(xu/š¦Ñî ¹£™®H‘N¶7ngë®­Ô6Û„Ðn§+ÒEW´ Ó21Ms·þW>AUTTUEUTž€b1% )Â~•û1¼r8A€7@YqEþ" à ö˰—ü_ªêDîeÅŠ[ÿüç?ÿgË–-›HôõØ¢¿3êw‘Î{¯uŒœês9•™½KNŽJàL:DP ” !*Ž8âˆIçŸþ¡tPU(‰;¸;e¦ÛµÔQ,i»#›–ÙM„MÎyÆáÔ³[…RUQí‘Éø»Óéûz<ÚÚÚxï½÷v=úè£Ëß~ûíõRJ'zO©ŽßBj#ÇÒ¿W;? çÌì}Hþ+ÒU·4àØ*°‰¡ä”SN™6{öì ³gÏ®ëzr„HÙõ¨ûá¶| 8íFUUâñ8‹/Þ¾xñâ^z饕آ} ¶¾ïŒþ™£þ>]Õ—S}.§2³ïRÝO#% ±m¥¤È ú|¾!“&MsÖYgM>òÈ#Gùý~oBwܸö û‰ãŇyë­·>yúé§×­_¿~S$ÙI*^¿“Z° ¡“Ô¨ï,Øg˜KmåóLÉKJp|‚ØA6”aO!ëº^YYYY}ÞyçM6mÚ¨áÇÊÊʰ,Ûrçs¨\? p« š¦¡( ÍÍÍlß¾½kåÊ•Ÿ<öØc«êãñ¸¬£ [äo"·¿“ÔÜþ ­åÏ¥¶Q €RÓ…n"‘P°‰ ›ŠE Í™3ç€I“&œ8qbù¤I“J}>ñx<Í—KeœOp·UUÑuH$Âúõë[Þÿý¦õë×o}ñÅ7X–ålÊÙŽ=Â7“ýýúœŽïLï ZÏ\jÈÈB"i¤ì~l"(Â&ƒR$J|ï«©©:eÊ”‘eee%'œpÂÈqãÆUú|¾äs9ÏV²Ã=ÂijU$á£>j\¸pá–¦¦¦Öµk×n­«««Åã="œÎïlÒÙÝñäô|'vß ~.Õ}²dÃutf ¼Ø6·zàB(ñÞï\SVVVYRRòûýþãŽ;nÔ8¤¼¼¼Èãñè~¿_ñz½I1VUÕ\yî})%¦i&Õ§h4J8¶b±X¼©©©cÍš5;-ZôIWWW¸­­­½¹¹yöHîtüR›r:@§ëš(éÖ}Èy–œês9•™Üên"ÐHù8ê#8©(‘‚ØDàH~UU}B®ëžƒ:¨z„ 555%Á`Ðïõzu]×Õij‹,eS…ò)ÖÀíMJ)‰Çãf4wvv†ëêêZ?øàƒÆ÷Þ{¯>Ǥ”1Ó4ŽîŒâìÎÝNj„wR˜”˜ïÌ绣õæLCÏ©>—S™É-HËéÆBG=ð¹’›ÜÉ9ïM$Ýõ{Åuìm‰PÎJ?ÑWo'°«k¿âØ8ŠÝ±ŽïNÎy'¹Å|÷âœCNõ¹œÊLî@2‹¤;9SˆŽšà!E ™Gë)2PÉMà³ŠÌø½ÎHǽû?îX?Ù¶uùÎÑ>Q €½ƒÌÆê¤Ãç=>POûû¸¿+`/âÿr.áÕŠ1aIEND®B`‚olive-continuous/app/packaging/windows/nsis/olive.nsi000066400000000000000000000043641370472574300234260ustar00rootroot00000000000000!include "MUI.nsh" !define MUI_ICON "install icon.ico" !define MUI_UNICON "uninstall icon.ico" !define APP_NAME "Olive" !define APP_TARGET "olive-editor" !define MUI_FINISHPAGE_RUN "$INSTDIR\olive-editor.exe" SetCompressor lzma Name ${APP_NAME} !ifdef X64 InstallDir "$PROGRAMFILES64\${APP_NAME}" !else InstallDir "$PROGRAMFILES32\${APP_NAME}" !endif !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE LICENSE !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_INSTFILES !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_RUN_TEXT "Run ${APP_NAME}" !define MUI_FINISHPAGE_RUN_FUNCTION "LaunchOlive" !insertmacro MUI_PAGE_FINISH !insertmacro MUI_LANGUAGE "English" Section "Olive (required)" SectionIn RO SetOutPath $INSTDIR File /r olive-editor\* WriteUninstaller "$INSTDIR\uninstall.exe" SectionEnd Section "Create Desktop shortcut" CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${APP_TARGET}.exe" SectionEnd Section "Create Start Menu shortcut" CreateDirectory "$SMPROGRAMS\${APP_NAME}" CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\${APP_TARGET}.exe" CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe" SectionEnd Section "Associate *.ove files with Olive" WriteRegStr HKCR ".ove" "" "OliveEditor.OVEFile" WriteRegStr HKCR ".ove" "Content Type" "application/vnd.olive-project" WriteRegStr HKCR "OliveEditor.OVEFile" "" "Olive project file" WriteRegStr HKCR "OliveEditor.OVEFile\DefaultIcon" "" "$INSTDIR\olive-editor.exe,1" WriteRegStr HKCR "OliveEditor.OVEFile\shell\open\command" "" "$\"$INSTDIR\olive-editor.exe$\" $\"%1$\"" System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' SectionEnd UninstPage uninstConfirm UninstPage instfiles Section "uninstall" rmdir /r "$INSTDIR" Delete "$DESKTOP\${APP_NAME}.lnk" rmdir /r "$SMPROGRAMS\${APP_NAME}" DeleteRegKey HKCR ".ove" DeleteRegKey HKCR "OliveEditor.OVEFile" DeleteRegKey HKCR "OliveEditor.OVEFile\DefaultIcon" "" DeleteRegKey HKCR "OliveEditor.OVEFile\shell\open\command" "" System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' SectionEnd Function LaunchOlive ExecShell "" "$INSTDIR\${APP_TARGET}.exe" FunctionEnd olive-continuous/app/packaging/windows/nsis/uninstall icon.ico000066400000000000000000000627751370472574300252250ustar00rootroot00000000000000 hV ˆ ¾  ¨F00 ¨%î g!–D(    ÿÿÿIÿ¨ÿåÿýÿýÿåÿ¨ÿHÿÿÿÿÿÿ’ÿïÿÿÿôÿâÿâÿôÿÿÿïÿ’ÿÿÿÿÿÿ±ÿÿÿåÿˆÿ=ÿ ÿ ÿ<ÿÿ÷ÿÿÿ±ÿÿÿÿ’ÿÿÿÎÿ;ÿÿÿÿÿyÿûÿüÿÿÿ’ÿÿIÿïÿåÿ;ÿÿÿÿÿ^ÿòÿçÿ}ÿãÿïÿIÿ§ÿÿÿˆÿÿÿÿÿCÿåÿöÿgÿÿˆÿÿÿ§ÿäÿôÿ>ÿÿÿÿ-ÿÒÿýÿ…ÿÿÿ>ÿôÿäÿýÿâÿ!ÿÿÿÿÿ¼ÿÿÿ¡ÿÿÿÿ!ÿâÿýÿýÿâÿ!ÿÿÿÿ¡ÿÿÿ¼ÿÿÿÿÿ!ÿâÿýÿäÿôÿ>ÿÿÿ…ÿýÿÒÿ-ÿÿÿÿ>ÿôÿäÿ§ÿÿÿˆÿÿgÿöÿåÿCÿÿÿÿÿˆÿÿÿ§ÿIÿïÿãÿ}ÿçÿòÿ^ÿÿÿÿÿ;ÿåÿïÿIÿÿ’ÿÿÿüÿûÿyÿÿÿÿÿ;ÿÎÿÿÿ’ÿÿÿÿ±ÿÿÿ÷ÿÿ<ÿ ÿ ÿ=ÿˆÿåÿÿÿ±ÿÿÿÿÿÿ’ÿîÿÿÿôÿâÿâÿôÿÿÿïÿ’ÿÿÿÿÿÿHÿ¨ÿåÿýÿüÿäÿ§ÿHÿÿàÀ€€€8xøðÀ€Àà(0   ÿÿÿ;ÿŠÿÊÿíÿüÿüÿîÿÊÿŠÿ;ÿÿÿÿÿ1ÿŸÿêÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿêÿŸÿ1ÿÿÿÿÿdÿâÿÿÿÿÿÿÿüÿìÿßÿßÿìÿüÿÿÿÿÿÿÿâÿdÿÿÿÿÿxÿôÿÿÿÿÿíÿ§ÿ[ÿ/ÿÿÿ/ÿ[ÿ¦ÿíÿÿÿÿÿôÿxÿÿÿÿÿdÿôÿÿÿþÿ¿ÿAÿÿÿÿÿÿ°ÿÿÿÿÿÿÿôÿeÿÿÿÿ2ÿáÿÿÿÿÿ©ÿÿÿÿÿÿpÿöÿÿÿýÿþÿÿÿáÿ2ÿÿÿŸÿÿÿÿÿ¿ÿÿÿÿÿÿTÿíÿÿÿúÿ•ÿ¿ÿÿÿÿÿŸÿÿ;ÿéÿÿÿíÿBÿÿÿÿÿ;ÿÞÿÿÿÿÿ¢ÿ ÿAÿíÿÿÿéÿ;ÿŠÿÿÿÿÿ¦ÿÿÿÿÿ&ÿËÿÿÿÿÿ¼ÿÿÿÿ¦ÿÿÿÿÿŠÿÉÿÿÿüÿ[ÿÿÿÿÿÿ³ÿÿÿÿÿÒÿ-ÿÿÿÿ[ÿüÿÿÿÉÿíÿÿÿìÿ/ÿÿÿ ÿ˜ÿþÿÿÿäÿDÿÿÿÿ/ÿìÿÿÿíÿüÿÿÿßÿÿÿÿÿ{ÿùÿÿÿñÿ^ÿÿÿÿÿßÿÿÿüÿüÿÿÿßÿÿÿÿÿ^ÿñÿÿÿùÿ{ÿÿÿÿÿßÿÿÿüÿíÿÿÿìÿ/ÿÿÿÿDÿäÿÿÿþÿ˜ÿ ÿÿÿ/ÿìÿÿÿíÿÉÿÿÿüÿ[ÿÿÿÿ-ÿÒÿÿÿÿÿ³ÿÿÿÿÿÿ[ÿüÿÿÿÉÿŠÿÿÿÿÿ§ÿÿÿÿ¼ÿÿÿÿÿËÿ&ÿÿÿÿÿ¦ÿÿÿÿÿŠÿ;ÿéÿÿÿíÿAÿ ÿ¢ÿÿÿÿÿÞÿ;ÿÿÿÿÿBÿíÿÿÿéÿ;ÿÿŸÿÿÿÿÿ¿ÿ•ÿúÿÿÿíÿTÿÿÿÿÿÿ¿ÿÿÿÿÿŸÿÿÿ2ÿáÿÿÿþÿýÿÿÿöÿpÿÿÿÿÿÿ©ÿÿÿÿÿáÿ2ÿÿÿÿeÿôÿÿÿÿÿÿÿ°ÿÿÿÿÿÿAÿ¿ÿþÿÿÿôÿdÿÿÿÿÿxÿôÿÿÿÿÿíÿ¦ÿ[ÿ/ÿÿÿ/ÿ[ÿ§ÿíÿÿÿÿÿôÿxÿÿÿÿÿdÿâÿÿÿÿÿÿÿûÿìÿßÿßÿìÿüÿÿÿÿÿÿÿâÿdÿÿÿÿÿ1ÿŸÿêÿþÿÿÿÿÿÿÿÿÿÿÿÿÿþÿêÿŸÿ1ÿÿÿÿÿ;ÿŠÿÊÿíÿüÿüÿíÿÊÿŠÿ;ÿÿü?ðàÀÀ~üüøð àpÀðððððàà?À€?À~Ààðü?( @   ÿÿÿ)ÿlÿ¬ÿÙÿòÿýÿýÿòÿÙÿ¬ÿlÿ)ÿÿÿÿÿ7ÿ—ÿßÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿßÿ—ÿ7ÿÿÿÿÿÿ‰ÿêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÿ‰ÿÿÿÿÿÿ6ÿÂÿþÿÿÿÿÿÿÿÿÿÿÿ÷ÿçÿÝÿÝÿèÿ÷ÿÿÿÿÿÿÿÿÿÿÿþÿÂÿ5ÿÿÿÿÿAÿÙÿÿÿÿÿÿÿÿÿ÷ÿÄÿ}ÿFÿ(ÿÿÿ(ÿFÿ}ÿÄÿ÷ÿÿÿÿÿÿÿÿÿÙÿBÿÿÿÿÿ6ÿØÿÿÿÿÿÿÿýÿÅÿUÿÿÿÿÿÿÿcÿïÿÿÿÿÿÿÿÿÿÙÿ7ÿÿÿÿÿÁÿÿÿÿÿÿÿ÷ÿ‘ÿÿÿÿÿÿ€ÿûÿÿÿÿÿÿÿÿÿÿÿÂÿÿÿÿÿ‰ÿÿÿÿÿÿÿ÷ÿ}ÿÿÿÿÿfÿôÿÿÿÿÿþÿþÿÿÿÿÿÿÿŠÿÿÿÿ7ÿéÿÿÿÿÿþÿ‘ÿÿÿÿÿKÿèÿÿÿÿÿÿÿ½ÿŸÿýÿÿÿÿÿéÿ7ÿÿÿ—ÿÿÿÿÿÿÿÅÿÿÿÿÿ3ÿØÿÿÿÿÿÿÿÓÿ,ÿÿÅÿÿÿÿÿÿÿ—ÿÿ*ÿÞÿÿÿÿÿ÷ÿVÿÿÿÿÿ ÿÃÿÿÿÿÿÿÿäÿDÿÿÿVÿ÷ÿÿÿÿÿÞÿ*ÿlÿûÿÿÿÿÿÃÿÿÿÿÿªÿÿÿÿÿÿÿñÿ^ÿÿÿÿÿÄÿÿÿÿÿûÿlÿ¬ÿÿÿÿÿÿÿ|ÿÿÿÿÿŽÿýÿÿÿÿÿùÿ{ÿÿÿÿÿ}ÿÿÿÿÿÿÿ¬ÿØÿÿÿÿÿ÷ÿFÿÿÿÿqÿ÷ÿÿÿÿÿþÿ˜ÿ ÿÿÿFÿ÷ÿÿÿÿÿØÿòÿÿÿÿÿçÿ(ÿÿÿÿUÿíÿÿÿÿÿÿÿ³ÿÿÿÿ(ÿèÿÿÿÿÿñÿýÿÿÿÿÿÝÿÿÿÿÿ<ÿßÿÿÿÿÿÿÿËÿ&ÿÿÿÿÿÝÿÿÿÿÿýÿüÿÿÿÿÿÝÿÿÿÿÿ&ÿËÿÿÿÿÿÿÿßÿ<ÿÿÿÿÿÝÿÿÿÿÿýÿñÿÿÿÿÿèÿ(ÿÿÿÿ³ÿÿÿÿÿÿÿíÿUÿÿÿÿ(ÿçÿÿÿÿÿòÿØÿÿÿÿÿ÷ÿFÿÿÿ ÿ˜ÿþÿÿÿÿÿ÷ÿqÿÿÿÿFÿ÷ÿÿÿÿÿØÿ¬ÿÿÿÿÿÿÿ}ÿÿÿÿÿ{ÿúÿÿÿÿÿýÿŽÿÿÿÿÿ|ÿÿÿÿÿÿÿ¬ÿlÿûÿÿÿÿÿÄÿÿÿÿÿ_ÿñÿÿÿÿÿÿÿªÿÿÿÿÿÃÿÿÿÿÿûÿlÿ*ÿÞÿÿÿÿÿ÷ÿVÿÿÿDÿäÿÿÿÿÿÿÿÃÿ ÿÿÿÿÿVÿ÷ÿÿÿÿÿÞÿ*ÿÿ–ÿÿÿÿÿÿÿÅÿÿ,ÿÓÿÿÿÿÿÿÿØÿ4ÿÿÿÿÿÅÿÿÿÿÿÿÿ—ÿÿÿ7ÿéÿÿÿÿÿýÿ ÿ½ÿÿÿÿÿÿÿèÿKÿÿÿÿÿ‘ÿþÿÿÿÿÿéÿ7ÿÿÿÿŠÿÿÿÿÿÿÿþÿþÿÿÿÿÿôÿgÿÿÿÿÿ}ÿ÷ÿÿÿÿÿÿÿ‰ÿÿÿÿÿÂÿÿÿÿÿÿÿÿÿÿÿûÿ€ÿÿÿÿÿÿ‘ÿ÷ÿÿÿÿÿÿÿÁÿÿÿÿÿ6ÿÙÿÿÿÿÿÿÿÿÿïÿcÿÿÿÿÿÿÿUÿÆÿýÿÿÿÿÿÿÿØÿ6ÿÿÿÿÿBÿÙÿÿÿÿÿÿÿÿÿ÷ÿÄÿ|ÿEÿ(ÿÿÿ(ÿFÿ}ÿÄÿ÷ÿÿÿÿÿÿÿÿÿÙÿAÿÿÿÿÿ5ÿÂÿþÿÿÿÿÿÿÿÿÿÿÿ÷ÿèÿÝÿÝÿçÿ÷ÿÿÿÿÿÿÿÿÿÿÿþÿÂÿ6ÿÿÿÿÿÿ‰ÿêÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÿ‰ÿÿÿÿÿÿ7ÿ—ÿßÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿßÿ—ÿ6ÿÿÿÿÿ)ÿlÿ¬ÿÙÿòÿýÿýÿñÿØÿ¬ÿlÿ)ÿÿÿ€ÿþü?øðàðÀ?ð€à€ÿàÿÀÿ€ÀÿÀþàüàüàøàðàà?àÀ?à€à€ÿÀÿÀÿ€€ÿ€þÀüàððøü?þÿ€ÿ(0` $  ÿÿÿ ÿ6ÿnÿ£ÿÌÿæÿõÿýÿýÿöÿæÿÌÿ£ÿnÿ6ÿ ÿÿÿÿÿ(ÿrÿ¼ÿéÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿéÿ¼ÿrÿ(ÿÿÿÿÿ.ÿ‘ÿâÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿâÿÿ.ÿÿÿÿÿÿ|ÿãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâÿ|ÿÿÿÿÿÿ;ÿ¿ÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ¿ÿ:ÿÿÿÿÿ^ÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÿíÿáÿÙÿÙÿáÿîÿúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâÿ]ÿÿÿÿÿqÿñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿ¾ÿƒÿRÿ2ÿ ÿÿÿ ÿ2ÿRÿƒÿ¾ÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñÿrÿÿÿÿÿqÿôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãÿÿ9ÿ ÿÿÿÿÿ ÿ:ÿÿâÿþÿÿÿÿÿÿÿÿÿÿÿÿÿôÿrÿÿÿÿÿ^ÿðÿÿÿÿÿÿÿÿÿÿÿÿÿôÿœÿ.ÿÿÿÿÿ@ÿåÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñÿ_ÿÿÿÿÿ;ÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÝÿ[ÿÿÿÿÿŠÿûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãÿ<ÿÿÿÿÿ¾ÿÿÿÿÿÿÿÿÿÿÿÿÿËÿ7ÿÿÿÿÿpÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾ÿÿÿÿÿ}ÿþÿÿÿÿÿÿÿÿÿÿÿÌÿ.ÿÿÿÿÿTÿìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿ}ÿÿÿÿ.ÿáÿÿÿÿÿÿÿÿÿÿÿÝÿ9ÿÿÿÿÿ;ÿÞÿÿÿÿÿÿÿÿÿÿÿ÷ÿžÿÚÿÿÿÿÿÿÿÿÿÿÿáÿ.ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôÿ\ÿÿÿÿÿ&ÿÊÿÿÿÿÿÿÿÿÿÿÿþÿ™ÿ ÿ[ÿôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(ÿáÿÿÿÿÿÿÿÿÿÿÿœÿÿÿÿÿ²ÿÿÿÿÿÿÿÿÿÿÿÿÿ´ÿÿÿÿœÿÿÿÿÿÿÿÿÿÿÿáÿ(ÿÿÿsÿÿÿÿÿÿÿÿÿÿÿâÿ/ÿÿÿÿ ÿ—ÿþÿÿÿÿÿÿÿÿÿÿÿÌÿ'ÿÿÿÿ/ÿâÿÿÿÿÿÿÿÿÿÿÿrÿÿÿ¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿzÿùÿÿÿÿÿÿÿÿÿÿÿßÿ=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»ÿ ÿ7ÿéÿÿÿÿÿÿÿÿÿîÿ:ÿÿÿÿ]ÿðÿÿÿÿÿÿÿÿÿÿÿíÿVÿÿÿÿ:ÿîÿÿÿÿÿÿÿÿÿèÿ6ÿnÿüÿÿÿÿÿÿÿÿÿ½ÿ ÿÿÿÿCÿäÿÿÿÿÿÿÿÿÿÿÿ÷ÿrÿÿÿÿ ÿ¾ÿÿÿÿÿÿÿÿÿüÿmÿ¢ÿÿÿÿÿÿÿÿÿÿÿ‚ÿÿÿÿÿ-ÿÑÿÿÿÿÿÿÿÿÿÿÿýÿÿÿÿÿÿƒÿÿÿÿÿÿÿÿÿÿÿ£ÿËÿÿÿÿÿÿÿÿÿúÿQÿÿÿÿ»ÿÿÿÿÿÿÿÿÿÿÿÿÿªÿÿÿÿRÿûÿÿÿÿÿÿÿÿÿÊÿæÿÿÿÿÿÿÿÿÿíÿ1ÿÿÿÿ¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÄÿ!ÿÿÿ2ÿîÿÿÿÿÿÿÿÿÿåÿõÿÿÿÿÿÿÿÿÿáÿ ÿÿÿÿ„ÿûÿÿÿÿÿÿÿÿÿÿÿØÿ4ÿÿÿÿ ÿáÿÿÿÿÿÿÿÿÿõÿýÿÿÿÿÿÿÿÿÿÙÿÿÿÿÿgÿôÿÿÿÿÿÿÿÿÿÿÿéÿLÿÿÿÿÿÙÿÿÿÿÿÿÿÿÿýÿýÿÿÿÿÿÿÿÿÿÙÿÿÿÿÿLÿéÿÿÿÿÿÿÿÿÿÿÿôÿgÿÿÿÿÿÙÿÿÿÿÿÿÿÿÿýÿõÿÿÿÿÿÿÿÿÿáÿ ÿÿÿÿ4ÿØÿÿÿÿÿÿÿÿÿÿÿûÿ„ÿÿÿÿ ÿáÿÿÿÿÿÿÿÿÿõÿæÿÿÿÿÿÿÿÿÿîÿ2ÿÿÿ!ÿÄÿÿÿÿÿÿÿÿÿÿÿÿÿ¡ÿÿÿÿ1ÿíÿÿÿÿÿÿÿÿÿæÿËÿÿÿÿÿÿÿÿÿûÿRÿÿÿÿªÿÿÿÿÿÿÿÿÿÿÿÿÿ»ÿÿÿÿQÿúÿÿÿÿÿÿÿÿÿËÿ¢ÿÿÿÿÿÿÿÿÿÿÿƒÿÿÿÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÑÿ-ÿÿÿÿÿ‚ÿÿÿÿÿÿÿÿÿÿÿ£ÿmÿüÿÿÿÿÿÿÿÿÿ¾ÿ ÿÿÿÿrÿ÷ÿÿÿÿÿÿÿÿÿÿÿäÿCÿÿÿÿ ÿ½ÿÿÿÿÿÿÿÿÿüÿnÿ6ÿèÿÿÿÿÿÿÿÿÿîÿ;ÿÿÿÿVÿíÿÿÿÿÿÿÿÿÿÿÿðÿ]ÿÿÿÿ:ÿîÿÿÿÿÿÿÿÿÿéÿ7ÿ ÿ»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=ÿßÿÿÿÿÿÿÿÿÿÿÿùÿzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼ÿÿÿrÿÿÿÿÿÿÿÿÿÿÿâÿ/ÿÿÿÿ'ÿÌÿÿÿÿÿÿÿÿÿÿÿþÿ—ÿ ÿÿÿÿ/ÿâÿÿÿÿÿÿÿÿÿÿÿsÿÿÿ'ÿàÿÿÿÿÿÿÿÿÿÿÿœÿÿÿÿ´ÿÿÿÿÿÿÿÿÿÿÿÿÿ²ÿÿÿÿÿœÿÿÿÿÿÿÿÿÿÿÿáÿ(ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôÿ[ÿ ÿ™ÿþÿÿÿÿÿÿÿÿÿÿÿÊÿ&ÿÿÿÿÿ\ÿôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ.ÿáÿÿÿÿÿÿÿÿÿÿÿÚÿžÿ÷ÿÿÿÿÿÿÿÿÿÿÿÞÿ;ÿÿÿÿÿ8ÿÝÿÿÿÿÿÿÿÿÿÿÿáÿ.ÿÿÿÿ}ÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìÿTÿÿÿÿÿ.ÿËÿÿÿÿÿÿÿÿÿÿÿþÿ|ÿÿÿÿÿ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿpÿÿÿÿÿ7ÿËÿÿÿÿÿÿÿÿÿÿÿÿÿ¾ÿÿÿÿÿ<ÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûÿŠÿÿÿÿÿ[ÿÝÿÿÿÿÿÿÿÿÿÿÿÿÿâÿ;ÿÿÿÿÿ_ÿñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåÿ@ÿÿÿÿÿ.ÿÿôÿÿÿÿÿÿÿÿÿÿÿÿÿðÿ^ÿÿÿÿÿrÿôÿÿÿÿÿÿÿÿÿÿÿÿÿþÿâÿÿ:ÿ ÿÿÿÿÿ ÿ9ÿÿãÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôÿqÿÿÿÿÿqÿñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÿ¾ÿ‚ÿQÿ2ÿ ÿÿÿ ÿ1ÿRÿƒÿ¾ÿïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñÿqÿÿÿÿÿ]ÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÿîÿáÿÙÿÙÿáÿíÿúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâÿ^ÿÿÿÿÿ:ÿ¿ÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÿ¿ÿ;ÿÿÿÿÿÿ|ÿâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿâÿ|ÿÿÿÿÿÿ-ÿÿâÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿâÿÿ-ÿÿÿÿÿ'ÿrÿ¼ÿéÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿéÿ¼ÿrÿ(ÿÿÿÿÿ ÿ6ÿnÿ£ÿËÿæÿõÿýÿýÿõÿåÿËÿ¢ÿmÿ6ÿ ÿÿÿÿÿÿÿøÿÿàÿÿÀÿÿÿþü?øøøþðÿþàÿüàÿüÀÿø€?ÿð€?ÿà€ÿÀÿ€ÿÿ€?ÿÿ?ÿþ€ÿüÿ€ÿøÿ€ÿðÿ€ÿàÿ€ÿàÿ€ÿÀÿ€ÿ€ÿ€ÿ?ÿ€þÿ€üÿÿüÿÿxÿþ€pÿþ€ ÿü€ÿüÀÿøà?ÿðà?ÿàðÿ€øþøøü?þÿÿÿÀÿÿàÿÿøÿÿÿÿÿ‰PNG  IHDR\r¨f!.IDATxÚíwœTåÕÇ¿3à"XvUÀ Hì#Ö¼$`ì’X‰X£iÄØ£Æó&v_£F…˜˜Ø5¢± cÔˆ%‘Ĉ‰ ¢‚DŠ,²À>ïgƆ™»SîÜsî½Ï÷ó9Ÿ]v‡½¿[žsŸržs2OÌYØ蛳~@/ X'÷µ%÷¹5€¦Üÿë¬^ðwËeÀg@+ð)ðIÎæä¾ÎË}?#gKµ/€§v2ÞĂխ-r¶eîëæHãÖ¢øx·À¦“€©ˆ3ñÆ;{¬ììì”ûº-ÐU[X•´ÿ&ÿ^^–h ótà€>ë{{{"?n½R–"ÎàïÀ ÀóÈ0ã„wÑÓ„4ôýý€@F[”+€×€g'‘žƒ'"¼ˆ†>À7F?™ó¬ÊgÀ3ÀcÀX`®¶ ¤ã@ã艼ñ³Ú‚bÆ à%à!` ð¡¶ $â@¸4Ãcð>LÚñÀ}ˆ3X -()xP?`ðmà0d}ÝÓ8– ½‚Û‘¹ƒvmAqÆ;€Úé|8 ØT[LJyø pœä©ïªç+ÀiÀVޤóè±\¼ª-&NxP`p0X[Œ'ç«'ÿxw‚wÁd‘Yü ‘õzO|˜\ <‚Ÿ'(‹w¥é | ¸‰Á÷Ä—IÀeÈÁ;‚"¼X™ pòÀl®-Æ*S€ÿþ€|w ®¾ª-ÄÓPþœ<§-ÄÞÀ6ÀUÀÁÚB<‘ò0p.0][ˆ&iŽT[ø%²EÕ7þôq(ðp#ÐS[ŒiíŒþ‰×÷x>Îî"eóis[£ðkùžÒ<ŒD²¥‚´ V~Šì=¬-Æc–¡ÈðBä™IFg.@²âéÒf’â=r=‰q÷VÙÀ!Ä(1iœÀב™þµ´…c R…w22+= ið徯õ6g'°°>`µ° %Ê×Õ¾Æø šþI[H%ÄÅ îD k¦™™ÀËȦ¦·röº¹îú#ñ¼í l¨¨ÇmH¡˜{µ…tFÀ_‘àxì&!ÕožGJjÏÖT!ƒ ,ùÛÓ›´…aÝœ\©-"BAJe?Žtá“@?d‚ìdËmš ªœƒ$Ÿ1‰eðS$‹kÒùx a~™¬K2=ùœCs¶¶¶ °ëœM»ÔK°-w0ÎÁ‘º¸ÞZÖÝÁp9h3p_i?6p½W1u%ì7«Q6ÝÁÅú¸ÎÖ¬§ƒÓüÛÀ}JPPdç¸IaÛ :êrC.o–qð5ç®öýK´PP`# Üœ0m‰ƒQ67pmãj›æ®áçîg˜6ÒÀµ5åŽqÐnàÆ„aŸ9¸ÖA×5)Ö×Á Z Üß0l¹ƒ£ \W}p°ÔÀM©×Z\ç ·kšT[ßÁ5.Ž`©ƒ!Ú×Tû†nï`±›Qµ;¸Ãù‰½(mC¿sñŸ#˜ï`€æµÔŒè‡D·ÅycÏËÀ™¹¯žèˆ”w¬-¤fÿ“û9Z É´:@çð¡0 ø ¾æ¼†7 –âÈ›HUêÖ¨¬‘¨ ²±'Î$ÙeÚ"<Ü”}»•ÜÐ6f @Š×D¿õZaÜq…±W˜v‚1±·ÛËÅ7˜è‚¨¯WÔC€#o¤$mÀ¾Àxm!ž/X¸øñzÖV ¦"Ë%¥Øɤš˜œêÌE ‘L×âY‰ý‘®uœæ»QÊñ¨æÖB²ù$±ñôÆ"“›;<‰¤‘{\[H4#m¥{‹ÊŒFzIfk$;l—Xf0 É-±B[L… @–7O '˜\‰ÒF˜óVÚöu0ÏÀ3R©ÑèkÒè9€­€W<þiâ4àFmž’l‚ôÔ¾¢-¤æ#yV•¸‘C€Õõþ´5~€ëH@Ù¨„ò.°â¬Ó‚$íÚ¨4Ò\„Ìf¦‘.È‹{°SRYŒ,I_¯-¤vÎmÔoÔ`Wà%è¹bÂ{ÀnÈ2¡Ç&g!ùú,Ç ,vBÒÀ‡J#@7à_À¶¾*1a’»M[ˆ§,Ç¿Ãö ëŸHo`y˜´C€ ð¿ÝB¦–ß0içNàhBn\!³  „Ý€¼ýW‹ä’Ä‹‹ð›‡¬spv{K‘2p¡¦È/"ÝϪ8à[Àm!ž@¬;ç‘ü¡4Ý0‡'ãà6dHà±ËƒÀìF Bê†BX=€õ€)¹¯ž`f#N@%Œ§bN@¶Å¹›¹Heæùõþ¡°z?Å7þJÙx)‘å±ËÈ„¶EzRÙ¼0z[ é±üÄ_uŒÃnWÓ#ŒFj‹(Ár$L¸®Ø€0zWa³ñ?ŽäZ³Ê0àrmžN9qÖÖèJ•³ëÜM´·S¥ì k;ØØÁz‚ìd»ä¼ÛšÞ4𬔲Áõœ[=C€ ’ág纽P¸ÌEÒ,¿“û÷nÈÒI“¶°2´Ïj ñ²ò¼¯£-¤ˆ …kjÊõ F`¯ñ¯@ÖÚß)øÙà$BZ7mMHžÄÍ´…x™ŽD Z›³Ù‰]¨»YS tªÉªz©}A6ÍA³î®·`³XÁzšƒ®µœO­áh']lOºàòÛ÷ÐdÏ8h2ð{ ~ùýÅÀ³RlÇÕr>µÌdבÂV˜”‰šÓÉçz cmËÑx¿Ææ²“§ƒ/¯a+ÛðÛÈ&¼ª*UÕ2ðMl5~Gç¤ôÒaØŽÂûRoÐc—-Ä5¼?ÆVH’“ꨲËqðªîN¡]WC×g€³]•x¹ƒaº»Þ‚í&ÏJ¡½á‚‡Á«Xµ'|°“,´©º×xó†åšö9”³ùN¹t´·NmMïxV íÕœCµC€³«ü|#iGvE-©ñÿÅn¬7Hˆ'¸oM>ÃÞóU}º o±­ïVh7…äÅo5p.Aö²ƒÞvÞÊÛÍž“BX©öjNò×N,o³œ„ú†qóšœ,¿iŸSÝíªÛy‹ÔšÌ6ðœäí¶°@‹ƒEN,o#B¾=ShŸW]bàA÷VÞFxFòÖš{¦;Õ]éÀ‰Ø)ì9ɹ&Ÿ ñø ´O.€KðkMî^Б£;ðýJ>XI PÉöc!VÝ!±Ï¯4èïAj³[Ý8ÔšÓ8A[ˆ§$;"黣*ºÄûH´ÀÀ J„ÁFãyó7ªñƒD ž®}’ôúi ñ”äU¤'`/ûvö¡J@h ëäsàÂŽók¤¶ŸUz!˃kk ñ”ä"$}·Nêì9€fàPí³È1ŠVI-âlfÉ3¸ ©Aè±Å àfm9†ë} 3p$2¡ Íàš·Ù_`=¥ØÕÚ"<%¹ ™¯Ñ¦pTÐ:sGkŸAŽ[ Q²)ñm¹°çYT8Û뉔9È3kc‚~´ ÐÙ5§=£¹ØøPéø»!“ƒVÓxû”b6éƒd¦ÒîA;`#`f©_5î£Ðoüw£×øA–ܾG.pÊ MÀCØY©ñ"EaµÉ°M8¨¦­it×k‹î~®-"€f$~Ág±ÅõT™ £A”ÏX&D°·³±UöI!žyË8‰É×¾&AæSŠÙ³G <íú–ÒW®p6–˜®ÓP€C†–£ð†`g Ê#Ü - +õ‹rà`mÅÀTà)mE´"ÎÑrJ±ï q <LÖTꇥ@7`mµÈŠÓQ‚¹ÈòàBm!\Aï‰ܪ-鮲"QÊìþοeÀíÊ‚x ²V$"O$&}€¶ +Ymʺƒ‹XÊì§,`𱶈N œ«-"€Èž>ÚB<ÌÅFhù*›ƒJ9€¡Ú*~‰l²J?àaì1¥‰;´Pbh_ ¸’C3hRp¡ÖdŸQÓ„¬ÁÑÀýHX·Å9•´Ð„ôj[58d7é¼üŠú ô£ÿÆŸÆ2¶; )i•áØdJmÀ#Ê2Àž…?(nì{) £-  ñøóêýC äB:Ùâi8h  ¨;€Ý•Å-þ¢¬¡V¦#û'´g{Ë‘A–V-×EL:O£ŸwrPá? ÀêÀNÊâž%^ÝÿRúOÑ@’Rl#m!)¥ ýÜ@ –ù Àè'ç|ü0¸Û‰:z!ó,ÍÚBRÊŸ•ßiëÀÊ`ea Rr̺o9 ;-ì÷HO ¿³cþ›l©*1•2I bÈ dÙÍrJ±ƒ8O´ÌFÿ¹0éÆ+?lZ‘=šÉL:ã4`¤¶ˆò¼òñwÈ“w«[+‹JšÙ5x(6D–ãFl1%í BÛ"“þ_8€-' ‰¶WlÚ Úã¾rtARŠm¥-$Eh;€®äîwÞl§,hðe d p±¶ˆš‘åÁ^ÚBR‡èGŽ®ä¶TÓÈr_V¸™y·Êfˆ£Ò^ N •¿¬<ÐäUåãGCJ5YN)6;ù쓎ö3¿’Ø\YŒöňŠ6$¥Ø m!œüD[D Ð~æ·€ŽíÀŸ ›Rºðò‰’ÈDÕh<|ÛÁLq§7ºIo-kŸ) YD:+݈40«Ñx­ÈÖQí±j’ù/’ƒC‹µ³HqM¦(_‹'€3µEÐqPý´…$˜·•ß7‹þ N« ­-"€~Àñ)ÅÅ4åã÷Ë"cM´×Cµ9Û…=wîDò xÂEûå×/ ôT‘” @µ²I)¦Ý âp$ŽÁ.ÚfúfÑ/(©},°Yœ«-$€ŸàSŠ…öÊWï,’Wï„éHg«)Å@RŠí¡-"Ah‡¿·Xèh{AKŒG Z¥ ©3°™¶„ ýì·hÏ,G?I¢5î®Ô@/d÷ Õ ¦8±Xªxü–,ºŸ*Û2qH)v?vƒ˜â„fhÉ"Õ€Óxò–qHJ1ËQxû!q žú˜¯xì–,¹Ì )¥Ø–ÊÇÿÈ‚ðãÁÆÐŠTôѾ¿AŒÄv4c£Ñv33N–"4ƒ>ÖU¾If ²…Øj4Þ $Nà m! ,@/G;Ð= ,D?P»:Q’™ˆd¶œRì^$Õxšè‹n2ž€¶ün@í2Å;(?éŒÅ~J±GIWJ±í•ÿtìEÖ.SþÛäê&}UY”wÑ3ø•¶ˆ6@„¬1ÕŠö³þEÕél©*±-~@ƒ³€qÚ"€¤KÊÆ¡þ臛tà@e id2óîSŠEÃAÚ(Ø$Vì´'÷W>~ZY€42íÜAœ œ¬-"öS>~ez‹ÑŸ؇ôD‚Yc²Æÿ°”X‚L°hs2éH Æçk‹ Ù3`±×˜ÁFÓ3”ˆñÈ–ù°…ØðmКðtp p«¶ˆú!)ŬmÚýØ€ÇKý°œ‹,hó#mž•8½Ãrì† µÔsq$Ùï˜ÀO¸ÎmŒgÀ>w°Qz½Eok;xÃÀ3d×Ft-ú;Xbà|ƒû:Ó[É åïkô>aÓ ¸T[„§$ ‘=sêýC ä,d(Ùh.C¶þZàöÎ>´ '‹Ôû²öÙ 3š» ŸºÌSšÝÉAkÑxyÚ%ÌF3íüý•3ê¿›ÑI@_%=€và·ÚgS ÷zl\`ϪL¾‹í”bјಠp-vžÍßPI4o…ãšžZ Œiòv‚q¯·òv‰g$Ȧ9X/äs>ÖÀyåm©ƒÞ•è®æo3pby›ã ÅÀƒî­´eÜmà9 ²g4…t¾->2pNy»£RíÕ„)Z*!Õ‹äŠH" XØORŽ!ÀÍ!ý­+¤V¸¾âOVééþjÀ»å­ÝÁžÞvÞÊ[/3 <+AvN縇ƒÎ#o­Fµ*÷,'ƒ,QZ·ô”f.R k¶® ö”bk Km6üä¹¶ªOWéí2Î^ÀÇ ÞtÞ‚m˜ƒåž•r¶ØÁ€ÎëFÚ íµ\­øj¹™Ã œhñP`_¹·`;ÓÀ³dÿqЧŠóš{ö´uÚáÕÞ—JŠÉ"µ¶ªþ¿6Œ€´…xŒÔÀdr°µ“Ïõ^ÃV9û·€í©2“W-c—v앎ZÙðai,æY•3°ŸRì÷ódgÍRãY«>_ݹ®N‚)´»<Åv®®·`kv0ÕÀ³d¿Ð¾}Å6ÅA—ZîG=7òH'^lËìgà!÷l›9˜kày)gíŽ)¡ûkÎædæ±µÞ‹Zæòd€—]kÿ a>²aÈrâJý”bmÀ :‚™6þ޽ÚÿBž÷ššr=cf‡$>°F ’ÑBBOyžÅNÖœR4!)Å6B2 =Œ½Æp656~ ”îÜcº@¥ìQWã¸È[¤v¥g%ÈÞ0üŒ?Rïõ¯gg[dI¤ký*tFcû-ã‘T]a¿À§5–!éΦÔóGÂX6{ YßµÈHü¦!묎ÞÐ3n¡ÎÆáô@ÆÝS±9FéŒÖá ¤2áfm}Ý"ÿEê ~Rï +pf>ðÅ Ò7Gj‹ð2 8ŒÎ£ð -ÄÈQÀ°“ZË/{RñÞ0Cg2ænS¸(•Ð)’à{¶\¤-Â(Ë€båî°cç'coŸ@!Þ Äƒ+€{´Eäjàõ0ÿ`˜C€<«!ÑI"¹$µ±8 ÙÔá±I0øª¶#Lv$äJ]Ø=· 8!÷Õ*];ð¥Ç-ӆļ§-ÄùVèeúµ}v"ð‹F^‘È×åÌo#¶É\àØN)?§A V1ÈÓéÂíÞ¸C„ÆÃÀqÀbm!ž’€ÄåGYàÓ /ƒ‘U¬Ði¤ÙH1 ²ÎÀ¡H4=~„Äs¤‰ùÀ@`F£Ðè®ï $?|ة붟¶OIn"}Ñœ§ÐÀÆD¶ãk´SÕ$9ÏU™]Õ[$ÖÅÁÓž‘(ì®(®i£‡yº#“–—‹y8Û%¯ÓH3’˜ckm! äm$?áÂF(*°9ÒÅnŽîuó1ðm$sÇ›Ãîæ³zXŒdÙšÅÁ¢\þš†Äâ7d6³A¬ŒCê"®®-ÆóÓ#°v^ß%¢Æ¨Œã,fU­Ä&;ØÝÀ8Ø[‡oà¹Ó®ŽúvùY4~¦—€mLBq¢2X7wI|ûÄבžÙžÚBB`ð¤]FF”s…ô@&r¶×9|ÝÌÎDv®ytÉ")éâ4Á\Ì›À^(DÍýl~î÷Y$KSñ×nHƒïª}1bp0!—ïj$qs Až ~ù<Éæ5d¢3V·q¬ˆ3ø¤˜‡Çc‘ ÏX5~ˆ§g\Lˆ¥’=ž*i.Ž>ÓS qs RJºE[ˆ'UÌŽERyÅ–$8”ã ³ÒO£™„ô@§j ©—¸Š™†R¸[[ˆ'ñÜ‚äí}ã‡äô 9©!׬-Ä“(æ#9ûÔ&It_FzIHíÑçeäÅ2C[HØ$ePÌûHÂ΋åÚb<±e²‹o/Øø!¹=€BvnEâÕ=žJy‰çŸ¨-¤‘$µPÈ$„ø"`‰¶yÚ·þÎ$¼ñC:z…lŽLÕâ1Éxàà-m!Q‘†@!Ó€¯'"›c<€‘ ž¯‘¢Æés ;áî¶Fá' ÓÌràz$—Á=äòd¦‰´ J±p#²jàIOg“µ…h’Æ@1“®ßÈ–NO²y¹×òÆÞò$²Zp0][Œ'tÞAÆù‘{íÁÊÑyX.6Ñã©‹)ÀÈßÏ÷á@0]‘ÐóðˆâÆ$à2$¤ÏQï*# Cêøý¶ÌìÅ7üNñ zvN†MÚb<,îEVs½&ÞÔNoà$à{ÀÆÚbRÊ dŸÇo9Úbâˆwõ“öŽÃçÉo4K:Š·Ïâ»ùuá@¸4#Cƒ£AøeÖ°hþÜ‡Ìæ/Д¼h}#‘^ÁxgP-ùFÿðGàmAIÄ;€hèMG9ì¡øòfåXŒ”H©å}ƒñ zš€½ýäHoïÀÿþŒ4úç‘鞈ð@Ÿu‘ù‚AÀîÀŽ$· òrd™îE¤±¿ÌÕ•f¼°Gw¤W°sÎ"[—ãæ–#o÷W‘Fÿ*²Ùj‘¶0OÞăÕ'°-°%°EÎ6ÖSÖ¶I´2‰»Ÿ’û~2¾;oïâÏšHôþ@Ïë]ðý:HÏb-dC¤üwžetÔ¶[4êÅH.üB›‹gý)„ù~I.Öü?ÓôdMßpZIEND®B`‚olive-continuous/app/packaging/windows/olive.ico000066400000000000000000004066151370472574300224400ustar00rootroot0000000000000000 ¨%f€€ (&@@ (B6.  ¨^p h ˆn…(0` °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°8°°°ª°°°á°°°÷°°°þ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°þ°°°÷°°°á°°°ª°°°8°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°°°ï´´´ÿ»»»ÿÀÀÀÿÁÁÁÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÁÁÁÿÀÀÀÿ»»»ÿ´´´ÿ°°°ï°°°}°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°O°°°ð···ÿÀÀÀÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÀÀÀÿ···ÿ°°°ð°°°O°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¨´µ´ÿ¾¾¾ÿÃÃÃÿÃÃÃÿÃÃÃÿ‹›‹ÿ8`8ÿ!P!ÿFÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ?ÿ>ÿEÿ!O!ÿ7^7ÿŠšŠÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ´µ´ÿ°°°©°°°°°°°°°°°°°°°°°°°°°°°°°°°Î¸¸¸ÿÃÃÃÿÃÃÃÿÃÃÃÿPrPÿGÿFÿIÿKÿNÿMÿNÿNÿNÿNÿNÿNÿNÿNÿNÿNÿNÿNÿNÿNÿMÿLÿIÿGÿCÿDÿNoNÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ°°°Î°°°°°°°°°°°°°°°°°°°°°°°°°°°Ó¸¸¸ÿÄÄÄÿÄÄÄÿ‘¡‘ÿ%X%ÿ K ÿ Q ÿ T ÿ W ÿ X ÿ X ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ X ÿ W ÿ V ÿ T ÿ P ÿ M ÿFÿ#S#ÿŸÿÄÄÄÿÄÄÄÿ¸¸¸ÿ°°°Ó°°°°°°°°°°°°°°°°°°°°°¨¹¹¹ÿÅÅÅÿÅÅÅÿkˆkÿ I ÿ R ÿ Y ÿ [ ÿ ] ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ \ ÿ [ ÿ Z ÿ W ÿ T ÿ M ÿCÿi…iÿÅÅÅÿÅÅÅÿ¹¹¹ÿ°°°¨°°°°°°°°°°°°°°°°°°Oµ¶µÿÆÆÆÿÆÆÆÿg‡gÿ O ÿ Z ÿ ` ÿ b ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ c ÿ c ÿ b ÿ a ÿ _ ÿ \ ÿ Y ÿ S ÿ I ÿdƒdÿÆÆÆÿÆÆÆÿµ¶µÿ°°°O°°°°°°°°°°°°°°°ðÁÁÁÿÇÇÇÿ“¥“ÿ Q ÿ ^ ÿ e ÿ h ÿ h ÿ h ÿ h ÿ h ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ g ÿ b ÿ b ÿ f ÿ g ÿ c ÿ ] ÿ Y ÿ Z ÿ [ ÿ U ÿJÿ‘£‘ÿÇÇÇÿÁÁÁÿ°°°ð°°°°°°°°°°°°}¹¹¹ÿÇÇÇÿÇÇÇÿ'e'ÿ ` ÿ i ÿ m ÿ n ÿ n ÿ n ÿ n ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ h ÿ Y ÿ X ÿ e ÿ f ÿ\ÿ]ÿ L ÿ W ÿ a ÿ ` ÿ W ÿ$]$ÿÇÇÇÿÇÇÇÿ¹¹¹ÿ°°°}°°°°°°°°°íÆÆÆÿÈÈÈÿTTÿ ^ ÿ k ÿ p ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ r ÿ°ÿ¢ÿIÿ \ ÿ#f#ÿ†¢†ÿ«¾«ÿ‹ª‹ÿ _ ÿ h ÿ g ÿ a ÿ U ÿQzQÿÈÈÈÿÆÆÆÿ°°°í°°°°°°8µµµÿÉÉÉÿÉÉÉÿ`ÿ l ÿvÿxÿyÿxÿxÿxÿxÿxÿxÿxÿxÿxÿxÿxÿxÿxÿuÿ s ÿvÿxÿxÿxÿxÿtÿ½Õ½ÿèíèÿDÿssÿõøõÿÿÿÿÿÇÔÇÿ[ÿ f ÿ o ÿ o ÿ k ÿ a ÿWÿÉÉÉÿÉÉÉÿµµµÿ°°°8°°°¦ÀÀÀÿÊÊÊÿ’©’ÿ g ÿvÿ~ÿ~ÿ}ÿ}ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿzÿ m ÿ f ÿ r ÿ|ÿ|ÿ|ÿ w ÿ i ÿæîæÿþþþÿVÿïóïÿÿÿÿÿÁÎÁÿJÿ O ÿ c ÿ q ÿ u ÿ r ÿ j ÿ [ ÿ¦ÿÊÊÊÿÀÀÀÿ°°°¦°°°ßÈÈÈÿËËËÿDEÿqÿÿ‚ÿ‚ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿ{ÿš»šÿ V ÿ pÿ€ÿ€ÿ{ÿ0€1ÿŠ­ŠÿúûúÿÛåÛÿT‡TÿêïêÿÐÚÑÿÖßÖÿøúøÿ¦Ä¦ÿ oÿyÿyÿwÿqÿ d ÿ>v?ÿËËËÿÈÈÈÿ°°°ß°°°÷ËËËÿÌÌÌÿ,u,ÿzÿ…ÿ‡ÿ‡ÿ…ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿÿˆ¸ˆÿæíæÿ N ÿqÿ„ÿÿ$$ÿ¶Ì¶ÿñõñÿ²Ç²ÿ}«}ÿ¾Õ¾ÿÿÿÿÿÿÿÿÿûüûÿ}®}ÿyÿ€ÿÿ~ÿ|ÿwÿ k ÿ$i$ÿÌÌÌÿËËËÿ°°°÷°°°þÍÍÍÿÍÍÍÿtÿƒÿÿŽÿÿŒÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿ Š ÿôøôÿòöòÿ M ÿvÿŠÿ€ÿÑáÑÿÿÿÿÿÒÝÒÿ!h!ÿs«sÿËâËÿùüùÿÄÞÄÿC˜Cÿ„ÿ‰ÿ‰ÿ‡ÿ…ÿ‚ÿÿtÿeÿÍÍÍÿÍÍÍÿ°°°þ°°°ÿÎÎÎÿÎÎÎÿuÿ‡ÿ‘ÿ‘ÿÿÿÿÿÿÿÿÿÿÿÿÿÿn±nÿÿÿÿÿûüûÿ L ÿpÿ‚ÿ…º…ÿÿÿÿÿÿÿÿÿ¥ÿ^˜^ÿF•Fÿÿ€ÿ{ÿzÿ|ÿ€ÿ…ÿ‰ÿ‰ÿ†ÿ‚ÿwÿeÿÎÎÎÿÎÎÎÿ°°°ÿ°°°ÿÏÏÏÿÏÏÏÿyÿÿ—ÿ–ÿ•ÿ”ÿ’ÿ’ÿ’ÿ’ÿ’ÿ’ÿ’ÿ’ÿ’ÿ’ÿ’ÿ¸Ù¸ÿÿÿÿÿÿÿÿÿ J ÿ ^ ÿmÿöúöÿÿÿÿÿÅ×Åÿggÿoªoÿ}ÿxÿeÿ V ÿ V ÿ ^ ÿlÿ}ÿ‹ÿŒÿ‹ÿˆÿ}ÿhÿÏÏÏÿÏÏÏÿ°°°ÿ°°°ÿÐÐÐÿÐÐÐÿ}ÿ‘ÿ›ÿ›ÿšÿ™ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿêôêÿÿÿÿÿõøõÿ_Š_ÿÑÞÑÿ a ÿôùôÿ˜Ã˜ÿgžgÿ–¾–ÿrÿyÿ™º™ÿ÷ù÷ÿçíçÿÊÙÊÿ«Ç«ÿa¡aÿƒÿÿ’ÿÿÿ€ÿlÿÐÐÐÿÐÐÐÿ°°°ÿ°°°ÿÑÑÑÿÑÑÑÿÿ!”!ÿ#Ÿ#ÿ!ž!ÿÿœÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿûýûÿÿÿÿÿÑÞÑÿèðèÿòöòÿnÿh¬hÿkªkÿ®Î®ÿsÿM”Mÿäîäÿÿÿÿÿÿÿÿÿÿÿÿÿáîáÿ™Ê™ÿC£Cÿ#™#ÿ–ÿ•ÿ“ÿÿƒÿnÿÑÑÑÿÑÑÑÿ°°°ÿ°°°ÿÒÒÒÿÒÒÒÿƒÿ#˜#ÿ%£%ÿ#¢#ÿ ¡ ÿ ÿžÿžÿžÿžÿžÿžÿÿšÿÿŠÿÿÜîÜÿÿÿÿÿs¤sÿìôìÿ–Æ–ÿ}ÿw±wÿËßËÿ•À•ÿÎäÎÿúýúÿóùóÿÚìÚÿ¤Ò¤ÿH§Hÿ˜ÿÿžÿÿœÿšÿ—ÿ”ÿ‡ÿrÿÒÒÒÿÒÒÒÿ°°°ÿ°°°ÿÓÓÓÿÓÓÓÿ!†!ÿ%œ%ÿ'¦'ÿ%¦%ÿ"¥"ÿ £ ÿ¢ÿ¢ÿ¢ÿ¢ÿ¢ÿ¢ÿžÿŠÿoÿbÿtÿ–È–ÿîõîÿzÿ_¯_ÿ…ÿ…¸…ÿ±Î±ÿeÿ`ÿtÿ“ÿ¢ÿ¢ÿ¢ÿ¢ÿ¢ÿ¢ÿ¢ÿ¡ÿ ÿžÿ›ÿ˜ÿ‹ÿtÿÓÓÓÿÓÓÓÿ°°°ÿ°°°ÿÔÔÔÿÔÔÔÿ$‰$ÿ)Ÿ)ÿ*ª*ÿ)©)ÿ&¨&ÿ#§#ÿ!¦!ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ))ÿ¯Ï¯ÿúüúÿ¹Ë¹ÿgÿ¥Í¥ÿ…¹…ÿƒÿN¢Nÿ È ÿ˜¿˜ÿ“¶“ÿëñëÿËÙËÿdÿŽÿ ¤ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¥ ÿ ¤ ÿ¡ÿŸÿœÿŽÿwÿÔÔÔÿÔÔÔÿ°°°ÿ°°°ÿÕÕÕÿÕÕÕÿ''ÿ*£*ÿ,®,ÿ+­+ÿ(¬(ÿ%«%ÿ#ª#ÿ"ª"ÿ"ª"ÿ"ª"ÿ"ª"ÿ"ª"ÿ¯Ú¯ÿÿÿÿÿÿÿÿÿçîçÿxÿæñæÿ+…+ÿ+†+ÿÃÜÃÿy¬yÿÎßÎÿÿÿÿÿÿÿÿÿ×â×ÿcÿ‹ÿ!¥!ÿ"ª"ÿ"ª"ÿ"ª"ÿ"ª"ÿ"ª"ÿ"ª"ÿ"©"ÿ"¨"ÿ!¥!ÿ!£!ÿ Ÿ ÿ’ÿzÿÕÕÕÿÕÕÕÿ°°°ÿ°°°ÿ×××ÿ×××ÿ*˜*ÿ.®/ÿ0µ1ÿ.°/ÿ+¯,ÿ(®)ÿ&­'ÿ%­&ÿ%­&ÿ%­&ÿ%­&ÿ%­&ÿõûöÿÿÿÿÿÿÿÿÿ|²|ÿQ¨Rÿ¡Ì¡ÿI”IÿÖçÖÿžÄžÿy§yÿÝçÝÿ÷ù÷ÿÞçÞÿÆÖÆÿažbÿ“ ÿ$¨%ÿ%­&ÿ%­&ÿ%­&ÿ%­&ÿ%­&ÿ%­&ÿ%¬&ÿ%«&ÿ$¨%ÿ#¦$ÿ#¢$ÿ” ÿ|ÿ×××ÿ×××ÿ°°°ÿ°°°ÿØØØÿØØØÿ.›.ÿ5µ5ÿ8Á8ÿ5¾5ÿ2·2ÿ.².ÿ,±,ÿ+±+ÿ+±+ÿ+±+ÿ+±+ÿ+±+ÿ©Û©ÿüþüÿŽÀŽÿ$•$ÿ‹Å‹ÿ“Á“ÿÕæÕÿk¦kÿ•¹•ÿ÷ù÷ÿÿÿÿÿÿÿÿÿÿÿÿÿäïäÿT­Tÿ)¨)ÿ+°+ÿ+±+ÿ+±+ÿ+±+ÿ+±+ÿ+±+ÿ+±+ÿ+°+ÿ*¯*ÿ*¬*ÿ)©)ÿ(¦(ÿ%˜%ÿÿØØØÿØØØÿ°°°ÿ°°°ÿÙÙÙÿÙÙÙÿ11ÿ8·8ÿ;Ä<ÿ9Ã:ÿ7Ã8ÿ4À5ÿ0¹1ÿ.´/ÿ.³.ÿ.³.ÿ.³.ÿ.².ÿ`·`ÿœÉœÿ#Š#ÿ--ÿ¾Ù¾ÿ›Á›ÿ'x'ÿÃÙÃÿÿÿÿÿÿÿÿÿÿÿÿÿèóèÿˆÇˆÿ2ª2ÿ-¯-ÿ.².ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.².ÿ-±-ÿ-®-ÿ,«,ÿ+¨+ÿ(™(ÿ!€!ÿÙÙÙÿÙÙÙÿ°°°ÿ°°°ÿÚÚÚÿÚÚÚÿ5 5ÿ=º=ÿ@È@ÿ@È@ÿ<Ç<ÿ:Æ:ÿ8Å8ÿ7Ä7ÿ6À6ÿ4º4ÿ3·3ÿ1¯1ÿËåËÿM˜Mÿ:‰:ÿÉÜÉÿˆ®ˆÿ”¸”ÿîôîÿÿÿÿÿöùöÿ¯Ô¯ÿ`®`ÿ,™,ÿ,Ÿ,ÿ.¦.ÿ0«0ÿ/ª/ÿ0«0ÿ1¯1ÿ2µ2ÿ3·3ÿ3·3ÿ3·3ÿ3·3ÿ3¶3ÿ2µ2ÿ2²2ÿ1¯1ÿ0¬0ÿ++ÿ$ƒ$ÿÚÚÚÿÚÚÚÿ°°°ÿ°°°ÿÛÛÛÿÛÛÛÿ:£:ÿC¾CÿFÌFÿEËEÿCËCÿ@Ê@ÿ>É>ÿ=É=ÿ=É=ÿ=É=ÿ<Å<ÿhÃhÿµØµÿµÿëóëÿÞêÞÿÊÜÊÿÉÛÉÿ™»™ÿV‘Vÿ'x'ÿ%x%ÿ$v$ÿ"q"ÿ#r#ÿ&|&ÿ)…)ÿ)‡)ÿ,,ÿ2¤2ÿ7¶7ÿ9»9ÿ9»9ÿ9»9ÿ9»9ÿ9º9ÿ8¹8ÿ7¶7ÿ7³7ÿ5¯5ÿ1 1ÿ)†)ÿÛÛÛÿÛÛÛÿ°°°ÿ°°°ÿÜÜÜÿÜÜÜÿ?§@ÿHÂIÿMÐNÿKÏLÿIÏJÿFÎGÿDÍEÿCÍDÿCÍDÿCÍDÿAÆBÿ¿å¿ÿ…Á†ÿÕëÖÿáòáÿ×ì×ÿÄàÅÿ³Ò³ÿ Â¡ÿ£¿£ÿ°Æ°ÿÁÑÁÿÙâÙÿëðëÿ¢º¢ÿvžvÿбŠÿš¿šÿj­kÿ7©8ÿ=»>ÿ>¿?ÿ>¿?ÿ>¿?ÿ>¿?ÿ>¾?ÿ=½>ÿ<º=ÿ;·<ÿ:³;ÿ5¤6ÿ-‰-ÿÜÜÜÿÜÜÜÿ°°°ÿ°°°ÿÝÝÝÿÝÝÝÿD©DÿNÄNÿRÒRÿRÒRÿOÑOÿLÑLÿJÐJÿIÐIÿIÐIÿHÎHÿpÎpÿ©Ù©ÿ¦×¦ÿC½CÿSÎSÿ™ã™ÿËîËÿôúôÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊäÊÿQ´QÿBºBÿDÀDÿDÁDÿDÁDÿDÁDÿDÁDÿDÀDÿC¿CÿB¼BÿA¹Aÿ@µ@ÿ:¥:ÿ1Š1ÿÝÝÝÿÝÝÝÿ°°°ÿ°°°ÿÞÞÞÿÞÞÞÿK¬KÿUÇUÿ[Ö[ÿY×YÿWÖWÿTÖTÿRÕRÿQÕQÿPÓPÿMÉMÿš×šÿ›Õ›ÿJÃJÿPÒPÿQÕQÿQÕQÿQÕQÿoÛoÿ¸ë¸ÿè÷èÿýþýÿüþüÿîøîÿÚïÚÿ¼ã¼ÿ˜Õ˜ÿeÆeÿIÀIÿJÄJÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÅKÿJÄJÿIÁIÿH½HÿF¹Fÿ@¨@ÿ77ÿÞÞÞÿÞÞÞÿ°°°ÿ°°°þßßßÿßßßÿV®Vÿ[Ê[ÿ`Ø`ÿ`Ú`ÿ^Ú^ÿ[Ù[ÿXØXÿX×XÿTÐTÿ‚Ђÿ Ø ÿOÅOÿUÔUÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿVÕVÿUÓUÿTÐTÿSÎSÿRÊRÿQÉQÿQÉQÿQÉQÿQÉQÿQÉQÿQÉQÿQÈQÿPÇPÿOÃOÿNÀNÿK»KÿDªDÿA’Aÿßßßÿßßßÿ°°°þ°°°öÞÞÞÿàààÿf²fÿ_È_ÿgÚgÿgÝgÿfÝfÿbÜbÿ`Û`ÿ]×]ÿnÌnÿ²Þ²ÿSÀSÿ\Ö\ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ^Û^ÿ]Ø]ÿ\×\ÿ[Õ[ÿ[Ó[ÿZÒZÿZÐZÿXÍXÿVÈVÿTÄTÿR½RÿI¨IÿS™SÿàààÿÞÞÞÿ°°°ö°°°ßÛÛÛÿáááÿ|¸|ÿdÄdÿnÛnÿpápÿnánÿkàkÿiàiÿdÐdÿÉçÉÿYµYÿ_Ð_ÿfÞfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfÞfÿdÜdÿcÙcÿbÕbÿ]Ë]ÿR²Rÿp¬pÿáááÿÛÛÛÿ°°°ß°°°¤ÐÐÐÿâââÿ¹Ñ¹ÿe¾eÿqØqÿvãvÿuäuÿsãsÿpãpÿ¯ã¯ÿÃÿT¯TÿfÖfÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlâlÿlálÿkàkÿjÞjÿiÛiÿgÖgÿ`È`ÿS­Sÿ´Í´ÿâââÿÐÐÐÿ°°°¤°°°8»»»ÿãããÿãããÿk¶kÿuÓuÿ}ã}ÿ~ç~ÿ|ç|ÿyçyÿñúñÿ‰Æ‰ÿ^¹^ÿoÚoÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtætÿtåtÿsäsÿrárÿpÞpÿmÖmÿcÄcÿY§Yÿãããÿãããÿ»»»ÿ°°°8°°°°°°íßßßÿäääÿ•ÕÿrÇrÿßÿ„è„ÿƒëƒÿêÿåùåÿ½í½ÿsÙsÿyäyÿ{é{ÿ{é{ÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzèzÿyæyÿxäxÿuÞuÿnÒnÿ_·_ÿ‹º‹ÿäääÿßßßÿ°°°í°°°°°°°°°}ÅÅÅÿäääÿäääÿ€¿€ÿÕÿˆçˆÿ‹í‹ÿ‹î‹ÿ‰î‰ÿ‡î‡ÿ…í…ÿ„í„ÿƒíƒÿƒíƒÿƒíƒÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿ‚í‚ÿìÿ€ê€ÿ~æ~ÿyÝyÿnÈnÿr²rÿäääÿäääÿÅÅÅÿ°°°}°°°°°°°°°°°°ðÖÖÖÿåååÿÄ×ÄÿwÁwÿ†Ü†ÿêÿïÿðÿðÿŽðŽÿŒðŒÿ‹ï‹ÿ‹ï‹ÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿ‰ï‰ÿ‰ï‰ÿ‰ï‰ÿˆïˆÿ‡î‡ÿ…ê…ÿãÿwÑwÿf´fÿÀÔÀÿåååÿÖÖÖÿ°°°ð°°°°°°°°°°°°°°°OÀÁÀÿæææÿæææÿ¬Î¬ÿÈÿŒÞÿ“ë”ÿ•ð–ÿ•ò–ÿ•ó–ÿ”ó•ÿ“ó”ÿ’ó“ÿ’ò“ÿ’ò“ÿ’ò“ÿ’ò“ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿ‘ò’ÿò‘ÿòÿñŽÿ‹íŒÿ‡åˆÿ~Öÿn¼nÿ¥È¦ÿæææÿæææÿÀÁÀÿ°°°O°°°°°°°°°°°°°°°°°°§ÇÇÇÿçççÿçççÿ±Ð±ÿÅÿÛÿ—ê—ÿ›ñ›ÿœõœÿöÿœöœÿœöœÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿ™õ™ÿ™õ™ÿ˜õ˜ÿ–ô–ÿ“ð“ÿæÿ‚Õ‚ÿr»rÿ¬Ë¬ÿçççÿçççÿÇÇÇÿ°°°§°°°°°°°°°°°°°°°°°°°°°°°°ÒÇÇÇÿèèèÿèèèÿÊÛÊÿÆÿ‹Ò‹ÿ•â•ÿšëšÿñÿŸõŸÿ ÷ ÿ ÷ ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿ ø ÿŸøŸÿŸøŸÿž÷žÿžöžÿœôœÿ˜ð˜ÿ“é“ÿŒàŒÿ€Ì€ÿ…¿…ÿÇØÇÿèèèÿèèèÿÇÇÇÿ°°°Ò°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÎÇÇÇÿèèèÿèèèÿèèèÿ¥Ì¥ÿˆÅˆÿŒÒŒÿ“Ý“ÿ–â–ÿšèšÿ™è™ÿ›ê›ÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿšêšÿ—è—ÿ–ç–ÿ’á’ÿÛÿ„΄ÿÀÿ Ç ÿèèèÿèèèÿèèèÿÇÇÇÿ°°°Î°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¤ÁÂÁÿÙÙÙÿéééÿéééÿéééÿÊÛÊÿœÈœÿ’Ç’ÿŒÉŒÿ‰É‰ÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿˆÊˆÿ‡É‡ÿ‡É‡ÿ‡È‡ÿ‰Ç‰ÿŽÅŽÿ—Å—ÿÈÚÈÿéééÿéééÿéééÿÙÙÙÿÁÂÁÿ°°°¦°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°M°°°ðÇÇÇÿãããÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿãããÿÇÇÇÿ°°°ð°°°M°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°}°°°í½½½ÿÕÕÕÿãããÿèèèÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿèèèÿãããÿÕÕÕÿ½½½ÿ°°°í°°°}°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°8°°°©°°°á°°°ö°°°þ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°þ°°°ö°°°á°°°©°°°8°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿàÿÿ€ÿþü?ððàÀÀ€€€€ÀÀàððü?þÿ€ÿÿàÿ(€ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ  ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ %.5:=?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?=:6.% ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%1<IWepw|~~|xpeWI<1%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ #4DWhw„Ž˜ ¥§©©ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©§¥ ˜Ž„whWD4# ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° *>Uj~Žš¤ °SSSÐ}}}ä–––ò¤¤¤ù«««ý¯¯¯þ¯¯¯ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ¯¯¯ÿ¯¯¯þ«««ý¤¤¤ù–––ò~~~åSSSÐ °¤šŽ~jU>* °°°°°°°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°° +C]v‹›©OOO͈ˆˆë¦¦¦ú°±°ÿ¶¶¶ÿºººÿ½½½ÿ¾¾¾ÿ¿¿¿ÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿÀÀÀÿ¿¿¿ÿ¾¾¾ÿ½½½ÿºººÿ¶¶¶ÿ°±°ÿ¦¦¦úˆˆˆëPPPÍ©›‹v]C+ °°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°(A^y‘¢===Å’’’ï®®®þ¶¶¶ÿ¼¼¼ÿÀÀÀÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÀÀÀÿ¼¼¼ÿ¶¶¶ÿ®®®þ’’’ï===Å¢‘y^A(°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°° 9Wv¥ddd×§§§ú´µ´ÿ¼¼¼ÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿ¼¼¼ÿ´µ´ÿ§§§úddd×¥vW9 °°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°*Ij‰¡iiiØ«««ü···ÿ¿¿¿ÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿ¿¿¿ÿ···ÿ«««üiiiØ¡‰jI*°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°° 5Wz˜KKKȨ¨¨û···ÿÀÀÀÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿ”¡”ÿjƒjÿKmKÿ6^6ÿ#P#ÿGÿDÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ;ÿ;ÿ;ÿ;ÿCÿFÿ"N"ÿ5\5ÿKlKÿh‚hÿ“ “ÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÀÀÀÿ···ÿ¨¨¨ûKKKȘzW5 °°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°° >d‡©“““îµµµÿ½½½ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿu‹uÿ9a9ÿDÿ?ÿ?ÿ@ÿAÿAÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿBÿAÿAÿ?ÿ?ÿ?ÿ=ÿ=ÿBÿ7^7ÿsŠsÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ½½½ÿµµµÿ“““d> °°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°° "Em‘KKKÅ­­­ý¹¹¹ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ’¡’ÿ^|^ÿ>ÿ@ÿBÿDÿDÿEÿFÿGÿGÿGÿHÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿGÿFÿEÿEÿEÿDÿCÿBÿAÿ?ÿ=ÿ;ÿ\z\ÿ‘ ‘ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ¹¹¹ÿ­­­ýKKKÅ‘mE" ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ %Is—|||á´µ´ÿ½½½ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ‚–‚ÿ,Z,ÿ@ÿBÿEÿFÿHÿHÿIÿJÿKÿKÿLÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ L ÿ K ÿ K ÿ J ÿJÿIÿIÿHÿGÿFÿEÿCÿBÿ?ÿ=ÿ+V+ÿ”ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ½½½ÿ´µ´ÿ|||á—sI% ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ %Jvœ™™™ñ···ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿŸÿ)X)ÿBÿEÿGÿIÿKÿLÿMÿNÿ N ÿ O ÿ O ÿ P ÿ P ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ P ÿ P ÿ P ÿ P ÿ P ÿ P ÿ P ÿ P ÿ P ÿ O ÿ N ÿ N ÿ M ÿ M ÿ L ÿKÿIÿHÿGÿEÿCÿAÿ>ÿ'U'ÿŽŽÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ···ÿ™™™òœvJ% ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ "Iv£¥¥¥ø¸¸¸ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ`~`ÿAÿEÿHÿIÿKÿMÿOÿ P ÿ P ÿ Q ÿ R ÿ R ÿ Q ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ Q ÿ O ÿ O ÿ O ÿ N ÿ M ÿ L ÿKÿIÿGÿEÿCÿ@ÿ=ÿ^{^ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¸¸¸ÿ¥¥¥ø£vI" ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Es¤¨¨¨ú¹¹¹ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ“¢“ÿSÿEÿ I ÿ K ÿ M ÿ O ÿ P ÿ R ÿ S ÿ T ÿ T ÿ T ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ T ÿ S ÿ S ÿ S ÿ S ÿ R ÿ Q ÿ Q ÿ P ÿ O ÿ N ÿLÿKÿIÿFÿDÿ@ÿNÿ‘ ‘ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¹¹¹ÿ¨¨¨ú¤sE ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>mŸ¨¨¨úºººÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿccÿDÿGÿ K ÿ N ÿ Q ÿ R ÿ T ÿ T ÿ U ÿ U ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ U ÿ U ÿ U ÿ U ÿ U ÿ U ÿ T ÿ T ÿ T ÿ S ÿ S ÿ R ÿ Q ÿ P ÿ O ÿMÿKÿHÿFÿBÿ>ÿ`~`ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿºººÿ¨¨¨úŸm>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ5d”¤¤¤÷¹¹¹ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ?i?ÿ G ÿ K ÿ N ÿ Q ÿ T ÿ U ÿ W ÿ X ÿ X ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ Y ÿ X ÿ X ÿ X ÿ X ÿ X ÿ X ÿ X ÿ W ÿ W ÿ W ÿ V ÿ V ÿ V ÿ U ÿ U ÿ U ÿ S ÿ S ÿ Q ÿ O ÿ N ÿ K ÿ H ÿEÿAÿ;d;ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¹¹¹ÿ¤¤¤÷”d5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ *W‡›››ð¹¹¹ÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ7f7ÿ I ÿ N ÿ Q ÿ T ÿ V ÿ X ÿ Y ÿ Z ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ Z ÿ Z ÿ Z ÿ Y ÿ Y ÿ Y ÿ X ÿ X ÿ X ÿ W ÿ V ÿ V ÿ U ÿ S ÿ R ÿ P ÿ N ÿ K ÿGÿCÿ4`4ÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ¹¹¹ÿ›››ð‡W* ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHz~~~ܸ¸¸ÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ4e4ÿ J ÿ O ÿ S ÿ V ÿ X ÿ Y ÿ Z ÿ [ ÿ \ ÿ \ ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ ] ÿ \ ÿ \ ÿ \ ÿ \ ÿ [ ÿ [ ÿ [ ÿ [ ÿ Z ÿ Z ÿ Y ÿ Y ÿ X ÿ X ÿ W ÿ V ÿ T ÿ S ÿ R ÿ O ÿ L ÿHÿDÿ1_1ÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ¸¸¸ÿ€€€ÝzIÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ7jPPP¹µ¶µÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿ6f6ÿ L ÿ P ÿ T ÿ X ÿ Z ÿ \ ÿ ] ÿ ] ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ^ ÿ ] ÿ ] ÿ ] ÿ \ ÿ \ ÿ \ ÿ [ ÿ [ ÿ Z ÿ Y ÿ Y ÿ X ÿ W ÿ V ÿ U ÿ R ÿ P ÿ M ÿIÿEÿ3`3ÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿÄÄÄÿµ¶µÿOOOºj9ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 'U­­­ýÀÀÀÿÅÅÅÿÅÅÅÿÅÅÅÿÅÅÅÿ>m>ÿ M ÿ Q ÿ V ÿ Y ÿ \ ÿ ^ ÿ _ ÿ ` ÿ ` ÿ ` ÿ ` ÿ ` ÿ ` ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ ` ÿ ` ÿ ` ÿ ` ÿ _ ÿ _ ÿ ^ ÿ ^ ÿ ] ÿ ] ÿ \ ÿ [ ÿ [ ÿ Z ÿ Y ÿ X ÿ V ÿ T ÿ Q ÿ O ÿJÿEÿ;g;ÿÅÅÅÿÅÅÅÿÅÅÅÿÅÅÅÿÀÀÀÿ­­­ýW( ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@t’’’躺ºÿÅÅÅÿÅÅÅÿÅÅÅÿÅÅÅÿd†dÿ L ÿ R ÿ W ÿ Z ÿ ] ÿ _ ÿ ` ÿ a ÿ a ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ a ÿ a ÿ ` ÿ ` ÿ ` ÿ _ ÿ _ ÿ ^ ÿ ] ÿ ] ÿ \ ÿ [ ÿ Z ÿ Y ÿ W ÿ U ÿ R ÿ O ÿ J ÿEÿ``ÿÅÅÅÿÅÅÅÿÅÅÅÿÅÅÅÿºººÿ–––êvAÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ +]FFF­´µ´ÿÅÅÅÿÅÅÅÿÅÅÅÿÅÅÅÿ”¥”ÿ L ÿ R ÿ W ÿ [ ÿ _ ÿ a ÿ b ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ c ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ e ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ d ÿ c ÿ c ÿ c ÿ c ÿ b ÿ a ÿ a ÿ a ÿ ` ÿ _ ÿ ^ ÿ ] ÿ ] ÿ \ ÿ [ ÿ Z ÿ X ÿ V ÿ R ÿ O ÿ J ÿEÿ‘£‘ÿÅÅÅÿÅÅÅÿÅÅÅÿÅÅÅÿ¶·¶ÿRRR´]+ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿCy§§§ø¿¿¿ÿÆÆÆÿÆÆÆÿÆÆÆÿÆÆÆÿ!\!ÿ R ÿ Y ÿ ] ÿ a ÿ c ÿ e ÿ f ÿ f ÿ f ÿ f ÿ f ÿ g ÿ g ÿ g ÿ g ÿ g ÿ g ÿ g ÿ g ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ g ÿ g ÿ g ÿ g ÿ g ÿ f ÿ f ÿ f ÿ e ÿ d ÿ d ÿ c ÿ b ÿ a ÿ ` ÿ _ ÿ _ ÿ ^ ÿ \ ÿ Z ÿ X ÿ T ÿ P ÿ J ÿVÿÆÆÆÿÆÆÆÿÆÆÆÿÆÆÆÿÀÀÀÿ¨¨¨ùxBÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ *]qqqȹ¹¹ÿÆÆÆÿÆÆÆÿÆÆÆÿÆÆÆÿf‰fÿ R ÿ W ÿ ] ÿ a ÿ d ÿ e ÿ f ÿ g ÿ g ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ i ÿ h ÿ h ÿ h ÿ g ÿ g ÿ g ÿ f ÿ f ÿ e ÿ d ÿ c ÿ b ÿ a ÿ ` ÿ ` ÿ ^ ÿ \ ÿ [ ÿ X ÿ T ÿ O ÿIÿ^ƒ^ÿÆÆÆÿÆÆÆÿÆÆÆÿÆÆÆÿ¹¹¹ÿqqqÇ[) ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>w¬¬¬ûÄÄÄÿÆÆÆÿÆÆÆÿÆÆÆÿ˜ª˜ÿ P ÿ X ÿ ] ÿ a ÿ e ÿ g ÿ i ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ h ÿ d ÿ e ÿ i ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ j ÿ h ÿ d ÿ ` ÿ b ÿ e ÿ h ÿ g ÿ f ÿ e ÿ d ÿ c ÿ b ÿ a ÿ ` ÿ ^ ÿ \ ÿ X ÿ S ÿ O ÿGÿ‘£‘ÿÆÆÆÿÆÆÆÿÆÆÆÿÄÄÄÿªªªút=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$UnnnºººÿÇÇÇÿÇÇÇÿÇÇÇÿÇÇÇÿ-f-ÿ V ÿ ] ÿ b ÿ f ÿ i ÿ k ÿ l ÿ l ÿ l ÿ l ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ m ÿ c ÿ R ÿ T ÿ e ÿ m ÿ m ÿ m ÿ m ÿ m ÿ j ÿ f ÿ ` ÿ X ÿ P ÿ M ÿ V ÿ d ÿ i ÿ j ÿ i ÿ h ÿ g ÿ f ÿ e ÿ d ÿ c ÿ a ÿ _ ÿ \ ÿ X ÿ S ÿ M ÿ*`*ÿÇÇÇÿÇÇÇÿÇÇÇÿÇÇÇÿ¹¹¹ÿhhh½R"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4j¨¨¨øÄÄÄÿÇÇÇÿÇÇÇÿÇÇÇÿ‡ ‡ÿ T ÿ \ ÿ b ÿ g ÿ j ÿ l ÿ n ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ m ÿ±Ë±ÿppÿAÿ \ ÿ l ÿ o ÿ n ÿ k ÿ d ÿ [ ÿ P ÿ"Y"ÿd†dÿ§¹§ÿ©ÿeÿ g ÿ m ÿ l ÿ l ÿ k ÿ j ÿ h ÿ h ÿ f ÿ e ÿ e ÿ b ÿ ` ÿ ] ÿ X ÿ Q ÿ K ÿŒ¡ŒÿÇÇÇÿÇÇÇÿÇÇÇÿÄÄÄÿ¨¨¨÷i2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDMMM¡¶¶¶ÿÇÇÇÿÇÇÇÿÇÇÇÿÇÇÇÿ0k0ÿ Y ÿ ` ÿ e ÿ j ÿ m ÿ o ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ"x"ÿþþþÿõ÷õÿJÿ Q ÿ i ÿ n ÿ g ÿ Z ÿ[ÿppÿÊÔÊÿÿÿÿÿÿÿÿÿ÷ù÷ÿX†Xÿ c ÿ n ÿ n ÿ n ÿ m ÿ l ÿ k ÿ j ÿ i ÿ h ÿ g ÿ f ÿ e ÿ b ÿ _ ÿ [ ÿ V ÿ O ÿ0e0ÿÇÇÇÿÇÇÇÿÇÇÇÿÇÇÇÿµµµÿDDD›Cÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%W™™™æÀÀÀÿÈÈÈÿÈÈÈÿÈÈÈÿ˜ª˜ÿ V ÿ ^ ÿ d ÿ i ÿ m ÿ o ÿ q ÿ q ÿ q ÿrÿrÿrÿrÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿ q ÿV—VÿÿÿÿÿÿÿÿÿqŠqÿHÿ d ÿ g ÿ0n0ÿ§»§ÿúûúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿšµšÿ a ÿ o ÿ p ÿ p ÿ o ÿ o ÿ n ÿ m ÿ l ÿ k ÿ j ÿ i ÿ h ÿ g ÿ d ÿ b ÿ ^ ÿ Y ÿ S ÿ L ÿ–©–ÿÈÈÈÿÈÈÈÿÈÈÈÿÀÀÀÿ“““áV%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ 1i¯¯¯ýÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿb‹bÿ [ ÿ b ÿ i ÿ m ÿ p ÿsÿtÿtÿtÿtÿtÿtÿtÿtÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ s ÿ{®{ÿÿÿÿÿÿÿÿÿ»Ç»ÿCÿ _ ÿpŸpÿøúøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÄÓÄÿ ` ÿ o ÿ s ÿ s ÿ r ÿ r ÿ q ÿ p ÿ o ÿ n ÿ n ÿ l ÿ k ÿ j ÿ i ÿ h ÿ e ÿ a ÿ ] ÿ W ÿ Q ÿ^„^ÿÈÈÈÿÈÈÈÿÈÈÈÿÈÈÈÿ®®®ýh0 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿx>ÿbÿjÿqÿvÿyÿ{ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ{ÿ{ÿ{ÿ{ÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿzÿxÿ l ÿ e ÿ q ÿâíâÿÿÿÿÿÿÿÿÿøùøÿJÿáëáÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèîèÿ&q&ÿ m ÿ o ÿ l ÿ i ÿ h ÿ j ÿ p ÿwÿyÿyÿxÿwÿvÿ u ÿ t ÿ r ÿ q ÿ p ÿ o ÿ l ÿ i ÿ c ÿ ] ÿ U ÿ9o9ÿÉÉÉÿÉÉÉÿÉÉÉÿÇÇÇÿ¨¨¨öW%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ .l±±±ÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿcÿfÿnÿtÿyÿ}ÿÿÿÿÿÿ~ÿ~ÿ~ÿ}ÿ}ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿzÿ v ÿ v ÿzÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿzÿ n ÿ…«…ÿ S ÿ l ÿöúöÿÿÿÿÿÿÿÿÿÛâÛÿ U ÿúüúÿÿÿÿÿÿÿÿÿÿÿÿÿåëåÿ,n,ÿ _ ÿ \ ÿ T ÿ L ÿGÿFÿ M ÿ b ÿ u ÿ|ÿ{ÿzÿzÿxÿ w ÿ v ÿ u ÿ t ÿ s ÿ r ÿ o ÿ l ÿ f ÿ a ÿ Y ÿWÿÊÊÊÿÊÊÊÿÊÊÊÿÊÊÊÿ±±±ÿj. ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6hhh§ºººÿÊÊÊÿÊÊÊÿÊÊÊÿœ¯œÿaÿjÿqÿwÿ|ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿÿÿ~ÿ~ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ|ÿ q ÿ c ÿ f ÿ v ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ}ÿ|ÿ r ÿ‘µ‘ÿóöóÿHÿ k ÿÿÿÿÿÿÿÿÿÿÿÿÿ›³›ÿ a ÿ÷ú÷ÿÿÿÿÿÿÿÿÿØâØÿ#^#ÿYÿ`‡`ÿ›±›ÿÌ×Ìÿíñíÿÿÿÿÿðóðÿ º ÿ f ÿ x ÿ}ÿ|ÿ|ÿ{ÿzÿyÿ x ÿ v ÿ u ÿ t ÿ s ÿ q ÿ n ÿ i ÿ c ÿ \ ÿ T ÿ™¬™ÿÊÊÊÿÊÊÊÿÊÊÊÿºººÿggg¦5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ:‹‹‹ÎÁÁÁÿËËËÿËËËÿËËËÿr˜rÿeÿnÿuÿzÿ~ÿ‚ÿƒÿƒÿƒÿ‚ÿ‚ÿ‚ÿÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwÿz¨zÿwœwÿ Y ÿtÿÿÿÿÿÿÿÿÿÿ~ÿwÿo¡oÿþþþÿþþþÿ H ÿ m ÿò÷òÿÿÿÿÿþþþÿ8r8ÿ i ÿ»Õ»ÿúüúÿš´šÿiŒiÿÁÎÁÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìñìÿ=…=ÿxÿ~ÿÿÿ~ÿ}ÿ|ÿ{ÿzÿyÿxÿwÿvÿtÿpÿ l ÿ e ÿ _ ÿ V ÿm’mÿËËËÿËËËÿËËËÿÁÁÁÿ‹‹‹Î:ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=æÆÆÆÿËËËÿËËËÿËËËÿTˆTÿhÿpÿxÿ~ÿ‚ÿƒÿ„ÿ„ÿ„ÿ„ÿ„ÿƒÿƒÿ‚ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ}ÿ]›]ÿþþþÿ›±›ÿ T ÿtÿÿÿÿÿÿÿÿÿ€ÿzÿLLÿýþýÿÿÿÿÿðóðÿ K ÿpÿ¿Ü¿ÿÿÿÿÿ¥À¥ÿ.t.ÿ(y(ÿ¯Ë¯ÿn—nÿçìçÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛæÛÿ)|)ÿ{ÿ€ÿÿ€ÿ€ÿ€ÿÿ~ÿ}ÿ|ÿ{ÿzÿyÿxÿvÿsÿoÿ i ÿ b ÿ Y ÿNNÿËËËÿËËËÿËËËÿÆÆÆÿæ=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?§§§óÈÈÈÿËËËÿËËËÿËËËÿ@}@ÿjÿsÿ{ÿ€ÿ„ÿ†ÿ‡ÿ‡ÿ‡ÿ†ÿ†ÿ…ÿ…ÿ„ÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿ‚ÿ'„'ÿîóîÿÿÿÿÿ¬½¬ÿ S ÿuÿƒÿƒÿƒÿƒÿƒÿƒÿƒÿ‚ÿ}ÿ8„8ÿô÷ôÿÿÿÿÿÿÿÿÿæëæÿ Q ÿtÿIŸIÿÚêÚÿZ”Zÿ6~6ÿÃÿ‹µ‹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²Ì²ÿ{ÿÿ‚ÿƒÿƒÿƒÿ‚ÿ‚ÿÿ€ÿÿ~ÿ}ÿ|ÿ{ÿzÿxÿuÿqÿ k ÿ d ÿ [ ÿ8s8ÿËËËÿËËËÿËËËÿÈÈÈÿ§§§ó?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?­­­úËËËÿÌÌÌÿÌÌÌÿÌÌÌÿ/t/ÿmÿuÿ|ÿ‚ÿ†ÿ‡ÿˆÿˆÿˆÿ‡ÿ‡ÿ†ÿ†ÿ…ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ€ÿ£Æ£ÿÿÿÿÿÿÿÿÿ¼É¼ÿ Q ÿtÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ„ÿ€ÿ(~(ÿåíåÿÿÿÿÿÿÿÿÿÿÿÿÿÈÔÈÿ Y ÿxÿ}ÿ~±~ÿf›fÿ‹´‹ÿpÿó÷óÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúüúÿxªxÿzÿ‚ÿ„ÿ„ÿ„ÿ„ÿ„ÿƒÿƒÿ‚ÿ‚ÿÿÿ~ÿ}ÿ|ÿ{ÿyÿwÿsÿmÿ f ÿ ] ÿ&h&ÿÌÌÌÿÌÌÌÿÌÌÌÿËËËÿ­­­ú@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@¯¯¯ýÌÌÌÿÌÌÌÿÌÌÌÿÌÌÌÿ"p"ÿpÿyÿÿ…ÿ‰ÿŠÿ‹ÿ‹ÿ‹ÿ‹ÿŠÿ‰ÿ‰ÿˆÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ†ÿ55ÿüýüÿÿÿÿÿÿÿÿÿÊÕÊÿ R ÿvÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ…ÿÿÔâÔÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿžµžÿ d ÿyÿAAÿ¨È¨ÿk¢kÿoÿI‘IÿÚéÚÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜèÜÿC’Cÿ€ÿ†ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ†ÿ†ÿ…ÿ„ÿƒÿ‚ÿÿ€ÿÿ}ÿ{ÿvÿpÿ i ÿ ` ÿbÿÌÌÌÿÌÌÌÿÌÌÌÿÌÌÌÿ¯¯¯ý@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°þÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿmÿsÿ|ÿƒÿˆÿŒÿŽÿŽÿÿÿÿŒÿ‹ÿ‹ÿŠÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ†ÿœÅœÿÿÿÿÿÿÿÿÿÿÿÿÿÓÜÓÿ Q ÿwÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿˆÿ€ÿÀ×ÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿcŽcÿ k ÿ0ƒ0ÿÐáÐÿu«uÿ{·{ÿ¦Ï¦ÿŠÀŠÿEœEÿ†¿†ÿéóéÿûýûÿÓæÓÿx´xÿ„ÿ†ÿˆÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿ‰ÿˆÿˆÿ‡ÿ†ÿ…ÿ„ÿƒÿÿ€ÿÿ|ÿxÿsÿkÿ c ÿ_ÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿ°°°þ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿkÿsÿ}ÿ„ÿŠÿÿÿÿÿŽÿŽÿÿŒÿŒÿ‹ÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿ‰ÿôøôÿÿÿÿÿÿÿÿÿÿÿÿÿßåßÿ P ÿxÿŠÿŠÿŠÿŠÿŠÿ†ÿVœVÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöøöÿdÿ(w(ÿãìãÿZ—Zÿ}ÿˆÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿ‰ÿ‰ÿˆÿ‡ÿ†ÿ…ÿ„ÿƒÿÿÿ~ÿzÿtÿmÿ c ÿ \ ÿÍÍÍÿÍÍÍÿÍÍÍÿÍÍÍÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿlÿwÿÿ†ÿŒÿÿ‘ÿ‘ÿ‘ÿÿÿÿÿŽÿÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿ‹ÿl¯lÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåêåÿ P ÿxÿŒÿŒÿŒÿŒÿŒÿ"‹"ÿìóìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿš·šÿ"l"ÿÜçÜÿˆ²ˆÿzÿ‰ÿŒÿŒÿŒÿ‹ÿ‰ÿ‚ÿ{ÿxÿyÿzÿ}ÿ€ÿ„ÿˆÿŠÿ‹ÿŒÿŒÿŒÿŒÿ‹ÿ‹ÿŠÿ‰ÿˆÿ‡ÿ†ÿ…ÿ„ÿƒÿ€ÿ|ÿvÿoÿ f ÿ \ ÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿmÿwÿÿ‡ÿŒÿÿ’ÿ’ÿ‘ÿ‘ÿ‘ÿÿÿÿŽÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŠÿ¼Ø¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðóðÿ O ÿyÿÿÿÿÿÿÁÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäëäÿ0o0ÿÔáÔÿ»Ò»ÿwÿ‰ÿÿÿÿŒÿ…ÿwÿ d ÿ V ÿ P ÿ Q ÿ T ÿ Z ÿ ` ÿgÿoÿuÿ{ÿ€ÿ†ÿ‹ÿÿÿŒÿ‹ÿŠÿ‰ÿˆÿ‡ÿ†ÿ…ÿ„ÿÿ|ÿwÿoÿfÿ \ ÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿnÿzÿ‚ÿ‰ÿŽÿ’ÿ”ÿ”ÿ“ÿ“ÿ“ÿ’ÿ’ÿ‘ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ##ÿúüúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúûúÿ P ÿzÿÿÿÿÿÿáîáÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõøõÿK‚KÿÏÝÏÿâëâÿ"|"ÿ‡ÿŽÿÿÿŒÿÿsÿ…«…ÿàèàÿøúøÿïòïÿÙáÙÿ»Ê»ÿ“«“ÿjjÿApAÿSÿ O ÿ X ÿhÿ|ÿ‹ÿÿÿŽÿÿŒÿ‹ÿŠÿ‰ÿˆÿ‡ÿ…ÿƒÿ~ÿyÿqÿiÿ ] ÿÎÎÎÿÎÎÎÿÎÎÎÿÎÎÎÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÏÏÏÿÏÏÏÿÏÏÏÿÏÏÏÿpÿ{ÿ„ÿ‹ÿÿ”ÿ–ÿ–ÿ•ÿ•ÿ•ÿ”ÿ”ÿ“ÿ’ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿd®dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ R ÿ|ÿ‘ÿ‘ÿ‘ÿ‘ÿ‘ÿûýûÿÿÿÿÿÿÿÿÿÿÿÿÿô÷ôÿWWÿÉÙÉÿõøõÿ<ˆ<ÿ†ÿÿ‘ÿÿ‹ÿ}ÿOŽOÿáéáÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüýüÿÔÞÔÿ ¼ ÿ\˜\ÿÿŽÿ‘ÿ‘ÿÿÿŽÿÿŒÿ‹ÿŠÿ‰ÿˆÿ…ÿ€ÿzÿsÿjÿ`ÿÏÏÏÿÏÏÏÿÏÏÏÿÏÏÏÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÏÏÏÿÏÏÏÿÏÏÏÿÏÏÏÿqÿ}ÿ…ÿÿ’ÿ–ÿ˜ÿ˜ÿ˜ÿ—ÿ—ÿ–ÿ–ÿ•ÿ”ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿžÌžÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ÷õÿ V ÿÿŽÿ…ÿ‚ÿ‰ÿ‘ÿÏèÏÿÿÿÿÿÿÿÿÿæíæÿC‚CÿÂÕÂÿþþþÿY—Yÿ…ÿ‘ÿ“ÿ’ÿ‹ÿ{ÿ‘µ‘ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüýüÿµÔµÿ9—9ÿÿ’ÿ“ÿ“ÿ’ÿ‘ÿÿÿŽÿÿŒÿ‹ÿŠÿ‡ÿ‚ÿ|ÿtÿlÿaÿÏÏÏÿÏÏÏÿÏÏÏÿÏÏÏÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿsÿ~ÿˆÿÿ”ÿ ˜ ÿ š ÿšÿšÿ™ÿ™ÿ˜ÿ—ÿ—ÿ–ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿ•ÿÌäÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿåëåÿ ] ÿÿ{ÿcÿ \ ÿqÿ‹ÿG«Gÿûýûÿïôïÿ a ÿ»Ð»ÿÿÿÿÿ¯ÿƒÿ‘ÿ‘ÿŒÿƒÿ&~&ÿÆØÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüýüÿ´Õ´ÿ:š:ÿÿ”ÿ•ÿ•ÿ•ÿ•ÿ”ÿ“ÿ“ÿ‘ÿÿÿŽÿÿŒÿ‰ÿ„ÿ~ÿvÿmÿbÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿtÿ€ÿ‰ÿÿ – ÿ!š!ÿ!œ!ÿ › ÿ › ÿ›ÿ›ÿšÿ™ÿ™ÿ˜ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿìõìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂÒÂÿeÿ&&ÿÅÙÅÿøúøÿv•vÿ \ ÿ…ÿ–ÿûýûÿ‹±‹ÿºÌºÿÿÿÿÿ›»›ÿtÿ€ÿÿxÿnÿ>>ÿåìåÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿò÷òÿ“Å“ÿ/˜/ÿ“ÿ–ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ–ÿ•ÿ•ÿ“ÿ’ÿ‘ÿÿÿŽÿŠÿ†ÿ€ÿwÿoÿcÿÐÐÐÿÐÐÐÿÐÐÐÿÐÐÐÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÑÑÑÿÑÑÑÿÑÑÑÿÑÑÑÿvÿ‚ÿ‹ÿ’ÿ ˜ ÿ!œ!ÿ!ž!ÿ ÿ ÿÿÿœÿ›ÿ›ÿšÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŽ­ŽÿpÿÕäÕÿÿÿÿÿÿÿÿÿäêäÿ X ÿ„ÿ”ÿòøòÿÄÖÄÿÿÿÿÿ²È²ÿ]ÿaÿ`ÿ;w;ÿddÿ±Æ±ÿüýüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûýûÿ¾Û¾ÿh²hÿ•ÿ—ÿ˜ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ™ÿ˜ÿ—ÿ—ÿ•ÿ”ÿ“ÿ’ÿ‘ÿÿŒÿˆÿÿyÿpÿeÿÑÑÑÿÑÑÑÿÑÑÑÿÑÑÑÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÑÑÑÿÑÑÑÿÑÑÑÿÑÑÑÿwÿ‚ÿ Œ ÿ!“!ÿ"™"ÿ##ÿ#Ÿ#ÿ#Ÿ#ÿ"ž"ÿ!ž!ÿ ž ÿÿœÿœÿ›ÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿùüùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿZZÿ‰¸‰ÿÿÿÿÿÿÿÿÿÿÿÿÿùûùÿ_ÿƒÿ…ÿØæØÿÿÿÿÿÔáÔÿƒ®ƒÿ¬É¬ÿ×ä×ÿúüúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîöîÿ³×³ÿm¶mÿ(š(ÿ—ÿ™ÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿ™ÿ˜ÿ˜ÿ–ÿ•ÿ”ÿ“ÿ’ÿÿÿ‰ÿ‚ÿzÿpÿeÿÑÑÑÿÑÑÑÿÑÑÑÿÑÑÑÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿyÿ„ÿ!Ž!ÿ"•"ÿ#›#ÿ$Ÿ$ÿ$¡$ÿ$¡$ÿ# #ÿ" "ÿ!Ÿ!ÿŸÿžÿžÿÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿæóæÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðôðÿrÿâïâÿÿÿÿÿÿÿÿÿÿÿÿÿÔàÔÿnÿ~ÿÀÖÀÿÿÿÿÿÞéÞÿ¾Û¾ÿéôéÿÿÿÿÿýþýÿîöîÿèóèÿÿÿÿÿÿÿÿÿùüùÿáïáÿÄáÄÿ›Í›ÿs»sÿB¦Bÿ™ÿ›ÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿ›ÿšÿšÿ˜ÿ—ÿ–ÿ•ÿ“ÿ’ÿÿ‹ÿ„ÿ|ÿrÿgÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿzÿ † ÿ""ÿ#—#ÿ$$ÿ%¡%ÿ%£%ÿ%£%ÿ$¢$ÿ#¢#ÿ"¡"ÿ ¡ ÿ ÿ ÿŸÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿ·Ý·ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ³ÿ…ÿöûöÿÿÿÿÿÿÿÿÿÿÿÿÿy«yÿ!y!ÿÇÚÇÿÿÿÿÿÎßÎÿ$‰$ÿ’ÿÿŠÿˆÿÿ˜ÿÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿžÿÿÿœÿšÿ™ÿ˜ÿ—ÿ•ÿ”ÿ‘ÿÿ†ÿ~ÿtÿhÿÒÒÒÿÒÒÒÿÒÒÒÿÒÒÒÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿ{ÿ!†!ÿ##ÿ$˜$ÿ%ž%ÿ&¢&ÿ&¤&ÿ&¤&ÿ%£%ÿ$£$ÿ#¢#ÿ!¢!ÿ ¡ ÿ¡ÿ ÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿžÿ˜ÿÿŠÿŠÿÿ™ÿžÿ‡Æ‡ÿÿÿÿÿÿÿÿÿÿÿÿÿèïèÿ""ÿ–ÿ…Ê…ÿúüúÿôøôÿŒºŒÿ&&ÿÎßÎÿÿÿÿÿÍÞÍÿ$‡$ÿˆÿ|ÿkÿ_ÿ\ÿiÿ„ÿ™ÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿŸÿžÿžÿÿ›ÿšÿ™ÿ˜ÿ–ÿ•ÿ“ÿŽÿ‡ÿ~ÿtÿiÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿ{ÿ"ˆ"ÿ#‘#ÿ%™%ÿ& &ÿ'¤'ÿ'¥'ÿ'¥'ÿ&¥&ÿ%¥%ÿ$¤$ÿ"¤"ÿ!£!ÿ ¢ ÿ¢ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿžÿ’ÿ~ÿiÿ]ÿ]ÿmÿ†ÿ›ÿ‹Æ‹ÿÿÿÿÿÿÿÿÿûüûÿR›Rÿ”ÿ ÿÿÚìÚÿ$€$ÿ**ÿÓâÓÿÿÿÿÿÊÝÊÿ$‡$ÿ€ÿF‹Fÿ¦À¦ÿäëäÿúûúÿÇÔÇÿ.e.ÿlÿ’ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ¡ÿ ÿ ÿžÿÿœÿ›ÿ™ÿ˜ÿ—ÿ”ÿÿˆÿÿvÿjÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿ } ÿ"Š"ÿ$“$ÿ&›&ÿ'¢'ÿ(¥(ÿ(§(ÿ(§(ÿ'§'ÿ&§&ÿ%¦%ÿ#¦#ÿ"¥"ÿ!¤!ÿ¤ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ ÿ’ÿM–Mÿ¼Ñ¼ÿòõòÿ÷ù÷ÿµÆµÿ-d-ÿlÿÿÉãÉÿÿÿÿÿñõñÿ`¡`ÿ”ÿ¡ÿ£ÿ8§8ÿ©Ñ©ÿ2€2ÿÝèÝÿÿÿÿÿÀØÀÿ#‰#ÿ(‡(ÿ®É®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¹É¹ÿaÿŽÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ¢ÿ¢ÿ ÿŸÿžÿÿ›ÿšÿ™ÿ–ÿ‘ÿŠÿÿxÿkÿÓÓÓÿÓÓÓÿÓÓÓÿÓÓÓÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÔÔÔÿÔÔÔÿÔÔÔÿÔÔÔÿ!~!ÿ#Š#ÿ%”%ÿ'œ'ÿ(£(ÿ)¦)ÿ)¨)ÿ)¨)ÿ(¨(ÿ'¨'ÿ&§&ÿ$¦$ÿ#¦#ÿ"¥"ÿ ¥ ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ£ÿ˜ÿ…¹…ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÄÒÄÿ_ÿ&&ÿüýüÿÿÿÿÿkškÿˆÿ¡ÿ¤ÿ¡ÿp¹pÿk¤kÿéïéÿÿÿÿÿ«Ì«ÿÿ:–:ÿàëàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ÷õÿgÿ‘ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ¤ÿ£ÿ£ÿ¡ÿ ÿŸÿžÿœÿ›ÿšÿ—ÿ’ÿ‹ÿ‚ÿxÿlÿÔÔÔÿÔÔÔÿÔÔÔÿÔÔÔÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÔÔÔÿÔÔÔÿÔÔÔÿÔÔÔÿ#ƒ#ÿ%Œ%ÿ'–'ÿ(ž(ÿ*¤*ÿ*¨*ÿ*ª*ÿ*ª*ÿ*ª*ÿ)©)ÿ(©(ÿ&¨&ÿ%¨%ÿ#§#ÿ"§"ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ¡ÿv¸vÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûüûÿcÿe«eÿÿÿÿÿ÷ù÷ÿ$x$ÿ–ÿ ¥ ÿ¡ÿ’ÿ˜Â˜ÿõøõÿÿÿÿÿ”Á”ÿ”ÿ/œ/ÿâíâÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×ã×ÿ|ÿœÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¦ ÿ ¥ ÿ ¥ ÿ£ÿ¢ÿ¡ÿŸÿžÿÿœÿ™ÿ“ÿŒÿ„ÿyÿmÿÔÔÔÿÔÔÔÿÔÔÔÿÔÔÔÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÕÕÕÿÕÕÕÿÕÕÕÿÕÕÕÿ%Š%ÿ'–'ÿ(›(ÿ) )ÿ*¥*ÿ+ª+ÿ+¬+ÿ+¬+ÿ+¬+ÿ*«*ÿ)«)ÿ'ª'ÿ&ª&ÿ$©$ÿ#©#ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ6¦6ÿ÷ú÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿæìæÿoÿ¥Î¥ÿÿÿÿÿ¦Â¦ÿƒÿ ¡ ÿ ¡ ÿŽÿ²ÿýþýÿüýüÿz´zÿ•ÿ™ÿ£Í£ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿm©mÿ–ÿ ¥ ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!§!ÿ!§!ÿ ¥ ÿ ¤ ÿ £ ÿ ¡ ÿ ÿŸÿÿ›ÿ•ÿŽÿ…ÿ{ÿoÿÕÕÕÿÕÕÕÿÕÕÕÿÕÕÕÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÕÕÕÿÕÕÕÿÕÕÕÿÕÕÕÿ%‹%ÿ(˜(ÿ*£*ÿ+ª+ÿ+ª+ÿ+«+ÿ+­+ÿ+­+ÿ+­+ÿ*¬*ÿ)¬)ÿ'«'ÿ&«&ÿ$ª$ÿ#ª#ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ™Ï™ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ©Ã©ÿÿåðåÿÿÿÿÿF‹Fÿ“ÿžÿ""ÿ©È©ÿÿÿÿÿðõðÿY£Yÿÿ‹ÿ…ÿøûøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ”¼”ÿŒÿ ¢ ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!©!ÿ!¨!ÿ!¨!ÿ ¦ ÿ ¥ ÿ ¤ ÿ ¢ ÿ¡ÿ ÿžÿœÿ–ÿÿ†ÿ|ÿoÿÕÕÕÿÕÕÕÿÕÕÕÿÕÕÕÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿ'Œ'ÿ*š*ÿ+¤+ÿ-®-ÿ/µ/ÿ0¸0ÿ.³.ÿ-¯-ÿ,¯,ÿ,®,ÿ+®+ÿ)­)ÿ(­(ÿ&¬&ÿ%¬%ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿÞïÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿK’KÿE¡EÿÿÿÿÿÄÙÄÿÿ”ÿ33ÿÍßÍÿÿÿÿÿÜèÜÿ<<ÿƒÿ0Œ0ÿ¾ÿåñåÿöúöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèðèÿd–dÿbÿyÿÿšÿ!¡!ÿ"¨"ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#ª#ÿ#ª#ÿ"¨"ÿ"§"ÿ"¦"ÿ"¤"ÿ!£!ÿ!¢!ÿ! !ÿ!ž!ÿ˜ÿ‘ÿˆÿ}ÿqÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿ''ÿ*š*ÿ,¥,ÿ.®.ÿ/¶/ÿ1º1ÿ1¼1ÿ1º1ÿ.´.ÿ-¯-ÿ,¯,ÿ*®*ÿ)®)ÿ'­'ÿ&­&ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ÷û÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿªÉªÿ‘ÿ„Ä„ÿÿÿÿÿU–UÿƒÿRšRÿêñêÿÿÿÿÿÀÕÀÿ'~'ÿLšLÿ¯Ò¯ÿîöîÿ˜Ê˜ÿ7™7ÿX¨Xÿ×è×ÿûýûÿëñëÿ»Ð»ÿqqÿ™·™ÿðôðÿw™wÿTÿdÿwÿ‘ÿ#¥#ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$¬$ÿ$«$ÿ$«$ÿ#©#ÿ#¨#ÿ#§#ÿ#¥#ÿ"¤"ÿ"£"ÿ"¡"ÿ"Ÿ"ÿ ™ ÿ’ÿˆÿ~ÿqÿÖÖÖÿÖÖÖÿÖÖÖÿÖÖÖÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿ×××ÿ×××ÿ×××ÿ×××ÿ)Ž)ÿ+›+ÿ.¦.ÿ0¯0ÿ1·1ÿ3»3ÿ3½3ÿ3½3ÿ2½2ÿ1¼1ÿ/¶/ÿ,°,ÿ+¯+ÿ)®)ÿ(®(ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿÜðÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖåÖÿ)“)ÿ$¤$ÿÄâÄÿÅÜÅÿoÿ|¬|ÿúüúÿÿÿÿÿ™¾™ÿp¬pÿÐæÐÿÍæÍÿy¾yÿ+”+ÿÿ#v#ÿXŽXÿ¦ÿœ·œÿ©À©ÿ¸Ë¸ÿàèàÿÿÿÿÿÿÿÿÿÿÿÿÿàçàÿºÎºÿ|¯|ÿ!•!ÿ%¨%ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&­&ÿ&¬&ÿ&¬&ÿ%ª%ÿ%©%ÿ%¨%ÿ%¦%ÿ$¥$ÿ$¤$ÿ$¢$ÿ# #ÿ"š"ÿ ’ ÿ‰ÿÿrÿ×××ÿ×××ÿ×××ÿ×××ÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿ×××ÿ×××ÿ×××ÿ×××ÿ**ÿ--ÿ/¨/ÿ2±2ÿ3¸3ÿ4½4ÿ5¿5ÿ5¿5ÿ4¿4ÿ3¿3ÿ2¾2ÿ1½1ÿ.·.ÿ+±+ÿ*°*ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿzÌzÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙçÙÿ6›6ÿ&§&ÿ/ª/ÿøûøÿPŽPÿªÄªÿÿÿÿÿöùöÿµÕµÿÀàÀÿ“ΓÿG°Gÿ$ž$ÿ ÿZ™Zÿ»Ï»ÿùûùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙèÙÿ>¢>ÿ&§&ÿ(®(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(¯(ÿ(®(ÿ(®(ÿ'¬'ÿ'«'ÿ'ª'ÿ&¨&ÿ&§&ÿ&¥&ÿ%¤%ÿ%¡%ÿ#›#ÿ"”"ÿ ‹ ÿ€ÿsÿ×××ÿ×××ÿ×××ÿ×××ÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿØØØÿØØØÿØØØÿØØØÿ++ÿ.ž.ÿ1©1ÿ3²3ÿ5¹5ÿ6¾6ÿ7À7ÿ7À7ÿ6À6ÿ5À5ÿ4¿4ÿ3¿3ÿ2¿2ÿ0¾0ÿ.¹.ÿ*²*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿuÈuÿæòæÿÿÿÿÿÅ×Åÿ1“1ÿ(©(ÿ)­)ÿd·dÿ°Î°ÿÓàÓÿÿÿÿÿéñéÿÅÿ@­@ÿ)«)ÿ)­)ÿ&¡&ÿ<”<ÿÀÕÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûýûÿ™É™ÿ/¤/ÿ)¬)ÿ*¯*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*¯*ÿ*¯*ÿ)­)ÿ)¬)ÿ)ª)ÿ(©(ÿ(¨(ÿ(¦(ÿ'¥'ÿ'¢'ÿ%œ%ÿ$•$ÿ"Œ"ÿÿsÿØØØÿØØØÿØØØÿØØØÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿØØØÿØØØÿØØØÿØØØÿ,,ÿ0Ÿ0ÿ3ª3ÿ5´5ÿ7»7ÿ8À8ÿ9Â9ÿ9Â9ÿ8Â8ÿ7Â7ÿ6Á6ÿ5Á5ÿ4Á4ÿ2À2ÿ1À1ÿ/¿/ÿ.».ÿ-¶-ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,±,ÿ-¨-ÿàîàÿüýüÿ,|,ÿ'ž'ÿ+¬+ÿ&œ&ÿ¬Ï¬ÿïôïÿÿÿÿÿ¿Ú¿ÿ4¡4ÿ+¬+ÿ,±,ÿ+°+ÿ(£(ÿ`§`ÿðôðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÇáÇÿO¯Oÿ*ª*ÿ,±,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,²,ÿ,±,ÿ,±,ÿ+¯+ÿ+®+ÿ+¬+ÿ*«*ÿ*ª*ÿ*¨*ÿ)§)ÿ(¤(ÿ'ž'ÿ&–&ÿ#Ž#ÿ!‚!ÿuÿØØØÿØØØÿØØØÿØØØÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿØØØÿØØØÿØØØÿØØØÿ-‘-ÿ1 1ÿ4«4ÿ6µ6ÿ8»8ÿ9Á9ÿ:Ã:ÿ:Ã:ÿ9Ã9ÿ8Â8ÿ7Â7ÿ6Â6ÿ5Á5ÿ3Á3ÿ2À2ÿ0À0ÿ0À0ÿ0À0ÿ0¾0ÿ.º.ÿ-µ-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ,¯,ÿÁÿÿÿÿÿ¿Ò¿ÿ!„!ÿ)¡)ÿ'–'ÿˆ·ˆÿýþýÿþþþÿ’Ã’ÿ+¢+ÿ,¯,ÿ-²-ÿ,¯,ÿ)£)ÿm¯mÿûýûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüýüÿ¹Û¹ÿ\¶\ÿ+ª+ÿ-±-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-±-ÿ-±-ÿ,¯,ÿ,®,ÿ,¬,ÿ+«+ÿ+ª+ÿ+¨+ÿ*§*ÿ)¤)ÿ(ž(ÿ&–&ÿ$Ž$ÿ!‚!ÿuÿØØØÿØØØÿØØØÿØØØÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿ.’.ÿ2¡2ÿ6¬6ÿ8¶8ÿ;½;ÿ;Â;ÿ<Ä<ÿ<Ä<ÿ;Ä;ÿ:Ã:ÿ9Ã9ÿ8Ã8ÿ7Â7ÿ5Â5ÿ4Á4ÿ2Á2ÿ2Á2ÿ2Á2ÿ2Á2ÿ2Á2ÿ2Á2ÿ1½1ÿ0¸0ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.².ÿ3©3ÿéòéÿÿÿÿÿlŸlÿ$Ž$ÿ,’,ÿ²Ï²ÿÿÿÿÿñöñÿf°fÿ+¦+ÿ-®-ÿ,ª,ÿ)¡)ÿ'–'ÿe¦eÿúüúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙëÙÿŒÊŒÿA¯Aÿ-®-ÿ.².ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.³.ÿ.².ÿ.².ÿ-°-ÿ-¯-ÿ-­-ÿ,¬,ÿ,«,ÿ+©+ÿ+¨+ÿ*¥*ÿ)Ÿ)ÿ'—'ÿ%%ÿ"ƒ"ÿvÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿ0”0ÿ4£4ÿ7¯7ÿ;¹;ÿ<¿<ÿ=Å=ÿ>Ç>ÿ>Ç>ÿ=Ç=ÿ<Æ<ÿ;Æ;ÿ:Æ:ÿ9Å9ÿ7Å7ÿ6Ä6ÿ4Ä4ÿ4Ä4ÿ4Ä4ÿ4Ä4ÿ4Ä4ÿ4Ä4ÿ4Ä4ÿ4Ä4ÿ4Ã4ÿ2¾2ÿ1¸1ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ/²/ÿ‹Ç‹ÿÿÿÿÿäìäÿ$y$ÿ:Ž:ÿÒâÒÿÿÿÿÿØçØÿE£Eÿ+¢+ÿ+¡+ÿ(—(ÿ$ˆ$ÿ!x!ÿnžnÿúüúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàïàÿšÑšÿU¹Uÿ.°.ÿ0µ0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0¶0ÿ0µ0ÿ0µ0ÿ/³/ÿ/²/ÿ.°.ÿ.¯.ÿ.­.ÿ-¬-ÿ-«-ÿ,¨,ÿ+¢+ÿ(š(ÿ&&ÿ#…#ÿ x ÿÙÙÙÿÙÙÙÿÙÙÙÿÙÙÙÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ1•2ÿ6¤6ÿ9°:ÿ<º=ÿ>À?ÿ?Æ@ÿ?È@ÿ?È@ÿ?È@ÿ>Ç?ÿ=Ç>ÿ<Ç=ÿ;Æ<ÿ9Æ:ÿ8Å9ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ6Å7ÿ5Â6ÿ4½5ÿ2¸3ÿ2¶3ÿ:­;ÿïöðÿÿÿÿÿ{¤|ÿOPÿéðéÿÿÿÿÿµÑµÿ/Ž0ÿ''ÿ$„%ÿ*{*ÿf˜fÿ¯Æ¯ÿöøöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþýÿÙíÙÿ’Î’ÿP·Pÿ0±1ÿ2¶3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2·3ÿ2¶3ÿ2¶3ÿ1´2ÿ1³2ÿ0±1ÿ0°1ÿ0®1ÿ/­0ÿ/¬0ÿ.©/ÿ,£-ÿ*›+ÿ(‘(ÿ$†%ÿ x!ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ4–4ÿ8¥8ÿ<±<ÿ?»?ÿAÂAÿBÈBÿBÊBÿBÊBÿBÉBÿAÉAÿ@É@ÿ?É?ÿ>È>ÿ<È<ÿ;Ç;ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ9Ç9ÿ6½6ÿ™Ï™ÿÿÿÿÿ×â×ÿk—kÿøúøÿýþýÿˆ®ˆÿ!p!ÿ==ÿ~¨~ÿÀÓÀÿúûúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿð÷ðÿ½á½ÿmÁmÿ:³:ÿ4¶4ÿ5¸5ÿ5¹5ÿ5¸5ÿ4µ4ÿ3±3ÿ1­1ÿ0¨0ÿ/¥/ÿ.¢.ÿ/£/ÿ1­1ÿ4¶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ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¹5ÿ5¸5ÿ5¸5ÿ4¶4ÿ4µ4ÿ3³3ÿ3²3ÿ3°3ÿ2¯2ÿ2­2ÿ1«1ÿ/¥/ÿ-œ-ÿ*“*ÿ'‡'ÿ#z#ÿÚÚÚÿÚÚÚÿÚÚÚÿÚÚÚÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿ6—6ÿ:¦:ÿ>²>ÿA¼AÿDÃDÿEÉEÿFËFÿEËEÿDÊDÿDÊDÿCÊCÿBÊBÿAÉAÿ?É?ÿ>È>ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<È<ÿ<Ç<ÿH¼Hÿõùõÿüýüÿ¢»¢ÿþþþÿñõñÿ…©…ÿ—µ—ÿÙãÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÞêÞÿ––ÿ>˜>ÿ.š.ÿ0 0ÿ1£1ÿ2¥2ÿ2¥2ÿ1£1ÿ1¡1ÿ/ž/ÿ-–-ÿ+Ž+ÿ(„(ÿ&}&ÿ$v$ÿ"p"ÿ$w$ÿ,’,ÿ2§2ÿ3ª3ÿ2§2ÿ1¤1ÿ1£1ÿ1¡1ÿ0 0ÿ0 0ÿ2¦2ÿ6³6ÿ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ÿ7·7ÿ7¶7ÿ6´6ÿ6³6ÿ5±5ÿ5°5ÿ4®4ÿ3¬3ÿ2¦2ÿ00ÿ-”-ÿ)ˆ)ÿ%{%ÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿ8˜8ÿ=¨=ÿA´AÿD¾DÿGÅGÿHËHÿIÍIÿHÌHÿGÌGÿGÌGÿFÌFÿEÌEÿDËDÿBËBÿAÊAÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ?Ê?ÿ=Ä=ÿ¦×¦ÿÿÿÿÿÒßÒÿÿÿÿÿòøòÿúýúÿýþýÿþþþÿ÷ù÷ÿíñíÿÜäÜÿ¼Ì¼ÿ«ÿY†Yÿ=u=ÿ*k*ÿ f ÿ!i!ÿ"m"ÿ$r$ÿ%t%ÿ%t%ÿ$r$ÿ%p%ÿ?}?ÿc“cÿ‡ª‡ÿ§¿§ÿ¾Ï¾ÿ×á×ÿðóðÿ}¡}ÿ%t%ÿ)ƒ)ÿ((ÿ&y&ÿ$t$ÿ#p#ÿ"n"ÿ"l"ÿ#o#ÿ+ˆ+ÿ6¬6ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;¼;ÿ;»;ÿ:º:ÿ:¹:ÿ:¸:ÿ9¶9ÿ9µ9ÿ8³8ÿ8²8ÿ7°7ÿ6®6ÿ5¨5ÿ2Ÿ2ÿ/–/ÿ+Š+ÿ'|'ÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿ:š:ÿ>©>ÿC¶CÿF¿FÿHÇHÿJÍJÿKÏKÿJÎJÿJÎJÿIÎIÿHÎHÿGÎGÿEÍEÿDÍDÿBÌBÿBÌBÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿAÌAÿ@Ê@ÿRÀRÿùüùÿîóîÿÿÿÿÿÍãÍÿF´Fÿ{Õ{ÿîùîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùúùÿçìçÿÔÞÔÿÃÑÃÿÇÕÇÿÐÜÐÿàèàÿøúøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿkŽkÿ¡ÿ¢¼¢ÿ»Í»ÿÎÚÎÿÛäÛÿäêäÿðóðÿóöóÿîóîÿ-Ž-ÿ8±8ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<¾<ÿ<½<ÿ;¼;ÿ;»;ÿ;º;ÿ:¸:ÿ:·:ÿ9µ9ÿ9´9ÿ8³8ÿ7¯7ÿ6©6ÿ2¡2ÿ0—0ÿ+‹+ÿ(~(ÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿ<›<ÿAªAÿE¶EÿIÀIÿKÈKÿMÍMÿNÐNÿNÐNÿMÏMÿLÏLÿKÏKÿJÏJÿHÎHÿGÎGÿEÍEÿEÍEÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿDÍDÿAÃAÿ´Û´ÿøûøÿÿÿÿÿ´×´ÿ@µ@ÿBÇBÿDÍDÿRÐRÿ©æ©ÿøýøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ…¼…ÿ9¬9ÿ>¼>ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¿?ÿ?¾?ÿ>½>ÿ>¼>ÿ>»>ÿ=¹=ÿ=¸=ÿ<¶<ÿ<µ<ÿ;´;ÿ:¯:ÿ8ª8ÿ5¢5ÿ2˜2ÿ.Œ.ÿ*~*ÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@°°°ÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿ=š=ÿBªBÿH·HÿKÂKÿMÉMÿOÎOÿOÐOÿOÐOÿOÐOÿNÐNÿMÐMÿLÐLÿJÏJÿIÏIÿGÎGÿGÎGÿFÎFÿFÎFÿFÎFÿFÎFÿFÎFÿFÎFÿFÎFÿFÎFÿFÎFÿFÎFÿDÈDÿ_º_ÿýþýÿÿÿÿÿ™É™ÿ?·?ÿEÊEÿFÎFÿFÎFÿFÎFÿFÎFÿTÑTÿ—á—ÿÚóÚÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôùôÿ…Ä…ÿ<²<ÿ@¼@ÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¿AÿA¾Aÿ@½@ÿ@¼@ÿ?»?ÿ?¹?ÿ>¸>ÿ>¶>ÿ=µ=ÿ=´=ÿ<¯<ÿ9ª9ÿ7¢7ÿ4˜4ÿ/‹/ÿ+~+ÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿ°°°ÿ@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?°°°ÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿ?œ?ÿE«EÿI¸IÿLÃLÿOÊOÿQÐQÿRÓRÿQÒQÿQÒQÿPÒPÿOÒOÿNÒNÿMÑMÿLÑLÿIÐIÿIÐIÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿFËFÿCµCÿìôìÿþþþÿÅÿA¼AÿGÍGÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿHÐHÿXÓXÿ…Ý…ÿ¨ä¨ÿè÷èÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíõíÿ›Ñ›ÿM¹MÿA¼AÿCÀCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÁCÿCÀCÿB¿BÿB¾BÿA¼AÿA»Aÿ@¹@ÿ@¸@ÿ@·@ÿ?¶?ÿ>±>ÿ;«;ÿ8£8ÿ5™5ÿ1Œ1ÿ+~+ÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿ°°°ÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?°°°ÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿCCÿG«GÿK¸KÿOÃOÿRËRÿTÑTÿUÓUÿTÓTÿTÓTÿSÓSÿRÓRÿQÓQÿPÒPÿOÒOÿMÒMÿLÑLÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿJÍJÿD¹DÿÎåÎÿýþýÿƒÂƒÿD¾DÿJÎJÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿKÑKÿzÜzÿÍðÍÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöûöÿÔëÔÿ¦Ù¦ÿtÇtÿF»FÿEÀEÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÂFÿFÁFÿEÀEÿE¿EÿD½DÿD¼DÿCºCÿC¹CÿB¸BÿB¶Bÿ@²@ÿ>¬>ÿ;¤;ÿ7™7ÿ3Œ3ÿ//ÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿ°°°ÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ=°°°þÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿJŸJÿI«IÿO¸OÿSÃSÿVËVÿXÒXÿYÔYÿYÔYÿXÔXÿWÔWÿWÔWÿUÔUÿTÓTÿRÓRÿQÓQÿPÒPÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿNÏNÿG½Gÿ®Õ®ÿûýûÿ{¾{ÿHÀHÿNÐNÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿOÒOÿd×dÿ–á–ÿ½ê½ÿÚòÚÿîùîÿøüøÿÿÿÿÿõûõÿäôäÿÓîÓÿÃéÃÿ±â±ÿŸÛŸÿƒÑƒÿaÆaÿH¿HÿHÁHÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÃIÿIÂIÿIÂIÿHÁHÿH¿HÿG¾GÿG½GÿF»FÿFºFÿE¹EÿE·EÿC³CÿA¬Aÿ=£=ÿ9™9ÿ5Œ5ÿ7ƒ7ÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿ°°°þ=ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ:¯¯¯ýÝÝÝÿÞÞÞÿÞÞÞÿÞÞÞÿR£RÿJ«KÿP¹QÿTÅUÿWÍXÿYÔZÿ[×\ÿ[×[ÿ[×[ÿZ×[ÿY×YÿX×YÿVÖWÿUÖVÿSÕTÿRÕSÿRÕSÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿPÓQÿJÃKÿ˜Í˜ÿýþýÿ~¾~ÿIÁJÿPÒQÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿQÕRÿPÒQÿOÏPÿNÍOÿMÊNÿLÈMÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÆLÿKÅLÿKÅLÿJÄKÿJÂKÿIÁJÿIÀJÿH¾IÿG½HÿG¼HÿG¹HÿEµFÿB¯Cÿ?¥@ÿ;š<ÿ6Ž6ÿ?‰?ÿÞÞÞÿÞÞÞÿÞÞÞÿÝÝÝÿ¯¯¯ý:ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6­­­ùÝÝÝÿßßßÿßßßÿßßßÿ\¨\ÿL¬LÿSºSÿWÆWÿZÎZÿ]Õ]ÿ^Ø^ÿ^Ù^ÿ]Ù]ÿ]Ù]ÿ\Ù\ÿ[Ù[ÿYØYÿXØXÿWØWÿU×UÿU×UÿT×TÿT×TÿT×TÿT×TÿTÖTÿOÊOÿ…Æ…ÿþÿþÿŒÄŒÿK¿KÿSÔSÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿT×TÿTÖTÿSÔSÿRÑRÿQÏQÿPÍPÿOÊOÿNÉNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÈNÿNÇNÿMÆMÿMÆMÿLÄLÿLÃLÿLÂLÿKÀKÿJ¿JÿJ¾JÿI»IÿG¶GÿE°EÿA¦Aÿ=›=ÿ8Ž8ÿKKÿßßßÿßßßÿßßßÿÝÝÝÿ­­­ù5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ .¨¨¨ñÛÛÛÿßßßÿßßßÿßßßÿl¯lÿNªNÿT¹TÿYÅYÿ]Í]ÿ_Ô_ÿaÙaÿaÚaÿaÚaÿ`Ú`ÿ_Ú_ÿ^Ú^ÿ]Ù]ÿ\Ù\ÿZÙZÿXØXÿXØXÿXØXÿWØWÿWØWÿWØWÿSÏSÿvÃvÿúüúÿ£Í£ÿK»KÿUÔUÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿWØWÿVÖVÿVÕVÿUÓUÿTÑTÿSÏSÿSÍSÿRËRÿRÊRÿQÉQÿQÉQÿQÉQÿQÉQÿQÉQÿQÉQÿQÉQÿQÈQÿPÇPÿPÇPÿOÅOÿOÄOÿNÃNÿNÁNÿMÀMÿM¿MÿK»KÿI¶IÿG¯GÿB¥Bÿ>š>ÿ9Œ9ÿ]š]ÿßßßÿßßßÿßßßÿÛÛÛÿ©©©ð. ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%£££ß×××ÿàààÿàààÿàààÿ·ÿO©OÿU¸Uÿ[Ã[ÿ^Î^ÿaÔaÿbÙbÿcÚcÿcÛcÿbÛbÿaÛaÿ`Û`ÿ`Ú`ÿ^Ú^ÿ\Ú\ÿ[Ù[ÿZÙZÿZÙZÿYÙYÿYÙYÿWÔWÿdÂdÿñ÷ñÿÅÞÅÿK´KÿVÒVÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿYÙYÿX×XÿXÖXÿWÕWÿWÔWÿWÓWÿVÑVÿVÏVÿTÎTÿTÍTÿRÊRÿRÈRÿQÇQÿQÄQÿOÁOÿOÀOÿM½MÿK·KÿH°HÿD¥Dÿ?™?ÿ9‹9ÿq¦qÿàààÿàààÿàààÿ×××ÿ£££ß%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ˜˜˜½ÏÏÏÿàààÿàààÿàààÿ˜Â˜ÿP¦PÿVµVÿ\Ã\ÿ`Î`ÿcÕcÿfÛfÿgÜgÿfÝfÿfÝfÿeÝeÿdÝdÿbÜbÿaÜaÿ`Ü`ÿ_Ü_ÿ]Û]ÿ]Û]ÿ]Û]ÿ[Ù[ÿXÇXÿÚìÚÿâîâÿS°SÿWÐWÿ\Ú\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Û\ÿ\Ú\ÿ[Ù[ÿ[Ø[ÿZ×ZÿYÕYÿYÔYÿXÒXÿXÑXÿWÏWÿVËVÿRÅRÿO¼OÿJ±JÿD¢Dÿ=“=ÿºÿàààÿàààÿàààÿÏÏÏÿ˜˜˜½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€€€‡ÂÂÂÿàààÿàààÿàààÿ»Ñ»ÿP£PÿY³Yÿ^Á^ÿcÌcÿgÔgÿiÚiÿjÜjÿkÝkÿjÞjÿiÞiÿhÞhÿgÞgÿfÝfÿdÝdÿbÝbÿbÜbÿaÜaÿaÛaÿ[Ð[ÿ°Ù°ÿúüúÿj±jÿWÈWÿ_Ú_ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Ü`ÿ`Û`ÿ`Û`ÿ_Ú_ÿ^Ù^ÿ^Ø^ÿ]Ö]ÿ]Õ]ÿ\Ó\ÿ[Ñ[ÿZÏZÿXÊXÿUÄUÿQºQÿL®LÿFŸFÿ??ÿ·Í·ÿàààÿàààÿàààÿÂÂÂÿ€€€†ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ $$$;²²²ÿáááÿáááÿáááÿáááÿW£WÿY°Yÿ_¾_ÿeÊeÿhÓhÿkÚkÿmÞmÿmßmÿmàmÿlàlÿlàlÿjàjÿißiÿhßhÿfßfÿeßeÿdÞdÿbÙbÿƒÍƒÿþÿþÿœÃœÿS»SÿaÚaÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÞcÿcÝcÿcÝcÿbÜbÿaÛaÿaÚaÿ`Ø`ÿ`Ö`ÿ_Õ_ÿ^Ó^ÿ]Ð]ÿZÊZÿWÃWÿS¹SÿM«MÿFFÿF‘Fÿáááÿáááÿáááÿáááÿ²²²ÿ 8 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ%«««òÝÝÝÿáááÿáááÿáááÿu²uÿY¬Yÿ`»`ÿeÇeÿjÒjÿnÙnÿoÞoÿqàqÿpápÿpápÿoáoÿnánÿmàmÿkàkÿjàjÿhàhÿhÞhÿfÎfÿéóéÿåîåÿO¦Oÿ`Ñ`ÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfÞfÿeÝeÿeÜeÿdÜdÿdÚdÿcÙcÿb×bÿbÖbÿaÔaÿ_Ñ_ÿ\É\ÿXÁXÿS¶SÿM¨MÿF™Fÿj¦jÿáááÿáááÿáááÿÝÝÝÿ«««ò%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸŸŸÉÓÓÓÿâââÿâââÿâââÿ¥È¥ÿW§Wÿ_·_ÿeÄeÿkÐkÿoØoÿqÞqÿràrÿsásÿrârÿqâqÿpâpÿoáoÿnánÿlálÿkákÿhÛhÿ¯Ý¯ÿÿÿÿÿ„¯„ÿW¹WÿfÜfÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhàhÿhßhÿhßhÿgÞgÿgÝgÿfÜfÿfÛfÿeÚeÿdØdÿdÖdÿbÓbÿaÐaÿ]È]ÿX¾XÿS²SÿL¥LÿD”Dÿ¡Ã¡ÿâââÿâââÿâââÿÓÓÓÿŸŸŸÈÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿƒƒƒ}ÂÂÂÿâââÿâââÿâââÿâââÿW¢Wÿ_²_ÿf¿fÿlËlÿpÖpÿsÜsÿtàtÿvâvÿuãuÿuãuÿtãtÿsãsÿqâqÿpâpÿoâoÿsÖsÿùüùÿöùöÿD†Dÿ]Â]ÿlàlÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkákÿkàkÿkàkÿjßjÿjÞjÿiÝiÿhÜhÿhÚhÿgÙgÿfÖfÿdÓdÿbÎbÿ]Å]ÿY»YÿS®SÿKžKÿI“IÿâââÿâââÿâââÿâââÿÂÂÂÿ‚‚‚|ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ %¯¯¯üáááÿâââÿâââÿâââÿ•Á•ÿ_­_ÿf¼fÿlÉlÿqÓqÿuÚuÿxáxÿyâyÿzäzÿyåyÿxåxÿwåwÿvävÿuäuÿtätÿ°ã°ÿÿÿÿÿÞæÞÿ=|=ÿZ·ZÿmÝmÿpãpÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoãoÿoâoÿoâoÿnánÿnànÿmßmÿlÞlÿlÜlÿkÚkÿiÖiÿgÔgÿdÌdÿ_Ã_ÿZ¸ZÿS«SÿLšLÿŒ¸Œÿâââÿâââÿâââÿáááÿ¯¯¯ü"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¤¤¤ÔÓÓÓÿãããÿãããÿãããÿ¾Ô¾ÿ]§]ÿf·fÿlÅlÿrÑrÿvÚvÿyáyÿ{ä{ÿ}ç}ÿ}ç}ÿ{è{ÿ{è{ÿzçzÿyçyÿwçwÿãõãÿÿÿÿÿôöôÿ>q>ÿN›NÿgÏgÿrärÿsæsÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrærÿrårÿrårÿqäqÿqãqÿpâpÿpápÿoàoÿnÞnÿnÜnÿkØkÿiÔiÿeÌeÿ_Â_ÿY´YÿR¥RÿJ”Jÿ¼Ñ¼ÿãããÿãããÿãããÿÑÑÑÿ¢¢¢Ìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ yyyd¾¾¾ÿãããÿãããÿãããÿãããÿu²uÿc¯cÿk¿kÿrÌrÿvÖvÿ{Þ{ÿ~ä~ÿæÿèÿéÿ~é~ÿ}è}ÿ|è|ÿ{è{ÿüþüÿÿÿÿÿÿÿÿÿ±Å±ÿO”OÿfÇfÿtâtÿvçvÿvçvÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuçuÿuæuÿuæuÿtåtÿtätÿsãsÿsâsÿrárÿqßqÿoÛoÿmØmÿjÑjÿeÇeÿ_¼_ÿX®XÿPPÿk§kÿãããÿãããÿãããÿãããÿ¼¼¼ÿttt[ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ñÞÞÞÿäääÿäääÿäääÿ´Ï´ÿa¨aÿi·iÿpÅpÿvÑvÿ|Û|ÿâÿåÿ‚è‚ÿ‚é‚ÿ‚ê‚ÿêÿ€é€ÿéÿëúëÿÿÿÿÿÿÿÿÿúüúÿ†É†ÿrÙrÿxæxÿyèyÿyèyÿyèyÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxèxÿxçxÿxçxÿwæwÿwåwÿvävÿuãuÿuáuÿsÞsÿqÚqÿnÕnÿkÎkÿeÃeÿ^µ^ÿV§VÿN—Nÿ·Î·ÿäääÿäääÿäääÿÜÜÜÿ­­­ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ •••ÆÆÆÿäääÿäääÿäääÿäääÿu°uÿf°fÿn¾nÿuËuÿ{Ö{ÿÞÿäÿƒçƒÿ„é„ÿ„ê„ÿƒëƒÿƒêƒÿ‚ê‚ÿšíšÿèùèÿä÷äÿŽÜŽÿxàxÿ{ç{ÿ|é|ÿ|é|ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzézÿzèzÿzèzÿyçyÿyæyÿxäxÿwãwÿuàuÿtÝtÿqÙqÿnÒnÿiÈiÿc¼cÿ[®[ÿSŸSÿh£hÿäääÿäääÿäääÿäääÿÅÅÅÿ‘‘‘ˆ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®øßßßÿäääÿäääÿäääÿÄÖÄÿc¦cÿl¶lÿrÄrÿzÐzÿÚÿƒáƒÿ…æ…ÿ‡é‡ÿ‡ë‡ÿ‡ë‡ÿ†ë†ÿ…ë…ÿ…ë…ÿ„ë„ÿƒëƒÿ‚ë‚ÿëÿ€ê€ÿ€ê€ÿêÿêÿ~ê~ÿ~ê~ÿ~ê~ÿ~ê~ÿ~ê~ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ~ê~ÿ~ê~ÿ~ê~ÿ}ê}ÿ}ê}ÿ}ê}ÿ}ê}ÿ}é}ÿ|è|ÿ|ç|ÿ{æ{ÿ{ä{ÿzäzÿxàxÿvÜvÿrÕrÿnÎnÿhÂhÿ`´`ÿY¦YÿO•Oÿ»Ð»ÿäääÿäääÿäääÿßßßÿ­­­õÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ˜˜˜“ÆÆÆÿåååÿåååÿåååÿåååÿ Æ ÿi®iÿp»pÿxÈxÿ~Ô~ÿƒÜƒÿ†å†ÿ‰è‰ÿŠëŠÿŠíŠÿ‰ì‰ÿŠíŠÿ‰í‰ÿˆíˆÿ‡í‡ÿ†í†ÿ…í…ÿ…í…ÿ„í„ÿƒìƒÿƒìƒÿƒìƒÿ‚ì‚ÿ‚ì‚ÿ‚ì‚ÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿ€ë€ÿ€ë€ÿ€ê€ÿéÿ~ç~ÿ}æ}ÿ|ã|ÿzßzÿwÚwÿrÐrÿmÇmÿfºfÿ^¬^ÿVžVÿ–¾–ÿåååÿåååÿåååÿåååÿÆÆÆÿ˜˜˜‘ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ­­­ïÔÔÔÿåååÿåååÿåååÿåååÿt¯tÿm²mÿuÀuÿ|Í|ÿ‚ׂÿ†ß†ÿ‰å‰ÿŒéŒÿŒìŒÿíÿŒíŒÿîÿŒîŒÿ‹î‹ÿŠîŠÿŠîŠÿ‰î‰ÿˆîˆÿ‡í‡ÿ‡í‡ÿ†í†ÿ†í†ÿ†í†ÿ…í…ÿ…í…ÿ…í…ÿ…í…ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿ…í…ÿ…í…ÿ…í…ÿ„í„ÿ„í„ÿ„í„ÿ„í„ÿƒìƒÿƒìƒÿƒëƒÿéÿ€ç€ÿäÿ}á}ÿzÜzÿwÔwÿqËqÿj¿jÿc±cÿ[£[ÿd¡dÿåååÿåååÿåååÿåååÿÖÖÖÿ­­­òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ………[¾¾¾ÿåååÿåååÿåååÿåååÿÂÖÂÿh¨hÿp¶pÿxÃxÿÐÿ„Ù„ÿˆáˆÿ‹æ‹ÿŽêŽÿŽíŽÿîÿŽîŽÿïÿŽïŽÿïÿïÿŒïŒÿ‹ï‹ÿ‹ï‹ÿŠïŠÿŠïŠÿ‰î‰ÿ‰î‰ÿˆîˆÿˆîˆÿˆîˆÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ†î†ÿ†î†ÿ…í…ÿ…ì…ÿƒêƒÿƒéƒÿæÿ€ã€ÿ|Þ|ÿy×yÿtÍtÿnÃnÿfµfÿ^§^ÿU˜Uÿ¾Ò¾ÿåååÿåååÿåååÿåååÿÀÁÀÿ‹‹‹eÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ §§§ÊÊÊÊÿæææÿæææÿæææÿæææÿ£Ç£ÿkªkÿs¸sÿzÅzÿÑÿ†Û†ÿŠâŠÿçÿëÿîÿîÿïÿðÿðÿðÿðÿŽðŽÿŽðŽÿðÿðÿŒðŒÿŒðŒÿ‹ï‹ÿ‹ï‹ÿ‹ï‹ÿ‹ï‹ÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿŠïŠÿ‰ï‰ÿ‰ï‰ÿ‰ï‰ÿ‰ï‰ÿˆïˆÿˆïˆÿ‡î‡ÿ†ì†ÿ…ê…ÿ„è„ÿ‚ä‚ÿàÿ|Ù|ÿvÐvÿpÅpÿi¸iÿaªaÿYœYÿ›À›ÿæææÿæææÿæææÿæææÿÊÊÊÿ¨¨¨Ð ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿSSS"¯¯¯ùØØØÿæææÿæææÿæææÿæææÿйŠÿm­mÿv»vÿ}Ç}ÿƒÒƒÿˆÛˆÿŒâŒÿèÿ‘ë‘ÿ“î“ÿ“ï“ÿ“ð“ÿ’ð’ÿ“ñ“ÿ’ñ’ÿ’ñ’ÿ‘ñ‘ÿ‘ñ‘ÿñÿñÿñÿñÿñÿðÿðÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿŽðŽÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿŒðŒÿŒðŒÿŒðŒÿ‹ð‹ÿŠïŠÿ‰î‰ÿ‰ì‰ÿ‡é‡ÿ…å…ÿ‚á‚ÿ~Ú~ÿyÑyÿsÇsÿlºlÿd®dÿ[Ÿ[ÿ¯ÿæææÿæææÿæææÿæææÿØØØÿ¯¯¯ùSSS"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ’’’eÁÂÁÿæææÿæææÿæææÿæææÿæææÿ†·†ÿo®oÿw¼wÿÈÿ…Ò…ÿŠÛŠÿŽâŽÿ‘è‘ÿ”ì”ÿ•î•ÿ•ð•ÿ•ò•ÿ•ò•ÿ–ó–ÿ–ó–ÿ•ó•ÿ•ó•ÿ”ó”ÿ”ó”ÿ“ó“ÿ“ó“ÿ“ó“ÿ’ó’ÿ’ó’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ’ò’ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿ‘ò‘ÿòÿòÿòÿòÿòÿòÿñÿŒðŒÿ‹î‹ÿŠëŠÿˆçˆÿ…â…ÿ€Û€ÿ{Ò{ÿvÈvÿn¼nÿf¯fÿ^ ^ÿz­zÿæææÿæææÿæææÿæææÿæææÿÁÂÁÿ’’’eÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ¤¤¤ªÇÇÇÿçççÿçççÿçççÿçççÿçççÿ‡·‡ÿr¯rÿx»yÿ€Çÿ†Ò‡ÿ‹ÚŒÿâÿ’ç“ÿ•ë•ÿ—î˜ÿ˜ð™ÿ—ñ˜ÿ˜ó™ÿ˜ó™ÿ˜ô™ÿ˜ô™ÿ—ô˜ÿ—ô˜ÿ—ô˜ÿ—ô˜ÿ–ô—ÿ–ô—ÿ–ô—ÿ–ô—ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ•ó–ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ”ó•ÿ“ó”ÿ“ó”ÿ“ó”ÿ‘ò’ÿò‘ÿðÿŽîÿëŽÿ‰æŠÿ†á‡ÿ‚Ûƒÿ}Ò~ÿwÈxÿp¼qÿh®iÿa¢aÿ{­{ÿçççÿçççÿçççÿçççÿçççÿÇÇÇÿ¤¤¤ª ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ «««ÙÈÈÈÿçççÿçççÿçççÿçççÿçççÿ‰¸‰ÿr®rÿzºzÿÅÿ†Ï†ÿŒØŒÿßÿ”å”ÿ•ê•ÿ˜í˜ÿšïšÿšñšÿšòšÿ›ô›ÿšôšÿšôšÿ›õ›ÿšõšÿšõšÿšõšÿ™õ™ÿ™õ™ÿ™õ™ÿ™õ™ÿ™ô™ÿ™ô™ÿ™ô™ÿ™ô™ÿ™ô™ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ˜ô˜ÿ—ô—ÿ—ô—ÿ—ô—ÿ—ô—ÿ—ô—ÿ—ô—ÿ•ó•ÿ•ó•ÿ”ó”ÿ“ñ“ÿ’ð’ÿ‘î‘ÿŽêŽÿ‹æ‹ÿˆàˆÿƒÙƒÿ~Ð~ÿxÆxÿq»qÿj®jÿa¡aÿ~®~ÿçççÿçççÿçççÿçççÿçççÿÈÈÈÿ«««Ù ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ888®®®êËËËÿçççÿçççÿçççÿçççÿçççÿ¼ÿr«rÿy¸yÿÂÿ…Ì…ÿ‹Ô‹ÿÛÿ’â’ÿ•ç•ÿ—ë—ÿšíšÿšðšÿœòœÿœóœÿœôœÿœõœÿœõœÿœöœÿœöœÿœöœÿœöœÿ›ö›ÿ›ö›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿ›õ›ÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿšõšÿ™õ™ÿ™õ™ÿ™õ™ÿ˜ô˜ÿ—ô—ÿ—ó—ÿ–ò–ÿ•ñ•ÿ“ï“ÿ‘ì‘ÿŽéŽÿ‹ä‹ÿ‡Ý‡ÿ‚Õ‚ÿ~Í~ÿxÃxÿq¸qÿi­iÿbŸbÿ…³…ÿçççÿçççÿçççÿçççÿçççÿËËËÿ®®®ê888ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿnnn ¯¯¯ðÍÍÍÿèèèÿèèèÿèèèÿèèèÿèèèÿ¨É¨ÿq©qÿx´xÿ~¿~ÿ„È„ÿ‰Ð‰ÿØÿ‘ß‘ÿ•ä•ÿ—é—ÿ™ì™ÿšîšÿ›ð›ÿœòœÿôÿõÿžöžÿ÷ÿ÷ÿöÿöÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿ÷ÿœ÷œÿœ÷œÿœ÷œÿœ÷œÿœ÷œÿœ÷œÿœ÷œÿœ÷œÿœ÷œÿ›ö›ÿ›ö›ÿ›ö›ÿšöšÿšõšÿ™ô™ÿ˜ó˜ÿ–ñ–ÿ•ï•ÿ“í“ÿ‘ê‘ÿŽçŽÿŠáŠÿ†Û†ÿ‚Ó‚ÿ}Ê}ÿvÀvÿpµpÿiªiÿaaÿ¡Ä¡ÿèèèÿèèèÿèèèÿèèèÿèèèÿÍÍÍÿ¯¯¯ðnnn ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°www%¯¯¯ñËËËÿèèèÿèèèÿèèèÿèèèÿèèèÿÈÙÈÿ±ÿv¯vÿ|º|ÿ‚Âÿ‡Ë‡ÿ‹Ó‹ÿÙÿ’ß’ÿ•ã•ÿ—ç—ÿ™ê™ÿ›ì›ÿœîœÿðÿñÿžóžÿžôžÿŸõŸÿŸõŸÿŸõŸÿŸõŸÿžõžÿžöžÿžöžÿžöžÿžöžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿžõžÿõÿõÿôÿôÿôÿôÿôÿœóœÿšòšÿ™ð™ÿ™ï™ÿ—í—ÿ•ë•ÿ“è“ÿåÿŒáŒÿ‰Ü‰ÿ…Õ…ÿ€Í€ÿ{Ä{ÿu»uÿn°nÿg¤gÿs§sÿÅÖÅÿèèèÿèèèÿèèèÿèèèÿèèèÿËËËÿ¯¯¯ñwww%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°qqq®®®ëÈÈÈÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿ¨É¨ÿs©sÿy³yÿ¼ÿ„Ä„ÿ‰Ì‰ÿŒÒŒÿØÿ’Ý’ÿ•á•ÿ—å—ÿ™ç™ÿ™é™ÿšêšÿ›ì›ÿœíœÿœîœÿœïœÿœïœÿðÿðÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿœðœÿ›ð›ÿ›ð›ÿ›ð›ÿšïšÿšïšÿšîšÿ™í™ÿ—ì—ÿ–ê–ÿ•è•ÿ“æ“ÿ‘ã‘ÿßÿŠÚŠÿ†Õ†ÿ‚΂ÿ~Æ~ÿx¾xÿrµrÿkªkÿeŸeÿ¢Ä¢ÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿÈÈÈÿ®®®ëqqq°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°FFF¬¬¬ÖÇÇÇÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿÆØÆÿ…´…ÿt«tÿzµzÿ¼ÿ„Äÿ‡Ê‡ÿŠÏŠÿŽÔŽÿÙÿ’Ý’ÿ”ß”ÿ–á–ÿ–ã–ÿ—ä—ÿ—å—ÿ˜ç˜ÿ˜æ˜ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ™ç™ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ˜ç˜ÿ–æ–ÿ–æ–ÿ•ä•ÿ“ã“ÿ“â“ÿ‘à‘ÿÞÿŒÛŒÿŠ×Šÿ†Ò†ÿ‚Ë‚ÿ~Å~ÿy¾yÿtµtÿn­nÿg£gÿ{«{ÿÄÖÄÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿÇÇÇÿ¬¬¬ÖFFF°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°¨¨¨¥ÂÃÂÿÚÚÚÿéééÿéééÿéééÿéééÿéééÿéééÿÁÖÁÿ‰¶‰ÿuªuÿz²zÿ¹ÿ‚¿‚ÿ†Å†ÿ‰Ê‰ÿ‹Î‹ÿÑÿÕÿ×ÿ‘Ù‘ÿ‘Ù‘ÿ“Û“ÿ’Ü’ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ“Ý“ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ’Ý’ÿ‘Ü‘ÿ‘Û‘ÿÚÿŽØŽÿŽ×ŽÿŒÕŒÿŠÓŠÿˆÏˆÿ„Ë„ÿ‚Ç‚ÿ~Á~ÿy»yÿu³uÿo«oÿi¢iÿ€®€ÿ½Ó½ÿéééÿéééÿéééÿéééÿéééÿéééÿÚÚÚÿÂÃÂÿ¨¨¨¥°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°ŸŸŸ]¯¯¯ùËËËÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿÊÚÊÿ©É©ÿw©xÿx®xÿ|³|ÿ~·~ÿ‚½‚ÿ„Á…ÿ†Ä‡ÿ‡ÈˆÿˆÉ‰ÿˆÊ‰ÿŠÌŠÿŠÍ‹ÿŠÍ‹ÿ‹ÎŒÿŠÎ‹ÿŠÏ‹ÿŠÏ‹ÿŠÏ‹ÿŠÏ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿŠÎ‹ÿ‰ÎŠÿ‰ÎŠÿ‰ÍŠÿ‰ÍŠÿˆÌ‰ÿˆÌ‰ÿ‡Ë‡ÿ…Ɇÿ„Ç…ÿƒÆƒÿ€Áÿ~¿ÿ{¹{ÿv³vÿs®sÿn¨nÿm£nÿ¤Å¤ÿÈØÈÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿËËËÿ¯¯¯ùŸŸŸ]°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°zzz­­­ÊÂÂÂÿÚÚÚÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿ»Ò»ÿ‘º‘ÿy«yÿuªvÿx®yÿz±zÿ|´|ÿ}·}ÿ~¸ÿº€ÿ»€ÿ¼€ÿ€½ÿ€½ÿ€½ÿ€½ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ¼€ÿ~¼ÿ}»~ÿ}º~ÿ|¹}ÿz¶{ÿy´yÿw±wÿt®tÿqªrÿn¦oÿq¦qÿŒ¶Œÿ¸Ð¸ÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿÙÙÙÿÂÂÂÿ¬¬¬Êzzz°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°¢¢¢Y¯¯¯ñÇÇÇÿäääÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿÍÛÍÿ±Í±ÿžÁžÿ¹ÿƒ±ƒÿ}­}ÿx©xÿt§tÿr¦rÿr¦rÿs§sÿs§sÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿr¦rÿq¦qÿq¦qÿq¦qÿq¦qÿq¦qÿq¦qÿp¥pÿp¥pÿq¥qÿu§uÿy«yÿ¯ÿŒ¶Œÿš¿šÿ®Ë®ÿÌÚÌÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿäääÿÇÇÇÿ¯¯¯ñ   X°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¨¨¨‡¯¯¯öÈÈÈÿäääÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿäääÿÈÈÈÿ¯¯¯ö¨¨¨‡°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°;;;¨¨¨€¯¯¯ï½½½ÿÕÕÕÿéééÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿéééÿÕÕÕÿ½½½ÿ¯¯¯ï¨¨¨€;;;°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°¢¢¢=­­­Á¯¯¯úÅÅÅÿÙÙÙÿåååÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿåååÿÙÙÙÿÅÅÅÿ¯¯¯ú­­­Á¢¢¢=°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°§§§a¬¬¬¹¯¯¯í°°°þÆÆÆÿÕÕÕÿßßßÿåååÿèèèÿéééÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿéééÿèèèÿåååÿßßßÿÕÕÕÿÆÆÆÿ²²²ÿ¯¯¯í¬¬¬¹§§§a°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°~~~©©©e¬¬¬¦­­­Ð¯¯¯é¯¯¯ö°°°ü°°°þ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°þ°°°ü¯¯¯ö¯¯¯é­­­Ð¬¬¬¦©©©e~~~°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿüÿÿÿÿÿÿðÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿþ?ÿÿÿÿøÿÿÿÿðÿÿÿÿàÿÿÿÿÀÿÿÿÿ€ÿÿÿÿÿÿþ?ÿÿüÿÿøÿÿðÿÿðÿÿàÿÿÀÿÿÀÿÿ€ÿÿ€ÿÿÿþ?þ?þ?üüüüøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøüüüüþ?þ?þ?ÿÿÿ€ÿÿ€ÿÿÀÿÿÀÿÿàÿÿðÿÿðÿÿøÿÿüÿÿþ?ÿÿÿÿÿÿ€ÿÿÿÿÀÿÿÿÿàÿÿÿÿðÿÿÿÿøÿÿÿÿþ?ÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿðÿÿÿÿÿÿüÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(@€ °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°P°°°­°°°Ý°°°ô°°°ý°°°þ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°þ°°°ý°°°ô°°°Ý°°°¯°°°Y°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°A°°°Â°°°ûµµµÿ¼¼¼ÿ¿¿¿ÿÀÀÀÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÀÀÀÿ¿¿¿ÿ¼¼¼ÿ¶¶¶ÿ°°°û°°°Ã°°°A°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°E°°°Þ´´´ÿ»»»ÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿÁÁÁÿ»»»ÿ´´´ÿ°°°ß°°°F°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°Ã´´´ÿ¼¼¼ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ¼¼¼ÿ´´´ÿ°°°Æ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°E°°°ö¹¹¹ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ¦¯¦ÿj†jÿCjCÿ)Y)ÿMÿIÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿDÿHÿLÿ)X)ÿAhAÿeeÿ¥®¥ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ¹¹¹ÿ°°°÷°°°J°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°t°°°þ¼¼¼ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ‘ ‘ÿFpFÿ H ÿIÿKÿLÿMÿ M ÿ M ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ N ÿ M ÿ M ÿ L ÿ L ÿLÿJÿHÿGÿ E ÿEmEÿŸÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ½½½ÿ°°°þ°°°y°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°Œ¶·¶ÿÀÀÀÿÃÃÃÿÃÃÃÿÃÃÃÿ©ÿEpEÿJÿNÿPÿ Q ÿ R ÿ S ÿ T ÿ T ÿ T ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ S ÿ R ÿ Q ÿ P ÿ N ÿLÿJÿFÿBlBÿ™§™ÿÃÃÃÿÃÃÃÿÃÃÃÿÁÁÁÿ¶·¶ÿ°°°Ž°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°s···ÿÃÃÃÿÄÄÄÿÄÄÄÿÄÄÄÿqqÿ L ÿ P ÿ R ÿ U ÿ V ÿ W ÿ W ÿ W ÿ W ÿ W ÿ W ÿ W ÿ W ÿ W ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ V ÿ U ÿ U ÿ T ÿ T ÿ R ÿ P ÿ M ÿ J ÿ F ÿlˆlÿÄÄÄÿÄÄÄÿÄÄÄÿÃÃÃÿ···ÿ°°°s°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°F°°°þÁÁÁÿÄÄÄÿÄÄÄÿÄÄÄÿZ€Zÿ P ÿ U ÿ Y ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ [ ÿ Z ÿ Z ÿ Y ÿ X ÿ X ÿ W ÿ U ÿ S ÿ O ÿ J ÿUzUÿÄÄÄÿÄÄÄÿÄÄÄÿÁÁÁÿ°°°þ°°°H°°°°°°°°°°°°°°°°°°°°°°°°°°°ö¾¾¾ÿÅÅÅÿÅÅÅÿÅÅÅÿNzNÿ S ÿ X ÿ \ ÿ ] ÿ ^ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ _ ÿ ^ ÿ ^ ÿ ^ ÿ ] ÿ ] ÿ \ ÿ [ ÿ Z ÿ Y ÿ W ÿ U ÿ R ÿ L ÿKsKÿÅÅÅÿÅÅÅÿÅÅÅÿ¿¿¿ÿ°°°÷°°°°°°°°°°°°°°°°°°°°°°°°ÂºººÿÅÅÅÿÅÅÅÿÅÅÅÿ\ƒ\ÿ T ÿ [ ÿ _ ÿ ` ÿ a ÿ a ÿ a ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ b ÿ a ÿ a ÿ ` ÿ ` ÿ _ ÿ ^ ÿ ] ÿ [ ÿ Y ÿ W ÿ S ÿ M ÿX}XÿÅÅÅÿÅÅÅÿÅÅÅÿºººÿ°°°È°°°°°°°°°°°°°°°°°°C´µ´ÿÆÆÆÿÆÆÆÿÆÆÆÿp‘pÿ W ÿ ` ÿ e ÿ f ÿ g ÿ g ÿ g ÿ g ÿ g ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ h ÿ g ÿ g ÿ g ÿ f ÿ e ÿ d ÿ b ÿ b ÿ ` ÿ ^ ÿ \ ÿ W ÿ O ÿlŒlÿÆÆÆÿÆÆÆÿÆÆÆÿµ¶µÿ°°°H°°°°°°°°°°°°°°°àÀÀÀÿÇÇÇÿÇÇÇÿ¢°¢ÿ X ÿ _ ÿ f ÿ h ÿ i ÿ i ÿ j ÿ j ÿ j ÿ j ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ k ÿ i ÿ f ÿ f ÿ i ÿ j ÿ j ÿ g ÿ a ÿ ] ÿ ] ÿ b ÿ c ÿ b ÿ ` ÿ ] ÿ V ÿ N ÿ™©™ÿÇÇÇÿÇÇÇÿÀÀÀÿ°°°ß°°°°°°°°°°°°?µµµÿÇÇÇÿÇÇÇÿÇÇÇÿH|Hÿ ` ÿ h ÿ m ÿ n ÿ n ÿ n ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ o ÿ h ÿ [ ÿ [ ÿ h ÿ l ÿ e ÿ [ ÿTÿ\ÿ V ÿ e ÿ i ÿ g ÿ e ÿ c ÿ ] ÿ W ÿCsCÿÇÇÇÿÇÇÇÿÇÇÇÿµ¶µÿ°°°A°°°°°°°°°ÂÀÀÀÿÈÈÈÿÈÈÈÿ“¨“ÿ [ ÿ f ÿ l ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ p ÿ n ÿ l ÿt¦tÿl•lÿ L ÿ ` ÿ ` ÿZÿjŒjÿ»É»ÿ«À«ÿ [ ÿ j ÿ k ÿ i ÿ h ÿ f ÿ b ÿ \ ÿ R ÿ’¦’ÿÈÈÈÿÈÈÈÿÀÀÀÿ°°°È°°°°°°°°°ûÉÉÉÿÉÉÉÿÉÉÉÿJJÿ e ÿ n ÿ s ÿ t ÿuÿuÿuÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ t ÿ s ÿ i ÿ b ÿ±Ì±ÿÔßÔÿEÿeÿ¢½¢ÿùúùÿÿÿÿÿëðëÿ&o&ÿ m ÿ r ÿ p ÿ o ÿ m ÿ k ÿ h ÿ b ÿ Z ÿEwEÿÉÉÉÿÉÉÉÿÉÉÉÿ°°°ü°°°°°°M¸¸¸ÿÉÉÉÿÉÉÉÿ¯º¯ÿbÿnÿvÿzÿ{ÿ{ÿzÿzÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿyÿuÿ s ÿvÿyÿyÿyÿyÿxÿ p ÿv£vÿ S ÿÔâÔÿûüûÿFÿ²Ê²ÿÿÿÿÿÿÿÿÿéîéÿ3r3ÿ b ÿ h ÿ n ÿsÿuÿ r ÿ p ÿ o ÿ j ÿ a ÿ U ÿ©µ©ÿÉÉÉÿÉÉÉÿ¸¸¸ÿ°°°P°°°©ÁÁÁÿÊÊÊÿÊÊÊÿq—qÿhÿtÿ|ÿ~ÿ~ÿ~ÿ~ÿ}ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ|ÿ w ÿ i ÿ d ÿ r ÿ|ÿ|ÿ|ÿ|ÿ v ÿW’WÿþþþÿJÿó÷óÿùûùÿ M ÿó÷óÿÿÿÿÿäêäÿ0e0ÿ L ÿJÿ O ÿ b ÿ t ÿyÿ w ÿ t ÿ r ÿ o ÿ f ÿ \ ÿjjÿÊÊÊÿÊÊÊÿÁÁÁÿ°°°«°°°ÛÇÇÇÿËËËÿËËËÿJ‚Jÿnÿyÿ€ÿÿÿÿ€ÿÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ~ÿ}ÿ(~(ÿ¥À¥ÿ S ÿ n ÿ~ÿ~ÿ~ÿzÿ7ƒ7ÿòöòÿöøöÿ L ÿ÷ú÷ÿÉÛÉÿ&l&ÿîôîÿµËµÿjjÿ¤·¤ÿçìçÿüýüÿ©Â©ÿ k ÿzÿ{ÿyÿwÿuÿsÿ k ÿ ` ÿBwBÿËËËÿËËËÿÇÇÇÿ°°°Ý°°°òÊÊÊÿËËËÿËËËÿ3x3ÿtÿÿ„ÿ…ÿ…ÿ„ÿƒÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ‚ÿ|ÿÇÛÇÿÞæÞÿ K ÿpÿ‚ÿ‚ÿ€ÿ } ÿÜçÜÿÿÿÿÿÛãÛÿ V ÿ¬Í¬ÿ{­{ÿZ—ZÿMMÿåíåÿÿÿÿÿÿÿÿÿÿÿÿÿÀÔÀÿwÿ}ÿ€ÿÿ~ÿ|ÿzÿwÿpÿ e ÿ)l)ÿËËËÿËËËÿÊÊÊÿ°°°ó°°°ýÌÌÌÿÌÌÌÿÌÌÌÿ q ÿxÿƒÿˆÿ‰ÿˆÿ‡ÿ†ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ…ÿ„ÿ[¡[ÿÿÿÿÿîòîÿ K ÿrÿ…ÿ…ÿ~ÿ¸Ò¸ÿÿÿÿÿÿÿÿÿ£¹£ÿ ^ ÿN”Nÿb¡bÿ0ƒ0ÿöúöÿÿÿÿÿÿÿÿÿÿÿÿÿ˜¾˜ÿzÿ‚ÿ…ÿ„ÿƒÿÿÿ}ÿzÿtÿ i ÿcÿÌÌÌÿÌÌÌÿÌÌÌÿ°°°ý°°°ÿÍÍÍÿÍÍÍÿÍÍÍÿpÿ~ÿ‰ÿŽÿŽÿŽÿÿ‹ÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿŠÿ†ÿÇÞÇÿÿÿÿÿ÷ù÷ÿ M ÿvÿŠÿŠÿX£XÿÿÿÿÿÿÿÿÿÿÿÿÿU†UÿQQÿ~³~ÿ}¸}ÿp³pÿz¹zÿêôêÿÑåÑÿZ¤Zÿ‚ÿˆÿŠÿŠÿ‰ÿˆÿ‡ÿ…ÿ‚ÿÿyÿnÿbÿÍÍÍÿÍÍÍÿÍÍÍÿ°°°þ°°°ÿÎÎÎÿÎÎÎÿÎÎÎÿqÿÿŒÿ‘ÿ‘ÿÿÿÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿŒÿ3•3ÿÿÿÿÿÿÿÿÿùúùÿ M ÿwÿŒÿŒÿÍãÍÿÿÿÿÿÿÿÿÿ¸Ê¸ÿG„Gÿ’¼’ÿ|ÿ‰ÿŒÿŠÿƒÿ|ÿyÿyÿ|ÿÿƒÿ†ÿ‰ÿ‰ÿ‡ÿ…ÿƒÿ|ÿqÿ a ÿÎÎÎÿÎÎÎÿÎÎÎÿ°°°ÿ°°°ÿÏÏÏÿÏÏÏÿÏÏÏÿsÿ„ÿŽÿ”ÿ“ÿ“ÿ’ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€»€ÿÿÿÿÿÿÿÿÿþþþÿ P ÿvÿƒÿƒÿóøóÿÿÿÿÿíòíÿK€Kÿ¾Õ¾ÿ}ÿ‰ÿŽÿŠÿ}ÿiÿ Y ÿ Q ÿ S ÿ Y ÿ ` ÿnÿ~ÿ‹ÿŒÿŠÿˆÿ†ÿ~ÿsÿ b ÿÏÏÏÿÏÏÏÿÏÏÏÿ°°°ÿ°°°ÿÏÏÏÿÏÏÏÿÏÏÏÿvÿ‡ÿ’ÿ˜ÿ—ÿ—ÿ–ÿ”ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ“ÿ¼Û¼ÿÿÿÿÿÿÿÿÿùúùÿ S ÿkÿgÿkÿ¥Ï¥ÿïöïÿsŸsÿÖäÖÿ*†*ÿ‰ÿÿ†ÿwÿiœiÿÝæÝÿúûúÿçìçÿË×Ëÿ¤¼¤ÿz¤zÿGŽGÿÿÿÿŽÿŒÿŠÿ‚ÿvÿeÿÏÏÏÿÏÏÏÿÏÏÏÿ°°°ÿ°°°ÿÐÐÐÿÐÐÐÿÐÐÐÿyÿ‹ÿ–ÿ œ ÿ›ÿ›ÿ™ÿ˜ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿ—ÿéóéÿÿÿÿÿÿÿÿÿæìæÿ_ÿ¾Ó¾ÿ¾Ð¾ÿ X ÿyÿáîáÿãìãÿ;ƒ;ÿyÿ~ÿvÿ(x(ÿ½Ñ½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúüúÿ·×·ÿ?ž?ÿ‘ÿ•ÿ”ÿ’ÿÿŽÿ†ÿzÿhÿÐÐÐÿÐÐÐÿÐÐÐÿ°°°ÿ°°°ÿÑÑÑÿÑÑÑÿÑÑÑÿ{ÿ Ž ÿ"™"ÿ#Ÿ#ÿ"ž"ÿ ž ÿœÿ›ÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿšÿüþüÿÿÿÿÿÿÿÿÿµÉµÿ™¼™ÿÿÿÿÿúûúÿ V ÿB‰BÿñöñÿO‘Oÿqÿ y ÿCCÿºÿ÷ù÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝìÝÿ„À„ÿ*™*ÿ–ÿ™ÿšÿ™ÿ—ÿ•ÿ“ÿÿ‰ÿ|ÿjÿÑÑÑÿÑÑÑÿÑÑÑÿ°°°ÿ°°°ÿÒÒÒÿÒÒÒÿÒÒÒÿ}ÿ!!ÿ#›#ÿ$¡$ÿ# #ÿ!Ÿ!ÿžÿÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿœÿêõêÿÿÿÿÿÿÿÿÿh™hÿëóëÿÿÿÿÿØãØÿFFÿîôîÿ‘¾‘ÿ´Ö´ÿéòéÿëóëÿåðåÿûýûÿñøñÿØëØÿ¦Ò¦ÿm¸mÿ1Ÿ1ÿ™ÿ›ÿœÿœÿœÿœÿ›ÿ™ÿ–ÿ•ÿ’ÿ‹ÿ~ÿlÿÒÒÒÿÒÒÒÿÒÒÒÿ°°°ÿ°°°ÿÓÓÓÿÓÓÓÿÓÓÓÿ € ÿ#’#ÿ%Ÿ%ÿ&¤&ÿ%¤%ÿ#£#ÿ ¢ ÿ¡ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿžÿ˜ÿŽÿÿ“ÿ¯Ù¯ÿÿÿÿÿíóíÿyÿÄáÄÿûýûÿ…®…ÿïõïÿb¢bÿxÿnÿaÿ_ÿuÿ“ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿŸÿÿ›ÿ˜ÿ–ÿÿÿoÿÓÓÓÿÓÓÓÿÓÓÓÿ°°°ÿ°°°ÿÓÓÓÿÓÓÓÿÓÓÓÿ!‚"ÿ%•%ÿ'¢(ÿ(§)ÿ'§(ÿ%¦&ÿ"¥#ÿ ¤!ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ¡ÿ–ÿ~ÿhÿbÿxÿ[¬\ÿÿÿÿÿe eÿˆÿS¨Sÿ–À–ÿïõïÿ_£`ÿ''ÿµÿÞçÞÿùûùÿ—±—ÿhÿ’ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ£ÿ¢ÿ ÿžÿ›ÿ™ÿ‘ÿ„ÿpÿÓÓÓÿÓÓÓÿÓÓÓÿ°°°ÿ°°°ÿÔÔÔÿÔÔÔÿÔÔÔÿ#„#ÿ&—'ÿ)¤*ÿ*ª*ÿ)ª*ÿ'©(ÿ$¨%ÿ"§#ÿ ¦!ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿžÿ[¥\ÿÓáÓÿôöôÿ—±—ÿfÿƒ»ƒÿßìßÿxÿ…ÿ«Ï¬ÿîõïÿSŸSÿG›Hÿéñéÿÿÿÿÿÿÿÿÿÿÿÿÿðõðÿ~ÿœÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¦ ÿ¥ ÿ£ÿ¡ÿžÿœÿ“ÿ…ÿrÿÔÔÔÿÔÔÔÿÔÔÔÿ°°°ÿ°°°ÿÕÕÕÿÕÕÕÿÕÕÕÿ&Š&ÿ)š)ÿ*¥*ÿ+¬+ÿ+¬+ÿ)«)ÿ&ª&ÿ$©$ÿ"¨"ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ^´^ÿüýüÿÿÿÿÿÿÿÿÿòõòÿnÿÃÞÃÿƒ´ƒÿuÿ—Á—ÿåïåÿ@“@ÿŠÿæñæÿÿÿÿÿÿÿÿÿÿÿÿÿûýûÿq­qÿ•ÿ ¤ ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!¨!ÿ!§!ÿ ¥ ÿ £ ÿ ÿÿ•ÿ‡ÿtÿÕÕÕÿÕÕÕÿÕÕÕÿ°°°ÿ°°°ÿÖÖÖÿÖÖÖÿÖÖÖÿ(‘(ÿ,¥,ÿ.®.ÿ-°-ÿ,¯,ÿ+®+ÿ(­(ÿ&¬&ÿ$«$ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ×ì×ÿÿÿÿÿÿÿÿÿÿÿÿÿ³Î³ÿ&‰&ÿëôëÿ5€5ÿ¿Ö¿ÿÄÛÄÿ.‰.ÿ]¨]ÿ—È—ÿ×è×ÿþþþÿçðçÿ ¿ ÿ={=ÿvÿ”ÿ"¦"ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#«#ÿ#ª#ÿ"¨"ÿ"¦"ÿ!£!ÿ! !ÿ˜ÿŠÿvÿÖÖÖÿÖÖÖÿÖÖÖÿ°°°ÿ°°°ÿ×××ÿ×××ÿ×××ÿ*“*ÿ.©.ÿ1¸1ÿ3½3ÿ1·1ÿ.².ÿ+°+ÿ)¯)ÿ'®'ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿóúóÿÿÿÿÿÿÿÿÿëòëÿ:—:ÿa¯aÿ£É£ÿáìáÿ¥Ë¥ÿƒ¿ƒÿœÍœÿ`¦`ÿoÿ<|<ÿS‡Sÿ{¢{ÿçîçÿ†©†ÿKŽKÿ ‘ ÿ%©%ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&®&ÿ&­&ÿ%«%ÿ%©%ÿ$¦$ÿ$£$ÿ"›"ÿÿxÿ×××ÿ×××ÿ×××ÿ°°°ÿ°°°ÿØØØÿØØØÿØØØÿ,•,ÿ2«2ÿ5¹5ÿ7À7ÿ6À6ÿ4¾4ÿ1º1ÿ-³-ÿ+°+ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*¯*ÿÎÿûýûÿÓæÓÿB¡Bÿ#’#ÿµÕµÿðöðÿ—È—ÿm½mÿ4 4ÿ@“@ÿ®É®ÿóöóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðõðÿf®fÿ& &ÿ)­)ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*°*ÿ*¯*ÿ)­)ÿ)ª)ÿ(¨(ÿ'¥'ÿ%œ%ÿ"Ž"ÿyÿØØØÿØØØÿØØØÿ°°°ÿ°°°ÿØØØÿØØØÿØØØÿ/—/ÿ4­4ÿ8»8ÿ:Ã:ÿ9Ã9ÿ7Â7ÿ5Á5ÿ2Á2ÿ0¼0ÿ.¶.ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ,­,ÿ¦Ó¦ÿ~µ~ÿ#Œ#ÿ)”)ÿ¢Ë¢ÿçñçÿN©Nÿ*¦*ÿ( (ÿj¬jÿ÷ù÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùûùÿ¿Ü¿ÿa´aÿ9®9ÿ,¯,ÿ-±-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-²-ÿ-±-ÿ,¯,ÿ,¬,ÿ+ª+ÿ*§*ÿ(ž(ÿ%%ÿzÿØØØÿØØØÿØØØÿ°°°ÿ°°°ÿÙÙÙÿÙÙÙÿÙÙÙÿ2™2ÿ8¯8ÿ<½<ÿ>Å>ÿ=Å=ÿ;Ä;ÿ9Ã9ÿ6Ã6ÿ5Â5ÿ4Â4ÿ4À4ÿ2»2ÿ1¶1ÿ0´0ÿ0³0ÿ=­=ÿôùôÿ4…4ÿ3Œ3ÿÉàÉÿ¿Ü¿ÿ5ž5ÿ+ +ÿ(˜(ÿq­qÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿñ÷ñÿÓèÓÿ‹Ê‹ÿ9­9ÿ/°/ÿ0³0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0´0ÿ0³0ÿ/°/ÿ.®.ÿ.¬.ÿ-©-ÿ+ +ÿ&‘&ÿ"|"ÿÙÙÙÿÙÙÙÿÙÙÙÿ°°°ÿ°°°ÿÚÚÚÿÚÚÚÿÚÚÚÿ5œ5ÿ;³;ÿ@Á@ÿAÉAÿAÈAÿ?È?ÿ=Ç=ÿ:Ç:ÿ9Æ9ÿ8Æ8ÿ8Æ8ÿ8Æ8ÿ8Æ8ÿ7Â7ÿ4¹4ÿ–ΖÿºÖºÿ@†@ÿÞêÞÿ’¾’ÿ)‹)ÿ(Ž(ÿ(…(ÿ¯ÿúûúÿþþþÿõùõÿð÷ðÿ¯×¯ÿM«Mÿ- -ÿ.¢.ÿ.¢.ÿ0¨0ÿ2°2ÿ2±2ÿ1¯1ÿ1®1ÿ2°2ÿ3µ3ÿ4¸4ÿ4¸4ÿ4¸4ÿ4¸4ÿ4¸4ÿ4¸4ÿ4¸4ÿ4¸4ÿ4·4ÿ3´3ÿ2²2ÿ2¯2ÿ1¬1ÿ.¤.ÿ*”*ÿ$$ÿÚÚÚÿÚÚÚÿÚÚÚÿ°°°ÿ°°°ÿÛÛÛÿÛÛÛÿÛÛÛÿ8ž8ÿ@µ@ÿEÄEÿFÌFÿEËEÿDËDÿBÊBÿ?Ê?ÿ>É>ÿ=É=ÿ=É=ÿ=É=ÿ=É=ÿ=É=ÿ@¾@ÿëõëÿv«vÿäîäÿi¥iÿ$v$ÿF†Fÿ™¹™ÿáêáÿùûùÿíòíÿ¨Ç¨ÿ] ]ÿ,‹,ÿ*‹*ÿ(…(ÿ&|&ÿ#s#ÿ#r#ÿ&~&ÿ+Ž+ÿ,‘,ÿ+Œ+ÿ+Œ+ÿ/›/ÿ6±6ÿ9»9ÿ9»9ÿ9»9ÿ9»9ÿ9»9ÿ9»9ÿ9»9ÿ9»9ÿ9º9ÿ8·8ÿ7µ7ÿ6²6ÿ6°6ÿ3§3ÿ.—.ÿ''ÿÛÛÛÿÛÛÛÿÛÛÛÿ°°°ÿ°°°ÿÜÜÜÿÜÜÜÿÜÜÜÿ< <ÿD¸DÿIÇIÿLÏLÿJÎJÿIÎIÿFÍFÿDÍDÿCÌCÿBÌBÿBÌBÿBÌBÿBÌBÿ@Ç@ÿ‹Ï‹ÿÉáÉÿßíßÿ¶ß¶ÿóúóÿùüùÿ÷ú÷ÿãìãÿÆÖÆÿ—´—ÿj“jÿU†UÿJJÿb‘bÿ†¨†ÿ¬Ã¬ÿÏÛÏÿéîéÿ­Á­ÿ:n:ÿZŠZÿj—jÿy£yÿ}¬}ÿ0”0ÿ9³9ÿ=¾=ÿ=¾=ÿ=¾=ÿ=¾=ÿ=¾=ÿ=¾=ÿ=¾=ÿ=¾=ÿ=½=ÿ<º<ÿ;¸;ÿ:µ:ÿ9³9ÿ7©7ÿ1š1ÿ*ƒ*ÿÜÜÜÿÜÜÜÿÜÜÜÿ°°°ÿ°°°ÿÜÜÜÿÜÜÜÿÜÜÜÿ?¡@ÿG¹HÿMÈNÿOÐPÿOÐPÿMÐNÿKÏLÿHÏIÿGÎHÿFÎGÿFÎGÿFÎGÿEËFÿA»AÿÞïßÿÒçÒÿLµMÿCÆDÿsÙtÿÙóÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿªÑªÿ:ª;ÿ@»AÿA¿BÿA¿BÿA¿BÿA¿BÿA¿BÿA¿BÿA¿BÿA¿Bÿ@¾Aÿ@»Aÿ?¹@ÿ>¶?ÿ=³>ÿ9©:ÿ4™5ÿ-„-ÿÜÜÜÿÜÜÜÿÜÜÜÿ°°°ÿ°°°ÿÝÝÝÿÝÝÝÿÝÝÝÿB¢CÿJºKÿQËRÿTÓUÿSÓSÿQÓRÿOÒPÿMÒNÿKÑLÿJÑKÿJÑKÿIÏJÿDÁEÿ±Ý²ÿÑéÑÿG¶GÿHÊIÿJÐKÿJÑKÿJÑKÿsÚtÿ«æ«ÿÔñÔÿøýøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØìØÿ‚È‚ÿA·BÿD¿EÿEÂFÿEÂFÿEÂFÿEÂFÿEÂFÿEÂFÿEÂFÿEÂFÿEÁFÿDÀEÿD¾EÿC¼DÿB¹CÿA¶Bÿ=¬>ÿ7›8ÿ/„/ÿÝÝÝÿÝÝÝÿÝÝÝÿ°°°ÿ°°°ÿÞÞÞÿÞÞÞÿÞÞÞÿJ¤JÿQ¼QÿWÍWÿZÕZÿZ×ZÿY×YÿVÖVÿTÖTÿRÕRÿQÕQÿQÔQÿLÈLÿ†Í†ÿËçËÿK¼KÿNÎNÿQÕQÿQÕQÿQÕQÿQÕQÿQÕQÿQÕQÿQÕQÿRÕRÿ‡à‡ÿÂíÂÿç÷çÿùýùÿþÿþÿîøîÿÞòÞÿÊêÊÿ­ß­ÿ‹Ò‹ÿ^Ä^ÿIÁIÿKÅKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÆKÿKÅKÿJÄJÿJÂJÿIÀIÿG½GÿF¸FÿB¯Bÿ<<ÿ8‰8ÿÞÞÞÿÞÞÞÿÞÞÞÿ°°°þ°°°ýßßßÿßßßÿßßßÿT¦TÿT»Tÿ\Í\ÿ_×_ÿ_Ù_ÿ^Ù^ÿ\Ø\ÿYØYÿW×WÿWÖWÿRÎRÿxÈxÿÊçÊÿO¼OÿSÐSÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿV×VÿUÔUÿTÒTÿSÏSÿRÍRÿQÊQÿPÉPÿPÈPÿPÈPÿPÈPÿPÈPÿPÈPÿPÈPÿPÇPÿOÆOÿNÄNÿMÂMÿL¿LÿJºJÿF®Fÿ?œ?ÿAŒAÿßßßÿßßßÿßßßÿ°°°ý°°°òÞÞÞÿàààÿàààÿe¬eÿV¹Vÿ^Í^ÿbÙbÿdÜdÿbÜbÿ`Û`ÿ^Û^ÿ\Ú\ÿYÔYÿiÈiÿÓëÓÿT»TÿVÑVÿZÙZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÚZÿZÙZÿY×YÿXÖXÿXÔXÿWÒWÿVÑVÿVÐVÿTÍTÿSÊSÿRÆRÿPÂPÿM¼MÿH®HÿA›AÿR•RÿàààÿàààÿÞÞÞÿ°°°ó°°°ÚÙÙÙÿàààÿàààÿy³zÿX³YÿbÊcÿhØiÿjÝkÿiÞjÿgÞhÿeÝfÿaÛbÿ_É`ÿ×ì×ÿe»fÿZÍ[ÿ`Ûaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Üaÿ`Ûaÿ_Ù`ÿ^×_ÿ]Ô^ÿ[Ñ\ÿXÈXÿQ¹QÿF¢Gÿl¦lÿàààÿàààÿÙÙÙÿ°°°Ü°°°©ÐÐÐÿáááÿáááÿ™Á™ÿY­YÿdÆdÿl×lÿpÞpÿpápÿnánÿkàkÿeÖeÿºáºÿÅÿYÀYÿdÜdÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfßfÿfÞfÿeÜeÿdÚdÿb×bÿ`Ò`ÿ\È\ÿSµSÿF›Fÿ¹ÿáááÿáááÿÑÑÑÿ°°°«°°°K¿¿¿ÿâââÿâââÿÍÙÍÿZ¥Zÿd¾eÿmÒnÿsßsÿtâuÿsãtÿqârÿ…׆ÿâïâÿJ›Kÿ_Ç`ÿjàkÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjákÿjàkÿißjÿhÝiÿhÜhÿfØgÿcÒcÿ\Ã]ÿR­RÿE‘EÿÇÕÈÿâââÿâââÿ¿¿¿ÿ°°°O°°°°°°úáááÿâââÿâââÿ„·„ÿc´cÿoËoÿwÛwÿ{ã{ÿzåzÿyåyÿÐîÐÿ¶Ó¶ÿIIÿbÄbÿqáqÿrärÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqäqÿqãqÿpâpÿoàoÿnÝnÿlÙlÿfÎfÿ^¼^ÿQ£Qÿw«wÿâââÿâââÿáááÿ°°°ü°°°°°°°°°ÀÑÑÑÿãããÿãããÿºÑºÿ`¨`ÿmÂmÿwÖwÿ}â}ÿçÿèÿûþûÿèóèÿd¬dÿiËiÿuãuÿwçwÿwçwÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvævÿuäuÿtátÿrßrÿn×nÿfÈfÿ[²[ÿM—Mÿ¶Í¶ÿãããÿãããÿÑÑÑÿ°°°Ç°°°°°°°°°:»¼»ÿäääÿäääÿäääÿ†¸†ÿi´iÿvËvÿ~Ü~ÿƒæƒÿ„é„ÿÖöÖÿçøçÿ‡Û‡ÿzázÿ~è~ÿ}é}ÿ|é|ÿ|é|ÿ|é|ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{é{ÿ{è{ÿzæzÿxâxÿtÝtÿnÐnÿd½dÿV¤Vÿz¬zÿäääÿäääÿäääÿ¼½¼ÿ°°°>°°°°°°°°°°°°ßÓÓÓÿäääÿäääÿÈ×Èÿf¦fÿq¼qÿ|Ñ|ÿ…à…ÿ‰è‰ÿ‰ì‰ÿˆìˆÿ‡í‡ÿ†í†ÿ…í…ÿ„ì„ÿƒìƒÿ‚ì‚ÿ‚ì‚ÿ‚ì‚ÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿìÿ€ê€ÿ~æ~ÿ{á{ÿuÖuÿlÅlÿ`®`ÿS•SÿÄÓÄÿäääÿäääÿÓÓÓÿ°°°Þ°°°°°°°°°°°°°°°A½¾½ÿåååÿåååÿåååÿ¦Æ¦ÿi©iÿwÁwÿÔÿ‰â‰ÿêÿŽíŽÿîÿïÿŒïŒÿŠïŠÿŠïŠÿ‰î‰ÿˆîˆÿˆîˆÿˆîˆÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ‡î‡ÿ†î†ÿ„ì„ÿ„ê„ÿäÿ{Ú{ÿqÉqÿe´eÿVšVÿ¿ÿåååÿåååÿåååÿ½¾½ÿ°°°C°°°°°°°°°°°°°°°°°°ÀÉÉÉÿæææÿæææÿæææÿ˜¿˜ÿm¬mÿyÂyÿ„Õ„ÿ‹â‹ÿêÿ‘î‘ÿ‘ð‘ÿ‘ñ‘ÿñÿñÿñÿŽñŽÿŽðŽÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿðÿŒðŒÿŒðŒÿŒðŒÿŒðŒÿ‹ð‹ÿ‰ï‰ÿ‡ì‡ÿ„å„ÿ}Û}ÿuÌuÿi¶iÿ[ž[ÿ·ÿæææÿæææÿæææÿÊÊÊÿ°°°Ã°°°°°°°°°°°°°°°°°°°°°°°°öÔÔÔÿæææÿæææÿæææÿ’¼’ÿn¬nÿ{Â{ÿ…Ó…ÿŒàŒÿ‘é‘ÿ•î•ÿ•ñ•ÿ•ó•ÿ•ô•ÿ•ô•ÿ”ô”ÿ”ô”ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ“ó“ÿ’ó’ÿ’ó’ÿ’ó’ÿòÿŽðŽÿŒíŒÿ‡æ‡ÿ€Ú€ÿxËxÿk¸kÿ]Ÿ]ÿˆ²ˆÿæææÿæææÿæææÿÕÕÕÿ°°°ö°°°°°°°°°°°°°°°°°°°°°°°°°°°C°°°þßßßÿçççÿçççÿçççÿœÀœÿp©pÿ{»{ÿ…Ì…ÿŒØŒÿ’â’ÿ•ê•ÿ˜í˜ÿ™ð™ÿ™ò™ÿšóšÿ™ô™ÿ™ô™ÿšõšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿšôšÿ™ô™ÿ™ô™ÿ˜ó˜ÿ˜ó˜ÿ—ò—ÿ–ñ–ÿ•ï•ÿ’ì’ÿŽèŽÿ‰à‰ÿÓÿyÅyÿl±lÿ`œ`ÿ“¸“ÿçççÿçççÿçççÿßßßÿ°°°þ°°°H°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°sÆÇÆÿäääÿçççÿçççÿçççÿ«È«ÿo¤oÿw²wÿ€Â€ÿˆÏˆÿŽÙŽÿ‘à‘ÿ•æ•ÿ–é–ÿ—ë—ÿ˜ì˜ÿ˜í˜ÿ™î™ÿ™î™ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ˜î˜ÿ–í–ÿ–ì–ÿ•ë•ÿ’é’ÿåÿŒàŒÿ†Ö†ÿ~Ë~ÿt¼tÿi©iÿ_™_ÿ¥Â¥ÿçççÿçççÿçççÿåååÿÆÇÆÿ°°°s°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ŠÆÇÆÿàààÿèèèÿèèèÿèèèÿÏÜÏÿ‘¸‘ÿq¦qÿx³xÿÀÿ†É†ÿŠÑŠÿÖÿÚÿÛÿÜÿ‘Þ‘ÿ‘Þ‘ÿ‘Þ‘ÿ‘Þ‘ÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿÞÿŽÛŽÿŽÚŽÿ‹Ø‹ÿˆÔˆÿƒÎƒÿ~Æ~ÿw»wÿm¬mÿccÿˆ±ˆÿÌÙÌÿèèèÿèèèÿèèèÿáááÿÆÇÆÿ°°°Œ°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°q°°°þÖÖÖÿèèèÿèèèÿèèèÿèèèÿÅÖÅÿ”¹”ÿq¤qÿuªuÿz²zÿ}¹}ÿ€½€ÿÀÿ‚‚ÿ‚‚ÿ‚‚ÿ‚‚ÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿÂÿ€Á€ÿ~¾~ÿ{»{ÿx¶xÿs¯sÿl¥lÿffÿ³ÿÂÓÂÿèèèÿèèèÿèèèÿèèèÿÖÖÖÿ°°°þ°°°t°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°E°°°öËËËÿéééÿéééÿéééÿéééÿéééÿØàØÿ«Ç«ÿ¶ÿ€¬€ÿu¤uÿq¡qÿllÿllÿllÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkžkÿkkÿkœkÿkœkÿi›iÿmŸmÿq¡qÿ|¨|ÿ³ÿ¨Ä¨ÿÖßÖÿéééÿéééÿéééÿéééÿéééÿËËËÿ°°°ö°°°E°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°À¾¿¾ÿÖÖÖÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿÖÖÖÿ¾¿¾ÿ°°°Á°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°C°°°Ü½½½ÿÕÕÕÿéééÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿéééÿÖÖÖÿ½¾½ÿ°°°Ü°°°C°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°:°°°Á°°°úÂÂÂÿÖÖÖÿâââÿçççÿéééÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿéééÿçççÿâââÿ×××ÿÂÂÂÿ°°°ú°°°Â°°°<°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°M°°°©°°°Ú°°°ò°°°ü°°°þ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°þ°°°ü°°°ò°°°Ú°°°ª°°°M°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°ÿþÿÿøÿÿàÿÿ€ÿÿÿþü?øðààÀÀ€€€€€€ÀÀààðøü?þÿÿÿ€ÿÿàÿÿøÿÿÿÿÿ( @ °°°°°°°°°°°°–°°°à°°°ú°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ú°°°à°°°”°°°°°°°°°°°°°°°§°°°ý¹¹¹ÿÀÀÀÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÀÀÀÿ¹¹¹ÿ°°°ý°°°¦°°°°°°°°°°°°#°°°î¸¸¸ÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿÂÂÂÿ¸¸¸ÿ°°°ì°°°!°°°°°°°°°°°°÷ºººÿÃÃÃÿÃÃÃÿ£¯£ÿN{Nÿ"`"ÿVÿ S ÿ S ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿ R ÿTÿ!^!ÿNxNÿ¢®¢ÿÃÃÃÿÃÃÃÿºººÿ°°°ö°°°°°°°°°°°°è»»»ÿÅÅÅÿÅÅÅÿTTÿ Y ÿ [ ÿ Z ÿ Z ÿ Z ÿ Z ÿ Z ÿ Z ÿ Z ÿ Z ÿ Z ÿ Z ÿ Y ÿ Y ÿ X ÿ X ÿ U ÿ O ÿNvNÿÀÀÀÿÅÅÅÿ»»»ÿ°°°ç°°°°°°°°°©ºººÿÆÆÆÿÆÆÆÿH|Hÿ ` ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ a ÿ ^ ÿ \ ÿ Z ÿ P ÿFÿ I ÿ@p@ÿÆÆÆÿÆÆÆÿ¹¹¹ÿ°°°§°°°°°°ýÇÇÇÿÇÇÇÿ\‰\ÿ h ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ j ÿ b ÿ Y ÿaÿ‚£‚ÿŸ¶Ÿÿ Q ÿ [ ÿW„WÿÇÇÇÿÇÇÇÿ°°°ý°°°°°°—¼¼¼ÿÈÈÈÿ¤³¤ÿ h ÿ p ÿ p ÿ p ÿ p ÿ q ÿ q ÿ q ÿ q ÿ q ÿ n ÿ l ÿ o ÿ q ÿ o ÿ m ÿ›¿›ÿ U ÿÎÝÎÿìñìÿ9m9ÿ Y ÿ c ÿ ^ ÿ¥²¥ÿÈÈÈÿ¼¼¼ÿ°°°‡°°°âÇÇÇÿÊÊÊÿO‡Oÿxÿ{ÿ{ÿzÿzÿzÿzÿzÿzÿwÿ k ÿ e ÿ q ÿyÿ o ÿ h ÿíôíÿ \ ÿâëâÿUUÿ M ÿ _ ÿ k ÿ j ÿS„SÿÊÊÊÿÆÆÆÿ°°°Ü°°°ûËËËÿËËËÿ&x&ÿ‚ÿ‚ÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ"ƒ"ÿŒ´Œÿ W ÿ p ÿzÿ}­}ÿ [ ÿ¡Ä¡ÿcžcÿºÐºÿîóîÿ˜¼˜ÿ n ÿvÿtÿ!l!ÿËËËÿÊÊÊÿ°°°ú°°°ÿÍÍÍÿÍÍÍÿxÿ‹ÿŠÿ‰ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿ‡ÿv²vÿñõñÿ M ÿ m ÿ<<ÿïôïÿ Y ÿ[[ÿÛêÛÿêòêÿb›bÿ m ÿxÿ|ÿ{ÿiÿÍÍÍÿÍÍÍÿ°°°ÿ°°°ÿÎÎÎÿÎÎÎÿ|ÿ‘ÿ‘ÿÿÿÿÿÿÿÿÈàÈÿüýüÿ H ÿ c ÿÚéÚÿ»Ò»ÿNŠNÿtÿiÿ ] ÿ Z ÿdÿtÿÿÿlÿÎÎÎÿÎÎÎÿ°°°ÿ°°°ÿÐÐÐÿÐÐÐÿƒÿ™ÿ˜ÿ–ÿ”ÿ”ÿ”ÿ”ÿ”ÿ“ÿóøóÿöùöÿ¯Æ¯ÿfÿæðæÿrªrÿ>Š>ÿCŒCÿØæØÿûüûÿêòêÿÀÿ''ÿŠÿ‰ÿrÿÐÐÐÿÐÐÐÿ°°°ÿ°°°ÿÑÑÑÿÑÑÑÿˆÿ#Ÿ#ÿ ž ÿœÿšÿšÿšÿ˜ÿÿ‹ÿüýüÿÄÜÄÿÒäÒÿuÿ——ÿ‘¾‘ÿËâËÿ÷û÷ÿâðâÿšËšÿ44ÿ”ÿ—ÿ”ÿÿwÿÑÑÑÿÑÑÑÿ°°°ÿ°°°ÿÓÓÓÿÓÓÓÿ"Ž#ÿ&¥'ÿ#¤$ÿ£ ÿ¡ÿ¡ÿ¡ÿ–ÿ|ÿFGÿÃÝÃÿN¥Nÿa®aÿl­mÿh hÿcÿuÿ”ÿ¡ÿ¡ÿ¡ÿ ÿžÿ›ÿ–ÿ|ÿÓÓÓÿÓÓÓÿ°°°ÿ°°°ÿÕÕÕÿÕÕÕÿ'’'ÿ+«+ÿ)ª)ÿ%©%ÿ"§"ÿ!§!ÿ!§!ÿ€Ã€ÿæïæÿx¥xÿ)…)ÿÿÄÿ““ÿÔãÔÿßéßÿoÿÿ ¤ ÿ!§!ÿ!§!ÿ!¦!ÿ ¤ ÿ   ÿœÿÿÕÕÕÿÕÕÕÿ°°°ÿ°°°ÿÖÖÖÿÖÖÖÿ*™*ÿ/°/ÿ-¯-ÿ)®)ÿ&¬&ÿ%¬%ÿ%¬%ÿëöëÿâîâÿm£mÿ ƒ ÿ“Ç“ÿU¥Uÿãïãÿæïæÿy¥yÿoÿÿ$¥$ÿ%¬%ÿ%¬%ÿ%«%ÿ$©$ÿ$¥$ÿ#¡#ÿ„ÿÖÖÖÿÖÖÖÿ°°°ÿ°°°ÿØØØÿØØØÿ2¥2ÿ8¿8ÿ4¹4ÿ0´0ÿ-²-ÿ,²,ÿ,±,ÿÖíÖÿºÙºÿO—Oÿ¨Î¨ÿ`©`ÿW Wÿ°ÿ·Ò·ÿâíâÿ—Ç—ÿ'ž'ÿ+¯+ÿ,²,ÿ,²,ÿ,±,ÿ+¯+ÿ*«*ÿ)¦)ÿ"‰"ÿØØØÿØØØÿ°°°ÿ°°°ÿÚÚÚÿÚÚÚÿ8ª8ÿ?È?ÿ>Ç>ÿ9Ä9ÿ5½5ÿ3¹3ÿ0±0ÿ”Δÿy·yÿœÇœÿ.ƒ.ÿg¢gÿíôíÿÿÿÿÿáìáÿºÿ.˜.ÿ-£-ÿ/¬/ÿ1´1ÿ2·2ÿ2¶2ÿ1´1ÿ0°0ÿ/«/ÿ&&ÿÚÚÚÿÚÚÚÿ°°°ÿ°°°ÿÛÛÛÿÛÛÛÿ@®@ÿIÍIÿGÍGÿDÌDÿAËAÿ?É?ÿTÁTÿ±Û±ÿ¥Ó¥ÿ¥Ó¥ÿÆàÆÿÃØÃÿ¯ÿE|Eÿ h ÿ$r$ÿ((ÿ--ÿ3¥3ÿ9·9ÿ;½;ÿ;¼;ÿ:º:ÿ9¶9ÿ7¯7ÿ.’.ÿÛÛÛÿÛÛÛÿ°°°ÿ°°°ÿÝÝÝÿÝÝÝÿG±GÿQÐQÿQÒQÿMÑMÿIÎIÿEÅEÿ¦ß¦ÿtÌtÿtÒtÿ³æ³ÿÔíÔÿæòæÿéñéÿñõñÿ÷ú÷ÿ¾Ö¾ÿÀÛÀÿˆÃˆÿ>°>ÿC¾CÿDÁDÿDÀDÿC¾CÿA¹Aÿ?²?ÿ3’3ÿÝÝÝÿÝÝÝÿ°°°ÿ°°°ÿÞÞÞÿÞÞÞÿP¯Pÿ\Ô\ÿ\Ù\ÿY×YÿRÍRÿ…Õ…ÿmÎmÿQÏQÿSÕSÿT×Tÿ¤è¤ÿæ÷æÿûþûÿõûõÿàòàÿÀåÀÿ‹Ð‹ÿN¾NÿMÅMÿNÈNÿNÈNÿNÇNÿMÅMÿKÀKÿG¶Gÿ=“=ÿÞÞÞÿÞÞÞÿ°°°ÿ°°°ûßßßÿàààÿ^©^ÿcÏcÿhÝhÿbÕbÿŠ×ŠÿuÍuÿZÐZÿ^Ù^ÿ_Û_ÿ_Û_ÿ_Û_ÿ_Û_ÿ_Û_ÿ_Û_ÿ_Û_ÿ_Û_ÿ_Û_ÿ^Ø^ÿ]Ö]ÿ\Ó\ÿ[Ò[ÿZÏZÿXËXÿVÆVÿM²MÿKKÿàààÿßßßÿ°°°ú°°°âÛÛÛÿáááÿz®zÿeÃeÿrßrÿØÿ’Ò’ÿ_È_ÿhÝhÿjájÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿiáiÿhßhÿgÝgÿcÔcÿT´Tÿw¨wÿáááÿÚÚÚÿ°°°Ü°°°—ÉÉÉÿãããÿÄÔÄÿ^§^ÿuÓuÿÃìÃÿhÁhÿnÓnÿxæxÿwçwÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿvçvÿuçuÿtåtÿqßqÿeÇeÿL—LÿÂÑÂÿãããÿÉÉÉÿ°°°ˆ°°°°°°ýäääÿäääÿƒ­ƒÿi°iÿæöæÿ…Ü…ÿƒåƒÿ„ë„ÿƒìƒÿƒëƒÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿ‚ë‚ÿëÿ€ë€ÿ}å}ÿpÎpÿX¢Xÿz¤zÿäääÿäääÿ°°°ý°°°°°°°°°ªÇÇÇÿåååÿåååÿ}¨}ÿm­mÿÎÿ‰á‰ÿêÿïÿñÿñÿñÿŽñŽÿŽñŽÿŽñŽÿŽñŽÿŽñŽÿŽñŽÿŽðŽÿŒîŒÿˆéˆÿ€ß€ÿsÈsÿ]¢]ÿržrÿåååÿåååÿÇÇÇÿ°°°¨°°°°°°°°°îÏÏÏÿæææÿæææÿ‡¬ˆÿd—dÿs±tÿ~Ä~ÿ‚̓ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿƒÐ„ÿÏ‚ÿ~ÌÿwÁxÿi¬jÿUUÿ€¦ÿæææÿæææÿÍÍÍÿ°°°í°°°°°°°°°°°°(°°°÷ÏÏÏÿèèèÿèèèÿËØËÿ‡ª‡ÿh”hÿ_Œ_ÿ\Š\ÿ\‰\ÿ[‰[ÿ[‰[ÿ[‰[ÿ[‰[ÿ[‰[ÿ[‰[ÿZˆZÿZˆZÿ[‰[ÿccÿ€¤€ÿÉÖÉÿèèèÿèèèÿÏÏÏÿ°°°÷°°°!°°°°°°°°°°°°#°°°îÉÉÉÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿÈÈÈÿ°°°í°°°#°°°°°°°°°°°°°°°°°°°°°°°°°°°©°°°ýÌÌÌÿâââÿèèèÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿéééÿèèèÿâââÿËËËÿ°°°ý°°°¨°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°–°°°á°°°ú°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ú°°°á°°°–°°°°°°°°°°°°°°°°°°°°°ü?ðàÀ€€€€Ààðü?(  °°°.°°°Ê°°°ù°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ù°°°Ê°°°&°°°e°°°þ»»»ÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿÃÃÃÿ¾¾¾ÿ¸¸¸ÿ¶¶¶ÿ°°°ý°°°_°°°3°°°ýÂÂÂÿšÿ2o2ÿ\ÿ Z ÿ Z ÿ Y ÿ W ÿSÿ&U&ÿkkÿ²²²ÿ¬¬¬þ°°°*°°°Ð¿¿¿ÿ~œ~ÿ f ÿ j ÿ j ÿ j ÿ h ÿ ` ÿ ] ÿ»Ñ»ÿLÿFÿj‚jÿ¶¶¶ÿ°°°Ê°°°ûËËËÿ.y.ÿzÿ{ÿzÿxÿ n ÿa—aÿ]ÿÌÞÌÿßêßÿœ¼œÿ'b'ÿÃÃÃÿ°°°ù°°°ÿÎÎÎÿyÿŒÿŠÿŠÿ&‘&ÿw°wÿ”¶”ÿ,m,ÿ/|/ÿlÿjÿaÿÈÈÈÿ°°°ÿ°°°ÿÑÑÑÿ„ÿ™ÿ—ÿ’ÿH£Hÿåðåÿ¼Ó¼ÿ•¹•ÿ›Æ›ÿÑçÑÿk²kÿoÿÎÎÎÿ°°°ÿ°°°ÿÔÔÔÿ##ÿ$¦$ÿ¢ÿ“ÿV¢VÿºÖºÿÊÝÊÿoÿƒÿ›ÿžÿÿÔÔÔÿ°°°ÿ°°°ÿ×××ÿ-Ÿ-ÿ0´0ÿA³AÿµÜµÿ\¥\ÿ•¿•ÿ¹Ñ¹ÿ•»•ÿ„ÿ%Ÿ%ÿ'§'ÿ ‰ ÿ×××ÿ°°°ÿ°°°ÿÚÚÚÿ;©;ÿ@Æ@ÿaËaÿªÝªÿçôçÿêõêÿ³Ö³ÿM˜Mÿ+Ž+ÿ2¤2ÿ4­4ÿ++ÿÚÚÚÿ°°°ÿ°°°ÿÝÝÝÿJ§JÿTÈTÿ×ÿbÎbÿOÏOÿ æ ÿâõâÿÎìÎÿˆÑˆÿH¼HÿF¶Fÿ99ÿÝÝÝÿ°°°ÿ°°°ûßßßÿa¡aÿ{Æ{ÿlËlÿeÕeÿißiÿhàhÿhàhÿhàhÿgÝgÿcÕcÿT¶TÿX˜Xÿßßßÿ°°°ú°°°ÐÐÐÐÿ¡¾¡ÿ—½—ÿe±eÿlÁlÿnÇnÿmÇmÿmÇmÿmÆmÿjÂjÿ^°^ÿKKÿŸ¼ŸÿÎÎÎÿ°°°Ê°°°5°°°þÜÜÜÿ¨Á¨ÿi•iÿX‡XÿU†UÿU…UÿU…UÿT…TÿT„Tÿbbÿ£½£ÿÜÜÜÿ°°°þ°°°,°°°k°°°þÒÒÒÿçççÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿçççÿÒÒÒÿ°°°ý°°°j°°°0°°°Ð°°°û°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ÿ°°°ú°°°Í°°°0À€€À‰PNG  IHDR\r¨f IDATxœì}wœEÚÿ·:LÚœwÙ]–° ¬ ¢ åÐDï &<¾Ê©ïÞW§ç©w'ŠŠùô”3+zÆPÀ" ¢dØ%í²9Lê®ßÕ¡ºgfg6̲°óôÖ§§««{»«ëyêÉE(¥H@Ð3A8Ò€$àÈA‚$ =  èÁ H@†H@z0$@Ѓ!A€ €ô`H€$ C‚$ =¤h !]ñG+Ûob«³·I@ÛÀî§N¹©M4ˆÅÍ?*H€ÈˆNÀ¸(}î˜' "Ðv Ü^/ªV§rÇ ÂÐnè0Xºtigúèþ—^zé 1й½U„ AZVf{ €¼xñâ‹srrn”$©´¨¨ˆäççÃáp©ÇM@œÁï÷ãÀ(//§Á`p[eeåÃ×]wÝË09ƒ£Š+H€0ñu_ž0aBú•W^ùg·Û=#77ןŸ”””#ö¬ 82ÐÐЀàСC----o?÷Üsw,_¾¼ŒØˆÝ–$­ ¾cÞ¼yýÆŽûW—Ë5®°°P,..† $!{:¨ªŠ½{÷¢¢¢Bñz½«V¯^}Ë¢E‹vðã(   †ü!ˆõÕW—L˜0á §ÓyjII éÕ«WÂ$—€ ”bß¾}ؽ{7õù|_-_¾|îÓO?½aAw"=žp³¾a¾ _xá…y^xá“.—ëW½{÷&EEEGî!pTAyy9öìÙC½^ïª7Þxãš7Þxã L=nNìÜ@%a´ú9==ݵhÑ¢û“““/-..{÷î÷g©÷×£Ú[Ú–ZÔxkÐèk„7à…7à…/èƒ?à‡BB ¨JÄ{­Ü ÁóÖ2Ö¨uOY’A)…HD8dœ’.‡ nÉdg22ÜÈpg Ë•…Tgjç¿„ öìÙƒ½{÷*/Λ7ïöÚÚZ/¬„àˆ[ z$ÃîËœ‹-º ¨¨èoÉ}ûö 2j>„]µ»PÙT‰êÆjÔ´Ô  ˜Þ~˜nAûׂ °ANl}ÙʣłLÝb|tþù1H)5îaJ ¨Š ªš‚²$#Ó“‰ìälä$ç _f?äyò:ë-,ϳsçNìß¿¿©¼¼ü–yóæ½ÀSYxDÅ‚El³¾nÎs̘1#ïâ‹/~¹  `x~~>ÒÒÒ:õÿn©Þ‚퇷£¼¦ÞF¢"ææ+ã7›ÉŒ>Ó‘ž 2Îé3_JpTA5]õTÕÞ™²Á«RÕè'ª2Äe„ª”Õ)š»pPAŠ+%Y%(Í.ÅñÙÇwê³Ö××cÿýØ¿oÿw/¿üòÅo¿ýöA0ýo>ìrn Ç€0³¾€ã©§žº>''çÿIÉîo©Ù‚ŸýŒŠš øU?Q`EØ,/šÈOb"?7Û¡€ŽäG+Û D_aÅ€!½V§·Ñg~J5¤‡jrŠITÅ,² £$«eye(Ë*ë´÷Ù³gÊË˃•••÷^sÍ5‹Àˆ€®(ìrnà˜'ad}€ã´ÓNËúÝï~÷Fqqñ‰p»Ýþ_UÞ*l8ðvTî@KÀ Q@D¢!¿hþ&D@€ ñ-ȯYõz –íÄðpôó1[ŽðG¸½ªRPUe{E…B5¢ 0n@Q¨Š % Â#¹10 Fô‰ON‡ßÆëõbß¾}Ø»wï†GyäÂ/¾øâ0 ‹uÇ4°iø YÿÁ<·´´ô‰ÂÂBWIII‡ÿχÀÆýq°îDIÔ,¢OÙ^”4Ö_Bâ Œ€Pƒ 4Ķq‘ˆ­õ÷Ñ.ÄÄ Àt}€~^UUPPP P•qŠª2B qJýVjPP *J0%¨ Wz!N.:'äžÐá÷Ù½{7***¼Û¶m›{ë­·¾«n K,Ç,°±üËïzá…HKK»lРA$##£Cÿã«ý_á‡ý? Î[I’ H‚F’Vž àd~‰róÊ?„cÿ;Êòk º2¤£ÔvªªõºÀäT¨T5ôú̯j„@ jVÔ€Š` ˆtw:† ÇØâ±zöššlÙ²…ÖÕÕýóòË/¿ €¦n î"Á1I8ä×g}Ç!CÒçÏŸÿ~qqqYG5ü_îû›*6¡)ÐI–@DQÙŒ/3"&1àdàgx»ì¯ÿ¦ &`Ÿú¹Ã£}fï0ÐðV»8Às†E€ªl¯q†.@#Á`P€`0% E 2BìHƈÞ#pZïÓÚÿøš¥`ïÞ½?Þ}÷ÝS6oÞ\ S$PG"pÌ ùy-¿kîܹƒ'MšôaaaaJŸ>}Ú}ï¯|Íû6£Þ[Ï^Ò^ûMDÂ8Q‘˜f_' ¢` ½®Ý·˜ýˆ.ü#æì€=‰D}WÛi^ s °pªjU5¹SЈA ¤1Ð÷J@Aš+ 'ŸÜ!Ž`×®]Ø·o_ÃÇ|öO<ñ7`X âAŽ`SöIÐäý»ï¾{âСC_ìÓ§Ô«W¯vÝû§Ã?aà 8Pw‚,0$ç_”#³ýúì®»©Ïnöã³Úû.l_’žEÛû†Aøcʉ Ԭ׉€N 2ÝL¨gÒ-JМýí èBñ+(Î,ÆÈ¢‘š;´]ï¶oß>ìÚµ+¸iÓ¦KçÏŸ¿ ¦^@ :U/pL€0Ê>×¢E‹®*..¾gàÀBVVV»î½l÷2l,ßIf2¾$K›/Ê¢)÷KæloÌúÚì®#¹>ë¿a“õ[‘÷)éYH bÒ_pH®C8ó ¡à­*5uj¨y0šz¿&h¿ƒ~¦( úƒ8¥Ï)˜2`J»ÞñðáÃøå—_Ôòòòù7ÜpÃS0õ®<ê @äw?ùä“·9aÈ-ù¹ùHJJjó}<ü#VîX Ÿâƒè`3½äج¯!¾ 1.@4¹_„‘ÇϘíE›‰/œ­_ ›~¸>£4º '@[D»^À¢(T©…+°è4Ž€*ŒXü4äWŠßÆ hD@/.Ñ…³ŸÝ.‹Ass3öÜÍ7ÿõÚk¯}@ â@Žjù<Ï<óÌ]eÇ—Í-*,jW‚Žÿìú6ïÛÌÝ¡!¾¤±û1ñÝÞ¯'ñ˜_gýu[O€È6~»Â/1û3h“¨A1¨Ÿ`(ö\2QC4Ð8C$šVf"TMå Ÿ‚` ˆ /hˆ#JF`êÀ©m~_¿ßòŠrüøÃO^uÕU 4ƒ‰FŽZ ùŸ{î¹û|Eqq1$©mYË·×mÇò­ËÑl†$KlæwˆVö_˜ Úߦéçµû„PB­³;'ë[öv™–³ôDh¯~#DFo@)ã,ÇG žP•šfBÝR qºhô™b€â39‚d9Ó†LÃÀÌmzEQ°gÏlÙ²å…9sæü/:™• ò'=ýôÓw 2äÚ’’’6'ëX¹w%¾Ýý mÆ—´½ ‰e†üë¯)üt“ž9ëN«Ï³û!ò½áÒoö_ÈÌò”Ç6'Oe¦~ï°„Á®3°C,°Å„õÐuÅ"|A(¾ Æ ‡‰ý'µíÙ)Å®]»°yóæ§®¾úêšÐID £àH® d™ù/^|ËñCŽ¿¶=™z^ÿéuì©ÙÑ)Ar2D—Óøër?‰éÙ'r&=›vŸêDÕíù0mûì„mv§‘ ³£§Y x÷î i1 ¬‚ˆTUAˆP)ˆ„}ì›S@«#¢`œƒ6&@€UÛ?Gy]æœ4'æg'„ wïÞ  ×,^¼¸éºë®{@;åÓö‘ãÃã ]žËfçwð<ôÐCs†ú?E…EmbûýªÏÿ<öÔíè!¹%È.’[‚èÒ8‡ÉÉ,D&¦ÉO‘)û hJ?‘±ü*h{¢)4yŸm¯;©DØT¨ÏEjikË}Ž¥-Ò»ó °µÚwÓõ8”Pã›ßW"d& ê"¡>>D§ÈÆ’‹M&’KbãÊmŽ«í‡·ãѵ¯úc«¢(¢¨°C‡ ½ù¡‡šÀ£€`[ªË K ‡üºk¯{þüù“úöí{OA^A›~‡}‡ñü†çq¸ù0$C|Ù!Ctˆ²&H†¹O÷ê9ß~^¦7d}ÎÖ¬›“¨ªÕi…ªÌæl‰R³•ª&Ê™¨ìÅ0U©ª…MM³bigÿ>ú·`(õol)š¨+ƒEI4ÄEÑ!2" %Ù)³qæ”q á­^„ÊæÊ˜Ç¬Ãá@A^úöí{Ïüùó'pkx á.#aÜ{Ý×\sͰáÇ?;`ÀÁãñDD&{©h¬À«_A£¿’K‚¬Sk§Y›ñ%‡® :H²hD÷‰¢QÔ¢ùD@ æ!6ïZ,# æùpõÆ9Êã¼m Ð{öÔ©£•oF¨±É¾­ "a_ ŒšÎHC~Fظ’ZÑ8‚Zo žýêì©ÛóØõx<0`€0|øðg¯¹æša`D@Öð‚t5è`C~ €³¬¬,{òäÉoõéÓGÊÌÌŒù^»vãíßF‹â5e~ÙY´°vD@DT€&ÓÁ÷(Æ\š¿UÊŠ>œôc½(T =¥^'\C-´Ç½#õq¸ö­ù† šN‡}k]¶§‚.ö[bãÆd‚6¾Dm¼1AFc° /®{Ûk·Ç<†333ѧOiòäÉo•••eƒéÁ$"w`sñ•¸$ÏŸ?ÿÍÂÂÂäüüü˜ïµ­nÞÛò|ÔÑ¥ÉjšÜ¦Sk½ε—÷ç×"øøõìò½E¦ä¶p²hDùœ§ü\»ž(Ï·¦×èHŸðÐj»z]Ebè OPÝ\ìÐÆ™Žôœ^It1]A‹Ú‚W׿Š-‡·Ä<–óóóQXX˜<þü7$kx!kOe_¡:nÐUV#}˜£ÏŸKJJµ%ƒÏîúÝøè—à£>S&sÉLãÀAÒy¸ð]C)Ä ÝdÇ›Jt@¸Á Z=G#Ÿkë½Ð:Dê»oÉ}ýœN$t·nJÙø¨Hæ5¢C4”¿¼ïG“¯ olx¿9ù7(M/é™{÷î UU=óÌ3¾êª«n—L]dˆ+Fãï^°`Á9ýKûÏjK"Ц ¼ûó»ðR¯¡¥]"Óæ;5VßA ?‘ˆÁPéZ|•¨P‰Êf{B%*(læ!lVPaÖé›ý˜¯wN¡ŠQZ».ÜëL™ØÌ­µ¾³×볿þ­U¨lLÔT æ¸Ñ ÕD&l¬9´qæظs\¬H. Í´/¯{ê÷Ä<¶KJJп´ÿ¬ œS)Øe–¸[B€kèС¹Ã† {$?/?fï¸jo5Þúé-´Ðƒµ]Z¯“ëHOdÂ>˜D,&<ùUb;âÇ‚„áÚECúÄÖ¹[gM !°ù!°ñ¤/žˆNÑ';nV›ñÏuÿDUKUL㛂ü¼| 6ì‘¡C‡æÂ* Ä]o@G~'Ïwܱ¤W¯^δ´´˜Øc¿âÇ+?¼‚æ`3d—lÚj5Ÿ~ü§Ûóùàé‡ýÍgŸj"€nòã€g£‰–ã¯ÒY,}B4h„ë·°u”Âú9M‘€0í0W”ù€HE6–8“£^ZðÌ×Ïà¦17Á)E_a:-- ½zõrÞqÇK.¾øâsa]Ž,®¢@\8€p¬ÿßÿþ÷¹%%%ÇÇ|Ÿ6¿€:_›ùõŸg÷%b¡ÔL‡ uX ÕдѾ+T‰ø›?6 o¿·µxM˜6±”ȃDi­cmOÁYetî@S^êcɰaébÆÁ(ü8=ÜrõxÌc½¸¸%%%Ç/\¸ð:t¡(ÐéÀfòsp=º°oß¾¿o‹ÆÉKPÕTÅ~º†_63ø²`¸ô‘„øíóŠKÔ8?qÎ×ÚïÖ|,)3_4;ñ‘Fžî\bí¯Xmò|±¤h£Ôà +Ì<†Å@)×¹QM!­;í«ß‡'¿y2æ1ŸŸŸ’’’ÿ=zt!˜( ¸‰ñxo?ϼyóž),,”\.WL/ß³{jvCtIš¼O4‡æ¤!ÈÌ‘sä!†IÉü‹OL¾¶‰ÍoÅ7~Óðm#Õµå|¢Cgô`Èwà& óØä‰ %Àâ´èp)(¥‚ʬ"@©U¡R[+Áû[ßÔçF}6—Ë…ÂÂBiÞ¼yϬ]»öl8ó^$„oµM+:ƒXê£AO&±¬ÐQˆø½¨À[õÌQŒcLsDQP6.U‚*j{¢"BUU,ÿéôÉèÓjEEEEðú¼Cî¹çž‹þð‡?,1H§OŸÞéyã¡0.—+µ¬¬ì®¼ÜØ×lûà—L–J“©ô":4?~MÛ¯w趃m#¦ÓŽn÷×훪k…¹6|/òç,çíæVþOk[¸ëzÊKÿt¤¯bºFçu1’˜õú±‘N$F‘µx‡hè§x•èñÚ÷¯ÅŒy¹y(++»Ëår¥‚)Ð ¡Î†N»©6û®¾<‹-º'??ßœœ“öïÿFS ÉŠôzÆ^Méb ¾îÑJ>@óöâ©w¹Ñ¾·×é1äFÆÙVäüXdÓöÈ¥‰¹t†þ Z±Œ„Ñ ÄêI(# È’yÊ! ÁÛ€Wx5¦ÿ›œœŒüü|÷¢E‹î‹4\…;[Ð) ŒÍß9f̘¢ìììóbõöûþð÷ø®â;sÖw†c$ <ˆd*aôÿ¨5Ô}—sï 7³·6뇛ñù{Eš…³ù±·Y܈9N€YéÍðb#¼Ä…›ëÖ¬Ù±ßø&&|èÝ»7²³³Ï3fL¬\@§*;S +þœU@¨B˜ò:(@•ˆŠU°tãRŒÌõ™!(,,æÎûàš5k.5µx§);Ì„ óuNœ8±ojjê¨Â˜îñÞÎ÷ÐB[ 8D@³­Y3ñi}¨È"·ô.…¨,Š˜Ñ^*Ñö º£oØ}HU-×éõᎣÕ'ÊÑUŒHÐXÛjŒ;ˆZD¡È ô1+³(Tbp²L™Ý¤4áµcÓ"55õ”‰'ö…ÉtªY°³8]óïà¹ì²ËþRXXÓ~ø{¬+_Ée.Ö!ˆf¶ÝƯgå`IÍe™ùY…YÃÞ~p‚3þ±.ÀÎÐÐv–qÄé ïA‘‰­‚j¦ŸWB@ÀÛ¾@¿Ì~‘?"ês’Ë.»ì¾eË–Í‚u¹±Ná:JBœ~Î9çœÒ”””ᡬUø²üK@Ö.4Û>ËP‘D P c÷ X'·æÎÛ&@##},Èž Ç„Ar½ž'öÉBWòqT¥, H¤ "eã9hZ  Ÿmÿ 'çõ± PQQqÒ9çœSúÁl†¹¶€ª%íÐàë % Åî?sæÌ;‹ŠŠbšýWV¬Äþ†ýf–^‰„äéãÃxsOAMí®¶…Óî·¶§”š‹HØêÃGÒDix¢tnñX{Æyÿøñ©)§ U=!—‡rwõnügÇbB°¢¢"2sæÌ;asŽéâ(Ѐ1û—––f§¥¥ŽÕåwݾu€&#iÔQOÞ¨¿"%ªÀ0Æ2[àX3MáG5ÊLaÍõc ™Èå…!Î!ð>­û_ÕeDê«Ñˆj,mp]HmÎA4²˜hŒ1-n€ ”©êô؆}Œ‰aÑú|çç˜Ô/zŠñüü|ìÝ»wtiiiö¶mÛø†ô€¡vCG¨ˆÝëÏuË-·ÜVPPÓìÿiŧ¨õ×2…ŸD¬"€hÊSz€Å9ƒ3ñQP¦†£aê¸ßNâÄ•éWâ̤3‘+å"YLÆ´Ìi¸,ã2u|>¶<”ª€¶²%Ì|ÇèFb¨ð›Ï6Ó`Žo=ˆMp¨n©Æ‡Û?Œ Ù È-·Ür¬1š1²ýÐQ@·û;xrssÏŠußoË¿µØPùÔÍüì¯#¾ Õû¡Ïô6sÏ¢Ù÷§'Ž|)”39.í8Üì¸ÿð8z™ê„äLуý~ 8F!F.€FÀðá=Rñ¬pރܘÿ|ûç8»ÿÙQ­W¯^Ø·oßdw­.$Ã\z¼ÝÐ^€Ÿýe°L?3sss±,ê±bß 4˜‡ŸU%3¹Ÿ_©ÇHÝ ëš|òÃîj4îkDKM ‚¾ åÔ> €-nXNã•÷V5ÒÓq:.=We­·íü(êÿ¹¹¹Ž Ì„5“p‡¸€Žp¼ãkРA—äääX'|[ñ­Áîëò·îU¥kýõ4MC@]û¯R5¼£¯  CÒÅôˆÏ³qÇFÜõú] T¤¢¡¸I ~‚H€vŽç(l:jŽ=‹˜ÀeÃ{U× hãõöÕ8«ÏYQ/''ƒ ºÀË`xçƒéÔ.è( pžrÊ)….—«ÈãñD½ðÛÊoQã­1Ü{uŸcåõÖ³õÚľƒ#¹ã†Û7*aŸgëÞ­˜÷Ð<:xþ&?Þ[(2!ë÷¼Í¦ˆ”ºµö!…›Üôôb–´õ"Aec%ÖT¬‰Š;.—«ð”SN)„Í1(:ʆ‡öpúkéñþÎK/½ô·±*ÿ¾Ü÷¥Ñú£«‚ Q<~zÒNÚ,¬c^ë¯A8ößø(ÚñáÀa$‹É!Ïs×3w¡ÉßOªR’É#È*ÔêWpTB[õv΀3 ªP­KÌi³? R3’USz¯Ü¹c ÇD}¼‚‚r饗^õõ×_ÿ?0üóá# }úèÐ^€'®¼¼¼3srr¢^TÞTŽŠú æõ§yùAb³>©)Íè|‰ßÏÅðH DðÌB(ØÚ¼%®ËóìÚ¿ [Ê·À•áBRN’ ’áÌpBt‹Fb‘ôl°ËÄcsè¦d › 6Ý$(ì¬Ú‰Ýõ»Q’j£vÈÉÉA^^Þ0­LïÀ6C{9ÃïôèÑEIII™²,G½puÅjC™gé x A˜ìD5û?‰Üù<åµÏþ°®~&dN°ü¯]ûwA8’ðäxàÎrÑâ`ºJA•è‘Ð `QëÜÏ%¨œÓ ‹£™¸(Cý÷òíËñÛá¿mõÑdYFRRRæèÑ£‹Ö®]Û†‡~0]@Ü9»öß1{öì+³³³cRþm©Üb‰›6Ì~…¤$t¹m#›¡–׳ y ¾"XÝ»Q’lRXËÑ!‘ä€3Í 9™eI•€žm$ñáJX‘]óD0ñ€ˆ›*6ž}ÜeggcöìÙW®]»ö°ZÚ,´‡°°ÿÙÙÙc²²²¢^ô]Õwh 6²%–‘åbT‚*jÞ~†ü/hÉ׌P_,HE0~‹˪–áªä«ŒûåŠÄA'@eö¿ã"y IDATBÙŽàv½á8Rc¬ë{*2îRTs!‘¢ÁÛ€¯÷S Niõy²²²=V1@@;Ä€öpÆ2_IIIIN§3'–e½×\oY—OŸý͸jÐ(e³$³ÿ›÷Ôëíܰ®y¦6OEž‡¥(ë•Ý ™hF³Õ·;1ù'€ç6Ã)íõ:w© /‚X»wmTàp8àt:s’’’’šššêa.,Úf1 -fÀöÿæ›ožš“ögÝN‹ý“ô³ØKÍÝ–X³÷¨°.õ¤ÿVh+KCñ+õT¦x«â-Ës=âl(Á`Š¢å’Ol‰Û,+ÙêùñvÓDZf¼ëтܺ¿ú%&dÌÎÎ&7ß|óT0 ÝNAmõà€ŽÒÒÒ‰±,íýí¡oÑâo±äï7<ýl.·ü lÌìÑ¢·(ÂFúY ˜#ƺæuØZ»Õø޽ð¦‚Þ ” rÄ£Ñå(.aÄRûo=·zÜ@³¯k+ÖFÅ©ÌÌL”––N„•´Ù ­@—ÿ%Τ¤¤~.—+j§lªÚd²üÚÌo1ùñ>z'j› Ó€¥ŽÏÛg¿ÆðËæÎC·€÷¼h|¤ì´lœ3äxë¼ð7ù¡”gHl=p‹ÔÁ{†˜õÂqëö­‹ŠS.— ÉÉÉý`& Õõm‚¶ètö_àðx<Y–“%)ú-vÕì2=¡`Ëæ«Ëø´ç§`/ÉËþF=lT•†wüáÏñ@D‚½t/>Øý¦ô™¸òŒ+±òù•ðÕûàHsižÐá5=hdÙ_¯3ùhV¦.€ã¶29ÔH I$IJNOOO®­­­…u‘¼˜•±ŽržNI×^{í™éééQYŽ=M{P竳xDñqÓüf‘liõµÞ(¥æ±ºœq¬†ÞC¥Ln#.‚7½‰ƒM™)™¸âÔ+Ð|¸Þz/‚¾`Äë%QÚZô Mµqªv\Ðñ£¦¹;ëwFEÊôôt2gΜñ0-|ð|LÐV% .ÿË “––õ¢Ÿk~6½ü8í?DXÒ+ó z¶•µBãt‚Ž #âVðÄÏOן?ò|”%•¡åp ”„(ØÌ-j\€ÞÚñ3?ë¯s¡sý·ÒÒÒ0`À€1:N¢z€¶Š† 55µŸÛíŽzQEc…5‘1ýüõõúT¨Ìç_¥ÖÄŸ”)VÖ*\烆²ÿü½ˆ“àgïÏxgÛ;˜^:„Ü:éVÌ}{.Z’[@²Gf+="ˆúƒQ*Ppí5ÎÐV¦Ö­”Z-‘Ø]»;꣹Ýn¤¦¦ö‡Õ Ð&Ù5VÀÉn·;G–e³S"Àþ†ý¡J (¥†íŸRùõ™Eb ²Óð7òŒÒJ ¯îee˜5éøÝ©¿Ãƒë„èb¹ $—ÔÁœ+ 8ª!V@mÀVg¹?¦8aymyTÜ’en·;¦%@WÚ´g‘¡­@×È¢(ºEQŒzaeS%{4ž Ðf}À|L=Ó/áŸÿͳèüyž€´v?HI!XøÓBüõÔ¿Â#{ðë²_c}Åz¬¨\ÁÜ‚µôÎ "ÐC!’"°5åO(øz•KLËé˜ìãÔˆúh¢(BELäo³/@»ÀôéÓ»Ýî¨ÿ¤Ê[Ÿâƒä›O„°²‘J™ R&„ÓþÛ÷öÙ?\=áªüUXôý"Ü>âvÀMgÞ„oï@ùár@äd9lаË<©!rX`?¶qªªMtzJ¡U¶×ÖžT‚Šù[e m¿×ƒM‘—Ôúº‡\xá…CÞxã*ĉð€\VVV–””õƒ--N•0>]é¡+ýˆ`úûÛ—‰' „›õuŽÂNIí÷ y3<¾¬ýoýüÎ?î|È¢Œ»Ïºsÿ=-ŽP‰BrI }ÀÑ­ ¶…µÓ.„õV¹zçUjeñy"aãŒs*@UT T¡*¬(ŠÂ¾ªÀE\ÌY¨'›£ÈÒáft»sŒ]VguöÿÓ d®ˆÌç‹Ê€¾?˜6ªvŽ]LAÑìkŽŠc@áåÿ¸ùðŒ1iýªú먠   TPœ j/É?u$D6f™xíAˆS€”&cñŽÅ(H*À©Å§"Ý“Ž&<ˆ—݈RG¦ƒ-"ÒM̓ôuõE_g_;‹Qà(@–œ…T)NâD’”¯âEѨ4¢>P¥ ÁÔëQ¯Ô£Ê_…ª@ªƒÕ¨ VÁOýÆm†ËvÖ=!bÑÒwWˆ@,ï…€jcšãX¥l”RÊðB \…_ñÇôh„ñÛ ÔV °ÿGŸª;ø~PI{aÍñA ‚¡xÎ hJA>ñ§}Ö·×…unE‰Øœ¤4 ÜðG<(?ˆãóGnJ.žø0~·ìw¨A œÎneL“Ò0*e†%ðäaðˆÑkq‰Ì¤›,%#ß}eçZ-ʛ˱·y/*|ØÛ´;šw &Pc‚ÜL¯C·GôHÐV€ÐsF{^ɨãB¢éõy£>–¦L·à'âà¤ïy½eTÐSWÒ(T1^R ·Ù‘?Üo ®³í['=H0-ˆÿûêÿð÷±Giv)rSr±pÂBÜ´ü&TÓj82Gœœ˜t"&eN©i§B"]óµuHw¤#Ý‘Ž!éC,õ•-•ØZ¿[ê·`cíFüÒø‹‘ì•_Ûñ¨„Î 0¹TCGB9]–vl¸“6a;òwº€ÿÓÍýŠŸ­¤EÇ"éïI¸vEbƒØß8×Ù,|Yôˆð)>ܾúv<=ñidz2‘ŸšE“á¦å7áÁ‘~dˆÀIÉ'aVþ, ô ìÒÿrÜ9Èqç`L[á¦)Є U°æÐ¬­^‹&ÚÄÒÂÄ€Úöúoj;îØ~=Wô@8ý¼1±>';]XX¹ B$"sÿå‹‚K~Y8€÷ +ï‡ùÝ)ò¿@% !Y@­Z‹ë–_‡—¦¼Y”‘“œƒE“áÆe7¢¢¶Ž4—Ð%<]JǼÂy•6*¾ÿ¨$'alÁXŒ-‹ Ä׿ƻ{ßÅ7µß˜KÂeÄ 5%u¸c‹@ƒpV.½N™äVÏIOhORИÁnбÌÜaL5­™q ¶è0ó`²„JW%îYsñŽ™žL,š´ýýà«ñ!ج™íÎ%T<‚ƒÜƒðç~îÖÈoI0¦` þrÊ_ðÂèpFÊPš(~ÅtÈ9Bß7®c‡FÀ¾NµMjœ’°ÐfR_aœÌ£†y9^1¢#Z¸{Øf{þ¾üy½ÃôúNÍ]XJ‘°²v%6Ø€ayÃ@Aº;‹ÎZ„;>½ßÕ|™Êf"Ì–³qRÊI’4ƒ“£ÈUÔ9ïs¡(¥w޼¾|÷¶5ncâ“Ô9‚u­á luúXî‚~ˆ+ ¶ÍðÔš ìQ€ü="íCâHÅè$R%<úó£x:ÿiÊL¸e7œð þ¸êXY³Ž G»‰@–œ… 0.}ú{úÇç]º ̈'Î|}õÞÙ÷$dêQº#@ÛE€HÇúø·ãˆå|@\uêÆÏú*@ hÔE^ ‡Ôú½º”Ð0óàŽÀ¬,_‰ñE㡨 DA„$J¸{üÝX¸v!Þ:ôóp‹Æª/­D$ŒL‰s²ÏÁˆÔli´’ áÖѷ¹ډ—w½ 9M6²1u;"@¹±Ås¯ Ñfö¦õõñL­ã8„{ˆt‰`ì9öÇx9ÊbxŽ€ÇßnGF\žßõ<ÆŽƒ(ˆð|pÊNBpó˜›ÑkS/<ºõQH™D·1«D$œu6fæÍDž³õØïc晇±©zãžb$œ] íælcºµç â qT¨†–ŸæY~Þ  _gÿMЃŒì×Ç4ËÀ®À.|Rþ &O„Sv¢¡¹)žÀ ý/ä'çcÁ†¨ˆ‘ɸœ™pLÚ\[t- …ñ}Þ8ÂG_~˃œBçÃ!G_'2B0wÄ\\ùæ• …CdD »B{Ø~ûo?ôñËÇ·°àK¼ - Í´XUUˆ-Š¿p€…:ÒÈÈo©ã8݉ÂÞ&Þ@d‚ìúÎ,<¢ Âãò ²¶9é9€_õýó<†[×ÞŠz¥R²"d9²psÉÍ“>¦Kž3¨T…?À\MuÎ¥=°÷Ð^,x~Y‘ ò3óÑ'·zeöBVJ2S2‘–”†TO*’\IpÊN¤&¥ÂítÃ!;àr¸à’™'âð>Ãá;äƒà˜9U&?’#öqÊݶÛÇØs6®¡ Ц‹¯@a•qxV½ÀÎê[ä&[û¸‚”«åøhÏG˜Òg DA„ ØV± ¥…¥€²¼2<÷ëçð?+ÿ»‚»0ªxæš4)úš m@0€Ãõ‡Q]_ÊÚJT×W³ÒPªº*v®¡Ú,Õ†ÆÝ!;0°p ú÷ê…1°ˆ•Þy½!‰­‘‰§LÄ—üRŠ1YD­\‹ïj¿Ãúªõ,þ^Ë€cdÐQ¹ï®Zº Óe(^fƒb÷Z¡©3÷ÎQ­q–ÿx+¡²> Dë bÔÄØ³žÑ#þ†Úê)wÏ.Òè@â x~Ï?pVï³ ²R³ðKù/¨kªÃÉOä¥äáÙÉÏbWíN—=(¢Åƒ‡ Dcs#ªêªPQYÁZCÞCµ‡PÓPcWÕW¡¡¥=¾À„È-=Íí‰@@ÜÎd§Ù–lõmÅÖ[ñá/ùê$*¡$»½3{£(»ˆ•œ"d +•Íîù™ùÄTÎ<'ãrDÂoT# ‡…pþïTádLöw¶p ÷­»´Uàë"Mlv1Ö>±Åâʨ  ”E@â1Ÿv £^#4z§Ú;E—› ¶)ÌuqØOàß»þýfF—Æ__ÿ+jšj0aø€KraPö`xƒ^ˆD„,¶žQI%¤§¤#=%ý û£¾©[+¶â«-_aÕ«ðCÅ‹L’ œ©Ncå%"ÓÓŽ/¶:c¥& ŒŒ;~Õ({ý{±ûÀnн"+Z:+†‹˜"BJ– gÈ3d²`æ¾S¨Ù–Úö€õ74×k—Á%°Õsº`Œ:À/wŽ‹õz^´í è€gwxÓ_H§Ù‚„pìþ%šƒÐó»žÇ”’)pˆL vãŒ1uÁTT7Vcæé3æ.É…÷¾{/®x§ô9㇌ljýO„(DVxB–œ†ÇÀˆãFàú󮇢*8Pwë÷®Çê]«ñSåOØÙ°“­u #z"Œ)-Ñã ¤UZ ®€–Æ: Õùµcnf¤ b’Ñ#²õŠô¬’ûî0ëVop)9ª @È{ÚpljpuFÖá8C|­6¹Ÿá°À>ãG"Âq¨D%–îXŠ™²Ë’Œ~ûfÜ75¸iêM†¢íÜáç¢_f?\õ÷«°ð­…HKNØAc0þ„ñ8ã„3PUõ_Š‚ˆÂŒBfbê S>Ň͕›±¡r6VoÄÆšh¤Vb Éý– %ÎÚS“ „+PÙy".‚G›µõ›iâ»=_B,"ã»vhЯk…Xð‚»¶[€XÛ¯šC™Ý_ ÚB \bhÿ£ÛþƒIÿØùœ×÷<8%'à„¾'àÚ³®ÅÃ?Œòºrüåâ¿@–ë_VR†÷ï}×?}=ÖîZ‹å»–cÙöeP_U10g ~Uö+Œ:§:Õ¸&8E'NÎ?'ç3݃JUì¨ÛõUëñÍáo°®fÕF¶ïjÊw—®sÓB‰±¦;²¨Ö À˜µ©Ð5÷ˆ@+ ⌯_ÇpÀ ¶¯ttëâQUÊ’‚¨PÍtàáÞ‘ïl±8à?0¨©ÕV€J%^Þò2®r…Ñü¦i7áƒMàíï߯¦xü²Ç‘æa€Œä ¼xã‹øËûÁóëŸ7dç¾Ø¾n;ž^ý4ÜpcLÿ1?d<ÎvŠs‹c~T(M/Eiz)f–΄JUüpø|]ù5VW®Æ¦úMlmF}†nmb&0ˆ‚Ye½€ÿÇ$ÄBôv:ƒZŽAµÕ‚ôñ«!º=€ Õ¢Œh†"H @¯¥K—.-++‹zóß|ø7ažpùy˄ٌ%b:Æ„[ÕÜFìD Ë €ýƒrˆoPôE²/LùÙÌijbó ÌyaÄ$ý2ûá©‹ŸBŸœ>–Û¿»ñ]Ì_19ÀØè …êU¡´(Pš¨Í*T¯Š~™ý0¾l<ÎzF•‚Sv¶û•j}µX½5V\…/‰Fµ‘éºk@Α†Î$º5ÄOM]‹¦x¥> ŧ€z)>¾úã¨õã?búôéÓìP  @¥4jB¸ët¥_D ¾[¹¹-ú…xûǵ۲U³þñëh–ü¸W»Ú¸Íø!ãqzßÓ±¦r vûvãÂ^ˆ…Sâ´§m¦0 ¥¹¥˜÷Ñ<Â!bÕ§Bñ*P[TìmÞ‹¾Ï}ùœª£ú¸Áãpư3 ߃X!Ý™Ž)}¦`JŸ)¨|µÿ+|²ÿ|vð3Ô«õ b`‡Žî¯ñ·hÿ¹kºB”Š+0óƒ™ÜÌ«+`h<w)ÃâƒÂÈah >l\¿,H‘äO‡ç~ˆgŠQÿãÞ1õ±©r%¦%oþwÌÿâò±—[þ}uS5nþøf¬k\Ç܇EÂfŠ ›-T?ã”fF”¶W½*JÒKðÂ/ AÇ"ªàËý_⣽á³CŸ¡‰6%ˆÐ.`i Xü ¨JÍKt+‹OûÆ>´…â?×þ'êcu„h·›•]ƒ¶´¶E;ßÕ§ŒQUÕÈ[¯U–›>À­NCmÉKxB$ B^øáK•—aBÿ PZÀL‚{¿¾w,½A%h´ËLÊijӟÅìÞ³ldÉEˆƒ@H ¦‹²$Èy2œEN8{;á*qÁÕ×Wö9öá¼GÏÖŠ-íý¬‘ˆÛk,þtêŸðé9ŸâÁaâô´Ó!ø6Hcù¾‰-ê úq xÖˆ¯Ÿ%?sr™€-¶Î#Yt“–¾\”¶„”êS *l,+e[Í5â=)#/m{ uÞ:KwÜ0ñjP½ ©åLoîy³ŸŸêÆj£$Hø¿ñÿ‡Nyr ¥I Rf¾“4“[ËX,gËód8 p;È àŠ×¯ÀöCÛ;å:D&”LÀ#§=‚OÎþ· ¼ ¥b)ã<üªÙ‡Gú[vƒ2»·2Æõ¶á®/>ÄâJ ™¦LCAc¢jq-Zg[fzmM9Åo®Dc }´Ugì™MBžÙøŒ¥?†öŠ‘ù#¬B ¨ .)KÂßÌxv¶ì³ÎÜSʦà•s_A¯`/ÙÊ9†8$Y‚1I„˜&BÊ” çȨK©Ã¥o^ŠŸüÜ©ß3Í™†Yƒfáõ³^ÇK§¿„³²ÎZÀúîNëÕéņnP«aÇâKÀ½lwA|…Ë1n¯Ü"“º»«>«é£Ml¦~yÇ˨j¶.ð8{ôlë‚P›˜&Xt‰3dtÄEK.Â6Ye¾¹ðæEoâô”Ó¡Ô)P½ìy$Àœm‡1I„”&¡ÖU‹Y¯Í—ۿŒÃ—NÈ=œöÞ?ë}\˜!¤f‰qü³õ„‚¶ Wngˆ«h]Æé’C~»l¯ËõaW‰íàðJÞ.`òÉ“á ¸lÐftBAÜR†„@f×x=þöÑß,6àdg2O[Œë»jfˆ´6!¡Lg" 9¥W¾{%–|¹¤½Ÿ9*¦bþ˜ùøðÜ1-gh e:“ÄÚ‰Æ˸Ø&FÞÐ%:ÐØ8†Ncó9Ä׃Y V?ȱùq~À+zñĆ',ý²ðê…xõÊWqfÞ™ ‘ýZBRHÙ¾¨ûç>q.½–kÇõ‡ó1ÎÉ>´‘2n Fþe&×dv¿e•Ë0éÑIX¶iYÄÓcžÆ%W ÔYjx•ýAAŒûUyªpõ[WcöâÙøêç¯âøÚ³O˜w¦¾ƒAÒ (Œ/ã& [@|ýâ]ìÚ|½×”Qƌϳù]\îq?Îï~Ä~œ:h*ž;ó9¸\ÌÜ`ú]/°¢j@Q(ªb\'‰z§÷F}}=Žs‡×&¾†OÎþ †,ÀøŒñp  1C„\ cMý\ø 1ñÞ‰ø×Š¡¡9>¢Aqz1^™þ fäÎ@°.ÈL‡Ç7‰«¥^ÿÍsÇ °pmÁ±Ž@ü³kŸÀ’<¬@m²ÿ¢”²{ZVàÑg~Þ–z„a|ÞxœUxVÔv'„g'?‹Ë–^²b’"ÀìðíÀ¾†}è•Ò ßnû}rú ;-Û¸öì²³ñõޝ1yÑdüzè¯1ë¤Y¸hÀE¨|Qñ>Úó>Ýÿ) – ÄTvoÁ-`kÝVÜöþmøß×ÿ£KFcô€Ñ9`$†ô‚´¤ÎIYæ¸ï¬û»*ýðÄT–ì£;çþÔúÛ“6í½eüqçÂ"½ŽÈ !õ]]“£|­uõÒ0@k§RÕbÒƒjÖm»\PrAÌmO*> Ožý$æ¼;‡­©˜Ì²Ã|±ï ÌîüâNH„eØ!"ÁÊ+1ó8–hä¿Ïûoœû‡sñÀ5à’__b\[Q€7罉?¼ñ,Y¿_üòrRs0󤙘}òlœÕç,œÕç,l:ˆ··¾W¶¿‚r”³øŒd!]`1-̽ÚWÃu‡A«LÎJOΗøó%Æe¿¾ÌòKW-Å o@s ™¥,s0nCLanÌÄO@Tbè(ŽfhmœE:2±…ÙøÅCã qŒDCŠýZ%5r0’j@GzN~2®í"§DodƒKF]‚U¿¬ÂÇ•3%žGÀšÊ5ªAH‚„‘FâŒgà¦Ü„ïö|‡û.¹ÏÈÅïxà7àÄ’qçûw¢²±}þ_ù8Æõ‡KN¹OÄÜçâša×àÓÝŸâŸ[þ‰5×@L!$ F`Š¥hV#·ŸÊ¾ÃíïߎU;Váö)·#Í“†¿½ú7<ýÞÓ€©Lù(x'#B²âÐ’†è„ýh‚9}<†«`™Ýã)ßÇqÍÄÆXìצ«ö¬ÂŠm+ëÉÅ쑳1ëÔY˜Ðg&ô™€í5Ûñì¦gñöî·ÈÉÌÁÇ]Ó NGïäÞHv$£Æ[ƒŠú ¬ß·ßT|ƒU»V¡¶¹ø<ôóRlV!¤²Ô`Rš1M#b¬@œZBÒnö­bûX 'ÆFûiìG¸&ÞD î"`ÍÔJcó§=`BG|N6â7ýÙÙ«# Ûê¶!Ë•ÕæëòÒóðÛ¿ÅÂo²Ù3EÀŠŠ8©ÿI7x¾Øÿ¾¯ý“ŒÅÿµcš ï=ï]û®~ýj|_ó=ˆ‡€(U¾*<ôùCxø³‡qæÀ3qéèKqæqgâÏãþŒ››nÆ¿·ÿçw>Òé–gÊpe Õ!¹CpÙ‰—Á¯ø±lÇ2¼²é¬øeˆ‹0S&DÈ”})‚±ê/˜ J°G#´GÐϵ&ØÛÄâ Àʦë¯øÐfuÝM×bÂÓ#õÔ£Ï|´¢bE»»îÊñW‚Ô7àS±jß*Ëù›Ï½™™ e Z®ÆÅ/_Œ§WÞûq»©xVJ~Uò+f?oVðÃáp¸å°q~lÙX /Έ€  V/À Kn€/à3Ú9e'ÍX„ÛN¾ Àð6³™Û±”-a_pîÿì~ŒüËH”¨9$Bà„‚ðêůâî_ß §Ó Èìÿ‹{tƒoqD<ÊùÖÚ„ãñ Š$óèYv4=`(œ hçõQe»waÙÎö»ÞžwòyPê¨M,)ɪ½V.`θ9P ÈÌjR¦„¥K1ãÉ8P{ÀhGÁ §Ý€§&>·× ¨Zû4 R¦)G‚”%AMVáWüízVB挘ƒ¥,EÍcÖ„=ê¿aÜ Âì Ï:]¬ÿÖ_H÷Ü£AjåðÜ5Í Gõ&Pü}ýßÛÝuxÿá ùµÀŸÏ*>³œŸ>j:Ò‘ÎΫ*óö˱ѿg?y6¾Ûõ¥ý¤Á“ðÖ…o¡—Ú ŠWaßÄÍ4öB¦1GÄWs>>ÿx¼qáÈôf2`"*°µ­5ˆv¾3 þ€R‹ŒOƒÔ˜ñÕg8/>iŠÜ‰…‚- [ðïþÑ®þ+Ì*dñÿÍÔOñEÅb┘uê,( ,ƒ,( ¸Héª\U8ÿŸçãÍoÞ´Üspþ`¼7û=Œp`ÜCÌÜèdY†žßò|»ž•‡âŒb<6ù1ÐÃJ£ê£ N –t)ûÄ[ È%Ô4Ø{mù)¨8fXýÖ>(‘îûö>¬/_ßæîó|ŒPz;}¸å06Un²´™óë9@# 6²e»@´,A©"”L¿ûðwøÓ»²°Š™I™xåâWpQáEPê‚R…‚‚Ï}޶~ÐægµÃèþ£1µx*”jfLˆZÇ´µmœ!¾Á@¼>¡§¢(m⦠€€ÀœÏÁÖC[ÛÔÇ?íúÉð¾£A6V”¯°´éÛ£KFCi`ÙÜ ,f‹X¼i1æÔñtb—Œ¼Áª Kæ?z•¹*hãx¡0¯‰ñÚŽ@œ9 ªeÒ…JªïPrg‡xÕ#Sˆ Ôˆ5˜ñ¯émJÑõÜûϱ{hvtŠÏ÷¯ iwÞˆó˜¼Ý¬€4ª*P $HÙ"–úVþ²2$¿ÀãoÄÂñ !6 -*@)I.y{6¶Ú󳆃¡%C¡Ô¡Ök©Ì”c@ÏGÿñ‡øê‚¬ PU+ Ñ ¶×'”oîØV¡¾Û Ì®ÎQ‹^¹÷¼{š¼M­öÝsï=‡×W¾hÞs뫾C½¯ÞÒvÚ¨i½"”&ªBU¨ù¿Eâ fHxçûpÊNlÞ³ÙrýÃ/ÀKÓ–ÀÓ”¥Yp@=ˆ/ÍèPNA¯ß ¥Y…Ò¨j |N,Ç¢œs tüw ˆF h+tÌP¶°†›€¦Q<öýc8éî“0ÿ•ùXûãZÔ4Ô@Q¬>ˆ÷×¼™ÿo&nzô&cã…$æOO ECÌY©Y8mÀiÌ é ø )ˆ\ÀŠÊD ßìþ~û¡åcúÁ[ÿõ²ÙP[Xš²©ýë"üíÿÁl»ypÃÖ Æb&ºC×ÿÝ¡Øñ!Ì1û‹?ˆ0–Â…[šÚr­Viì©ylt×QzM·-1‡@Ô××ã‰uOà±ÏƒÚ¤‚z)“ß)X¸lš1™yí iàdõ ÀÊŠ•8·ô\Ë­¯žx5>{ê3(Í Hó½·bó¡Í¸xÔÅ8ù¶“QQU«&_e4\0ï^ò..~ùbìôîq¨©*üúA¼óý;x`Æuܨ˜_÷±73\~oC»é·‰¨í·Ž¤öñmûMih½Žß[ˆ7žã GwF £­€šD C€˜/Bê%±R 1Ú\R>;  )MNªEi ù“Nž„AYƒ 6i šØó‚ødÏ'pÉ.Ì=g.n}éVÜ÷ú}–ûgãËßÁ×(^…y¦ øEùSŸšŠéŽ•›VF/|ð–¯_nä4€PÒ ¾Á1X:ñÏÊÀÏöˆá÷±^Àb§ÀóÐüçå"roŽäbr¡ÌÖLeì?!,ˆÆ!:ðû“ÒÍ„¼öû×àò¹˜IÐGÃr[Ë÷.\vÚeð¤zðàGâÖ—nµ¤ËJÎÂ[W¼…1ic ¶¨l5¢TRž„55kpÁ“`Äm#p×Kwaùºå¨¨ª€×ïEu}5>[ÿ.ÿÓå¸aá F°.ÂÜ^O,ˆR0mºº$%XG® ·ç7{]Gþg—¦Ôc zÀ …úb=¬ô¥/Eß´¾ao[˜]ˆ?Mûnùø„#¥ÓoàûêïQÕ\…lO6.s–¬Y‚ç¾yÕ¾j,¾|1Ë-äLÂ’K—`οæà³ÊÏXXo èA’v7ìÆ£_>ŠG>y„‰/|BR¸!Y€%@H Ef·ÿ6m„XßÇÞ.Ú¸îª~Š4`G)ä±\ɉƒ0¥ŸKq;/Z–K¡WwE«]~ÙøË02k$”z´…Zü-@•¨X±g–7`DâÝíïâò\n $rÉ.¼0ûLΛ µ‘™p·1C„”ËD¹H¶ˆ0R®¶Ï×J¶!Y`ÁAGº¿»[AŒmâqטp×!B{~kƒ\}¤e°®*C2† OjŸV¿ !œþG(Õ sö™×_Ðï|tÞG8oày€SûŠY§Ìb^€N‚Oö‚YÏÍB‹ßÔ18$ž™ý ¦McÎFA•­I˜Â² ‹9"CþB R±©·¶ïÅôBª¦À$8ö¾U´÷‰õ}µvƱv@×ê¥Cåô^§ÇÔå#ŒÄ¯ŠŲôhÞ³JgááÓÆÐ¬¡#‹®X„Î{4ÀVú¢ò \ôôE–U„$AÂâß,Æô¢éPë4ý˜Ë±$°ô_lqR1KÛ§‹†ì¯ë/Žtÿu‹Û>ZÛ8C×. ÆS-Š˜)\DÊ× ÷8šÊЬؓŒ^{æµPêæ!èSqÍk"¶ýíøß⪯b}dà뚯1㩨iª1Úˆ‚ˆÇ/~çËB”½ª‘¥ ˜¦ß\05ÿúÖ ú/%Ö1©]H½Oâ qO Þ&Êh¿6Öc;e=F¡4­4æ¶Ošˆ|9• • о©á‡:Üyîxå›WÐDš@Ü7búSÓñÆoß@NjFžœõ$¯8t1¦ÿ”å–¡8¥iÎ4$ÉI€æ@3Z‚-hð7àPó!¤8þ{WE‘ý¿Ýsd2É$„û–CQAYQ‘KXA\ÔÅõV¼X÷³üVVðtY]E¼<"¨€*àzr LæHæèúýQ]ÝÕ==3=¹82ß|Þ§'ÝÕWu½Wï½zõÊ…–®–°ŠVØD¬¢î€„”U–á˜ïJ|%8ê=Š£Þ£ØW¾åØ_±!Ò81O+¢µ¹h¿£g+2Z¿:BÝ&5zqÄømtn¬kÆÚw¢™³™é²¢ bÔ…£ðÚ¯AÌQVY†gNÔòéŽtŒë6 ¶.€Åf˜*bWå.ŒúÏ(||ûÇÈÍÊ@W$zå¦WbÞÛisÂis";5m3Û–ɰg2S2Ñ&³a™`8ˆ]'vagéNü|ìgüTòv—íFáÓ#Ì£}Ñ@´kqÿ×µP?‘€@ôŠ —K ÛrjÛo´ï\„ÓêL¨üð>ÃñÊ7¯@ô‰Ø[º9­£ Ôu^_÷:M š"Nàwßïñê|vçgšÌápo÷6D«ˆNÍ:¡Kn4Nk\­÷ЛņžM{¢gÓžßm<Àð`ó‘ÍØxd#¾-úÛNlIý„(L«´ó8B©üF¿5æêGýê! :¨¯—?ÛbMI¨üÅÝ.†}A¬Ú½ —¶¾4fùm{аd/q:$™.à ÷ Vî^‰?õýlê@´Z¬¸áâ0ræHüXø# Ç•ƒ®-º¢c³Žè’×]ZuAç¼ÎhÕ¤Uõ^Øéöt n7ƒÛ ”xK°ºp5ÖZƒµ‡ÖÂr«ËŽn“á,@ ‰H$"A paë DÍ /í—â@RPQQUŒ” ÓåíV;.hy6ŸØŒ%?.Á_ý›#jùœÌHUÂþ0„ LlônÛ6‹ ÅeÅŠ9àLqbÙ´e¸æÿ®ÁÎc;Qâ/AIA 6ìÝ@g€Ê1N››wF—¼.èÚª+ºµé†ç„Ë™øÂ)z4Ik‚ =&`B I!l>¼Ÿÿþ9ò óQ\YLc)jKÔP0êñym@Ó†ëÉ x.ÐÖpáEΈ‡ž­{‚T?uoýï­˜e !”qƒDÕ'Ø´oÜðSáO(,.TÎÉHËÀÒÇ–¢m^[%\Øšg…¥%ç`ifA¥«Ûʶáƒ-`æò™?g<òþ”‡¼õMrMa­¸¬õe˜uå,l™¼ËF.ÃÄöá".mF¢$ÔKV`þw’ªOEž¢„¿S·ÖÝ€@B³¾™…Ãe‡£–-*)¢L‚šª ªzÀÕ=¯ÆM³oBáQUäeçaùÔåh’Þ„F3fаæXÕÉN-ej% µ°BÌñÒ·/aÄÓ#p¬ìXÂï¢ â²Ö—áÅk^ÄöÛ¶cîÀ¹èר ŒbÂàLÈOg$ÀŸÕ¤žjt¶ èUôꎣÖÖyg3qI¸þÛ4kC“¯ *¸õƒ[5‘~<6nßÂþt÷fÚ‡ÝjÇ•½®Äµ»ûŽîSÎmŸÛïÞþ.RB) 4& ]€A‚ØX„˜#BlJgAZš[`iaÁ&÷&\>ûr¬Ý¾¶ZíË 6n<ÿF|6þ3|7ñ;Lî<©¡TmRÚ|ÓmºŽÑˆ7@ÔøŠz@½™f_¨¦í\Æï§OÑÕ"»MÄ¢I?·”nÁ oÝ  òh½¿ñétn‚UžŒÄÙÍ¥¾Rå÷ä!“QTV„á3†kÌ>úàño@¨ÔhAã 8ˆNy‚K„˜¥®RTê(Ř7Ç`ÆG3ªµ0I"è”Ó ³¯ž­ÙŠé}§#×’K“©†zâ¹3 uŸ˜©8liiîC2R‘$Ýù ”ôÍ 7;—ªô¹þ¬ÀÆ’0gÞúæ-œ¬8‰²Š2ÜÿÂýøiïOtR[ÀS ÷ÍNɆˮ:ìÚ7oA ÂáòÃöì0ì;¦jÃz ÃãxÒ)9yc.Æ`l”M^58C„ÐXÀ¿6ÿ CfÁþcû~ÏD‘éÈÄý—ÜŸoÿÿ¾âßhii â'4M:3jBñÚ8ÿX·ÿ]ǨÛÉ@œjUMŠb$rí†BÕ»C»î‚ 8Š£xðÓÑöþ¶hyKK,üf!í™]"§œÄC  ».²YízSFOùŠ0|îpì?¾_9vß5÷áOÝþ¤ÎEˆ¦fƒÐiÎ6j.ˆDüâý—κ¯}õZ½hƒVÑŠ{݈îøoyíííi˜sH÷̱̄j´EZ3€[õZc&˜½V5Q?&ïÔ`+ÿòû¹—ÕüŽ-RS*,/ÄqÏñ„ªÞép*&ëQ« .ÚÄK3 ,Méo±±!CPòŒî0—¶ˆŒ¸º÷Õ¸ÿÚû 8Zy×Í¿‡OªÆç'>M€¸ ]´$š†PAcèÊF™TeTáÑüG1|¶ÖĨKXE+®ë~Vߺ7¶¿Q]g¡¦ëV Á²êCÖ>vH'ñôÌŸ$ãº[ 2-x<¢c@¨ '6ai&ÙåZ誾NyIoÜÐ冨×}ú–§1Ò|Øùẗ¯Ã‘“ÔQi·Ú±è/‹ÐÆÚR…u ÐLI‚ƒf²d[°ñäFôª?žûø¹¨ŽËšâø©ãøú‡¯1çý9¸ùù›ÑZ,^µÄC´yëø»qŽÕêo2þ™bJ9Â6Dó¿þxÄöÆw‡¾Ã¸îã;‰¯snhO° DÄ.3§0Ã'"éÕ¬WÌKß4ð&äåäaÒ'¡Ð]ˆÑ/ÆçS>G³ÌfhìjŒïúW¾p%<¢‡š|†¢(`ÁG¢ED•¯ O­y 7,Äã×?ŽqÇAï·üU~ì9°; wbçþرo¶lCÑÉ"š±Ù*'eI ºD*Bg6Åè™–mÍþŽF’Á9uŒ: $É ˆtax…"P¦Žó¢ìLý¯ØP ÇÏE|Uø!êû8Ka*h%­©@D„È \6þ ƒÎ„÷þüƽ>{ËöbÔK£ðù”Ï‘“‘ƒŽÍ;bñ­‹1æ1D Bš@µ‹x/§Q‡m"Šªë€JTbʲ)0ùÙÜyÕ*$ vüöy—.köÄø'Ð;§7 ¸IÄp¦“~,?NY&jyp× ˆ™¼…‡Y~4Bµ† Eܱh›ÅF'W('*ç+• Èá ê¼9¶ @¼þ¿×1¤ë˜å,¢EU}«£Ë^ø G6`Ϊ9˜zõTÓ§^ÛïZ´p´ÀQßQX©lY€,g¦žŽú«v®BÏ6=QxªÛK¶cýþõø¡è¥ Ú=ÉÏ<°õ@L:.my)š¦5E0Ä÷l>´ù»óñõ¾¯éX¿î¼Z…Ac¶|u¯ÃÇ(mŸ@Y¿!æeh‡Zo€€$I!P«*&œ¶TŸ"ѵïQ‘Ô)%«¼6ª†±‰ú?ïtaåøßç4°¦p5vÛ…®ÍºF-¦8Q!Hˆ@J3@¬/~÷¹êÓAH¢ âºÞ×á•o_ˆv‚˜óíóhžÕ·ºç垇ñsÇcXŸ¡¸å²[1uÀTøƒ~¬+X‹Oûù{ó!Š"þ=â%Œì2Rs}«hEÇìŽè˜Ý7õº NÀ³kŸÅ»¿¾b%µ“PߌHäV#Œ¶ì·Äm%¨&®@ùM”¸gJª©G”ùÑèiã¢Z&@(ª ‡Ãqé).•ج4¦@"D[FGšãRôr Ž˜ÿÝü˜ßŠ%ñ¬é½ ð >ÌøbFBmeøÅÃA|’Ÿ€„b„4S?›Š÷7½î­ºãÕ[^Åß|ˆ>ÿ×W=w>þéc lw9æ_ÿ v=´¿Ü³%‚ùЦq¼<æe¬¼åKtwõ€T)ßS:ÚŽ¤Ý*íŒÚ6€t‡ ñx,# UÅ©š¨0+ÿ; úÍh.»Ëx>tªã'1I˜¤($ïm{/¦ƒNµaØÕ¾¡fÇÜïçâýÞz?=ú×– …æm}ÁJ½õ÷~x/Vo_­{`ñ=‹Ñ!£6íØ„»^¿ éŒ)ÿo¥Y©YñoÄß³m?|sï7˜Úw*Ÿ@g#†Q;óüÍPX·•ëO³e‚úmtÏg&,!Á`К­+3€p[@òù|eáp|tÓô¦š¹èÌù§øä ‰5¾š¤Øxú«§£~‹hÑ6¾ê@ø´Ü÷Ñ}X÷Ûº¨÷äát8q~ëóJÐä !zÁ. äaâ‰8tâìV;–<°½[÷¸«ÜX¸n!œ)‰­…À`³ØðÿÀ“¿@k[ëê6˜-«gð¯¯ttÐîo–!˜p8 ŸÏW¦»2¸mL$¢(VVVv< Å9E~îL–ëL3¼§ëeªó1DzýÏù‘ùó ‚€v|„]GCv µt?‹€ -ˆ[Ý¢É Ý[w§sëP‡ºäȾ*{^ÿöu¤¥¦áë-_cÑ}äç° IDAT‹0è¼ATKp(.+6uh¸¤ã%øî‘ï0®Ó8H¾ÎñןÃwffÏÕk€ÂüŠ Ïiž¥.Ä ¡PeeeÇÉE¦¨ ¤âââÃ@ ®}’—‘§z8ù«€Vœ™ å<å§éwk€°%ŒäÿÃð°#EJJ¨YľŸ`P&”aÌü1(u—Æ=¥s«Î4Õ¸.Ýx†3Ÿßù9Æôƒë_º#ûÄ´ÅÓ°ðÎ…sÑÀ <÷õs5~dWª oÜúþ5ü_H©J¡B€g@#T÷˜¾L¼ëðB€oçAˬ–qy, ¸¸ø0"Å“)$" gëÖ­¿¸'µnÔš>¨Ä‘>/ /!õvS Í $å3 ¢€UûVáÃÿ}ñ 4Újç~ØB!&½6I™o íš·£ÃÁhÔðWG½Šm`@‡xr쓘0g& š„ ÏMÀ¼Iópçewbɦ%x6ÿÙ˜×7‹?_þg|}ï×Jþ?%KRm|‡xf€ÙýÜÿ­·ŽûNÁ`;vìØcÝ".ÌúØ£…„׬Y³/ ƽI®+©ÖTCæUrÔñ§’ͨ[FæÀ9O`ùä?S†LÁ¿ÿ4ù¿ä£çý=ñüÏÃã÷DÞ$d»²ññýãÖóoñJ IÓ& I2ÚF©Óh×kó\9È[¹^ˆülùµXGPs×™àô € ×ë=iÆغQkHaÚãKa‰¨Äxšº#†DteØjþge¸8ݼYo$° ØVº ã_V§à~±i Ù²¡ï zO¤ ˜µf6ÞÿÞxx03=“ja@’è·ì“××°ì¼ûæaëž­ 6ìùãþ57^6_=ˆ]¯ì½®Àìwgã±×CÁáÍ×V‹sož‹ÇO‡TA U©íѰý r ã6¦/Ë~ëÛ»0w/™Ëˆ´Î‰¯þ‡B!ø|¾S †•>¡y­ ùUÕÞ@°´´ôH0D<'EûìöÊ€Þ®ge$"%múÚ €Xwh®™u Ön[‹½%{ÕYq:jP«÷„œIÇÜûþ½Ø´gSDã±Ûì´ „‰ÒD[72nàM²š`ʈ)8|ì0QÀ†ß7`oñ^d:3‘áÌ@ßÎ}ñää'ñÀ àñ㊻¯ÀKï¿„G›¬Ä0uÄT<=ìi 4^€—ElÀȈåàÏTÎR˜ŸëдC\Þ ƒ(--= Õ»Âk¦`VðƒaÁíÛ·o­¬¬Œ}€‹Z_I¢ .Éê>O|®:I’(ãyâJ¾¢–71U2n™s‰ H¶žØŠás†Óyñé :ÿup_9·ÀÀ„×&  XÛ3;N¥õ°s2™QÛÌÝ×Ý —è‚–+ТQ‹ˆ29™9X<}1¦ŒŸ‚YïÌB—›ºà‚›/ÀÔOÅÊ+2îzf\;’[R× j»Ôüæö)˜Á±’t唨Xí¹ Tôk×/îsWVVbÛ¶mÛiH1Oäˆ@a~¡>øàgŸÏóDèܤ3rÒr"¤%ÿ²<³ª7üKÂX¶ß4uM>!KN†aCÝMéðàIr׿t½’ P“òd£OCÉHËÀÈ>#iê0B‡ñ¢aì ±X?=:µï„='÷àå¯^Æõ3¯Gîè\ôžÜw̺ó?œ/7~‰=öà”û”2ÚWéîý»°dåäoȧӓ+‰:Rú6KwÆÙêöécb!häj„®¹Ñçw0ø|>|øá‡?Ckè×aŠ ³“˜BÃL€€ÏçóŸ$INQŒÝªºµè†u¿¯Dú‚$§[A+3U‰šš:΄“˜•ovÿ¹ –ÚÛI™4Á¥Å ÁemBû½ûqãË7bÙCË`·ÚQCÕ9Pî/Gfjt-`p¯ÁX²a H€¨S™£ c^G¬}a-Æ?3 6*íì·òßðÛ÷¿añúÅÊèƒÆ e3‹"H@ ‘Ù’yF6bîxŒÏ›Œ“8®âMä­zÄ|_$ Á`Ð磽p›zPuòäÉ£Á`üÅû·ïo<Î/¿8¯)’0 ½&‘$±dšl­?–ಮï+› ë­Ç} îx+½jF¹Ü±ŠØK‚÷êÔ‹öÆ•å¾ò˜e ;#ùçct¿Ñô}3ºÈISš;%³µéÃÄ,ymÂ49%¸Eé´LËoŽ•ã gžùyn"‘et÷}ƒÁ Nœ8q@d­õ óTmÙ²åG¿ß×FÜy0Ò­éBò:qlT@ö (΂+I5 @;¶žîɲø¾»õ]ÌùtªBUTa­OjãôhѤ;P*ŠY–!Å–‚ÿ>ø_Œï;žj ÐLÂh6a1GÎ ÜÔ±™¨!K6Í ,8èb)J}E Ô‰g××Ca@Q˜]ùÍ€a‚t{:†t—§ü~?¶lÙò#¨à‡ëDÚ>< °páÂo½^¯©›õlÕS©=së$ ÑüF~C“ ‰Óæ‡H0cå ügÕhbÎA™£ÿ{iì¥Î3Ò2¨Ú$ø¥ðÓ·¶ˆ¼v×k¸¥ß-´•Z!…fÿÒ¹D¢™œ)Ò¢NyqÝÒèŒYŠüŽÕ yÓƒ˜þŸïÃ@¿NñÇþªþ/Z´h%´ ÎM@u†äWóx<fR„]áõêcòq…ÜÿŠ£0¤ŽÇF0=_¡F•™¤3‹ OâT좲"øÑãH~ùíÕ)K6/Á¢õ‹¢–AðÊݯ`T×QªÐg£ÒÏ@’9H¯½–7Pë•¶Éï3 ±}ÆÆå¡p8 ÇSQPPpª`<)%Z?‰ &רH@%€Ê={öl7Ô´3º6ïÑók"y"ô‹d•À"õdTaf¢“TÄÿÉßpû‘íQÛʦí›Ô±x€¸ÿû1gùºêt°ˆ,x`¶¨®HÄ¢ðâEïÕ´Œ®=ó£_¼æÛ9òF<ø|>ìÝ»w?(ÿñN@ë\#$êdò‹¾… ®¬¨¨0u‘ë.¸N‰ WbÃuš¯é%0#3=ÙrI: D€-—7« TaÕ÷«ÔÕ}å-±üó“bà_bÍOk ϻՎÅ.F;G;u°Q^ÊX=¸Q¹hFdï¯ÓvÙ~"\×û:SïQQQ ¬€±kÖ<ª«0G`%ÿJÜn÷I3AA×ö¸y™yZõ'NCQ¶Å JÚýg>m=¼FøòÛ/áö»iô¢•š‚ (C‹[K¶bÄS#pñ]ãío«‘†q™åÓ–ÃrÑ$¥A¢m[í,â˜Q»Ôolý>®ýçfæbx¯áqŸ? ÂívŸ¬_¿~(óó@µì z“_Ì ðð½ùæ›<OÈŒÍ=±ßD4Ikb¬ZÝxJâœÂ¡S‡°õ V È_—oùV]øÓ¦ ̱Ðù‚S A¾;wn3;$8âÂ̯‘´ì|Å&qöC}§zöKN–àާ¿ƒ[åW"Îlòq—,äPßcä®[ˆq3Æ!od†NŠÙ gcÓ¶M…UNú¶§‘L£¦@ȘÉæ‡vÄÿü–+£éý‰ÊôJû–†õfªª¼^/vîܹ 2¯ò ª–úB“é DÎÊc®™.4רQ£v ,˜™››kj1¦›^½ ÅÅŠ­Ç–q,êl,ÍòNÑ–yª‡uÔ“¨XÃV|õàW°+þ2ã/øuׯÜTætY ˆösÉ&%  QR‘“*Êä.» ψ+.º—^p)æ-›‡¥¿,Uæ(‹ÝóÇbtž}t=¿&®…™¸!õY›d4Áûš[d¥¸¸˜Lžº›î`=<_¹L* ºã±z†¤08ó!€ÎpÊs6$ÕÆ‡ 4ÛP"M›Å X¨P 69ÿ„Üû !A]¡ˆ°DäLOë9õê<€ïýõê> j“{ÿN-:aÒ€I¦^©¢¢óçÏ_ÀÊg>Ô‚úÔ,?  ¨õFzxvïÞ}¸¨¨è Çã1 2¶÷؈ˆ(}Ô i=§¦=²FCŠI:³òôa9!‡˜)Òy)Úéà 뙯ÀNýb*÷Ïî#ºDˆN‘–‘{ ÃѧXíG?<È1»Ò~ù.¹]¹xŒ)þðx<8räÈÁÝ»w†*øÀ¹Ç«+Ø+3-€9=RR4 ŠõÝÌì×÷Ú$ò˜©vÆ ë)a¤ú‡»®½ fáñxÈìٳ߃Úû3õ¿ÆÎ?†šjZ hEEEÇ~ýõ×­fç\Ýãj ¿hx£G`wç·FOÇ“Ù7Jôœ$êñ¾M¬ö ;_3T­]ñ×3j†cüLP°6|mïk1´—¹¨¿ŠŠ lß¾}[QQÑ1h{^Ô¸…ÖF’h^ ðƒ>h€Š3f|ìv»ƒfæÀÃCFvZv¤í¤³Í<ªÃØF=Oõ 3õ븎Y(N¶¨ç'Êü|ûä’}°vÜ8­1õ¨©×•cþƒ?þøRȼÊW,ú/áyÿÑP€^ ð‚J¬òp8\¾téÒ^Ÿ×ô´Ñ†>1k*‚xÍ –šfV}LTõ7Pÿ’æC-Q"õ¯Œ^Ýg*¿ÞÞ7ãè‹RN¯öG›ó?eäÓ<àõy±lÙ²áp¸”—܈TÿÉòåË jˆÚZ&‚½2‹ ð@~ð÷Þ{oÓÁ‹Í:ûwêúß ÿ±Q½=ÅûôN—ÚhxµÕx¡ÓÍ|uÍȵQ‰Æ7ì8ôçÆº÷¿f¤JnƒüÔ_¶üøØc1°ë@˜×ëÅ¡ƒ‡ŠßyçM;R¨ê?‹ø«•Þ¨ K!m`Tm)PþÏþs‰Çã‘Ì$€;®¼½ÛõV+QNF®Ä9 y©«× ªÓ£huJ±´ž³êª>Ì”•´¿•éáÇ4G´}úã¬CâÚ¡ÒƒÐ´Ë Û]ˆ{†Ü3³ýHÓ§O_™w@ùÈ ]àOmôþ@í.%A òÇŽ+þꫯLO€g&>ƒÍ:¨š/Uu0®9P[=mCìÉë’êBÐ÷ø¼s.VÏ®¿†þ7Û²^^'(øi¾ŒùÛ5k‡çÿü<ÌÂç÷á믿^wìØ±bhëýkø£G­N  Õ˜ Söꫯ~sàÀcfMxñæÑ<³¹6…XH›JIŸZ<á4M±Ò=U—L$+IR-Ôk´ô\úòFÿë÷•×§ ëÊ…¹ýºvÙ,«þ}û¿M·u¯×‹û{å•W¾P&ó ³ýYï/¡{ 5ù¡˜BÄûÊA_¨ìÑG]\QQ ¦®éLqbÖM³èâ¢|Je¦ösR\ãØÁ6¢õ0Iœ^˜ýºã~@ÛH”ý<$Ý~ùÞÃ@íñ¹¶™žgn}ÎgŒ‡VPQQzôÑGCe~½í®Mæêf­X^ Ѐòòòã ,ø4‘Q¼Fyxì¡‘£‘FýWl0NÓÄ`ëÕ·ê¨æI5¿n©&&€®¯–#ºkÆ2 ºòì|V`‚ˆ`5"h”Ú -·LÈë¿hÑ¢ÏÊËËK@yåTÀ÷þµŽZ²tbUÄÇ”ƒ¾Ô©üüü_6oÚ¼Íì\èž×ówd¥f©3¹¸yÕš„¢ú‰CŒô  ®o’jÆàñê[ÞoÈôF í·£=«†ùy4¥ d82ð·?þ =Ûô„Yx<lÞ´yÛ§Ÿ~ú3€“Ð2¿fÜ¿¶{ îV‹— æ dA&ÙN=ñÄŸ:t¨4ÀEí.ÂÔ‘S‘åÌŠL®À;eIÍ'cáŽy’OwO˜¤ØÌ®ûFQ{{#Æ7bl£²|;áþ×d¡æ:ý$ŸLg&þ:ö¯èÛ±/ÌBŽõ/}â‰'>ÊeP5Ê÷gµ.tÂ,8H£({衇þ[^^0³¬Ã%/Á´±ÓÐ(­‘æ£(Á wP>6t[Â]8^ƒL¢ö‘@}ëUæ˜×‹¶Ï蘾Œ¤ÝLJó*š€®­‘0A£´FøûÿŽþ]ûÇo~¿ååå‡zè¿ LªýïAý¡N4€(¦ÓN8éñxŽÏœ9óŠŠ ©ªÊ\Zg€j9é9ê¾&&€Ip]˜fÌF §»G<)ZUØÈÑ G¹žþÇb~ÀXË`í†Óô±$D~ÿ¼éŸèÛÉ|Ï_UU…ŠŠ iæÌ™ïx<žãyjï_çª?C]™ ´Yƒ*@5€Nnß¾½`þüùËÝn7 …B1.£E÷–Ýñì¤gÑ<«¹6 C ÁíÓ Æú9íŒÑ(–C,îù±L·x&‘YÁz}®G7Œ:ei²qK¹Y¹xfò3èÙÚ¼Í …àv»Éüùó?Ù¾}{(ãŸå 7´Ù~êLõg¨3` 7N8¹jÕªm}ôÑ7^ŸfÖdÔ*§^½óU´oÚ^ý8цÍ8¢X¨í˜€$E2y¢ŽA³ÇÝÇÛõ¬‡—tûùÀN´kÖ¯ÝÿÚ6ikú½Ãá0¼>/>úè£oV­ZµZæçUÿ:ó7Bj1F˜)P àä’%K¾[ñÅŠÍlxÐ,œ)Nüç®ÿ wûÞʪÃÊûßH 0Z’LÿákêÑNôü†D‰h ‰ …hûÂÿËûX»Ð)ÚߦÂv¼¯ßÿºéq~€v,^Ÿ+¾XñÃ’%K¾×þAù¡^¼þzÔµ ÀÀX`Z@)€“óæÍ[½zÕê_`˜}ólÜpÙ ‘¡Â²ª¦ßÇ÷ôša $ÔP«ÛÈ“T;õñ%ƒÿY`£E!h‘TÆçÛÕ¸ãðÜäç(¼^/Ö¬^ó˼yóVAe~Öûë½þᨪeT7+°i,_¾œŒ=Z­^–€%d²p$Ι3çK»Ýn½üòË{¦¥¥­I·_s;º·îŽ—>{ %%4´úqE@ ÜúÔTPQSPñëði© Û—DÍPÝ~-ÞyÄ  ¿ûáoà„‡~D‰„ ²]Ù˜2z tØ#¯×‹õë×ÿúüóÏ µÓãí~½êúèýzÒtCƒ,TØ ­)P  tÖ¬Y_¬Zµj‹Ç뉻Λý»öÇ»}Ã{ðDŒèˆ95½…¾Aƒ}µÓÝëÖ7U·n¢çµ…hû%h¿šï¯ŸåÇk !‚¡}‡âƒi$Ìü’$Áãõ`õêÕ[fÍšõ¸vÚîË¡Æú+ |Öóõ 0Èš@_’e4©)Í™3çK¿ß>bx_gªVkbùШ‡Ð£m¼úÅ«t•Y‰Þ…ˆôà ¢bpgY#")aˆ¦$µƒÚ™¦M ôô PýJ1ÌM̈Ìü®Tîq†\d.ƒ/æð[ñÅŠçÍ›·*ã—€öþl¦Ÿá·^™¨ÞÒ`,_¾<¡Êæ€*|ìÒ@—k @™r&MšÔ̘1222»ÝžÐ}^üôEäoÎW—c MòÙg @·ÊûG3 Ì0~R8DÂŒ:o¿‘ºÏ¶ŒñõBAÏølTP‚Á°‹‡á‘1˜y“¸Ýn²|ùòo-Zô=TÆgÌê<%Ú¯:Ì/wª†0ãP¯w(B€Ùþ)œ2@×dB @ΕW^Ùý¾ûîžžž.:Ž„ï«·®Æ§›?Å΃;UA BÑAˆ)òê5ú*‰÷Æ0Ûܘހù H$£†ÌO@"Ì="tkÓ #/‰«/¼º/TVVÂãñHóæÍË_³fÍDöüúñþ0j0˯¦ ÞL0O' äÙFù\kÖ¬ùõСCî'Ÿ|ò†ÌÌL›Ói~è…aðƒ1ø‚Áxoý{Èÿ!ÅeÅôêʲs´á(j¿ÉOE@4ûšk)OÏp® ƒºTXc0;ÝèT{@íÍÙoþ1?·Q.†õ†‰˜XíÇõù|(//NŸ>ýÃÝ»wï‡êð+:чOðÁ¼T§ §E-ˆÔ\²@5™§§§7yá…nhÕªUc3ëÆÂÛß¼üòQZQÙóËÿ-T¡DÑèFWoz!‘„1 ì{ £óå¢m|ÃóŒŸãÊÁ°K†áæÁ7×è±å‰='~øá¹ð^Þáw jnÍp_Mìþ³Ò`ˆ#2¡úräßþþ÷¿_Óÿ²þç9S°ÙlÕ¾7,ùf Vþ´ŧŠÕñ@HHÄú­G½ºzÎBõþñ@4€ÝŸÛ(Cú Á¤Á“jô˜Á`>¿ß÷ýo³fÍúj\?êcÞ~Þ¿¦N¿³Z†BÀ @:¨&ÀüŠ:thÛn»mpzzº¥:&+Z‰Ï7}ŽÝGäUŠüL ð>€x ‰šA? GD0¼Ž!èÒ² †_2Ãú«ñãù|>x<žð›o¾¹zÅŠÛA{y}ïígQ~µÂüÀ9 €˜B ªsi4ÊÊÊjòôÓOj×®]¶Ãá€Åb1¸rbØW¼˾_†»6¢¼¢<ºcÐjü>ýï¤êŸŒš£d|\Ãðì˜Þæ'™é™¸ä¼K0fÀtÈíPãG ‡Ã¨¬¬Daaá‰iÓ¦}RVVV•ùY¯Ïœ}^Ôóçˆ4B€ Ú@M‚t¨~¦ 4–ÿϼí¶Û.>|å¶IDATxŸ´´4155µVž #k·®ÅŽý;àö»#„ 1´ˆƒxߣ!ŠDš=sº2i¶?!.‡ ÝÛuÇ ^ƒpU¯«jòÄøý~x½^)??ÿÇ7ß|sÔ”wüÄ6­—-æ!' ¯ý(¿sF0pqPAàõ ¤ƒú˜6 œœœ&3gÎÞ¦m›œTGjÂCñ°zËj|ÿÛ÷ØQ¸¥îR•±õÂ06 ôÇx$}ZÕ‡ ‡AvF6º·ëŽþçõÇUÕÓt¯¿Òûœ˜>}ú祥¥%Ð2¿>[ÇO™nVA>çœ!ÀblÐú2@ŸiACÆØ±c{Ž?þ2—Ëe­ ߀~?ú;~Øõ ‹ q°ä Ž–…?è×zýÍøÌöö A@D{Ç(6?Aª=ͳ›£UÓVh—Û}ºôA—¼.uòx>Ÿ¡÷ßÿ»¥K—þ 5Ý=cú2™X\?Sùë<ÂFðQƒLÈ€*A¢(º}ôÑAýúõëìt:…Ú4 ¢¡øT1–ÄáÒÃ(>YŒ’ò¸½nx*=ðú½ðWù ÓyP•U•š1\Ø€À«÷‚ Àa§^6‹ ©)©Hs¤!=5iÈÉÌAóÆÍ‘—“‡6MÚ ·qn?Ÿßï‡Ïç#?üðÞgŸ}v­$I LΞ1?[¿_½—©üuÞ{Î ÀÐ9ÈüL`Ã…YeÈÈÎÎnÞÃÏz}~ù®ZuöEÃ9-€ç Õ$Ðûô” ½uëÖM~øá?´iÓ¦iR$ Œñ8pü…^øæàÁƒ%Pº-7 ÞÖg*?›cX/SzÏyÀ 3 ØP!ï`þ^d°cmÛ¶mrï½÷ìØ±cnjjªàp8Ê7Ĺ B*++á÷ûÉï¿ÿ^üòË/oØ¿?c|e•k¨LïæŽ1[_Éâƒ:Vùõh0ˆÐØ(jaTAÀ“KÞŸær¹2xàþ\pAÛ´´4KJJJ­$qæ# ¡ªª ^¯7¼uëÖýsçÎý¾¢¢‚Û{@U{·ŽX(/‹èãCzë5‘Cƒ Úó  TMÀ%sH;vìy×^{mÏœœœŒÔÔT¤¤¤@ë+KZõ I’PUU¿ßÒÒR÷Ê•+]ºtéo =¹ê²ö¬çgB@Ïø¼­_ï½>)Cß âýLð&ûí”ÉѤI“¬É“'_Ô³gÏV.—+ÕápÀn·'…Á9I’PYY‰ŠŠ ÿ¯¿þzhÁ‚?—”””Úî>¨ Ù2Æ÷pÄŸ·óùU)ë½×çÑ`ƒn¤@Eèõ ƒtnª\ÖÑ¢E‹ÌI“&õêÖ­[^FF†3%%E°Ûí°X,IŸÁY–~; ªªŠ¸ÝnßÎ;,^¼xKQQQ9(#W‚öúŒ¹=0fz¿\–õø|êÐÓÊø ^0˜¼£ÐU+`LÏÛçà(Åjµ¦Œ=ºÓ€:4kÖ,Óáp¤ØívØl6X,ˆ¢˜ §„H’„p8Œ`0ÈzúªcÇŽ•oܸqßÒ¥K÷„B!¦²WrÄÜ«#¦ °r¼ƒï´«ûFH œ6M°Q& xíÀÉíce˜_ÁÀf·ÛS† Ò¶OŸ>­[´h‘•‘‘á´Ûí6«Õ «Õ QM§$ª£…5$IB(B(B ºÝn_QQQÙ?þxðË/¿ÜX‚ÍT{õøÌÖgÌïãö±2Da|àÌèõy$€b´~ÞLàÉÉígå˜a×°ÊdéÕ«W“nݺ5iÓ¦M£¦M›f¸\.GJJŠÝn·[¬V«EEeÖ@R D׉$I$ …@¸ªª*PQQQyüøq÷Níܹ³dË–-%P³L‡@Uô Tæå{}Æä~UråÜ5ÎxÆg8íà ‡^ðÇŒ‘Y/Ï› FÄ—Ó  ·¹­QúXÏÙ«áé§ûè’w+CoÑ_¯òë‰/ÇÎׯe”’ä¬BRh¡5`C^Øu”¢#~+ÏÎW4¨ !…óó‹yñ=>SõÙ´ll¾JGñLÏ{ôÙ„ã³–éy$€1¢i¬ç 4â{|;"™?Â,@¤ña0Ñ7*óóL̘šgnÆì!D2¼~ȳ¾·7™žøtAßÈXÃÒ ^­gŒÎüVÝ>+¢3?¿AæÁeñ3Œ‘yÆêöñæBƒ`úDÑXÂ@ï@äã ,q(ó'A|è³ DH¿Ø›þ  ]ð0Ê,hÕxQGl!‹Á±h9ƒŒÐƒ&Ô›úý˜Ð޶¦p”l‚I0$€1øÆ†qbp^(°-´ûk Ñü€ñ®zÁdxH sˆÖ°¢ D)“DbÐ3q’ÑkqG’H"‰sÉénI$Ñ€‘I$Ñ€‘I$Ñ€‘I$Ñ€‘I$Ñ€ñÿì%´³ü¬cxIEND®B`‚olive-continuous/app/packaging/windows/olive_ove.ico000066400000000000000000011124361370472574300233050ustar00rootroot00000000000000 (Öèþ èæ00hÎh6 Èž ¨f00¨" h¶0 ˆ 5  ¨¦>00 ¨%NO ( öt( L²T`¸h©¬ª„µ¹¶–Íœ Ë¤©Ê³ÂÉÇÃÖÉÏÓÑÅãÈÝáÞèíéûþüÿò"""""ÿÿ(ˆ¨ˆ„„/ÿ*ª¨¤ah/ÿ*ª§—1:/ÿ,ÌÁ¡vZ/ÿ,ÌÐUœ/ÿ,Þ0œÜ/ÿ-ÝÝÌ/ÿ-æ5œª/ÿ.ÛíV¤D/ÿ.¾îîNêÿÿ.¾îìNÔÿÿ.îîìNOÿÿ.îîêH/ÿÿ.îîìBÿÿÿ""""/ÿÿàÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ(0†‰‡2©:ž¡Ÿe»m§¬©‚ˆ“Èœ¨Ô¬µÐ½»ÎÂÆÌËÖÛØäéåúýûîîîîîîîîîîîîîà""""""""îî⪪ªªªªªª.îî⪪ªªª¤©ª.îî⪫ªª©Cª.îîâ«««š¹S5ª.îîâ»»»9¡eZ».îîâ¼»»q—5».îîâ˼ÌSSk».îîâ̼È5S¼¼Ì.îîâÌÍ1U3ÌÌÌ.îîâÜÍ5cÌÌ».îîâÌÝ6œÌ»«.îîâÝÕ—1›ºª.îîâÝŒÝÜÜ¢"".îîâÜÝÝÜ-ÝÔ.îîâÖÝÝÝÛ-Ý¢îîîâÝÝÝÝË-Ü.îîîâÝÝÝÝË-ÔîîîîâÝÝÝÝË-BîîîîâÝÝÝÝË+.îîîîâÝÝÝÝË"îîîîä""""""îîîîîîîîîîîîîîîîÿÿÿàààààààààààààààààà?à?àààÿÿÿÿ( @‚€ˆ‹‰•˜–*Å5Ÿ£ YÐd¶¹·|Ú„žà§ÎÒжà¿ÌîÒßçæøüùîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîâ""D$$$DDDDîîîîîLÌÌœÉÉÉÉ™œ™Nîîîî,œœÌœÌÌ•ƒ¼ÌNîîîîLÌÌÌÌÉÉ¥8¬ÌNîîîîLÌÌÌɌLj3¬ÌNîîîîLÌÌÌÇ|£¨‹ÌÌNîîîîLÍÌÍÃŒU¬wŒÜNîîîîLÌÍÌÃww…7¬ÜNîîîîLÜÜÍÓ‡x«ÍÜÜNîîîîMÍÍØ‡‡SÜÜÍÍ.îîîîLÜݳwxXÍÝÝÝNîîîîMÝÝÓw£5ÝÝÝÝNîîîîMÝ݇§W½ÝÝÝÝNîîîîMÝÝU5wx­ÝÝÝNîîîîMÝØÍØsWÝÝÝÝNîîîîMÝ»ÝÝÝÝÝÝÌÌNîîîîMÝ­ÝÝÝÝÝÌÌœNîîîîM×ÝÝÝÝÝÜ™ffNîîîîMØÝÝÝÝÝÆfffNîîîîMÝÝÝÝÝÝÄÝÝÔ.îîîîMÜÙÍ™œ”ÝÝdîîîîîMÑdÑM œ”ÝÙNîîîîîM”М”ÝÄîîîîîîM”Ñ–,É”ÝNîîîîîîMÑ&)fi”ÖîîîîîîîMÝÝÝÝÌÉ””îîîîîîîMÝÝÝÝÝÙ”NîîîîîîîDDDDDDDDNîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîÿÿÿÿÿÿÿÿø?ðððððððððððððððððððð?ððÿðÿðÿðÿðÿðÿÿÿÿÿÿÿÿÿ(0`|}‡ŠˆÌ$§ª¨BÏM_Òj~Ö‡¤Ü¬ÈÐËÄíÈÞçåñõòûÿüÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÓ333333333333333ÝÝÝÝÝÝÝÝ8ªªŠªŠªª¨¨ªªŠŠŠ¨=ÝÝÝÝÝÝÝ:Ѝª¨ª¨ªŠªªŠ¨ªªŠ=ÝÝÝÝÝÝÝ:ªŠ¨ª¨ª¨ªŠ¨ˆˆx¨ª=ÝÝÝÝÝÝÝ:ªªªªªªªªª¨Gb*ªª=ÝÝÝÝÝÝÝ:ªªªªªªªªªŠ%$ˆªª=ÝÝÝÝÝÝÝ:ªªªªªªŠª¨x%&Vªª=ÝÝÝÝÝÝÝ:ªºªªªªgª©)F")ªª=ÝÝÝÝÝÝÝ:ºª»ººª&ª„(e$šª»=ÝÝÝÝÝÝÝ;««ª««§&ºbVšªª»ª=ÝÝÝÝÝÝÝ;«««««¥&ªBY©Ugª«=ÝÝÝÝÝÝÝ;»»»»»´'hDzb"%»»=ÝÝÝÝÝÝÝ;»»»»«²&'Dd"V«»»=ÝÝÝÝÝÝÝ;»»»»»´)&Y™«»»»»=ÝÝÝÝÝÝÝ;»»»»©”iFT[»»»»»=ÝÝÝÝÝÝÝ<¼ÌËÌbTµe"lÌ̼¼Ë=ÝÝÝÝÝÝÝ<¼»»É"eUtEœ»»¼¼»=ÝÝÝÝÝÝÝ<ÌÌÌË"bWdBKÌÌËËÌ=ÝÝÝÝÝÝÝ<ÌÌÌÌGG¤"&¼ÌÌÌÌÌ=ÝÝÝÝÝÝÝ<ÌÌÌÇD—BWÌÌÌÌÌÌÌ=ÝÝÝÝÝÝÝ<ÌÌÌÂ$$i§zšÌÌÌÌÌ=ÝÝÝÝÝÝÝ<ÌÌÌe–"$""&ÌÌËËË=ÝÝÝÝÝÝÝ<ÌÌÉ\ÌÌd"EœÌË»»»=ÝÝÝÝÝÝÝ<ÌÌ¥ÌÌÌÌÌÌÌÌ»»ºº=ÝÝÝÝÝÝÝ<ÌÌ[ÌÌÌÌÌÌÌË»»««=ÝÝÝÝÝÝÝ<ÌÆ|ÌÌÌÌÌÌÌË»ªªª=ÝÝÝÝÝÝÝ<̵ÌÌÌÌÌÌÌË£3333=ÝÝÝÝÝÝÝ<ÌdÌÌÌÌÌÌÌ»;ÌÌÌÈ=ÝÝÝÝÝÝÝ<̶ÌÌÌÌÌÌÌ»<ÌÌ̃ÝÝÝÝÝÝÝ<ÌÌÌÌÌÌÌÌË»<Ì̺0ÝÝÝÝÝÝÝÝ<ÌÌÌÌÌÌÌÌË»<Ì˸=ÝÝÝÝÝÝÝÝ<ˈ̸̃‹¼»º<Ë»ƒÝÝÝÝÝÝÝÝÝ;Á1Œ0¼;Ì»º;»¸1ÝÝÝÝÝÝÝÝÝ<°¸<Œ ÌÌ»ª;ªƒÝÝÝÝÝÝÝÝÝ<¡È<Ë»º;«3ÝÝÝÝÝÝÝÝÝÝ< È8»Ì»¨:ƒ=ÝÝÝÝÝÝÝÝÝÝ<Áƒ< ‹Ë»ª8ƒÝÝÝÝÝÝÝÝÝÝÝ<Ê3ì:3;Ì»ª8=ÝÝÝÝÝÝÝÝÝÝÝ<ÌÌÌÌÌÌÌÌ»ª3=ÝÝÝÝÝÝÝÝÝÝÝ:ÌÌÌÌÌÌÌÌ»º3 ÝÝÝÝÝÝÝÝÝÝÝÓ33333333331ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( A®KO´VX°aR³ZU²^\³d_¶g^¹f_ºgg»ow»~kÀsªªªs¾{«««t¿{¬¬¬{½ƒ­­­¯¯¯}Á„±±±†ÁŒ|Å‚²²²´´´“À™µµµ„ÇŠŠÅ‘ŠÇ¸¸¸¹¹¹žÃ£–Æœººº»»»–É›½½½¾¾¾—Щʰ«Ë±ªÍ¯¾ÈÃÂÈÈÉÉÉÃÊɧ֫ÄÊʤשÅÊÊÅËËÉÌÊÌÌÌÂÑÇÊÏϱڴÊÐÐËÐÐËÑÑÐÑÑÅÕÉÐÕÕÓÕÕÑÖÖÒÖÖÊÚÎÇÝÉÒÙ××ÛÛØÛÛÛÛÛÐßÓØÜÜÝÝÝÜÞÞÞÞÞÉçËÜààÍçÐÞááßááÕåÙáããÎëÑäääãååãææãçæäççèêêßîáçëéìììêííëííìííåñçñòò÷÷÷÷øøøøøùùùúúúúýûüýýýýýýþþþþþÿÿÿooooooo1443311//,-ooo<;;;;;:!8oooBBAA*7) ?oooJJGF>+"EoooQQQQ %COoooZZY IXXWooo`_]S[TRooocc0 (DL@=oooebPd\295$ ooolNkkkja'nn6ooooiUnnnnV&n^oooonnnnngM$kooooonnnnnfH#.ooooomnnnnhKoooooo oooooàÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ(0žž¡&'¥1„„„,¥5‰‰‰6¨?‰ŠŠ8¨A@¬JC±ML²TT°]˜˜˜S²[P´Yœœœ^³gb³jŸŸŸX¹``¶h   `·h¡¡¡^¹f¢¢¢c¹j£££k¸s¤¤¤e»l¥¥¥jºrf¼o¦¦¦§§§j¾rk¾swºoÁv{½‚~¼…sÁzy€ƒ¿‰‚À‰xÄ~Â…|ăƒÂг³³„ÅŠ‡Ä†ÅÅ’¸¸¸»»»œÇ£Î••Íš«Æ±£Ë©¤ËªœÑ¡µÇ»±Êµ²É¸šÕžÁÆÆÆÇǡզÂÈÈÀÉÆÇÈÈÂÊÈÅÊÊÉÊʶн¶Ò·ÅËËÆË˺ѾÆÌÌÇÌÌÍÍÍÁÐÇ»ÓÀÉÎÎÉÏÏÊÏÏÊÐÐËÐÐÐÐÐÐÑÑÀØÃÎÓÓÏÓÓÓÓÓÏÔÔÐÔÔÒÔÔÓÔÔÔÔÔÕÕÕÑÖÔÔÖÖÏ×ÕÒ×××××ÔØØØØØÏÛÓÕÚÙÙÚÚ×ÛÛØÜÜÙÜÜÚÜÜÙÝÝÌãÏÚßÝÉæÌÛßßÜßßÝßßÝààÞàààààÝááßááÛâßÐçÒÌéÏÞãáàããâããáääâääâååäååäææàèâãçæåççåèèèèèßëâæééçéééééêêêëëëêìììììâðäëííéîëçôèïññðññòòòôõõó÷õðùñö÷÷÷÷÷÷ùøøùùùùùûûûüüüûýûýýýýþþþþþÿÿÿ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²FIIIIIIIIIIIIIIF²²²²²²UTTTTTRRRQQJLBMM²²²²²²]]]]]\\[[[> DZY²²²²²²eeddddWWbC( +aa²²²²²²ooooooOl;.*jmm²²²²²²xvvuuuX? S@/rt²²²²²²‚‚z6"38q}|²²²²²²ŒŒŒ‹„`71‡Šˆˆˆˆ²²²²²²–••• -5#’’‘‘‘²²²²²²,2='&šŽƒ~€²²²²²²¡¡ ” )0Ayž‰wkfg²²²²²²£££<…H Ps_NGK²²²²²²ªª{œ©©©¤¨™:!²²²²²²¯Ÿ†®®®®®¦«±±°4²²²²²²±E¥±±±±±¢°±±V²²²²²²²±­±±±±±±›p°±“²²²²²²²²±±±±±±±®—i°§$²²²²²²²²²±±±±±±±¬“c°9²²²²²²²²²±±±±±±±¬“h^²²²²²²²²²²«±±±±±±±˜n²²²²²²²²²²%²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²ÿÿÿàààààààààààààààààà?à?àààÿÿÿÿ( @€€€ƒƒƒ‡‡‡‰‰‰ŽŽŽÀ"À$Á%Á&•••Á*Â+#Â0˜˜˜$Ã1™™™(Ã6&Ä40Æ>1Æ>   7ÇC ¡¡¡¡¡¡¢¢¢¢¢£££¤¤¤=ÊIBÈO¥¥¥¦¦¦DÉQ§§§BÌNDÌOCÍN©©©GÌS¬¬¬SÍ^OÏY¯¯¯WÒa[Ñe²²²cÑnµµµcÓmlÏy¶¶¶`ÕkeÔogÓrdÕm¸¸¸kÔu¹¹¹oÔyi×rsÓ}»»»lØuuÕ½½½sØ{|Ô‡¾¾¾¿¿¿}Ö‡{×…}ׇÀÀÀÁÁÁ„،‚ي‡×‘…Ø€Û‰„Ú‹×–ŠØ”„ÛŒ‚܊݈ŠÙ”ÅÅÅÆÆÆˆÞ—×¢‡ßŽ‰Þ‘Ý•ÉÉɛ٦ÊÊÊ٦ߗá–ÌÌ̟۪ݦÍÍÍÎÎ΢ݬÏÏϨܰŸà§Ÿá¥ÐÐСᨥᬬ޵§à°¡å¦ÓÓÓ æ¦ÔÔÔ©ã°µÞ¿ªã²¸ÞÁ¦ç«ÖÖÖ¹àÁ×××¬ç±³äºØØØÁÞ˰ç·ÙÙÙºã°èµÑÚÚÚÚÚ¯ê´ÛÛÛÜÜÜÀæÇÌâÔÞÞÞÑàÜßßß»ì¿ÊåÒÖàà×àà×ááØáá¾îÂØââÙââËéÐâââÚãããããÚäãÛäääääÜååÝåååååÝææÞææßææßççÓí×àççËñÎçççàèèáèèèèèáééâééÞëäéééÝìäãêêäêêêêêäëëåëëëëëäìêåìììììÙóÜçííèíííííèîîêïïïïïèðîéðîÝößëððìðððððåôèñññíòòîòòèõëïóóóóóîôòæøèðôôñôôïõòôôôçùèñõõòõõõõõöööìúíô÷÷õ÷÷÷÷÷õøøöøøøøøðûñ÷ùùøùùùùùøúúùúúôüõ÷üøùûûúüüûüüüüüüýýýýýþþþþÿþþÿÿÿÿÿ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷‰••••••••••••••••‘••‰÷÷÷÷÷÷÷÷÷•••–—————˜˜˜šš3\„›››÷÷÷÷÷÷÷÷÷žžžžžžž¡¡¡¡¡ |"az£¤¤÷÷÷÷÷÷÷÷÷¤¤¦¦§§§§c¨©DgS m«®®÷÷÷÷÷÷÷÷÷®¯¯¯¯¯±²>O² skT”¶¶¶·÷÷÷÷÷÷÷÷÷·¹¹¹¹ºººX½0*‡³PGh¼ÀÀ÷÷÷÷÷÷÷÷÷ÀÀÁÁÃÃõLAHIt<ŽÄÄÄ÷÷÷÷÷÷÷÷÷ÉÉÉÉÉÊÊÆ n7Rr‚œÇÎÎÏÏÏ÷÷÷÷÷÷÷÷÷ÏÏÑÑÑÑq{:yN(ÓÕÖÖÖÖÚÚ÷÷÷÷÷÷÷÷÷ÛÛÛÛÛª2UQo._×ßßßßßàà÷÷÷÷÷÷÷÷÷àââããÌ$Vd…6Ðææççééé÷÷÷÷÷÷÷÷÷êêêêíCˆ^%^¿îïïïïïïïð÷÷÷÷÷÷÷÷÷ññññì+8 5[W=u“óóõöööö÷÷÷÷÷÷÷÷÷ööööwÙöÞ‹@&-eåööóèáÝÝ÷÷÷÷÷÷÷÷÷ööö¬Èööööööööööá;´°´÷÷÷÷÷÷÷÷÷ööÔ™ööööööööö󨾥’Š÷÷÷÷÷÷÷÷÷öö]ôöööööööööÜ­iZMJFF÷÷÷÷÷÷÷÷÷öö}ëööööööööä¾/9EBBB,!÷÷÷÷÷÷÷÷÷öööööööööööóËŸóöööÜ!÷÷÷÷÷÷÷÷÷öö­jèöŒ´öl`ƒ¸óööó4÷÷÷÷÷÷÷÷÷÷öË9ö)öbx¢~óööi!÷÷÷÷÷÷÷÷÷÷÷ö~'ð ö4€’póö­ ÷÷÷÷÷÷÷÷÷÷÷÷ö†ÝY9 ´vfóÝ#÷÷÷÷÷÷÷÷÷÷÷÷÷öè?†1K;Šbò4÷÷÷÷÷÷÷÷÷÷÷÷÷÷ööðÒöÅðäÒÍ»Šbf#÷÷÷÷÷÷÷÷÷÷÷÷÷÷äöööööööööòÂf!÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷!÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ÿÿÿÿÿÿÿÿø?ðððððððððððððððððððð?ððÿðÿðÿðÿðÿðÿÿÿÿÿÿÿÿÿ(0`wzxy|z|}~‚€‡ŠˆŠ‹Ž‘’•’•˜–ÌÍÎÊ,Ë.%Ç9œŸœÌ0*Í.Í2(Ê<Ÿ¢ ,Ï13ÉG¡¤¢;ÇO6Í>£¦¤KÆU¤§¥7ÍK¥¨¦HËRAÎK¦©§;ÒC§ª¨IÍT<ÓE¨«©QË[©¬ª^Èhª­«ZÌe`Êj¬¯­UÐ`GÓ\PÔ[¯³°^ÐiXÓc°´±qËykÍu²µ²S×_lÎvgÓigÒrmÐwzÌ´·µtÎ}pÒy‚͈^Új¸»¹fÚrº½»nØyhÛs»¾¼‘Ê¡¼¿½Ï™ˆÓŽ|×…qÞtwÛ‚„׌y܃…؆َÂÅÃך“ÕŸváÝ‹ŽÚ•ÄÇÅ~ሡԩÅÈÆ–Ú›ÚÆÉÇ’Þ™€ä‹šÝ¦‰å’•áœÊÎˬس¹ÓÁÆÐϵٹÏÒвݸÐÓÑÑÔÒ§ä«ÒÕӜ飵⵺ÝÅÔ×ո俳èµ×ÛØÌßÒÆßÔ´è¼»çÂÇâÏÛÞÜÔàØÉæËÏáÛÐåÐ×ààËèÍÞáß¹ð¼ÙäÜßãàÇìËÚããÇêÒÚåÝÔçÚáåâÛåäÄòÄâæãÜææÑìÙäçåÝççØíØåèæßèèæéçàééàëäçêèèëéâëëéíêÞñäêîëäîíØ÷Ôëïìæóäæððîñïïòðãøãðóñäùäñôòò÷íòöóó÷ôîûëôøõïúò÷úøøûùùüúùþôúýûûÿüüÿýººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººº'')$))$)))))$$)$))"''$'"ººººººººººººººººjƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒgººººººººººººººº$ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ$ººººººººººººººº'…ƒ……ƒŠƒƒƒƒƒƒƒƒŠƒƒ‡ƒƒƒiƒƒyJzƒ…ƒ…$ººººººººººººººº$ЕЕ••Š••”ŠŽŠŠ”ŠŠŠˆ]>ƒŠ$ººººººººººººººº$’Š”ŠŠŠ’ŠŠ’Ž˜”ŽŠ’ , }Š”ŠŠŽ$ººººººººººººººº$˜˜•••••˜••˜•œ•••˜Lt 36*@••••$ººººººººººººººº$™š™šœœ™šœ™šššBVššœh1>v™šš™$ººººººººººººººº$¢¢š¢¢¢¢¢¢š‡Mž‡zA% #€žš¢¢$ººººººººººººººº$ž§¢žžž¢žž§WN¦§@ /=‹ž›š¢Ÿ§ž¡$ººººººººººººººº$¦¦¤¦¦§¤¤¤§¤¤(S§ž3‰§k*7L•¢¤¤$ººººººººººººººº$§§ª¨¨¦ª¬¬¦ª¨ `>„(wŒB G §§§$ººººººººººººººº$ªª¬¦®¬¬¦¦¦¨¦ Td(A! 0f ¦ª¨¨¨$ººººººººººººººº'¯¯¯¬¬¦³¬¨¬¯ª|7Gv|‰ ¬¬¬¬¬¬®®¬$ººººººººººººººº$¬¬¬¬¬¬¬¬¬­h/Y€ G7<¬¬¬¬¬¬¬¬¬¬¬$ººººººººººººººº$³³³³³³³´±:43R- P³³³³³³³³³³³$ººººººººººººººº$´´´³³³³´“34,Rb9;€±³³³³³³³³³³$ººººººººººººººº'µµµµµµµµ²ZC{@  !­·µµµµ´´´´´$ººººººººººººººº'¸¸¸¸¸¸¹¸¯_%–( e²···········$ººººººººººººººº'¸¸¸¸¸¸·¹_(9vM C†¶¹·¸¸¸¸¸¸¸¸¸¸¹$ººººººººººººººº'¸¸¸¸¸¹¸­!!b€‚mM“‚¥¸¸¸¸¹¹¹¹¹¹$ººººººººººººººº'¸¸¸¸¸¹¹Q9£X \¸¹¹¹µ¹´´³³$ººººººººººººººº'¸¸¸¸¹¹sE¸¸¸¸©r9&O¸¹¹·µµ³¬¬ªª$ººººººººººººººº'¸¸¸¹¸“H¶¸¸¸¸¸¸¸¸¸¸¸¸¹¹·³¬¬ª¨§§§$ººººººººººººººº'¸¸¸¸±G°¸¸¸¸¸¸¸¸¸¸¸¸¹¹´³¬¬§œ™™—$ººººººººººººººº'¸¸¹¹T†¸¸¸¸¸¸¸¸¸¸¸¸¹¹·³¬§œ—””””'ººººººººººººººº'¸¸¸ 4¸¸¸¸¸¸¸¸¸¸¸¸¸¸·³~8$$$$$$$$+ººººººººººººººº'¸¸¹p¸¸¸¸¸¸¸¸¸¸¸¸¹¹³¬?—¸¸¸¸¸¹¹Iººººººººººººººº'¸¸¸«c¸¸¸¸¸¸¸¸¸¸¸¸¹µ¬¬'¸¸¸¸¸¹¹q)ºººººººººººººººº'¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¹·´¬'¸¸¹¹¹³™)ººººººººººººººººº'¸¸¹¹¹¸¸¹¹¸¸¹¹¹¹¸¹·³¬'¸¹¹·³8ºººººººººººººººººº'¹¹¬[q¸¹™U¹¹UKK§¸¹´¨™'¹·³ªU'ºººººººººººººººººº'¸¹a¸8§¹$5Ÿ¸¸³ª§”'´¬§n'ººººººººººººººººººº'¹™´[¹l¹”¸¸¹¹³ª”'¨™”u+ººººººººººººººººººº'¸…¹nªF"¹¸¸·¬§œ…'—…~?ºººººººººººººººººººº'¹”·ao~¹l—¸¹¹¬§™…'~uK'ººººººººººººººººººººº'¸µF F..³œFlª¸µ¬§™…'o^'ºººººººººººººººººººººº'¸¸‘'D´?x¸2~)œ¹µª§…"a+ºººººººººººººººººººººº'¹¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸µ¬§™…'8$ººººººººººººººººººººººº'”¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹·³§™…$$ººººººººººººººººººººººººº$"$$$$$$$$$$$$$$$$$$$'ººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººººÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?ÿÿ?ÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(  ­­­«¬¬¬þ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ¬¬¬þ®®®©¬¬¬þÄÊÊÿÅËËÿÅËËÿÅÊÊÿÅÊÊÿÄÊÊÿÄÊÊÿÃÊÉÿÃÊÉÿ¾ÈÃÿÂÈÈÿ¬¬¬þ«««þËÑÑÿËÐÐÿËÐÐÿËÐÐÿËÐÐÿËÐÐÿÊÐÐÿžÃ£ÿX°aÿ“À™ÿÊÏÏÿ«««ÿ«««þÒÖÖÿÒÖÖÿÑÖÖÿÑÖÖÿ«Ë±ÿÂÑÇÿ©Ê°ÿ{½ƒÿ\³dÿw»~ÿÐÕÕÿ«««ÿ«««þØÜÜÿØÜÜÿØÛÛÿ×ÛÛÿ_¶gÿÅÕÉÿU²^ÿªÍ¯ÿ–Æœÿ†ÁŒÿÒÙ×ÿ«««ÿ«««þÞááÿÞááÿÞááÿÞááÿR³Zÿs¾{ÿ}Á„ÿ–É›ÿŠÅ‘ÿÊÚÎÿÜààÿ«««ÿ«««þäççÿäççÿãçæÿg»oÿŠÇÿt¿{ÿA®KÿÐßÓÿãææÿãææÿãååÿ«««ÿ«««þëííÿêííÿçëéÿ_ºgÿ„ÇŠÿ^¹fÿ^¹fÿÕåÙÿèêêÿáããÿßááÿ«««ÿ«««þñòòÿñòòÿ§Ö«ÿkÀsÿO´Vÿ|Å‚ÿ—ÐÿÇÝÉÿÜÞÞÿÓÕÕÿÐÑÑÿ«««ÿ«««þ÷øøÿåñçÿÍçÐÿ÷÷÷ÿßîáÿ¤×©ÿ±Ú´ÿÉÌÊÿ»»»ÿ¹¹¹ÿ¸¸¸ÿ±±±ÿ«««þýþþÿÉçËÿýýýÿýýýÿýýýÿüýýÿìííÿ¾¾¾ÿÿÿÿÿÿÿÿÿÌÌÌÿ¯¯¯Â«««þúýûÿÎëÑÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿäääÿ½½½ÿÿÿÿÿìììÿ´´´ù¥¥¥«««þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿÞÞÞÿ»»»ÿýýýÿµµµþ¬¬¬S«««þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿÛÛÛÿºººÿÉÉÉÿ­­­½«««ýþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿÝÝÝÿµµµÿ²²²ø³³³ ²²²¬«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿªªªÿ¯¯¯ý«««CÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ(0 %9;;;;;;;;;;;;;;:.  ‰ŠŠª   ü¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ   ü‰‰‰ª%¡¡¡ûÁÆÆÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÂÈÈÿÁÆÆÿ   ü-   ÿÇÌÌÿÆÌÌÿÆÌÌÿÆÌÌÿÆÌÌÿÆÌÌÿÆËËÿÆËËÿÆËËÿÅËËÿÅËËÿÀÉÆÿÂÊÈÿµÇ»ÿÅÊÊÿÅÊÊÿ   ÿ.   ÿËÐÐÿËÐÐÿËÐÐÿËÐÐÿËÐÐÿÊÐÐÿÊÐÐÿÊÏÏÿÊÏÏÿÊÏÏÿ«Æ±ÿb³jÿ8¨Aÿ²É¸ÿÉÏÏÿÉÎÎÿ   ÿ.   ÿÐÔÔÿÐÔÔÿÏÔÔÿÏÔÔÿÏÔÔÿÏÔÔÿÁÐÇÿÁÐÇÿÏÓÓÿ±Êµÿwºÿ^³gÿT°]ÿ~¼…ÿÎÓÓÿÎÓÓÿ   ÿ.   ÿÔØØÿÔØØÿÔØØÿÔØØÿÔØØÿÔØØÿk¸sÿ¶Ð½ÿÏ×Õÿ6¨?ÿœÇ£ÿƒ¿‰ÿ{½‚ÿÑÖÔÿÒ××ÿÒ××ÿ   ÿ.   ÿÙÝÝÿÙÜÜÿÙÜÜÿØÜÜÿØÜÜÿØÜÜÿ,¥5ÿ»ÓÀÿ£Ë©ÿ@¬JÿºÑ¾ÿ¤Ëªÿ`¶hÿ‚À‰ÿÕÚÙÿ×ÛÛÿ   ÿ.   ÿÝááÿÝááÿÝààÿÝààÿÝààÿÚßÝÿžÿ`·hÿ‡ÄÿjºrÿƒÂŠÿS²[ÿÅ’ÿÏÛÓÿÜßßÿÛßßÿ   ÿ.   ÿâååÿâååÿâååÿâääÿÛâßÿÀØÃÿc¹jÿ†Åÿ~Â…ÿc¹jÿÞãáÿáääÿàããÿàããÿàããÿàããÿ   ÿ.   ÿçééÿæééÿæééÿæééÿe»lÿP´Yÿy€ÿ„ÅŠÿ^¹fÿf¼oÿãçæÿåèèÿåèèÿåççÿåççÿåççÿ   ÿ.   ÿëííÿëííÿëííÿëííÿsÁzÿ|ăÿ•Íšÿk¾sÿ'¥1ÿj¾rÿàèâÿêììÿäææÿßááÿÝßßÿÞààÿ   ÿ.   ÿðññÿðññÿïññÿßëâÿC±MÿoÁvÿxÄÿœÑ¡ÿÌãÏÿéîëÿëííÿâããÿÚÜÜÿÔÖÖÿÒÔÔÿÓÔÔÿ   ÿ.   ÿôõõÿôõõÿôõõÿΕÿÐçÒÿ¡Õ¦ÿX¹`ÿ¡&ÿžÿL²Tÿ¶Ò·ÿÙÚÚÿÐÑÑÿÉÊÊÿÆÇÇÿÇÈÈÿ   ÿ-   ÿùùùÿùùùÿÉæÌÿâðäÿøùùÿøùùÿøùùÿó÷õÿ÷ùøÿëëëÿ»»»ÿ¢¢¢ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¥¥¥þ$¡¡¡ÿýþþÿçôèÿÌéÏÿýýýÿýýýÿýýýÿýýýÿýýýÿö÷÷ÿäååÿ£££ÿûûûÿÿÿÿÿÿÿÿÿþþþÿ³³³ÿ˜˜˜Ä ¡¡¡ÿÿÿÿÿšÕžÿðùñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòòòÿàààÿ¢¢¢ÿþþþÿÿÿÿÿÿÿÿÿÍÍÍÿ£££ô+++¡¡¡ÿÿÿÿÿûýûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììÿØØØÿ¢¢¢ÿþþþÿÿÿÿÿèèèÿ¤¤¤þrrr:¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿéééÿÕÕÕÿ¢¢¢ÿþþþÿ÷÷÷ÿ¦¦¦ÿ}¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿèèèÿÓÓÓÿ¢¢¢ÿþþþÿ¸¸¸ÿœœœÉ¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿèèèÿÔÔÔÿ¢¢¢ÿÐÐÐÿ£££öUUU¢¢¢ûûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêêêÿ×××ÿ¢¢¢ÿ¤¤¤þ„„„6§§§™¡¡¡ý¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¤¤¤þŸŸŸuÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ?àÿÿÿ( @  ,0000000000000000000/# ………¡¡¡ú¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ú„„„ž" ¡¢¢ûÑÚÚÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÑàÜÿÖààÿÖààÿÑÚÚÿ¢¢¢û-   ÿÖààÿÖààÿÖààÿ×ààÿ×ááÿ×ááÿ×ááÿ×ááÿ×ááÿØááÿØááÿØááÿØââÿØââÿlÏyÿ—×¢ÿBÈOÿÁÞËÿÙââÿÙââÿÙââÿ¡¡¡þ!!!/   ÿÚããÿÚããÿÚããÿÚããÿÚããÿÚããÿÚããÿÛääÿÛääÿÛääÿÛääÿÛääÿÚäãÿ¸ÞÁÿDÉQÿ(Ã6ÿ›Ù¦ÿµÞ¿ÿÜååÿÝååÿÝååÿ¡¡¡þ!!!/   ÿÝååÿÝååÿÝææÿÝææÿÞææÿÞææÿÞææÿÞææÿÌâÔÿÙ¦ÿßææÿßççÿ|Ô‡ÿŸÛªÿ‹×–ÿ0Æ>ÿ#Â0ÿ¨Ü°ÿàççÿàèèÿàèèÿ¡¡¡þ!!!/   ÿàèèÿáèèÿáèèÿáèèÿáèèÿáèèÿáééÿâééÿsÓ}ÿ‡×‘ÿâééÿ¹àÁÿÁ*ÿ¬Þµÿ¢Ý¬ÿŠØ”ÿÊåÒÿãêêÿãêêÿãêêÿäêêÿ¡¡¡þ!!!/   ÿäêêÿäëëÿäëëÿäëëÿäëëÿåëëÿåëëÿåëëÿ1Æ>ÿŠÙ”ÿåììÿcÑnÿSÍ^ÿºãÂÿÞëäÿ…Øÿ}Ö‡ÿݦÿäìêÿçííÿçííÿ¡¡¡þ!!!/   ÿçííÿçííÿèííÿèííÿèîîÿèîîÿèîîÿÝìäÿÀ"ÿ„ØŒÿuÕÿ{×…ÿ}ׇÿ§à°ÿ7ÇCÿ&Ä4ÿoÔyÿÀæÇÿêïïÿêïïÿêïïÿ¡¡¡þ!!!/   ÿëððÿëððÿëððÿëððÿëððÿìððÿìððÿèðîÿÂ+ÿŸà§ÿgÓrÿ„Úÿ¥á¬ÿ³äºÿËéÐÿéðîÿíòòÿíòòÿîòòÿîòòÿîòòÿ¡¡¡þ!!!/   ÿîòòÿîòòÿïóóÿïóóÿïóóÿïóóÿ¡á¨ÿªã²ÿkÔuÿ©ã°ÿ‚ÙŠÿGÌSÿ$Ã1ÿîôòÿðôôÿñôôÿñôôÿñôôÿñôôÿñõõÿñõõÿ¡¡¡þ!!!/   ÿòõõÿòõõÿòõõÿòõõÿòõõÿÓí×ÿÀ$ÿcÓmÿ„ÛŒÿ€Û‰ÿŸá¥ÿ[ÑeÿÝ•ÿïõòÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿõ÷÷ÿõ÷÷ÿ¡¡¡þ!!!/   ÿõ÷÷ÿõøøÿõøøÿöøøÿöøøÿåôèÿBÌNÿ‚ÜŠÿß—ÿ°ç·ÿ=ÊIÿÁ%ÿeÔoÿèõëÿ÷ùùÿ÷ùùÿøùùÿøùùÿøúúÿøúúÿøúúÿ¡¡¡þ!!!/   ÿùúúÿùúúÿùúúÿùúúÿùûûÿ¬ç±ÿsØ{ÿ°èµÿ‰Þ‘ÿDÌOÿ‰Þ‘ÿÙóÜÿúüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿüüüÿ¡¡¡þ!!!/ ¡¡ÿüýýÿüýýÿüýýÿüýýÿ÷üøÿOÏYÿdÕmÿÁ&ÿ`ÕkÿˆÞÿ݈ÿi×rÿ¡å¦ÿ»ì¿ÿþþþÿþþþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¡¡¡þ!!!/¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ æ¦ÿçùèÿÿÿÿÿìúíÿ¯ê´ÿlØuÿCÍNÿWÒaÿá–ÿðûñÿÿÿÿÿÿÿÿÿþþþÿùùùÿ÷÷÷ÿöööÿöööÿ¡¡¡þ!!!/¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿËñÎÿÝößÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿñññÿìììÿéééÿèèèÿéééÿ¡¡¡þ!!!/¡¡¡ÿÿÿÿÿÿÿÿÿæøèÿ¾îÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿôôôÿìììÿåååÿßßßÿÜÜÜÿÚÚÚÿÜÜÜÿ¡¡¡þ!!!.¡¡¡ÿÿÿÿÿÿÿÿÿ‡ßŽÿþÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿçççÿÍÍÍÿÆÆÆÿÂÂÂÿÀÀÀÿ¿¿¿ÿ¿¿¿ÿ¡¡¡þ$$$#¡¡¡ÿÿÿÿÿÿÿÿÿ¦ç«ÿôüõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿìììÿ²²²ÿ¸¸¸ÿ¾¾¾ÿ½½½ÿ½½½ÿ½½½ÿ¯¯¯ÿ¦¦¦þ ¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿðððÿãããÿ¢¢¢ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿõõõÿ¦¦¦ÿ™™™Š¡¡¡ÿÿÿÿÿÿÿÿÿçççÿÎÎÎÿùùùÿÿÿÿÿÛÛÛÿéééÿÿÿÿÿÏÏÏÿÉÉÉÿØØØÿêêêÿÜÜÜÿ¢¢¢ÿþþþÿÿÿÿÿÿÿÿÿþþþÿ¶¶¶ÿ¢¢¢Ñ¡¡¡ÿÿÿÿÿðððÿ‰‰‰ÿ¸¸¸ÿ¡¡¡ÿÿÿÿÿ‰‰‰ÿ¬¬¬ÿÿÿÿÿ€€€ÿÊÊÊÿÔÔÔÿäääÿÖÖÖÿ¢¢¢ÿþþþÿÿÿÿÿÿÿÿÿÍÍÍÿ¦¦¦øwww¡¡¡ÿÿÿÿÿÖÖÖÿ©©©ÿüüüÿƒƒƒÿíííÿ•••ÿ‰‰‰ÿÿÿÿÿÿ¶¶¶ÿ×××ÿßßßÿÐÐÐÿ¢¢¢ÿþþþÿÿÿÿÿçççÿ¥¥¥þ“““;¡¡¡ÿÿÿÿÿÙÙÙÿ¤¤¤ÿöööÿ‡‡‡ÿÅÅÅÿ¸¸¸ÿ•••ÿéééÿ€€€ÿÓÓÓÿÞÞÞÿÜÜÜÿÌÌÌÿ¢¢¢ÿþþþÿöööÿ§§§ÿœœœ¡¡¡ÿÿÿÿÿùùùÿŽŽŽÿ˜˜˜ÿ»»»ÿÿÙÙÙÿµµµÿÁÁÁÿÿ£££ÿ¹¹¹ÿÚÚÚÿÊÊÊÿ¢¢¢ÿýýýÿ¶¶¶ÿ¢¢¢Î''' ¡¡¡ÿÿÿÿÿÿÿÿÿüüüÿóóóÿÿÿÿÿïïïÿüüüÿøøøÿóóóÿñññÿëëëÿâââÿÚÚÚÿÊÊÊÿ¢¢¢ÿÌÌÌÿ§§§öjjj ¢¢¢úøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿíííÿÜÜÜÿÌÌÌÿ¢¢¢ÿ¦¦¦þ———6¦¦¦¢¢¢ú¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¡¡¡ÿ¤¤¤ÿ£££zðààààààààààààààààààààààà?àààÿàÿàÿðÿÿÿÿÿÿÿÿÿ(0`   B]cccccccccccccccccccccccccccb[> ]]]q¢££ñ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ÿ¡¡¡òFFF–; ¥¥¥ðÉÐÐÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÈÏÏÿ¡¢¢òW ©©©þÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿÖààÿ©©©ÿ`©©©þÙââÿÙââÿÙââÿÙââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿØââÿ·ÔÁÿÕàßÿ×ááÿ½ÖÇÿ“ÊžÿÉßÓÿØááÿØááÿØááÿØááÿ©©©ÿa©©©þÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛääÿÛããÿÛããÿÛããÿÛããÿ>ÇLÿ¡Ô«ÿoÄ{ÿ,Ç;ÿ4ÌCÿÖãàÿÚããÿÚããÿÚããÿÚããÿ©©©ÿa©©©þÝææÿÝææÿÝææÿÝææÿÝææÿÝææÿÝææÿÝææÿÝææÿÝææÿÝååÿÝååÿÝååÿÝååÿÝååÿÝååÿÝååÿÝååÿÝååÿÛäãÿÒáÛÿÊ*ÿUÊbÿË%ÿ%Ì4ÿÇâÐÿÚäâÿÝååÿÝååÿÝååÿÝååÿ©©©ÿa©©©þàèèÿàèèÿàççÿàççÿàççÿàççÿàççÿàççÿàççÿàççÿàççÿàççÿàççÿØäàÿÒà×ÿàççÿàççÿàççÿàççÿ‹Ì”ÿ»ÝÅÿË$ÿ\Ïhÿ$Ë3ÿrÊ~ÿUÃ`ÿnÎ{ÿßççÿßççÿßççÿßççÿ©©©ÿa©©©þâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿ€ÍŠÿ×™ÿâééÿâééÿâééÿ¬Öµÿ#É2ÿÒçÚÿHÏVÿxÌÿ!É0ÿË$ÿ Ì/ÿ¹ãÁÿâééÿâééÿâééÿâééÿ©©©ÿa©©©þåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿ×åÜÿ'È7ÿ„ÖÿåëëÿäëëÿØåÞÿ9ÈGÿ)Ë8ÿÊßÒÿpÒ{ÿQÐ]ÿË%ÿCÐPÿÉçÑÿäëëÿäëëÿäëëÿäëëÿäëëÿ©©©ÿa©©©þçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿ•ÖžÿË$ÿÖ‰ÿçííÿçííÿxÎÿË$ÿVÑcÿqÓ}ÿÈèÐÿçííÿàìæÿäìêÿçííÿçííÿçííÿçííÿçííÿçííÿ©©©ÿa©©©þêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿUË`ÿË$ÿ†Øÿéïïÿéïïÿ4ÊBÿË-ÿaÐnÿÇêÐÿéïïÿ³ØºÿUÆaÿKÅWÿ`ÇjÿϘÿáêåÿéîîÿéîîÿéîîÿ©©©ÿa©©©þìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿ3ÊAÿË$ÿ’Û›ÿ{˃ÿÌçÒÿOÎ\ÿ:ÌGÿ¥ã­ÿÚèßÿ„ÌŒÿ$É3ÿË$ÿË$ÿË*ÿkÙvÿàîåÿìððÿìððÿìððÿ©©©ÿa©©©þïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿîóóÿîòòÿîòòÿ#Ë2ÿË$ÿ†×ÿË&ÿœÞ¤ÿKÌXÿ;ÎHÿqÑ{ÿHÍTÿË&ÿÌ,ÿLÓZÿ“áœÿßðäÿîòòÿîòòÿîòòÿîòòÿîòòÿ©©©ÿa©©©þñõõÿñõõÿñõõÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿ8ÌFÿ)Ì8ÿ·ç½ÿ(Í7ÿoÏxÿtÚ~ÿ­Þ´ÿ»èÁÿÅìÊÿÚðßÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿðôôÿðôôÿðôôÿ©©©ÿa©©©þôööÿôööÿôööÿôööÿôööÿôööÿóööÿóööÿóööÿéñìÿ«Ø²ÿÓêØÿMÎZÿ€ÝŠÿÍæÑÿIÍUÿoØyÿbÊlÿ$Ê3ÿhÒrÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿ©©©ÿa©©©þöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿõø÷ÿkÍuÿË&ÿUÑ`ÿ>ÍKÿ×íÛÿYÏdÿ~Þ‡ÿ_ÌjÿË$ÿË$ÿy܃ÿöøøÿöøøÿöøøÿöøøÿöøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿ©©©ÿa©©©þùúúÿùúúÿùúúÿøúúÿøúúÿøúúÿøúúÿøúúÿÚîÝÿË)ÿË$ÿj×tÿ[ÒfÿYÎeÿyÛƒÿ•ßÿOÔ[ÿDÑQÿeÒoÿÅäÊÿöùøÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿ©©©ÿaªªªþûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿéøëÿË)ÿ0Ï=ÿÚ”ÿ*Í8ÿcÙnÿ²è¸ÿuÏ~ÿDÉPÿ/É<ÿË%ÿ=ÑJÿòúóÿúüüÿúüüÿúüüÿúüüÿúüüÿúûûÿúûûÿúûûÿúûûÿúûûÿ©©©ÿaªªªþýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿñøóÿ9ÎGÿ˜ÜŸÿJÒVÿ»ï¿ÿØìÛÿKÊVÿË$ÿË$ÿ"Í0ÿŠä’ÿðúñÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ–ÚœÿOÏ[ÿMÓYÿºå¾ÿˆÒÿ:ÍGÿÍ,ÿ`Úkÿ²î·ÿöýöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿð÷ðÿ3ËAÿÌ+ÿ=ËIÿ#Ë2ÿ@ÎLÿ’Ý™ÿÉæÊÿÎæÐÿ³Þ·ÿ‹Ó‘ÿÓìÕÿÑèÔÿÝîÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ€Õ‡ÿ[ÙgÿÖöØÿzáƒÿ,Ï:ÿË$ÿË(ÿÊ,ÿË*ÿË$ÿË$ÿ(Ê6ÿ#Ì2ÿ€áˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿùùùÿùùùÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµá¸ÿiÛsÿüþüÿÿÿÿÿÿÿÿÿÿÿÿÿáøãÿé¤ÿU×`ÿ"Í1ÿ!Ì0ÿ:ÒGÿqÞzÿÃòÇÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿùùùÿ÷÷÷ÿöööÿôôôÿôôôÿôôôÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×íØÿgÚqÿöýöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿøøøÿöööÿôôôÿòòòÿñññÿðððÿïïïÿïïïÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóùôÿpØyÿìûíÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿøøøÿôôôÿñññÿïïïÿíííÿëëëÿêêêÿêêêÿêêêÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŠÙ‘ÿ·ï»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿøøøÿôôôÿðððÿíííÿêêêÿçççÿåååÿåååÿåååÿäääÿ©©©ÿaªªªþÿÿÿÿÿÿÿÿÿÿÿÿåóçÿXÓcÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿøøøÿáááÿ´´´ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¬¬¬ÿXªªªþÿÿÿÿÿÿÿÿÿÿÿÿ£ã¨ÿ:ÍGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿôôôÿ´´´ÿçççÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾¾¾ÿ¢¢¢ï5 ªªªþÿÿÿÿÿÿÿÿÿÿÿÿäùæÿãŠÿýÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿöööÿñññÿªªªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÕÕÕÿ¬¬¬þ666_ªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿôôôÿíííÿªªªÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿèèèÿ¬¬¬ÿpppŸªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ÷÷÷ÿòòòÿëëëÿªªªÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ÷÷÷ÿîîîÿ³³³ÿ™™™Þ.ªªªþÿÿÿÿÿÿÿÿôôôÿÆÆÆÿÕÕÕÿÿÿÿÿÿÿÿÿèèèÿÆÆÆÿÿÿÿÿÿÿÿÿÄÄÄÿÀÀÀÿÀÀÀÿðððÿÿÿÿÿÿÿÿÿûûûÿôôôÿïïïÿéééÿªªªÿÿÿÿÿÿÿÿÿùùùÿóóóÿíííÿÂÂÂÿ«««ûIªªªþÿÿÿÿþþþÿ‘‘‘ÿ¦¦¦ÿŒŒŒÿÈÈÈÿÿÿÿÿ´´´ÿyyyÿðððÿÿÿÿÿ€€€ÿ©©©ÿ³³³ÿìììÿÿÿÿÿÿÿÿÿùùùÿóóóÿìììÿæææÿªªªÿûûûÿõõõÿïïïÿéééÿÒÒÒÿ«««ÿZZZ‚ªªªþÿÿÿÿëëëÿ{{{ÿûûûÿÅÅÅÿžžžÿÿÿÿÿ‘‘‘ÿŠŠŠÿÍÍÍÿÿÿÿÿ€€€ÿçççÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿòòòÿëëëÿäääÿªªªÿñññÿëëëÿåååÿÚÚÚÿ¬¬¬ÿ‰‰‰Ä$ªªªþÿÿÿÿâââÿ†††ÿÿÿÿÿÒÒÒÿ”””ÿóóóÿ|||ÿ½½½ÿªªªÿÿÿÿÿ€€€ÿÿ‹‹‹ÿÿÿÿÿÿÿÿÿýýýÿöööÿðððÿêêêÿâââÿªªªÿçççÿáááÿÛÛÛÿ¶¶¶ÿ¥¥¥ò 6 ªªªþÿÿÿÿéééÿ~~~ÿýýýÿÈÈÈÿœœœÿÑÑÑÿ”””ÿÝÝÝÿ‡‡‡ÿÿÿÿÿ€€€ÿÓÓÓÿéééÿÿÿÿÿÿÿÿÿüüüÿöööÿðððÿéééÿâââÿªªªÿÝÝÝÿ×××ÿ¿¿¿ÿ«««þCCCcªªªþÿÿÿÿüüüÿ‡‡‡ÿ½½½ÿ˜˜˜ÿ½½½ÿ¯¯¯ÿ±±±ÿùùùÿ{{{ÿêêêÿ€€€ÿ¾¾¾ÿÍÍÍÿóóóÿÿÿÿÿüüüÿöööÿïïïÿèèèÿáááÿªªªÿÓÓÓÿÇÇÇÿ«««ÿxxx¦ªªªþÿÿÿÿÿÿÿÿåååÿ«««ÿ»»»ÿûûûÿ¶¶¶ÿÚÚÚÿÿÿÿÿ²²²ÿÝÝÝÿ¬¬¬ÿ§§§ÿ§§§ÿêêêÿÿÿÿÿüüüÿõõõÿïïïÿèèèÿáááÿªªªÿÈÈÈÿ­­­ÿžžžä+ ªªªþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿöööÿïïïÿéééÿâââÿªªªÿ²²²ÿ©©©ü***I  ªªªìæææÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿ÷÷÷ÿïïïÿéééÿâââÿ©©©ÿ©©©ÿfff‚ŠŠŠL©©©ë¨¨¨ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿªªªÿ•••Á ÿÿÿÿÿÿÿÿÿÿÿÿÿ?þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþ?þ?þþÿþÿþÿþÿþÿþÿþÿþÿþ?ÿÿ?ÿÿÿÿÿÿÿÿÿÿÿÿÿ(                                                                                                                                                                                                                                                                                                                                                                    "$ & '()))))****************************************************************************************************************************************************)))))( ' &$"        %),/13455566666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666555432/-)%       #)/48;>?@ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBA@?>;84/*$     %,3:?CFIKLMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMLKIGC?:4- &    $-5=CINQTUVWWWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWVVTRNJD>6.%   "+4=FMRWZ\^__````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````__^]ZWSMF>5,#     '1;EMTZ7;;puxx¤”””Ñ¡¡¡ë§§§ø©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¦¦¦ù¡¡¡ì•••Òwyy§:??rZUNF<2(    !,7AKS155iˆŠŠ½¨¨¨û©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ü‹ŒŒÁ499lTLB7-#  %0;FPOQQx¡¡¡ì©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿªªªÿªªªÿªªªÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿ«««ÿªªªÿ«««ÿ«««ÿªªªÿªªªÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¤¥¥ó]aa„QG<1 &    (3?JSWWx§§§ù©©©ÿ©©©ÿ©©©ÿ©©©ÿªªªÿ¬¬¬ÿ­­­ÿ°°°ÿ±±±ÿ³³³ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ²²²ÿ±±±ÿ¯¯¯ÿ­­­ÿ«««ÿªªªÿ©©©ÿ©©©ÿ¨¨¨ü\^^K@4)    *6B777\¤¤¤í©©©ÿ©©©ÿ©©©ÿªªªÿ³µµÿÌÑÑÿÜââÿãééÿçííÿèííÿéïïÿéîîÿêïïÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿèîîÿéïïÿçííÿàååÿÒÖÖÿºººÿ­­­ÿªªªÿ©©©ÿ©©©ÿ¤¥¥ò<>>bC7+    ,8DŽŽµ©©©ÿ©©©ÿ©©©ÿªªªÿÇÊÊÿãêêÿæííÿèîîÿêïïÿêïïÿêïïÿêïïÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿêïïÿêïïÿëððÿéîîÿæììÿÏÒÒÿ°°°ÿ«««ÿ©©©ÿ©©©ÿ‘’’¾E9-"  !-9?BBY§§§ú©©©ÿ©©©ÿªªªÿÇÊÊÿåëëÿèîîÿêïïÿëïïÿëððÿéîîÿèííÿçííÿçììÿçììÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿçííÿéîîÿéîîÿêïïÿëïïÿëïïÿêïïÿÒÕÕÿ°°°ÿ«««ÿ©©©ÿ¨¨¨ýHMM`:.#  ".:}€€“©©©ÿ©©©ÿ©©©ÿ³´´ÿäëëÿèîîÿëññÿëððÿéïïÿçîîÿäëëÿäëëÿäëëÿâêêÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿãëëÿäëëÿåììÿåììÿèîîÿëððÿëððÿêððÿÁÂÂÿ¯¯¯ÿªªªÿ©©©ÿ„……›;/#  #/:—˜˜Ç©©©ÿ©©©ÿªªªÿÍÑÑÿçííÿìññÿëððÿéîîÿæììÿäëëÿãêêÿãééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿãêêÿãêêÿåëëÿèîîÿëððÿìððÿÙÝÝÿ´´´ÿ¬¬¬ÿ©©©ÿšœœÐ<0$  #/;¡¡¡â©©©ÿ©©©ÿ¬¬¬ÿÝââÿêïïÿíññÿêïïÿæììÿãêêÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿâééÿãêêÿåëëÿèîîÿëððÿèëëÿ¼¼¼ÿ°°°ÿªªªÿ£¤¤ë<0$  #/;¥¥¥ò©©©ÿªªªÿ¯¯¯ÿæêêÿíññÿìññÿèîîÿåëëÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿäëëÿæííÿêïïÿëððÿÁÁÁÿ´´´ÿ«««ÿ§§§ú>0$  #/;©©©û©©©ÿªªªÿ±±±ÿéîîÿíññÿêïïÿçííÿäëëÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿåëëÿèîîÿìññÿÅÅÅÿ¸¸¸ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ³³³ÿêîîÿíññÿéîîÿæììÿãééÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿäêêÿåëëÿèííÿìððÿÆÆÆÿºººÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ´´´ÿëððÿíòòÿêïïÿæììÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿãêêÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿåëëÿæììÿìññÿÆÆÆÿ»»»ÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ´´´ÿêïïÿìññÿèîîÿåëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿãêêÿãêêÿâééÿâééÿãêêÿãêêÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿãêêÿãêêÿãêêÿâêéÿáéèÿáéèÿáèèÿáèèÿáéèÿáéèÿâééÿãêêÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿäëëÿæììÿëððÿÆÆÆÿ¼¼¼ÿ°°°ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ¬¬¬ÿµµµÿëïïÿìððÿêïïÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿäêêÿãêéÿâéèÿáèèÿâèèÿâéèÿãêéÿäêêÿäêêÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿäêêÿäêêÿäêêÿãêéÿâéèÿâèèÿáçæÿàçæÿÞæäÿÝåãÿÞæäÿßæåÿáçæÿâéèÿãééÿäêêÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿåëëÿèííÿìððÿÅÅÅÿ¼¼¼ÿ°°°ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ¬¬¬ÿ´´´ÿëïïÿìññÿéïïÿæííÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿäëëÿâêéÿâèèÿàèçÿÞçåÿÞçåÿßçæÿâèèÿâêéÿäëëÿåììÿåììÿåììÿåììÿåììÿäëëÿäëëÿãëêÿâêéÿâééÿáèçÿßçæÿÝæäÿÛãâÿÙáßÿ×àÝÿÖßÝÿ×àÝÿÚãáÿÝæäÿáèçÿâêéÿäëëÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿåììÿèîîÿìññÿÅÅÅÿ»»»ÿ°°°ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ´´´ÿëïïÿíññÿêïïÿçííÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿåëëÿäëêÿâèèÿßçåÿÛãáÿÙáÞÿÙáÞÿÛãáÿÞæäÿâéèÿãêéÿåëëÿæììÿæììÿåëëÿåëëÿäëêÿãêéÿâèèÿáèçÿÞæäÿÜãâÿÙáÞÿ×ßÜÿÓÝÙÿÐÚÕÿÎØÔÿÎØÔÿÑÚÖÿÖßÜÿÛãáÿàçæÿãêéÿåëëÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿèîîÿìññÿÄÄÄÿ¼¼¼ÿ°°°ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ´´´ÿëïïÿíòòÿêïïÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿåëëÿâéèÿàçæÿÚâàÿÔÝÚÿÐÚÖÿÐÚÖÿÓÜÙÿÚáßÿßçåÿãééÿäëêÿåëëÿåëëÿäëêÿãêéÿâéèÿàçæÿÜäãÿÚâàÿÖÞÜÿÓÝÙÿÏÙÕÿËÖÑÿÇÓÍÿÅÐÊÿÅÑÊÿÇÒÌÿËÖÑÿÒÜØÿÚáßÿßçåÿâéèÿäêêÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿæììÿèîîÿëððÿÄÄÄÿ»»»ÿ°°°ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ´´´ÿìððÿíññÿëððÿèîîÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿæììÿåìëÿãéèÿÝäãÿÖßÜÿÎØÓÿÉÔÎÿÉÔÎÿÍ×ÒÿÔÞÚÿÜäâÿâèçÿäëêÿäëêÿäëêÿãééÿáèçÿÝåäÿÚâßÿÖßÜÿÑÛÖÿÍ×ÒÿÈÔÎÿÄÐÊÿÁÌÅÿ¾ËÄÿ¼ÊÂÿ¿ÌÅÿÂÏÈÿÉÕÐÿÒÜØÿÛâàÿáèçÿäëêÿæììÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿéïïÿìððÿÄÄÄÿºººÿ°°°ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ´´´ÿëïïÿîòòÿëððÿèîîÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿæììÿäëêÿáèçÿÚâßÿÐÚÖÿÇÒÌÿÁÌÅÿÀÌÅÿÅÑÊÿÏØÔÿØàÞÿßçåÿãéèÿãééÿâèçÿÞæäÿÛâàÿÖßÜÿÐÚÖÿÊÖÑÿÆÒËÿÂÍÆÿ½ËÃÿ¹Ç¿ÿ·Å¼ÿ¶Ä»ÿ¸Æ½ÿ»ÉÁÿÂÏÈÿÊÕÏÿÒÞØÿÙãàÿãéèÿäëêÿæììÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿçííÿéïïÿíññÿÃÃÃÿ»»»ÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ³³³ÿíððÿîòòÿëïïÿéîîÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿæëëÿäééÿßæåÿ×ßÜÿÌÖÑÿÁÍÅÿʤÿʤÿ¿ÌÄÿÉÔÏÿÔÝÙÿÝäâÿáèæÿàçåÿÞåãÿÙßÝÿÒÜ×ÿÌÖÑÿÆÑËÿÁÍÆÿ¼ÈÀÿ¸Å¼ÿµÃ¹ÿ³Â¸ÿ²Á·ÿ´Â¸ÿµÆºÿ§É®ÿ|Ç…ÿVÁaÿ0º<ÿ¹ß¿ÿåêêÿæëëÿçììÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿèííÿêïïÿìððÿÂÂÂÿºººÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ³³³ÿìññÿíòòÿëððÿéïïÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿçííÿæíìÿäêéÿÝåãÿÓÝÙÿÈÓÍÿ¢Ë©ÿ.¹:ÿ-¸9ÿžË¥ÿÅÑËÿÐÚÖÿÙáßÿÜäâÿÛâàÿÖßÜÿÐÙÕÿÉÔÎÿÁÍÆÿ¼ÊÁÿ·Å¼ÿ³Â¸ÿ°À¶ÿ®¿´ÿ«Á±ÿ•Áœÿk¿sÿ@»Kÿ#·0ÿ#·0ÿ#·0ÿHÁTÿáêæÿåìëÿçííÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿêïïÿìññÿÂÂÂÿºººÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ³³³ÿëððÿîóóÿëððÿéïïÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿçííÿåìëÿâéèÿÚâßÿÏÙÕÿÂÑÈÿ_Âiÿ#·0ÿ#·0ÿQ¿[ÿ½ÎÂÿÌ×ÒÿÔÞÚÿ×ßÜÿÓÝÙÿÍ×ÒÿÅÑËÿ¾ÌÄÿ¸Æ½ÿ³Â¸ÿ¯¿µÿ¬¾±ÿ˜¿Ÿÿh¼qÿ:¸Fÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸3ÿ»àÁÿåìëÿçííÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿèîîÿêïïÿíòòÿÁÁÁÿºººÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ²²²ÿíññÿïòòÿëððÿêïïÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿèííÿåëëÿáèæÿÙàÝÿÍ×Ñÿ¬Ï²ÿ+¸7ÿ#·0ÿ#·0ÿ$·1ÿ—ÌžÿÉÔÎÿÐÙÔÿÑÚÖÿÌÖÑÿÅÐÊÿ¾ÊÂÿ·Äºÿ±À¶ÿ©¿®ÿ€¾‰ÿJºTÿ%·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿyσÿäëêÿçììÿèííÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿéîîÿëïïÿíññÿÁÁÁÿ¹¹¹ÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ³³³ÿìððÿîòòÿìññÿêððÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿçííÿåëëÿàçæÿÖàÜÿÉÕÏÿ{Ê…ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ]ÃgÿÄÒÊÿÊÕÏÿÉÕÏÿÅÒËÿ¾ÊÂÿ·Å»ÿ¬Á²ÿ}À†ÿ;¹Gÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿOÃZÿßêäÿçîíÿèîîÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿéïïÿëððÿîòòÿÁÁÁÿ¸¸¸ÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ²²²ÿíññÿîòòÿíññÿëððÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿéîîÿèîíÿåëêÿßæäÿÔÞÚÿÅÔÉÿPÀZÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ4º@ÿ¹Î¾ÿÆÑËÿÅÑÊÿ¿ÌÄÿ·Æ¼ÿáÿIºTÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ6½CÿÏèÕÿçíìÿéîîÿéîîÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿìððÿîòòÿÀÀÀÿ¸¸¸ÿ¯¯¯ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ²²²ÿìððÿïóóÿíññÿëððÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿéîîÿéîîÿéîîÿçíìÿäêéÿÜäáÿÑÛ×ÿ´Ôºÿ*¸7ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿœÍ¤ÿÃÎÇÿÀÌÅÿ¹Ç¾ÿÄ“ÿ/·;ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ(¸5ÿ´ßºÿçíìÿèîíÿèííÿéîîÿéîîÿéîîÿéîîÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿêïïÿìððÿíññÿ¿¿¿ÿ¸¸¸ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ±±±ÿîòòÿïóóÿîòòÿìññÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿêïïÿêïïÿéïîÿéïîÿèîíÿèííÿäëéÿÛãáÿÑÚÕÿŽÎ•ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ}ɆÿÁÍÆÿ¾ÊÂÿ•Èÿ,¸9ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ˜Ø¡ÿæíëÿèííÿçííÿçííÿèîíÿèîíÿèîíÿéîîÿêïïÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿíññÿïóóÿ¿ÀÀÿ···ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ²²²ÿíññÿðóóÿîòòÿìññÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿêïïÿéïîÿçíìÿçììÿçíìÿçíìÿæëêÿâéèÿÛâßÿÏÙÔÿhÇqÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿjÅsÿÀÍÅÿµË¹ÿ>»Iÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ‚ÑŒÿâêçÿåêéÿåëéÿäëéÿäëéÿäëéÿåêéÿæìëÿçííÿéïîÿêïïÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿëððÿìññÿïóóÿ¿ÀÀÿ···ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ±±±ÿîññÿïòòÿîòòÿíññÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿëïïÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿëïïÿéîíÿèììÿæêéÿäêèÿäêèÿåëéÿäêèÿáçåÿÚàÝÿÈ×ÍÿI¾Sÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ_ÃiÿÁÌÅÿ€Ç‡ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿnËxÿÝæáÿàæäÿßåãÿÝäáÿÜãáÿÜãáÿÝäáÿßåãÿâèçÿæêéÿèììÿêïîÿëïïÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿìððÿíññÿïòòÿ½¾¾ÿ···ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ°°°ÿîòòÿðôôÿîóóÿíòòÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿëððÿëððÿêïïÿêïïÿêïïÿëððÿëððÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿëððÿéïîÿçíìÿäëéÿáèæÿÞæãÿÝåâÿàçåÿâéçÿßæäÿØàÜÿÁÙÆÿ0º<ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ_ÃiÿÀÐÅÿM¿Wÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$¸1ÿ[ÅgÿÒà×ÿØàÜÿÖßÚÿÔÞÚÿÓÝØÿÑÛÖÿÑÛÖÿÓÜØÿÖßÚÿÜãàÿáèæÿæëêÿèîíÿëððÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿíòòÿîóóÿ¾¿¿ÿ¶¶¶ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ±±±ÿíññÿïóóÿîóóÿíññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿëððÿêðïÿéïîÿèîîÿéîîÿéïïÿéïîÿëððÿëððÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿëððÿêðïÿèîíÿäëéÿÞæãÿÚáÞÿ×ßÛÿØàÜÿÜãàÿÞæãÿÜäâÿÖßÚÿ¬Õ²ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿfÇoÿ¼ÒÀÿ-¹9ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿUÄ`ÿÉÚÍÿÏÙÔÿÍ×ÑÿÊÕÎÿÇÒÌÿÇÒËÿÆÑÊÿÇÒËÿÈÓÍÿÎØÓÿÕßÚÿÜäâÿäëéÿèííÿêïïÿëððÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿìññÿíòòÿïóóÿ¼½½ÿ¶¶¶ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ±±±ÿïòòÿñôôÿïóóÿîññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿìððÿëðïÿêîîÿçìëÿçëêÿæëéÿçëêÿéííÿêïîÿìððÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿìððÿëðïÿéííÿæëéÿßæãÿÙàÜÿÒÛÖÿÐÙÔÿÒÛÖÿØßÛÿÝãáÿÜãáÿÖßÚÿÑ—ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿuË~ÿ±Ô·ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¸2ÿPÂ[ÿ¾ÒÂÿÇÒËÿÄÏÈÿÁÍÅÿ¿ËÂÿ½ÉÁÿ¼ÉÀÿ¼ÈÀÿ¿ËÃÿÃÎÇÿÊÔÎÿÓÜ×ÿÝäáÿäêéÿéííÿëðïÿìððÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿíññÿîòòÿðóóÿ½¾¾ÿ¶¶¶ÿ®®®ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ°°°ÿîòòÿðôôÿïóóÿîòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿìññÿëððÿêïïÿçìëÿãéèÿàçåÿàçåÿãêèÿæìêÿêïïÿëñðÿìññÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿìññÿëððÿéïïÿçìëÿàçåÿÙáÝÿÐÛÕÿÊÕÏÿÉÔÎÿ½ØÃÿÎßÔÿÜäáÿÜåâÿÖßÚÿ{Í„ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ“Ò›ÿ¥Õ¬ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¹3ÿMÀVÿ¶Î¼ÿ¿ÌÄÿ»ÉÀÿºÇ¾ÿ¸Å»ÿ¶ÄºÿµÄºÿ¶Äºÿ¸Å»ÿ»ÉÀÿÂÎÇÿËÖÐÿÔÞÚÿÝåãÿåìêÿêïïÿëððÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿíòòÿîóóÿðôôÿ¼½½ÿµµµÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ°°°ÿðóóÿñõõÿðóóÿîññÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿíññÿìððÿêïïÿèìëÿãéçÿÞåâÿÚáÝÿÚáÝÿÞåâÿäêèÿèíìÿëðïÿíññÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿíññÿëðïÿèíìÿãéçÿÛáÞÿÑÚÕÿÉÔÍÿÄÐÉÿµÓ¼ÿHÁTÿ­Û´ÿÝäáÿÝäâÿØàÛÿmËvÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%·2ÿ½ÝÃÿ¡Õ¨ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ'¹3ÿN¿Yÿ°É´ÿ¸Å»ÿ·ÄºÿµÃ¹ÿ³Â·ÿ³Á¶ÿ±Àµÿ°Â´ÿ©Å¯ÿœÇ¡ÿÉ”ÿË•ÿ¡Ò§ÿÉÞÍÿâèæÿèìëÿëðïÿíññÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿïóóÿðóóÿ¼½½ÿµµµÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ«««ÿ¯¯¯ÿïóóÿñôôÿðóóÿïòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿíññÿëðïÿèíìÿäéèÿÜãàÿÕÞÚÿÑÛÕÿÓÜ×ÿ×àÚÿßæãÿçìêÿêïïÿíññÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿíññÿëðïÿéîíÿåêéÿÝäáÿÓÜ×ÿÉÓÍÿÂÎÆÿ³Ï·ÿPÂ[ÿ&¸3ÿ¥Ú¬ÿÝäáÿßæãÿÚáÝÿ`Çjÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿJÂUÿÑßÕÿ¨×¯ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¹2ÿ'¹4ÿU¿^ÿ­Å°ÿ³Â·ÿ²Á¶ÿ°Àµÿ©À®ÿ•ÿqÁzÿYÁbÿCÂOÿ;ÄGÿ>ÄIÿ?ÅKÿAÇMÿBÆMÿCÇNÿ«Þ±ÿêîîÿìñðÿíññÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿîòòÿïóóÿðóóÿº»»ÿ´´´ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ°°°ÿðóóÿòõõÿñôôÿðóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿîòòÿíòñÿëïïÿæìëÿÞåãÿÖÞÚÿÏØÒÿÌÕÐÿ´ÜºÿÈáÌÿÞåâÿæìëÿëïïÿíòñÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿîòòÿíòñÿëïïÿçìêÿßæäÿÖÞÚÿÌÖÐÿÂÏÇÿ¸Ì½ÿ\Ägÿ&¸2ÿ&¸2ÿªÚ°ÿßæäÿâèæÿÝåáÿ]Ègÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ‹Ô’ÿ×ßÛÿ²×¸ÿ#·0ÿ#·0ÿ%¸1ÿ&¸3ÿ(¹5ÿ[Àcÿ®À±ÿ±Âµÿ¦Â¬ÿ€Ã†ÿ[Àdÿ=ÀHÿ7ÀBÿ8ÂEÿ;ÃFÿ<ÃHÿ>ÄJÿ@ÅLÿBÆMÿAÆLÿ@ÅKÿAÅKÿÁæÇÿìñðÿîòòÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿðôôÿñõõÿ»¼¼ÿ³³³ÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ°°°ÿðóóÿòõõÿðóóÿðóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿîòòÿìñðÿéíìÿâèæÿÙáÜÿÏØÒÿÈÒËÿ»ÖÀÿfÏpÿ·á¾ÿÝäàÿåêéÿëðïÿíòñÿîòòÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿîòòÿíññÿëððÿèíëÿáçåÿÙáÜÿÏØÒÿÄÏÈÿ»Ë¿ÿrÉ{ÿ&¸3ÿ%¸2ÿ&¸2ÿ»àÀÿáèåÿåëéÿàèäÿ\Çfÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ:½FÿÍáÑÿÕÞÙÿÀ×Äÿ*¸7ÿ$¸2ÿ'¸3ÿ+º8ÿoÁwÿ¨Â¬ÿ‰ÁÿV¿aÿ5½Aÿ4¿@ÿ5ÀBÿ8ÁCÿ9ÂEÿ;ÃFÿ=ÄHÿ?ÄJÿAÅLÿBÆNÿ@ÆMÿ?ÆKÿ>ÄIÿŒØ“ÿëñïÿîòòÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿïóóÿðôôÿñõõÿº»»ÿ´´´ÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¯¯¯ÿðòòÿóõõÿñôôÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿïòòÿîòñÿëïîÿæêéÿÝãàÿÓÜ×ÿÊÓÌÿÀÑÃÿqÑ{ÿBÀMÿšÝ¢ÿÜâÞÿåêèÿëïîÿîòñÿïòòÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿïòòÿíñðÿêîíÿåêèÿÜãßÿÒÛÖÿÈÑÊÿÀÌÃÿ‰Ëÿ-º9ÿ%¸2ÿ$·1ÿ)¹6ÿÊãÍÿäéçÿçìêÿåêèÿbÊlÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ‚Ò‰ÿØßÛÿÑÚÕÿÄÔÆÿC¾Nÿ'¹4ÿ5»Bÿ}Ã…ÿoÂvÿB¾Mÿ1¾=ÿ3¾>ÿ5ÀAÿ6ÀCÿ8ÁDÿ:ÃFÿ;ÃHÿ>ÄIÿ?ÆKÿAÆLÿBÆMÿAÅLÿ?ÄJÿ>ÄIÿ…Öÿìñðÿïòòÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿðóóÿñôôÿòõõÿºººÿ³³³ÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¯¯¯ÿñôôÿòõõÿñõõÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿïóóÿíññÿéîìÿáèåÿ×ßÛÿÌÖÐÿÄÏÇÿ€Ôˆÿ9½Eÿ5½Aÿ~ׇÿÜãÞÿåëéÿëðïÿîóòÿïóóÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿïóóÿíòñÿëðïÿæìëÿßæãÿÕÝØÿÊÕÎÿÁÎÆÿžÍ¤ÿ8¼Dÿ&¸2ÿ#·0ÿ$·1ÿ4¼@ÿÍåÒÿæìêÿéîíÿèíëÿrÑ{ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿKÂVÿÍàÒÿÕÝØÿÎØÒÿÄÐÈÿxÆ€ÿN¿XÿXÀbÿ6¼@ÿ0½<ÿ1¾=ÿ3¿?ÿ5ÀAÿ7ÁCÿ8ÂDÿ;ÂGÿ<ÄIÿ>ÅJÿAÅLÿBÇNÿAÆLÿ@ÅKÿ>ÅJÿ>ÃIÿÙ–ÿëñïÿïóóÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿòõõÿ¹¹¹ÿ²²²ÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¯¯¯ÿðóóÿòööÿñõõÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿïóóÿîóòÿëðïÿæëêÿÜäàÿÑÛÖÿÇÑËÿ›Õ¢ÿDÀPÿ,º8ÿ.»;ÿrÔ|ÿÛâßÿäêèÿêïîÿîóòÿïóóÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿïóóÿîòòÿíññÿèíëÿáèåÿØàÜÿÍØÑÿÃÎÆÿ¯Í³ÿH¿Sÿ&¸3ÿ#·0ÿ#·0ÿ$·1ÿA¿LÿÓå×ÿæìëÿéîíÿéîíÿŒÙ”ÿ#·0ÿ#·0ÿ#·0ÿ.º:ÿ±Ý¸ÿ×ßÚÿÑÛÖÿÇÕËÿˆÌÿ;¾Fÿ-¼9ÿ.½;ÿ0¾=ÿ2¾>ÿ4À@ÿ5ÁBÿ8ÁCÿ9ÂEÿ;ÃGÿ>ÄHÿ?ÅJÿ@ÆMÿBÇNÿAÅLÿ?ÅKÿ>ÄIÿ>ÅIÿ“Ûœÿìòñÿïóóÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿðôôÿñõõÿòõõÿºººÿ²²²ÿ­­­ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¯¯¯ÿñôôÿóööÿòõõÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿðóóÿîòòÿêîíÿãéæÿØßÛÿÍÖÑÿºÓ½ÿYÈcÿ.»;ÿ%¸2ÿ-º:ÿhÏqÿÚâÝÿåêèÿëïîÿîòñÿðóóÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿðóóÿîòñÿêîíÿåêèÿÛâÞÿÐÚÔÿÇÑÊÿ¹Ì¾ÿ`Æjÿ'¸4ÿ$·1ÿ#·0ÿ#·0ÿ$·1ÿOÃZÿÛæÞÿèìëÿêîíÿéíëÿÀåÅÿ%¸1ÿ#·0ÿ(¸5ÿ’Õ˜ÿÖßÙÿÖÝØÿÉÛÎÿqÊzÿyË‚ÿ-¼:ÿ/½;ÿ1½=ÿ2¿?ÿ5ÀAÿ7ÁCÿ8ÂDÿ:ÃFÿ<ÄHÿ>ÄIÿ@ÅKÿAÇLÿAÇMÿAÅLÿ>ÅKÿ>ÄIÿAÅMÿ¥à­ÿîóñÿðóóÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿñôôÿóõõÿ¹¹¹ÿ²²²ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¯¯¯ÿðôôÿòõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿðôôÿïôóÿíòñÿèìëÿÞåâÿÓÜ×ÿÈÔÌÿzÔƒÿ3¼?ÿ&¸3ÿ$·1ÿ,º9ÿbÌlÿÕäÙÿäêèÿëðïÿîóòÿðôôÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿðôôÿïôóÿìñðÿèìëÿßæãÿÕÝØÿÊÔÍÿ¿ÌÃÿ̉ÿ,¹7ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿdËnÿàèåÿçìëÿèíëÿæìêÿÜèàÿtÏ}ÿKÂVÿš×¢ÿÎßÒÿ¼àÃÿÈßÌÿcÊlÿ™ÕŸÿjÈrÿ/½<ÿ2¾>ÿ3¿@ÿ6ÀAÿ7ÁCÿ9ÂEÿ;ÃGÿ<ÄIÿ>ÄKÿAÅLÿBÇNÿAÇMÿ@ÆKÿ>ÅJÿ=ÄIÿGÆTÿ¼èÄÿîóòÿðôôÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿñõõÿòõõÿóööÿ¸¸¸ÿ²²²ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ®®®ÿòõõÿôööÿóööÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿñôôÿïóòÿëïîÿåêèÿÚâÞÿÏÙÓÿ²Ö´ÿHÁSÿ*¹6ÿ$·1ÿ#·0ÿ,º8ÿ\ÉfÿÑãÕÿåêèÿìðïÿïóòÿñôôÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿðóóÿïòòÿêïíÿãéæÿÙàÜÿÎØÒÿÅÏÇÿŸÏ¥ÿ9¼Eÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿzÒƒÿâèæÿçìêÿæëéÿâèåÿÛãßÿÕß×ÿÏÝÒÿÑÝÓÿ‹Õ’ÿ«ß²ÿVÇaÿ Û§ÿÆßÊÿ>ÁIÿ2¿?ÿ4¿@ÿ5ÀBÿ8ÁDÿ9ÂEÿ;ÄGÿ>ÄIÿ?ÅKÿAÇMÿBÆNÿAÅLÿ?ÅJÿ>ÄIÿ<ÃHÿWÊbÿÑìÔÿñôôÿñôôÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòôôÿóõõÿ¸¸¸ÿ²²²ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ®®®ÿòõõÿôööÿóööÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿðóóÿïòòÿêîìÿâèåÿÖÝØÿËÕÎÿvÔ~ÿ1¼=ÿ&¸2ÿ#·0ÿ#·0ÿ+º7ÿWÇaÿÎåÒÿåêèÿìðïÿïóòÿñôôÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿñôôÿïóòÿìðïÿçìêÿÝäàÿÒÚÕÿÈÒËÿ¶Í¹ÿPÂ[ÿ'¸4ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ”ÙÿáçåÿäêçÿâèåÿÛâÞÿØßÚÿÔÜ×ÿÒÝÕÿƒÒŠÿ3½?ÿ@ÁKÿ¬à²ÿÞèâÿxÑ€ÿ2¿?ÿ5À@ÿ7ÁCÿ8ÂDÿ;ÃFÿ<ÃHÿ?ÄJÿ@ÅKÿBÆMÿAÆLÿ@ÅLÿ>ÄKÿ=ÄHÿ;ÄHÿwÓ€ÿæòéÿñôôÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿòõõÿóõõÿóööÿ···ÿ±±±ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ®®®ÿóõõÿõ÷÷ÿô÷÷ÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿòõõÿñõôÿîòñÿéíëÿÞåáÿÓÛÕÿ¶ÙºÿKÃUÿ*¹6ÿ$·1ÿ#·0ÿ#·0ÿ+º7ÿTÆ^ÿËäÑÿæëéÿíñðÿðôóÿòõõÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿòõõÿñõôÿïòòÿêîìÿãéæÿØßÚÿÌ×ÐÿÁÏÅÿmÊvÿ*¹6ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ²à¶ÿáçäÿáçäÿÝäàÿÙàÜÿ×ÞÙÿÖÞØÿ‘טÿ1¼>ÿÕ‹ÿÈèÌÿæìèÿ™Ý ÿ7ÀBÿ6ÀBÿ8ÀCÿ9ÂEÿ:ÃFÿ=ÃHÿ>ÅKÿAÅLÿBÆNÿAÆMÿ?ÆKÿ?ÄJÿ<ÄIÿFÆQÿ¡â©ÿïôòÿòõõÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿôööÿô÷÷ÿ¶¶¶ÿ°°°ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ®®®ÿóõõÿõ÷÷ÿô÷÷ÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿòõõÿðôóÿìðïÿåëèÿÙáÝÿÏÙÓÿyÕ‚ÿ1¼=ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿRÆ\ÿËåÐÿåêèÿíñðÿðôóÿòõõÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿòõõÿðôóÿìðïÿæëéÿÜäßÿÑÙÓÿÆÑÉÿЗÿ1»=ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ,º9ÿÉäÎÿÞåáÿÜäßÿØàÜÿØßÚÿØàÚÿŸÛ¦ÿ2¼?ÿZÊdÿæíèÿäðèÿ‹Û’ÿ7ÂCÿ6ÁCÿ8ÁDÿ:ÃFÿ;ÄHÿ>ÄIÿ?ÆKÿAÆLÿBÆMÿAÅLÿ?ÅJÿ>ÄIÿ<ÄHÿjÑtÿÖïÛÿñôôÿòõõÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿóööÿô÷÷ÿ¶¶¶ÿ°°°ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ­­­ÿóõõÿõ÷÷ÿõ÷÷ÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿòôôÿñóóÿêîìÿãèåÿ×ÞÙÿ½ÙÁÿPÆ[ÿ*¹6ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿOÄZÿÊåÎÿçëéÿîñðÿñôóÿóõõÿôööÿôööÿôööÿôööÿôööÿôööÿóõõÿòõôÿðóòÿëíìÿâçäÿ×ÞØÿÌÕÎÿ·Ñ»ÿKÁVÿ'¸4ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿIÁTÿÒâÕÿÛâÞÿÙàÛÿØßÚÿÚáÜÿ­ß±ÿ8¿Cÿ-½:ÿIÅUÿŒÛ”ÿUÌ`ÿIÆUÿpÓyÿ”ß›ÿ¬æ³ÿ–ßžÿTË_ÿAÅLÿBÆMÿAÆLÿ@ÆKÿ>ÄKÿ=ÄHÿ]Ìgÿ³å¹ÿîóðÿóõõÿóõõÿóõõÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿôööÿõ÷÷ÿ¶¶¶ÿ°°°ÿ¬¬¬ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ­­­ÿóööÿô÷÷ÿõøøÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿóööÿòöõÿïóòÿêîìÿßæâÿÔÜÖÿ”Úšÿ3¼@ÿ&¸3ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿOÅYÿÊåÏÿçìêÿîòñÿñõôÿóööÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿóööÿñõôÿíñðÿçìêÿÜäàÿÑÚÔÿÆÑÉÿuÍ}ÿ+º7ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿeËoÿ×àÚÿ×ßÚÿ×ßÚÿÙáÜÿ¶á¼ÿ?ÁKÿ.½;ÿ0½=ÿHÅSÿz׃ÿ¿ìÆÿéöíÿñöõÿóööÿóööÿóööÿçôëÿ’ß™ÿcÏmÿTÊ^ÿ^Ígÿ}Ö†ÿ¼èÃÿìôïÿñõôÿñõôÿòöõÿòöõÿòõõÿóööÿóööÿóööÿóööÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿõøøÿµµµÿ¯¯¯ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ­­­ÿóööÿõøøÿõ÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿóööÿñõôÿíñðÿæìéÿÛãßÿÏÙÒÿfÑpÿ,º9ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿLÃUÿÇäÌÿçìêÿîòñÿñõôÿóööÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿòöõÿðóóÿêïîÿãéæÿ×ßÚÿËÕÎÿ£Ó©ÿ9½Eÿ&¸3ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿˆÔÿÖÞÙÿÖÞÙÿ×ßÚÿÀáÆÿHÄTÿ/½;ÿ<ÁHÿŽÝ•ÿâõæÿòöõÿóööÿô÷÷ÿô÷÷ÿô÷÷ÿóööÿóööÿòöõÿñõôÿìóðÿéòìÿéñíÿíòðÿíñðÿîòñÿîòñÿîòñÿïóòÿðôóÿñôôÿðôôÿñõôÿñõôÿòöõÿòöõÿòõõÿóööÿóööÿóööÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿô÷÷ÿõøøÿ´´´ÿ¯¯¯ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ­­­ÿôööÿöøøÿö÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿôööÿñôôÿìðîÿäéçÿØßÚÿ·Ü»ÿEÁPÿ(¸5ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿKÄUÿÉåÍÿèìêÿïòñÿòõôÿôööÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿôööÿòõôÿïòñÿéìêÿÞäàÿÓÚÔÿÁÔÃÿ[Æeÿ)¸5ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ/»;ÿ»Þ¾ÿÔÝ×ÿÖÞÙÿÇâÌÿRÈ[ÿ0½=ÿ@ÂLÿ¹ê¿ÿñõóÿôööÿõ÷÷ÿõ÷÷ÿõ÷÷ÿôööÿôööÿóöõÿòõõÿñôóÿîñðÿìðîÿëíìÿêíëÿèìêÿèìêÿèìêÿèìêÿéìêÿêíëÿëíìÿëïîÿìðîÿîñðÿîñðÿðóòÿñôóÿòôôÿñôóÿòõôÿóöõÿóõõÿôööÿôööÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿöøøÿ´´´ÿ¯¯¯ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ­­­ÿô÷÷ÿöùùÿöøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿóööÿñôôÿêïîÿâéåÿÕÞÙÿ†ÙŽÿ0»<ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿHÃTÿÈçÎÿèìêÿïóòÿòöõÿô÷÷ÿõøøÿõøøÿõøøÿõøøÿõøøÿô÷÷ÿòöõÿîòñÿæëéÿÛâÞÿÎØÑÿÓ”ÿ/»<ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ(¹4ÿ`ÊjÿÐÜÒÿÔÞØÿÏâÒÿ]Ëhÿ2¾>ÿAÂJÿµë½ÿñõôÿô÷÷ÿõøøÿõøøÿõøøÿô÷÷ÿóööÿòöõÿñõôÿîòñÿêïîÿèìêÿäêçÿáèäÿÞæáÿÜäàÿÛãßÿÛãßÿÜäàÿÝåáÿßæâÿáèäÿãéæÿåëèÿæëéÿèìêÿêîìÿëîíÿëðîÿíòðÿîòñÿðôóÿòõõÿòöõÿóööÿô÷÷ÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿõøøÿöùùÿ´´´ÿ¯¯¯ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¬¬¬ÿõ÷÷ÿ÷ùùÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿõ÷÷ÿô÷öÿñôóÿêîìÿßæáÿÒÝÔÿ`Îkÿ+º7ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ)¸5ÿGÂQÿÈèÌÿéìêÿðóòÿóöõÿõ÷÷ÿöøøÿöøøÿöøøÿöøøÿöøøÿõ÷÷ÿòõõÿíñïÿåêçÿØàÚÿÂØÅÿQÄ[ÿ(¹5ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ(º5ÿ0¼>ÿ§Ú­ÿÔÛÕÿÐàÔÿkÎuÿ4¿?ÿ9ÀDÿªå°ÿòöôÿõ÷÷ÿöøøÿöøøÿöøøÿõ÷÷ÿô÷öÿóõõÿðóòÿìðïÿèëéÿãèåÿÝäàÿØßÚÿÕÝ×ÿÒÚÔÿÐØÒÿÏØÑÿÏØÑÿÐØÒÿÑÙÓÿÒÛÔÿÔÜÖÿÖÞÙÿØàÚÿÛâÝÿÜãßÿßæáÿâèäÿäéæÿæëéÿéìêÿëîíÿíñïÿðóòÿòõõÿô÷öÿõ÷÷ÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿ³³³ÿ®®®ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¬¬¬ÿõ÷÷ÿ÷ùùÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿõ÷÷ÿóöõÿïòñÿèìéÿÜâÞÿ½ÝÀÿGÃRÿ(¹5ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿIÂSÿÈæÍÿêíëÿðóòÿóöõÿõ÷÷ÿöøøÿõ÷÷ÿõ÷÷ÿõ÷÷ÿõ÷÷ÿô÷öÿòôôÿìðïÿäéæÿ×ßÚÿÕ’ÿ-º:ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ(¹4ÿ+º8ÿjÌsÿÏÜÒÿÑÞÔÿxÓƒÿ3¾@ÿ7ÀBÿ‡Úÿðöòÿõ÷÷ÿõ÷÷ÿöøøÿõ÷÷ÿõ÷÷ÿóöõÿòôôÿïòñÿêîìÿæëèÿÞåáÿ×ßÚÿÒÚÔÿÍÕÎÿÉÒÊÿÅÐÈÿÃÎÆÿÂÎÅÿÂÎÅÿÃÎÆÿÄÏÇÿÆÑÈÿÈÒÊÿÉÒËÿËÔÍÿÎÖÏÿÐÙÒÿÒÚÔÿÔÜÖÿ×ßÚÿÛâÝÿÞåáÿãèåÿèìéÿëïîÿðóòÿóööÿõ÷÷ÿõ÷÷ÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿöøøÿ÷øøÿ³³³ÿ®®®ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¬¬¬ÿöøøÿøùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿöøøÿóööÿîòðÿæêèÿÚáÜÿ›Ý ÿ1¼=ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿLÄWÿÍêÑÿêîìÿñôóÿô÷öÿõø÷ÿõ÷÷ÿõø÷ÿõø÷ÿõ÷÷ÿõ÷÷ÿõø÷ÿóõõÿíñðÿåêçÿÏáÓÿWÆaÿ)¹6ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¹2ÿ'¹4ÿ,º7ÿA¿MÿºÜ¿ÿÒÝÔÿ‡Øÿ7ÁCÿ6ÀBÿgÒqÿëõíÿõ÷÷ÿöøøÿ÷ùùÿöøøÿõ÷÷ÿô÷öÿòõôÿîòðÿêíëÿãéåÿÜãÞÿÔÜÖÿÍÖÎÿÇÑÈÿÂÍÄÿ¿ËÁÿ¼É¿ÿ»È¾ÿºÇ½ÿºÇ½ÿ»È¾ÿ»È¾ÿ½ÊÀÿ¾ËÁÿ¿ËÁÿÁÍÃÿÂÍÄÿÄÎÆÿÇÑÈÿÉÓËÿÍÖÏÿÐÚÓÿÕÝ×ÿÛâÝÿâèäÿéìêÿîòðÿóõõÿõø÷ÿöøøÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿøùùÿ³³³ÿ®®®ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿªªªÿ¬¬¬ÿöøøÿøùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿõ÷÷ÿóõõÿìðïÿäéæÿ×ßÚÿoÔxÿ,º9ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿPÆ[ÿÍèÒÿêîìÿñôóÿôööÿô÷öÿôööÿóöõÿóöõÿóõõÿóöõÿô÷÷ÿóõõÿîòðÿçêèÿ¬à°ÿ0»<ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ%¸1ÿ&¸3ÿ(¹5ÿ+»8ÿ3¾?ÿ‹Ó’ÿÒÜÕÿ“Ú›ÿ:ÀGÿ7ÁBÿPÉ\ÿØñÝÿõø÷ÿöøøÿöøøÿöøøÿõø÷ÿôööÿñôóÿìðïÿçëéÿàæâÿØàÛÿÐÚÓÿÉÓËÿÂÍÄÿ¾ËÁÿºÇ½ÿ·Æ¹ÿ²Æ¶ÿ°Æ´ÿ¯Å²ÿ¯Å³ÿ²Åµÿ³Å·ÿ¶Ä¹ÿ¸Å»ÿ¹Æ»ÿ¹Ç¼ÿºÇ½ÿ¼É¿ÿ¾ÊÀÿÂÌÃÿÅÏÇÿÉÓËÿÏØÑÿÖßÙÿÞåáÿçëéÿíñðÿòõôÿõø÷ÿöøøÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ÷ùùÿ±±±ÿ­­­ÿ«««ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ«««ÿ÷÷÷ÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿ÷øøÿöø÷ÿóõôÿíðîÿâçãÿÎÞÐÿVÉ`ÿ*¹6ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*¹6ÿRÆ\ÿÒêÔÿëîìÿñóòÿóõôÿñóòÿïòðÿîðïÿíïîÿîñïÿñóòÿóõôÿôöõÿðóñÿêíëÿ|Ö„ÿ+º7ÿ$·1ÿ#·0ÿ#·0ÿ$¸2ÿ'¸3ÿ(º5ÿ+»8ÿ0½>ÿeÌmÿÍÜÏÿ¡Ý¦ÿBÃLÿ7ÀDÿBÅOÿºëÀÿõ÷öÿ÷øøÿ÷øøÿ÷øøÿõ÷öÿôõõÿñóòÿìïíÿçêçÿÞäàÿ×ÞØÿÎÖÏÿÇÐÈÿÁÌÂÿ¼È¾ÿ¯È±ÿ€Æ†ÿUÀ_ÿ@½Kÿ/¼<ÿ.½;ÿ2»>ÿ9»CÿF¼QÿU¾^ÿi¿pÿ}Á„ÿ•Úÿ®Ç°ÿ·Èºÿ¼É¾ÿÁÌÂÿÅÏÆÿÉÓËÿÐÙÒÿØßÚÿáæâÿèìéÿïòðÿôõõÿöø÷ÿ÷øøÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿøùùÿ²²²ÿ¬¬¬ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ«««ÿöøøÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿ÷ùùÿõø÷ÿòõôÿêîìÿßåáÿ´ßºÿ<¾Gÿ'¸4ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ+º7ÿVÈ`ÿÔê×ÿêîìÿîòñÿîòñÿëïíÿèìêÿåéæÿåéæÿèìéÿëïíÿïóñÿòõôÿñôóÿèðëÿeÎnÿ)¸5ÿ#·0ÿ$¸1ÿ%¸2ÿ'¹4ÿ)»6ÿ,»9ÿ0½<ÿLÅXÿ½ÝÁÿ¯ß²ÿHÆSÿ9ÁEÿ<ÂHÿ–áÿó÷õÿöùøÿöøøÿöùøÿõø÷ÿóöõÿïóñÿêîìÿäéåÿÜãÞÿÔÝÖÿËÕÎÿÄÏÆÿ¿ËÁÿ¶É¸ÿ|ƃÿ?¿Iÿ/½;ÿ-¼:ÿ,»9ÿ*»7ÿ)º5ÿ'¹5ÿ'¸3ÿ$·1ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ$¸1ÿ8ºCÿU¾^ÿsÅ{ÿ“Ìšÿ¸×½ÿÕÞØÿÞæáÿçëèÿíñïÿñôóÿõø÷ÿ÷ùùÿ÷ùùÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿ±±±ÿ­­­ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ«««ÿöøøÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿ÷ùùÿõø÷ÿñôóÿèíêÿßæáÿÛ•ÿ/»;ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ+º7ÿYÊbÿ×êÙÿèíêÿëïíÿèíëÿãèäÿÝäßÿÙáÜÿÙáÜÿÝäßÿäéåÿëïíÿðôòÿñôóÿëòïÿfÏoÿ)¸5ÿ%¸1ÿ'¸3ÿ(º5ÿ+º7ÿ,º8ÿ0½<ÿ@ÂKÿ¡Ú©ÿºÞ¾ÿPÇZÿ9ÂFÿ;ÃGÿuÖ}ÿìõïÿõø÷ÿõø÷ÿõø÷ÿô÷öÿñôóÿíðïÿèìêÿáçãÿÙáÜÿÑÛÔÿÊÓËÿÃÍÄÿ¼É¾ÿ¢È¦ÿQÁ[ÿ0½=ÿ.½;ÿ.¼9ÿ+»8ÿ+º7ÿ(º5ÿ'¹4ÿ%¸3ÿ%¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ/º;ÿXÆbÿŠÔ‘ÿÊèÍÿõ÷÷ÿöùøÿ÷ùùÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿøúúÿ±±±ÿ¬¬¬ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ«««ÿ÷øøÿøùùÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿøùùÿöøøÿñôòÿèìêÿÝãÞÿoÕwÿ,º8ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ+¹7ÿ]ÊgÿØéÚÿçëèÿçëèÿáçâÿÚáÜÿÒÚÔÿÎ×ÐÿÎÖÐÿÔÜÖÿÝãÞÿçëèÿïñðÿòôóÿðóñÿ‚ÚŠÿ.»:ÿ(¹5ÿ)º5ÿ*»7ÿ-¼9ÿ0½;ÿ9ÀDÿ…Õ‹ÿÀÝÃÿYËbÿ;ÂFÿ;ÃGÿZÍdÿáôãÿõööÿõööÿôöõÿòôóÿîñðÿëîìÿæéæÿßåáÿØßÙÿÏ×ÐÿÈÒÊÿÂÌÂÿ¹È»ÿ„Æ‹ÿ;¾Gÿ/½<ÿ.¼:ÿ,¼9ÿ+¼7ÿ*º6ÿ(º5ÿ'¹3ÿ%¸2ÿ$¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿPÄZÿð÷òÿøùùÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿùúúÿ°°°ÿ¬¬¬ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ«««ÿ÷ùùÿøúúÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿøúúÿöøøÿðôòÿçìéÿ×ãÛÿ\Ífÿ*¹6ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ,º8ÿ`ËjÿÙçÜÿäéåÿàæâÿØàÛÿÐÙÒÿÈÒÊÿÅÑÈÿÆÑÉÿÍ×Ðÿ×ßÙÿâçãÿìðîÿñõóÿñõóÿÉìÌÿAÁMÿ-»:ÿ+»8ÿ-¼:ÿ0½<ÿ7¿BÿiÍrÿ¾ÜÂÿaÎkÿ<ÂHÿ<ÃHÿLÉWÿÃíÇÿñõóÿñõóÿïóñÿîñðÿêïìÿçëèÿáçãÿÛãÞÿÓÜÖÿÌÖÏÿÅÑÈÿÀÌÂÿ³Ê¶ÿiÄqÿ2½>ÿ/½;ÿ-¼:ÿ,»8ÿ*»7ÿ)º5ÿ'¹4ÿ&¸3ÿ$¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ(¹5ÿ†Öÿï÷òÿøúúÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿùûûÿ°°°ÿ¬¬¬ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿªªªÿøùùÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿøùùÿ÷øøÿðóñÿçëèÿÇäËÿIÄTÿ(¹5ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ,º9ÿeÎoÿßæßÿàåáÿÚáÜÿÒÚÓÿÉÓËÿÃÎÄÿ¯Ó³ÿ‘Ó–ÿ±ÙµÿÔÝÖÿàåáÿêîëÿðóñÿñôòÿéîêÿ}Ø…ÿ4¾Aÿ0½=ÿ0½=ÿ6ÀBÿUÇ_ÿµÚºÿmÏtÿ?ÃJÿ=ÄIÿEÅPÿ¢å¨ÿëïìÿìïíÿêîëÿèìéÿåêæÿáæâÿÜãÞÿÖÝ×ÿÐØÑÿÊÓËÿÄÎÅÿ¾ÊÀÿ§É«ÿSÃ]ÿ/½<ÿ.½;ÿ-¼9ÿ+»8ÿ*º7ÿ(¹5ÿ(¹4ÿ%¹2ÿ%·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿiÍrÿÔð×ÿùúúÿùúúÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿ¯¯¯ÿ«««ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ¨¨¨ÿªªªÿøùùÿùúúÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿøúùÿö÷÷ÿïòñÿæêçÿ®ä´ÿ3¼?ÿ&¸3ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ,º9ÿmÓuÿàåáÿÜãÝÿÔÜÖÿËÔÌÿ½Ó¿ÿzÒÿHÁRÿ5½AÿKÃVÿ¶ß¹ÿàæáÿéíëÿïñðÿïñðÿéíêÿÊåÍÿNÇYÿ4¾@ÿ4ÀAÿDÃOÿž×¢ÿrÑzÿ?ÅJÿ>ÅIÿBÆNÿ†ÚŽÿãéãÿäéåÿãèãÿàåáÿÝãÞÿÙáÛÿÕÝ×ÿÐØÑÿÊÔÌÿÆÑÈÿÂÍÃÿ½Ë¿ÿÊ–ÿA¿Kÿ/½<ÿ.¼:ÿ,»8ÿ+»7ÿ)»6ÿ(¹5ÿ'¹3ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ'¸4ÿmÏvÿÎíÒÿøúùÿùúúÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿúûûÿ®®®ÿ«««ÿªªªÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿªªªÿùúúÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿùûúÿ÷øøÿñóòÿæêçÿ“à™ÿ.»;ÿ%·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ-º:ÿtÕ|ÿÞäßÿÙßÙÿÐÙÒÿ¾ÕÁÿjÍsÿ4¼@ÿ+º7ÿ'¸4ÿ/»;ÿqÑzÿÞåÞÿêîëÿîñïÿìðíÿäéåÿÛáÜÿsÒ}ÿ8ÀDÿ:ÂEÿqÒ{ÿsÑ|ÿBÅMÿ>ÄJÿCÆNÿmÑwÿ×ãØÿÝâÝÿÛáÜÿÙßÙÿÖÞØÿÒÛÔÿÏØÑÿËÕÍÿÉÓËÿÅÐÇÿÂÍÃÿºÍ½ÿtÈ|ÿ4¾?ÿ/¼:ÿ-¼:ÿ,º8ÿ*º6ÿ)º5ÿ'¹4ÿ&¹3ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ1¼=ÿ‚ÖŠÿÞóàÿùûúÿúûûÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿ®®®ÿªªªÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿªªªÿùúúÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿùúúÿ÷øøÿðóòÿèëéÿÜŠÿ,º8ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ.»;ÿ€Ú‡ÿÝâÞÿÕÜÖÿË×Ìÿ{Ó‚ÿ5½Aÿ(¹5ÿ$·1ÿ#·0ÿ*¹8ÿEÀOÿÈæÌÿèìéÿêîìÿçëèÿàåàÿÕÝ×ÿ„Ô‹ÿ<ÂHÿ?ÃJÿ]ËfÿAÅMÿ?ÄKÿBÆNÿ]ÍfÿÈßËÿ×Ý×ÿÖÞØÿÔÝÖÿÒÚÓÿÏØÑÿÌÖÎÿËÔÌÿÈÒÊÿÆÑÈÿÃÑÅÿŸÑ£ÿSÅ\ÿ0½<ÿ.½;ÿ-¼9ÿ+»8ÿ*º7ÿ(¹4ÿ'¹4ÿ%¹2ÿ$¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿHÃRÿ˜Þžÿë÷ìÿùûúÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿûüüÿ­­­ÿªªªÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿúúúÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿúúúÿùùùÿòôòÿêíêÿrØzÿ*¹6ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ2¼>ÿ”Þ™ÿÜâÝÿÖÝ×ÿ”Øšÿ?¿Jÿ*¹6ÿ$·1ÿ$¸1ÿ%¹2ÿ*º6ÿ7¿Cÿªã¯ÿèêèÿçëçÿáæâÿÙßÙÿÒÙÒÿ|Ô„ÿ=ÃIÿ<ÃGÿ>ÅJÿ@ÅKÿBÆNÿRË]ÿµÞ¸ÿ×Þ×ÿ×ÞØÿÖÝ×ÿÔÜÕÿÓÚÓÿÑÙÒÿÐØÑÿÎÖÏÿÈØÉÿ¨Ö­ÿjÊrÿ6¿Aÿ/½;ÿ-½:ÿ,»9ÿ*»7ÿ)»6ÿ'¹5ÿ'¹3ÿ$¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ/»;ÿtÑ{ÿÄëÇÿ÷ú÷ÿûûûÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿ­­­ÿªªªÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿúûûÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿûüüÿøúúÿô÷õÿìîíÿhÕrÿ)¹6ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ(¹5ÿ<¾Gÿ»ç¿ÿÞåàÿÉáÌÿXÇcÿ-º:ÿ$·1ÿ%¸1ÿ'¸3ÿ(º5ÿ+»8ÿ7¾Bÿ’ÞšÿåëæÿáçãÿÚáÜÿÔÜÕÿËÛÌÿ_Ìgÿ?ÄKÿ<ÃHÿ>ÅJÿCÆMÿMÉWÿ Þ§ÿÞåßÿÝäßÿÜãÞÿÛâÝÿÚáÛÿÔàÕÿÈàÊÿ¨Ý­ÿ€Ó‡ÿXÈbÿ4À@ÿ1½>ÿ.½;ÿ-»9ÿ+»8ÿ+º7ÿ)¹5ÿ'¹4ÿ&¸3ÿ%¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ*º7ÿbÌkÿ£ã©ÿêøíÿùüûÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿúûûÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿûüüÿùûúÿõ÷öÿíðíÿdÓnÿ)¹6ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ+º7ÿ^ÌhÿÚêÜÿãçãÿ‘Ý—ÿ5¼Aÿ&·3ÿ%¸2ÿ'¹4ÿ)º5ÿ*»7ÿ.½;ÿ;ÂGÿ§å®ÿàæáÿÚáÜÿÖÝ×ÿÓÚÓÿ–Û›ÿEÅOÿ?ÅJÿ?ÅJÿ@ÅMÿEÇQÿz؃ÿÝìßÿÙíÛÿÎêÑÿ«ã³ÿÜ’ÿrÓ{ÿ^ÍhÿCÄPÿ7ÀBÿ4¿@ÿ2½>ÿ0½<ÿ.¼;ÿ-¼9ÿ+»7ÿ*º7ÿ(º5ÿ'¸3ÿ%¸2ÿ$¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ0¼<ÿhÎqÿ§ä¬ÿèøëÿøûùÿûüüÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿüýýÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿûûûÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿüüüÿúûúÿ÷ø÷ÿðòðÿgÔrÿ)¹6ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ.º:ÿ~Û†ÿìïìÿÛìÜÿ_Ëiÿ.»;ÿ&¸4ÿ'¹4ÿ)»6ÿ+»8ÿ-¼:ÿ3¿@ÿEÄQÿÅçÈÿÛáÜÿÖÝ×ÿÓÚÓÿ¾ÜÀÿYÌbÿBÆMÿ@ÆLÿAÆLÿAÆMÿCÆMÿRÊ\ÿ`ÏiÿVÊ_ÿDÅNÿ>ÃJÿ:ÂEÿ9ÂCÿ7ÁBÿ5ÀAÿ3¾?ÿ0¾=ÿ/½;ÿ-¼:ÿ,»9ÿ*»7ÿ)º5ÿ'¹5ÿ&¸3ÿ$·1ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ,º9ÿYÊcÿˆÛÿ¿ìÃÿîúïÿúüúÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿûüüÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿüýýÿûýüÿøúùÿòôóÿsÚ|ÿ*¹6ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸3ÿ5½Aÿ°ê´ÿñôòÿÆïÌÿ?ÀJÿ-»9ÿ(¹4ÿ+º7ÿ,»9ÿ.¼:ÿ0½=ÿ:ÁEÿhÐrÿÖã×ÿÕÝ×ÿÔÛÕÿÍÝÏÿmÓvÿEÆQÿCÆMÿDÇPÿFÈQÿCÆOÿBÆMÿBÄMÿAÄLÿ?ÄKÿ<ÃHÿ:ÂGÿ8ÁDÿ6ÀAÿ4ÀAÿ3¾?ÿ2¾>ÿ/½;ÿ.¼:ÿ,¼9ÿ+º8ÿ(º5ÿ(º4ÿ%¸3ÿ%¸1ÿ#·0ÿ.»:ÿPÇZÿrÔzÿ•ßœÿÁîÄÿêúìÿøýùÿüýýÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿýþþÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿüüüÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿüüüÿûûûÿôöôÿŽâ•ÿ,º9ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ+º7ÿWÊaÿàôáÿôöôÿ³ë·ÿ;ÀFÿ-»9ÿ*»7ÿ-¼9ÿ.½;ÿ0¾=ÿ4À?ÿAÄLÿ‘Ý•ÿ×ߨÿÔÚÔÿÐÝÑÿ~ׇÿHÇRÿDÆOÿEÇQÿMÊYÿ„Ý‹ÿ†Ýÿ}Ù„ÿxØ€ÿtÖ}ÿkÒuÿgÐpÿcÏlÿ\Îfÿ[Ìeÿ\ÎfÿUËaÿPÇZÿUË_ÿ]ÍdÿbÏlÿkÒuÿtÖ}ÿ‡Üÿžä¥ÿºì¿ÿÖõÙÿíûîÿõüöÿüýüÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿüüüÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿüüüÿúûûÿöøöÿ¾îÃÿ5¼Aÿ&¸3ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ/º;ÿ‚Þ‹ÿöøöÿøùøÿËóÏÿEÄQÿ2¾>ÿ.¼;ÿ/½<ÿ1¾=ÿ3¿@ÿ<ÁGÿ[ÍfÿÇàÉÿÔÛÔÿÒÜÒÿŒÜ‘ÿKÉXÿDÇPÿDÈOÿKÉVÿ”àšÿæíæÿäéåÿâçâÿÞäßÿÝãÝÿÝãÝÿÝåÞÿàèàÿãîäÿéòéÿíöíÿîúïÿïúðÿóüôÿöü÷ÿùüùÿýýýÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿýþýÿüýüÿüýüÿûüüÿûüûÿüýüÿüýüÿýþýÿûüüÿøùøÿßóàÿRÊ]ÿ(¹5ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ(¹5ÿAÁLÿÈñÍÿùúùÿûüûÿòùòÿvÙ}ÿ<ÀHÿ3¾>ÿ2¾>ÿ6ÀBÿ;ÂGÿGÆRÿ”Ý›ÿÕÜÕÿÔÜÔÿ’Ü—ÿOÊ[ÿFÇRÿDÆOÿJÈTÿ‰ÞÿáëâÿßåàÿÚáÚÿÖÝÖÿÑÙÒÿÏØÐÿÏØÐÿÒÚÓÿØßÙÿàåáÿêîêÿòôòÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüýüÿûüüÿúûúÿøùøÿ÷ù÷ÿöøöÿ÷ù÷ÿøùøÿúûúÿûûûÿûûûÿøúøÿðóðÿhÕrÿ*¹6ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ-º:ÿkÔtÿòùóÿûûûÿûûûÿ÷ø÷ÿÔðÕÿeÑoÿ>ÃIÿ6ÀCÿ=ÃGÿSÉ^ÿŽÝ”ÿÑÝÓÿÔÜÔÿ–ÝÿRË\ÿGÇQÿCÆOÿHÈRÿ~Ú†ÿÚæÛÿÚáÛÿÓÚÓÿÎÖÎÿÉÓÊÿÇÑÇÿÅÏÅÿÅÏÅÿÈÒÉÿÎÖÎÿÖÞ×ÿáæáÿìïìÿôöõÿûüûÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûüûÿúûúÿ÷ù÷ÿôöôÿñóñÿîñïÿîðîÿîñïÿðóðÿôöôÿöøöÿøùøÿöøöÿïòïÿŽá•ÿ-º:ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ(¹4ÿ5½Bÿ¥ê«ÿùúùÿüüüÿúûúÿõ÷õÿïñðÿÌêÎÿ\Ìeÿ@ÄKÿIÆSÿ“Þ™ÿÕÜÖÿÕÝÖÿ™ßžÿTË_ÿFÇPÿCÆNÿGÇSÿuÖ}ÿÔäÕÿÕÜÕÿÏ×ÏÿÉÓÊÿÄÎÅÿÂÍÃÿ¿ËÀÿºË¼ÿ¶Î·ÿ½Í¾ÿÈÒÈÿÏ×ÏÿÛáÛÿæëæÿòôòÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿüüüÿøùøÿôõôÿîñîÿêîêÿåêæÿâçâÿáæáÿâçâÿåêæÿêîêÿïòïÿôöôÿôöôÿíðîÿ½èÀÿ9½Dÿ&¸3ÿ#·0ÿ#·0ÿ%¸3ÿ.»:ÿZËdÿã÷åÿûûûÿüüüÿøùøÿóõóÿêîêÿàçàÿpÕ{ÿJÈUÿlÒvÿÌÜÎÿÔÜÕÿ•ÝšÿVÌ`ÿFÈQÿBÆNÿFÇQÿqÖzÿÏäÒÿÓÛÔÿËÔÌÿÅÏÅÿÂÍÃÿ¹Î»ÿ–Ï™ÿiËrÿXÅ`ÿIÂTÿWÅ`ÿˆÐÿÅÕÆÿÖÞ×ÿäèäÿïòïÿ÷ø÷ÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿ÷ù÷ÿòôòÿëîëÿäéåÿÝãÞÿØßÙÿÕÜÕÿÓÚÓÿÕÜÕÿÙàÚÿßåàÿçìçÿîñîÿïòðÿêíêÿÒçÔÿQÈ\ÿ(¹5ÿ$¸1ÿ%¸2ÿ*º6ÿ5¾Aÿä”ÿøùøÿûûûÿúûúÿõ÷öÿîñîÿäèäÿÓäÔÿiÑrÿYËcÿ®Þ²ÿÓÝÔÿ•ÞœÿUË_ÿFÇQÿBÅMÿGÇRÿrÕzÿÌáÎÿÐÙÑÿÈÒÉÿÃÎÄÿ¹Îºÿ‡ÑÿTÅ^ÿ:ÀFÿ4¿Aÿ1½=ÿ/¼;ÿ-¼:ÿ0»<ÿiÊpÿÍÞÎÿâçâÿîñïÿ÷ù÷ÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿ÷ù÷ÿñóñÿéíéÿàåàÿØßÙÿÑÙÒÿÌÕÍÿÉÓÊÿÈÑÈÿÉÓÊÿÎÖÎÿÕÜÕÿÞäßÿæëçÿêîêÿæëçÿØåÚÿXËbÿ+º7ÿ'¸3ÿ(º5ÿ0¼<ÿOÇ[ÿÖôÚÿúûúÿúûúÿöøöÿðóðÿæëæÿÞäÞÿºá½ÿ\Îfÿ|׃ÿÑÜÓÿ“Þ™ÿSÌ_ÿFÇPÿAÅMÿGÇRÿqÔyÿÍâÏÿÐØÐÿÈÒÉÿÂÏÂÿ–Ñœÿ[Çeÿ:ÁFÿ5¿Aÿ1¾<ÿ.¼:ÿ+»8ÿ+º7ÿ(º5ÿ)º6ÿ*¹8ÿ{Ó‚ÿáèáÿïòïÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿøùøÿñóñÿéíéÿßåàÿÖÝÖÿÎÖÎÿÈÒÈÿÃÎÄÿÀËÁÿÀÌÁÿÁÌÂÿÇÑÇÿÎ×Îÿ×ߨÿàæàÿäéåÿâçâÿÑâÒÿTÉ^ÿ+»9ÿ)º5ÿ,¼9ÿ7¿Cÿ|Þ„ÿöùöÿùúùÿ÷ù÷ÿòôòÿêîêÿßåàÿØßÙÿ“Ü™ÿaÏjÿ°à´ÿ’ß™ÿRÊ]ÿEÇPÿAÆMÿGÆQÿqÓzÿÎâÏÿÐÙÑÿÉÒÉÿ¸Ð»ÿwÐ~ÿCÄNÿ7¿Bÿ1¾>ÿ/¼;ÿ,¼9ÿ+¼7ÿ*º6ÿ(º5ÿ'¹3ÿ%¸2ÿ&¹3ÿ0º<ÿÄèÇÿòôòÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿóõóÿêîêÿàæáÿÖÝÖÿÌÕÍÿÅÏÅÿºÏ¼ÿÔ”ÿgÑpÿZÏdÿ_Ðgÿ}Ô…ÿ¹Ö»ÿÓÛÔÿÜâÜÿàåàÿÞäßÿ¾ãÂÿEÃOÿ-»:ÿ+»8ÿ2¾?ÿIÆSÿÇñÌÿ÷ù÷ÿöøöÿòôòÿëîëÿâçâÿÙàÚÿÑÝÒÿu×}ÿyØ€ÿŽÚ•ÿNÉYÿCÆOÿAÆMÿFÆRÿrÖzÿÑåÒÿÓÛÔÿÊÓËÿ±Ò´ÿ`Ìiÿ<ÁGÿ4¾@ÿ0½<ÿ-¼:ÿ,»8ÿ*»7ÿ)º5ÿ'¹4ÿ&¸3ÿ$¸1ÿ#·0ÿ$·1ÿ&¸3ÿ‰Ûÿõ÷öÿûûûÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûüûÿôöõÿíðíÿâçâÿÖÞ×ÿÍÖÎÿÃÏÃÿŽÕ“ÿKÈVÿ.º9ÿ(¹5ÿ'¸4ÿ(¹5ÿ,º8ÿIÅSÿ Ü¦ÿÙàÚÿÝäÞÿÝâÝÿ¥àªÿ6½Bÿ/¼:ÿ/¼<ÿ7ÀDÿoÙyÿïôðÿôöõÿñóñÿëîëÿãèãÿÚàÚÿÕÜÕÿ¶àºÿ\ÎeÿfÐmÿIÈTÿAÅLÿAÅLÿGÇRÿu×~ÿÕèÖÿ×ߨÿÎÖÏÿ¦ÕªÿWÊaÿ:ÁFÿ2¾>ÿ.½;ÿ-¼9ÿ+»8ÿ*º7ÿ(¹5ÿ(¹4ÿ%¹2ÿ%·1ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ{؃ÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿðóðÿåêæÿÚáÚÿÏ×Ïÿ¿ÒÀÿgÓpÿ1»=ÿ&¸3ÿ%¸2ÿ$·1ÿ#·0ÿ$·1ÿ%¸2ÿ*¹6ÿKÅUÿÃàÆÿÛáÛÿÚáÛÿƒÛŠÿ5¿Aÿ1½<ÿ3¾?ÿCÃNÿ±ì·ÿòôòÿðóðÿêîêÿãèãÿÛáÛÿÕÜÕÿÏÜÑÿt×|ÿKÈVÿCÇOÿ@ÅKÿAÅLÿIÇTÿ܆ÿÚëÜÿÝãÝÿÒÚÓÿ¯×±ÿTÈ^ÿ9ÀDÿ1¾>ÿ.¼:ÿ,»8ÿ+»7ÿ)»6ÿ(¹5ÿ'¹3ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ'¸4ÿžå£ÿüüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿúûúÿôöõÿëîëÿßåàÿÓÛÔÿÀÕÂÿ\Òeÿ*¹7ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ'¹3ÿ/¼;ÿ†ÜÿÛáÛÿØßÙÿgÓpÿ5¿Aÿ2¾>ÿ9ÁEÿdÒnÿæòçÿíðîÿéíéÿâçâÿÛáÛÿÕÜÕÿÔÝÕÿ˜ÞœÿOÊ\ÿBÅNÿ>ÅJÿAÅMÿLÈUÿ†àŽÿáîâÿâæâÿØßÙÿ¿ÛÁÿ[Édÿ9ÀEÿ1½<ÿ-¼:ÿ,º8ÿ*º6ÿ)º5ÿ'¹4ÿ&¹3ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿEÃPÿãøäÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿñóñÿåêæÿÙàÚÿË×ÌÿbÖmÿ)¸6ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·2ÿ(¸4ÿ.¼;ÿo×xÿÚáÚÿÊáÌÿUË_ÿ6¿Bÿ7ÀBÿ@ÄLÿ™æŸÿëîëÿæëæÿàåàÿÚáÚÿÕÜÕÿÕÜÖÿ¥à©ÿYÎcÿEÇPÿ>ÄJÿBÅLÿNÉYÿŽà•ÿåïåÿäéåÿÝãÞÿÔßÔÿsÒ|ÿ;ÁFÿ1¾=ÿ-¼9ÿ+»8ÿ*º7ÿ(¹4ÿ'¹4ÿ%¹2ÿ$¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ-º9ÿ¨é­ÿüýüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿöøöÿíðîÿáæáÿÔÛÔÿÙˆÿ/»;ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$¸1ÿ%¹2ÿ'¹4ÿ)»6ÿ0¼<ÿfÔoÿÚàÚÿ°ä´ÿ@ÃKÿ6ÁCÿ;ÂHÿXÌbÿÒëÕÿäèäÿÞäßÿØßÙÿÔÛÔÿÔÛÕÿ«ß°ÿ\ÎdÿEÆQÿ>ÅIÿBÅMÿOÉ[ÿ–ã›ÿèîèÿåêæÿâçâÿÞäÞÿ­á²ÿDÄNÿ2¾>ÿ,»9ÿ*»7ÿ)»6ÿ'¹5ÿ'¹3ÿ$¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ,º9ÿß—ÿóøóÿûûûÿüýüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿûûûÿõöõÿëîëÿÝãÞÿ´Ü¶ÿ<ÂHÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸1ÿ'¸3ÿ(º5ÿ*º7ÿ-º9ÿ3¾>ÿsÚ}ÿÝâÝÿ…Üÿ<ÂIÿ9ÁDÿ@ÄLÿzÜ‚ÿàæáÿÜâÜÿÖÞ×ÿÒÚÓÿÑÚÒÿ£ß§ÿ[ÌeÿDÆPÿ>ÅIÿAÅMÿSË]ÿå£ÿçíçÿçìçÿåêæÿãèãÿáæáÿƒÚŠÿ7¿Cÿ-¼:ÿ+º7ÿ)¹5ÿ'¹4ÿ&¸3ÿ%¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ'¸4ÿ0»=ÿ’ß™ÿêñëÿôõôÿ÷ù÷ÿúûúÿûüüÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûüûÿôõôÿéíéÿÛâÛÿ[Ódÿ&¸3ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#¶0ÿ%¸2ÿ'¹4ÿ)º5ÿ*»7ÿ,¼9ÿ0¾<ÿ8¿Dÿà˜ÿÛâÛÿeÒoÿ=ÃHÿ<ÃHÿNÈYÿ¸å»ÿØßÙÿÔÛÔÿÐØÑÿÐÚÑÿ”Ý›ÿVË`ÿCÅNÿ=ÃIÿAÅMÿVËaÿ¥ç¬ÿèíèÿçëçÿçìçÿæëçÿçìçÿÕì×ÿdÎmÿ2½=ÿ*º7ÿ(º5ÿ'¸3ÿ%¸2ÿ$¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ*¹6ÿGÂQÿ¡Ü¥ÿÝæÞÿåêæÿëîëÿðóðÿõöõÿøùøÿûûûÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿúûúÿôöôÿéíéÿ³ä·ÿ6¾Bÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ$¸1ÿ%¸3ÿ'¹4ÿ)»6ÿ+»8ÿ-¼:ÿ/½;ÿ4¾@ÿKÈVÿÅèÉÿÊãÍÿVÌ`ÿ>ÄJÿBÅMÿhÔrÿÑÜÓÿÐÙÑÿÏÖÏÿÍØÍÿˆÜÿQÊ[ÿBÅMÿ=ÄHÿBÅNÿZÍdÿ¯è³ÿèìèÿéíéÿéíéÿêíêÿçîçÿ½ê¿ÿaÎkÿ7ÀCÿ,»8ÿ(¹6ÿ&¸3ÿ$·1ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ&¸3ÿ*¹6ÿ4¼@ÿkÌsÿ»Ù½ÿÐØÐÿÔÛÔÿÚáÚÿàæáÿæëæÿíñîÿôöôÿøùøÿûüüÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿûüûÿôõôÿêîêÿmÛwÿ&¸3ÿ$·1ÿ#·0ÿ#·0ÿ$·1ÿ'¹3ÿ(¹4ÿ+º7ÿ,»9ÿ.¼:ÿ0½<ÿ3¾?ÿ8ÁDÿeÕoÿÝåÞÿªâ¯ÿFÇQÿ@ÅMÿIÇTÿ™ÞžÿÍÖÎÿÌÕÍÿÄׯÿ{Ù‚ÿMÈWÿAÄLÿ<ÃHÿCÅMÿ`Ïjÿ½ëÁÿëïëÿêíêÿìîìÿéîéÿÊìÍÿ܆ÿMÇWÿ;ÀFÿ3¾@ÿ1½>ÿ.»;ÿ,º7ÿ(¹5ÿ&¸3ÿ'¸4ÿ(¹5ÿ)¹6ÿ,º8ÿ6¼CÿgÌpÿ¦ÖªÿÄÑÅÿÆÐÇÿÇÑÇÿÊÔËÿÏØÐÿÖÞ×ÿÞäßÿçìçÿïòïÿöøöÿûûûÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿõ÷õÿéðéÿOÎYÿ&¸2ÿ#·0ÿ$·1ÿ%¸2ÿ(º4ÿ)º5ÿ*»7ÿ-¼9ÿ.½;ÿ0¾=ÿ2¿>ÿ7ÁBÿEÅPÿ­ç³ÿÝãÝÿ{Ú„ÿDÆOÿDÇOÿ]Îeÿ¾ÖÀÿÊÔËÿ¼Ø¿ÿmÕvÿGÈSÿ?ÅKÿ<ÃHÿCÅNÿdÑmÿÊîÍÿíðíÿîñîÿêðêÿÇîÊÿƒÜŠÿWÊaÿDÄNÿEÃOÿbÌjÿ~Ö…ÿ‰ÙÿÕ‡ÿ`Êiÿ@ÀLÿ3¼?ÿ8¼DÿIÁTÿ_ÈgÿЉÿ­Õ²ÿÀÎÁÿ¿ÍÀÿ’ЗÿoËwÿ Ð¥ÿÅÐÅÿËÔÌÿÒÚÓÿÛáÛÿäéåÿïñïÿõ÷õÿûüûÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿÚòÜÿDÆOÿ%¸2ÿ$·1ÿ&¹3ÿ'¹5ÿ*º7ÿ+¼8ÿ-¼:ÿ/½<ÿ1¾=ÿ2¿?ÿ6ÀAÿ=ÃGÿg×pÿáêáÿØàÙÿcÒlÿEÆOÿGÈSÿtÕ{ÿËÓËÿµÜ·ÿbÑmÿEÆQÿ>ÃIÿ;ÃHÿDÄNÿkÔtÿÕðÙÿðóñÿéóêÿ¼ìÂÿ|ÚƒÿTÉ`ÿHÃRÿXÊcÿ|׃ÿ°ß´ÿËÛÌÿÏØÏÿÌÖÍÿÊÓÊÿÂÒÃÿ¶Ö¹ÿ®Õ±ÿ³Óµÿ¶Ð¹ÿ¿ÏÀÿÁËÁÿÀÊÁÿ¹Í»ÿvÌ~ÿ/º<ÿ*¹6ÿ9¼Cÿ“Ò—ÿÌÖÍÿÕÛÕÿÝäÞÿçìçÿðóðÿ÷ù÷ÿüüüÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿúûúÿ×õÙÿ?ÃKÿ&¸3ÿ'¹3ÿ(¹5ÿ*º6ÿ,»9ÿ.¼;ÿ0½<ÿ2¾>ÿ4¿@ÿ6ÀBÿ9ÁFÿPËZÿÁëÄÿàåàÿÂàÄÿUË`ÿGÈSÿPÊZÿªÛ¯ÿ¥Ûªÿ[ÍdÿCÅNÿ;ÂHÿ<ÂGÿDÄNÿtÙ~ÿâóãÿàôâÿ¤è©ÿqÖzÿQÇZÿLÆWÿkÐrÿÝ—ÿÂàÅÿÐØÐÿÊÔËÿÇÑÇÿÃÎÄÿÂÍÃÿÁÌÂÿÁËÁÿÀËÁÿ»Î½ÿ¶Î¸ÿ±Í²ÿ­Ð°ÿ¡Ï¤ÿ„ΊÿZÅbÿ-º:ÿ&¸2ÿ$·1ÿ&¸3ÿ2¼@ÿoÎxÿªÞ®ÿËèÎÿÛðÝÿìôíÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿã÷äÿGÈRÿ)º6ÿ)º5ÿ+¼7ÿ-¼9ÿ/¼:ÿ0¿=ÿ3¾>ÿ4¿Aÿ6ÁBÿ:ÂEÿBÅNÿä•ÿæêæÿÝâÝÿŸß£ÿIÊTÿGÈQÿcÑlÿ•ÝšÿTË_ÿAÅMÿ<ÃGÿ;ÂGÿCÄOÿ€Ü‡ÿÎóÑÿã–ÿeÐnÿJÅVÿVÊbÿyÙÿ®ä²ÿÏßÐÿÐØÐÿÉÓÊÿÅÐÆÿÂÌÃÿÁÌÂÿ½Ì¾ÿ¯Ñ²ÿ™Òœÿ}΄ÿhËqÿWÅaÿLÂVÿ?¿Kÿ4¼@ÿ.»;ÿ+¹7ÿ(¹5ÿ%¸2ÿ#·0ÿ#·0ÿ$·1ÿ%¸2ÿ'¸4ÿ(¹5ÿ)¹6ÿ4»@ÿ{ׄÿøüøÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿöùöÿYÕdÿ,»8ÿ,»8ÿ-¼:ÿ/½<ÿ1½=ÿ2¿?ÿ5À@ÿ7ÀBÿ:ÂFÿ@ÄJÿnÛvÿàíáÿßåàÿØàÙÿvÚ}ÿEÇPÿEÆPÿaÔlÿPÉYÿ?ÄKÿ:ÃFÿ8ÁEÿ?ÃLÿrÙ}ÿ‡ÞŽÿYËcÿQÈ[ÿmÔvÿâ—ÿÈéËÿÛãÛÿÓÛÔÿËÔÌÿÆÐÆÿÃÍÄÿºÏ¼ÿ¢Ô¥ÿ}Ñ„ÿaÉiÿB¿Lÿ3¼?ÿ-º:ÿ+º7ÿ*¹6ÿ(¹5ÿ'¸4ÿ&¸3ÿ&¸2ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¸2ÿ&¸3ÿ.º:ÿ¡ç§ÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿ÷ù÷ÿê¥ÿ7¿Dÿ0½<ÿ0½=ÿ2¿>ÿ4¿@ÿ6ÀBÿ8ÁCÿ:ÂFÿ?ÄJÿ`ÕkÿÖì×ÿàåàÿÙàÙÿÐÛÐÿ`ÒiÿAÆMÿ>ÄKÿBÅLÿ=ÄIÿ9ÂEÿ8ÀCÿ:ÂEÿ@ÄLÿFÆQÿeÓoÿ‡âÿÄñÈÿäïäÿäéäÿÚáÛÿÐØÑÿÉÓÊÿÅÏÆÿ²ÓµÿƒÓ‹ÿ[Èeÿ:¾Dÿ0»<ÿ,º8ÿ)¹6ÿ&¸3ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸3ÿ7¾Cÿ¡æ§ÿøüùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿûûûÿõ÷õÿçñèÿ]Õgÿ4¿@ÿ3¾?ÿ5ÀAÿ6ÀCÿ8ÁDÿ;ÃGÿ>ÄKÿVÏbÿÈëÌÿàæàÿÚáÚÿÕÜÕÿ»à¿ÿPÊ[ÿ>ÄJÿ<ÃGÿ:ÂFÿ9ÁDÿ9ÂDÿ<ÁGÿIÆTÿpÙxÿ±ïµÿèøéÿòôòÿêíêÿâçâÿØßÙÿÏØÐÿÉÒÉÿÀÑÂÿ‰ÕÿNÄYÿ3¼?ÿ,º9ÿ'¸4ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ)¹6ÿVÉ`ÿËóÍÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿóõóÿéíéÿÁæÄÿJÉTÿ7ÁCÿ7ÁCÿ8ÂDÿ;ÂGÿ=ÄJÿQÌZÿµçºÿßåàÿÙàÚÿÖÝÖÿÔÛÔÿ”à›ÿAÄMÿ;ÃGÿ8ÂEÿ9ÂEÿ:ÁGÿAÃLÿhÕrÿÀôÄÿöû÷ÿöøöÿñóñÿêîêÿáæáÿ×ÞØÿÏ×ÏÿÉÒÉÿ¸ÔºÿnÏvÿ:¾Dÿ,º9ÿ&¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ'¸4ÿ2½>ÿ‚܉ÿìûíÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿöøöÿîñïÿäèäÿÙàÙÿ~܈ÿ:ÂEÿ:ÂFÿ;ÃGÿ?ÅJÿJÈTÿ›å¢ÿÝãÞÿØßÙÿÖÝÖÿÖÝÖÿŸá¥ÿRË]ÿ<ÃHÿ8ÁEÿ:ÂDÿ<ÂHÿTË^ÿë¥ÿðûñÿùúùÿõ÷õÿðóðÿéíéÿàæàÿÖÞ×ÿÎÖÎÿÉÒÉÿ±Õ³ÿ_Ëhÿ3¼?ÿ(¹5ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ'¸4ÿ+º7ÿ[ÌeÿÁòÆÿúþûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿôöôÿêîêÿßåàÿÒÞÓÿXÒaÿ<ÃGÿ<ÄHÿ>ÄJÿCÈPÿuÜ}ÿÛâÛÿ×ÞØÿÖÝÖÿÕÞÕÿá—ÿNÊYÿ<ÃIÿ9ÂEÿ9ÂEÿ?ÃJÿeÕnÿÒöÔÿøùøÿöøöÿóõóÿíðîÿæëæÿÞäßÿÖÝÖÿÎÖÎÿÈÑÈÿ¨Ô¬ÿWÈaÿ1¼=ÿ&¸3ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ(¹5ÿ,º8ÿLÆWÿ™å ÿñýòÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿ÷ù÷ÿîñïÿäéåÿÚáÚÿœß£ÿDÆOÿ=ÄJÿ?ÄKÿCÆNÿ]ÕgÿÐáÒÿÖÞ×ÿÕÜÕÿÑÞÒÿ~Þ‡ÿGÇRÿ<ÂGÿ9ÂEÿ:ÁFÿHÇSÿ†åÿëøìÿõ÷öÿóõóÿîñïÿêîêÿãèãÿÜâÜÿÔÛÔÿÍÖÎÿÈÒÈÿ¢×§ÿPÄZÿ/»;ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸3ÿ)¹6ÿ-º:ÿXËbÿšå ÿëüìÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿôöôÿêîêÿßåàÿÔÞÔÿZÓcÿ@ÅKÿ@ÅLÿCÇNÿNÊZÿ¯â´ÿÕÜÕÿÔÛÔÿÍßÏÿqÛyÿCÅNÿ:ÂFÿ9ÁDÿ:ÂFÿRÊ\ÿªë¯ÿñõòÿñóñÿîñîÿéíéÿäèäÿÞäßÿ×ÞØÿÑÙÒÿËÔÌÿÉÓÉÿšØ ÿJÂUÿ-º:ÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¸2ÿ'¸4ÿ+¹7ÿ5½AÿiÒsÿ±í·ÿðýñÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿ÷ù÷ÿîñïÿäéåÿÙàÚÿŸÜ¤ÿGÇRÿAÆLÿCÆNÿFÆQÿyÜ€ÿÓÚÔÿÒÚÓÿÆßÈÿd×oÿ@ÄIÿ:ÁEÿ8ÁCÿ;ÂFÿ\ÒeÿÅîÊÿíðíÿêîêÿæëçÿâçâÿÜãÝÿØßÙÿÓÛÔÿÏ×ÏÿÊÔËÿÈÒÈÿ•×™ÿEÂQÿ,º9ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ'¸4ÿ*¹6ÿ.»;ÿAÂMÿ{ÚƒÿÇôÌÿ÷þ÷ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿôöôÿêîêÿÞäßÿÒÛÒÿZÔfÿCÆMÿCÆNÿDÆNÿXÒbÿÆÙÆÿÐØÑÿ¹Þ¼ÿYÑcÿ<ÃHÿ9ÁDÿ8ÁDÿ;ÂGÿiØrÿÓìÕÿåêæÿâçâÿÝãÞÿÚáÚÿÖÞ×ÿÒÚÓÿÐØÐÿÌÕÍÿËÕÌÿÈÕÊÿŽÛ“ÿBÀNÿ+¹7ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ'¸4ÿ+º7ÿ.»;ÿ<ÀGÿiÓsÿœæ¢ÿÞùÞÿúüúÿþþþÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿ÷ù÷ÿîñïÿäèäÿ×ÞØÿ¢Ü¨ÿJÇUÿDÇOÿBÆMÿLÉVÿ¢Ù§ÿËÔÌÿ¤Û©ÿPÍZÿ;ÃFÿ8ÁDÿ7ÁCÿ?ÄKÿxÝÿØæÙÿÜâÜÿØßÙÿÖÝÖÿÒÚÓÿÏØÐÿÎÖÎÿÍÖÎÿÍÕÎÿÎÖÏÿ¾ÛÁÿtÖ|ÿ:¾Fÿ*¹6ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ'¸4ÿ+º7ÿ/»;ÿ9¾DÿaÏlÿâ—ÿÒöÕÿõýöÿüýüÿüýüÿüýüÿüýüÿüýüÿýþýÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿóõóÿéíéÿÝäÞÿÑÙÒÿ\ÕfÿCÇNÿAÆLÿ@ÅMÿiÖpÿÆÑÆÿÙ”ÿJÉUÿ9ÁFÿ7ÁDÿ6ÀCÿCÅNÿ‚Þ‹ÿÔßÕÿÒÚÓÿÏØÐÿÍÖÍÿËÔÌÿÊÓËÿÊÓËÿÌÕÍÿÎ×Ïÿ¸Ü»ÿØŠÿQÈ[ÿ/»;ÿ(¹5ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ(¹5ÿ,º9ÿ0»<ÿ9¾Dÿ\Ìeÿ†ßÿÅóÈÿîûðÿûüüÿüüüÿûüûÿúûúÿùúùÿøùøÿøùøÿùúùÿûüûÿûüüÿýþýÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿýýýÿýýýÿýýýÿþþþÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿöøöÿîñïÿãèãÿÖÞ×ÿ¦Ý«ÿJÉUÿ@ÅMÿ@ÅJÿMÊWÿ«Ó¯ÿyØÿDÆPÿ:ÂDÿ6ÀCÿ7ÀBÿFÆRÿÜ—ÿÍ×ÎÿÊÓËÿÈÑÈÿÆÐÆÿÅÏÅÿÆÐÆÿÈÒÈÿÁØÂÿ¢Ý¨ÿkÓtÿGÂQÿ.»;ÿ)¹6ÿ&¸2ÿ$·1ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ)¹6ÿ,º9ÿ2¼>ÿ@ÁJÿhÑqÿŒá”ÿÄôÇÿêùëÿúûúÿùúùÿøùøÿ÷ù÷ÿöøöÿôöõÿóõóÿòôòÿðòðÿñóñÿòôòÿôöõÿøùøÿûüûÿüýýÿüýüÿüýüÿüýüÿüýüÿûüüÿüüüÿüüüÿûûûÿüüüÿûüüÿüýüÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿóõóÿéíéÿÝãÝÿÐØÑÿ^ÕhÿAÅMÿ>ÄJÿ?ÄKÿi×rÿi×qÿ@ÃKÿ9ÂCÿ6ÀAÿ6ÀBÿKÈVÿØ¢ÿÆÐÆÿÄÏÅÿÁÌÂÿÀËÁÿÀÌÁÿµÑ¸ÿ–Ö›ÿjÓrÿQÇ[ÿ3»?ÿ+º7ÿ(¹5ÿ%·1ÿ$·1ÿ#·0ÿ$·1ÿ&¸3ÿ)¹6ÿ,º9ÿ2¼>ÿHÄRÿmÔvÿ–äœÿÌñÐÿì÷îÿõöõÿôöõÿôõôÿóõóÿòôòÿðóðÿîñïÿíðíÿêîêÿèìèÿåêæÿäéåÿåêæÿçëçÿìïìÿñóñÿõ÷öÿøùøÿùúùÿùúùÿøùøÿ÷ù÷ÿöøöÿõ÷õÿõ÷öÿõ÷öÿöøöÿ÷ù÷ÿùúùÿüüüÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿõ÷õÿîñîÿâçâÿ×Þ×ÿ¦ÛªÿIÈTÿ>ÄJÿ=ÄIÿJÈUÿVÕaÿ=ÃHÿ7ÁDÿ6ÀAÿ5ÀBÿOÊYÿ¦Õ«ÿÂÍÃÿ¿ËÀÿ½Ë½ÿªÑ­ÿ…Ò‹ÿ_ÎiÿHÄTÿ0»<ÿ*¹6ÿ(¹5ÿ&¸2ÿ$·1ÿ$·1ÿ%¸2ÿ&¸3ÿ)¸5ÿ,º9ÿ3¼?ÿPÅZÿq×zÿžå£ÿÐðÒÿéðéÿîñîÿìïìÿìïìÿëîëÿëïëÿéíéÿèìèÿæëçÿäéåÿâçâÿßåàÿÜãÝÿÚáÚÿØßÙÿ×ߨÿØßÙÿÜâÜÿáæáÿçëçÿíðíÿðóðÿñóñÿñóñÿðóðÿîñïÿíñîÿíðíÿìïìÿìïìÿîñîÿðóðÿôõôÿøùøÿûüüÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿñóñÿçìçÿÜâÜÿÑÙÒÿ\Ôdÿ>ÄJÿ;ÃGÿ:ÂFÿ;ÄFÿ:ÂDÿ6ÁCÿ5ÀAÿ5ÀAÿUÐ`ÿµÖ·ÿ¼Ò¾ÿÔ¡ÿrÔyÿTÍ^ÿ@ÁKÿ.»:ÿ*º7ÿ'¹4ÿ&¸2ÿ$·1ÿ$·1ÿ%¸2ÿ&¸3ÿ)¸5ÿ,º9ÿ6½BÿUÉ_ÿt×|ÿ¤â©ÿÌæÎÿÝäÞÿßåàÿßåàÿßåàÿßåàÿßåàÿÞäßÿÞäßÿÜãÝÿÜâÜÿÚáÚÿØßÙÿÖÞ×ÿÔÛÔÿÑÙÒÿÏØÐÿÍÖÎÿËÔÌÿÊÓËÿÌÕÍÿÏØÐÿÖÝÖÿÝãÝÿâçâÿäéåÿåêæÿäéåÿäèäÿâçâÿàåàÿßåàÿßåàÿàæáÿãèãÿèìèÿîñïÿôöõÿúûúÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿõöõÿìïìÿáæáÿ×Þ×ÿ¢Ü§ÿFÆSÿ<ÃGÿ8ÂDÿ8ÀCÿ6ÀCÿ6ÀAÿ3¿@ÿ4¿@ÿUÑ`ÿwÜÿgÓoÿLÉVÿ8¾Bÿ.¼:ÿ*º7ÿ)¹5ÿ&¸3ÿ$·1ÿ#·0ÿ$·1ÿ&¸2ÿ)¹6ÿ,º9ÿ:¿FÿYËcÿwÕ€ÿ§Ü«ÿÄÚÅÿÐ×ÐÿÐØÐÿÐØÑÿÐØÑÿÑÙÒÿÑÙÒÿÑÙÒÿÑÙÒÿÑÙÒÿÑÙÒÿÐØÑÿÏØÐÿÏ×ÏÿÍÖÍÿËÔÌÿÉÓÊÿÈÑÈÿÆÐÆÿÄÎÄÿÃÎÄÿÂÍÃÿÂÍÃÿÃÎÄÿÈÒÈÿÌÕÍÿÑÙÒÿÖÝÖÿ×ÞØÿ×ÞØÿ×ߨÿÖÝÖÿÔÛÔÿÓÛÔÿÒÚÓÿÓÛÔÿÕÜÕÿÚáÚÿáæáÿêîêÿòôòÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿüüüÿ÷ù÷ÿïòïÿåêæÿÛáÛÿÑÛÒÿZÔeÿ;ÂGÿ9ÂDÿ7ÀBÿ6ÀBÿ4À@ÿ3¾>ÿ2¾>ÿ2¾?ÿ7¿Cÿ/½;ÿ.¼:ÿ,»8ÿ*º7ÿ(¹5ÿ%¹2ÿ$·1ÿ#·0ÿ#·0ÿ%¸2ÿ*¹6ÿ6½CÿVÉ_ÿzÓ‚ÿ©Ö®ÿÀÐÁÿÄÏÅÿÄÏÅÿÄÏÅÿÄÏÅÿÄÎÄÿÅÏÅÿÅÏÅÿÆÐÆÿÆÐÆÿÆÐÆÿÆÐÆÿÆÐÆÿÆÐÆÿÅÏÅÿÄÎÄÿÄÏÅÿÃÎÄÿÁÌÂÿÁÌÂÿÁÌÁÿÀÌÁÿÀËÁÿ¾Ì¿ÿ³Îµÿ§Ñªÿ•Ñšÿ…Ï‹ÿžÓ¡ÿÇÒÇÿÉÓÊÿËÔÌÿËÔÌÿÊÓËÿÉÓÊÿÈÒÉÿÈÒÉÿÈÒÉÿÊÓËÿÏ×ÏÿÖÝÖÿÞäßÿéíéÿòôòÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿóõóÿêîêÿßåàÿÖÞ×ÿ™ÞŸÿDÆOÿ9ÂEÿ6ÀCÿ5À@ÿ3¿@ÿ3¿?ÿ2¿>ÿ1¾>ÿ.½;ÿ-»9ÿ*»7ÿ)»6ÿ(¹5ÿ'¹3ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ&¸3ÿDÅPÿpÚyÿšØŸÿ«Õ¯ÿ¯Ó±ÿ³Ð¶ÿºÏ¼ÿ¿ÎÀÿ¿ËÀÿÀÌÁÿÁÌÁÿÁÌÁÿÁÌÁÿÁÌÁÿÁÌÁÿÁÌÁÿÁÌÁÿÁÌÁÿÁËÁÿÀÊÀÿÁËÂÿÀËÁÿÀÌÁÿ¹Í»ÿ±Ï´ÿ¥Ò¨ÿŒÑ‘ÿsÍ{ÿ_ÉiÿIÁTÿ4¼?ÿ.»;ÿ/»;ÿPÃZÿ»Ï½ÿÁÌÂÿÂÍÃÿÂÍÃÿÁÌÂÿÁÌÂÿÂÍÃÿÄÏÅÿÆÐÆÿÊÔËÿÐØÑÿ×ÞØÿáæáÿìïìÿôõôÿúûúÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿõöõÿíðíÿäéäÿÚáÚÿËÝÌÿRÒ]ÿ9ÁEÿ6ÀCÿ4ÀAÿ2¿?ÿ4¿@ÿ7ÁDÿQÏ]ÿ<ÁJÿ/¼;ÿ,»8ÿ*º6ÿ'¹4ÿ&¹3ÿ%¸1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ)¹6ÿ,º9ÿ.»;ÿ5¼BÿAÀMÿJÄUÿSÈ^ÿ[ÊdÿaÌjÿjÐsÿoÑwÿuÒ}ÿxÒ€ÿÓ‰ÿ†ÓÿŒÔ’ÿ‰Òÿ…Ó‹ÿ†Òÿ‚ÑŠÿ{Ñ‚ÿsÏzÿjÌrÿ[ÈeÿHÁRÿ5¼Aÿ0»<ÿ,º9ÿ*¹6ÿ(¹5ÿ&¸3ÿ&¸2ÿ(¹5ÿE¿OÿµÎ·ÿ¿ËÀÿÀÊÁÿºË¼ÿ¶Ï¹ÿ²Òµÿ£Ò§ÿ‘ЖÿΆÿxÏ€ÿuÏ|ÿoÏxÿtÑ|ÿ ã¦ÿñøñÿûüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿöøöÿïòïÿæëæÿÝãÞÿ×ߨÿ}à‡ÿ;ÁHÿ6ÀBÿ4À@ÿ3¾?ÿ4¿?ÿBÄMÿˆéÿìûíÿÄöÇÿhÜsÿ@ÅLÿ*º6ÿ'¹3ÿ%¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¸2ÿ&¸2ÿ&¸3ÿ'¸4ÿ(¹5ÿ)¹6ÿ*¹6ÿ*¹6ÿ+º7ÿ+º7ÿ,º9ÿ-º:ÿ.º:ÿ0»<ÿ1»=ÿ2¼>ÿ1»=ÿ1¼=ÿ0»<ÿ.»;ÿ-º:ÿ,º9ÿ+º7ÿ)¹6ÿ'¸4ÿ&¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ0»<ÿqÌyÿqÍzÿcÇkÿSÄ^ÿD¿Oÿ2º>ÿ+º7ÿ)¹6ÿ'¸4ÿ&¸3ÿ&¸2ÿ&¸2ÿ&¸3ÿ9¾Dÿêúëÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿøùøÿñóñÿéíéÿàåàÿÚáÚÿ½âÁÿJÊUÿ7ÀBÿ3¿?ÿ3¾?ÿ3¾>ÿIËTÿ°ó¶ÿüýüÿþþþÿþþþÿýþýÿÕúØÿyã‚ÿJÉUÿ*º7ÿ&¸3ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ$·1ÿ%¸2ÿ&¸2ÿ&¸2ÿ&¸2ÿ&¸2ÿ%¸2ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ(¹5ÿ)¹6ÿ(¹5ÿ'¸4ÿ&¸3ÿ&¸2ÿ%¸2ÿ$·1ÿ#¶0ÿ#·0ÿ#·0ÿ$·1ÿ&¸3ÿ‹Ý‘ÿùüùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿþþþÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿþþþÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüýüÿøùøÿóõóÿìïìÿãèãÿÜâÜÿÕà×ÿaÚkÿ6ÀCÿ3¿@ÿ2½>ÿ3¾?ÿLÍXÿÆ÷Ëÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿçüéÿ£îªÿ`×jÿ<ÁHÿ(¹5ÿ&¸3ÿ&¸2ÿ%¸2ÿ$·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ÿ$·1ÿ&¸3ÿoÓyÿñüòÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿÿÿÿÿþþþÿþþþÿýýýÿýýýÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿûûûÿüüüÿüüüÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿõöõÿîðîÿåêæÿÞäßÿÚàÚÿŽä–ÿ>ÃJÿ3À@ÿ2½>ÿ1¾?ÿQÑ\ÿÒ÷ÕÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûýûÿÓùÖÿ‹ç“ÿ^Õhÿ@ÃLÿ*¹6ÿ(¹5ÿ'¸4ÿ&¸3ÿ&¸2ÿ%¸2ÿ$·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ÿ%¸2ÿ(¹5ÿoÓvÿîûïÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿþþþÿþþþÿýýýÿüüüÿüüüÿüüüÿûûûÿüüüÿûûûÿûûûÿûûûÿûûûÿûûûÿûûûÿüüüÿüüüÿûûûÿûûûÿûûûÿüüüÿüüüÿüüüÿûûûÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿõ÷öÿîñîÿçìçÿàæáÿÜâÜÿ¿åÁÿIËUÿ4¿@ÿ1¾=ÿ2¾>ÿPÑ\ÿÙùÜÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúþûÿÙùÜÿ¢îªÿoÜxÿ[ÏdÿEÅPÿ/»<ÿ+¹7ÿ*¹6ÿ(¸5ÿ'¸4ÿ&¸2ÿ$·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ÿ$·1ÿ%¸2ÿ&¸3ÿ3¼?ÿŒÞ’ÿòüóÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿþþþÿýýýÿýýýÿüüüÿüüüÿüüüÿûûûÿûûûÿûûûÿüüüÿûûûÿûûûÿúúúÿúúúÿúúúÿùùùÿúúúÿúúúÿúúúÿúúúÿúúúÿúúúÿúúúÿúúúÿúúúÿùùùÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿöøöÿðóðÿéíéÿáæáÿÜãÝÿÕâÕÿY×eÿ4¿@ÿ1¾>ÿ1¾=ÿPÑ[ÿÙúÜÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷þ÷ÿÞûáÿ½óÂÿ’çšÿsÜ|ÿ^ÑhÿBÂLÿ/»;ÿ,º8ÿ)¹6ÿ&¸3ÿ$·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ÿ%¸2ÿ&¸2ÿ(¹5ÿ.»:ÿiÒrÿÇóÌÿüþüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿüüüÿûûûÿûûûÿûûûÿûûûÿúúúÿùùùÿúúúÿúúúÿúúúÿùùùÿùùùÿùùùÿøøøÿøøøÿøøøÿøøøÿøøøÿøøøÿøøøÿøøøÿøøøÿøøøÿøøøÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿüüüÿ÷ù÷ÿñóñÿêîêÿãèãÿÞäßÿÛãÜÿrázÿ7¾Dÿ1¾>ÿ1½<ÿNÏZÿØùÛÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿõýöÿÛúÝÿ«î±ÿzÞƒÿYÍcÿ4½@ÿ,¹9ÿ(¸5ÿ%·1ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ&¸2ÿ'¸4ÿ)¹6ÿ+º7ÿ>¿JÿxØÿÃòÈÿ÷þøÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿüüüÿûûûÿûûûÿûûûÿúúúÿùùùÿúúúÿúúúÿùùùÿùùùÿøøøÿøøøÿøøøÿøøøÿ÷÷÷ÿ÷÷÷ÿøøøÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿøøøÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿûüüÿøùøÿóõóÿìïìÿäéåÿßåàÿÝãÞÿã—ÿ>ÃIÿ2½<ÿ0½=ÿJÍVÿÒøÕÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿìüîÿ¾õÃÿyÜÿIÄTÿ0»<ÿ+º7ÿ'¸4ÿ%¸2ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ$·1ÿ%¸2ÿ&¸2ÿ'¸4ÿ)¹6ÿ*¹6ÿ+º7ÿ0¼<ÿSÉ]ÿ|Ú„ÿ­ê³ÿåûèÿüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿûûûÿûûûÿûûûÿúúúÿùùùÿúúúÿúúúÿùùùÿøøøÿøøøÿøøøÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿöööÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿöööÿöööÿöööÿöööÿöööÿ÷÷÷ÿ÷÷÷ÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿôõôÿîñîÿåêæÿàæàÿÝãÞÿ®æ´ÿDÉOÿ1¾=ÿ/½<ÿFÊRÿÄöÇÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþýÿÙùÜÿ‹ä’ÿ_Îhÿ9¾Dÿ0»<ÿ-º:ÿ,º8ÿ*¹6ÿ*¹6ÿ)¹6ÿ)¹6ÿ)¹6ÿ*¹6ÿ*¹6ÿ+º7ÿ+¹7ÿ,º8ÿ.»;ÿ1¼=ÿCÁMÿ`ÍjÿzÙ‚ÿ—äÿÍöÑÿïüðÿýþýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿûûûÿûûûÿûûûÿúúúÿúúúÿúúúÿùùùÿøøøÿøøøÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿöööÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿõõõÿõõõÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿôôôÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿõ÷öÿîñïÿçìçÿáæáÿÞäßÿÄæÇÿJÎVÿ0¾=ÿ/¼:ÿAÇLÿ¶ó¼ÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿîüïÿÄôÉÿ”æ›ÿuØÿfÑoÿUÉ^ÿJÅUÿEÃPÿDÃOÿDÃOÿRÇ[ÿ_ÍiÿnÔxÿzÚ‚ÿˆßÿ£èªÿËôÎÿèûéÿôýôÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿýýýÿüüüÿüüüÿûûûÿüüüÿúúúÿùùùÿúúúÿùùùÿøøøÿøøøÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿ÷÷÷ÿöööÿõõõÿôôôÿôôôÿôôôÿôôôÿóóóÿôôôÿôôôÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿöøöÿðóðÿéíéÿâçâÿßåàÿÑåÓÿRÓ_ÿ0¼<ÿ.¼:ÿ>ÄHÿ¤ð«ÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿþÿóýôÿçúéÿãûåÿáúãÿâûåÿãûäÿêûëÿòýóÿúþûÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿüüüÿûûûÿüüüÿúúúÿúúúÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿöööÿ÷÷÷ÿöööÿõõõÿõõõÿôôôÿôôôÿóóóÿôôôÿóóóÿóóóÿóóóÿóóóÿóóóÿóóóÿòòòÿòòòÿòòòÿòòòÿòòòÿòòòÿòòòÿòòòÿòòòÿòòòÿòòòÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿøùøÿòôòÿëîëÿäèäÿßåàÿÚåÜÿcÜmÿ2¾>ÿ.¼9ÿ:ÂEÿ’ì˜ÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿýýýÿüüüÿûûûÿûûûÿûûûÿùùùÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿöööÿ÷÷÷ÿöööÿõõõÿôôôÿôôôÿôôôÿóóóÿóóóÿóóóÿóóóÿòòòÿòòòÿñññÿòòòÿòòòÿòòòÿòòòÿñññÿñññÿñññÿñññÿñññÿñññÿñññÿñññÿñññÿñññÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿôöôÿíðíÿåêæÿàæáÿÞåßÿuá~ÿ5¿Bÿ-¼9ÿ4ÀBÿ‚éŠÿúýûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿüüüÿûûûÿûûûÿùùùÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿõõõÿôôôÿôôôÿôôôÿóóóÿóóóÿóóóÿòòòÿòòòÿñññÿòòòÿòòòÿñññÿðððÿðððÿðððÿðððÿðððÿðððÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿðððÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿõ÷öÿîñïÿçìçÿáæáÿÞäßÿ—æœÿ;ÃGÿ-»9ÿ1½>ÿrå|ÿùýùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿýýýÿüüüÿûûûÿüüüÿúúúÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿõõõÿôôôÿóóóÿóóóÿóóóÿóóóÿòòòÿñññÿòòòÿòòòÿñññÿðððÿðððÿðððÿïïïÿïïïÿïïïÿïïïÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿ÷ù÷ÿðóðÿéíéÿâçâÿÞäßÿ»ç¾ÿCÉOÿ,»9ÿ,»8ÿ\Ûfÿòüòÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿûûûÿûûûÿúúúÿúúúÿøøøÿ÷÷÷ÿ÷÷÷ÿöööÿöööÿõõõÿôôôÿóóóÿóóóÿóóóÿóóóÿòòòÿòòòÿòòòÿñññÿðððÿðððÿïïïÿïïïÿïïïÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿíííÿíííÿíííÿíííÿíííÿíííÿíííÿíííÿíííÿíííÿíííÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿóõóÿëîëÿäèäÿßåàÿÓåÕÿNÒZÿ-»9ÿ+º8ÿNÑYÿãùåÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿüüüÿúúúÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿöööÿõõõÿôôôÿóóóÿóóóÿóóóÿòòòÿñññÿòòòÿñññÿðððÿðððÿïïïÿïïïÿîîîÿîîîÿïïïÿîîîÿíííÿíííÿíííÿíííÿìììÿìììÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿôöõÿíñîÿåêæÿàæáÿÚäÜÿaÜjÿ.»;ÿ*º7ÿCÊNÿÐöÓÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿÿÿýýýÿüüüÿûûûÿûûûÿùùùÿúúúÿøøøÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿõõõÿôôôÿóóóÿóóóÿóóóÿòòòÿñññÿòòòÿñññÿðððÿïïïÿïïïÿîîîÿîîîÿîîîÿíííÿíííÿíííÿìììÿìììÿëëëÿëëëÿëëëÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿëëëÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿûûûÿöøöÿïòïÿçëçÿáæáÿÝãÞÿ…äÿ5ÀAÿ*º6ÿ8ÀDÿ¦ñ¬ÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿüüüÿûûûÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿöööÿõõõÿôôôÿóóóÿóóóÿóóóÿñññÿòòòÿðððÿðððÿïïïÿïïïÿîîîÿïïïÿîîîÿíííÿíííÿìììÿëëëÿëëëÿëëëÿëëëÿêêêÿëëëÿêêêÿêêêÿêêêÿêêêÿêêêÿéééÿêêêÿêêêÿêêêÿêêêÿêêêÿêêêÿéééÿêêêÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿóõóÿêíêÿãèãÿÝãÞÿ¹ä½ÿ?ÈLÿ)º6ÿ,º8ÿræ|ÿûýûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿüüüÿûûûÿúúúÿúúúÿøøøÿøøøÿ÷÷÷ÿ÷÷÷ÿõõõÿôôôÿóóóÿóóóÿóóóÿñññÿòòòÿñññÿðððÿïïïÿïïïÿîîîÿîîîÿíííÿíííÿìììÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿêêêÿéééÿêêêÿéééÿéééÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿèèèÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿúûúÿôöõÿîðîÿåêæÿÞäßÿÓäÔÿMÓXÿ(º5ÿ'¹4ÿR×_ÿðúñÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿüüüÿüüüÿúúúÿúúúÿøøøÿ÷÷÷ÿöööÿöööÿõõõÿôôôÿóóóÿóóóÿòòòÿòòòÿñññÿðððÿïïïÿïïïÿîîîÿîîîÿíííÿíííÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿéééÿêêêÿéééÿèèèÿèèèÿèèèÿèèèÿçççÿçççÿæææÿçççÿçççÿçççÿçççÿçççÿçççÿçççÿçççÿçççÿçççÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿ÷ù÷ÿðóðÿèìèÿàåáÿÜãÝÿoàxÿ+º8ÿ'¸4ÿ=ÄIÿÇöËÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿüüüÿûûûÿùùùÿùùùÿøøøÿøøøÿöööÿöööÿôôôÿóóóÿóóóÿóóóÿñññÿòòòÿðððÿïïïÿïïïÿîîîÿîîîÿíííÿìììÿëëëÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿéééÿèèèÿèèèÿçççÿæææÿçççÿçççÿçççÿæææÿæææÿåååÿæææÿæææÿæææÿæææÿæææÿæææÿæææÿæææÿæææÿæææÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿôöôÿìïìÿãèãÿÜãÝÿ¦æ«ÿ9ÂEÿ&¸2ÿ+º8ÿ~ç†ÿûüüÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿûûûÿûûûÿùùùÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿôôôÿóóóÿòòòÿòòòÿñññÿðððÿïïïÿîîîÿîîîÿíííÿíííÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿéééÿèèèÿèèèÿçççÿçççÿçççÿæææÿæææÿæææÿåååÿåååÿåååÿåååÿæææÿåååÿåååÿåååÿåååÿåååÿåååÿåååÿåååÿåååÿåååÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿüüüÿöøöÿîñïÿåêæÿÞäßÿÒâÓÿHÑUÿ&¸3ÿ&¸3ÿLÓXÿíûîÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿûûûÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿõõõÿôôôÿóóóÿóóóÿòòòÿòòòÿðððÿïïïÿïïïÿîîîÿíííÿíííÿëëëÿëëëÿëëëÿêêêÿêêêÿêêêÿèèèÿèèèÿçççÿæææÿçççÿæææÿæææÿåååÿåååÿåååÿåååÿåååÿäääÿäääÿäääÿäääÿäääÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿãããÿäääÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ"&&C0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿóõóÿêîêÿàåàÿÛáÛÿoàyÿ)¹7ÿ&¸2ÿ8ÁDÿ¹ó¾ÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿûûûÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿõõõÿôôôÿóóóÿóóóÿñññÿñññÿðððÿïïïÿîîîÿîîîÿíííÿìììÿëëëÿëëëÿêêêÿêêêÿêêêÿèèèÿèèèÿçççÿçççÿçççÿåååÿåååÿåååÿæææÿåååÿäääÿäääÿäääÿãããÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿâââÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ#''B0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿûûûÿöøöÿîñïÿäéåÿÜâÜÿ®ã´ÿ:ÃEÿ&¸2ÿ)¹6ÿmãwÿûûûÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿóóóÿòòòÿòòòÿñññÿðððÿïïïÿîîîÿíííÿíííÿëëëÿëëëÿëëëÿêêêÿêêêÿèèèÿèèèÿçççÿçççÿæææÿæææÿåååÿæææÿåååÿäääÿäääÿãããÿâââÿãããÿâââÿâââÿâââÿáááÿâââÿáááÿáááÿáááÿáááÿàààÿàààÿàààÿàààÿàààÿáááÿáááÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ#''B0$  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿùúùÿóõóÿéíéÿÞäßÿÔÞÕÿMÕYÿ&¸3ÿ&¸2ÿDÍOÿãùäÿüýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿüüüÿùùùÿùùùÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿóóóÿòòòÿòòòÿðððÿïïïÿîîîÿïïïÿíííÿìììÿëëëÿëëëÿêêêÿéééÿéééÿèèèÿçççÿçççÿæææÿæææÿåååÿåååÿäääÿäääÿãããÿâââÿâââÿâââÿâââÿâââÿáááÿàààÿàààÿàààÿàààÿàààÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿßßßÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ#''A/#  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿöøöÿîñïÿäèäÿÙàÚÿ‘à—ÿ2½>ÿ&¸2ÿ,º9ÿŒê”ÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿüüüÿùùùÿùùùÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿóóóÿòòòÿòòòÿðððÿïïïÿîîîÿîîîÿíííÿëëëÿëëëÿëëëÿêêêÿêêêÿèèèÿçççÿçççÿæææÿæææÿåååÿåååÿäääÿäääÿãããÿãããÿâââÿáááÿâââÿáááÿàààÿàààÿßßßÿßßßÿÞÞÞÿßßßÿßßßÿßßßÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿÞÞÞÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ$((@.#  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿúûúÿôõôÿêîêÿÞäßÿÉÜÊÿCÏOÿ&¸2ÿ&¸2ÿGÑTÿçôèÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿûûûÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿóóóÿòòòÿòòòÿðððÿïïïÿîîîÿîîîÿíííÿëëëÿëëëÿêêêÿêêêÿéééÿèèèÿçççÿçççÿæææÿåååÿåååÿäääÿäääÿâââÿâââÿâââÿâââÿáááÿàààÿàààÿßßßÿÞÞÞÿßßßÿßßßÿÞÞÞÿÝÝÝÿÞÞÞÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ$$$?-!  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿøùøÿñóñÿåêæÿÙàÚÿ{߃ÿ*¹7ÿ&¸2ÿ)¹5ÿ„æŒÿðóðÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿúúúÿøøøÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿóóóÿòòòÿòòòÿðððÿïïïÿîîîÿíííÿìììÿìììÿëëëÿêêêÿêêêÿèèèÿçççÿçççÿæææÿåååÿåååÿäääÿäääÿãããÿâââÿâââÿâââÿàààÿàààÿßßßÿÞÞÞÿßßßÿÞÞÞÿÝÝÝÿÞÞÞÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÝÝÝÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿÜÜÜÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ&&&<+   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûüûÿ÷ù÷ÿîñïÿâçâÿÌÞÍÿAÍNÿ&¸2ÿ%¸2ÿ=ÆJÿÈçËÿîñîÿöøöÿüüüÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿûûûÿûûûÿúúúÿøøøÿ÷÷÷ÿ÷÷÷ÿõõõÿóóóÿóóóÿîîîÿÚÚÚÿÆÆÆÿ½½½ÿ¶¶¶ÿ²²²ÿ±±±ÿ±±±ÿ±±±ÿ±±±ÿ¶¶¶ÿµµµÿµµµÿµµµÿµµµÿµµµÿµµµÿµµµÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ´´´ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿ³³³ÿµµµÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿ¶¶¶ÿªªªÿ©©©ÿ©©©ÿ©©©ÿ$((9(  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿõ÷õÿíðíÿßåßÿ„àŒÿ-»9ÿ%¸2ÿ&¸2ÿHÒUÿÝãÝÿéíéÿóõóÿùúùÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿûûûÿúúúÿøøøÿøøøÿöööÿõõõÿôôôÿîîîÿÌÌÌÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ&++6%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿõ÷öÿìïìÿÜæÞÿEÑQÿ&¸2ÿ$·1ÿ&¸2ÿXØdÿØßÙÿäéåÿðóðÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿüüüÿùùùÿùùùÿ÷÷÷ÿöööÿõõõÿôôôÿåååÿ²²²ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ)..2!   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿöøöÿíðíÿ´ç·ÿ5¿Aÿ%¸2ÿ#·0ÿ&¸2ÿNÕZÿÕÝÖÿâçâÿîñïÿöøöÿûüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿûûûÿúúúÿùùùÿøøøÿöööÿöööÿôôôÿäääÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ú&   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿ÷ù÷ÿïòïÿnáxÿ&¸3ÿ$·1ÿ#·0ÿ%¸2ÿ:ÃFÿ²á¶ÿãèãÿîñïÿöøöÿûüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿíííÿ²²²ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ²²²ÿÑÑÑÿæææÿïïïÿôôôÿôôôÿôôôÿôôôÿôôôÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿîîîÿíííÿìììÿìììÿëëëÿêêêÿéééÿèèèÿèèèÿçççÿæææÿåååÿäääÿäääÿßßßÿÝÝÝÿÜÜÜÿÜÜÜÿÛÛÛÿÚÚÚÿÙÙÙÿÙÙÙÿØØØÿ×××ÿÖÖÖÿÔÔÔÿ¯¯¯ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ‘‘!   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿúûúÿôöôÿJÕUÿ&¸2ÿ#·0ÿ#·0ÿ$·1ÿ&¸3ÿO×[ÿáìâÿñóñÿøùøÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿúúúÿøøøÿøøøÿ÷÷÷ÿõõõÿóóóÿÈÈÈÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÐÐÐÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿÄÄÄÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ ¡¡Ï%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿòøòÿCÎOÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ%¸2ÿ/¼;ÿŠé’ÿõ÷öÿúûúÿýþýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿþþþÿüüüÿûûûÿúúúÿùùùÿ÷÷÷ÿöööÿõõõÿôôôÿëëëÿ«««ÿ©©©ÿ©©©ÿ©©©ÿÑÑÑÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿÓÓÓÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ô4441   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýþýÿòúóÿCÎOÿ&¸2ÿ#·0ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ@ÉLÿÝøßÿüýüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿÓÓÓÿ©©©ÿ©©©ÿ©©©ÿµµµÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿßßßÿ®®®ÿ©©©ÿ©©©ÿ©©©ÿ©©©þsss["  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüýüÿ^ßgÿ&¸3ÿ$·1ÿ#·0ÿ#·0ÿ#·0ÿ&¸2ÿ.¼;ÿ¹ö¾ÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿúúúÿøøøÿ÷÷÷ÿ÷÷÷ÿôôôÿôôôÿóóóÿÀÀÀÿ©©©ÿ©©©ÿ©©©ÿÙÙÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿäääÿ¸¸¸ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ“““œ$   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿØúÛÿAËMÿ&¸3ÿ%¸2ÿ$·1ÿ&¸2ÿ4¾@ÿgãqÿõýöÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿùùùÿ÷÷÷ÿöööÿõõõÿóóóÿóóóÿñññÿ³³³ÿ©©©ÿ©©©ÿ©©©ÿðððÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿÆÆÆÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ£££Û '   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÊøÏÿIÓTÿ+º8ÿ'¸4ÿBÊMÿšð¡ÿüþüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿñññÿ­­­ÿ©©©ÿ©©©ÿ©©©ÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿÖÖÖÿªªªÿ©©©ÿ©©©ÿ©©©ÿ¨©©øAFF7   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðýñÿ›ï¢ÿŽì•ÿàûáÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿùùùÿùùùÿøøøÿ÷÷÷ÿôôôÿôôôÿóóóÿòòòÿðððÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿßßßÿ¯¯¯ÿ©©©ÿ©©©ÿ©©©ÿªªªþy||e"    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿûûûÿúúúÿøøøÿöööÿõõõÿôôôÿóóóÿñññÿñññÿïïïÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿ»»»ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ˜˜˜©%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿòòòÿòòòÿðððÿîîîÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿÉÉÉÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¥¥¥â(   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿúúúÿøøøÿöööÿõõõÿóóóÿóóóÿòòòÿðððÿïïïÿïïïÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿ×××ÿªªªÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨úMQQ?!  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿñññÿïïïÿîîîÿíííÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿàààÿ°°°ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ„††v#   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿúúúÿøøøÿöööÿõõõÿóóóÿóóóÿòòòÿðððÿïïïÿîîîÿìììÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿ½½½ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿœœœ·%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿñññÿïïïÿîîîÿíííÿìììÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿÊÊÊÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¥¥¥é+   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿôôôÿóóóÿòòòÿðððÿîîîÿîîîÿìììÿëëëÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿçççÿæææÿåååÿäääÿãããÿØØØÿ«««ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨üY\\E!  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿùùùÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿñññÿïïïÿîîîÿíííÿëëëÿêêêÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿÞÞÞÿ±±±ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿŒŽŽƒ#   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿóóóÿòòòÿðððÿîîîÿíííÿìììÿëëëÿêêêÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿ½½½ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿžžÃ &   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿýýýÿüüüÿüüüÿüüüÿüüüÿüüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿüüüÿüüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿýýýÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿôôôÿóóóÿòòòÿñññÿïïïÿîîîÿíííÿëëëÿêêêÿéééÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿËËËÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ§§§î(((-   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿõõõÿñññÿïïïÿíííÿíííÿïïïÿñññÿôôôÿùùùÿüüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿøøøÿóóóÿðððÿðððÿðððÿðððÿóóóÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿôôôÿðððÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿïïïÿóóóÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿòòòÿðððÿîîîÿîîîÿìììÿëëëÿêêêÿèèèÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿØØØÿ«««ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ýjjjR"    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿúúúÿóóóÿëëëÿãããÿÝÝÝÿØØØÿÖÖÖÿÕÕÕÿØØØÿÛÛÛÿâââÿêêêÿóóóÿùùùÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿùùùÿíííÿáááÿÚÚÚÿÙÙÙÿÙÙÙÿÚÚÚÿâââÿîîîÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿæææÿÛÛÛÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿØØØÿÙÙÙÿâââÿðððÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿûûûÿúúúÿùùùÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿòòòÿñññÿïïïÿîîîÿíííÿëëëÿêêêÿéééÿçççÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿÞÞÞÿ³³³ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ‘‘$   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿøøøÿïïïÿãããÿÒÒÒÿ½½½ÿ©©©ÿžžžÿ™™™ÿ———ÿžžžÿ¦¦¦ÿ¹¹¹ÿÍÍÍÿàààÿíííÿ÷÷÷ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿôôôÿØØØÿ¡¢¡ÿ   ÿŸŸŸÿŸŸŸÿ   ÿ¢¢¢ÿØØØÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿñññÿ¶·¶ÿ   ÿžžžÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿŸŸŸÿ   ÿ¢¢¢ÿÝÝÝÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿùùùÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿñññÿðððÿïïïÿîîîÿìììÿëëëÿêêêÿèèèÿçççÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿ¿¿¿ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ ¢¢Í &   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿùùùÿìììÿÜÜÜÿ»»»ÿ–––ÿ€€€ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿÿ‘‘‘ÿ¶¶¶ÿØØØÿëëëÿ÷÷÷ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿðððÿ¿¿¿ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿÁÁÁÿñññÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ¢£¢ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿÚÚÚÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿôôôÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿêêêÿèèèÿçççÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿÿÿÿÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿÎÎÎÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ§§§ô4441   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿïïïÿÝÝÝÿ¯¯¯ÿ‚‚‚ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿ¦¦¦ÿÖÖÖÿìììÿúúúÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿúúúÿëëëÿ«¬«ÿÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ­­­ÿìììÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ£¤£ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿÚÚÚÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿôôôÿóóóÿñññÿðððÿïïïÿîîîÿìììÿëëëÿêêêÿèèèÿæææÿæææÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿþþþÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿØØØÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ©©©þpss["    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿãããÿ°°°ÿ€€€ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿÿÿÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿ¦¦¦ÿÝÝÝÿóóóÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ÷÷÷ÿåååÿ‘‘‘ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ“”“ÿæææÿ÷÷÷ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ£££ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ}}}ÿÿ~~~ÿÿÿÿÿÿÿÿ€€€ÿÿÜÜÜÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿóóóÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿëëëÿêêêÿèèèÿçççÿåååÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿýýýÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿÞÞÞÿµµµÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ’’’›$   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿùùùÿìììÿÃÃÃÿ‚ƒ‚ÿÿ}}}ÿ~~~ÿÿ€€€ÿÿ‚‚‚ÿ‚‚‚ÿÿÿÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿ¸¸¸ÿéééÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿÐÐÐÿ‚‚‚ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿÓÓÓÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ¡¢¡ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿÿÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿƒƒƒÿàààÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿñññÿïïïÿîîîÿíííÿëëëÿêêêÿéééÿçççÿæææÿæææÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÀÀÀÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ£££Ø '   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿßßßÿ•–•ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿƒƒƒÿ¯°¯ÿÍÍÍÿÍÍÍÿ¹¹¹ÿ‡‡‡ÿ€€€ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿŠ‹ŠÿÖÖÖÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿðððÿºººÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿ»¼»ÿïïïÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ ¡ ÿ~~~ÿ~~~ÿ}}}ÿ}}}ÿ€€€ÿ¯¯¯ÿ¹¹¹ÿ»»»ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ¼¼¼ÿ»»»ÿ»»»ÿºººÿ»»»ÿîîîÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿôôôÿóóóÿñññÿðððÿïïïÿîîîÿìììÿëëëÿêêêÿèèèÿçççÿåååÿäääÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿûûûÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÏÏÏÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨øHLL9   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿðððÿÃÃÃÿ€€€ÿ}}}ÿ~~~ÿ~~~ÿÿ‡‡‡ÿÚÚÚÿùùùÿýýýÿýýýÿûûûÿäåäÿÿ€€€ÿ~~~ÿÿ~~~ÿ~~~ÿ¶¶¶ÿîîîÿüüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿúúúÿëëëÿ£¤£ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ¥¦¥ÿëëëÿúúúÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿžŸžÿ~~~ÿ~~~ÿ}}}ÿ}}}ÿÿÜÜÜÿ÷÷÷ÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿóóóÿóóóÿòòòÿðððÿîîîÿíííÿìììÿêêêÿéééÿçççÿæææÿåååÿäääÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿúúúÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÙÙÙÿ­­­ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ|~~g#    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿúúúÿëëëÿ£££ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿÃÃÃÿøøøÿþþþÿÿÿÿÿÿÿÿÿþþþÿùùùÿÏÐÏÿÿ~~~ÿ~~~ÿÿ~~~ÿ–––ÿçççÿøøøÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ÷÷÷ÿãããÿŠŠŠÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿ~~~ÿ}}}ÿ~~~ÿ‹‹‹ÿâââÿøøøÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿžžžÿ}}}ÿ}}}ÿ|||ÿ}}}ÿ€€€ÿÛÛÛÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿñññÿïïïÿïïïÿíííÿëëëÿêêêÿèèèÿæææÿæææÿåååÿãããÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿùùùÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÝÝÝÿ¶¶¶ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ———©%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿãããÿ‰‰‰ÿ~~~ÿ~~~ÿ~~~ÿÿˆˆˆÿêêêÿüüüÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿòòòÿ“““ÿ~~~ÿ~~~ÿ~~~ÿ}}}ÿ‚‚‚ÿÖÖÖÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿÊÊÊÿÿ}}}ÿ}}}ÿ|||ÿ}}}ÿ~~~ÿ}}}ÿ}}}ÿ}}}ÿÿËËËÿóóóÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿœœœÿ|||ÿ|||ÿ{{{ÿ|||ÿ~~~ÿÚÛÚÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿúúúÿùùùÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿñññÿðððÿïïïÿîîîÿìììÿêêêÿêêêÿèèèÿçççÿåååÿäääÿâââÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿøøøÿ÷÷÷ÿöööÿõõõÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÂÂÂÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¤¤¤á)   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿÐÐÐÿ€€€ÿ~~~ÿ~~~ÿ~~~ÿÿ¢£¢ÿòóòÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿôôôÿ¯¯¯ÿ~~~ÿ}}}ÿ}}}ÿ}}}ÿ~~~ÿÂÂÂÿóóóÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿðððÿ°±°ÿ|||ÿ|||ÿ|||ÿ|||ÿŒŒŒÿ‰‰‰ÿ}}}ÿ|||ÿ|||ÿ}}}ÿ²²²ÿïïïÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿšššÿ|||ÿ|||ÿ{{{ÿ|||ÿ~~~ÿÛÛÛÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿðððÿîîîÿíííÿìììÿêêêÿéééÿçççÿæææÿæææÿäääÿâââÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ÷÷÷ÿõõõÿôôôÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÐÐÐÿªªªÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨úPTT@!  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿôôôÿ¿¿¿ÿÿ~~~ÿ|||ÿ}}}ÿ~~~ÿ³³³ÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿ¾¾¾ÿ~~~ÿ|||ÿ{{{ÿ|||ÿ}}}ÿ²²²ÿóóóÿýýýÿÿÿÿÿÿÿÿÿþþþÿúúúÿêêêÿ™™™ÿ|||ÿ|||ÿ|||ÿ}}}ÿ£££ÿ   ÿ}}}ÿ|||ÿ|||ÿ|||ÿšššÿêêêÿúúúÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ™™™ÿ{{{ÿ|||ÿ{{{ÿ|||ÿÿØØØÿøøøÿýýýÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿôôôÿóóóÿñññÿïïïÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿæææÿåååÿãããÿáááÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿöööÿöööÿôôôÿóóóÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÙÙÙÿ®®®ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿƒ……s#   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿ¶¶¶ÿ~~~ÿ}}}ÿ|||ÿ}}}ÿ}}}ÿ½½½ÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÈÈÈÿ}}}ÿ|||ÿ{{{ÿ}}}ÿ}}}ÿ¨¨¨ÿñññÿüüüÿÿÿÿÿÿÿÿÿýýýÿöööÿÞÞÞÿƒƒƒÿ|||ÿ|||ÿ|||ÿ}}}ÿ¶¶¶ÿ³³³ÿ|||ÿzzzÿ{{{ÿ{{{ÿ„„„ÿÝÝÝÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ———ÿ{{{ÿ{{{ÿzzzÿ{{{ÿ}}}ÿÕÕÕÿñññÿöööÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿøøøÿùùùÿüüüÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿòòòÿðððÿïïïÿîîîÿìììÿëëëÿéééÿèèèÿçççÿåååÿäääÿâââÿáááÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿõõõÿõõõÿòòòÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÜÜÜÿ···ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿššš¶ &   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿ°°°ÿ}}}ÿ|||ÿ{{{ÿ|||ÿ}}}ÿÂÂÂÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ÷÷÷ÿÌÌÌÿ}}}ÿ|||ÿ|||ÿ|||ÿ}}}ÿ£££ÿðððÿüüüÿÿÿÿÿÿÿÿÿýýýÿòòòÿÃÃÃÿ}}}ÿ|||ÿ|||ÿ|||ÿ}}}ÿÌÌÌÿÉÉÉÿ}}}ÿ{{{ÿ{{{ÿ{{{ÿ}}}ÿÄÄÄÿòòòÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ–––ÿ{{{ÿ{{{ÿ{{{ÿ{{{ÿ}}}ÿÌÌÌÿáááÿåååÿåååÿåååÿåååÿæææÿæææÿêêêÿòòòÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿúúúÿùùùÿøøøÿ÷÷÷ÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿëëëÿéééÿçççÿæææÿåååÿäääÿâââÿàààÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿõõõÿòòòÿòòòÿñññÿðððÿïïïÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÄÄÄÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¥¥¥é###,   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿòòòÿ§§§ÿ}}}ÿ|||ÿ{{{ÿ|||ÿ}}}ÿÃÃÃÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÏÏÏÿ}}}ÿ|||ÿ|||ÿ|||ÿ}}}ÿœœœÿðððÿüüüÿÿÿÿÿþþþÿûûûÿîîîÿ§§§ÿ{{{ÿ{{{ÿ{{{ÿ|||ÿÿäääÿáááÿ€€€ÿ}}}ÿ{{{ÿ{{{ÿ{{{ÿ¨¨¨ÿîîîÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ•••ÿ|||ÿ|||ÿ{{{ÿ{{{ÿ|||ÿ°±°ÿ···ÿ¹¹¹ÿ¸¸¸ÿ¸¸¸ÿ¸¸¸ÿ···ÿºººÿ¿¿¿ÿÙÙÙÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿôôôÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿåååÿãããÿâââÿàààÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿóóóÿòòòÿðððÿïïïÿîîîÿíííÿìììÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÑÑÑÿªªªÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ü\\\H!  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿòòòÿ§§§ÿ|||ÿ|||ÿ{{{ÿ|||ÿ}}}ÿÂÂÂÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÍÎÍÿ|||ÿ{{{ÿ{{{ÿ{{{ÿ|||ÿšššÿðððÿüüüÿÿÿÿÿýýýÿùùùÿéééÿÿ{{{ÿ{{{ÿ{{{ÿ|||ÿ‘’‘ÿïïïÿïïïÿÿ|||ÿ}}}ÿ|||ÿ{{{ÿÿéééÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ”””ÿ|||ÿ|||ÿ|||ÿ|||ÿ{{{ÿ}}}ÿ}}}ÿ|||ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿÿ´´´ÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿôôôÿóóóÿñññÿïïïÿïïïÿìììÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿâââÿßßßÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿòòòÿñññÿðððÿîîîÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿßßßÿÝÝÝÿØØØÿ¯¯¯ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿˆŠŠ#   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿòòòÿ¥¥¥ÿ|||ÿ{{{ÿzzzÿ{{{ÿ|||ÿÂÂÂÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÎÏÎÿ|||ÿ{{{ÿ{{{ÿ{{{ÿ|||ÿ˜˜˜ÿðððÿüüüÿÿÿÿÿýýýÿöööÿØØØÿ~~~ÿzzzÿzzzÿ{{{ÿ}}}ÿ¥¥¥ÿóóóÿóóóÿ£££ÿ}}}ÿ|||ÿ{{{ÿ{{{ÿ€€€ÿ×××ÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ’“’ÿ|||ÿ|||ÿ|||ÿ|||ÿ|||ÿ|||ÿzzzÿzzzÿ{{{ÿ{{{ÿ{{{ÿ|||ÿ{{{ÿ}}}ÿ²²²ÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿòòòÿñññÿïïïÿîîîÿìììÿêêêÿêêêÿèèèÿçççÿåååÿäääÿâââÿáááÿÞÞÞÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿñññÿðððÿïïïÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿßßßÿÞÞÞÿÝÝÝÿ¹¹¹ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿžŸŸÂ &   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿòòòÿ¥¥¥ÿ|||ÿ{{{ÿzzzÿ{{{ÿ}}}ÿÁÁÁÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÎÎÎÿ|||ÿ{{{ÿ{{{ÿ{{{ÿ|||ÿ˜˜˜ÿðððÿüüüÿþþþÿýýýÿòòòÿºººÿ}}}ÿ|||ÿzzzÿ{{{ÿ}}}ÿºººÿ÷÷÷ÿöööÿ¸¸¸ÿ}}}ÿ|||ÿ{{{ÿ|||ÿ}}}ÿ»»»ÿòòòÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿïïïÿ’’’ÿ|||ÿ|||ÿ|||ÿ}}}ÿ}}}ÿ}}}ÿ}}}ÿ}}}ÿ|||ÿ|||ÿ|||ÿ|||ÿ|||ÿ~~~ÿ±±±ÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿëëëÿéééÿçççÿæææÿæææÿãããÿâââÿàààÿßßßÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿðððÿðððÿíííÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÞÞÞÿÝÝÝÿÜÜÜÿÅÅÅÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¦¦¦ï0000   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿ£££ÿ}}}ÿ{{{ÿzzzÿ{{{ÿ}}}ÿÀÀÀÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÍÍÍÿ}}}ÿ{{{ÿ{{{ÿ{{{ÿ|||ÿ”””ÿðððÿüüüÿþþþÿûûûÿíííÿŸŸŸÿ}}}ÿ|||ÿ|||ÿ|||ÿ}}}ÿÓÓÓÿùùùÿúúúÿÐÐÐÿ~~~ÿ|||ÿ|||ÿ|||ÿ~~~ÿ   ÿíííÿûûûÿþþþÿÿÿÿÿÿÿÿÿýýýÿïïïÿÿ|||ÿ}}}ÿ}}}ÿ}}}ÿ}}}ÿ}}}ÿ~~~ÿÿÿÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿ³³³ÿöööÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿúúúÿùùùÿøøøÿöööÿôôôÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿåååÿâââÿáááÿàààÿßßßÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿîîîÿïïïÿìììÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÞÞÞÿÞÞÞÿÑÑÑÿªªªÿ©©©ÿ©©©ÿ©©©ÿ©©©ýiiiP"    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿ¢¢¢ÿ}}}ÿ|||ÿ{{{ÿ{{{ÿ|||ÿ¿¿¿ÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ÷÷÷ÿÍÍÍÿ}}}ÿ|||ÿ|||ÿ{{{ÿ|||ÿ•••ÿñññÿüüüÿþþþÿøøøÿèèèÿˆˆˆÿ}}}ÿ}}}ÿ}}}ÿ}}}ÿ‚‚‚ÿêêêÿûûûÿûûûÿêêêÿ€€€ÿ|||ÿ}}}ÿ}}}ÿ}}}ÿ‡‡‡ÿèèèÿøøøÿþþþÿÿÿÿÿÿÿÿÿýýýÿïïïÿÿ}}}ÿ~~~ÿ~~~ÿ~~~ÿÿÿ€€€ÿ€€€ÿÿÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ···ÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿöööÿóóóÿóóóÿòòòÿïïïÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿáááÿßßßÿÞÞÞÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿîîîÿïïïÿëëëÿêêêÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÞÞÞÿßßßÿÛÛÛÿ°°°ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ$   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿôôôÿ¦¦¦ÿ}}}ÿ|||ÿ{{{ÿ|||ÿ}}}ÿ¾¾¾ÿõõõÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿ÷÷÷ÿÉÊÉÿ~~~ÿ}}}ÿ|||ÿ~~~ÿ}}}ÿ˜˜˜ÿñññÿüüüÿüüüÿõõõÿÓÓÓÿÿ}}}ÿ}}}ÿ}}}ÿ~~~ÿ’’’ÿòòòÿýýýÿýýýÿóóóÿ‘‘‘ÿ~~~ÿ~~~ÿ~~~ÿ~~~ÿ€€€ÿÒÒÒÿõõõÿýýýÿÿÿÿÿÿÿÿÿýýýÿïïïÿ’’’ÿ~~~ÿ~~~ÿ}}}ÿ~~~ÿ€€€ÿ¥¥¥ÿ°°°ÿ³³³ÿ³³³ÿ´´´ÿ´´´ÿ³³³ÿ´´´ÿ´´´ÿ×××ÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿóóóÿñññÿïïïÿïïïÿìììÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿáááÿÞÞÞÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿîîîÿîîîÿëëëÿéééÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÝÝÝÿßßßÿÝÝÝÿ»»»ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¡¡¡Ñ '   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿôôôÿ®®®ÿ}}}ÿ|||ÿ|||ÿ}}}ÿ~~~ÿºººÿôôôÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿÅÅÅÿ~~~ÿ}}}ÿ|||ÿ}}}ÿÿŸŸŸÿóóóÿýýýÿüüüÿñññÿ···ÿ~~~ÿÿ~~~ÿ~~~ÿÿ©©©ÿöööÿýýýÿýýýÿõõõÿ¨¨¨ÿÿ~~~ÿ~~~ÿÿ€€€ÿµµµÿñññÿüüüÿÿÿÿÿÿÿÿÿýýýÿïïïÿ“““ÿ€€€ÿÿ~~~ÿÿÿÖÖÖÿøøøÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿýýýÿþþþÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿñññÿïïïÿîîîÿìììÿêêêÿêêêÿèèèÿæææÿåååÿäääÿâââÿàààÿÞÞÞÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿïïïÿîîîÿêêêÿèèèÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÝÝÝÿàààÿÞÞÞÿÈÈÈÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ§¨¨ó:??5   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿöööÿµµµÿÿ|||ÿ|||ÿ}}}ÿ~~~ÿ³³³ÿòòòÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿ¼½¼ÿÿ~~~ÿ~~~ÿ~~~ÿÿ«««ÿõõõÿýýýÿûûûÿíííÿŸŸŸÿ~~~ÿ~~~ÿÿÿ€€€ÿÁÁÁÿøøøÿþþþÿþþþÿùùùÿ¾¾¾ÿÿ€€€ÿÿÿÿŸ Ÿÿìììÿûûûÿþþþÿÿÿÿÿýýýÿïïïÿ–––ÿÿÿ€€€ÿ€€€ÿÿØØØÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿïïïÿíííÿëëëÿëëëÿéééÿçççÿæææÿåååÿãããÿâââÿàààÿßßßÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿìììÿíííÿéééÿçççÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿàààÿßßßÿÔÔÔÿªªªÿ©©©ÿ©©©ÿ©©©ÿ©©©þpss["    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÄÄÄÿÿ}}}ÿ~~~ÿ~~~ÿ~~~ÿ¦¦¦ÿîîîÿûûûÿþþþÿÿÿÿÿÿÿÿÿþþþÿüüüÿðððÿ°°°ÿ€€€ÿÿÿÿ€€€ÿµµµÿ÷÷÷ÿýýýÿøøøÿçççÿ‹Œ‹ÿÿÿÿÿ‚‚‚ÿÚÚÚÿûûûÿþþþÿþþþÿûûûÿÖÖÖÿ‚‚‚ÿÿÿÿ€€€ÿŒŒÿæææÿøøøÿþþþÿÿÿÿÿýýýÿïïïÿ˜˜˜ÿ‚‚‚ÿ‚‚‚ÿÿ‚‚‚ÿ„„„ÿØØØÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿåååÿâââÿáááÿàààÿÞÞÞÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿìììÿëëëÿèèèÿæææÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÞÞÞÿßßßÿÝÝÝÿ³³³ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ”””›%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿÛÛÛÿ€€€ÿ~~~ÿ~~~ÿÿÿ———ÿçççÿ÷÷÷ÿýýýÿÿÿÿÿÿÿÿÿþþþÿøøøÿéééÿžŸžÿÿÿ€€€ÿ€€€ÿÿÍÍÍÿúúúÿüüüÿõõõÿÏÏÏÿƒƒƒÿÿÿ€€€ÿ€€€ÿ‹‹‹ÿîîîÿüüüÿÿÿÿÿÿÿÿÿüüüÿîîîÿ‹‹‹ÿƒƒƒÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ………ÿÏÐÏÿôôôÿüüüÿÿÿÿÿýýýÿïïïÿ›››ÿƒƒƒÿƒƒƒÿ‚‚‚ÿ„„„ÿ………ÿØÙØÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿûûûÿùùùÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿæææÿäääÿâââÿâââÿßßßÿÞÞÞÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿíííÿëëëÿçççÿåååÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÞÞÞÿàààÿßßßÿ½½½ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ£££Ø(   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿðððÿ‰‰‰ÿ€€€ÿÿÿ€€€ÿ†††ÿÔÔÔÿïïïÿùùùÿüüüÿüüüÿùùùÿðððÿÚÚÚÿ‹‹‹ÿÿÿÿ‚‚‚ÿ†††ÿåååÿûûûÿüüüÿðððÿ¶·¶ÿƒƒƒÿ‚‚‚ÿ‚‚‚ÿ‚‚‚ÿ„„„ÿ¡¡¡ÿóóóÿýýýÿÿÿÿÿÿÿÿÿýýýÿóóóÿ   ÿ„„„ÿƒƒƒÿ„„„ÿ„„„ÿ„„„ÿ···ÿðððÿûûûÿþþþÿýýýÿïïïÿÿ„„„ÿ………ÿ„„„ÿ………ÿ‡‡‡ÿØÙØÿ÷÷÷ÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿüüüÿúúúÿùùùÿøøøÿöööÿôôôÿòòòÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿáááÿßßßÿÝÝÝÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿëëëÿìììÿæææÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿâââÿáááÿÌÌÌÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ§§§÷FKK:   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿöööÿªªªÿ‚‚‚ÿÿ€€€ÿÿÿ¬¬¬ÿàààÿíííÿòòòÿòòòÿìììÿáááÿ´´´ÿ‚‚‚ÿ‚‚‚ÿƒƒƒÿ‚‚‚ÿ„„„ÿŸŸŸÿõõõÿýýýÿúúúÿìììÿ£¤£ÿ„„„ÿƒƒƒÿƒƒƒÿƒƒƒÿ………ÿ¶·¶ÿöööÿýýýÿÿÿÿÿÿÿÿÿýýýÿöööÿ¶¶¶ÿ………ÿ………ÿ………ÿ………ÿ†††ÿ¤¤¤ÿëëëÿúúúÿÿÿÿÿüüüÿïïïÿžžžÿ†††ÿ†††ÿ………ÿ………ÿˆˆˆÿÔÔÔÿëëëÿðððÿñññÿñññÿñññÿñññÿñññÿñññÿñññÿõõõÿùùùÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿûûûÿúúúÿùùùÿ÷÷÷ÿöööÿóóóÿóóóÿòòòÿïïïÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿáááÿÞÞÞÿÞÞÞÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿëëëÿìììÿäääÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿßßßÿàààÿØØØÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ÿ}€€j#   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿÑÒÑÿ„„„ÿ‚‚‚ÿ‚‚‚ÿƒƒƒÿ‚‚‚ÿ‰‰‰ÿ»»»ÿØØØÿÞÞÞÿÝÝÝÿÙÙÙÿ¿¿¿ÿÿƒƒƒÿƒƒƒÿ„„„ÿ„„„ÿ†††ÿÆÆÆÿùùùÿýýýÿ÷÷÷ÿåååÿ‘‘‘ÿ„„„ÿ………ÿ………ÿ………ÿ†††ÿËÌËÿùùùÿþþþÿÿÿÿÿÿÿÿÿþþþÿùùùÿÉÉÉÿˆˆˆÿ†††ÿ†††ÿ†††ÿ†††ÿ“““ÿäääÿ÷÷÷ÿýýýÿüüüÿïïïÿ¡¡¡ÿ‡‡‡ÿ‡‡‡ÿˆˆˆÿ‡‡‡ÿ‰‰‰ÿÊÊÊÿØØØÿÚÚÚÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿÛÛÛÿÜÜÜÿäääÿñññÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿúúúÿøøøÿ÷÷÷ÿõõõÿóóóÿóóóÿñññÿïïïÿïïïÿìììÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿëëëÿêêêÿãããÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿàààÿâââÿàààÿ³³³ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ˜˜˜¨%   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿõõõÿœœœÿ„„„ÿ„„„ÿƒƒƒÿ‚‚‚ÿƒƒƒÿ‰‰‰ÿ¡¢¡ÿ±±±ÿ±±±ÿ¥¥¥ÿŒŒŒÿ………ÿ„„„ÿ………ÿ†††ÿ†††ÿ“““ÿðððÿýýýÿýýýÿôôôÿÏÐÏÿŠŠŠÿ†††ÿ†††ÿ†††ÿ†††ÿ‰‰‰ÿâââÿûûûÿþþþÿÿÿÿÿÿÿÿÿþþþÿüüüÿàààÿŠŠŠÿ‡‡‡ÿˆˆˆÿˆˆˆÿˆˆˆÿ‹‹‹ÿÎÎÎÿóóóÿýýýÿüüüÿïïïÿ¤¤¤ÿ‰‰‰ÿ‰‰‰ÿ‰‰‰ÿ‰‰‰ÿ‹‹‹ÿ©©©ÿ¦§¦ÿ¦§¦ÿ¦§¦ÿ¦§¦ÿ¦§¦ÿ§§§ÿ§§§ÿ§§§ÿ§§§ÿ­­­ÿâââÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿêêêÿêêêÿèèèÿæææÿæææÿãããÿâââÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿêêêÿêêêÿâââÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿÝÝÝÿãããÿâââÿÁÁÁÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¤¤¤á+   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿÜÜÜÿ‰‰‰ÿ†††ÿ†††ÿ………ÿ„„„ÿ………ÿ………ÿ………ÿ………ÿ†††ÿ†††ÿ†††ÿ†††ÿ†††ÿ‡‡‡ÿ‰‰‰ÿÐÐÐÿûûûÿþþþÿüüüÿðððÿ»»»ÿˆˆˆÿ‡‡‡ÿ‡‡‡ÿˆˆˆÿ‰‰‰ÿšššÿòòòÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿòòòÿ™š™ÿŠŠŠÿŠŠŠÿŠŠŠÿŠŠŠÿ‹‹‹ÿ»»»ÿïïïÿûûûÿüüüÿïïïÿ¦§¦ÿ‹‹‹ÿ‹‹‹ÿ‹‹‹ÿŒŒŒÿŒŒŒÿŒŒŒÿŒŒŒÿŒŒŒÿÿÿÿŽŽŽÿŽŽŽÿÿÿÿÜÜÜÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿñññÿïïïÿîîîÿëëëÿêêêÿêêêÿçççÿæææÿåååÿãããÿâââÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿêêêÿêêêÿáááÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿÚÚÚÿãããÿâââÿÑÑÑÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ùPTT@!  #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿùùùÿÁÁÁÿ‰‰‰ÿ‡‡‡ÿˆˆˆÿ‡‡‡ÿ‡‡‡ÿ†††ÿ‡‡‡ÿ‡‡‡ÿ‡‡‡ÿ‡‡‡ÿ‡‡‡ÿˆˆˆÿ‰‰‰ÿ‹‹‹ÿµµµÿùùùÿþþþÿþþþÿúúúÿìììÿªªªÿ‰‰‰ÿ‰‰‰ÿ‰‰‰ÿ‰‰‰ÿŒŒŒÿ±±±ÿôôôÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿóóóÿ¯¯¯ÿŒŒŒÿŒŒŒÿŒŒŒÿŒŒŒÿŒŒŒÿ«¬«ÿëëëÿùùùÿûûûÿïïïÿ¨©¨ÿŽŽŽÿŽŽŽÿÿÿŽŽŽÿŽŽŽÿŽŽŽÿÿÿÿÿÿÿ‘‘‘ÿÿ“““ÿÜÜÜÿùùùÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿðððÿïïïÿîîîÿëëëÿëëëÿéééÿçççÿæææÿåååÿãããÿáááÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿêêêÿéééÿàààÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿÚÚÚÿáááÿãããÿÛÛÛÿ¬¬¬ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ„††v#   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿúúúÿ½½½ÿ‹‹‹ÿŠŠŠÿŠŠŠÿŠŠŠÿ‰‰‰ÿ‰‰‰ÿˆˆˆÿ‰‰‰ÿŠŠŠÿŠŠŠÿŒŒŒÿŽŽŽÿµµµÿ÷÷÷ÿýýýÿÿÿÿÿþþþÿøøøÿæææÿ™š™ÿŒŒŒÿ‹‹‹ÿ‹‹‹ÿÿŽŽŽÿÄÄÄÿøøøÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿøøøÿÄÄÄÿÿŽŽŽÿŽŽŽÿŽŽŽÿÿšššÿãããÿøøøÿûûûÿñññÿ¬­¬ÿ‘‘‘ÿ‘‘‘ÿ’’’ÿ’’’ÿ‘‘‘ÿ‘‘‘ÿ‘‘‘ÿ’’’ÿ’’’ÿ’’’ÿ“““ÿ“““ÿ“““ÿ“““ÿ“““ÿ–––ÿàààÿúúúÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿòòòÿðððÿïïïÿíííÿëëëÿëëëÿéééÿçççÿæææÿåååÿãããÿáááÿàààÿÞÞÞÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿéééÿèèèÿßßßÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿÚÚÚÿßßßÿäääÿãããÿ···ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ›œœµ &   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿÚÚÚÿš›šÿŽŽŽÿŽŽŽÿÿÿÿŽŽŽÿŽŽŽÿÿ———ÿÍÎÍÿúúúÿýýýÿÿÿÿÿÿÿÿÿþþþÿùùùÿ×××ÿ’’’ÿÿÿÿÿ’’’ÿÚÚÚÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿûûûÿØÙØÿ”””ÿ“““ÿ“““ÿ“““ÿ“““ÿ”””ÿ×××ÿùùùÿüüüÿõõõÿ²²²ÿ”””ÿ”””ÿ•••ÿ•••ÿ•••ÿ•••ÿ–––ÿ–––ÿ–––ÿ–––ÿ———ÿ———ÿ———ÿ˜˜˜ÿ˜˜˜ÿ˜˜˜ÿåååÿûûûÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿïïïÿíííÿëëëÿêêêÿéééÿçççÿæææÿåååÿâââÿâââÿàààÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿèèèÿéééÿÞÞÞÿÝÝÝÿÜÜÜÿÛÛÛÿÚÚÚÿÜÜÜÿåååÿäääÿÄÄÄÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¦¦¦è(((-   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿôõôÿר×ÿ¹º¹ÿ§§§ÿœœœÿšššÿ¦§¦ÿ·¸·ÿÔÕÔÿóóóÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿÖ×Öÿ­­­ÿ­­­ÿ­­­ÿ®®®ÿ­­­ÿ°°°ÿñññÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿòòòÿ±±±ÿ®®®ÿ°°°ÿ°°°ÿ¯¯¯ÿ±±±ÿÕÖÕÿüüüÿþþþÿûûûÿÊËÊÿ´´´ÿ´´´ÿµµµÿµµµÿµµµÿµµµÿµµµÿµµµÿµµµÿµµµÿ´´´ÿ³³³ÿ³³³ÿ²²²ÿ³³³ÿ³³³ÿíííÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿåååÿâââÿâââÿßßßÿÞÞÞÿÜÜÜÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿèèèÿèèèÿÝÝÝÿÜÜÜÿÛÛÛÿÚÚÚÿÚÚÚÿäääÿåååÿÓÓÓÿªªªÿ©©©ÿ©©©ÿ©©©ÿ©©©üaaaL"   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿýýýÿüüüÿüüüÿûüûÿüýüÿýýýÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿýýýÿüüüÿüüüÿüüüÿüüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýþýÿýýýÿüüüÿüüüÿûüûÿûüûÿüýüÿýýýÿþþþÿÿÿÿÿþþþÿýýýÿýýýÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿüüüÿýýýÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿêêêÿéééÿæææÿæææÿäääÿâââÿâââÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿèèèÿèèèÿÜÜÜÿÛÛÛÿÚÚÚÿÙÙÙÿáááÿæææÿàààÿ®®®ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ‰‹‹‚$   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿäääÿâââÿáááÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿèèèÿåååÿÛÛÛÿÚÚÚÿÙÙÙÿßßßÿæææÿäääÿºººÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿžŸŸÂ &   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿäääÿâââÿáááÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿèèèÿæææÿÚÚÚÿÙÙÙÿÛÛÛÿæææÿæææÿÊÊÊÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¦¦¦î4441   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿäääÿâââÿáááÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿæææÿäääÿØØØÿØØØÿåååÿæææÿØØØÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©þjmmT"    #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿëëëÿêêêÿéééÿæææÿæææÿäääÿâââÿáááÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿæææÿäääÿ×××ÿàààÿçççÿáááÿ°°°ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿŽŽŽŽ$   #/;©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿüüüÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿêêêÿéééÿæææÿæææÿäääÿâââÿâââÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿæææÿãããÿÛÛÛÿæææÿæææÿ½½½ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ   Î '   ".:©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿîîîÿíííÿìììÿêêêÿéééÿæææÿæææÿäääÿâââÿâââÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿåååÿãããÿäääÿæææÿÌÌÌÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¦¦¦ôAFF7   "-:©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿñññÿðððÿïïïÿíííÿëëëÿêêêÿéééÿæææÿæææÿåååÿâââÿâââÿßßßÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿäääÿåååÿåååÿÚÚÚÿªªªÿ©©©ÿ©©©ÿ©©©ÿ©©©þruu^#    !,8©©©û©©©ÿ©©©ÿ©©©ÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿôôôÿóóóÿòòòÿðððÿïïïÿíííÿëëëÿëëëÿéééÿçççÿæææÿåååÿâââÿáááÿàààÿÞÞÞÿÝÝÝÿÛÛÛÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿäääÿäääÿáááÿ±±±ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ•••œ%    +6¥¥¥ò©©©ÿ©©©ÿ©©©ÿùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿðððÿïïïÿîîîÿëëëÿëëëÿéééÿçççÿåååÿåååÿãããÿáááÿàààÿÞÞÞÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿãããÿãããÿ¾¾¾ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¢¢¢×(    (4¢¢¢á©©©ÿ©©©ÿ©©©ÿîîîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿúúúÿøøøÿöööÿõõõÿóóóÿòòòÿñññÿïïïÿîîîÿëëëÿêêêÿêêêÿçççÿæææÿåååÿãããÿâââÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿâââÿÍÍÍÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨öMQQ<!   &1™ššÀ©©©ÿ©©©ÿ©©©ÿØØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿûûûÿùùùÿøøøÿ÷÷÷ÿõõõÿôôôÿòòòÿñññÿïïïÿîîîÿìììÿêêêÿêêêÿçççÿæææÿæææÿãããÿâââÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿËËËÿªªªÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ{}}h#   "-„„„‰©©©ÿ©©©ÿ©©©ÿ´´´ÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿûûûÿúúúÿøøøÿ÷÷÷ÿõõõÿóóóÿóóóÿñññÿïïïÿîîîÿìììÿëëëÿêêêÿèèèÿæææÿåååÿäääÿâââÿàààÿßßßÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¯¯¯ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ—˜˜©%    (EIIF¨¨¨ù©©©ÿ©©©ÿ©©©ÿÒÒÒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿýýýÿûûûÿúúúÿùùùÿ÷÷÷ÿöööÿóóóÿóóóÿòòòÿïïïÿïïïÿìììÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿàààÿÞÞÞÿÝÝÝÿÜÜÜÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¤¤¤à$$$*   #,•••©©©©ÿ©©©ÿ©©©ÿ©©©ÿÓÓÓÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿüüüÿúúúÿùùùÿøøøÿöööÿôôôÿòòòÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿåååÿäääÿâââÿáááÿÞÞÞÿÞÞÞÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨úVZZA!    &AEE?¤¤¤ç©©©ÿ©©©ÿ©©©ÿ©©©ÿ¶¶¶ÿÚÚÚÿðððÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿüüüÿûûûÿùùùÿ÷÷÷ÿ÷÷÷ÿôôôÿóóóÿòòòÿðððÿîîîÿíííÿëëëÿêêêÿèèèÿçççÿåååÿäääÿãããÿáááÿßßßÿÝÝÝÿÝÝÝÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿƒ……s"    'looZ§§§÷©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿœžžµ#     %hllS¥¥¥è©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¦¦¦è177*     "KOO:™šš§©©©û©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨üjnnA     !X\\=ŽŸŸŸÀ£¤¤Þ¦¦¦ò©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ©©©ÿ¨¨¨ùŒŒŒh            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!                                                                                                                                                                                                                                                           ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÀ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÀ?ÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿþ?ÿÿÿÿÿÿþ?ÿÿÿÿÿÿþÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþ?ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€?ÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀ?ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿolive-continuous/app/packaging/windows/resources.rc000066400000000000000000000020271370472574300231530ustar00rootroot00000000000000IDI_ICON1 ICON DISCARDABLE "olive.ico" IDI_ICON2 ICON DISCARDABLE "olive_ove.ico" #include #include "version.h" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_PRODUCTVERSION BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", VER_COMPANYNAME_STR VALUE "FileDescription", VER_FILEDESCRIPTION_STR VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", VER_INTERNALNAME_STR VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR VALUE "ProductName", VER_PRODUCTNAME_STR VALUE "ProductVersion", VER_PRODUCTVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END olive-continuous/app/packaging/windows/version.h000066400000000000000000000013171370472574300224520ustar00rootroot00000000000000#ifndef VERSION_H #define VERSION_H #define VER_FILEVERSION 1,0,0,0 #define VER_FILEVERSION_STR "1.0.0.0\0" #define VER_PRODUCTVERSION 1,0,0,0 #define VER_PRODUCTVERSION_STR "1.0\0" #define VER_COMPANYNAME_STR "Olive Team" #define VER_FILEDESCRIPTION_STR "Olive" #define VER_INTERNALNAME_STR "Olive" #define VER_LEGALCOPYRIGHT_STR "Copyright © 2018 Olive Team" #define VER_LEGALTRADEMARKS1_STR "All Rights Reserved" #define VER_LEGALTRADEMARKS2_STR VER_LEGALTRADEMARKS1_STR #define VER_ORIGINALFILENAME_STR "Olive.exe" #define VER_PRODUCTNAME_STR "Olive" #define VER_COMPANYDOMAIN_STR "www.olivevideoeditor.org" #endif // VERSION_H olive-continuous/app/panel/000077500000000000000000000000001370472574300162735ustar00rootroot00000000000000olive-continuous/app/panel/CMakeLists.txt000066400000000000000000000022731370472574300210370ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(audiomonitor) add_subdirectory(curve) add_subdirectory(footageviewer) add_subdirectory(node) add_subdirectory(param) add_subdirectory(pixelsampler) add_subdirectory(project) add_subdirectory(scope) add_subdirectory(sequenceviewer) add_subdirectory(table) add_subdirectory(taskmanager) add_subdirectory(timebased) add_subdirectory(timeline) add_subdirectory(tool) add_subdirectory(viewer) set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/panelmanager.h panel/panelmanager.cpp PARENT_SCOPE ) olive-continuous/app/panel/audiomonitor/000077500000000000000000000000001370472574300210045ustar00rootroot00000000000000olive-continuous/app/panel/audiomonitor/CMakeLists.txt000066400000000000000000000014771370472574300235550ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/audiomonitor/audiomonitor.h panel/audiomonitor/audiomonitor.cpp PARENT_SCOPE ) olive-continuous/app/panel/audiomonitor/audiomonitor.cpp000066400000000000000000000020511370472574300242170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiomonitor.h" OLIVE_NAMESPACE_ENTER AudioMonitorPanel::AudioMonitorPanel(QWidget *parent) : PanelWidget(QStringLiteral("AudioMonitor"), parent) { audio_monitor_ = new AudioMonitor(this); setWidget(audio_monitor_); Retranslate(); } void AudioMonitorPanel::Retranslate() { SetTitle(tr("Audio Monitor")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/audiomonitor/audiomonitor.h000066400000000000000000000022261370472574300236700ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOMONITORPANEL_H #define AUDIOMONITORPANEL_H #include "widget/audiomonitor/audiomonitor.h" #include "widget/panel/panel.h" OLIVE_NAMESPACE_ENTER /** * @brief PanelWidget wrapper around an AudioMonitor */ class AudioMonitorPanel : public PanelWidget { public: AudioMonitorPanel(QWidget* parent = nullptr); private: virtual void Retranslate() override; AudioMonitor* audio_monitor_; }; OLIVE_NAMESPACE_EXIT #endif // AUDIOMONITORPANEL_H olive-continuous/app/panel/curve/000077500000000000000000000000001370472574300174175ustar00rootroot00000000000000olive-continuous/app/panel/curve/CMakeLists.txt000066400000000000000000000014431370472574300221610ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/curve/curve.h panel/curve/curve.cpp PARENT_SCOPE ) olive-continuous/app/panel/curve/curve.cpp000066400000000000000000000036721370472574300212570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "curve.h" OLIVE_NAMESPACE_ENTER CurvePanel::CurvePanel(QWidget *parent) : TimeBasedPanel(QStringLiteral("CurvePanel"), parent) { // Create main widget and set it SetTimeBasedWidget(new CurveWidget()); // Set strings Retranslate(); } NodeInput *CurvePanel::GetInput() const { return static_cast(GetTimeBasedWidget())->GetInput(); } void CurvePanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); } void CurvePanel::SetInput(NodeInput *input) { static_cast(GetTimeBasedWidget())->SetInput(input); Retranslate(); } void CurvePanel::IncreaseTrackHeight() { CurveWidget* c = static_cast(GetTimeBasedWidget()); c->SetVerticalScale(c->GetVerticalScale() * 2); } void CurvePanel::DecreaseTrackHeight() { CurveWidget* c = static_cast(GetTimeBasedWidget()); c->SetVerticalScale(c->GetVerticalScale() * 0.5); } void CurvePanel::Retranslate() { TimeBasedPanel::Retranslate(); SetTitle(tr("Curve Editor")); NodeInput* connected_input = static_cast(GetTimeBasedWidget())->GetInput(); if (connected_input) { SetSubtitle(connected_input->name()); } else { SetSubtitle(QString()); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/curve/curve.h000066400000000000000000000023751370472574300207230ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CURVEPANEL_H #define CURVEPANEL_H #include "panel/timebased/timebased.h" #include "widget/curvewidget/curvewidget.h" OLIVE_NAMESPACE_ENTER class CurvePanel : public TimeBasedPanel { Q_OBJECT public: CurvePanel(QWidget* parent); NodeInput* GetInput() const; virtual void DeleteSelected() override; public slots: void SetInput(NodeInput* input); virtual void IncreaseTrackHeight() override; virtual void DecreaseTrackHeight() override; protected: virtual void Retranslate() override; }; OLIVE_NAMESPACE_EXIT #endif // CURVEPANEL_H olive-continuous/app/panel/footageviewer/000077500000000000000000000000001370472574300211415ustar00rootroot00000000000000olive-continuous/app/panel/footageviewer/CMakeLists.txt000066400000000000000000000015031370472574300237000ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/footageviewer/footageviewer.h panel/footageviewer/footageviewer.cpp PARENT_SCOPE ) olive-continuous/app/panel/footageviewer/footageviewer.cpp000066400000000000000000000032651370472574300245210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "footageviewer.h" #include "widget/viewer/footageviewer.h" OLIVE_NAMESPACE_ENTER FootageViewerPanel::FootageViewerPanel(QWidget *parent) : ViewerPanelBase(QStringLiteral("FootageViewerPanel"), parent) { // Set ViewerWidget as the central widget FootageViewerWidget* fvw = new FootageViewerWidget(); fvw->SetAutoCacheEnabled(false); connect(fvw, &FootageViewerWidget::RequestScopePanel, this, &FootageViewerPanel::CreateScopePanel); SetTimeBasedWidget(fvw); // Set strings Retranslate(); } QList FootageViewerPanel::GetSelectedFootage() const { return {static_cast(GetTimeBasedWidget())->GetFootage()}; } void FootageViewerPanel::SetFootage(Footage *f) { static_cast(GetTimeBasedWidget())->SetFootage(f); if (f) { SetSubtitle(f->name()); } else { Retranslate(); } } void FootageViewerPanel::Retranslate() { ViewerPanelBase::Retranslate(); SetTitle(tr("Footage Viewer")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/footageviewer/footageviewer.h000066400000000000000000000024501370472574300241610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOOTAGE_VIEWER_PANEL_H #define FOOTAGE_VIEWER_PANEL_H #include #include "panel/viewer/viewerbase.h" #include "panel/project/footagemanagementpanel.h" OLIVE_NAMESPACE_ENTER /** * @brief Dockable wrapper around a ViewerWidget */ class FootageViewerPanel : public ViewerPanelBase, public FootageManagementPanel { Q_OBJECT public: FootageViewerPanel(QWidget* parent); virtual QList GetSelectedFootage() const override; void SetFootage(Footage* f); protected: virtual void Retranslate() override; }; OLIVE_NAMESPACE_EXIT #endif // FOOTAGE_VIEWER_PANEL_H olive-continuous/app/panel/node/000077500000000000000000000000001370472574300172205ustar00rootroot00000000000000olive-continuous/app/panel/node/CMakeLists.txt000066400000000000000000000014371370472574300217650ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/node/node.h panel/node/node.cpp PARENT_SCOPE ) olive-continuous/app/panel/node/node.cpp000066400000000000000000000040611370472574300206520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "node.h" OLIVE_NAMESPACE_ENTER NodePanel::NodePanel(QWidget *parent) : PanelWidget(QStringLiteral("NodePanel"), parent) { // Create NodeView widget node_view_ = new NodeView(this); // Connect node view signals to this panel connect(node_view_, SIGNAL(SelectionChanged(QList)), this, SIGNAL(SelectionChanged(QList))); // Set it as the main widget of this panel SetWidgetWithPadding(node_view_); // Set strings Retranslate(); } void NodePanel::SetGraph(NodeGraph *graph) { node_view_->SetGraph(graph); } void NodePanel::SelectAll() { node_view_->SelectAll(); } void NodePanel::DeselectAll() { node_view_->DeselectAll(); } void NodePanel::DeleteSelected() { node_view_->DeleteSelected(); } void NodePanel::CutSelected() { node_view_->CopySelected(true); } void NodePanel::CopySelected() { node_view_->CopySelected(false); } void NodePanel::Paste() { node_view_->Paste(); } void NodePanel::Duplicate() { node_view_->Duplicate(); } void NodePanel::Select(const QList &nodes) { node_view_->Select(nodes); } void NodePanel::SelectWithDependencies(const QList &nodes) { node_view_->SelectWithDependencies(nodes); } void NodePanel::SelectBlocks(const QList &nodes) { node_view_->SelectBlocks(nodes); } void NodePanel::Retranslate() { SetTitle(tr("Node Editor")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/node/node.h000066400000000000000000000032661370472574300203250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPANEL_H #define NODEPANEL_H #include "widget/nodeview/nodeview.h" #include "widget/panel/panel.h" OLIVE_NAMESPACE_ENTER /** * @brief A PanelWidget wrapper around a NodeView */ class NodePanel : public PanelWidget { Q_OBJECT public: NodePanel(QWidget* parent); void SetGraph(NodeGraph* graph); virtual void SelectAll() override; virtual void DeselectAll() override; virtual void DeleteSelected() override; virtual void CutSelected() override; virtual void CopySelected() override; virtual void Paste() override; virtual void Duplicate() override; public slots: void Select(const QList& nodes); void SelectWithDependencies(const QList& nodes); void SelectBlocks(const QList& nodes); signals: /** * @brief Wrapper for NodeView::SelectionChanged() */ void SelectionChanged(QList selected_nodes); private: virtual void Retranslate() override; NodeView* node_view_; }; OLIVE_NAMESPACE_EXIT #endif // NODEPANEL_H olive-continuous/app/panel/panelmanager.cpp000066400000000000000000000074421370472574300214400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "panelmanager.h" #include "config/config.h" OLIVE_NAMESPACE_ENTER PanelManager* PanelManager::instance_ = nullptr; PanelManager::PanelManager(QObject *parent) : QObject(parent), locked_(false), last_focused_panel_(nullptr) { } void PanelManager::DeleteAllPanels() { // Prevent any confusion regarding focus history by clearing it first QList copy = focus_history_; focus_history_.clear(); qDeleteAll(copy); } const QList &PanelManager::panels() { return focus_history_; } PanelWidget *PanelManager::CurrentlyFocused() const { // If hover focus is enabled, find the currently hovered panel and return it (if no panel is hovered, resort to // default behavior) if (Config::Current()["HoverFocus"].toBool()) { PanelWidget* hovered = CurrentlyHovered(); if (hovered != nullptr) { return hovered; } } if (focus_history_.isEmpty()) { return nullptr; } return focus_history_.first(); } PanelWidget *PanelManager::CurrentlyHovered() const { foreach (PanelWidget* panel, focus_history_) { if (panel->underMouse()) { return panel; } } return nullptr; } bool PanelManager::ArePanelsLocked() { return locked_; } void PanelManager::CreateInstance() { instance_ = new PanelManager(); } void PanelManager::DestroyInstance() { delete instance_; } PanelManager *PanelManager::instance() { return instance_; } void PanelManager::FocusChanged(QWidget *old, QWidget *now) { Q_UNUSED(old) QObject* parent = now; PanelWidget* panel_cast_test; // Loop through widget's parent hierarchy while (parent != nullptr) { // Use dynamic_cast to test if this object is a PanelWidget panel_cast_test = dynamic_cast(parent); if (panel_cast_test) { if (last_focused_panel_ != panel_cast_test) { // If so, bump this to the top of the focus history int panel_index = focus_history_.indexOf(panel_cast_test); // Disable highlight border on old panel if (!focus_history_.isEmpty()) { focus_history_.first()->SetBorderVisible(false); } // Enable new border's highlight panel_cast_test->SetBorderVisible(true); // If it's not in the focus history, prepend it, otherwise move it if (panel_index == -1) { focus_history_.prepend(panel_cast_test); } else { focus_history_.move(panel_index, 0); } last_focused_panel_ = panel_cast_test; emit FocusedPanelChanged(panel_cast_test); } break; } parent = parent->parent(); } } void PanelManager::SetPanelsLocked(bool locked) { foreach (PanelWidget* panel, focus_history_) { // Only affect panels actually in our layout if (!panel->isFloating()) { panel->SetMovementLocked(locked); } } locked_ = locked; } void PanelManager::PanelDestroyed() { PanelWidget* panel = static_cast(sender()); focus_history_.removeOne(panel); if (last_focused_panel_ == panel) { last_focused_panel_ = focus_history_.isEmpty() ? nullptr : focus_history_.first(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/panelmanager.h000066400000000000000000000135221370472574300211010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PANELFOCUSMANAGER_H #define PANELFOCUSMANAGER_H #include #include #include "widget/panel/panel.h" OLIVE_NAMESPACE_ENTER /** * @brief The PanelFocusManager class * * This object keeps track of which panel is focused at any given time. * * Sometimes a function (specifically a keyboard-triggered one, e.g. Delete) may have different purposes depending on * which panel is "focused" at any given time. Pressing Delete on the Timeline is not the same as pressing Delete in * the Project panel, for example. This kind of "focus" is slightly different from standard QWidget focus, since it * aims to be less specific than a single QPushButton or QLineEdit, and rather specific to the panel widgets like * that belong to. * * PanelFocusManager's SLOT(FocusChanged()) connects to the QApplication instance's SIGNAL(focusChanged()) so that * it always knows when focus has changed within the application. */ class PanelManager : public QObject { Q_OBJECT public: PanelManager(QObject* parent = nullptr); /** * @brief Destroy all panels * * Should only be used on application exit to cleanly free all panels. */ void DeleteAllPanels(); /** * @brief Get a list of all existing panels * * Panels are ordered from most recently focused to least recently focused. */ const QList& panels(); /** * @brief Return the currently focused widget, or nullptr if nothing is focused * * This result == CurrentlyFocused() if HoverFocus is true */ PanelWidget* CurrentlyFocused() const; /** * @brief Return the widget that the mouse is currently hovering over, or nullptr if nothing is hovered over * * This result == CurrentlyFocused() if HoverFocus is true */ PanelWidget* CurrentlyHovered() const; template /** * @brief Get most recently focused panel of a certain type * * @return * * The most recently focused panel of the specified type, or nullptr if none exists */ T* MostRecentlyFocused(); template /** * @brief Create a panel */ T* CreatePanel(QWidget* parent); /** * @brief Get whether panels are currently prevented from moving */ bool ArePanelsLocked(); /** * @brief Create PanelManager singleton instance */ static void CreateInstance(); /** * @brief Destroy PanelManager singleton instance * * If no PanelManager was created, this is a no-op. */ static void DestroyInstance(); /** * @brief Access to PanelManager singleton instance */ static PanelManager* instance(); template /** * @brief Get a list of panels of a certain type */ QList GetPanelsOfType(); public slots: /** * @brief Connect this to a QApplication's SIGNAL(focusChanged()) * * Interprets focus information to determine the currently focused panel */ void FocusChanged(QWidget* old, QWidget* now); /** * @brief Sets whether panels should be prevented from moving */ void SetPanelsLocked(bool locked); signals: /** * @brief Signal emitted when the currently focused panel changes */ void FocusedPanelChanged(PanelWidget* panel); private: /** * @brief History array for traversing through (see MostRecentlyFocused()) */ QList focus_history_; /** * @brief Internal panel movement is locked value */ bool locked_; /** * @brief PanelManager singleton instance */ static PanelManager* instance_; /** * @brief The last panel that was focused * * Stored to prevent emitting FocusedPanelChanged() multiple times for the same panel */ PanelWidget* last_focused_panel_; private slots: /** * @brief Processing if a panel gets deleted */ void PanelDestroyed(); }; template T *PanelManager::CreatePanel(QWidget *parent) { T* panel = new T(parent); // Add panel to the bottom of the focus history focus_history_.append(panel); panel->SetMovementLocked(locked_); // Sane default for panel size panel->resize(parent->size() / 3); // We're about to center the panel relative to the parent (usually the main window), but for some // reason this requires the panel to be shown first. panel->show(); // Center the panel relative to the parent QPoint parent_center = panel->mapFromGlobal(parent->mapToGlobal(parent->rect().center())); QPoint panel_center = panel->rect().center(); panel->move(parent_center - panel_center); // Connect destroy signal so we can remove it from focus history connect(panel, &PanelWidget::destroyed, this, &PanelManager::PanelDestroyed, Qt::DirectConnection); return panel; } template T* PanelManager::MostRecentlyFocused() { T* cast_test; for (int i=0;i(focus_history_.at(i)); if (cast_test != nullptr) { return cast_test; } } return nullptr; } template QList PanelManager::GetPanelsOfType() { QList panels; T* cast_test; foreach (PanelWidget* panel, focus_history_) { cast_test = dynamic_cast(panel); if (cast_test) { panels.append(cast_test); } } return panels; } OLIVE_NAMESPACE_EXIT #endif // PANELFOCUSMANAGER_H olive-continuous/app/panel/param/000077500000000000000000000000001370472574300173735ustar00rootroot00000000000000olive-continuous/app/panel/param/CMakeLists.txt000066400000000000000000000014431370472574300221350ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/param/param.h panel/param/param.cpp PARENT_SCOPE ) olive-continuous/app/panel/param/param.cpp000066400000000000000000000077311370472574300212070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "param.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER ParamPanel::ParamPanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("ParamPanel"), parent) { NodeParamView* view = new NodeParamView(); connect(view, &NodeParamView::InputDoubleClicked, this, &ParamPanel::CreateCurvePanel); connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode); connect(view, &NodeParamView::FoundGizmos, this, &ParamPanel::FoundGizmos); SetTimeBasedWidget(view); Retranslate(); } void ParamPanel::SetNodes(QList nodes) { static_cast(GetTimeBasedWidget())->SetNodes(nodes); Retranslate(); } void ParamPanel::SetTimestamp(const int64_t ×tamp) { TimeBasedPanel::SetTimestamp(timestamp); // Ensure all CurvePanels are updated with this time too ParamViewTimeChanged(timestamp); } void ParamPanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); } void ParamPanel::Retranslate() { SetTitle(tr("Parameter Editor")); NodeParamView* view = static_cast(GetTimeBasedWidget()); if (view->nodes().isEmpty()) { SetSubtitle(tr("(none)")); } else if (view->nodes().size() == 1) { SetSubtitle(view->nodes().first()->Name()); } else { SetSubtitle(tr("(multiple)")); } } void ParamPanel::CreateCurvePanel(NodeInput *input) { if (!input->is_keyframable()) { return; } CurvePanel* panel = open_curve_panels_.value(input); if (panel) { panel->raise(); return; } NodeParamView* view = static_cast(GetTimeBasedWidget()); panel = Core::instance()->main_window()->AppendCurvePanel(); panel->ConnectViewerNode(view->GetConnectedNode()); panel->SetTimestamp(view->GetTimestamp()); panel->SetInput(input); connect(view, &NodeParamView::TimeChanged, this, &ParamPanel::ParamViewTimeChanged); connect(panel, &CurvePanel::TimeChanged, this, &ParamPanel::CurvePanelTimeChanged); connect(panel, &CurvePanel::CloseRequested, this, &ParamPanel::ClosingCurvePanel); open_curve_panels_.insert(input, panel); } void ParamPanel::ClosingCurvePanel() { CurvePanel* panel = static_cast(sender()); open_curve_panels_.remove(panel->GetInput()); } void ParamPanel::ParamViewTimeChanged(const int64_t &time) { // Ensure all CurvePanels are updated with this time too QHash::const_iterator i; for (i=open_curve_panels_.begin(); i!=open_curve_panels_.end(); i++) { // If connected viewers are the same, set the timestamp if (i.value()->GetConnectedViewer() == GetConnectedViewer()) { i.value()->SetTimestamp(time); } } } void ParamPanel::CurvePanelTimeChanged(const int64_t &time) { GetTimeBasedWidget()->SetTimestamp(time); emit GetTimeBasedWidget()->TimeChanged(time); CurvePanel* src = static_cast(sender()); // Ensure all CurvePanels are updated with this time too QHash::const_iterator i; for (i=open_curve_panels_.begin(); i!=open_curve_panels_.end(); i++) { // If connected viewers are the same and the panel isn't the source, set the timestamp if (i.value() != src && i.value()->GetConnectedViewer() == src->GetConnectedViewer()) { i.value()->SetTimestamp(time); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/param/param.h000066400000000000000000000031021370472574300206400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PARAM_H #define PARAM_H #include "panel/curve/curve.h" #include "panel/timebased/timebased.h" #include "widget/nodeparamview/nodeparamview.h" OLIVE_NAMESPACE_ENTER class ParamPanel : public TimeBasedPanel { Q_OBJECT public: ParamPanel(QWidget* parent); public slots: void SetNodes(QList nodes); virtual void SetTimestamp(const int64_t& timestamp) override; virtual void DeleteSelected() override; signals: void RequestSelectNode(const QList& target); void FoundGizmos(Node* node); protected: virtual void Retranslate() override; private slots: void CreateCurvePanel(NodeInput* input); void ClosingCurvePanel(); private: QHash open_curve_panels_; private slots: void ParamViewTimeChanged(const int64_t& time); void CurvePanelTimeChanged(const int64_t& time); }; OLIVE_NAMESPACE_EXIT #endif // PARAM_H olive-continuous/app/panel/pixelsampler/000077500000000000000000000000001370472574300210005ustar00rootroot00000000000000olive-continuous/app/panel/pixelsampler/CMakeLists.txt000066400000000000000000000015111370472574300235360ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/pixelsampler/pixelsamplerpanel.h panel/pixelsampler/pixelsamplerpanel.cpp PARENT_SCOPE ) olive-continuous/app/panel/pixelsampler/pixelsamplerpanel.cpp000066400000000000000000000023121370472574300252270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "pixelsamplerpanel.h" OLIVE_NAMESPACE_ENTER PixelSamplerPanel::PixelSamplerPanel(QWidget *parent) : PanelWidget(QStringLiteral("ProjectPanel"), parent) { sampler_widget_ = new ManagedPixelSamplerWidget(); SetWidgetWithPadding(sampler_widget_); Retranslate(); } void PixelSamplerPanel::SetValues(const Color &reference, const Color &display) { sampler_widget_->SetValues(reference, display); } void PixelSamplerPanel::Retranslate() { SetTitle(tr("Pixel Sampler")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/pixelsampler/pixelsamplerpanel.h000066400000000000000000000023011370472574300246720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PIXELSAMPLERPANEL_H #define PIXELSAMPLERPANEL_H #include "widget/panel/panel.h" #include "widget/pixelsampler/pixelsampler.h" OLIVE_NAMESPACE_ENTER class PixelSamplerPanel : public PanelWidget { Q_OBJECT public: PixelSamplerPanel(QWidget* parent = nullptr); public slots: void SetValues(const Color& reference, const Color& display); private: virtual void Retranslate() override; ManagedPixelSamplerWidget* sampler_widget_; }; OLIVE_NAMESPACE_EXIT #endif // PIXELSAMPLERPANEL_H olive-continuous/app/panel/project/000077500000000000000000000000001370472574300177415ustar00rootroot00000000000000olive-continuous/app/panel/project/CMakeLists.txt000066400000000000000000000015241370472574300225030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/project/footagemanagementpanel.h panel/project/project.h panel/project/project.cpp PARENT_SCOPE ) olive-continuous/app/panel/project/footagemanagementpanel.h000066400000000000000000000017751370472574300246250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOOTAGEMANAGEMENTPANEL_H #define FOOTAGEMANAGEMENTPANEL_H #include #include "project/item/footage/footage.h" OLIVE_NAMESPACE_ENTER class FootageManagementPanel { public: virtual QList GetSelectedFootage() const = 0; }; OLIVE_NAMESPACE_EXIT #endif // FOOTAGEMANAGEMENTPANEL_H olive-continuous/app/panel/project/project.cpp000066400000000000000000000143511370472574300221170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "project.h" #include #include #include "core.h" #include "panel/footageviewer/footageviewer.h" #include "panel/timeline/timeline.h" #include "panel/panelmanager.h" #include "project/item/sequence/sequence.h" #include "widget/menu/menushared.h" #include "widget/projecttoolbar/projecttoolbar.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER ProjectPanel::ProjectPanel(QWidget *parent) : PanelWidget(QStringLiteral("ProjectPanel"), parent) { // Create main widget and its layout QWidget* central_widget = new QWidget(this); QVBoxLayout* layout = new QVBoxLayout(central_widget); layout->setMargin(0); SetWidgetWithPadding(central_widget); // Set up project toolbar ProjectToolbar* toolbar = new ProjectToolbar(this); layout->addWidget(toolbar); // Make toolbar connections connect(toolbar, &ProjectToolbar::NewClicked, this, &ProjectPanel::ShowNewMenu); connect(toolbar, &ProjectToolbar::OpenClicked, Core::instance(), &Core::OpenProject); connect(toolbar, &ProjectToolbar::SaveClicked, Core::instance(), &Core::SaveActiveProject); connect(toolbar, &ProjectToolbar::UndoClicked, Core::instance()->undo_stack(), &QUndoStack::undo); connect(toolbar, &ProjectToolbar::RedoClicked, Core::instance()->undo_stack(), &QUndoStack::redo); // Set up main explorer object explorer_ = new ProjectExplorer(this); layout->addWidget(explorer_); connect(explorer_, &ProjectExplorer::DoubleClickedItem, this, &ProjectPanel::ItemDoubleClickSlot); // Set toolbar's view to the explorer's view toolbar->SetView(explorer_->view_type()); // Connect toolbar's view change signal to the explorer's view change slot connect(toolbar, &ProjectToolbar::ViewChanged, explorer_, &ProjectExplorer::set_view_type); // Set strings Retranslate(); } Project* ProjectPanel::project() const { return explorer_->project(); } void ProjectPanel::set_project(Project* p) { if (project()) { disconnect(project(), &Project::NameChanged, this, &ProjectPanel::UpdateSubtitle); disconnect(project(), &Project::NameChanged, this, &ProjectPanel::ProjectNameChanged); disconnect(project(), &Project::ModifiedChanged, this, &ProjectPanel::setWindowModified); } explorer_->set_project(p); if (project()) { connect(project(), &Project::NameChanged, this, &ProjectPanel::UpdateSubtitle); connect(project(), &Project::NameChanged, this, &ProjectPanel::ProjectNameChanged); connect(project(), &Project::ModifiedChanged, this, &ProjectPanel::setWindowModified); } UpdateSubtitle(); emit ProjectNameChanged(); if (p) { setWindowModified(p->is_modified()); } else { setWindowModified(false); } } QModelIndex ProjectPanel::get_root_index() const { return explorer_->get_root_index(); } void ProjectPanel::set_root(Item *item) { explorer_->set_root(item); Retranslate(); } QList ProjectPanel::SelectedItems() const { return explorer_->SelectedItems(); } Folder *ProjectPanel::GetSelectedFolder() const { return explorer_->GetSelectedFolder(); } ProjectViewModel *ProjectPanel::model() const { return explorer_->model(); } void ProjectPanel::SelectAll() { explorer_->SelectAll(); } void ProjectPanel::DeselectAll() { explorer_->DeselectAll(); } void ProjectPanel::Insert() { TimelinePanel* timeline = PanelManager::instance()->MostRecentlyFocused(); if (timeline) { timeline->InsertFootageAtPlayhead(GetSelectedFootage()); } } void ProjectPanel::Overwrite() { TimelinePanel* timeline = PanelManager::instance()->MostRecentlyFocused(); if (timeline) { timeline->OverwriteFootageAtPlayhead(GetSelectedFootage()); } } void ProjectPanel::DeleteSelected() { explorer_->DeleteSelected(); } void ProjectPanel::Edit(Item* item) { explorer_->Edit(item); } void ProjectPanel::Retranslate() { if (explorer_->get_root_index().isValid()) { SetTitle(tr("Folder")); } else { SetTitle(tr("Project")); } UpdateSubtitle(); } void ProjectPanel::ItemDoubleClickSlot(Item *item) { if (item == nullptr) { // If the user double clicks on empty space, show the import dialog Core::instance()->DialogImportShow(); } else if (item->type() == Item::kFootage) { // Open this footage in a FootageViewer PanelManager::instance()->MostRecentlyFocused()->SetFootage(static_cast(item)); } else if (item->type() == Item::kSequence) { // Open this sequence in the Timeline Core::instance()->main_window()->OpenSequence(static_cast(item)); } } void ProjectPanel::ShowNewMenu() { Menu new_menu(this); MenuShared::instance()->AddItemsForNewMenu(&new_menu); new_menu.exec(QCursor::pos()); } void ProjectPanel::UpdateSubtitle() { if (project()) { QString project_title = QStringLiteral("[*]%1").arg(project()->name()); if (explorer_->get_root_index().isValid()) { QString folder_path; Item* item = static_cast(explorer_->get_root_index().internalPointer()); do { folder_path.prepend(QStringLiteral("/%1").arg(item->name())); item = item->parent(); } while (item != project()->root()); project_title.append(folder_path); } SetSubtitle(project_title); } else { SetSubtitle(tr("(none)")); } } QList ProjectPanel::GetSelectedFootage() const { QList items = SelectedItems(); QList footage; foreach (Item* i, items) { if (i->type() == Item::kFootage) { footage.append(static_cast(i)); } } return footage; } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/project/project.h000066400000000000000000000037321370472574300215650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECT_PANEL_H #define PROJECT_PANEL_H #include "footagemanagementpanel.h" #include "project/project.h" #include "widget/panel/panel.h" #include "widget/projectexplorer/projectexplorer.h" OLIVE_NAMESPACE_ENTER /** * @brief A PanelWidget wrapper around a ProjectExplorer and a ProjectToolbar */ class ProjectPanel : public PanelWidget, public FootageManagementPanel { Q_OBJECT public: ProjectPanel(QWidget* parent); Project* project() const; void set_project(Project* p); QModelIndex get_root_index() const; void set_root(Item* item); QList SelectedItems() const; Folder* GetSelectedFolder() const; virtual QList GetSelectedFootage() const override; ProjectViewModel* model() const; virtual void SelectAll() override; virtual void DeselectAll() override; virtual void Insert() override; virtual void Overwrite() override; virtual void DeleteSelected() override; public slots: void Edit(Item *item); signals: void ProjectNameChanged(); private: virtual void Retranslate() override; ProjectExplorer* explorer_; private slots: void ItemDoubleClickSlot(Item* item); void ShowNewMenu(); void UpdateSubtitle(); }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ProjectPtr) #endif // PROJECT_PANEL_H olive-continuous/app/panel/scope/000077500000000000000000000000001370472574300174045ustar00rootroot00000000000000olive-continuous/app/panel/scope/CMakeLists.txt000066400000000000000000000014431370472574300221460ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/scope/scope.h panel/scope/scope.cpp PARENT_SCOPE ) olive-continuous/app/panel/scope/scope.cpp000066400000000000000000000051411370472574300212220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "scope.h" #include #include "panel/viewer/viewer.h" OLIVE_NAMESPACE_ENTER ScopePanel::ScopePanel(QWidget* parent) : PanelWidget(QStringLiteral("ScopePanel"), parent) { QWidget* central = new QWidget(); setWidget(central); QVBoxLayout* layout = new QVBoxLayout(central); QHBoxLayout* toolbar_layout = new QHBoxLayout(); toolbar_layout->setMargin(0); scope_type_combobox_ = new QComboBox(); for (int i=0;iaddItem(QString()); } toolbar_layout->addWidget(scope_type_combobox_); toolbar_layout->addStretch(); layout->addLayout(toolbar_layout); stack_ = new QStackedWidget(); layout->addWidget(stack_); // Create waveform view waveform_view_ = new WaveformScope(); stack_->addWidget(waveform_view_); // Create histogram histogram_ = new HistogramScope(); stack_->addWidget(histogram_); connect(scope_type_combobox_, static_cast(&QComboBox::currentIndexChanged), stack_, &QStackedWidget::setCurrentIndex); Retranslate(); } void ScopePanel::SetType(ScopePanel::Type t) { scope_type_combobox_->setCurrentIndex(t); } QString ScopePanel::TypeToName(ScopePanel::Type t) { switch (t) { case kTypeWaveform: return tr("Waveform"); case kTypeHistogram: return tr("Histogram"); case kTypeCount: break; } return QString(); } void ScopePanel::SetReferenceBuffer(Frame *frame) { histogram_->SetBuffer(frame); waveform_view_->SetBuffer(frame); } void ScopePanel::SetColorManager(ColorManager *manager) { histogram_->ConnectColorManager(manager); waveform_view_->ConnectColorManager(manager); } void ScopePanel::Retranslate() { SetTitle(tr("Scope")); for (int i=0;isetItemText(i, TypeToName(static_cast(i))); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/scope/scope.h000066400000000000000000000030371370472574300206710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SCOPE_PANEL_H #define SCOPE_PANEL_H #include #include #include "widget/panel/panel.h" #include "widget/scope/histogram/histogram.h" #include "widget/scope/waveform/waveform.h" OLIVE_NAMESPACE_ENTER class ViewerPanel; class ScopePanel : public PanelWidget { Q_OBJECT public: enum Type { kTypeWaveform, kTypeHistogram, kTypeCount }; ScopePanel(QWidget* parent = nullptr); void SetType(Type t); static QString TypeToName(Type t); public slots: void SetReferenceBuffer(Frame* frame); void SetColorManager(ColorManager* manager); protected: virtual void Retranslate() override; private: Type type_; QStackedWidget* stack_; QComboBox* scope_type_combobox_; WaveformScope* waveform_view_; HistogramScope* histogram_; }; OLIVE_NAMESPACE_EXIT #endif // SCOPE_PANEL_H olive-continuous/app/panel/sequenceviewer/000077500000000000000000000000001370472574300213255ustar00rootroot00000000000000olive-continuous/app/panel/sequenceviewer/CMakeLists.txt000066400000000000000000000015071370472574300240700ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/sequenceviewer/sequenceviewer.h panel/sequenceviewer/sequenceviewer.cpp PARENT_SCOPE ) olive-continuous/app/panel/sequenceviewer/sequenceviewer.cpp000066400000000000000000000020401370472574300250570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sequenceviewer.h" OLIVE_NAMESPACE_ENTER SequenceViewerPanel::SequenceViewerPanel(QWidget *parent) : ViewerPanel(QStringLiteral("SequenceViewerPanel"), parent) { // Set strings Retranslate(); } void SequenceViewerPanel::Retranslate() { ViewerPanel::Retranslate(); SetTitle(tr("Sequence Viewer")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/sequenceviewer/sequenceviewer.h000066400000000000000000000020151370472574300245260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SEQUENCEVIEWERPANEL_H #define SEQUENCEVIEWERPANEL_H #include "panel/viewer/viewer.h" OLIVE_NAMESPACE_ENTER class SequenceViewerPanel : public ViewerPanel { public: SequenceViewerPanel(QWidget* parent); protected: virtual void Retranslate() override; }; OLIVE_NAMESPACE_EXIT #endif // SEQUENCEVIEWERPANEL_H olive-continuous/app/panel/table/000077500000000000000000000000001370472574300173625ustar00rootroot00000000000000olive-continuous/app/panel/table/CMakeLists.txt000066400000000000000000000014431370472574300221240ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/table/table.h panel/table/table.cpp PARENT_SCOPE ) olive-continuous/app/panel/table/table.cpp000066400000000000000000000021511370472574300211540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "table.h" OLIVE_NAMESPACE_ENTER NodeTablePanel::NodeTablePanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("NodeTablePanel"), parent) { view_ = new NodeTableWidget(); SetTimeBasedWidget(view_); Retranslate(); } void NodeTablePanel::SetNodes(const QList &nodes) { view_->SetNodes(nodes); } void NodeTablePanel::Retranslate() { SetTitle(tr("Table View")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/table/table.h000066400000000000000000000022151370472574300206220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODETABLEPANEL_H #define NODETABLEPANEL_H #include "panel/timebased/timebased.h" #include "widget/nodetableview/nodetablewidget.h" OLIVE_NAMESPACE_ENTER class NodeTablePanel : public TimeBasedPanel { Q_OBJECT public: NodeTablePanel(QWidget* parent); public slots: void SetNodes(const QList& nodes); private: virtual void Retranslate() override; NodeTableWidget* view_; }; OLIVE_NAMESPACE_EXIT #endif // NODETABLEPANEL_H olive-continuous/app/panel/taskmanager/000077500000000000000000000000001370472574300205705ustar00rootroot00000000000000olive-continuous/app/panel/taskmanager/CMakeLists.txt000066400000000000000000000014731370472574300233350ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/taskmanager/taskmanager.h panel/taskmanager/taskmanager.cpp PARENT_SCOPE ) olive-continuous/app/panel/taskmanager/taskmanager.cpp000066400000000000000000000030231370472574300235670ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "taskmanager.h" #include "task/taskmanager.h" OLIVE_NAMESPACE_ENTER TaskManagerPanel::TaskManagerPanel(QWidget* parent) : PanelWidget(QStringLiteral("TaskManagerPanel"), parent) { // Create task view view_ = new TaskView(this); // Set it as the main widget setWidget(view_); // Connect task view to the task manager connect(TaskManager::instance(), &TaskManager::TaskAdded, view_, &TaskView::AddTask); connect(TaskManager::instance(), &TaskManager::TaskRemoved, view_, &TaskView::RemoveTask); connect(TaskManager::instance(), &TaskManager::TaskFailed, view_, &TaskView::TaskFailed); connect(view_, &TaskView::TaskCancelled, TaskManager::instance(), &TaskManager::CancelTask); // Set strings Retranslate(); } void TaskManagerPanel::Retranslate() { SetTitle(tr("Task Manager")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/taskmanager/taskmanager.h000066400000000000000000000021751370472574300232430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TASKMANAGER_PANEL_H #define TASKMANAGER_PANEL_H #include "widget/taskview/taskview.h" #include "widget/panel/panel.h" OLIVE_NAMESPACE_ENTER /** * @brief A PanelWidget wrapper around a TaskView widget */ class TaskManagerPanel : public PanelWidget { Q_OBJECT public: TaskManagerPanel(QWidget* parent); private: virtual void Retranslate() override; TaskView* view_; }; OLIVE_NAMESPACE_EXIT #endif // TASKMANAGER_H olive-continuous/app/panel/timebased/000077500000000000000000000000001370472574300202305ustar00rootroot00000000000000olive-continuous/app/panel/timebased/CMakeLists.txt000066400000000000000000000014631370472574300227740ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/timebased/timebased.h panel/timebased/timebased.cpp PARENT_SCOPE ) olive-continuous/app/panel/timebased/timebased.cpp000066400000000000000000000101301370472574300226640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timebased.h" OLIVE_NAMESPACE_ENTER TimeBasedPanel::TimeBasedPanel(const QString &object_name, QWidget *parent) : PanelWidget(object_name, parent), widget_(nullptr) { } rational TimeBasedPanel::GetTime() { return widget_->GetTime(); } void TimeBasedPanel::GoToStart() { widget_->GoToStart(); } void TimeBasedPanel::PrevFrame() { widget_->PrevFrame(); } void TimeBasedPanel::NextFrame() { widget_->NextFrame(); } void TimeBasedPanel::GoToEnd() { widget_->GoToEnd(); } void TimeBasedPanel::ZoomIn() { widget_->ZoomIn(); } void TimeBasedPanel::ZoomOut() { widget_->ZoomOut(); } void TimeBasedPanel::SetTimebase(const rational &timebase) { widget_->SetTimebase(timebase); } void TimeBasedPanel::SetTimestamp(const int64_t ×tamp) { widget_->SetTimestamp(timestamp); } void TimeBasedPanel::GoToPrevCut() { widget_->GoToPrevCut(); } void TimeBasedPanel::GoToNextCut() { widget_->GoToNextCut(); } void TimeBasedPanel::PlayPause() { emit PlayPauseRequested(); } void TimeBasedPanel::PlayInToOut() { emit PlayInToOutRequested(); } void TimeBasedPanel::ShuttleLeft() { emit ShuttleLeftRequested(); } void TimeBasedPanel::ShuttleStop() { emit ShuttleStopRequested(); } void TimeBasedPanel::ShuttleRight() { emit ShuttleRightRequested(); } TimeBasedWidget *TimeBasedPanel::GetTimeBasedWidget() const { return widget_; } ViewerOutput *TimeBasedPanel::GetConnectedViewer() const { return widget_->GetConnectedNode(); } TimeRuler *TimeBasedPanel::ruler() const { return widget_->ruler(); } void TimeBasedPanel::ConnectViewerNode(ViewerOutput *node) { if (widget_->GetConnectedNode() == node) { return; } if (widget_->GetConnectedNode()) { disconnect(widget_->GetConnectedNode(), &ViewerOutput::MediaNameChanged, this, &TimeBasedPanel::SetSubtitle); } widget_->ConnectViewerNode(node); if (node) { connect(node, &ViewerOutput::MediaNameChanged, this, &TimeBasedPanel::SetSubtitle); } // Update strings Retranslate(); } void TimeBasedPanel::SetTimeBasedWidget(TimeBasedWidget *widget) { if (widget_) { disconnect(widget_, &TimeBasedWidget::TimeChanged, this, &TimeBasedPanel::TimeChanged); disconnect(widget_, &TimeBasedWidget::TimebaseChanged, this, &TimeBasedPanel::TimebaseChanged); } widget_ = widget; if (widget_) { connect(widget_, &TimeBasedWidget::TimeChanged, this, &TimeBasedPanel::TimeChanged); connect(widget_, &TimeBasedWidget::TimebaseChanged, this, &TimeBasedPanel::TimebaseChanged); } SetWidgetWithPadding(widget_); } void TimeBasedPanel::Retranslate() { if (GetTimeBasedWidget()->GetConnectedNode()) { SetSubtitle(GetTimeBasedWidget()->GetConnectedNode()->media_name()); } else { SetSubtitle(tr("(none)")); } } void TimeBasedPanel::SetIn() { GetTimeBasedWidget()->SetInAtPlayhead(); } void TimeBasedPanel::SetOut() { GetTimeBasedWidget()->SetOutAtPlayhead(); } void TimeBasedPanel::ResetIn() { GetTimeBasedWidget()->ResetIn(); } void TimeBasedPanel::ResetOut() { GetTimeBasedWidget()->ResetOut(); } void TimeBasedPanel::ClearInOut() { GetTimeBasedWidget()->ClearInOutPoints(); } void TimeBasedPanel::SetMarker() { GetTimeBasedWidget()->SetMarker(); } void TimeBasedPanel::ToggleShowAll() { GetTimeBasedWidget()->ToggleShowAll(); } void TimeBasedPanel::GoToIn() { GetTimeBasedWidget()->GoToIn(); } void TimeBasedPanel::GoToOut() { GetTimeBasedWidget()->GoToOut(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/timebased/timebased.h000066400000000000000000000051011370472574300223330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMEBASEDPANEL_H #define TIMEBASEDPANEL_H #include "widget/panel/panel.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER class TimeBasedPanel : public PanelWidget { Q_OBJECT public: TimeBasedPanel(const QString& object_name, QWidget *parent = nullptr); void ConnectViewerNode(ViewerOutput* node); void DisconnectViewerNode(); rational GetTime(); ViewerOutput* GetConnectedViewer() const; TimeRuler* ruler() const; virtual void ZoomIn() override; virtual void ZoomOut() override; virtual void GoToStart() override; virtual void PrevFrame() override; virtual void NextFrame() override; virtual void GoToEnd() override; virtual void GoToPrevCut() override; virtual void GoToNextCut() override; virtual void PlayPause() override; virtual void PlayInToOut() override; virtual void ShuttleLeft() override; virtual void ShuttleStop() override; virtual void ShuttleRight() override; virtual void SetIn() override; virtual void SetOut() override; virtual void ResetIn() override; virtual void ResetOut() override; virtual void ClearInOut() override; virtual void SetMarker() override; virtual void ToggleShowAll() override; virtual void GoToIn() override; virtual void GoToOut() override; public slots: void SetTimebase(const rational& timebase); virtual void SetTimestamp(const int64_t& timestamp); signals: void TimeChanged(const int64_t& time); void TimebaseChanged(const rational& timebase); void PlayPauseRequested(); void PlayInToOutRequested(); void ShuttleLeftRequested(); void ShuttleStopRequested(); void ShuttleRightRequested(); protected: TimeBasedWidget* GetTimeBasedWidget() const; void SetTimeBasedWidget(TimeBasedWidget* widget); virtual void Retranslate() override; private: TimeBasedWidget* widget_; }; OLIVE_NAMESPACE_EXIT #endif // TIMEBASEDPANEL_H olive-continuous/app/panel/timeline/000077500000000000000000000000001370472574300201015ustar00rootroot00000000000000olive-continuous/app/panel/timeline/CMakeLists.txt000066400000000000000000000014571370472574300226500ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/timeline/timeline.h panel/timeline/timeline.cpp PARENT_SCOPE ) olive-continuous/app/panel/timeline/timeline.cpp000066400000000000000000000110301370472574300224060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timeline.h" #include "panel/panelmanager.h" #include "panel/project/footagemanagementpanel.h" OLIVE_NAMESPACE_ENTER TimelinePanel::TimelinePanel(QWidget *parent) : TimeBasedPanel(QStringLiteral("TimelinePanel"), parent) { TimelineWidget* tw = new TimelineWidget(); SetTimeBasedWidget(tw); Retranslate(); connect(tw, &TimelineWidget::SelectionChanged, this, &TimelinePanel::SelectionChanged); } void TimelinePanel::Clear() { static_cast(GetTimeBasedWidget())->Clear(); } void TimelinePanel::SplitAtPlayhead() { static_cast(GetTimeBasedWidget())->SplitAtPlayhead(); } QByteArray TimelinePanel::SaveSplitterState() const { return static_cast(GetTimeBasedWidget())->SaveSplitterState(); } void TimelinePanel::RestoreSplitterState(const QByteArray &state) { static_cast(GetTimeBasedWidget())->RestoreSplitterState(state); } void TimelinePanel::SelectAll() { static_cast(GetTimeBasedWidget())->SelectAll(); } void TimelinePanel::DeselectAll() { static_cast(GetTimeBasedWidget())->DeselectAll(); } void TimelinePanel::RippleToIn() { static_cast(GetTimeBasedWidget())->RippleToIn(); } void TimelinePanel::RippleToOut() { static_cast(GetTimeBasedWidget())->RippleToOut(); } void TimelinePanel::EditToIn() { static_cast(GetTimeBasedWidget())->EditToIn(); } void TimelinePanel::EditToOut() { static_cast(GetTimeBasedWidget())->EditToOut(); } void TimelinePanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(false); } void TimelinePanel::RippleDelete() { static_cast(GetTimeBasedWidget())->DeleteSelected(true); } void TimelinePanel::IncreaseTrackHeight() { static_cast(GetTimeBasedWidget())->IncreaseTrackHeight(); } void TimelinePanel::DecreaseTrackHeight() { static_cast(GetTimeBasedWidget())->DecreaseTrackHeight(); } void TimelinePanel::Insert() { FootageManagementPanel* project_panel = PanelManager::instance()->MostRecentlyFocused(); if (project_panel) { InsertFootageAtPlayhead(project_panel->GetSelectedFootage()); } } void TimelinePanel::Overwrite() { FootageManagementPanel* project_panel = PanelManager::instance()->MostRecentlyFocused(); if (project_panel) { OverwriteFootageAtPlayhead(project_panel->GetSelectedFootage()); } } void TimelinePanel::ToggleLinks() { static_cast(GetTimeBasedWidget())->ToggleLinksOnSelected(); } void TimelinePanel::CutSelected() { static_cast(GetTimeBasedWidget())->CopySelected(true); } void TimelinePanel::CopySelected() { static_cast(GetTimeBasedWidget())->CopySelected(false); } void TimelinePanel::Paste() { static_cast(GetTimeBasedWidget())->Paste(false); } void TimelinePanel::PasteInsert() { static_cast(GetTimeBasedWidget())->Paste(true); } void TimelinePanel::DeleteInToOut() { static_cast(GetTimeBasedWidget())->DeleteInToOut(false); } void TimelinePanel::RippleDeleteInToOut() { static_cast(GetTimeBasedWidget())->DeleteInToOut(true); } void TimelinePanel::ToggleSelectedEnabled() { static_cast(GetTimeBasedWidget())->ToggleSelectedEnabled(); } void TimelinePanel::InsertFootageAtPlayhead(const QList &footage) { static_cast(GetTimeBasedWidget())->InsertFootageAtPlayhead(footage); } void TimelinePanel::OverwriteFootageAtPlayhead(const QList &footage) { static_cast(GetTimeBasedWidget())->OverwriteFootageAtPlayhead(footage); } void TimelinePanel::Retranslate() { TimeBasedPanel::Retranslate(); SetTitle(tr("Timeline")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/timeline/timeline.h000066400000000000000000000043771370472574300220730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINE_PANEL_H #define TIMELINE_PANEL_H #include "panel/timebased/timebased.h" #include "widget/timelinewidget/timelinewidget.h" OLIVE_NAMESPACE_ENTER /** * @brief Panel container for a TimelineWidget */ class TimelinePanel : public TimeBasedPanel { Q_OBJECT public: TimelinePanel(QWidget* parent); void Clear(); void SplitAtPlayhead(); QByteArray SaveSplitterState() const; void RestoreSplitterState(const QByteArray& state); virtual void SelectAll() override; virtual void DeselectAll() override; virtual void RippleToIn() override; virtual void RippleToOut() override; virtual void EditToIn() override; virtual void EditToOut() override; virtual void DeleteSelected() override; virtual void RippleDelete() override; virtual void IncreaseTrackHeight() override; virtual void DecreaseTrackHeight() override; virtual void Insert() override; virtual void Overwrite() override; virtual void ToggleLinks() override; virtual void CutSelected() override; virtual void CopySelected() override; virtual void Paste() override; virtual void PasteInsert() override; virtual void DeleteInToOut() override; virtual void RippleDeleteInToOut() override; virtual void ToggleSelectedEnabled() override; void InsertFootageAtPlayhead(const QList &footage); void OverwriteFootageAtPlayhead(const QList &footage); protected: virtual void Retranslate() override; signals: void SelectionChanged(const QList& selected_blocks); }; OLIVE_NAMESPACE_EXIT #endif // TIMELINE_PANEL_H olive-continuous/app/panel/tool/000077500000000000000000000000001370472574300172505ustar00rootroot00000000000000olive-continuous/app/panel/tool/CMakeLists.txt000066400000000000000000000014371370472574300220150ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/tool/tool.h panel/tool/tool.cpp PARENT_SCOPE ) olive-continuous/app/panel/tool/tool.cpp000066400000000000000000000031741370472574300207360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "tool.h" #include "core.h" #include "widget/toolbar/toolbar.h" OLIVE_NAMESPACE_ENTER ToolPanel::ToolPanel(QWidget *parent) : PanelWidget(QStringLiteral("ToolPanel"), parent) { Toolbar* t = new Toolbar(this); t->SetTool(Core::instance()->tool()); t->SetSnapping(Core::instance()->snapping()); SetWidgetWithPadding(t); connect(t, &Toolbar::ToolChanged, Core::instance(), &Core::SetTool); connect(Core::instance(), &Core::ToolChanged, t, &Toolbar::SetTool); connect(t, &Toolbar::SnappingChanged, Core::instance(), &Core::SetSnapping); connect(Core::instance(), &Core::SnappingChanged, t, &Toolbar::SetSnapping); connect(t, &Toolbar::AddableObjectChanged, Core::instance(), &Core::SetSelectedAddableObject); connect(t, &Toolbar::SelectedTransitionChanged, Core::instance(), &Core::SetSelectedTransitionObject); Retranslate(); } void ToolPanel::Retranslate() { SetTitle(tr("Tools")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/tool/tool.h000066400000000000000000000020371370472574300204000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TOOL_PANEL_H #define TOOL_PANEL_H #include "widget/panel/panel.h" OLIVE_NAMESPACE_ENTER /** * @brief A PanelWidget wrapper around a Toolbar */ class ToolPanel : public PanelWidget { Q_OBJECT public: ToolPanel(QWidget* parent); private: virtual void Retranslate() override; }; OLIVE_NAMESPACE_EXIT #endif // TOOL_PANEL_H olive-continuous/app/panel/viewer/000077500000000000000000000000001370472574300175745ustar00rootroot00000000000000olive-continuous/app/panel/viewer/CMakeLists.txt000066400000000000000000000015411370472574300223350ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} panel/viewer/viewer.h panel/viewer/viewer.cpp panel/viewer/viewerbase.h panel/viewer/viewerbase.cpp PARENT_SCOPE ) olive-continuous/app/panel/viewer/viewer.cpp000066400000000000000000000023101370472574300215750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewer.h" OLIVE_NAMESPACE_ENTER ViewerPanel::ViewerPanel(const QString &object_name, QWidget *parent) : ViewerPanelBase(object_name, parent) { // Set ViewerWidget as the central widget ViewerWidget* vw = new ViewerWidget(); connect(vw, &ViewerWidget::RequestScopePanel, this, &ViewerPanel::CreateScopePanel); SetTimeBasedWidget(vw); // Set strings Retranslate(); } void ViewerPanel::Retranslate() { ViewerPanelBase::Retranslate(); SetTitle(tr("Viewer")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/viewer/viewer.h000066400000000000000000000021401370472574300212430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWER_PANEL_H #define VIEWER_PANEL_H #include #include "viewerbase.h" OLIVE_NAMESPACE_ENTER /** * @brief Dockable wrapper around a ViewerWidget */ class ViewerPanel : public ViewerPanelBase { Q_OBJECT public: ViewerPanel(const QString& object_name, QWidget* parent); protected: virtual void Retranslate() override; }; OLIVE_NAMESPACE_EXIT #endif // VIEWER_PANEL_H olive-continuous/app/panel/viewer/viewerbase.cpp000066400000000000000000000073731370472574300224460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewerbase.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER ViewerPanelBase::ViewerPanelBase(const QString& object_name, QWidget *parent) : TimeBasedPanel(object_name, parent) { } void ViewerPanelBase::PlayPause() { static_cast(GetTimeBasedWidget())->TogglePlayPause(); } void ViewerPanelBase::PlayInToOut() { static_cast(GetTimeBasedWidget())->Play(true); } void ViewerPanelBase::ShuttleLeft() { static_cast(GetTimeBasedWidget())->ShuttleLeft(); } void ViewerPanelBase::ShuttleStop() { static_cast(GetTimeBasedWidget())->ShuttleStop(); } void ViewerPanelBase::ShuttleRight() { static_cast(GetTimeBasedWidget())->ShuttleRight(); } void ViewerPanelBase::ConnectTimeBasedPanel(TimeBasedPanel *panel) { connect(panel, &TimeBasedPanel::PlayPauseRequested, this, &ViewerPanelBase::PlayPause); connect(panel, &TimeBasedPanel::PlayInToOutRequested, this, &ViewerPanelBase::PlayInToOut); connect(panel, &TimeBasedPanel::ShuttleLeftRequested, this, &ViewerPanelBase::ShuttleLeft); connect(panel, &TimeBasedPanel::ShuttleStopRequested, this, &ViewerPanelBase::ShuttleStop); connect(panel, &TimeBasedPanel::ShuttleRightRequested, this, &ViewerPanelBase::ShuttleRight); } void ViewerPanelBase::DisconnectTimeBasedPanel(TimeBasedPanel *panel) { disconnect(panel, &TimeBasedPanel::PlayPauseRequested, this, &ViewerPanelBase::PlayPause); disconnect(panel, &TimeBasedPanel::PlayInToOutRequested, this, &ViewerPanelBase::PlayInToOut); disconnect(panel, &TimeBasedPanel::ShuttleLeftRequested, this, &ViewerPanelBase::ShuttleLeft); disconnect(panel, &TimeBasedPanel::ShuttleStopRequested, this, &ViewerPanelBase::ShuttleStop); disconnect(panel, &TimeBasedPanel::ShuttleRightRequested, this, &ViewerPanelBase::ShuttleRight); } void ViewerPanelBase::ConnectPixelSamplerPanel(PixelSamplerPanel *psp) { ViewerWidget* vw = static_cast(GetTimeBasedWidget()); connect(psp, &PixelSamplerPanel::visibilityChanged, vw, &ViewerWidget::SetSignalCursorColorEnabled); connect(vw, &ViewerWidget::CursorColor, psp, &PixelSamplerPanel::SetValues); } void ViewerPanelBase::SetFullScreen(QScreen *screen) { static_cast(GetTimeBasedWidget())->SetFullScreen(screen); } void ViewerPanelBase::SetGizmos(Node *node) { static_cast(GetTimeBasedWidget())->SetGizmos(node); } void ViewerPanelBase::CreateScopePanel(ScopePanel::Type type) { ViewerWidget* vw = static_cast(GetTimeBasedWidget()); ScopePanel* p = Core::instance()->main_window()->AppendScopePanel(); p->SetType(type); // Connect viewer widget texture drawing to scope panel connect(vw, &ViewerWidget::LoadedBuffer, p, &ScopePanel::SetReferenceBuffer); connect(vw, &ViewerWidget::ColorManagerChanged, p, &ScopePanel::SetColorManager); p->SetColorManager(vw->color_manager()); vw->ForceUpdate(); } void ViewerPanelBase::closeEvent(QCloseEvent *e) { static_cast(GetTimeBasedWidget())->Pause(); TimeBasedPanel::closeEvent(e); } OLIVE_NAMESPACE_EXIT olive-continuous/app/panel/viewer/viewerbase.h000066400000000000000000000033261370472574300221050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERPANELBASE_H #define VIEWERPANELBASE_H #include "panel/pixelsampler/pixelsamplerpanel.h" #include "panel/timebased/timebased.h" #include "widget/viewer/viewer.h" OLIVE_NAMESPACE_ENTER class ViewerPanelBase : public TimeBasedPanel { Q_OBJECT public: ViewerPanelBase(const QString& object_name, QWidget* parent = nullptr); virtual void PlayPause() override; virtual void PlayInToOut() override; virtual void ShuttleLeft() override; virtual void ShuttleStop() override; virtual void ShuttleRight() override; void ConnectTimeBasedPanel(TimeBasedPanel* panel); void DisconnectTimeBasedPanel(TimeBasedPanel* panel); void ConnectPixelSamplerPanel(PixelSamplerPanel *psp); /** * @brief Wrapper for ViewerWidget::SetFullScreen() */ void SetFullScreen(QScreen* screen = nullptr); public slots: void SetGizmos(Node* node); protected: void CreateScopePanel(ScopePanel::Type type); virtual void closeEvent(QCloseEvent* e) override; }; OLIVE_NAMESPACE_EXIT #endif // VIEWERPANELBASE_H olive-continuous/app/project/000077500000000000000000000000001370472574300166425ustar00rootroot00000000000000olive-continuous/app/project/CMakeLists.txt000066400000000000000000000015631370472574300214070ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(item) set(OLIVE_SOURCES ${OLIVE_SOURCES} project/project.h project/project.cpp project/projectviewmodel.h project/projectviewmodel.cpp PARENT_SCOPE ) olive-continuous/app/project/item/000077500000000000000000000000001370472574300176005ustar00rootroot00000000000000olive-continuous/app/project/item/CMakeLists.txt000066400000000000000000000015621370472574300223440ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(folder) add_subdirectory(footage) add_subdirectory(sequence) set(OLIVE_SOURCES ${OLIVE_SOURCES} project/item/item.h project/item/item.cpp PARENT_SCOPE ) olive-continuous/app/project/item/folder/000077500000000000000000000000001370472574300210535ustar00rootroot00000000000000olive-continuous/app/project/item/folder/CMakeLists.txt000066400000000000000000000014661370472574300236220ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} project/item/folder/folder.h project/item/folder/folder.cpp PARENT_SCOPE ) olive-continuous/app/project/item/folder/folder.cpp000066400000000000000000000046401370472574300230360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "folder.h" #include "common/xmlutils.h" #include "project/item/footage/footage.h" #include "project/item/sequence/sequence.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER Item::Type Folder::type() const { return kFolder; } bool Folder::CanHaveChildren() const { return true; } QIcon Folder::icon() { return icon::Folder; } void Folder::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { return; } if (attr.name() == QStringLiteral("name")) { set_name(attr.value().toString()); } else if (attr.name() == QStringLiteral("ptr")) { xml_node_data.item_ptrs.insert(attr.value().toULongLong(), this); } } while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } ItemPtr child; if (reader->name() == QStringLiteral("folder")) { child = std::make_shared(); } else if (reader->name() == QStringLiteral("footage")) { child = std::make_shared(); } else if (reader->name() == QStringLiteral("sequence")) { child = std::make_shared(); } else { reader->skipCurrentElement(); continue; } add_child(child); child->Load(reader, xml_node_data, cancelled); } } void Folder::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("folder")); writer->writeAttribute(QStringLiteral("name"), name()); writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(this))); foreach (ItemPtr child, children()) { child->Save(writer); } writer->writeEndElement(); // folder } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/folder/folder.h000066400000000000000000000030441370472574300225000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOLDER_H #define FOLDER_H #include "node/param.h" #include "project/item/footage/footage.h" #include "project/item/item.h" OLIVE_NAMESPACE_ENTER /** * @brief The Folder class representing a directory in a project structure * * The Item base class already has support for children, but this functionality is disabled by default * (see CanHaveChildren() override). The Folder is a specific type that enables this functionality. */ class Folder : public Item { public: Folder() = default; virtual Type type() const override; virtual bool CanHaveChildren() const override; virtual QIcon icon() override; virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) override; virtual void Save(QXmlStreamWriter* writer) const override; private: }; OLIVE_NAMESPACE_EXIT #endif // FOLDER_H olive-continuous/app/project/item/footage/000077500000000000000000000000001370472574300212245ustar00rootroot00000000000000olive-continuous/app/project/item/footage/CMakeLists.txt000066400000000000000000000021401370472574300237610ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} project/item/footage/audiostream.h project/item/footage/audiostream.cpp project/item/footage/footage.h project/item/footage/footage.cpp project/item/footage/imagestream.h project/item/footage/imagestream.cpp project/item/footage/stream.h project/item/footage/stream.cpp project/item/footage/videostream.h project/item/footage/videostream.cpp PARENT_SCOPE ) olive-continuous/app/project/item/footage/audiostream.cpp000066400000000000000000000045021370472574300242460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiostream.h" OLIVE_NAMESPACE_ENTER AudioStream::AudioStream() { set_type(kAudio); } QString AudioStream::description() const { return QCoreApplication::translate("Stream", "%1: Audio - %2 Channels, %3Hz").arg(QString::number(index()), QString::number(channels()), QString::number(sample_rate())); } const int &AudioStream::channels() const { return channels_; } void AudioStream::set_channels(const int &channels) { channels_ = channels; } const uint64_t &AudioStream::channel_layout() const { return layout_; } void AudioStream::set_channel_layout(const uint64_t &layout) { layout_ = layout; } const int &AudioStream::sample_rate() const { return sample_rate_; } void AudioStream::set_sample_rate(const int &sample_rate) { sample_rate_ = sample_rate; } bool AudioStream::try_start_conforming(const AudioParams ¶ms) { QMutexLocker locker(proxy_access_lock()); if (!currently_conforming_.contains(params) && !conformed_.contains(params)) { currently_conforming_.append(params); return true; } return false; } bool AudioStream::has_conformed_version(const AudioParams ¶ms) { QMutexLocker locker(proxy_access_lock()); return conformed_.contains(params); } void AudioStream::append_conformed_version(const AudioParams ¶ms) { { QMutexLocker locker(proxy_access_lock()); currently_conforming_.removeOne(params); conformed_.append(params); } emit ConformAppended(params); } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/footage/audiostream.h000066400000000000000000000034521370472574300237160ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOSTREAM_H #define AUDIOSTREAM_H #include #include "common/rational.h" #include "render/audioparams.h" #include "stream.h" OLIVE_NAMESPACE_ENTER /** * @brief A Stream derivative containing audio-specific information */ class AudioStream : public Stream { Q_OBJECT public: AudioStream(); virtual QString description() const override; const int& channels() const; void set_channels(const int& channels); const uint64_t& channel_layout() const; void set_channel_layout(const uint64_t& channel_layout); const int& sample_rate() const; void set_sample_rate(const int& sample_rate); bool try_start_conforming(const AudioParams& params); bool has_conformed_version(const AudioParams& params); void append_conformed_version(const AudioParams& params); signals: void ConformAppended(OLIVE_NAMESPACE::AudioParams params); private: int channels_; uint64_t layout_; int sample_rate_; QList conformed_; QList currently_conforming_; }; using AudioStreamPtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // AUDIOSTREAM_H olive-continuous/app/project/item/footage/footage.cpp000066400000000000000000000242301370472574300233550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "footage.h" #include #include #include "codec/decoder.h" #include "common/xmlutils.h" #include "config/config.h" #include "core.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER Footage::Footage() { Clear(); } Footage::~Footage() { ClearStreams(); } void Footage::Load(QXmlStreamReader *reader, XMLNodeData &xml_node_data, const QAtomicInt* cancelled) { QXmlStreamAttributes attributes = reader->attributes(); foreach (const QXmlStreamAttribute& attr, attributes) { if (attr.name() == QStringLiteral("name")) { set_name(attr.value().toString()); } else if (attr.name() == QStringLiteral("filename")) { set_filename(attr.value().toString()); } } // Validate filename if (!QFileInfo::exists(filename_)) { // Absolute filename does not exist, use some heuristics to try relocating the file if (xml_node_data.real_project_url != xml_node_data.saved_project_url) { // Project path has changed, check if the file we're looking for is the same relative to the // new project path QDir saved_dir(QFileInfo(xml_node_data.saved_project_url).dir()); QDir true_dir(QFileInfo(xml_node_data.real_project_url).dir()); QString relative_filename = saved_dir.relativeFilePath(filename_); QString transformed_abs_filename = true_dir.filePath(relative_filename); if (QFileInfo::exists(transformed_abs_filename)) { // Use this file instead qInfo() << "Footage" << filename_ << "doesn't exist, using relative file" << transformed_abs_filename; set_filename(transformed_abs_filename); } } } Decoder::ProbeMedia(this, cancelled); while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("stream")) { int stream_index = -1; quintptr stream_ptr = 0; XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { return; } if (attr.name() == QStringLiteral("index")) { stream_index = attr.value().toInt(); } else if (attr.name() == QStringLiteral("ptr")) { stream_ptr = attr.value().toULongLong(); } } if (stream_index > -1 && stream_ptr > 0) { xml_node_data.footage_ptrs.insert(stream_ptr, stream(stream_index)); stream(stream_index)->Load(reader); } else { qWarning() << "Invalid stream found in project file"; } } else if (reader->name() == QStringLiteral("points")) { TimelinePoints::Load(reader); } else { reader->skipCurrentElement(); } } } void Footage::Save(QXmlStreamWriter *writer) const { writer->writeStartElement("footage"); writer->writeAttribute("name", name()); writer->writeAttribute("filename", filename()); TimelinePoints::Save(writer); foreach (StreamPtr stream, streams_) { stream->Save(writer); } writer->writeEndElement(); // footage } const Footage::Status& Footage::status() const { return status_; } void Footage::set_status(const Footage::Status &status) { status_ = status; UpdateTooltip(); } void Footage::Clear() { // Clear all streams ClearStreams(); // Reset ready state set_status(kUnprobed); } const QString &Footage::filename() const { return filename_; } void Footage::set_filename(const QString &s) { filename_ = s; } const QDateTime &Footage::timestamp() const { return timestamp_; } void Footage::set_timestamp(const QDateTime &t) { timestamp_ = t; } void Footage::add_stream(StreamPtr s) { // Set its footage parent to this s->set_footage(this); // Add a copy of this stream to the list streams_.append(s); } StreamPtr Footage::stream(int index) const { return streams_.at(index); } const QList &Footage::streams() const { return streams_; } int Footage::stream_count() const { return streams_.size(); } Item::Type Footage::type() const { return kFootage; } const QString &Footage::decoder() const { return decoder_; } void Footage::set_decoder(const QString &id) { decoder_ = id; } QIcon Footage::icon() { switch (status_) { case kUnprobed: case kUnindexed: // FIXME Set a waiting icon return QIcon(); case kReady: if (HasStreamsOfType(Stream::kVideo)) { // Prioritize the video icon return icon::Video; } else if (HasStreamsOfType(Stream::kAudio)) { // Otherwise assume it's audio only return icon::Audio; } else if (HasStreamsOfType(Stream::kImage)) { // Otherwise assume it's an image return icon::Image; } /* fall-through */ case kInvalid: return icon::Error; } return QIcon(); } QString Footage::duration() { if (streams_.isEmpty()) { return QString(); } if (streams_.first()->type() == Stream::kVideo) { VideoStreamPtr video_stream = std::static_pointer_cast(streams_.first()); int64_t duration = video_stream->duration(); rational frame_rate_timebase = video_stream->frame_rate().flipped(); if (video_stream->timebase() != frame_rate_timebase) { // Convert from timebase to frame rate rational duration_time = Timecode::timestamp_to_time(duration, video_stream->timebase()); duration = Timecode::time_to_timestamp(duration_time, frame_rate_timebase); } return Timecode::timestamp_to_timecode(duration, frame_rate_timebase, Core::instance()->GetTimecodeDisplay()); } else if (streams_.first()->type() == Stream::kAudio) { AudioStreamPtr audio_stream = std::static_pointer_cast(streams_.first()); // If we're showing in a timecode, we prefer showing audio in seconds instead Timecode::Display display = Core::instance()->GetTimecodeDisplay(); if (display == Timecode::kTimecodeDropFrame || display == Timecode::kTimecodeNonDropFrame) { display = Timecode::kTimecodeSeconds; } return Timecode::timestamp_to_timecode(streams_.first()->duration(), streams_.first()->timebase(), display); } return QString(); } QString Footage::rate() { if (streams_.isEmpty()) { return QString(); } if (streams_.first()->type() == Stream::kVideo) { // Return the timebase as a frame rate VideoStreamPtr video_stream = std::static_pointer_cast(streams_.first()); return QCoreApplication::translate("Footage", "%1 FPS").arg(video_stream->frame_rate().toDouble()); } else if (streams_.first()->type() == Stream::kAudio) { // Return the sample rate AudioStreamPtr audio_stream = std::static_pointer_cast(streams_.first()); return QCoreApplication::translate("Footage", "%1 Hz").arg(audio_stream->sample_rate()); } return QString(); } quint64 Footage::get_enabled_stream_flags() const { quint64 enabled_streams = 0; quint64 stream_enabler = 1; foreach (StreamPtr s, streams_) { if (s->enabled()) { enabled_streams |= stream_enabler; } stream_enabler <<= 1; } return enabled_streams; } void Footage::ClearStreams() { if (streams_.empty()) { return; } // Delete all streams streams_.clear(); } bool Footage::HasStreamsOfType(const Stream::Type &type) const { // Return true if any streams are video streams foreach (StreamPtr stream, streams_) { if (stream->type() == type) { return true; } } return false; } StreamPtr Footage::get_first_stream_of_type(const Stream::Type &type) const { foreach (StreamPtr stream, streams_) { if (stream->type() == type) { return stream; } } return nullptr; } void Footage::UpdateTooltip() { switch (status_) { case kUnprobed: set_tooltip(QCoreApplication::translate("Footage", "Waiting for probe")); break; case kUnindexed: set_tooltip(QCoreApplication::translate("Footage", "Waiting for index")); break; case kReady: { QString tip = QCoreApplication::translate("Footage", "Filename: %1").arg(filename()); if (!streams_.isEmpty()) { tip.append("\n"); for (int i=0;itype()) { case Stream::kVideo: case Stream::kImage: { ImageStreamPtr vs = std::static_pointer_cast(s); tip.append( QCoreApplication::translate("Footage", "\nVideo %1: %2x%3").arg(QString::number(i), QString::number(vs->width()), QString::number(vs->height())) ); break; } case Stream::kAudio: { AudioStreamPtr as = std::static_pointer_cast(s); tip.append( QCoreApplication::translate("Footage", "\nAudio %1: %2 channels %3 Hz").arg(QString::number(i), QString::number(as->channels()), QString::number(as->sample_rate())) ); break; } default: break; } } } set_tooltip(tip); } break; case kInvalid: set_tooltip(QCoreApplication::translate("Footage", "An error occurred probing this footage")); break; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/footage/footage.h000066400000000000000000000160151370472574300230240ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOOTAGE_H #define FOOTAGE_H #include #include #include "common/rational.h" #include "project/item/item.h" #include "project/item/footage/audiostream.h" #include "project/item/footage/imagestream.h" #include "project/item/footage/videostream.h" #include "timeline/timelinepoints.h" OLIVE_NAMESPACE_ENTER /** * @brief A reference to an external media file with metadata in a project structure * * Footage objects serve two purposes: storing metadata about external media and storing it as a project item. * Footage objects store a list of Stream objects which store the majority of video/audio metadata. These streams * are identical to the stream data in the files. */ class Footage : public Item, public TimelinePoints { public: enum Status { kUnprobed, kUnindexed, kReady, kInvalid }; /** * @brief Footage Constructor */ Footage(); /** * @brief Footage Destructor * * Makes sure Stream objects are cleared properly */ virtual ~Footage() override; /** * @brief Load function */ virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) override; /** * @brief Save function */ virtual void Save(QXmlStreamWriter *writer) const override; /** * @brief Check the ready state of this Footage object * * @return * * If the Footage has been successfully probed, this will return TRUE. */ const Status& status() const; /** * @brief Set ready state * * This should only be set by olive::ProbeMedia. Sets the Footage's current status to a member of enum * Footage::Status. * * This function also runs UpdateIcon() and UpdateTooltip(). If you need to override the tooltip (e.g. for an error * message), you must run set_tooltip() *after* running set_status(); */ void set_status(const Status& status); /** * @brief Reset Footage state ready for running through Probe() again * * If a Footage object needs to be re-probed (e.g. source file changes or Footage is linked to a new file), its * state needs to be reset so the Decoder::Probe() function can accurately mirror the source file. Clear() will * reset the Footage object's state to being freshly created (keeping the filename). * * In most cases, you'll be using olive::ProbeMedia() for re-probing which already runs Clear(), so you won't need * to worry about this. */ void Clear(); /** * @brief Return the current filename of this Footage object */ const QString& filename() const; /** * @brief Set the filename * * NOTE: This does not automtaically clear the old streams and re-probe for new ones. If the file link has been * changed, this will need to be done manually. * * @param s * * New filename */ void set_filename(const QString& s); /** * @brief Retrieve the last modified time/date * * The file's last modified timestamp is stored for potential organization in the ProjectExplorer. It can be * retrieved here. */ const QDateTime& timestamp() const; /** * @brief Set the last modified time/date * * This should probably only be done on import or replace. * * @param t * * New last modified time/date */ void set_timestamp(const QDateTime& t); /** * @brief Add a stream metadata object to this footage * * Usually done during a Decoder::Probe() function for retrieving metadata about the video/audio/other streams * inside a container. Streams can have non-video/audio types so that they can be equivalent to the file's actual * stream list, though the only streams officially supported are video and audio streams. * * @param s * * A pointer to a stream object. The Footage takes ownership of this object and will free it when it's deleted. */ void add_stream(StreamPtr s); /** * @brief Retrieve a stream at the given index. * * @param index * * The index will be equivalent to the stream's index in the file (or in FFmpeg * terms AVStream->file_index). Must be < stream_count(). * * @return * * The stream at the index provided */ StreamPtr stream(int index) const; /** * @brief Returns a list of the streams in this Footage */ const QList& streams() const; /** * @brief Retrieve total number of streams in this Footage file */ int stream_count() const; /** * @brief Item::Type() override * * @return kFootage */ virtual Type type() const override; /** * @brief Get the Decoder ID set when this Footage was probed * * @return * * A decoder ID */ const QString& decoder() const; /** * @brief Used by decoders when they Probe to attach itself to this Footage */ void set_decoder(const QString& id); virtual QIcon icon() override; virtual QString duration() override; virtual QString rate() override; quint64 get_enabled_stream_flags() const; /** * @brief Check if this footage has streams of a certain type * * @param type * * The stream type to check for */ bool HasStreamsOfType(const Stream::Type& type) const; StreamPtr get_first_stream_of_type(const Stream::Type& type) const; private: /** * @brief Internal function to delete all Stream children and empty the array */ void ClearStreams(); /** * @brief Update the icon based on the Footage status * * For kUnprobed and kError an appropriate icon will be shown. For kReady, this function will determine what the * dominant type of media in this Footage is (video/audio/image) and set the icon accordingly based on that. */ void UpdateIcon(); /** * @brief Update the tooltip based on the Footage status * * For kUnprobed and kError, this sets an appropriate generic message. For kReady, this function will set * basic information about the Footage in the tooltip (based on the results of a previous probe). */ void UpdateTooltip(); /** * @brief Internal filename string */ QString filename_; /** * @brief Internal timestamp object */ QDateTime timestamp_; /** * @brief Internal streams array */ QList streams_; /** * @brief Internal ready setting */ Status status_; /** * @brief Internal attached decoder ID */ QString decoder_; }; using FootagePtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // FOOTAGE_H olive-continuous/app/project/item/footage/imagestream.cpp000066400000000000000000000072251370472574300242340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "imagestream.h" #include "common/xmlutils.h" #include "footage.h" #include "project/project.h" #include "render/colormanager.h" OLIVE_NAMESPACE_ENTER ImageStream::ImageStream() : premultiplied_alpha_(false), interlacing_(kInterlaceNone) { set_type(kImage); } void ImageStream::FootageSetEvent(Footage *f) { // For some reason this connection fails if we don't explicitly specify DirectConnection connect(f->project()->color_manager(), &ColorManager::ConfigChanged, this, &ImageStream::ColorConfigChanged, Qt::DirectConnection); connect(f->project()->color_manager(), &ColorManager::DefaultInputColorSpaceChanged, this, &ImageStream::DefaultColorSpaceChanged, Qt::DirectConnection); } void ImageStream::LoadCustomParameters(QXmlStreamReader *reader) { while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("colorspace")) { set_colorspace(reader->readElementText()); } else { reader->skipCurrentElement(); } } } void ImageStream::SaveCustomParameters(QXmlStreamWriter *writer) const { writer->writeTextElement("colorspace", colorspace_); } QString ImageStream::description() const { return QCoreApplication::translate("Stream", "%1: Image - %2x%3").arg(QString::number(index()), QString::number(width()), QString::number(height())); } bool ImageStream::premultiplied_alpha() const { return premultiplied_alpha_; } void ImageStream::set_premultiplied_alpha(bool e) { premultiplied_alpha_ = e; emit ParametersChanged(); } const QString &ImageStream::colorspace(bool default_if_empty) const { if (colorspace_.isEmpty() && default_if_empty) { return footage()->project()->color_manager()->GetDefaultInputColorSpace(); } else { return colorspace_; } } void ImageStream::set_colorspace(const QString &color) { colorspace_ = color; emit ParametersChanged(); } QString ImageStream::get_colorspace_match_string() const { return QStringLiteral("%1:%2").arg(footage()->project()->color_manager()->GetConfigFilename(), colorspace()); } void ImageStream::ColorConfigChanged() { ColorManager* color_manager = footage()->project()->color_manager(); // Check if this colorspace is in the new config if (!colorspace_.isEmpty()) { QStringList colorspaces = color_manager->ListAvailableColorspaces(); if (!colorspaces.contains(colorspace_)) { // Set to empty if not colorspace_.clear(); } } // Either way, the color calculation has likely changed so we signal here emit ParametersChanged(); } void ImageStream::DefaultColorSpaceChanged() { // If no colorspace is set, this stream uses the default color space and it's just changed if (colorspace_.isEmpty()) { emit ParametersChanged(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/footage/imagestream.h000066400000000000000000000046661370472574300237070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef IMAGESTREAM_H #define IMAGESTREAM_H #include "render/pixelformat.h" #include "stream.h" OLIVE_NAMESPACE_ENTER /** * @brief A Stream derivative containing video-specific information */ class ImageStream : public Stream { Q_OBJECT public: ImageStream(); virtual QString description() const override; const int& width() const { return width_; } void set_width(const int& width) { width_ = width; } const int& height() const { return height_; } void set_height(const int& height) { height_ = height; } const PixelFormat::Format& format() const { return format_; } void set_format(const PixelFormat::Format& format) { format_ = format; } bool premultiplied_alpha() const; void set_premultiplied_alpha(bool e); const QString& colorspace(bool default_if_empty = true) const; void set_colorspace(const QString& color); QString get_colorspace_match_string() const; enum Interlacing { kInterlaceNone, kInterlacedTopFirst, kInterlacedBottomFirst }; Interlacing interlacing() const { return interlacing_; } void set_interlacing(Interlacing i) { interlacing_ = i; emit ParametersChanged(); } protected: virtual void FootageSetEvent(Footage*) override; virtual void LoadCustomParameters(QXmlStreamReader *reader) override; virtual void SaveCustomParameters(QXmlStreamWriter* writer) const override; private: int width_; int height_; bool premultiplied_alpha_; QString colorspace_; Interlacing interlacing_; PixelFormat::Format format_; private slots: void ColorConfigChanged(); void DefaultColorSpaceChanged(); }; using ImageStreamPtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // IMAGESTREAM_H olive-continuous/app/project/item/footage/stream.cpp000066400000000000000000000053631370472574300232320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "stream.h" #include "footage.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER Stream::Stream() : footage_(nullptr), type_(kUnknown), enabled_(true) { } Stream::~Stream() { } void Stream::Load(QXmlStreamReader *reader) { LoadCustomParameters(reader); } void Stream::Save(QXmlStreamWriter *writer) const { writer->writeStartElement("stream"); writer->writeAttribute("ptr", QString::number(reinterpret_cast(this))); writer->writeAttribute("index", QString::number(index_)); SaveCustomParameters(writer); writer->writeEndElement(); // stream } QString Stream::description() const { return QCoreApplication::translate("Stream", "%1: Unknown").arg(index()); } const Stream::Type &Stream::type() const { return type_; } void Stream::set_type(const Stream::Type &type) { type_ = type; } Footage *Stream::footage() const { return footage_; } void Stream::set_footage(Footage *f) { footage_ = f; FootageSetEvent(footage_); } const rational &Stream::timebase() const { return timebase_; } void Stream::set_timebase(const rational &timebase) { timebase_ = timebase; } const int &Stream::index() const { return index_; } void Stream::set_index(const int &index) { index_ = index; } const int64_t &Stream::duration() const { return duration_; } void Stream::set_duration(const int64_t &duration) { duration_ = duration; emit ParametersChanged(); } bool Stream::enabled() const { return enabled_; } void Stream::set_enabled(bool e) { enabled_ = e; } QIcon Stream::IconFromType(const Stream::Type &type) { switch (type) { case Stream::kVideo: return icon::Video; case Stream::kImage: return icon::Image; case Stream::kAudio: return icon::Audio; default: break; } return QIcon(); } QMutex *Stream::proxy_access_lock() { return &proxy_access_lock_; } void Stream::FootageSetEvent(Footage*) { } void Stream::LoadCustomParameters(QXmlStreamReader* reader) { reader->skipCurrentElement(); } void Stream::SaveCustomParameters(QXmlStreamWriter*) const { } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/footage/stream.h000066400000000000000000000053151370472574300226740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef STREAM_H #define STREAM_H #include #include #include #include #include #include "common/rational.h" OLIVE_NAMESPACE_ENTER class Footage; /** * @brief A base class for keeping metadata about a media stream. * * A Stream can contain video data, audio data, subtitle data, * etc. and a Stream object stores metadata about it. * * The Stream class is fairly simple and is intended to be subclassed for data that pertains specifically to one * Stream::Type. \see VideoStream and \see AudioStream. */ class Stream : public QObject { Q_OBJECT public: enum Type { kUnknown, kVideo, kAudio, kData, kSubtitle, kAttachment, kImage = 100 }; /** * @brief Stream constructor */ Stream(); /** * @brief Required virtual destructor, serves no purpose */ virtual ~Stream(); void Load(QXmlStreamReader* reader); void Save(QXmlStreamWriter *writer) const; virtual QString description() const; const Type& type() const; void set_type(const Type& type); Footage* footage() const; void set_footage(Footage* f); const rational& timebase() const; void set_timebase(const rational& timebase); const int& index() const; void set_index(const int& index); const int64_t& duration() const; void set_duration(const int64_t& duration); bool enabled() const; void set_enabled(bool e); static QIcon IconFromType(const Type& type); QMutex* proxy_access_lock(); protected: virtual void FootageSetEvent(Footage*); virtual void LoadCustomParameters(QXmlStreamReader *reader); virtual void SaveCustomParameters(QXmlStreamWriter* writer) const; signals: void ParametersChanged(); private: Footage* footage_; rational timebase_; int64_t duration_; int index_; Type type_; bool enabled_; QMutex proxy_access_lock_; }; using StreamPtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #include Q_DECLARE_METATYPE(OLIVE_NAMESPACE::StreamPtr) #endif // STREAM_H olive-continuous/app/project/item/footage/videostream.cpp000066400000000000000000000105511370472574300242540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "videostream.h" #include #include "common/timecodefunctions.h" OLIVE_NAMESPACE_ENTER VideoStream::VideoStream() : start_time_(0), is_image_sequence_(false) { set_type(kVideo); } QString VideoStream::description() const { return QCoreApplication::translate("Stream", "%1: Video - %2x%3").arg(QString::number(index()), QString::number(width()), QString::number(height())); } const rational &VideoStream::frame_rate() const { return frame_rate_; } void VideoStream::set_frame_rate(const rational &frame_rate) { frame_rate_ = frame_rate; } const int64_t &VideoStream::start_time() const { return start_time_; } void VideoStream::set_start_time(const int64_t &start_time) { start_time_ = start_time; emit ParametersChanged(); } bool VideoStream::is_image_sequence() const { return is_image_sequence_; } void VideoStream::set_image_sequence(bool e) { is_image_sequence_ = e; } /* int64_t VideoStream::get_closest_timestamp_in_frame_index(const rational &time) { // Get rough approximation of what the timestamp would be in this timebase int64_t target_ts = Timecode::time_to_timestamp(time, timebase()); // Find closest actual timebase in the file return get_closest_timestamp_in_frame_index(target_ts); } int64_t VideoStream::get_closest_timestamp_in_frame_index(int64_t timestamp) { QMutexLocker locker(proxy_access_lock()); if (!frame_index_.isEmpty()) { if (timestamp <= frame_index_.first()) { return frame_index_.first(); } else if (timestamp >= frame_index_.last()) { return frame_index_.last(); } else { // Use index to find closest frame in file for (int i=1;i timestamp) { return frame_index_.at(i - 1); } } } } return -1; } */ /* void VideoStream::clear_frame_index() { { QMutexLocker locker(&index_access_lock_); frame_index_.clear(); } emit IndexChanged(); } void VideoStream::append_frame_index(const int64_t &ts) { { QMutexLocker locker(&index_access_lock_); frame_index_.append(ts); } emit IndexChanged(); } bool VideoStream::is_frame_index_ready() { QMutexLocker locker(&index_access_lock_); return !frame_index_.isEmpty() && frame_index_.last() == VideoStream::kEndTimestamp; } int64_t VideoStream::last_frame_index_timestamp() { QMutexLocker locker(&index_access_lock_); return frame_index_.last(); } bool VideoStream::load_frame_index(const QString &s) { // Load index from file QFile index_file(s); if (index_file.exists() && index_file.open(QFile::ReadOnly)) { { QMutexLocker locker(&index_access_lock_); // Resize based on filesize frame_index_.resize(static_cast(index_file.size()) / sizeof(int64_t)); // Read frame index into vector index_file.read(reinterpret_cast(frame_index_.data()), index_file.size()); } index_file.close(); emit IndexChanged(); return true; } return false; } bool VideoStream::save_frame_index(const QString &s) { QFile index_file(s); if (index_file.open(QFile::WriteOnly)) { // Write index in binary QMutexLocker locker(&index_access_lock_); index_file.write(reinterpret_cast(frame_index_.constData()), frame_index_.size() * static_cast(sizeof(int64_t))); index_file.close(); return true; } return false; } */ OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/footage/videostream.h000066400000000000000000000036001370472574300237160ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIDEOSTREAM_H #define VIDEOSTREAM_H #include "imagestream.h" OLIVE_NAMESPACE_ENTER class VideoStream : public ImageStream { Q_OBJECT public: VideoStream(); virtual QString description() const override; /** * @brief Get this video stream's frame rate * * Used purely for metadata, rendering uses the timebase instead. */ const rational& frame_rate() const; void set_frame_rate(const rational& frame_rate); const int64_t& start_time() const; void set_start_time(const int64_t& start_time); bool is_image_sequence() const; void set_image_sequence(bool e); /* int64_t get_closest_timestamp_in_frame_index(const rational& time); int64_t get_closest_timestamp_in_frame_index(int64_t timestamp); void clear_frame_index(); void append_frame_index(const int64_t& ts); bool is_frame_index_ready(); int64_t last_frame_index_timestamp(); bool load_frame_index(const QString& s); bool save_frame_index(const QString& s); */ private: rational frame_rate_; //QVector frame_index_; int64_t start_time_; bool is_image_sequence_; }; using VideoStreamPtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // VIDEOSTREAM_H olive-continuous/app/project/item/item.cpp000066400000000000000000000070271370472574300212500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "item.h" OLIVE_NAMESPACE_ENTER Item::Item() : parent_(nullptr), project_(nullptr) { } Item::~Item() { } void Item::add_child(ItemPtr c) { if (c->parent_ == this) { return; } if (c->parent_ != nullptr) { c->parent_->remove_child(c.get()); } children_.append(c); c->parent_ = this; } void Item::remove_child(Item *c) { if (c->parent_ != this) { return; } // Remove all instances of this child in the list for (int i=0;iparent_ = nullptr; } int Item::child_count() const { return children_.size(); } Item *Item::child(int i) const { return children_.at(i).get(); } const QList &Item::children() const { return children_; } ItemPtr Item::get_shared_ptr() const { QList siblings = parent()->children(); foreach (ItemPtr s, siblings) { if (s.get() == this) { return s; } } return nullptr; } const QString &Item::name() const { return name_; } void Item::set_name(const QString &n) { name_ = n; NameChangedEvent(n); } const QString &Item::tooltip() const { return tooltip_; } void Item::set_tooltip(const QString &t) { tooltip_ = t; } QString Item::duration() { return QString(); } QString Item::rate() { return QString(); } Item *Item::parent() const { return parent_; } const Item *Item::root() const { const Item* item = this; while (item->parent()) { item = item->parent(); } return item; } Project *Item::project() const { const Item* root_item = root(); return root_item->project_; } void Item::set_project(Project *project) { project_ = project; } QList Item::get_children_of_type(Type type, bool recursive) const { QList list; foreach (ItemPtr item, children_) { if (item->type() == type) { list.append(item); } if (recursive && item->CanHaveChildren()) { list.append(item->get_children_of_type(type, recursive)); } } return list; } bool Item::CanHaveChildren() const { return false; } bool Item::ChildExistsWithName(const QString &name) { return ChildExistsWithNameInternal(name, this); } void Item::NameChangedEvent(const QString &) { } bool Item::ChildExistsWithNameInternal(const QString &name, Item *folder) { // Loop through all children for (int i=0;ichild_count();i++) { Item* child = folder->child(i); // If this child has the same name, return true if (child->name() == name) { return true; } else if (child->CanHaveChildren()) { // If the child has children, run function recursively on this item if (ChildExistsWithNameInternal(name, child)) { // If it returns true, we've found a child so we can return now return true; } } } return false; } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/item.h000066400000000000000000000053471370472574300207200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef ITEM_H #define ITEM_H #include #include #include #include #include #include #include "common/threadedobject.h" #include "common/xmlutils.h" #include "node/param.h" #include "project/item/footage/stream.h" OLIVE_NAMESPACE_ENTER class Project; class Item; using ItemPtr = std::shared_ptr; /** * @brief A base-class representing any element in a Project * * Project objects implement a parent-child hierarchy of Items that can be used throughout the Project. The Item class * itself is abstract and will need to be subclassed to be used in a Project. */ class Item { public: enum Type { kFolder, kFootage, kSequence }; /** * @brief Item constructor */ Item(); /** * @brief Required virtual Item destructor */ virtual ~Item(); DISABLE_COPY_MOVE(Item) virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt *cancelled) = 0; virtual void Save(QXmlStreamWriter* writer) const = 0; virtual Type type() const = 0; void add_child(ItemPtr c); void remove_child(Item* c); int child_count() const; Item* child(int i) const; const QList& children() const; ItemPtr get_shared_ptr() const; const QString& name() const; void set_name(const QString& n); const QString& tooltip() const; void set_tooltip(const QString& t); virtual QIcon icon() = 0; virtual QString duration(); virtual QString rate(); Item *parent() const; const Item* root() const; Project* project() const; void set_project(Project* project); QList get_children_of_type(Type type, bool recursive) const; virtual bool CanHaveChildren() const; bool ChildExistsWithName(const QString& name); protected: virtual void NameChangedEvent(const QString& name); private: bool ChildExistsWithNameInternal(const QString& name, Item* folder); QList children_; Item* parent_; Project* project_; QString name_; QString tooltip_; }; OLIVE_NAMESPACE_EXIT #endif // ITEM_H olive-continuous/app/project/item/sequence/000077500000000000000000000000001370472574300214105ustar00rootroot00000000000000olive-continuous/app/project/item/sequence/CMakeLists.txt000066400000000000000000000014761370472574300241600ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} project/item/sequence/sequence.h project/item/sequence/sequence.cpp PARENT_SCOPE ) olive-continuous/app/project/item/sequence/sequence.cpp000066400000000000000000000251031370472574300237250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sequence.h" #include #include "config/config.h" #include "common/channellayout.h" #include "common/timecodefunctions.h" #include "common/xmlutils.h" #include "node/factory.h" #include "panel/panelmanager.h" #include "panel/node/node.h" #include "panel/curve/curve.h" #include "panel/param/param.h" #include "panel/timeline/timeline.h" #include "panel/sequenceviewer/sequenceviewer.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER Sequence::Sequence() { viewer_output_ = new ViewerOutput(); viewer_output_->SetCanBeDeleted(false); AddNode(viewer_output_); } void Sequence::Load(QXmlStreamReader *reader, XMLNodeData& xml_node_data, const QAtomicInt *cancelled) { XMLAttributeLoop(reader, attr) { if (cancelled && *cancelled) { return; } if (attr.name() == QStringLiteral("name")) { set_name(attr.value().toString()); } else if (attr.name() == QStringLiteral("ptr")) { xml_node_data.item_ptrs.insert(attr.value().toULongLong(), this); } } while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("video")) { int video_width = 0, video_height = 0, preview_div = 1; rational video_timebase; PixelFormat::Format preview_format = PixelFormat::PIX_FMT_INVALID; while (XMLReadNextStartElement(reader)) { if (cancelled && *cancelled) { return; } if (reader->name() == QStringLiteral("width")) { video_width = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("height")) { video_height = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("timebase")) { video_timebase = rational::fromString(reader->readElementText()); } else if (reader->name() == QStringLiteral("divider")) { preview_div = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("format")) { preview_format = static_cast(reader->readElementText().toInt()); } else { reader->skipCurrentElement(); } } set_video_params(VideoParams(video_width, video_height, video_timebase, preview_format, preview_div)); } else if (reader->name() == QStringLiteral("audio")) { int rate = 0; uint64_t layout = 0; SampleFormat::Format format = SampleFormat::SAMPLE_FMT_INVALID; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("rate")) { rate = reader->readElementText().toInt(); } else if (reader->name() == QStringLiteral("layout")) { layout = reader->readElementText().toULongLong(); } else if (reader->name() == QStringLiteral("format")) { format = static_cast(reader->readElementText().toInt()); } else { reader->skipCurrentElement(); } } set_audio_params(AudioParams(rate, layout, format)); } else if (reader->name() == QStringLiteral("points")) { TimelinePoints::Load(reader); } else if (reader->name() == QStringLiteral("node") || reader->name() == QStringLiteral("viewer")) { Node* node; if (reader->name() == QStringLiteral("node")) { node = XMLLoadNode(reader); } else { node = viewer_output_; } if (node) { node->Load(reader, xml_node_data, cancelled); AddNode(node); } } else { reader->skipCurrentElement(); } } // Make connections XMLConnectNodes(xml_node_data); // Link blocks XMLLinkBlocks(xml_node_data); // Ensure this and all children are in the main thread // (FIXME: Weird place for this? This should probably be in ProjectLoadManager somehow) if (thread() != qApp->thread()) { moveToThread(qApp->thread()); } } void Sequence::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("sequence")); writer->writeAttribute(QStringLiteral("name"), name()); writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(this))); writer->writeStartElement(QStringLiteral("video")); writer->writeTextElement(QStringLiteral("width"), QString::number(video_params().width())); writer->writeTextElement(QStringLiteral("height"), QString::number(video_params().height())); writer->writeTextElement(QStringLiteral("timebase"), video_params().time_base().toString()); writer->writeTextElement(QStringLiteral("divider"), QString::number(video_params().divider())); writer->writeTextElement(QStringLiteral("format"), QString::number(video_params().format())); writer->writeEndElement(); // video writer->writeStartElement(QStringLiteral("audio")); writer->writeTextElement(QStringLiteral("rate"), QString::number(audio_params().sample_rate())); writer->writeTextElement(QStringLiteral("layout"), QString::number(audio_params().channel_layout())); writer->writeTextElement(QStringLiteral("format"), QString::number(audio_params().format())); writer->writeEndElement(); // audio // Write TimelinePoints TimelinePoints::Save(writer); foreach (Node* node, nodes()) { if (node != viewer_output_) { node->Save(writer); } } viewer_output_->Save(writer, QStringLiteral("viewer")); writer->writeEndElement(); // sequence } void Sequence::add_default_nodes() { // Create tracks and connect them to the viewer Node* video_track_output = viewer_output_->track_list(Timeline::kTrackTypeVideo)->AddTrack(); Node* audio_track_output = viewer_output_->track_list(Timeline::kTrackTypeAudio)->AddTrack(); NodeParam::ConnectEdge(video_track_output->output(), viewer_output_->texture_input()); NodeParam::ConnectEdge(audio_track_output->output(), viewer_output_->samples_input()); } Item::Type Sequence::type() const { return kSequence; } QIcon Sequence::icon() { return icon::Sequence; } QString Sequence::duration() { rational timeline_length = viewer_output_->GetLength(); int64_t timestamp = Timecode::time_to_timestamp(timeline_length, video_params().time_base()); return Timecode::timestamp_to_timecode(timestamp, video_params().time_base(), Core::instance()->GetTimecodeDisplay()); } QString Sequence::rate() { return QCoreApplication::translate("Sequence", "%1 FPS").arg(video_params().time_base().flipped().toDouble()); } const VideoParams &Sequence::video_params() const { return viewer_output_->video_params(); } void Sequence::set_video_params(const VideoParams &vparam) { viewer_output_->set_video_params(vparam); } const AudioParams &Sequence::audio_params() const { return viewer_output_->audio_params(); } void Sequence::set_audio_params(const AudioParams ¶ms) { viewer_output_->set_audio_params(params); } void Sequence::set_default_parameters() { int width = Config::Current()["DefaultSequenceWidth"].toInt(); int height = Config::Current()["DefaultSequenceHeight"].toInt(); set_video_params(VideoParams(width, height, Config::Current()["DefaultSequenceFrameRate"].value(), static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), VideoParams::generate_auto_divider(width, height))); set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), SampleFormat::kInternalFormat)); } void Sequence::set_parameters_from_footage(const QList footage) { bool found_video_params = false; bool found_audio_params = false; foreach (Footage* f, footage) { foreach (StreamPtr s, f->streams()) { switch (s->type()) { case Stream::kVideo: { VideoStream* vs = static_cast(s.get()); // If this is a video stream, use these parameters if (!found_video_params && !vs->frame_rate().isNull()) { set_video_params(VideoParams(vs->width(), vs->height(), vs->frame_rate().flipped(), static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), VideoParams::generate_auto_divider(vs->width(), vs->height()))); found_video_params = true; } break; } case Stream::kImage: if (!found_video_params) { // If this is an image stream, we'll use it's resolution but won't set `found_video_params` in case // something with a frame rate comes along which we'll prioritize ImageStream* is = static_cast(s.get()); set_video_params(VideoParams(is->width(), is->height(), video_params().time_base(), static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), VideoParams::generate_auto_divider(is->width(), is->height()))); } break; case Stream::kAudio: if (!found_audio_params) { AudioStream* as = static_cast(s.get()); set_audio_params(AudioParams(as->sample_rate(), as->channel_layout(), SampleFormat::kInternalFormat)); found_audio_params = true; } break; case Stream::kUnknown: case Stream::kData: case Stream::kSubtitle: case Stream::kAttachment: // Ignore these types break; } if (found_video_params && found_audio_params) { return; } } } } ViewerOutput *Sequence::viewer_output() const { return viewer_output_; } void Sequence::NameChangedEvent(const QString &name) { viewer_output_->set_media_name(name); } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/item/sequence/sequence.h000066400000000000000000000042751370472574300234010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SEQUENCE_H #define SEQUENCE_H #include "common/rational.h" #include "node/graph.h" #include "node/output/viewer/viewer.h" #include "render/videoparams.h" #include "project/item/footage/stream.h" #include "project/item/item.h" #include "timeline/timelinepoints.h" OLIVE_NAMESPACE_ENTER class Sequence; using SequencePtr = std::shared_ptr; /** * @brief The main timeline object, an graph of edited clips that forms a complete edit */ class Sequence : public Item, public NodeGraph, public TimelinePoints { public: Sequence(); /** * @brief Load function */ virtual void Load(QXmlStreamReader* reader, XMLNodeData &xml_node_data, const QAtomicInt* cancelled) override; /** * @brief Save function */ virtual void Save(QXmlStreamWriter *writer) const override; void add_default_nodes(); /** * @brief Item::Type() override */ virtual Type type() const override; virtual QIcon icon() override; virtual QString duration() override; virtual QString rate() override; const VideoParams &video_params() const; void set_video_params(const VideoParams &vparam); const AudioParams& audio_params() const; void set_audio_params(const AudioParams& params); void set_default_parameters(); void set_parameters_from_footage(const QList footage); ViewerOutput* viewer_output() const; protected: virtual void NameChangedEvent(const QString& name) override; private: ViewerOutput* viewer_output_; }; OLIVE_NAMESPACE_EXIT #endif // SEQUENCE_H olive-continuous/app/project/project.cpp000066400000000000000000000112741370472574300210210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "project.h" #include #include #include "common/xmlutils.h" #include "core.h" #include "dialog/progress/progress.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER Project::Project() : is_modified_(false), autorecovery_saved_(true) { root_.set_project(this); } void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, const QAtomicInt* cancelled) { XMLNodeData xml_node_data; // Set project filename (hacky) xml_node_data.real_project_url = static_cast(reader->device())->fileName(); while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("folder")) { // Assume this folder is our root root_.Load(reader, xml_node_data, cancelled); } else if (reader->name() == QStringLiteral("colormanagement")) { // Read color management info while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("config")) { color_manager_.SetConfig(reader->readElementText()); } else if (reader->name() == QStringLiteral("default")) { color_manager_.SetDefaultInputColorSpace(reader->readElementText()); } else { reader->skipCurrentElement(); } } } else if (reader->name() == QStringLiteral("layout")) { // Since the main window's functions have to occur in the GUI thread (and we're likely // loading in a secondary thread), we load all necessary data into a separate struct so we // can continue loading and queue it with the main window so it can handle the data // appropriately in its own thread. *layout = MainWindowLayoutInfo::fromXml(reader, xml_node_data); } else if (reader->name() == QStringLiteral("url")) { // This should be read in before most other elements xml_node_data.saved_project_url = reader->readElementText(); } else { // Skip this reader->skipCurrentElement(); } } foreach (const XMLNodeData::FootageConnection& con, xml_node_data.footage_connections) { if (con.footage) { con.input->set_standard_value(QVariant::fromValue(xml_node_data.footage_ptrs.value(con.footage))); } } } void Project::Save(QXmlStreamWriter *writer) const { writer->writeStartElement("project"); writer->writeTextElement("url", filename_); root_.Save(writer); writer->writeStartElement("colormanagement"); writer->writeTextElement("config", color_manager_.GetConfigFilename()); writer->writeTextElement("default", color_manager_.GetDefaultInputColorSpace()); writer->writeEndElement(); // colormanagement // Save main window project layout MainWindowLayoutInfo main_window_info = Core::instance()->main_window()->SaveLayout(); main_window_info.toXml(writer); writer->writeEndElement(); // project } Folder *Project::root() { return &root_; } QString Project::name() const { if (filename_.isEmpty()) { return tr("(untitled)"); } else { return QFileInfo(filename_).completeBaseName(); } } const QString &Project::filename() const { return filename_; } QString Project::pretty_filename() const { QString fn = filename(); if (fn.isEmpty()) { return tr("(untitled)"); } else { return fn; } } void Project::set_filename(const QString &s) { filename_ = s; #ifdef Q_OS_WINDOWS // Prevents filenames filename_.replace('/', '\\'); #endif emit NameChanged(); } ColorManager *Project::color_manager() { return &color_manager_; } QList Project::get_items_of_type(Item::Type type) const { return root_.get_children_of_type(type, true); } bool Project::is_modified() const { return is_modified_; } void Project::set_modified(bool e) { is_modified_ = e; autorecovery_saved_ = !e; emit ModifiedChanged(is_modified_); } bool Project::has_autorecovery_been_saved() const { return autorecovery_saved_; } void Project::set_autorecovery_saved(bool e) { autorecovery_saved_ = e; } bool Project::is_new() const { return !is_modified_ && filename_.isEmpty(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/project.h000066400000000000000000000044221370472574300204630ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECT_H #define PROJECT_H #include #include #include "render/colormanager.h" #include "project/item/folder/folder.h" #include "window/mainwindow/mainwindowlayoutinfo.h" OLIVE_NAMESPACE_ENTER /** * @brief A project instance containing all the data pertaining to the user's project * * A project instance uses a parent-child hierarchy of Item objects. Projects will usually contain the following: * * * Footage * * Sequences * * Folders * * Project Settings * * Window Layout */ class Project : public QObject { Q_OBJECT public: Project(); void Load(QXmlStreamReader* reader, MainWindowLayoutInfo *layout, const QAtomicInt* cancelled); void Save(QXmlStreamWriter* writer) const; Folder* root(); QString name() const; const QString& filename() const; QString pretty_filename() const; void set_filename(const QString& s); ColorManager* color_manager(); QList get_items_of_type(Item::Type type) const; bool is_modified() const; void set_modified(bool e); bool has_autorecovery_been_saved() const; void set_autorecovery_saved(bool e); bool is_new() const; const QString& cache_path() const { return cache_path_; } void set_cache_path(const QString& cache_path) { cache_path_ = cache_path; } signals: void NameChanged(); void ModifiedChanged(bool e); private: Folder root_; QString filename_; ColorManager color_manager_; bool is_modified_; bool autorecovery_saved_; QString cache_path_; }; using ProjectPtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // PROJECT_H olive-continuous/app/project/projectviewmodel.cpp000066400000000000000000000371371370472574300227430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectviewmodel.h" #include #include #include #include "core.h" OLIVE_NAMESPACE_ENTER ProjectViewModel::ProjectViewModel(QObject *parent) : QAbstractItemModel(parent), project_(nullptr) { // FIXME: make this configurable columns_.append(kName); columns_.append(kDuration); columns_.append(kRate); } Project *ProjectViewModel::project() const { return project_; } void ProjectViewModel::set_project(Project *p) { beginResetModel(); project_ = p; endResetModel(); } QModelIndex ProjectViewModel::index(int row, int column, const QModelIndex &parent) const { // I'm actually not 100% sure what this does, but it seems logical and was in the earlier code if (!hasIndex(row, column, parent)) { return QModelIndex(); } // Get the parent object (project root if the index is invalid) Item* item_parent = GetItemObjectFromIndex(parent); // Return an index to this object return createIndex(row, column, item_parent->child(row)); } QModelIndex ProjectViewModel::parent(const QModelIndex &child) const { // Get the Item object from the index Item* item = GetItemObjectFromIndex(child); // Get Item's parent object Item* par = item->parent(); // If the parent is the root, return an empty index if (par == project_->root()) { return QModelIndex(); } // Otherwise return a true index to its parent int parent_index = IndexOfChild(par); // Make sure the index is valid (there's no reason it shouldn't be) Q_ASSERT(parent_index > -1); // Return an index to the parent return createIndex(parent_index, 0, par); } int ProjectViewModel::rowCount(const QModelIndex &parent) const { // If there's no project, there are obviously no items to show if (project_ == nullptr) { return 0; } // If the index is the root, return the root child count if (parent == QModelIndex()) { return project_->root()->child_count(); } // Otherwise, the index must contain a valid pointer, so we just return its child count return GetItemObjectFromIndex(parent)->child_count(); } int ProjectViewModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) // Not strictly necessary, but a decent visual cue that there's no project currently active if (project_ == nullptr) { return 0; } return columns_.size(); } QVariant ProjectViewModel::data(const QModelIndex &index, int role) const { Item* internal_item = GetItemObjectFromIndex(index); ColumnType column_type = columns_.at(index.column()); switch (role) { case Qt::DisplayRole: { // Standard text role switch (column_type) { case kName: return internal_item->name(); case kDuration: return internal_item->duration(); case kRate: return internal_item->rate(); } } break; case Qt::DecorationRole: // If this is the first column, return the Item's icon if (column_type == kName) { return internal_item->icon(); } break; case Qt::ToolTipRole: return internal_item->tooltip(); } return QVariant(); } QVariant ProjectViewModel::headerData(int section, Qt::Orientation orientation, int role) const { // Check if we need text data (DisplayRole) and orientation is horizontal // FIXME I'm not 100% sure what happens if the orientation is vertical/if that check is necessary if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { ColumnType column_type = columns_.at(section); // Return the name based on the column's current type switch (column_type) { case kName: return tr("Name"); case kDuration: return tr("Duration"); case kRate: return tr("Rate"); } } return QAbstractItemModel::headerData(section, orientation, role); } bool ProjectViewModel::hasChildren(const QModelIndex &parent) const { // Check if this is a valid index if (parent.isValid()) { Item* item = GetItemObjectFromIndex(parent); // Check if this item is a kFolder type // If it's a folder, we always return TRUE in order to always show the "expand triangle" icon, // even when there are no "physical" children if (item->CanHaveChildren()) { return true; } } // Otherwise, return default behavior return QAbstractItemModel::hasChildren(parent); } bool ProjectViewModel::setData(const QModelIndex &index, const QVariant &value, int role) { // The name is editable if (index.isValid() && columns_.at(index.column()) == kName && role == Qt::EditRole) { Item* item = GetItemObjectFromIndex(index); RenameItemCommand* ric = new RenameItemCommand(this, item, value.toString()); Core::instance()->undo_stack()->push(ric); return true; } return false; } bool ProjectViewModel::canFetchMore(const QModelIndex &parent) const { // Check if this is a valid index if (parent.isValid()) { Item* item = GetItemObjectFromIndex(parent); // Check if this item is a kFolder type // If it's a folder, we always return TRUE in order to always show the "expand triangle" icon, // even when there are no "physical" children if (item->CanHaveChildren()) { return true; } } // Otherwise, return default behavior return QAbstractItemModel::canFetchMore(parent); } Qt::ItemFlags ProjectViewModel::flags(const QModelIndex &index) const { if (!index.isValid()) { // Allow dropping files from external sources return Qt::ItemIsDropEnabled; } Qt::ItemFlags f = Qt::ItemIsDragEnabled | QAbstractItemModel::flags(index); if (GetItemObjectFromIndex(index)->CanHaveChildren()) { f |= Qt::ItemIsDropEnabled; } // If the column is the kName column, that means it's editable if (columns_.at(index.column()) == kName) { f |= Qt::ItemIsEditable; } return f; } QStringList ProjectViewModel::mimeTypes() const { // Allow data from this model and a file list from external sources return {"application/x-oliveprojectitemdata", "text/uri-list"}; } QMimeData *ProjectViewModel::mimeData(const QModelIndexList &indexes) const { // Compliance with Qt standard if (indexes.isEmpty()) { return nullptr; } // Encode mime data for the rows/items that were dragged QMimeData* data = new QMimeData(); // Use QDataStream to stream the item data into a byte array QByteArray encoded_data; QDataStream stream(&encoded_data, QIODevice::WriteOnly); // The indexes list includes indexes for each column which we don't use. To make sure each row only gets sent *once*, // we keep a list of dragged items QVector dragged_items; foreach (QModelIndex index, indexes) { if (index.isValid()) { // Check if we've dragged this item before if (!dragged_items.contains(index.internalPointer())) { // If not, add it to the stream (and also keep track of it in the vector) quint64 stream_flags; if (static_cast(index.internalPointer())->type() == Item::kFootage) { stream_flags = static_cast(index.internalPointer())->get_enabled_stream_flags(); } else { stream_flags = UINT64_MAX; } stream << stream_flags << index.row() << reinterpret_cast(index.internalPointer()); dragged_items.append(index.internalPointer()); } } } // Set byte array as the mime data and return the mime data data->setData("application/x-oliveprojectitemdata", encoded_data); return data; } bool ProjectViewModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &drop) { // Default recommended checks from https://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views if (!canDropMimeData(data, action, row, column, drop)) { return false; } if (action == Qt::IgnoreAction) { return true; } // Probe mime data for its format QStringList mime_formats = data->formats(); if (mime_formats.contains("application/x-oliveprojectitemdata")) { // Data is drag/drop data from this model QByteArray model_data = data->data("application/x-oliveprojectitemdata"); // Use QDataStream to deserialize the data QDataStream stream(&model_data, QIODevice::ReadOnly); // Get the Item object that the items were dropped on Item* drop_location = GetItemObjectFromIndex(drop); // If this is not a folder, we cannot drop these items here if (!drop_location->CanHaveChildren()) { return false; } // Variables to deserialize into quintptr item_ptr; int r; quint64 enabled_streams; // Loop through all data QUndoCommand* move_command = new QUndoCommand(); move_command->setText(tr("Move Items")); while (!stream.atEnd()) { stream >> enabled_streams >> r >> item_ptr; Item* item = reinterpret_cast(item_ptr); // Check if Item is already the drop location or if its parent is the drop location, in which case this is a // no-op if (item != drop_location && item->parent() != drop_location && !ItemIsParentOfChild(item, drop_location)) { MoveItemCommand* mic = new MoveItemCommand(this, item, static_cast(drop_location), move_command); Q_UNUSED(mic) } } Core::instance()->undo_stack()->pushIfHasChildren(move_command); return true; } else if (mime_formats.contains("text/uri-list")) { // We received a list of files QByteArray file_data = data->data("text/uri-list"); // Use text stream to parse (just an easy way of sifting through line breaks QTextStream stream(&file_data); // Convert QByteArray to QStringList (which Core takes for importing) QStringList urls; while (!stream.atEnd()) { QUrl url = stream.readLine(); if (!url.isEmpty()) { urls.append(url.toLocalFile()); } } // Get folder dropped onto Item* drop_item = GetItemObjectFromIndex(drop); // If we didn't drop onto an item, find the nearest parent folder (should eventually terminate at root either way) while (!drop_item->CanHaveChildren()) { drop_item = drop_item->parent(); } // Trigger an import Core::instance()->ImportFiles(urls, this, static_cast(drop_item)); } return false; } void ProjectViewModel::AddChild(Item *parent, ItemPtr child) { QModelIndex parent_index; if (parent != project_->root()) { parent_index = CreateIndexFromItem(parent); } beginInsertRows(parent_index, parent->child_count(), parent->child_count()); parent->add_child(child); endInsertRows(); } void ProjectViewModel::RemoveChild(Item *parent, Item *child) { QModelIndex parent_index; if (parent != project_->root()) { parent_index = CreateIndexFromItem(parent); } int child_row = IndexOfChild(child); beginRemoveRows(parent_index, child_row, child_row); parent->remove_child(child); endRemoveRows(); } void ProjectViewModel::RenameChild(Item *item, const QString &name) { item->set_name(name); QModelIndex index = CreateIndexFromItem(item, columns_.indexOf(kName)); emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); } int ProjectViewModel::IndexOfChild(Item *item) const { // Find parent's index within its own parent // (FIXME: this model should handle sorting, which means it'll have to "know" the indices) if (item == project_->root()) { return -1; } Item* parent = item->parent(); if (parent != nullptr) { for (int i=0;ichild_count();i++) { if (parent->child(i) == item) { return i; } } } return -1; } int ProjectViewModel::ChildCount(const QModelIndex &index) { Item* item = GetItemObjectFromIndex(index); return item->child_count(); } Item *ProjectViewModel::GetItemObjectFromIndex(const QModelIndex &index) const { if (index.isValid()) { return static_cast(index.internalPointer()); } return project_->root(); } bool ProjectViewModel::ItemIsParentOfChild(Item *parent, Item *child) const { // Loop through parent hierarchy checking if `parent` is one of its parents do { child = child->parent(); if (parent == child) { return true; } } while (child != nullptr); return false; } void ProjectViewModel::MoveItemInternal(Item *item, Item *destination) { QModelIndex item_index = CreateIndexFromItem(item); QModelIndex destination_index = CreateIndexFromItem(destination); beginMoveRows(item_index.parent(), item_index.row(), item_index.row(), destination_index, destination->child_count()); ItemPtr item_ptr = item->get_shared_ptr(); destination->add_child(item_ptr); endMoveRows(); } QModelIndex ProjectViewModel::CreateIndexFromItem(Item *item, int column) { return createIndex(IndexOfChild(item), column, item); } ProjectViewModel::MoveItemCommand::MoveItemCommand(ProjectViewModel *model, Item *item, Folder *destination, QUndoCommand *parent) : UndoCommand(parent), model_(model), item_(item), destination_(destination) { source_ = static_cast(item->parent()); setText(tr("Move Item")); } Project *ProjectViewModel::MoveItemCommand::GetRelevantProject() const { return model_->project(); } void ProjectViewModel::MoveItemCommand::redo_internal() { model_->MoveItemInternal(item_, destination_); } void ProjectViewModel::MoveItemCommand::undo_internal() { model_->MoveItemInternal(item_, source_); } ProjectViewModel::RenameItemCommand::RenameItemCommand(ProjectViewModel* model, Item *item, const QString &name, QUndoCommand *parent) : UndoCommand(parent), model_(model), item_(item), new_name_(name) { old_name_ = item->name(); setText(tr("Rename Item")); } Project *ProjectViewModel::RenameItemCommand::GetRelevantProject() const { return model_->project(); } void ProjectViewModel::RenameItemCommand::redo_internal() { model_->RenameChild(item_, new_name_); } void ProjectViewModel::RenameItemCommand::undo_internal() { model_->RenameChild(item_, old_name_); } ProjectViewModel::AddItemCommand::AddItemCommand(ProjectViewModel* model, Item* folder, ItemPtr child, QUndoCommand* parent) : UndoCommand(parent), model_(model), parent_(folder), child_(child), done_(false) { } Project *ProjectViewModel::AddItemCommand::GetRelevantProject() const { return model_->project(); } void ProjectViewModel::AddItemCommand::redo_internal() { model_->AddChild(parent_, child_); done_ = true; } void ProjectViewModel::AddItemCommand::undo_internal() { model_->RemoveChild(parent_, child_.get()); done_ = false; } ProjectViewModel::RemoveItemCommand::RemoveItemCommand(ProjectViewModel *model, ItemPtr item, QUndoCommand *parent) : UndoCommand(parent), model_(model), item_(item) { } Project *ProjectViewModel::RemoveItemCommand::GetRelevantProject() const { return model_->project(); } void ProjectViewModel::RemoveItemCommand::redo_internal() { parent_ = item_->parent(); model_->RemoveChild(parent_, item_.get()); } void ProjectViewModel::RemoveItemCommand::undo_internal() { model_->AddChild(parent_, item_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/project/projectviewmodel.h000066400000000000000000000167531370472574300224110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWMODEL_H #define VIEWMODEL_H #include #include "project.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER /** * @brief An adapter that interprets the data in a Project into a Qt item model for usage in ViewModel Views. * * Assuming a Project is currently "open" (i.e. the Project is connected to a ProjectExplorer/ProjectPanel through * a ProjectViewModel), it may be better to make modifications (e.g. additions/removals/renames) through the * ProjectViewModel so that the views can be efficiently and correctly updated. ProjectViewModel contains several * "wrapper" functions for Project and Item functions that also signal any connected views to update accordingly. */ class ProjectViewModel : public QAbstractItemModel { public: enum ColumnType { /// Media name kName, /// Media duration kDuration, /// Media rate (frame rate for video, sample rate for audio) kRate }; /** * @brief ProjectViewModel Constructor * * @param parent * Parent object for memory handling */ ProjectViewModel(QObject* parent); /** * @brief Get currently active project * * @return * * Currently active project or nullptr if there is none */ Project* project() const; /** * @brief Set the project to adapt * * Any views attached to this model will get updated by this function. * * @param p * * Project to adapt, can be set to nullptr to "close" the project (will show an empty model that cannot be modified) */ void set_project(Project* p); /** Compulsory Qt QAbstractItemModel overrides */ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex &child) const override; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; /** Optional Qt QAbstractItemModel overrides */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; virtual bool canFetchMore(const QModelIndex &parent) const override; /** Drag and drop support */ virtual Qt::ItemFlags flags(const QModelIndex &index) const override; virtual QStringList mimeTypes() const override; virtual QMimeData * mimeData(const QModelIndexList &indexes) const override; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; /** Other model functions */ void AddChild(Item* parent, ItemPtr child); void RemoveChild(Item* parent, Item* child); void RenameChild(Item* item, const QString& name); /** * @brief Convenience function for creating QModelIndexes from an Item object */ QModelIndex CreateIndexFromItem(Item* item, int column = 0); /** * @brief A QUndoCommand for moving an item from one folder to another folder */ class MoveItemCommand : public UndoCommand { public: MoveItemCommand(ProjectViewModel* model, Item* item, Folder* destination, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: ProjectViewModel* model_; Item* item_; Folder* source_; Folder* destination_; }; /** * @brief A QUndoCommand for renaming an item */ class RenameItemCommand : public UndoCommand { public: RenameItemCommand(ProjectViewModel* model, Item* item, const QString& name, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: ProjectViewModel* model_; Item* item_; QString old_name_; QString new_name_; }; /** * @brief A QUndoCommand for adding an item */ class AddItemCommand : public UndoCommand { public: AddItemCommand(ProjectViewModel* model, Item* folder, ItemPtr child, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: ProjectViewModel* model_; Item* parent_; ItemPtr child_; bool done_; }; /** * @brief An undo command for removing an item */ class RemoveItemCommand : public UndoCommand { public: RemoveItemCommand(ProjectViewModel* model, ItemPtr item, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: ProjectViewModel* model_; ItemPtr item_; Item* parent_; }; private: /** * @brief Retrieve the index of `item` in its parent * * This function will return the index of a specified item in its parent according to whichever sorting algorithm * is currently active. * * @return * * Index of the specified item, or -1 if the item is root (in which case it has no parent). */ int IndexOfChild(Item* item) const; /** * @brief Get the child count of an index * * @param index * * @return * * Return number of children (immediate children only) */ int ChildCount(const QModelIndex& index); /** * @brief Retrieves the Item object from a given index * * A convenience function for retrieving Item objects. If the index is not valid, this returns the root Item. */ Item* GetItemObjectFromIndex(const QModelIndex& index) const; /** * @brief Check if an Item is a parent of a Child * * Checks entire "parent hierarchy" of `child` to see if `parent` is one of its parents. */ bool ItemIsParentOfChild(Item* parent, Item* child) const; /** * @brief Moves an item to a new destination updating all views in the process * * This function will emit a signal indicating that rows are moving, set `destination` as the new parent of `item`, * and then emit a signal that the row has finished moving. * * It's not recommended to use this function directly in most cases since it does not create a QUndoCommand allowing * the user to undo the move. Instead this function should primarily be called from QUndoCommands belonging to this * class (e.g. MoveItemCommand). */ void MoveItemInternal(Item* item, Item* destination); Project* project_; QVector columns_; }; OLIVE_NAMESPACE_EXIT #endif // VIEWMODEL_H olive-continuous/app/render/000077500000000000000000000000001370472574300164535ustar00rootroot00000000000000olive-continuous/app/render/CMakeLists.txt000066400000000000000000000026711370472574300212210ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(backend) add_subdirectory(ocioconf) set(OLIVE_SOURCES ${OLIVE_SOURCES} render/audioparams.h render/audioparams.cpp render/audioplaybackcache.h render/audioplaybackcache.cpp render/color.h render/color.cpp render/colormanager.h render/colormanager.cpp render/colorprocessor.h render/colorprocessor.cpp render/diskmanager.h render/diskmanager.cpp render/framehashcache.h render/framehashcache.cpp render/managedcolor.h render/managedcolor.cpp render/pixelformat.h render/pixelformat.cpp render/playbackcache.h render/playbackcache.cpp render/rendermodes.h render/shaderinfo.h render/videoparams.h render/videoparams.cpp PARENT_SCOPE ) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} PARENT_SCOPE ) olive-continuous/app/render/audioparams.cpp000066400000000000000000000060301370472574300214630ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audioparams.h" extern "C" { #include } OLIVE_NAMESPACE_ENTER int AudioParams::time_to_bytes(const double &time) const { Q_ASSERT(is_valid()); return time_to_samples(time) * channel_count() * bytes_per_sample_per_channel(); } bool AudioParams::operator==(const AudioParams &other) const { return (format() == other.format() && sample_rate() == other.sample_rate() && channel_layout() == other.channel_layout()); } bool AudioParams::operator!=(const AudioParams &other) const { return !(*this == other); } int AudioParams::time_to_bytes(const rational &time) const { return time_to_bytes(time.toDouble()); } int AudioParams::time_to_samples(const double &time) const { Q_ASSERT(is_valid()); return qFloor(time * sample_rate()); } int AudioParams::time_to_samples(const rational &time) const { return time_to_samples(time.toDouble()); } int AudioParams::samples_to_bytes(const int &samples) const { Q_ASSERT(is_valid()); return samples * channel_count() * bytes_per_sample_per_channel(); } rational AudioParams::samples_to_time(const int &samples) const { return rational(samples, sample_rate()); } int AudioParams::bytes_to_samples(const int &bytes) const { Q_ASSERT(is_valid()); return bytes / (channel_count() * bytes_per_sample_per_channel()); } rational AudioParams::bytes_to_time(const int &bytes) const { Q_ASSERT(is_valid()); return samples_to_time(bytes_to_samples(bytes)); } int AudioParams::channel_count() const { return av_get_channel_layout_nb_channels(channel_layout()); } int AudioParams::bytes_per_sample_per_channel() const { switch (format_) { case SampleFormat::SAMPLE_FMT_U8: return 1; case SampleFormat::SAMPLE_FMT_S16: return 2; case SampleFormat::SAMPLE_FMT_S32: case SampleFormat::SAMPLE_FMT_FLT: return 4; case SampleFormat::SAMPLE_FMT_DBL: case SampleFormat::SAMPLE_FMT_S64: return 8; case SampleFormat::SAMPLE_FMT_INVALID: case SampleFormat::SAMPLE_FMT_COUNT: break; } return 0; } int AudioParams::bits_per_sample() const { return bytes_per_sample_per_channel() * 8; } bool AudioParams::is_valid() const { return (sample_rate() > 0 && channel_layout() > 0 && format_ != SampleFormat::SAMPLE_FMT_INVALID && format_ != SampleFormat::SAMPLE_FMT_COUNT); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/audioparams.h000066400000000000000000000044331370472574300211350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOPARAMS_H #define AUDIOPARAMS_H #include #include "audio/sampleformat.h" #include "common/rational.h" OLIVE_NAMESPACE_ENTER class AudioParams { public: AudioParams() : sample_rate_(0), channel_layout_(0), format_(SampleFormat::SAMPLE_FMT_INVALID) { } AudioParams(const int& sample_rate, const uint64_t& channel_layout, const SampleFormat::Format& format) : sample_rate_(sample_rate), channel_layout_(channel_layout), format_(format) { } const int& sample_rate() const { return sample_rate_; } const uint64_t& channel_layout() const { return channel_layout_; } rational time_base() const { return rational(1, sample_rate()); } const SampleFormat::Format &format() const { return format_; } int time_to_bytes(const double& time) const; int time_to_bytes(const rational& time) const; int time_to_samples(const double& time) const; int time_to_samples(const rational& time) const; int samples_to_bytes(const int& samples) const; rational samples_to_time(const int& samples) const; int bytes_to_samples(const int &bytes) const; rational bytes_to_time(const int &bytes) const; int channel_count() const; int bytes_per_sample_per_channel() const; int bits_per_sample() const; bool is_valid() const; bool operator==(const AudioParams& other) const; bool operator!=(const AudioParams& other) const; private: int sample_rate_; uint64_t channel_layout_; SampleFormat::Format format_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::AudioParams) #endif // AUDIOPARAMS_H olive-continuous/app/render/audioplaybackcache.cpp000066400000000000000000000143141370472574300227560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audioplaybackcache.h" #include #include #include #include "common/filefunctions.h" OLIVE_NAMESPACE_ENTER AudioPlaybackCache::AudioPlaybackCache(QObject* parent) : PlaybackCache(parent) { quint32 r = std::rand(); UpdateFilename(QString::number(r)); } void AudioPlaybackCache::SetParameters(const AudioParams ¶ms) { QMutexLocker locker(lock()); if (params_ == params) { return; } params_ = params; // Restart empty file so there's always "something" to play QFile f(filename_); if (f.open(QFile::WriteOnly)) { f.close(); } // Our current audio cache is unusable, so we truncate it automatically TimeRange invalidate_range(0, NoLockGetLength()); if (invalidate_range.in() != invalidate_range.out()) { NoLockInvalidate(invalidate_range); } locker.unlock(); emit ParametersChanged(); emit Invalidated(invalidate_range); } void AudioPlaybackCache::WritePCM(const TimeRange &range, SampleBufferPtr samples, const qint64 &job_time) { QMutexLocker locker(lock()); QList valid_ranges = NoLockGetValidRanges(range, job_time); if (valid_ranges.isEmpty()) { return; } QFile f(filename_); if (f.open(QFile::ReadWrite)) { QByteArray a = samples->toPackedData(); foreach (const TimeRange& r, valid_ranges) { // Calculate destination offsets qint64 start_offset = params_.time_to_bytes(r.in()); qint64 max_len = params_.time_to_bytes(r.out()); if (f.size() < max_len) { f.resize(max_len); } // Calculate source offsets qint64 sample_start = params_.time_to_bytes(r.in() - range.in()); qint64 sample_len = params_.time_to_bytes(r.length()); qint64 actual_write = qMin(sample_len, a.size() - sample_start); f.seek(start_offset); f.write(a.data() + sample_start, actual_write); if (actual_write < sample_len) { // Fill remaining space with silence QByteArray s(sample_len - actual_write, 0x00); f.write(s); } } f.close(); NoLockValidate(range); locker.unlock(); emit Validated(range); } else { qWarning() << "Failed to write PCM data to" << filename_; } } void AudioPlaybackCache::WriteSilence(const TimeRange &range) { QMutexLocker locker(lock()); QFile f(filename_); if (f.open(QFile::ReadWrite)) { qint64 start_offset = params_.time_to_bytes(range.in()); qint64 max_len = params_.time_to_bytes(range.out()); qint64 write_len = max_len - start_offset; if (f.size() < max_len) { f.resize(max_len); } f.seek(start_offset); QByteArray a(write_len, 0x00); f.write(a); f.close(); } else { qWarning() << "Failed to write PCM data to" << filename_; } } /* void AudioPlaybackCache::SetUuid(const QUuid &id) { UpdateFilename(id.toByteArray()); } */ void AudioPlaybackCache::ShiftEvent(const rational &from, const rational &to) { qint64 from_offset = params_.time_to_bytes(from); qint64 to_offset = params_.time_to_bytes(to); if (from_offset == to_offset) { return; } QFile f(filename_); if (f.open(QFile::ReadWrite)) { if (!f.size()) { return; } qint64 chunk = qAbs(to_offset - from_offset); QByteArray buf(chunk, Qt::Uninitialized); if (to > from) { // Shifting forwards, we must insert a new region and shift all the bytes there // For shifting forwards, we copy bytes starting at the back so that bytes we need don't // get overwritten. qint64 read_offset = f.size(); f.resize(f.size() + chunk); qint64 write_offset = f.size(); while (read_offset != from_offset) { // Calculate how much will be read this time qint64 chunk_sz = qMin(chunk, read_offset - from_offset); read_offset -= chunk_sz; // Read that chunk f.seek(read_offset); f.read(buf.data(), chunk_sz); // Write it at the destination write_offset -= chunk_sz; f.seek(write_offset); f.write(buf.data(), chunk_sz); } // Replace remainder with silence f.seek(from_offset); buf.fill(0); f.write(buf); } else { // Shifting backwards, we will shift bytes and truncate while (from_offset != f.size()) { // Read region to be shifted f.seek(from_offset); qint64 read_sz = f.read(buf.data(), buf.size()); from_offset += read_sz; // Write it at the destination f.seek(to_offset); to_offset += f.write(buf, read_sz); } // Truncate f.resize(f.size() - chunk); } f.close(); } else { qWarning() << "Failed to write PCM data to" << filename_; } } void AudioPlaybackCache::LengthChangedEvent(const rational& old, const rational& newlen) { if (!params_.is_valid()) { return; } if (newlen < old) { QFile(filename_).resize(params_.time_to_bytes(newlen)); } } QList AudioPlaybackCache::NoLockGetValidRanges(const TimeRange& range, const qint64& job_time) { QList valid_ranges; for (int i=jobs_.size()-1;i>=0;i--) { const JobIdentifier& job = jobs_.at(i); if (job_time >= job.job_time && job.range.OverlapsWith(range)) { valid_ranges.append(job.range.Intersected(range)); } } return valid_ranges; } void AudioPlaybackCache::UpdateFilename(const QString &s) { filename_ = QDir(FileFunctions::GetMediaCacheLocation()).filePath(s); filename_.append(QStringLiteral(".pcm")); } const QString &AudioPlaybackCache::GetCacheFilename() const { return filename_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/audioplaybackcache.h000066400000000000000000000037241370472574300224260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOPLAYBACKCACHE_H #define AUDIOPLAYBACKCACHE_H #include "common/timerange.h" #include "codec/samplebuffer.h" #include "render/playbackcache.h" OLIVE_NAMESPACE_ENTER class AudioPlaybackCache : public PlaybackCache { Q_OBJECT public: AudioPlaybackCache(QObject* parent = nullptr); AudioParams GetParameters() { QMutexLocker locker(lock()); return params_; } void SetParameters(const AudioParams& params); void WritePCM(const TimeRange &range, SampleBufferPtr samples, const qint64& job_time); void WriteSilence(const TimeRange &range); //void SetUuid(const QUuid& id); const QString& GetCacheFilename() const; QList GetValidRanges(const TimeRange &range, const qint64 &job_time) { QMutexLocker locker(lock()); return NoLockGetValidRanges(range, job_time); } signals: void ParametersChanged(); protected: virtual void ShiftEvent(const rational& from, const rational& to) override; virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; private: QList NoLockGetValidRanges(const TimeRange &range, const qint64 &job_time); void UpdateFilename(const QString& s); QString filename_; AudioParams params_; }; OLIVE_NAMESPACE_EXIT #endif // AUDIOPLAYBACKCACHE_H olive-continuous/app/render/backend/000077500000000000000000000000001370472574300200425ustar00rootroot00000000000000olive-continuous/app/render/backend/CMakeLists.txt000066400000000000000000000021561370472574300226060ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(opengl) set(OLIVE_SOURCES ${OLIVE_SOURCES} render/backend/colorprocessorcache.h render/backend/decodercache.h render/backend/renderbackend.h render/backend/renderbackend.cpp render/backend/renderticket.h render/backend/renderticket.cpp render/backend/renderticketwatcher.h render/backend/renderticketwatcher.cpp render/backend/renderworker.h render/backend/renderworker.cpp PARENT_SCOPE ) olive-continuous/app/render/backend/colorprocessorcache.h000066400000000000000000000017371370472574300242650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORPROCESSORCACHE_H #define COLORPROCESSORCACHE_H #include "project/item/footage/stream.h" #include "render/colorprocessor.h" OLIVE_NAMESPACE_ENTER using ColorProcessorCache = QHash; OLIVE_NAMESPACE_EXIT #endif // COLORPROCESSORCACHE_H olive-continuous/app/render/backend/decodercache.h000066400000000000000000000016641370472574300226130ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef DECODERCACHE_H #define DECODERCACHE_H #include "codec/decoder.h" #include "project/item/footage/stream.h" OLIVE_NAMESPACE_ENTER using DecoderCache = QHash; OLIVE_NAMESPACE_EXIT #endif // DECODERCACHE_H olive-continuous/app/render/backend/opengl/000077500000000000000000000000001370472574300213265ustar00rootroot00000000000000olive-continuous/app/render/backend/opengl/CMakeLists.txt000066400000000000000000000027771370472574300241030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} render/backend/opengl/openglbackend.h render/backend/opengl/openglbackend.cpp render/backend/opengl/openglcolorprocessor.h render/backend/opengl/openglcolorprocessor.cpp render/backend/opengl/openglframebuffer.h render/backend/opengl/openglframebuffer.cpp render/backend/opengl/openglproxy.h render/backend/opengl/openglproxy.cpp render/backend/opengl/openglrenderfunctions.h render/backend/opengl/openglrenderfunctions.cpp render/backend/opengl/openglshader.h render/backend/opengl/openglshader.cpp render/backend/opengl/opengltexture.h render/backend/opengl/opengltexture.cpp render/backend/opengl/opengltexturecache.h render/backend/opengl/opengltexturecache.cpp render/backend/opengl/openglworker.h render/backend/opengl/openglworker.cpp PARENT_SCOPE ) olive-continuous/app/render/backend/opengl/openglbackend.cpp000066400000000000000000000017761370472574300246410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglbackend.h" #include "openglworker.h" OLIVE_NAMESPACE_ENTER OpenGLBackend::OpenGLBackend(QObject* parent) : RenderBackend(parent) { } OpenGLBackend::~OpenGLBackend() { Close(); } RenderWorker *OpenGLBackend::CreateNewWorker() { return new OpenGLWorker(this); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglbackend.h000066400000000000000000000021201370472574300242660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLBACKEND_H #define OPENGLBACKEND_H #include "openglproxy.h" #include "render/backend/renderbackend.h" OLIVE_NAMESPACE_ENTER class OpenGLBackend : public RenderBackend { public: OpenGLBackend(QObject* parent = nullptr); virtual ~OpenGLBackend() override; protected: virtual RenderWorker* CreateNewWorker() override; }; OLIVE_NAMESPACE_EXIT #endif // OPENGLBACKEND_H olive-continuous/app/render/backend/opengl/openglcolorprocessor.cpp000066400000000000000000000047131370472574300263220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglcolorprocessor.h" #include #include #include "openglrenderfunctions.h" OLIVE_NAMESPACE_ENTER void OpenGLColorProcessor::Enable(QOpenGLContext *context, bool alpha_is_associated) { if (IsEnabled()) { return; } context_ = context; pipeline_ = OpenGLShader::CreateOCIO(context_, ocio_lut_, GetProcessor(), alpha_is_associated); connect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLColorProcessor::ClearTexture, Qt::DirectConnection); } bool OpenGLColorProcessor::IsEnabled() const { return ocio_lut_; } OpenGLShaderPtr OpenGLColorProcessor::pipeline() const { return pipeline_; } void OpenGLColorProcessor::ProcessOpenGL(bool flipped, const QMatrix4x4& matrix) { OpenGLRenderFunctions::OCIOBlit(pipeline_, ocio_lut_, flipped, matrix); } void OpenGLColorProcessor::ClearTexture() { if (IsEnabled()) { // Clean up OCIO LUT texture and shader context_->functions()->glDeleteTextures(1, &ocio_lut_); disconnect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLColorProcessor::ClearTexture); ocio_lut_ = 0; pipeline_ = nullptr; } } OpenGLColorProcessor::OpenGLColorProcessor(ColorManager* config, const QString &source_space, const ColorTransform &dest_space) : ColorProcessor(config, source_space, dest_space), ocio_lut_(0) { } OpenGLColorProcessor::~OpenGLColorProcessor() { ClearTexture(); } OpenGLColorProcessorPtr OpenGLColorProcessor::Create(ColorManager *config, const QString &source_space, const ColorTransform &dest_space) { return std::make_shared(config, source_space, dest_space); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglcolorprocessor.h000066400000000000000000000035651370472574300257730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLCOLORPROCESSOR_H #define OPENGLCOLORPROCESSOR_H #include "openglshader.h" #include "render/colorprocessor.h" OLIVE_NAMESPACE_ENTER class OpenGLColorProcessor; using OpenGLColorProcessorPtr = std::shared_ptr; class OpenGLColorProcessor : public QObject, public ColorProcessor { Q_OBJECT public: OpenGLColorProcessor(ColorManager *config, const QString& input, const ColorTransform& dest); virtual ~OpenGLColorProcessor() override; static OpenGLColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest); void Enable(QOpenGLContext* context, bool alpha_is_associated); bool IsEnabled() const; OpenGLShaderPtr pipeline() const; void ProcessOpenGL(bool flipped = false, const QMatrix4x4& matrix = QMatrix4x4()); private: QOpenGLContext* context_; GLuint ocio_lut_; OpenGLShaderPtr pipeline_; private slots: void ClearTexture(); }; using OpenGLColorProcessorCache = QHash; OLIVE_NAMESPACE_EXIT #endif // OPENGLCOLORPROCESSOR_H olive-continuous/app/render/backend/opengl/openglframebuffer.cpp000066400000000000000000000064561370472574300255360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglframebuffer.h" #include #include OLIVE_NAMESPACE_ENTER OpenGLFramebuffer::OpenGLFramebuffer() : context_(nullptr), buffer_(0), texture_(nullptr) { } OpenGLFramebuffer::~OpenGLFramebuffer() { Destroy(); } void OpenGLFramebuffer::Create(QOpenGLContext *ctx) { if (ctx == nullptr) { qWarning() << "OpenGLFramebuffer::Create was passed an invalid context"; return; } // Free any previous framebuffer Destroy(); context_ = ctx; connect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLFramebuffer::Destroy); // Create framebuffer object context_->functions()->glGenFramebuffers(1, &buffer_); } void OpenGLFramebuffer::Destroy() { if (context_ != nullptr) { disconnect(context_, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLFramebuffer::Destroy); context_->functions()->glDeleteFramebuffers(1, &buffer_); buffer_ = 0; context_ = nullptr; } } bool OpenGLFramebuffer::IsCreated() const { return (buffer_ > 0); } void OpenGLFramebuffer::Bind() { if (context_ == nullptr) { return; } context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, buffer_); } void OpenGLFramebuffer::Release() { if (context_ == nullptr) { return; } context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0); } void OpenGLFramebuffer::Attach(OpenGLTexture *texture, bool clear) { if (context_ == nullptr) { return; } Detach(); texture_ = texture; QOpenGLFunctions* f = context_->functions(); // bind framebuffer for attaching f->glBindFramebuffer(GL_FRAMEBUFFER, buffer_); context_->extraFunctions()->glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_->texture(), 0 ); if (clear) { context_->functions()->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); context_->functions()->glClear(GL_COLOR_BUFFER_BIT); } // release framebuffer f->glBindFramebuffer(GL_FRAMEBUFFER, 0); } void OpenGLFramebuffer::Attach(OpenGLTexturePtr texture, bool clear) { Attach(texture.get(), clear); } void OpenGLFramebuffer::Detach() { if (context_ == nullptr) { return; } if (texture_) { QOpenGLFunctions* f = context_->functions(); // bind framebuffer for attaching f->glBindFramebuffer(GL_FRAMEBUFFER, buffer_); context_->extraFunctions()->glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 ); // release framebuffer f->glBindFramebuffer(GL_FRAMEBUFFER, 0); texture_ = nullptr; } } const GLuint &OpenGLFramebuffer::buffer() const { return buffer_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglframebuffer.h000066400000000000000000000026121370472574300251710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLFRAMEBUFFER_H #define OPENGLFRAMEBUFFER_H #include #include "opengltexture.h" OLIVE_NAMESPACE_ENTER class OpenGLFramebuffer : public QObject { Q_OBJECT public: OpenGLFramebuffer(); virtual ~OpenGLFramebuffer() override; void Create(QOpenGLContext *ctx); bool IsCreated() const; void Bind(); void Release(); void Attach(OpenGLTexture* texture, bool clear = false); void Attach(OpenGLTexturePtr texture, bool clear = false); void Detach(); const GLuint& buffer() const; public slots: void Destroy(); private: QOpenGLContext* context_; GLuint buffer_; OpenGLTexture* texture_; }; OLIVE_NAMESPACE_EXIT #endif // OPENGLFRAMEBUFFER_H olive-continuous/app/render/backend/opengl/openglproxy.cpp000066400000000000000000000430111370472574300244170ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglproxy.h" #include #include "common/clamp.h" #include "core.h" #include "node/block/transition/transition.h" #include "node/node.h" #include "openglcolorprocessor.h" #include "openglrenderfunctions.h" #include "render/colormanager.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER OpenGLProxy* OpenGLProxy::instance_ = nullptr; OpenGLProxy::OpenGLProxy(QObject *parent) : QObject(parent), ctx_(nullptr), functions_(nullptr) { surface_.create(); } OpenGLProxy::~OpenGLProxy() { Close(); surface_.destroy(); } void OpenGLProxy::CreateInstance() { instance_ = new OpenGLProxy(); QThread* proxy_thread = new QThread(); proxy_thread->start(QThread::IdlePriority); instance_->moveToThread(proxy_thread); if (!instance_->Init()) { DestroyInstance(); } } void OpenGLProxy::DestroyInstance() { if (instance_) { instance_->thread()->quit(); instance_->thread()->wait(); instance_->thread()->deleteLater(); instance_->deleteLater(); instance_ = nullptr; } } bool OpenGLProxy::Init() { // Create context object ctx_ = new QOpenGLContext(); // Create OpenGL context (automatically destroys any existing if there is one) if (!ctx_->create()) { qWarning() << "Failed to create OpenGL context in thread" << thread(); return false; } ctx_->moveToThread(this->thread()); // The rest of the initialization needs to occur in the other thread, so we signal for it to start QMetaObject::invokeMethod(this, "FinishInit", Qt::QueuedConnection); return true; } QVariant OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, const VideoParams& params, const RenderMode::Mode& mode) { ImageStreamPtr video_stream = std::static_pointer_cast(stream); // Set up OCIO context QString colorspace_match = video_stream->get_colorspace_match_string(); OpenGLColorProcessorPtr color_processor = std::static_pointer_cast(color_cache_.value(colorspace_match)); if (!color_processor) { color_processor = OpenGLColorProcessor::Create(video_stream->footage()->project()->color_manager(), video_stream->colorspace(), video_stream->footage()->project()->color_manager()->GetReferenceColorSpace()); color_cache_.insert(colorspace_match, color_processor); } ColorManager::OCIOMethod ocio_method = ColorManager::GetOCIOMethodForMode(mode); // OCIO's CPU conversion is more accurate, so for online we render on CPU but offline we render GPU if (ocio_method == ColorManager::kOCIOAccurate) { bool has_alpha = PixelFormat::FormatHasAlphaChannel(frame->format()); // Convert frame to float for OCIO frame = PixelFormat::ConvertPixelFormat(frame, has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F); // If alpha is associated, disassociate for the color transform if (has_alpha && video_stream->premultiplied_alpha()) { ColorManager::DisassociateAlpha(frame); } // Perform color transform color_processor->ConvertFrame(frame); // Associate alpha if (has_alpha) { if (video_stream->premultiplied_alpha()) { ColorManager::ReassociateAlpha(frame); } else { ColorManager::AssociateAlpha(frame); } } } OpenGLTextureCache::ReferencePtr footage_tex_ref = texture_cache_.Get(ctx_, frame); if (ocio_method == ColorManager::kOCIOFast) { if (!color_processor->IsEnabled()) { color_processor->Enable(ctx_, video_stream->premultiplied_alpha()); } VideoParams frame_params = frame->video_params(); // Check frame aspect ratio if (frame->sample_aspect_ratio() != 1 && frame->sample_aspect_ratio() != 0) { int new_width = frame_params.width(); int new_height = frame_params.height(); // Scale the frame in a way that does not reduce the resolution if (frame->sample_aspect_ratio() > 1) { // Make wider new_width = qRound(static_cast(new_width) * frame->sample_aspect_ratio().toDouble()); } else { // Make taller new_height = qRound(static_cast(new_height) / frame->sample_aspect_ratio().toDouble()); } frame_params = VideoParams(new_width, new_height, frame_params.format(), frame_params.divider()); } PixelFormat::Format texture_fmt; if (PixelFormat::FormatHasAlphaChannel(frame_params.format())) { texture_fmt = PixelFormat::GetFormatWithAlphaChannel(params.format()); } else { texture_fmt = PixelFormat::GetFormatWithoutAlphaChannel(params.format()); } VideoParams dest_params(frame_params.width(), frame_params.height(), texture_fmt, frame_params.divider()); // Create destination texture OpenGLTextureCache::ReferencePtr associated_tex_ref = texture_cache_.Get(ctx_, dest_params); buffer_.Attach(associated_tex_ref->texture(), true); buffer_.Bind(); footage_tex_ref->texture()->Bind(); // Set viewport for texture size functions_->glViewport(0, 0, associated_tex_ref->texture()->width(), associated_tex_ref->texture()->height()); // Blit old texture to new texture through OCIO shader color_processor->ProcessOpenGL(); footage_tex_ref->texture()->Release(); buffer_.Release(); buffer_.Detach(); footage_tex_ref = associated_tex_ref; } return QVariant::fromValue(footage_tex_ref); } QVariant OpenGLProxy::PreCachedFrameToValue(FramePtr frame) { return QVariant::fromValue(texture_cache_.Get(ctx_, frame)); } OpenGLShaderPtr OpenGLProxy::ResolveShaderFromCache(const Node *node, const QString &shader_id) { // Make a composite of the node ID and the shader ID (if applicable) QString full_shader_id = QStringLiteral("%1:%2").arg(node->id(), shader_id); OpenGLShaderPtr shader = shader_cache_.value(full_shader_id); if (!shader) { // Since we have shader code, compile it now ShaderCode code = node->GetShaderCode(shader_id); QString vert_code = code.vert_code(); QString frag_code = code.frag_code(); if (frag_code.isEmpty() && vert_code.isEmpty()) { qWarning() << "No shader code found for" << node->id() << "- operation will be a no-op"; } if (frag_code.isEmpty()) { frag_code = OpenGLShader::CodeDefaultFragment(); } if (vert_code.isEmpty()) { vert_code = OpenGLShader::CodeDefaultVertex(); } shader = OpenGLShader::Create(); if (shader && shader->create() && shader->addShaderFromSourceCode(QOpenGLShader::Fragment, frag_code) && shader->addShaderFromSourceCode(QOpenGLShader::Vertex, vert_code) && shader->link()) { shader_cache_.insert(full_shader_id, shader); } else { qWarning() << "Failed to compile shader for" << node->id(); shader = nullptr; } } return shader; } void OpenGLProxy::Close() { shader_cache_.clear(); buffer_.Destroy(); copy_pipeline_ = nullptr; functions_ = nullptr; delete ctx_; ctx_ = nullptr; } QVariant OpenGLProxy::RunNodeAccelerated(const Node *node, const TimeRange &range, const ShaderJob &job, const VideoParams& params) { // If this node is iterative, we'll pick up which input here GLuint iterative_input = 0; QList textures_to_bind; bool input_textures_have_alpha = false; OpenGLShaderPtr shader = ResolveShaderFromCache(node, job.GetShaderID()); if (!shader) { return QVariant(); } shader->bind(); NodeValueMap::const_iterator it; for (it=job.GetValues().constBegin(); it!=job.GetValues().constEnd(); it++) { // See if the shader has takes this parameter as an input int variable_location = shader->uniformLocation(it.key()); if (variable_location == -1) { continue; } // See if this value corresponds to an input (NOTE: it may not and this may be null) NodeInput* corresponding_input = node->GetInputWithID(it.key()); // This variable is used in the shader, let's set it const QVariant& value = it.value().data(); NodeParam::DataType data_type = (it.value().type() != NodeParam::kNone) ? it.value().type() : corresponding_input->data_type(); switch (data_type) { case NodeInput::kInt: shader->setUniformValue(variable_location, value.toInt()); break; case NodeInput::kFloat: shader->setUniformValue(variable_location, value.toFloat()); break; case NodeInput::kVec2: if (corresponding_input && corresponding_input->IsArray()) { QVector nv = value.value< QVector >(); QVector a(nv.size()); for (int j=0;j(); } shader->setUniformValueArray(variable_location, a.constData(), a.size()); int count_location = shader->uniformLocation(QStringLiteral("%1_count").arg(it.key())); if (count_location > -1) { shader->setUniformValue(count_location, a.size()); } } else { shader->setUniformValue(variable_location, value.value()); } break; case NodeInput::kVec3: shader->setUniformValue(variable_location, value.value()); break; case NodeInput::kVec4: shader->setUniformValue(variable_location, value.value()); break; case NodeInput::kMatrix: shader->setUniformValue(variable_location, value.value()); break; case NodeInput::kCombo: shader->setUniformValue(variable_location, value.value()); break; case NodeInput::kColor: { Color color = value.value(); shader->setUniformValue(variable_location, color.red(), color.green(), color.blue(), color.alpha()); break; } case NodeInput::kBoolean: shader->setUniformValue(variable_location, value.toBool()); break; case NodeInput::kBuffer: case NodeInput::kTexture: { OpenGLTextureCache::ReferencePtr texture = value.value(); if (texture) { if (PixelFormat::FormatHasAlphaChannel(texture->texture()->format())) { input_textures_have_alpha = true; } } // Set value to bound texture shader->setUniformValue(variable_location, textures_to_bind.size()); // If this texture binding is the iterative input, set it here if (corresponding_input && corresponding_input == job.GetIterativeInput()) { iterative_input = textures_to_bind.size(); } GLuint tex_id = texture ? texture->texture()->texture() : 0; textures_to_bind.append(tex_id); // Set enable flag if shader wants it int enable_param_location = shader->uniformLocation(QStringLiteral("%1_enabled").arg(it.key())); if (enable_param_location > -1) { shader->setUniformValue(enable_param_location, tex_id > 0); } if (tex_id > 0) { // Set texture resolution if shader wants it int res_param_location = shader->uniformLocation(QStringLiteral("%1_resolution").arg(it.key())); if (res_param_location > -1) { shader->setUniformValue(res_param_location, static_cast(texture->texture()->width() * texture->texture()->divider()), static_cast(texture->texture()->height() * texture->texture()->divider())); } } break; } case NodeInput::kSamples: case NodeInput::kText: case NodeInput::kRational: case NodeInput::kFont: case NodeInput::kFile: case NodeInput::kDecimal: case NodeInput::kNumber: case NodeInput::kString: case NodeInput::kVector: case NodeInput::kShaderJob: case NodeInput::kSampleJob: case NodeInput::kGenerateJob: case NodeInput::kFootage: case NodeInput::kNone: case NodeInput::kAny: break; } } // Provide some standard args shader->setUniformValue("ove_resolution", static_cast(params.width()), static_cast(params.height())); shader->release(); // Create the output textures PixelFormat::Format output_format = (input_textures_have_alpha || job.GetAlphaChannelRequired()) ? PixelFormat::GetFormatWithAlphaChannel(params.format()) : PixelFormat::GetFormatWithoutAlphaChannel(params.format()); VideoParams output_params(params.width(), params.height(), params.time_base(), output_format, params.divider()); int real_iteration_count; if (job.GetIterationCount() > 1 && job.GetIterativeInput()) { real_iteration_count = job.GetIterationCount(); } else { real_iteration_count = 1; } OpenGLTextureCache::ReferencePtr dst_refs[2]; dst_refs[0] = texture_cache_.Get(ctx_, output_params); // If this node requires multiple iterations, get a texture for it too if (real_iteration_count > 1) { dst_refs[1] = texture_cache_.Get(ctx_, output_params); } // Some nodes use multiple iterations for optimization OpenGLTextureCache::ReferencePtr input_tex, output_tex; // Set up OpenGL parameters as necessary functions_->glViewport(0, 0, params.effective_width(), params.effective_height()); // Bind all textures for (int i=0; iglActiveTexture(GL_TEXTURE0 + i); functions_->glBindTexture(GL_TEXTURE_2D, textures_to_bind.at(i)); OpenGLRenderFunctions::PrepareToDraw(functions_); } for (int iteration=0; iterationbind(); shader->setUniformValue("ove_iteration", iteration); shader->release(); // Replace iterative input if (iteration == 0) { output_tex = dst_refs[0]; } else { input_tex = dst_refs[(iteration+1)%2]; output_tex = dst_refs[iteration%2]; functions_->glActiveTexture(GL_TEXTURE0 + iterative_input); functions_->glBindTexture(GL_TEXTURE_2D, input_tex->texture()->texture()); OpenGLRenderFunctions::PrepareToDraw(functions_); } buffer_.Attach(output_tex->texture(), true); buffer_.Bind(); // Blit this texture through this shader OpenGLRenderFunctions::Blit(shader); buffer_.Release(); buffer_.Detach(); } // Release any textures we bound before for (int i=textures_to_bind.size()-1; i>=0; i--) { functions_->glActiveTexture(GL_TEXTURE0 + i); functions_->glBindTexture(GL_TEXTURE_2D, 0); } return QVariant::fromValue(output_tex); } void OpenGLProxy::TextureToBuffer(const QVariant& tex_in, FramePtr frame, const QMatrix4x4& matrix) { OpenGLTextureCache::ReferencePtr texture = tex_in.value(); if (!texture) { return; } OpenGLTextureCache::ReferencePtr download_tex; functions_->glViewport(0, 0, frame->width(), frame->height()); if (frame->width() != texture->texture()->width() || frame->height() != texture->texture()->height()) { // Resize the texture if necessary OpenGLTextureCache::ReferencePtr resized = texture_cache_.Get(ctx_, frame->video_params()); buffer_.Attach(resized->texture(), true); buffer_.Bind(); texture->texture()->Bind(); // Blit to this new texture OpenGLRenderFunctions::Blit(copy_pipeline_, false, matrix); texture->texture()->Release(); buffer_.Release(); buffer_.Detach(); download_tex = resized; } else { download_tex = texture; } buffer_.Attach(download_tex->texture()); buffer_.Bind(); functions_->glPixelStorei(GL_PACK_ROW_LENGTH, frame->linesize_pixels()); functions_->glReadPixels(0, 0, frame->width(), frame->height(), OpenGLRenderFunctions::GetPixelFormat(frame->format()), OpenGLRenderFunctions::GetPixelType(frame->format()), frame->data()); functions_->glPixelStorei(GL_PACK_ROW_LENGTH, 0); buffer_.Release(); buffer_.Detach(); } void OpenGLProxy::FinishInit() { // Make context current on that surface if (!ctx_->makeCurrent(&surface_)) { qWarning() << "Failed to makeCurrent() on offscreen surface in thread" << thread(); return; } // Store OpenGL functions instance functions_ = ctx_->functions(); functions_->glBlendFunc(GL_ONE, GL_ZERO); buffer_.Create(ctx_); copy_pipeline_ = OpenGLShader::CreateDefault(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglproxy.h000066400000000000000000000102171370472574300240660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLPROXY_H #define OPENGLPROXY_H #include #include #include "common/timerange.h" #include "node/value.h" #include "openglcolorprocessor.h" #include "openglframebuffer.h" #include "opengltexturecache.h" #include "render/shaderinfo.h" OLIVE_NAMESPACE_ENTER class OpenGLProxy : public QObject { Q_OBJECT public: OpenGLProxy(QObject* parent = nullptr); virtual ~OpenGLProxy() override; static void CreateInstance(); static void DestroyInstance(); static OpenGLProxy* instance() { return instance_; } /** * @brief Initialize OpenGL instance in whatever thread this object is a part of * * This function creates a context (shared with share_ctx provided in the constructor) as well as various other * OpenGL thread-specific objects necessary for rendering. This function should only ever be called from the main * thread (i.e. the thread where share_ctx is current on) but AFTER this object has been pushed to its thread with * moveToThread(). If this function is called from a different thread, it could fail or even segfault on some * platforms. * * The reason this function must be called in the main thread (rather than initializing asynchronously in a separate * thread) is because different platforms have different rules about creating a share context with a context that * is still "current" in another thread. While some implementations do allow this, Windows OpenGL (wgl) explicitly * forbids it and other platforms/drivers will segfault attempting it. While we can obviously call "doneCurrent", I * haven't found any reliable way to prevent the main thread from making it current again before initialization is * complete other than blocking it entirely. * * To get around this, we create all share contexts in the main thread and then move them to the other thread * afterwards (which is completely legal). While annoying, this gets around the issue listed above by both preventing * the main thread from using the context during initialization and preventing more than one shared context being made * at the same time (which may or may not actually make a difference). */ bool Init(); void Close(); public slots: QVariant RunNodeAccelerated(const OLIVE_NAMESPACE::Node *node, const OLIVE_NAMESPACE::TimeRange &range, const OLIVE_NAMESPACE::ShaderJob &job, const OLIVE_NAMESPACE::VideoParams ¶ms); void TextureToBuffer(const QVariant& texture, OLIVE_NAMESPACE::FramePtr frame, const QMatrix4x4& matrix); QVariant FrameToValue(OLIVE_NAMESPACE::FramePtr frame, OLIVE_NAMESPACE::StreamPtr stream, const OLIVE_NAMESPACE::VideoParams ¶ms, const OLIVE_NAMESPACE::RenderMode::Mode &mode); QVariant PreCachedFrameToValue(OLIVE_NAMESPACE::FramePtr frame); private: OpenGLShaderPtr ResolveShaderFromCache(const Node* node, const QString &shader_id); QOpenGLContext* ctx_; QOffscreenSurface surface_; QOpenGLFunctions* functions_; OpenGLFramebuffer buffer_; OpenGLColorProcessorCache color_cache_; OpenGLShaderPtr copy_pipeline_; QHash shader_cache_; OpenGLTextureCache texture_cache_; static OpenGLProxy* instance_; private slots: void FinishInit(); }; OLIVE_NAMESPACE_EXIT #endif // OPENGLPROXY_H olive-continuous/app/render/backend/opengl/openglrenderfunctions.cpp000066400000000000000000000140071370472574300264510ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglrenderfunctions.h" #include #include #include OLIVE_NAMESPACE_ENTER const QVector blit_vertices = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f }; const QVector blit_texcoords = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }; const QVector flipped_blit_texcoords = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; /** * @brief Set up texture parameters and mipmap for drawing * * Internal function used just before drawing to allow mipmapped bilinear filtering when drawing textures small. * * @param f * * Currently active QOpenGLFunctions object (use context()->functions() if unsure). */ void OpenGLRenderFunctions::PrepareToDraw(QOpenGLFunctions* f) { f->glGenerateMipmap(GL_TEXTURE_2D); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } GLint OpenGLRenderFunctions::GetInternalFormat(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGB8: return GL_RGB8; case PixelFormat::PIX_FMT_RGBA8: return GL_RGBA8; case PixelFormat::PIX_FMT_RGB16U: return GL_RGB16; case PixelFormat::PIX_FMT_RGBA16U: return GL_RGBA16; case PixelFormat::PIX_FMT_RGB16F: return GL_RGB16F; case PixelFormat::PIX_FMT_RGBA16F: return GL_RGBA16F; case PixelFormat::PIX_FMT_RGB32F: return GL_RGB32F; case PixelFormat::PIX_FMT_RGBA32F: return GL_RGBA32F; case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return GL_INVALID_VALUE; } GLenum OpenGLRenderFunctions::GetPixelFormat(const PixelFormat::Format &format) { if (PixelFormat::FormatHasAlphaChannel(format)) { return GL_RGBA; } else { return GL_RGB; } } GLenum OpenGLRenderFunctions::GetPixelType(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGBA8: return GL_UNSIGNED_BYTE; case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGBA16U: return GL_UNSIGNED_SHORT; case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGBA16F: return GL_HALF_FLOAT; case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_RGBA32F: return GL_FLOAT; case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return GL_INVALID_VALUE; } void OpenGLRenderFunctions::Blit(OpenGLShaderPtr pipeline, bool flipped, QMatrix4x4 matrix) { Blit(pipeline.get(), flipped, matrix); } void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, bool flipped, QMatrix4x4 matrix) { Blit(pipeline, GL_TRIANGLES, blit_vertices, flipped ? flipped_blit_texcoords : blit_texcoords, matrix); } void OpenGLRenderFunctions::Blit(OpenGLShader *pipeline, GLenum mode, const QVector &vert, const QVector &tex, QMatrix4x4 matrix) { QOpenGLFunctions* func = QOpenGLContext::currentContext()->functions(); PrepareToDraw(func); QOpenGLVertexArrayObject m_vao; m_vao.create(); m_vao.bind(); QOpenGLBuffer m_vbo; m_vbo.create(); m_vbo.bind(); m_vbo.allocate(vert.constData(), vert.size() * sizeof(GLfloat)); m_vbo.release(); QOpenGLBuffer m_vbo2; m_vbo2.create(); m_vbo2.bind(); m_vbo2.allocate(tex.constData(), tex.size() * sizeof(GLfloat)); m_vbo2.release(); pipeline->bind(); pipeline->setUniformValue("ove_mvpmat", matrix); pipeline->setUniformValue("ove_maintex", 0); int vertex_location = pipeline->attributeLocation("a_position"); m_vbo.bind(); func->glEnableVertexAttribArray(vertex_location); func->glVertexAttribPointer(vertex_location, 3, GL_FLOAT, GL_FALSE, 0, nullptr); m_vbo.release(); int tex_location = pipeline->attributeLocation("a_texcoord"); m_vbo2.bind(); func->glEnableVertexAttribArray(tex_location); func->glVertexAttribPointer(tex_location, 2, GL_FLOAT, GL_FALSE, 0, nullptr); m_vbo2.release(); // (Size / 3) because we assume each GLfloat has an XYZ pair func->glDrawArrays(mode, 0, blit_vertices.size() / 3); pipeline->release(); m_vbo2.destroy(); m_vbo.destroy(); m_vao.release(); m_vao.destroy(); } void OpenGLRenderFunctions::OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped, QMatrix4x4 matrix) { OCIOBlit(pipeline.get(), lut, flipped, matrix); } void OpenGLRenderFunctions::OCIOBlit(OpenGLShader *pipeline, GLuint lut, bool flipped, QMatrix4x4 matrix) { QOpenGLContext* ctx = QOpenGLContext::currentContext(); QOpenGLExtraFunctions* xf = ctx->extraFunctions(); xf->glActiveTexture(GL_TEXTURE1); xf->glBindTexture(GL_TEXTURE_3D, lut); xf->glActiveTexture(GL_TEXTURE0); pipeline->bind(); pipeline->setUniformValue("ove_ociolut", 1); Blit(pipeline, flipped, matrix); pipeline->release(); xf->glActiveTexture(GL_TEXTURE1); xf->glBindTexture(GL_TEXTURE_3D, 0); xf->glActiveTexture(GL_TEXTURE0); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglrenderfunctions.h000066400000000000000000000042111370472574300261120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLFUNCTIONS_H #define OPENGLFUNCTIONS_H #include #include #include #include "openglshader.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER class OpenGLRenderFunctions { public: /** * @brief Draw texture on screen * * @param pipeline * * Shader to use for the texture drawing * * @param flipped * * Draw the texture vertically flipped (defaults to FALSE) * * @param matrix * * Transformation matrix to use when drawing (defaults to no transform) */ static void Blit(OpenGLShaderPtr pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); static void Blit(OpenGLShader* pipeline, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); static void Blit(OpenGLShader* pipeline, GLenum mode, const QVector& vert, const QVector& tex, QMatrix4x4 matrix = QMatrix4x4()); static void OCIOBlit(OpenGLShaderPtr pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); static void OCIOBlit(OpenGLShader* pipeline, GLuint lut, bool flipped = false, QMatrix4x4 matrix = QMatrix4x4()); static void PrepareToDraw(QOpenGLFunctions* f); static GLint GetInternalFormat(const PixelFormat::Format& format); static GLenum GetPixelFormat(const PixelFormat::Format& format); static GLenum GetPixelType(const PixelFormat::Format& format); }; OLIVE_NAMESPACE_EXIT #endif // OPENGLFUNCTIONS_H olive-continuous/app/render/backend/opengl/openglshader.cpp000066400000000000000000000224541370472574300245140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglshader.h" #include OLIVE_NAMESPACE_ENTER OpenGLShaderPtr OpenGLShader::Create() { return std::make_shared(); } OpenGLShaderPtr OpenGLShader::CreateDefault(const QString &function_name, const QString &shader_code) { OpenGLShaderPtr program = Create(); // Add shaders to program program->addShaderFromSourceCode(QOpenGLShader::Vertex, CodeDefaultVertex()); program->addShaderFromSourceCode(QOpenGLShader::Fragment, CodeDefaultFragment(function_name, shader_code)); program->link(); return program; } // copied from source code to OCIODisplay const int OCIO_LUT3D_EDGE_SIZE = 64; // copied from source code to OCIODisplay, expanded from 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE const int OCIO_NUM_3D_ENTRIES = 3*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE*OCIO_LUT3D_EDGE_SIZE; OpenGLShaderPtr OpenGLShader::CreateOCIO(QOpenGLContext* ctx, GLuint& lut_texture, OCIO::ConstProcessorRcPtr processor, bool alpha_is_associated) { QOpenGLExtraFunctions* xf = ctx->extraFunctions(); // Set up shader description OCIO::GpuShaderDesc shaderDesc; const char* ocio_func_name = "OCIODisplay"; shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_3); shaderDesc.setFunctionName(ocio_func_name); shaderDesc.setLut3DEdgeLen(OCIO_LUT3D_EDGE_SIZE); // Compute LUT std::vector ocio_lut_data(OCIO_NUM_3D_ENTRIES); processor->getGpuLut3D(&ocio_lut_data[0], shaderDesc); // Create LUT texture xf->glGenTextures(1, &lut_texture); // Bind LUT xf->glActiveTexture(GL_TEXTURE1); xf->glBindTexture(GL_TEXTURE_3D, lut_texture); // Set texture parameters xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); xf->glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Allocate storage for texture xf->glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, OCIO_LUT3D_EDGE_SIZE, 0, GL_RGB, GL_FLOAT, &ocio_lut_data[0]); // Create OCIO shader code QString shader_text; // Workaround since OCIO doesn't support the GLSL version we use shader_text.append(QStringLiteral("#define texture2D texture\n" "#define texture3D texture\n")); // Append OCIO shader code shader_text.append(processor->getGpuShaderText(shaderDesc)); QString shader_call; // Enforce alpha association if (alpha_is_associated) { // If alpha is already associated, we'll need to disassociate and reassociate shader_text.append("\n"); QString disassociate_func_name = "disassoc"; shader_text.append(CodeAlphaDisassociate(disassociate_func_name)); QString reassociate_func_name = "reassoc"; shader_text.append(CodeAlphaReassociate(reassociate_func_name)); // Make OCIO call pass through disassociate and reassociate function shader_call = QStringLiteral("%3(%1(%2(col), ove_ociolut));").arg(ocio_func_name, disassociate_func_name, reassociate_func_name); } else { // If alpha is not already associated, we can just associate after OCIO // Add associate function QString associate_func_name = "assoc"; shader_text.append(CodeAlphaAssociate(associate_func_name)); // Make OCIO call pass through associate function shader_call = QStringLiteral("%2(%1(col, ove_ociolut));").arg(ocio_func_name, associate_func_name); } // Add process() function, which GetPipeline() will call if specified QString process_function_name = "process"; shader_text.append(QStringLiteral("\n" "uniform sampler3D ove_ociolut;\n" "\n" "vec4 %2(vec4 col) {\n" " return %1\n" "}\n").arg(shader_call, process_function_name)); // Get pipeline-based shader to inject OCIO shader into OpenGLShaderPtr shader = OpenGLShader::CreateDefault(process_function_name, shader_text); // Release LUT xf->glBindTexture(GL_TEXTURE_3D, 0); xf->glActiveTexture(GL_TEXTURE0); return shader; } QString OpenGLShader::CodeDefaultFragment(const QString &function_name, const QString &shader_code) { QString frag_code = QStringLiteral("#version 150\n" "\n" "#ifdef GL_ES\n" "precision highp int;\n" "precision highp float;\n" "#endif\n" "\n" "uniform sampler2D ove_maintex;\n" "uniform bool color_only;\n" "uniform vec4 color_only_color;\n" "\n" "in vec2 ove_texcoord;\n" "\n" "out vec4 fragColor;\n" "\n"); // Finish the function with the main function // Check if additional code was passed to this function, add it here if (shader_code.isEmpty()) { // If not, just add a pure main() function frag_code.append(QStringLiteral("\n" "void main() {\n" " if (color_only) {\n" " fragColor = color_only_color;" " } else {\n" " vec4 color = texture(ove_maintex, ove_texcoord);\n" " fragColor = color;\n" " }\n" "}\n")); } else { // If additional code was passed, add it and reference it in main(). // // The function in the additional code is expected to be `vec4 function_name(vec4 color)`. The texture coordinate // can be acquired through `ove_texcoord`. frag_code.append(shader_code); frag_code.append(QStringLiteral("\n" "void main() {\n" " vec4 color = %1(texture(ove_maintex, ove_texcoord));\n" " fragColor = color;\n" "}\n").arg(function_name)); } return frag_code; } QString OpenGLShader::CodeDefaultVertex() { // Generate vertex shader return QStringLiteral("#version 150\n" "\n" "#ifdef GL_ES\n" "precision highp int;\n" "precision highp float;\n" "#endif\n" "\n" "uniform mat4 ove_mvpmat;\n" "\n" "in vec4 a_position;\n" "in vec2 a_texcoord;\n" "\n" "out vec2 ove_texcoord;\n" "\n" "void main() {\n" " gl_Position = ove_mvpmat * a_position;\n" " ove_texcoord = a_texcoord;\n" "}\n"); } QString OpenGLShader::CodeAlphaDisassociate(const QString &function_name) { return QStringLiteral("vec4 %1(vec4 col) {\n" " if (col.a > 0.0) {\n" " return vec4(col.rgb / col.a, col.a);" " }\n" " return col;\n" "}\n").arg(function_name); } QString OpenGLShader::CodeAlphaReassociate(const QString &function_name) { return QStringLiteral("vec4 %1(vec4 col) {\n" " if (col.a > 0.0) {\n" " return vec4(col.rgb * col.a, col.a);" " }\n" " return col;\n" "}\n").arg(function_name); } QString OpenGLShader::CodeAlphaAssociate(const QString &function_name) { return QStringLiteral("vec4 %1(vec4 col) {\n" " return vec4(col.rgb * col.a, col.a);\n" "}\n").arg(function_name); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglshader.h000066400000000000000000000040601370472574300241520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLSHADER_H #define OPENGLSHADER_H #include #include #include namespace OCIO = OCIO_NAMESPACE::v1; #include "common/define.h" OLIVE_NAMESPACE_ENTER class OpenGLShader; using OpenGLShaderPtr = std::shared_ptr; /** * @brief A simple QOpenGLShaderProgram derivative with static functions for creating */ class OpenGLShader : public QOpenGLShaderProgram { public: OpenGLShader() = default; static OpenGLShaderPtr Create(); static OpenGLShaderPtr CreateDefault(const QString &function_name = QString(), const QString &shader_code = QString()); static OpenGLShaderPtr CreateOCIO(QOpenGLContext* ctx, GLuint& lut_texture, OCIO::ConstProcessorRcPtr processor, bool alpha_is_associated); static QString CodeDefaultFragment(const QString &function_name = QString(), const QString &shader_code = QString()); static QString CodeDefaultVertex(); static QString CodeAlphaDisassociate(const QString& function_name); static QString CodeAlphaReassociate(const QString& function_name); static QString CodeAlphaAssociate(const QString& function_name); }; OLIVE_NAMESPACE_EXIT #endif // OPENGLSHADER_H olive-continuous/app/render/backend/opengl/opengltexture.cpp000066400000000000000000000116311370472574300247410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "opengltexture.h" #include #include #include #include "openglrenderfunctions.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER OpenGLTexture::OpenGLTexture() : created_ctx_(nullptr), texture_(0) { } OpenGLTexture::~OpenGLTexture() { Destroy(); } bool OpenGLTexture::IsCreated() const { return (texture_); } void OpenGLTexture::Create(QOpenGLContext *ctx, const VideoParams ¶ms, const void* data, int linesize) { if (!ctx) { qWarning() << "OpenGLTexture::Create was passed an invalid context"; return; } Destroy(); created_ctx_ = ctx; params_ = params; connect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy()), Qt::DirectConnection); // Create main texture CreateInternal(created_ctx_, &texture_, data, linesize); } void OpenGLTexture::Create(QOpenGLContext *ctx, const VideoParams ¶ms) { Create(ctx, params, nullptr, 0); } void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame) { Create(ctx, frame.get()); } void OpenGLTexture::Create(QOpenGLContext *ctx, Frame *frame) { Create(ctx, frame->video_params(), frame->data(), frame->linesize_pixels()); } void OpenGLTexture::Destroy() { if (created_ctx_) { disconnect(created_ctx_, SIGNAL(aboutToBeDestroyed()), this, SLOT(Destroy())); created_ctx_->functions()->glDeleteTextures(1, &texture_); texture_ = 0; created_ctx_ = nullptr; } } void OpenGLTexture::Bind() { created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, texture_); } void OpenGLTexture::Release() { created_ctx_->functions()->glBindTexture(GL_TEXTURE_2D, 0); } const int &OpenGLTexture::width() const { return params_.effective_width(); } const int &OpenGLTexture::height() const { return params_.effective_height(); } const PixelFormat::Format &OpenGLTexture::format() const { return params_.format(); } const GLuint &OpenGLTexture::texture() const { return texture_; } const int &OpenGLTexture::divider() const { return params_.divider(); } void OpenGLTexture::Upload(FramePtr frame) { Upload(frame.get()); } void OpenGLTexture::Upload(Frame *frame) { Upload(frame->data(), frame->linesize_pixels()); } void OpenGLTexture::Upload(const void *data, int linesize) { if (!IsCreated()) { qWarning() << "OpenGLTexture::Upload() called while it wasn't created"; return; } Bind(); created_ctx_->functions()->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); created_ctx_->functions()->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width(), height(), OpenGLRenderFunctions::GetPixelFormat(format()), OpenGLRenderFunctions::GetPixelType(format()), data); created_ctx_->functions()->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); Release(); } void OpenGLTexture::CreateInternal(QOpenGLContext* create_ctx, GLuint* tex, const void *data, int linesize) { QOpenGLFunctions* f = create_ctx->functions(); // Create texture f->glGenTextures(1, tex); // Verify texture if (texture_ == 0) { qWarning() << "OpenGL texture creation failed"; return; } // Bind texture f->glBindTexture(GL_TEXTURE_2D, *tex); // Set linesize f->glPixelStorei(GL_UNPACK_ROW_LENGTH, linesize); // Allocate storage for texture f->glTexImage2D(GL_TEXTURE_2D, 0, OpenGLRenderFunctions::GetInternalFormat(format()), width(), height(), 0, OpenGLRenderFunctions::GetPixelFormat(format()), OpenGLRenderFunctions::GetPixelType(format()), data); // Return linesize to default f->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Set texture filtering to bilinear f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Release texture f->glBindTexture(GL_TEXTURE_2D, 0); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/opengltexture.h000066400000000000000000000040411370472574300244030ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLTEXTURE_H #define OPENGLTEXTURE_H #include #include #include "codec/frame.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER /** * @brief A class wrapper around an OpenGL texture */ class OpenGLTexture : public QObject { Q_OBJECT public: OpenGLTexture(); virtual ~OpenGLTexture() override; DISABLE_COPY_MOVE(OpenGLTexture) void Create(QOpenGLContext* ctx, const VideoParams& params, const void *data, int linesize); void Create(QOpenGLContext* ctx, const VideoParams& params); void Create(QOpenGLContext* ctx, FramePtr frame); void Create(QOpenGLContext* ctx, Frame* frame); bool IsCreated() const; void Bind(); void Release(); const int& width() const; const int& height() const; const PixelFormat::Format &format() const; const GLuint& texture() const; const int& divider() const; void Upload(FramePtr frame); void Upload(Frame* frame); void Upload(const void *data, int linesize); public slots: void Destroy(); private: void CreateInternal(QOpenGLContext *create_ctx, GLuint *tex, const void *data, int linesize); QOpenGLContext* created_ctx_; GLuint texture_; VideoParams params_; }; using OpenGLTexturePtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLTexturePtr) #endif // OPENGLTEXTURE_H olive-continuous/app/render/backend/opengl/opengltexturecache.cpp000066400000000000000000000056621370472574300257340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "opengltexturecache.h" OLIVE_NAMESPACE_ENTER OpenGLTextureCache::~OpenGLTextureCache() { foreach (Reference* ref, existing_references_) { ref->ParentKilled(); } } OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, FramePtr frame) { return Get(ctx, frame.get()); } OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, Frame *frame) { return Get(ctx, frame->video_params(), frame->data(), frame->linesize_pixels()); } OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext* ctx, const VideoParams ¶ms, const void *data, int linesize) { OpenGLTexturePtr texture = nullptr; lock_.lock(); // Iterate through textures and see if we have one that matches these parameters for (int i=0;iwidth() == params.effective_width() && test->height() == params.effective_height() && test->format() == params.format()) { texture = test; available_textures_.removeAt(i); break; } } // If we didn't find a texture, we'll need to create one if (!texture) { texture = std::make_shared(); texture->Create(ctx, params); } ReferencePtr ref = std::make_shared(this, texture); existing_references_.append(ref.get()); lock_.unlock(); if (data) { texture->Upload(data, linesize); } return ref; } OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoParams ¶ms) { return Get(ctx, params, nullptr, 0); } void OpenGLTextureCache::Relinquish(OpenGLTextureCache::Reference *ref) { OpenGLTexturePtr tex = ref->texture(); lock_.lock(); existing_references_.removeOne(ref); available_textures_.append(tex); lock_.unlock(); } OpenGLTextureCache::Reference::Reference(OpenGLTextureCache *parent, OpenGLTexturePtr texture) : parent_(parent), texture_(texture) { } OpenGLTextureCache::Reference::~Reference() { if (parent_) { parent_->Relinquish(this); } } OpenGLTexturePtr OpenGLTextureCache::Reference::texture() { return texture_; } void OpenGLTextureCache::Reference::ParentKilled() { parent_ = nullptr; } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/opengltexturecache.h000066400000000000000000000036341370472574300253760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLTEXTURECACHE_H #define OPENGLTEXTURECACHE_H #include #include "openglframebuffer.h" #include "opengltexture.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER class OpenGLTextureCache { public: class Reference { public: Reference(OpenGLTextureCache* parent, OpenGLTexturePtr texture); ~Reference(); DISABLE_COPY_MOVE(Reference) OpenGLTexturePtr texture(); void ParentKilled(); private: OpenGLTextureCache* parent_; OpenGLTexturePtr texture_; }; using ReferencePtr = std::shared_ptr; OpenGLTextureCache() = default; ~OpenGLTextureCache(); DISABLE_COPY_MOVE(OpenGLTextureCache) ReferencePtr Get(QOpenGLContext *ctx, FramePtr frame); ReferencePtr Get(QOpenGLContext *ctx, Frame* frame); ReferencePtr Get(QOpenGLContext *ctx, const VideoParams& params, const void *data, int linesize); ReferencePtr Get(QOpenGLContext *ctx, const VideoParams& params); private: void Relinquish(Reference* ref); QMutex lock_; QList available_textures_; QList existing_references_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::OpenGLTextureCache::ReferencePtr) #endif // OPENGLTEXTURECACHE_H olive-continuous/app/render/backend/opengl/openglworker.cpp000066400000000000000000000060731370472574300245560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "openglworker.h" OLIVE_NAMESPACE_ENTER OpenGLWorker::OpenGLWorker(RenderBackend *parent) : RenderWorker(parent) { } void OpenGLWorker::TextureToFrame(const QVariant &texture, FramePtr frame, const QMatrix4x4& mat) const { QMetaObject::invokeMethod(OpenGLProxy::instance(), "TextureToBuffer", Qt::BlockingQueuedConnection, Q_ARG(const QVariant&, texture), OLIVE_NS_ARG(FramePtr, frame), Q_ARG(const QMatrix4x4&, mat)); } QVariant OpenGLWorker::FootageFrameToTexture(StreamPtr stream, FramePtr frame) const { QVariant value; QMetaObject::invokeMethod(OpenGLProxy::instance(), "FrameToValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, value), OLIVE_NS_ARG(FramePtr, frame), OLIVE_NS_ARG(StreamPtr, stream), OLIVE_NS_CONST_ARG(VideoParams&, video_params()), OLIVE_NS_CONST_ARG(RenderMode::Mode&, render_mode())); return value; } QVariant OpenGLWorker::CachedFrameToTexture(FramePtr frame) const { QVariant value; QMetaObject::invokeMethod(OpenGLProxy::instance(), "PreCachedFrameToValue", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, value), OLIVE_NS_ARG(FramePtr, frame)); return value; } QVariant OpenGLWorker::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { QVariant value; QMetaObject::invokeMethod(OpenGLProxy::instance(), "RunNodeAccelerated", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QVariant, value), OLIVE_NS_CONST_ARG(Node*, node), OLIVE_NS_CONST_ARG(TimeRange&, range), OLIVE_NS_CONST_ARG(ShaderJob&, job), OLIVE_NS_CONST_ARG(VideoParams&, video_params())); return value; } bool OpenGLWorker::TextureHasAlpha(const QVariant &v) const { return PixelFormat::FormatHasAlphaChannel(v.value()->texture()->format()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/opengl/openglworker.h000066400000000000000000000026551370472574300242250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef OPENGLWORKER_H #define OPENGLWORKER_H #include "openglproxy.h" #include "render/backend/renderworker.h" OLIVE_NAMESPACE_ENTER class OpenGLWorker : public RenderWorker { public: OpenGLWorker(RenderBackend* parent); protected: virtual void TextureToFrame(const QVariant& texture, FramePtr frame, const QMatrix4x4 &mat) const override; virtual QVariant FootageFrameToTexture(StreamPtr stream, FramePtr frame) const override; virtual QVariant CachedFrameToTexture(FramePtr frame) const override; virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override; virtual bool TextureHasAlpha(const QVariant& v) const override; }; OLIVE_NAMESPACE_EXIT #endif // OPENGLWORKER_H olive-continuous/app/render/backend/renderbackend.cpp000066400000000000000000000323071370472574300233420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "renderbackend.h" #include #include #include "config/config.h" #include "core.h" #include "task/conform/conform.h" #include "task/taskmanager.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER RenderBackend::RenderBackend(QObject *parent) : QObject(parent), viewer_node_(nullptr), update_with_graph_(false), preview_job_time_(0), render_mode_(RenderMode::kOnline) { } RenderBackend::~RenderBackend() { Close(); } void RenderBackend::SetViewerNode(ViewerOutput *viewer_node) { if (viewer_node_ == viewer_node) { return; } ViewerOutput* old_viewer = viewer_node_; if (!viewer_node) { // If setting to null, set it here before we wait for jobs to finish viewer_node_ = viewer_node; } if (old_viewer) { // Delete all of our copied nodes pool_.clear(); pool_.waitForDone(); // Cancel all tickets foreach (RenderTicketPtr t, render_queue_) { t->Cancel(); } render_queue_.clear(); // Delete all the nodes foreach (Node* c, copy_map_) { c->deleteLater(); } copy_map_.clear(); copied_viewer_node_ = nullptr; graph_update_queue_.clear(); disconnect(old_viewer, &ViewerOutput::GraphChangedFrom, this, &RenderBackend::NodeGraphChanged); } if (viewer_node) { // If setting to non-null, set it now viewer_node_ = viewer_node; } if (viewer_node_) { // Copy graph copied_viewer_node_ = static_cast(viewer_node_->copy()); copy_map_.insert(viewer_node_, copied_viewer_node_); NodeGraphChanged(viewer_node_->texture_input()); NodeGraphChanged(viewer_node_->samples_input()); ProcessUpdateQueue(); if (update_with_graph_) { connect(viewer_node_, &ViewerOutput::GraphChangedFrom, this, &RenderBackend::NodeGraphChanged); } } } void RenderBackend::ClearVideoQueue() { foreach (RenderTicketPtr t, render_queue_) { t->Cancel(); } render_queue_.clear(); } RenderTicketPtr RenderBackend::Hash(const QVector ×) { if (!viewer_node_) { return nullptr; } RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeHash, QVariant::fromValue(times)); render_queue_.push_back(ticket); QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); return ticket; } RenderTicketPtr RenderBackend::RenderFrame(const rational &time) { if (!viewer_node_) { return nullptr; } RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, QVariant::fromValue(time)); render_queue_.push_back(ticket); QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); return ticket; } RenderTicketPtr RenderBackend::RenderAudio(const TimeRange &r) { if (!viewer_node_) { return nullptr; } RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeAudio, QVariant::fromValue(r)); render_queue_.push_back(ticket); QMetaObject::invokeMethod(this, "RunNextJob", Qt::QueuedConnection); return ticket; } void RenderBackend::SetVideoParams(const VideoParams ¶ms) { video_params_ = params; } void RenderBackend::SetAudioParams(const AudioParams ¶ms) { audio_params_ = params; } void RenderBackend::SetVideoDownloadMatrix(const QMatrix4x4 &mat) { video_download_matrix_ = mat; } std::list RenderBackend::SplitRangeIntoChunks(const TimeRange &r) { // FIXME: Magic number const int chunk_size = 2; std::list split_ranges; int start_time = qFloor(r.in().toDouble() / static_cast(chunk_size)) * chunk_size; int end_time = qCeil(r.out().toDouble() / static_cast(chunk_size)) * chunk_size; for (int i=start_time; iparentNode()); // If we don't have this node yet, assume it's coming in a later copy in which case it'll be // copied then if (!our_copy_node) { // Assert that there are updates coming Q_ASSERT(!graph_update_queue_.isEmpty()); return; } // If we're here, we must have this node. Determine if we're already copying a "parent" of this for (int i=0; iparentNode()->OutputsTo(queued_input, true)) { // In which case, no further copy is necessary return; } // Check if the source is a member of this array, in which case it'll be copied eventually anyway if (queued_input->IsArray() && static_cast(queued_input)->sub_params().contains(source)) { return; } // Check if this input supersedes an already queued input if (queued_input->parentNode()->OutputsTo(source, true) || (source->IsArray() && static_cast(source)->sub_params().contains(queued_input))) { // In which case, we don't need to queue it and can queue our own graph_update_queue_.removeAt(i); i--; } } graph_update_queue_.append(source); } void RenderBackend::Close() { SetViewerNode(nullptr); for (int i=0;ideleteLater(); } workers_.clear(); } void RenderBackend::RunNextJob() { // If queue is empty, nothing to be done if (render_queue_.empty()) { return; } // Check if params are valid if (!video_params_.is_valid() || !audio_params_.is_valid()) { qDebug() << "Failed to run job, parameters are invalid"; return; } // If we have a value update queued, check if all workers are available and proceed from there if (update_with_graph_ && !graph_update_queue_.isEmpty()) { bool all_workers_available = true; foreach (const WorkerData& data, workers_) { if (data.busy) { all_workers_available = false; break; } } if (all_workers_available) { // Process queue ProcessUpdateQueue(); } else { return; } } // If we have no workers allocated, allocate them now if (workers_.isEmpty()) { // Allocate workers here workers_.resize(pool_.maxThreadCount()); for (int i=0;iSetVideoParams(video_params_); worker->SetAudioParams(audio_params_); worker->SetVideoDownloadMatrix(video_download_matrix_); worker->SetRenderMode(render_mode_); if (preview_job_time_) { worker->EnablePreviewGeneration(viewer_node_->audio_playback_cache(), preview_job_time_); } worker->SetCopyMap(©_map_); RenderTicketPtr ticket = render_queue_.front(); render_queue_.pop_front(); switch (ticket->GetType()) { case RenderTicket::kTypeHash: QtConcurrent::run(&pool_, worker, &RenderWorker::Hash, ticket, copied_viewer_node_, ticket->GetTime().value >()); break; case RenderTicket::kTypeVideo: QtConcurrent::run(&pool_, worker, &RenderWorker::RenderFrame, ticket, copied_viewer_node_, ticket->GetTime().value()); break; case RenderTicket::kTypeAudio: QtConcurrent::run(&pool_, worker, &RenderWorker::RenderAudio, ticket, copied_viewer_node_, ticket->GetTime().value()); break; } if (render_queue_.empty()) { // No more jobs, can exit here break; } } } } //#define PRINT_UPDATE_QUEUE_INFO void RenderBackend::ProcessUpdateQueue() { #ifdef PRINT_UPDATE_QUEUE_INFO qint64 t = QDateTime::currentMSecsSinceEpoch(); qDebug() << "Processing update queue of" << graph_update_queue_.size() << "elements:"; #endif while (!graph_update_queue_.isEmpty()) { NodeInput* i = graph_update_queue_.takeFirst(); #ifdef PRINT_UPDATE_QUEUE_INFO qDebug() << " " << i->parentNode()->id() << i->id(); #endif CopyNodeInputValue(i); } #ifdef PRINT_UPDATE_QUEUE_INFO qDebug() << "Update queue took:" << (QDateTime::currentMSecsSinceEpoch() - t); #endif } void RenderBackend::WorkerFinished() { RenderWorker* worker = static_cast(sender()); // Set busy state to false for (int i=0;iparentNode()); NodeInput* our_copy = our_copy_node->GetInputWithID(input->id()); // Copy the standard/keyframe values between these two inputs NodeInput::CopyValues(input, our_copy, false, false); // Handle connections if (input->is_connected() || our_copy->is_connected()) { // If one of the inputs is connected, it's likely this change came from connecting or // disconnecting whatever was connected to it // We start by removing all old dependencies from the map QList old_deps = our_copy->GetExclusiveDependencies(); foreach (Node* i, old_deps) { copy_map_.take(copy_map_.key(i))->deleteLater(); } // And clear any other edges while (!our_copy->edges().isEmpty()) { NodeParam::DisconnectEdge(our_copy->edges().first()); } // Then we copy all node dependencies and connections (if there are any) CopyNodeMakeConnection(input, our_copy); } // Call on sub-elements too if (input->IsArray()) { foreach (NodeInput* i, static_cast(input)->sub_params()) { CopyNodeInputValue(i); } } } Node* RenderBackend::CopyNodeConnections(Node* src_node) { // Check if this node is already in the map Node* dst_node = copy_map_.value(src_node); // If not, create it now if (!dst_node) { dst_node = src_node->copy(); if (dst_node->IsTrack()) { // Hack that ensures the track type is set since we don't bother copying the whole timeline static_cast(dst_node)->set_track_type(static_cast(src_node)->track_type()); } copy_map_.insert(src_node, dst_node); } // Make sure its values are copied Node::CopyInputs(src_node, dst_node, false); // Copy all connections QList src_node_inputs = src_node->GetInputsIncludingArrays(); QList dst_node_inputs = dst_node->GetInputsIncludingArrays(); for (int i=0;iis_connected()) { Node* dst_node = CopyNodeConnections(src_input->get_connected_node()); NodeOutput* corresponding_output = dst_node->GetOutputWithID(src_input->get_connected_output()->id()); NodeParam::ConnectEdge(corresponding_output, dst_input); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/renderbackend.h000066400000000000000000000064061370472574300230100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERBACKEND_H #define RENDERBACKEND_H #include #include "dialog/rendercancel/rendercancel.h" #include "decodercache.h" #include "node/graph.h" #include "node/output/viewer/viewer.h" #include "render/backend/colorprocessorcache.h" #include "renderticket.h" #include "renderworker.h" OLIVE_NAMESPACE_ENTER class RenderBackend : public QObject { Q_OBJECT public: RenderBackend(QObject* parent = nullptr); virtual ~RenderBackend() override; void Close(); ViewerOutput* GetViewerNode() const { return viewer_node_; } void SetViewerNode(ViewerOutput* viewer_node); void SetUpdateWithGraph(bool e) { update_with_graph_ = e; } void SetRenderMode(RenderMode::Mode e) { render_mode_ = e; } void EnablePreviewGeneration(qint64 job_time) { preview_job_time_ = job_time; } void ClearVideoQueue(); void ProcessUpdateQueue(); /** * @brief Asynchronously generate a hash at a given time */ RenderTicketPtr Hash(const QVector ×); /** * @brief Asynchronously generate a frame at a given time */ RenderTicketPtr RenderFrame(const rational& time); /** * @brief Asynchronously generate a chunk of audio */ RenderTicketPtr RenderAudio(const TimeRange& r); const VideoParams& GetVideoParams() const { return video_params_; } const AudioParams& GetAudioParams() const { return audio_params_; } void SetVideoParams(const VideoParams& params); void SetAudioParams(const AudioParams& params); void SetVideoDownloadMatrix(const QMatrix4x4& mat); static std::list SplitRangeIntoChunks(const TimeRange& r); public slots: void NodeGraphChanged(NodeInput *source); protected: virtual RenderWorker* CreateNewWorker() = 0; private: void CopyNodeInputValue(NodeInput* input); Node *CopyNodeConnections(Node *src_node); void CopyNodeMakeConnection(NodeInput *src_input, NodeInput *dst_input); ViewerOutput* viewer_node_; // VIDEO MEMBERS VideoParams video_params_; QMatrix4x4 video_download_matrix_; // AUDIO MEMBERS AudioParams audio_params_; QList graph_update_queue_; QHash copy_map_; ViewerOutput* copied_viewer_node_; QThreadPool pool_; std::list render_queue_; struct WorkerData { RenderWorker* worker; bool busy; }; QVector workers_; bool update_with_graph_; qint64 preview_job_time_; RenderMode::Mode render_mode_; private slots: void WorkerFinished(); void RunNextJob(); }; OLIVE_NAMESPACE_EXIT #endif // RENDERBACKEND_H olive-continuous/app/render/backend/renderticket.cpp000066400000000000000000000033701370472574300232340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "renderticket.h" OLIVE_NAMESPACE_ENTER RenderTicket::RenderTicket(Type type, const QVariant &time) : finished_(false), cancelled_(false), time_(time), type_(type) { } void RenderTicket::WaitForFinished() { QMutexLocker locker(&lock_); if (!finished_) { wait_.wait(&lock_); } } QVariant RenderTicket::Get() { QMutexLocker locker(&lock_); if (!finished_) { wait_.wait(&lock_); } return result_; } bool RenderTicket::IsFinished(bool lock) { if (lock) { lock_.lock(); } bool finished = finished_; if (lock) { lock_.unlock(); } return finished; } bool RenderTicket::WasCancelled() { QMutexLocker locker(&lock_); return cancelled_; } void RenderTicket::Finish(QVariant result) { QMutexLocker locker(&lock_); finished_ = true; result_ = result; wait_.wakeAll(); locker.unlock(); emit Finished(); } void RenderTicket::Cancel() { QMutexLocker locker(&lock_); finished_ = true; cancelled_ = true; wait_.wakeAll(); locker.unlock(); emit Finished(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/renderticket.h000066400000000000000000000032241370472574300226770ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERTICKET_H #define RENDERTICKET_H #include #include #include "codec/frame.h" #include "codec/samplebuffer.h" #include "common/timerange.h" OLIVE_NAMESPACE_ENTER class RenderTicket : public QObject { Q_OBJECT public: enum Type { kTypeHash, kTypeVideo, kTypeAudio }; RenderTicket(Type type, const QVariant& time); const QVariant& GetTime() const { return time_; } Type GetType() const { return type_; } void WaitForFinished(); QVariant Get(); bool IsFinished(bool lock = true); bool WasCancelled(); QMutex* lock() { return &lock_; } void Finish(QVariant result); void Cancel(); signals: void Finished(); private: bool finished_; bool cancelled_; QVariant result_; QMutex lock_; QWaitCondition wait_; QVariant time_; Type type_; }; using RenderTicketPtr = std::shared_ptr; OLIVE_NAMESPACE_EXIT #endif // RENDERTICKET_H olive-continuous/app/render/backend/renderticketwatcher.cpp000066400000000000000000000034151370472574300246120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "renderticketwatcher.h" OLIVE_NAMESPACE_ENTER RenderTicketWatcher::RenderTicketWatcher(QObject *parent) : QObject(parent), ticket_(nullptr) { } void RenderTicketWatcher::SetTicket(RenderTicketPtr ticket) { // Ensure that a ticket has NOT already been set and that this ticket is NOT NULL Q_ASSERT(!ticket_ && ticket); ticket_ = ticket; QMutexLocker locker(ticket->lock()); if (ticket_->IsFinished(false)) { locker.unlock(); emit Finished(); } else { connect(ticket_.get(), &RenderTicket::Finished, this, &RenderTicketWatcher::Finished); } } bool RenderTicketWatcher::WasCancelled() { if (ticket_) { return ticket_->WasCancelled(); } else { return false; } } bool RenderTicketWatcher::IsFinished() { if (ticket_) { return ticket_->IsFinished(); } else { return false; } } void RenderTicketWatcher::WaitForFinished() { if (ticket_) { ticket_->WaitForFinished(); } } QVariant RenderTicketWatcher::Get() { if (ticket_) { return ticket_->Get(); } else { return QVariant(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/renderticketwatcher.h000066400000000000000000000022551370472574300242600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERTICKETWATCHER_H #define RENDERTICKETWATCHER_H #include "renderticket.h" OLIVE_NAMESPACE_ENTER class RenderTicketWatcher : public QObject { Q_OBJECT public: RenderTicketWatcher(QObject* parent = nullptr); void SetTicket(RenderTicketPtr ticket); bool WasCancelled(); bool IsFinished(); void WaitForFinished(); QVariant Get(); signals: void Finished(); private: RenderTicketPtr ticket_; }; OLIVE_NAMESPACE_EXIT #endif // RENDERTICKETWATCHER_H olive-continuous/app/render/backend/renderworker.cpp000066400000000000000000000340771370472574300232720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "renderworker.h" #include #include #include "audio/audiovisualwaveform.h" #include "common/functiontimer.h" #include "config/config.h" #include "node/block/clip/clip.h" #include "task/conform/conform.h" OLIVE_NAMESPACE_ENTER RenderWorker::RenderWorker(RenderBackend* parent) : parent_(parent), available_(true), audio_mode_is_preview_(false), preview_cache_(nullptr), render_mode_(RenderMode::kOnline) { } void RenderWorker::Hash(RenderTicketPtr ticket, ViewerOutput *viewer, const QVector ×) { QVector hashes(times.size()); for (int i=0;itexture_input()->get_connected_node(), video_params_, times.at(i)); } ticket->Finish(QVariant::fromValue(hashes)); emit FinishedJob(); } QByteArray RenderWorker::HashNode(const Node *n, const VideoParams ¶ms, const rational &time) { QCryptographicHash hasher(QCryptographicHash::Sha1); // Embed video parameters into this hash hasher.addData(reinterpret_cast(¶ms.effective_width()), sizeof(int)); hasher.addData(reinterpret_cast(¶ms.effective_height()), sizeof(int)); hasher.addData(reinterpret_cast(¶ms.format()), sizeof(PixelFormat::Format)); if (n) { n->Hash(hasher, time); } return hasher.result(); } void RenderWorker::RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, const rational &time) { NodeValueTable table = ProcessInput(viewer->texture_input(), TimeRange(time, time + video_params_.time_base())); QVariant texture = table.Get(NodeParam::kTexture); PixelFormat::Format output_format; if (!texture.isNull() && TextureHasAlpha(texture)) { output_format = PixelFormat::GetFormatWithAlphaChannel(video_params_.format()); } else { output_format = PixelFormat::GetFormatWithoutAlphaChannel(video_params_.format()); } FramePtr frame = Frame::Create(); frame->set_video_params(VideoParams(video_params_.width(), video_params_.height(), video_params_.time_base(), output_format, video_params_.divider())); frame->set_timestamp(time); frame->allocate(); if (texture.isNull()) { // Blank frame out memset(frame->data(), 0, frame->allocated_size()); } else { // Dump texture contents to frame TextureToFrame(texture, frame, video_download_matrix_); } ticket->Finish(QVariant::fromValue(frame)); emit FinishedJob(); } void RenderWorker::RenderAudio(RenderTicketPtr ticket, ViewerOutput* viewer, const TimeRange &range) { NodeValueTable table = ProcessInput(viewer->samples_input(), range); QVariant samples = table.Get(NodeParam::kSamples); ticket->Finish(samples); emit FinishedJob(); } NodeValueTable RenderWorker::GenerateBlockTable(const TrackOutput *track, const TimeRange &range) { if (track->track_type() == Timeline::kTrackTypeAudio) { QList active_blocks = track->BlocksAtTimeRange(range); // All these blocks will need to output to a buffer so we create one here SampleBufferPtr block_range_buffer = SampleBuffer::CreateAllocated(audio_params_, audio_params_.time_to_samples(range.length())); block_range_buffer->fill(0); NodeValueTable merged_table; // Loop through active blocks retrieving their audio foreach (Block* b, active_blocks) { TimeRange range_for_block(qMax(b->in(), range.in()), qMin(b->out(), range.out())); int destination_offset = audio_params_.time_to_samples(range_for_block.in() - range.in()); int max_dest_sz = audio_params_.time_to_samples(range_for_block.length()); // Destination buffer NodeValueTable table = GenerateTable(b, range_for_block); SampleBufferPtr samples_from_this_block = table.Take(NodeParam::kSamples).value(); if (!samples_from_this_block) { // If we retrieved no samples from this block, do nothing continue; } // Stretch samples here rational abs_speed = qAbs(b->speed()); if (abs_speed != 1) { samples_from_this_block->speed(abs_speed.toDouble()); } if (b->is_reversed()) { // Reverse the audio buffer samples_from_this_block->reverse(); } int copy_length = qMin(max_dest_sz, samples_from_this_block->sample_count()); // Copy samples into destination buffer block_range_buffer->set(samples_from_this_block->const_data(), destination_offset, copy_length); NodeValueTable::Merge({merged_table, table}); } if (preview_cache_) { // Find original track object TrackOutput* original_track = nullptr; QList valid_ranges = preview_cache_->GetValidRanges(range, preview_job_time_); if (!valid_ranges.isEmpty()) { QHash::const_iterator i; for (i=copy_map_->constBegin(); i!=copy_map_->constEnd(); i++) { if (i.value() == track) { original_track = static_cast(i.key()); break; } } // Generate visual waveform in this background thread if (original_track) { AudioVisualWaveform visual_waveform; visual_waveform.set_channel_count(audio_params_.channel_count()); visual_waveform.OverwriteSamples(block_range_buffer, audio_params_.sample_rate()); original_track->waveform_lock()->lock(); original_track->waveform().set_channel_count(audio_params_.channel_count()); foreach (const TimeRange& r, valid_ranges) { original_track->waveform().OverwriteSums(visual_waveform, r.in(), r.in() - range.in(), r.length()); } original_track->waveform_lock()->unlock(); emit original_track->PreviewChanged(); } } } merged_table.Push(NodeParam::kSamples, QVariant::fromValue(block_range_buffer), track); return merged_table; } else { return NodeTraverser::GenerateBlockTable(track, range); } } QVariant RenderWorker::ProcessSamples(const Node *node, const TimeRange &range, const SampleJob& job) { if (!job.samples() || !job.samples()->is_allocated()) { return QVariant(); } SampleBufferPtr output_buffer = SampleBuffer::CreateAllocated(job.samples()->audio_params(), job.samples()->sample_count()); NodeValueDatabase value_db; for (int i=0;isample_count();i++) { // Calculate the exact rational time at this sample double sample_to_second = static_cast(i) / static_cast(audio_params_.sample_rate()); rational this_sample_time = rational::fromDouble(range.in().toDouble() + sample_to_second); // Update all non-sample and non-footage inputs NodeValueMap::const_iterator j; for (j=job.GetValues().constBegin(); j!=job.GetValues().constEnd(); j++) { NodeValueTable value; NodeInput* corresponding_input = node->GetInputWithID(j.key()); if (corresponding_input) { value = ProcessInput(corresponding_input, TimeRange(this_sample_time, this_sample_time)); } else { value.Push(j.value()); } value_db.Insert(j.key(), value); } AddGlobalsToDatabase(value_db, TimeRange(this_sample_time, this_sample_time)); node->ProcessSamples(value_db, job.samples(), output_buffer, i); } return QVariant::fromValue(output_buffer); } QVariant RenderWorker::ProcessFrameGeneration(const Node* node, const GenerateJob &job) { FramePtr frame = Frame::Create(); PixelFormat::Format output_fmt; if (job.GetAlphaChannelRequired()) { output_fmt = PixelFormat::GetFormatWithAlphaChannel(video_params_.format()); } else { output_fmt = PixelFormat::GetFormatWithoutAlphaChannel(video_params_.format()); } frame->set_video_params(VideoParams(video_params_.width(), video_params_.height(), video_params_.time_base(), output_fmt, video_params_.divider())); frame->allocate(); node->GenerateFrame(frame, job); return CachedFrameToTexture(frame); } QVariant RenderWorker::GetCachedFrame(const Node* node, const rational& time) { if (node->id() == QStringLiteral("org.olivevideoeditor.Olive.videoinput")) { QByteArray hash = HashNode(node, video_params(), time); QString fn = FrameHashCache::CachePathName(hash); if (QFileInfo::exists(fn)) { FramePtr f = FrameHashCache::LoadCacheFrame(hash); if (f) { // The cached frame won't load with the correct divider by default, so we enforce it here f->set_video_params(VideoParams(f->width() * video_params_.divider(), f->height() * video_params_.divider(), f->video_params().time_base(), f->video_params().format(), video_params_.divider())); return CachedFrameToTexture(f); } } } return QVariant(); } DecoderPtr RenderWorker::ResolveDecoderFromInput(StreamPtr stream) { // Access a map of Node inputs and decoder instances and retrieve a frame! DecoderPtr decoder = decoder_cache_.value(stream.get()); if (!decoder && stream) { // Create a new Decoder here decoder = Decoder::CreateFromID(stream->footage()->decoder()); decoder->set_stream(stream); if (decoder->Open()) { decoder_cache_.insert(stream.get(), decoder); } else { decoder = nullptr; qWarning() << "Failed to open decoder for" << stream->footage()->filename() << "::" << stream->index(); } } return decoder; } QVariant RenderWorker::ProcessVideoFootage(StreamPtr stream, const rational &input_time) { ImageStreamPtr video_stream = std::static_pointer_cast(stream); rational time_match = (stream->type() == Stream::kImage) ? rational() : input_time; QString colorspace_match = video_stream->get_colorspace_match_string(); QVariant value; bool found_cache = false; if (still_image_cache_.contains(stream.get())) { const CachedStill& cs = still_image_cache_[stream.get()]; if (cs.colorspace == colorspace_match && cs.alpha_is_associated == video_stream->premultiplied_alpha() && cs.divider == video_params_.divider() && cs.time == time_match) { value = cs.texture; found_cache = true; } else { still_image_cache_.remove(stream.get()); } } if (!found_cache) { DecoderPtr decoder = ResolveDecoderFromInput(stream); if (decoder) { FramePtr frame = decoder->RetrieveVideo(input_time, video_params().divider()); if (frame) { // Return a texture from the derived class value = FootageFrameToTexture(stream, frame); if (!value.isNull()) { // Put this into the image cache instead still_image_cache_.insert(stream.get(), {value, colorspace_match, video_stream->premultiplied_alpha(), video_params_.divider(), time_match}); } } } } return value; } QVariant RenderWorker::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) { QVariant value; DecoderPtr decoder = ResolveDecoderFromInput(stream); if (decoder) { // See if we have a conformed version of this audio if (!decoder->HasConformedVersion(audio_params())) { // If not, check what audio mode we're in if (audio_mode_is_preview_) { // For preview, we report the conform is missing and finish the render without it // temporarily. The backend that picks up this signal will recache this section once the // conform is available. emit AudioConformUnavailable(decoder->stream(), audio_render_time_, input_time.out(), audio_params()); } else { // For online rendering/export, it's a waste of time to render the audio until we have // all we need, so we try to handle the conform ourselves AudioStreamPtr as = std::static_pointer_cast(stream); // Check if any other threads are conforming this audio if (as->try_start_conforming(audio_params())) { // If not, conform it ourselves decoder->ConformAudio(&IsCancelled(), audio_params()); } else { // If another thread is conforming already, hackily try to wait until it's done. do { QThread::msleep(1000); } while (!as->has_conformed_version(audio_params()) && !IsCancelled()); } } } if (decoder->HasConformedVersion(audio_params())) { SampleBufferPtr frame = decoder->RetrieveAudio(input_time.in(), input_time.length(), audio_params()); if (frame) { value = QVariant::fromValue(frame); } } } return value; } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/backend/renderworker.h000066400000000000000000000112641370472574300227300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERWORKER_H #define RENDERWORKER_H #include #include "decodercache.h" #include "node/traverser.h" #include "node/output/viewer/viewer.h" #include "renderticket.h" OLIVE_NAMESPACE_ENTER class RenderBackend; class RenderWorker : public QObject, public NodeTraverser { Q_OBJECT public: RenderWorker(RenderBackend* parent); bool IsAvailable() const { return available_; } void SetAvailable(bool a) { available_ = a; } void SetVideoParams(const VideoParams& params) { video_params_ = params; } void SetAudioParams(const AudioParams& params) { audio_params_ = params; } void SetVideoDownloadMatrix(const QMatrix4x4& mat) { video_download_matrix_ = mat; } void SetAudioModeIsPreview(bool audio_mode_is_preview) { audio_mode_is_preview_ = audio_mode_is_preview; } void SetCopyMap(QHash* copy_map) { copy_map_ = copy_map; } void SetRenderMode(const RenderMode::Mode& mode) { render_mode_ = mode; } void EnablePreviewGeneration(AudioPlaybackCache* cache, qint64 job_time) { preview_cache_ = cache; preview_job_time_ = job_time; } void Hash(RenderTicketPtr ticket, ViewerOutput* viewer, const QVector& times); /** * @brief Render the frame at this time * * Produces a fully rendered frame from the connected viewer at this time. * * @return * * A frame corresponding to the set video parameters. If no nodes are active at the time, this * function will still return a blank frame with the same parameters. If no viewer node is set, * nullptr is returned. */ void RenderFrame(RenderTicketPtr ticket, ViewerOutput* viewer, const rational &time); void RenderAudio(RenderTicketPtr ticket, ViewerOutput* viewer, const TimeRange& range); protected: virtual void TextureToFrame(const QVariant& texture, FramePtr frame, const QMatrix4x4 &mat) const = 0; virtual QVariant FootageFrameToTexture(StreamPtr stream, FramePtr frame) const = 0; virtual QVariant CachedFrameToTexture(FramePtr frame) const = 0; virtual NodeValueTable GenerateBlockTable(const TrackOutput *track, const TimeRange &range) override; virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time) override; virtual QVariant ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) override; virtual QVariant ProcessSamples(const Node *node, const TimeRange &range, const SampleJob &job) override; virtual QVariant ProcessFrameGeneration(const Node *node, const GenerateJob& job) override; virtual QVariant GetCachedFrame(const Node *node, const rational &time) override; virtual bool TextureHasAlpha(const QVariant& v) const = 0; const VideoParams& video_params() const { return video_params_; } const AudioParams& audio_params() const { return audio_params_; } const RenderMode::Mode& render_mode() const { return render_mode_; } signals: void AudioConformUnavailable(StreamPtr stream, TimeRange range, rational stream_time, AudioParams params); void FinishedJob(); void WaveformGenerated(OLIVE_NAMESPACE::TrackOutput* track, OLIVE_NAMESPACE::AudioVisualWaveform samples, OLIVE_NAMESPACE::TimeRange start); private: DecoderPtr ResolveDecoderFromInput(StreamPtr stream); static QByteArray HashNode(const Node* n, const VideoParams& params, const rational& time); RenderBackend* parent_; VideoParams video_params_; AudioParams audio_params_; struct CachedStill { QVariant texture; QString colorspace; bool alpha_is_associated; int divider; rational time; }; QHash still_image_cache_; QMatrix4x4 video_download_matrix_; DecoderCache decoder_cache_; TimeRange audio_render_time_; bool available_; bool audio_mode_is_preview_; AudioPlaybackCache* preview_cache_; qint64 preview_job_time_; QHash* copy_map_; RenderMode::Mode render_mode_; }; OLIVE_NAMESPACE_EXIT #endif // RENDERWORKER_H olive-continuous/app/render/color.cpp000066400000000000000000000137111370472574300203000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "color.h" #include "common/clamp.h" OLIVE_NAMESPACE_ENTER Color Color::fromHsv(const float &h, const float &s, const float &v) { float C = s * v; float X = C * (1.0f - abs(fmod(h / 60.0f, 2.0f) - 1.0f)); float m = v - C; float Rs, Gs, Bs; if(h >= 0.0f && h < 60.0f) { Rs = C; Gs = X; Bs = 0.0f; } else if(h >= 60.0f && h < 120.0f) { Rs = X; Gs = C; Bs = 0.0f; } else if(h >= 120.0f && h < 180.0f) { Rs = 0.0f; Gs = C; Bs = X; } else if(h >= 180.0f && h < 240.0f) { Rs = 0.0f; Gs = X; Bs = C; } else if(h >= 240.0f && h < 300.0f) { Rs = X; Gs = 0.0f; Bs = C; } else { Rs = C; Gs = 0.0f; Bs = X; } return Color(Rs + m, Gs + m, Bs + m); } Color::Color(const char *data, const PixelFormat::Format &format) { *this = fromData(data, format); } Color::Color(const QColor &c) { set_red(c.redF()); set_green(c.greenF()); set_blue(c.blueF()); set_alpha(c.alphaF()); } void Color::toHsv(float *hue, float *sat, float *val) const { float fCMax = qMax(qMax(red(), green()), blue()); float fCMin = qMin(qMin(red(), green()), blue()); float fDelta = fCMax - fCMin; if(fDelta > 0) { if(fCMax == red()) { *hue = 60 * (fmod(((green() - blue()) / fDelta), 6)); } else if(fCMax == green()) { *hue = 60 * (((blue() - red()) / fDelta) + 2); } else if(fCMax == blue()) { *hue = 60 * (((red() - green()) / fDelta) + 4); } if(fCMax > 0) { *sat = fDelta / fCMax; } else { *sat = 0; } *val = fCMax; } else { *hue = 0; *sat = 0; *val = fCMax; } if(*hue < 0) { *hue = 360 + *hue; } } float Color::hsv_hue() const { float h, s, v; toHsv(&h, &s, &v); return h; } float Color::hsv_saturation() const { float h, s, v; toHsv(&h, &s, &v); return s; } float Color::value() const { float h, s, v; toHsv(&h, &s, &v); return v; } void Color::toHsl(float *hue, float *sat, float *lightness) const { float fCMin = qMin(red(), qMin(green(), blue())); float fCMax = qMax(red(), qMax(green(), blue())); *lightness = 0.5 * (fCMin + fCMax); if (fCMin == fCMax) { *sat = 0; *hue = 0; return; } else if (*lightness < 0.5) { *sat = (fCMax - fCMin) / (fCMax + fCMin); } else { *sat = (fCMax - fCMin) / (2.0 - fCMax - fCMin); } if (fCMax == red()) { *hue = 60 * (green() - blue()) / (fCMax - fCMin); } if (fCMax == green()) { *hue = 60 * (blue() - red()) / (fCMax - fCMin) + 120; } if (fCMax == blue()) { *hue = 60 * (red() - green()) / (fCMax - fCMin) + 240; } if (*hue < 0) { *hue = *hue + 360; } } float Color::hsl_hue() const { float h, s, l; toHsl(&h, &s, &l); return h; } float Color::hsl_saturation() const { float h, s, l; toHsl(&h, &s, &l); return s; } float Color::lightness() const { float h, s, l; toHsl(&h, &s, &l); return l; } void Color::toData(char *data, const PixelFormat::Format &format) const { OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F), data_, PixelFormat::GetOIIOTypeDesc(format), data, PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels); } Color Color::fromData(const char *data, const PixelFormat::Format &format) { Color c; OIIO::convert_types(PixelFormat::GetOIIOTypeDesc(format), data, PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F), c.data_, PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels); if (!PixelFormat::FormatHasAlphaChannel(format)) { c.set_alpha(1.0f); } return c; } QColor Color::toQColor() const { QColor c; // QColor only supports values from 0.0 to 1.0 and are only used for UI representations c.setRedF(clamp(red(), 0.0f, 1.0f)); c.setGreenF(clamp(green(), 0.0f, 1.0f)); c.setBlueF(clamp(blue(), 0.0f, 1.0f)); c.setAlphaF(clamp(alpha(), 0.0f, 1.0f)); return c; } float Color::GetRoughLuminance() const { return (2*red()+blue()+3*green())/6.0f; } const Color &Color::operator+=(const Color &rhs) { for (int i=0;i. ***/ #ifndef COLOR_H #define COLOR_H #include #include #include "common/define.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER /** * @brief High precision 32-bit float based RGBA color value */ class Color { public: Color() { for (int i=0;i. ***/ #include "colormanager.h" #include #include #include "common/define.h" #include "common/filefunctions.h" #include "config/config.h" #include "core.h" OLIVE_NAMESPACE_ENTER OCIO::ConstConfigRcPtr ColorManager::default_config_; ColorManager::ColorManager() { // Set config to our built-in default config_ = GetDefaultConfig(); // Default input space default_input_color_space_ = QStringLiteral("sRGB OETF"); // Default reference space is scene linear reference_space_ = OCIO::ROLE_SCENE_LINEAR; } OCIO::ConstConfigRcPtr ColorManager::GetConfig() const { return config_; } OCIO::ConstConfigRcPtr ColorManager::CreateConfigFromFile(const QString &filename) { OCIO_SET_C_LOCALE_FOR_SCOPE; return OCIO::Config::CreateFromFile(filename.toUtf8()); } const QString &ColorManager::GetConfigFilename() const { return config_filename_; } OCIO::ConstConfigRcPtr ColorManager::GetDefaultConfig() { return default_config_; } void ColorManager::SetUpDefaultConfig() { OCIO_SET_C_LOCALE_FOR_SCOPE; if (!qgetenv("OCIO").isEmpty()) { // Attempt to set config from "OCIO" environment variable try { default_config_ = OCIO::Config::CreateFromEnv(); return; } catch (OCIO::Exception& e) { qWarning() << "Failed to load config from OCIO environment variable config:" << e.what(); } } // Extract OCIO config - kind of hacky, but it'll work QString dir = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("ocioconf")); FileFunctions::CopyDirectory(QStringLiteral(":/ocioconf"), dir, true); qDebug() << "Extracting default OCIO config to" << dir; default_config_ = CreateConfigFromFile(QDir(dir).filePath(QStringLiteral("config.ocio"))); } void ColorManager::SetConfig(const QString &filename) { if (filename != config_filename_) { SetConfigInternal(filename); emit ConfigChanged(); } } void ColorManager::SetConfigInternal(const QString &filename) { config_filename_ = filename; OCIO::ConstConfigRcPtr cfg; if (config_filename_.isEmpty()) { cfg = OCIO::GetCurrentConfig(); } else { cfg = OCIO::Config::CreateFromFile(filename.toUtf8()); } config_ = cfg; } void ColorManager::SetDefaultInputColorSpaceInternal(const QString &s) { default_input_color_space_ = s; } void ColorManager::SetConfigAndDefaultInput(const QString &filename, const QString &s) { bool config_changed = false; bool default_input_changed = false; if (filename != config_filename_) { SetConfigInternal(filename); config_changed = true; } if (default_input_color_space_ != s) { SetDefaultInputColorSpaceInternal(s); default_input_changed = true; } if (config_changed) { emit ConfigChanged(); } if (default_input_changed) { emit DefaultInputColorSpaceChanged(); } } void ColorManager::DisassociateAlpha(FramePtr f) { AssociateAlphaPixFmtFilter(kDisassociate, f); } void ColorManager::AssociateAlpha(FramePtr f) { AssociateAlphaPixFmtFilter(kAssociate, f); } void ColorManager::ReassociateAlpha(FramePtr f) { AssociateAlphaPixFmtFilter(kReassociate, f); } QStringList ColorManager::ListAvailableDisplays() { QStringList displays; int number_of_displays = config_->getNumDisplays(); for (int i=0;igetDisplay(i)); } return displays; } QString ColorManager::GetDefaultDisplay() { return config_->getDefaultDisplay(); } QStringList ColorManager::ListAvailableViews(QString display) { QStringList views; int number_of_views = config_->getNumViews(display.toUtf8()); for (int i=0;igetView(display.toUtf8(), i)); } return views; } QString ColorManager::GetDefaultView(const QString &display) { return config_->getDefaultView(display.toUtf8()); } QStringList ColorManager::ListAvailableLooks() { QStringList looks; int number_of_looks = config_->getNumLooks(); for (int i=0;igetLookNameByIndex(i)); } return looks; } QStringList ColorManager::ListAvailableColorspaces() { return ListAvailableColorspaces(config_); } const QString &ColorManager::GetDefaultInputColorSpace() const { return default_input_color_space_; } void ColorManager::SetDefaultInputColorSpace(const QString &s) { if (default_input_color_space_ != s) { SetDefaultInputColorSpaceInternal(s); emit DefaultInputColorSpaceChanged(); } } const QString &ColorManager::GetReferenceColorSpace() const { return reference_space_; } void ColorManager::SetReferenceColorSpace(const QString &s) { reference_space_ = s; emit ConfigChanged(); } QString ColorManager::GetCompliantColorSpace(const QString &s) { if (ListAvailableColorspaces().contains(s)) { return s; } else { return GetDefaultInputColorSpace(); } } ColorTransform ColorManager::GetCompliantColorSpace(const ColorTransform &transform, bool force_display) { if (transform.is_display() || force_display) { // Get display information QString display = transform.display(); QString view = transform.view(); QString look = transform.look(); // Check if display still exists in config if (!ListAvailableDisplays().contains(display)) { display = GetDefaultDisplay(); } // Check if view still exists in display if (!ListAvailableViews(display).contains(view)) { view = GetDefaultView(display); } // Check if looks still exists if (!ListAvailableLooks().contains(look)) { look.clear(); } return ColorTransform(display, view, look); } else { QString output = transform.output(); if (!ListAvailableColorspaces().contains(output)) { output = GetDefaultInputColorSpace(); } return ColorTransform(output); } } QStringList ColorManager::ListAvailableColorspaces(OCIO::ConstConfigRcPtr config) { QStringList spaces; int number_of_colorspaces = config->getNumColorSpaces(); for (int i=0;igetColorSpaceNameByIndex(i)); } return spaces; } void ColorManager::GetDefaultLumaCoefs(float *rgb) const { config_->getDefaultLumaCoefs(rgb); } Color ColorManager::GetDefaultLumaCoefs() const { Color c; // Just a default value, shouldn't be significant c.set_alpha(1.0f); // The float data in Color lines up with the "rgb" param of this function GetDefaultLumaCoefs(c.data()); return c; } ColorManager::OCIOMethod ColorManager::GetOCIOMethodForMode(RenderMode::Mode mode) { return static_cast(Core::GetPreferenceForRenderMode(mode, QStringLiteral("OCIOMethod")).toInt()); } void ColorManager::SetOCIOMethodForMode(RenderMode::Mode mode, ColorManager::OCIOMethod method) { Core::SetPreferenceForRenderMode(mode, QStringLiteral("OCIOMethod"), method); } void ColorManager::AssociateAlphaPixFmtFilter(ColorManager::AlphaAction action, FramePtr f) { if (!PixelFormat::FormatHasAlphaChannel(f->format())) { // This frame has no alpha channel, do nothing return; } int pixel_count = f->width() * f->height() * kRGBAChannels; switch (static_cast(f->format())) { case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: qWarning() << "Alpha association functions received an invalid pixel format"; break; case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGBA8: case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGBA16U: qWarning() << "Alpha association functions only works on float-based pixel formats at this time"; break; case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGBA16F: { AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count); break; } case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_RGBA32F: { AssociateAlphaInternal(action, reinterpret_cast(f->data()), pixel_count); break; } } } template void ColorManager::AssociateAlphaInternal(ColorManager::AlphaAction action, T *data, int pix_count) { for (int i=0;i 0) { for (int j=0;j. ***/ #ifndef COLORSERVICE_H #define COLORSERVICE_H #include #include "codec/frame.h" #include "colorprocessor.h" #define OCIO_SET_C_LOCALE_FOR_SCOPE ColorManager::SetLocale d("C") OLIVE_NAMESPACE_ENTER class ColorManager : public QObject { Q_OBJECT public: ColorManager(); OCIO::ConstConfigRcPtr GetConfig() const; static OCIO::ConstConfigRcPtr CreateConfigFromFile(const QString& filename); const QString& GetConfigFilename() const; static OCIO::ConstConfigRcPtr GetDefaultConfig(); static void SetUpDefaultConfig(); void SetConfig(const QString& filename); void SetConfigAndDefaultInput(const QString& filename, const QString& s); static void DisassociateAlpha(FramePtr f); static void AssociateAlpha(FramePtr f); static void ReassociateAlpha(FramePtr f); QStringList ListAvailableDisplays(); QString GetDefaultDisplay(); QStringList ListAvailableViews(QString display); QString GetDefaultView(const QString& display); QStringList ListAvailableLooks(); QStringList ListAvailableColorspaces(); const QString& GetDefaultInputColorSpace() const; void SetDefaultInputColorSpace(const QString& s); const QString& GetReferenceColorSpace() const; void SetReferenceColorSpace(const QString& s); QString GetCompliantColorSpace(const QString& s); ColorTransform GetCompliantColorSpace(const ColorTransform& transform, bool force_display = false); static QStringList ListAvailableColorspaces(OCIO::ConstConfigRcPtr config); void GetDefaultLumaCoefs(float* rgb) const; Color GetDefaultLumaCoefs() const; enum OCIOMethod { kOCIOFast, kOCIOAccurate }; static OCIOMethod GetOCIOMethodForMode(RenderMode::Mode mode); static void SetOCIOMethodForMode(RenderMode::Mode mode, OCIOMethod method); class SetLocale { public: SetLocale(const char* new_locale); ~SetLocale(); private: QString old_locale_; }; signals: void ConfigChanged(); void DefaultInputColorSpaceChanged(); private: void SetConfigInternal(const QString& filename); void SetDefaultInputColorSpaceInternal(const QString& s); OCIO::ConstConfigRcPtr config_; enum AlphaAction { kAssociate, kDisassociate, kReassociate }; static void AssociateAlphaPixFmtFilter(AlphaAction action, FramePtr f); template static void AssociateAlphaInternal(AlphaAction action, T* data, int pix_count); QString config_filename_; QString default_input_color_space_; QString reference_space_; static OCIO::ConstConfigRcPtr default_config_; }; OLIVE_NAMESPACE_EXIT #endif // COLORSERVICE_H olive-continuous/app/render/colorprocessor.cpp000066400000000000000000000053571370472574300222470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorprocessor.h" #include "common/define.h" #include "colormanager.h" OLIVE_NAMESPACE_ENTER ColorProcessor::ColorProcessor(ColorManager *config, const QString &input, const ColorTransform &transform) { const QString& output = (transform.output().isEmpty()) ? config->GetDefaultDisplay() : transform.output(); if (transform.is_display()) { const QString& view = (transform.view().isEmpty()) ? config->GetDefaultView(output) : transform.view(); OCIO::DisplayTransformRcPtr display_transform = OCIO::DisplayTransform::Create(); display_transform->setInputColorSpaceName(input.toUtf8()); display_transform->setDisplay(output.toUtf8()); display_transform->setView(view.toUtf8()); if (!transform.look().isEmpty()) { display_transform->setLooksOverride(transform.look().toUtf8()); display_transform->setLooksOverrideEnabled(true); } OCIO_SET_C_LOCALE_FOR_SCOPE; processor_ = config->GetConfig()->getProcessor(display_transform); } else { OCIO_SET_C_LOCALE_FOR_SCOPE; processor_ = config->GetConfig()->getProcessor(input.toUtf8(), output.toUtf8()); } } void ColorProcessor::ConvertFrame(Frame *f) { OCIO::PackedImageDesc img(reinterpret_cast(f->data()), f->width(), f->height(), PixelFormat::ChannelCount(f->format()), OCIO::AutoStride, OCIO::AutoStride, f->linesize_bytes()); processor_->apply(img); } Color ColorProcessor::ConvertColor(Color in) { processor_->applyRGBA(in.data()); return in; } ColorProcessorPtr ColorProcessor::Create(ColorManager *config, const QString& input, const ColorTransform &transform) { return std::make_shared(config, input, transform); } OCIO::ConstProcessorRcPtr ColorProcessor::GetProcessor() { return processor_; } void ColorProcessor::ConvertFrame(FramePtr f) { ConvertFrame(f.get()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/colorprocessor.h000066400000000000000000000031071370472574300217030ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORPROCESSOR_H #define COLORPROCESSOR_H #include "codec/frame.h" #include "render/color.h" #include "render/colortransform.h" OLIVE_NAMESPACE_ENTER class ColorManager; class ColorProcessor; using ColorProcessorPtr = std::shared_ptr; class ColorProcessor { public: enum Direction { kNormal, kInverse }; ColorProcessor(ColorManager* config, const QString& input, const ColorTransform& dest_space); DISABLE_COPY_MOVE(ColorProcessor) static ColorProcessorPtr Create(ColorManager* config, const QString& input, const ColorTransform& dest_space); OCIO::ConstProcessorRcPtr GetProcessor(); void ConvertFrame(FramePtr f); void ConvertFrame(Frame* f); Color ConvertColor(Color in); private: OCIO::ConstProcessorRcPtr processor_; }; using ColorProcessorChain = QList; OLIVE_NAMESPACE_EXIT #endif // COLORPROCESSOR_H olive-continuous/app/render/colortransform.h000066400000000000000000000032271370472574300217020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORTRANSFORM_H #define COLORTRANSFORM_H #include namespace OCIO = OCIO_NAMESPACE::v1; #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ColorTransform { public: ColorTransform() { is_display_ = false; } ColorTransform(const QString& output) { is_display_ = false; output_ = output; } ColorTransform(const QString& display, const QString& view, const QString& look) { is_display_ = true; output_ = display; view_ = view; look_ = look; } bool is_display() const { return is_display_; } const QString& display() const { return output_; } const QString& output() const { return output_; } const QString& view() const { return view_; } const QString& look() const { return look_; } private: QString output_; bool is_display_; QString view_; QString look_; }; OLIVE_NAMESPACE_EXIT #endif // COLORTRANSFORM_H olive-continuous/app/render/diskmanager.cpp000066400000000000000000000116011370472574300214430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "diskmanager.h" #include #include #include #include #include #include #include "common/filefunctions.h" #include "config/config.h" OLIVE_NAMESPACE_ENTER DiskManager* DiskManager::instance_ = nullptr; DiskManager::DiskManager() : consumption_(0) { // Try to load any current cache index from file QFile cache_index_file(GetCacheIndexFilename()); if (cache_index_file.open(QFile::ReadOnly)) { QDataStream ds(&cache_index_file); while (!cache_index_file.atEnd()) { HashTime h; ds >> h.file_name; ds >> h.hash; ds >> h.access_time; ds >> h.file_size; if (QFileInfo::exists(h.file_name)) { consumption_ += h.file_size; disk_data_.append(h); } } } } DiskManager::~DiskManager() { if (Config::Current()["ClearDiskCacheOnClose"].toBool()) { // Clear all cache data ClearDiskCache(true); } else { // Save current cache index QFile cache_index_file(GetCacheIndexFilename()); if (cache_index_file.open(QFile::WriteOnly)) { QDataStream ds(&cache_index_file); foreach (const HashTime& h, disk_data_) { ds << h.file_name; ds << h.hash; ds << h.access_time; ds << h.file_size; } } else { qWarning() << "Failed to write cache index:" << GetCacheIndexFilename(); } } } void DiskManager::CreateInstance() { instance_ = new DiskManager(); } void DiskManager::DestroyInstance() { delete instance_; instance_ = nullptr; } DiskManager *DiskManager::instance() { return instance_; } void DiskManager::Accessed(const QByteArray &hash) { lock_.lock(); for (int i=disk_data_.size()-1;i>=0;i--) { const HashTime& h = disk_data_.at(i); if (h.hash == hash) { HashTime moved_hash = h; moved_hash.access_time = QDateTime::currentMSecsSinceEpoch(); disk_data_.removeAt(i); disk_data_.append(moved_hash); break; } } lock_.unlock(); } void DiskManager::Accessed(const QString &filename) { lock_.lock(); for (int i=disk_data_.size()-1;i>=0;i--) { const HashTime& h = disk_data_.at(i); if (h.file_name == filename) { HashTime moved_hash = h; moved_hash.access_time = QDateTime::currentMSecsSinceEpoch(); disk_data_.removeAt(i); disk_data_.append(moved_hash); break; } } lock_.unlock(); } void DiskManager::CreatedFile(const QString &file_name, const QByteArray &hash) { lock_.lock(); qint64 file_size = QFile(file_name).size(); disk_data_.append({file_name, hash, QDateTime::currentMSecsSinceEpoch(), file_size}); consumption_ += file_size; QList deleted_hashes; while (consumption_ > DiskLimit()) { deleted_hashes.append(DeleteLeastRecent()); } lock_.unlock(); foreach (const QByteArray& h, deleted_hashes) { emit DeletedFrame(h); } } bool DiskManager::ClearDiskCache(bool quick_delete) { bool deleted_files; lock_.lock(); if (quick_delete) { deleted_files = QDir(FileFunctions::GetMediaCacheLocation()).removeRecursively(); disk_data_.clear(); } else { deleted_files = true; for (int i=0;i. ***/ #ifndef DISKMANAGER_H #define DISKMANAGER_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class DiskManager : public QObject { Q_OBJECT public: static void CreateInstance(); static void DestroyInstance(); static DiskManager* instance(); void Accessed(const QByteArray& hash); void Accessed(const QString& filename); void CreatedFile(const QString& file_name, const QByteArray& hash); bool ClearDiskCache(bool quick_delete); signals: void DeletedFrame(const QByteArray& hash); private: DiskManager(); virtual ~DiskManager() override; static DiskManager* instance_; QByteArray DeleteLeastRecent(); qint64 DiskLimit(); static QString GetCacheIndexFilename(); struct HashTime { QString file_name; QByteArray hash; qint64 access_time; qint64 file_size; }; QList disk_data_; qint64 consumption_; QMutex lock_; }; OLIVE_NAMESPACE_EXIT #endif // DISKMANAGER_H olive-continuous/app/render/framehashcache.cpp000066400000000000000000000235071370472574300221100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "framehashcache.h" #include #include #include #include #include #include #include "codec/frame.h" #include "common/filefunctions.h" #include "common/timecodefunctions.h" #include "render/diskmanager.h" OLIVE_NAMESPACE_ENTER QByteArray FrameHashCache::GetHash(const rational &time) { QMutexLocker locker(lock()); return time_hash_map_.value(time); } void FrameHashCache::SetHash(const rational &time, const QByteArray &hash, const qint64& job_time) { QMutexLocker locker(lock()); bool is_current = false; for (int i=jobs_.size()-1; i>=0; i--) { const JobIdentifier& job = jobs_.at(i); if (job.range.Contains(time) && job_time >= job.job_time) { is_current = true; break; } } if (!is_current) { return; } time_hash_map_.insert(time, hash); TimeRange validated_range(time, time + timebase_); NoLockValidate(validated_range); locker.unlock(); emit Validated(validated_range); } void FrameHashCache::SetTimebase(const rational &tb) { QMutexLocker locker(lock()); timebase_ = tb; } QList FrameHashCache::GetFramesWithHash(const QByteArray &hash) { QMutexLocker locker(lock()); QList times; QMap::const_iterator iterator; for (iterator=time_hash_map_.begin();iterator!=time_hash_map_.end();iterator++) { if (iterator.value() == hash) { times.append(iterator.key()); } } return times; } QList FrameHashCache::TakeFramesWithHash(const QByteArray &hash) { QMutexLocker locker(lock()); QList times; QMap::iterator iterator = time_hash_map_.begin(); while (iterator != time_hash_map_.end()) { if (iterator.value() == hash) { times.append(iterator.key()); iterator = time_hash_map_.erase(iterator); } else { iterator++; } } foreach (const rational& r, times) { NoLockInvalidate(TimeRange(r, r + timebase_)); } locker.unlock(); foreach (const rational& r, times) { emit Invalidated(TimeRange(r, r + timebase_)); } return times; } QMap FrameHashCache::time_hash_map() { QMutexLocker locker(lock()); return time_hash_map_; } QString FrameHashCache::GetFormatExtension() { return QStringLiteral(".exr"); } QVector FrameHashCache::GetFrameListFromTimeRange(TimeRangeList range_list, const rational &timebase) { QVector times; while (!range_list.isEmpty()) { const TimeRange& range = range_list.first(); rational time = range.in(); rational snapped = Timecode::snap_time_to_timebase(time, timebase); rational next; if (snapped > time) { next = snapped; snapped -= timebase; } else { next = snapped + timebase; } times.append(snapped); range_list.RemoveTimeRange(TimeRange(snapped, next)); } return times; } QVector FrameHashCache::GetFrameListFromTimeRange(const TimeRangeList &range) { QMutexLocker locker(lock()); return GetFrameListFromTimeRange(range, timebase_); } QVector FrameHashCache::GetInvalidatedFrames() { QMutexLocker locker(lock()); return GetFrameListFromTimeRange(NoLockGetInvalidatedRanges()); } void FrameHashCache::SaveCacheFrame(const QByteArray& hash, char* data, const VideoParams& vparam, int linesize_bytes) { QString fn = CachePathName(hash); if (SaveCacheFrame(fn, data, vparam, linesize_bytes)) { // Register frame with the disk manager DiskManager::instance()->CreatedFile(fn, hash); } } void FrameHashCache::SaveCacheFrame(const QByteArray &hash, FramePtr frame) { SaveCacheFrame(hash, frame->data(), frame->video_params(), frame->linesize_bytes()); } FramePtr FrameHashCache::LoadCacheFrame(const QByteArray &hash) { return LoadCacheFrame(CachePathName(hash)); } FramePtr FrameHashCache::LoadCacheFrame(const QString &fn) { FramePtr frame = nullptr; if (!fn.isEmpty() && QFileInfo::exists(fn)) { Imf::InputFile file(fn.toUtf8(), 0); Imath::Box2i dw = file.header().dataWindow(); Imf::PixelType pix_type = file.header().channels().begin().channel().type; int width = dw.max.x - dw.min.x + 1; int height = dw.max.y - dw.min.y + 1; bool has_alpha = file.header().channels().findChannel("A"); PixelFormat::Format image_format; if (pix_type == Imf::HALF) { if (has_alpha) { image_format = PixelFormat::PIX_FMT_RGBA16F; } else { image_format = PixelFormat::PIX_FMT_RGB16F; } } else { if (has_alpha) { image_format = PixelFormat::PIX_FMT_RGBA32F; } else { image_format = PixelFormat::PIX_FMT_RGB32F; } } frame = Frame::Create(); frame->set_video_params(VideoParams(width, height, image_format)); frame->allocate(); int bpc = PixelFormat::BytesPerChannel(image_format); size_t xs = PixelFormat::ChannelCount(image_format) * bpc; size_t ys = frame->linesize_bytes(); Imf::FrameBuffer framebuffer; framebuffer.insert("R", Imf::Slice(pix_type, frame->data(), xs, ys)); framebuffer.insert("G", Imf::Slice(pix_type, frame->data() + bpc, xs, ys)); framebuffer.insert("B", Imf::Slice(pix_type, frame->data() + 2*bpc, xs, ys)); if (has_alpha) { framebuffer.insert("A", Imf::Slice(pix_type, frame->data() + 3*bpc, xs, ys)); } file.setFrameBuffer(framebuffer); file.readPixels(dw.min.y, dw.max.y); } return frame; } void FrameHashCache::LengthChangedEvent(const rational &old, const rational &newlen) { if (newlen < old) { QMap::iterator i = time_hash_map_.begin(); while (i != time_hash_map_.end()) { if (i.key() >= newlen) { i = time_hash_map_.erase(i); } else { i++; } } } } void FrameHashCache::InvalidateEvent(const TimeRange &r) { QMap::iterator i = time_hash_map_.begin(); while (i != time_hash_map_.end()) { if (i.key() >= r.in() && i.key() < r.out()) { i = time_hash_map_.erase(i); } else { i++; } } } struct HashTimePair { rational time; QByteArray hash; }; void FrameHashCache::ShiftEvent(const rational &from, const rational &to) { QMap::iterator i = time_hash_map_.begin(); // POSITIVE if moving forward -> // NEGATIVE if moving backward <- rational diff = to - from; bool diff_is_negative = (diff < rational()); QList shifted_times; while (i != time_hash_map_.end()) { if (diff_is_negative && i.key() >= to && i.key() < from) { // This time will be removed in the shift so we just discard it i = time_hash_map_.erase(i); } else if (i.key() >= from) { // This time is after the from time and must be shifted shifted_times.append({i.key() + diff, i.value()}); i = time_hash_map_.erase(i); } else { // Do nothing i++; } } foreach (const HashTimePair& p, shifted_times) { time_hash_map_.insert(p.time, p.hash); } } QString FrameHashCache::CachePathName(const QByteArray& hash) { QString ext = GetFormatExtension(); QDir cache_dir(QDir(FileFunctions::GetMediaCacheLocation()).filePath(QString(hash.left(1).toHex()))); cache_dir.mkpath("."); QString filename = QStringLiteral("%1%2").arg(QString(hash.mid(1).toHex()), ext); return cache_dir.filePath(filename); } bool FrameHashCache::SaveCacheFrame(const QString &filename, char *data, const VideoParams &vparam, int linesize_bytes) { Q_ASSERT(PixelFormat::FormatIsFloat(vparam.format())); // Floating point types are stored in EXR Imf::PixelType pix_type; if (vparam.format() == PixelFormat::PIX_FMT_RGB16F || vparam.format() == PixelFormat::PIX_FMT_RGBA16F) { pix_type = Imf::HALF; } else { pix_type = Imf::FLOAT; } Imf::Header header(vparam.effective_width(), vparam.effective_height()); header.channels().insert("R", Imf::Channel(pix_type)); header.channels().insert("G", Imf::Channel(pix_type)); header.channels().insert("B", Imf::Channel(pix_type)); if (PixelFormat::FormatHasAlphaChannel(vparam.format())) { header.channels().insert("A", Imf::Channel(pix_type)); } header.compression() = Imf::DWAA_COMPRESSION; header.insert("dwaCompressionLevel", Imf::FloatAttribute(200.0f)); Imf::OutputFile out(filename.toUtf8(), header, 0); int bpc = PixelFormat::BytesPerChannel(vparam.format()); size_t xs = PixelFormat::ChannelCount(vparam.format()) * bpc; size_t ys = linesize_bytes; Imf::FrameBuffer framebuffer; framebuffer.insert("R", Imf::Slice(pix_type, data, xs, ys)); framebuffer.insert("G", Imf::Slice(pix_type, data + bpc, xs, ys)); framebuffer.insert("B", Imf::Slice(pix_type, data + 2*bpc, xs, ys)); if (PixelFormat::FormatHasAlphaChannel(vparam.format())) { framebuffer.insert("A", Imf::Slice(pix_type, data + 3*bpc, xs, ys)); } out.setFrameBuffer(framebuffer); out.writePixels(vparam.effective_height()); return true; } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/framehashcache.h000066400000000000000000000054501370472574300215520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIDEORENDERFRAMECACHE_H #define VIDEORENDERFRAMECACHE_H #include #include "common/rational.h" #include "common/timerange.h" #include "render/pixelformat.h" #include "render/playbackcache.h" #include "render/videoparams.h" OLIVE_NAMESPACE_ENTER class FrameHashCache : public PlaybackCache { Q_OBJECT public: FrameHashCache(QObject* parent = nullptr) : PlaybackCache(parent) { } QByteArray GetHash(const rational& time); void SetTimebase(const rational& tb); /** * @brief Returns a list of frames that use a particular hash */ QList GetFramesWithHash(const QByteArray& hash); /** * @brief Same as FramesWithHash() but also removes these frames from the map */ QList TakeFramesWithHash(const QByteArray& hash); QMap time_hash_map(); /** * @brief Return the path of the cached image at this time */ static QString CachePathName(const QByteArray &hash); static bool SaveCacheFrame(const QString& filename, char *data, const VideoParams &vparam, int linesize_bytes); static void SaveCacheFrame(const QByteArray& hash, char *data, const VideoParams &vparam, int linesize_bytes); static void SaveCacheFrame(const QByteArray& hash, FramePtr frame); static FramePtr LoadCacheFrame(const QByteArray& hash); static FramePtr LoadCacheFrame(const QString& fn); static QString GetFormatExtension(); static QVector GetFrameListFromTimeRange(TimeRangeList range_list, const rational& timebase); QVector GetFrameListFromTimeRange(const TimeRangeList &range); QVector GetInvalidatedFrames(); public slots: void SetHash(const OLIVE_NAMESPACE::rational& time, const QByteArray& hash, const qint64 &job_time); protected: virtual void LengthChangedEvent(const rational& old, const rational& newlen) override; virtual void InvalidateEvent(const TimeRange& range) override; virtual void ShiftEvent(const rational& from, const rational& to) override; private: QMap time_hash_map_; rational timebase_; }; OLIVE_NAMESPACE_EXIT #endif // VIDEORENDERFRAMECACHE_H olive-continuous/app/render/managedcolor.cpp000066400000000000000000000027111370472574300216130ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "managedcolor.h" OLIVE_NAMESPACE_ENTER ManagedColor::ManagedColor() { } ManagedColor::ManagedColor(const float &r, const float &g, const float &b, const float &a) : Color(r, g, b, a) { } ManagedColor::ManagedColor(const char *data, const PixelFormat::Format &format) : Color(data, format) { } ManagedColor::ManagedColor(const Color &c) : Color(c) { } const QString &ManagedColor::color_input() const { return color_input_; } void ManagedColor::set_color_input(const QString &color_input) { color_input_ = color_input; } const ColorTransform &ManagedColor::color_output() const { return color_transform_; } void ManagedColor::set_color_output(const ColorTransform &color_output) { color_transform_ = color_output; } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/managedcolor.h000066400000000000000000000025711370472574300212640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MANAGEDCOLOR_H #define MANAGEDCOLOR_H #include "color.h" #include "colortransform.h" OLIVE_NAMESPACE_ENTER class ManagedColor : public Color { public: ManagedColor(); ManagedColor(const float& r, const float& g, const float& b, const float& a = 1.0f); ManagedColor(const char *data, const PixelFormat::Format &format); ManagedColor(const Color& c); const QString& color_input() const; void set_color_input(const QString &color_input); const ColorTransform& color_output() const; void set_color_output(const ColorTransform &color_output); private: QString color_input_; ColorTransform color_transform_; }; OLIVE_NAMESPACE_EXIT #endif // MANAGEDCOLOR_H olive-continuous/app/render/ocioconf/000077500000000000000000000000001370472574300202525ustar00rootroot00000000000000olive-continuous/app/render/ocioconf/CMakeLists.txt000066400000000000000000000021761370472574300230200ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . file(GLOB_RECURSE OCIOCONF_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.ocio *.spi3d *.spi1d) set(QRC_BODY "") foreach(OCIOCONF_FILE ${OCIOCONF_RESOURCES}) string(APPEND QRC_BODY "${OCIOCONF_FILE}\n") configure_file(${OCIOCONF_FILE} ${OCIOCONF_FILE} COPYONLY) endforeach() configure_file(ocioconf.qrc.in ocioconf.qrc @ONLY) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ${CMAKE_CURRENT_BINARY_DIR}/ocioconf.qrc PARENT_SCOPE ) olive-continuous/app/render/ocioconf/config.ocio000077500000000000000000000270651370472574300224070ustar00rootroot00000000000000# Film Emulsion-like configuration for # Blender. Crafted by Troy James Sobotka with # special thanks, feedback, and knowledge from Guillermo # Espertino, Claudio Rocha, Bassam Kurdali, Eugenio # Pignataro, Henri Hebeisen, Jason Clarke, # Haarm-Peter Duiker, Thomas Mansencal, Andrew # Price, Nick Shaw, and Timothy # Lottes. ocio_profile_version: 1 search_path: "luts:looks" strictparsing: true luma: [0.2126, 0.7152, 0.0722] description: A filmlike dynamic range encoding set for Blender roles: default: Linear reference: Linear scene_linear: Linear data: Non-Colour Data compositing_log: Filmic Log Encoding color_timing: Filmic Log Encoding default_byte: sRGB OETF default_float: Linear default_sequencer: sRGB OETF color_picking: sRGB OETF texture_paint: sRGB OETF matte_paint: Filmic Log Encoding displays: sRGB: - ! {name: sRGB OETF, colorspace: sRGB OETF} - ! {name: Non-Colour Data, colorspace: Non-Colour Data} - ! {name: Linear Raw, colorspace: Linear} - ! {name: Filmic Log Encoding Base, colorspace: Filmic Log Encoding} BT.1886: - ! {name: BT.1886 EOTF, colorspace: BT.1886 EOTF} - ! {name: Non-Colour Data, colorspace: Non-Colour Data} - ! {name: Linear Raw, colorspace: Linear} - ! {name: Filmic Log Encoding Base, colorspace: BT.1886 Filmic Log Encoding} Apple Display P3: - ! {name: sRGB OETF, colorspace: AppleP3 sRGB OETF} - ! {name: Non-Colour Data, colorspace: Non-Colour Data} - ! {name: Linear Raw, colorspace: Linear} - ! {name: Filmic Log Encoding Base, colorspace: AppleP3 Filmic Log Encoding} active_displays: [sRGB, BT.1886, Apple Display P3, None] #active_views: [Filmic Log Encoding Base, sRGB OETF, Non-Colour Data, Linear Raw, No View] colorspaces: - ! name: Linear family: equalitygroup: bitdepth: 32f description: | ITU BT.709 primaries based scene referred linear space. isdata: false allocation: lg2 allocationvars: [-12.4739311883, 12.5260688117, 0.00392156862] - ! name: Filmic Log Encoding family: equalitygroup: bitdepth: 32f description: | Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range. isdata: false allocation: lg2 allocationvars: [-12.4739311883, 12.5260688117, 0.00392156862] from_reference: ! children: - ! {allocation: lg2, vars: [-12.4739311883, 12.5260688117, 0.00392156862]} - ! {src: desat65cube.spi3d, interpolation: best} - ! {allocation: uniform, vars: [0, 0.66]} to_reference: ! {allocation: lg2, vars: [-12.4739311883, 4.02606881167, 0.00392156862], direction: inverse} - ! name: sRGB OETF family: equalitygroup: bitdepth: 32f description: | sRGB specification display referred Optical-Electro Transfer Function. isdata: false allocation: uniform allocationvars: [0.0, 1.0] to_reference: ! {src: sRGB_OETF_to_Linear.spi1d, interpolation: linear} - ! name: Apple DCI-P3 D65 family: display equalitygroup: "" bitdepth: 32f isdata: false allocation: lg2 allocationvars: [-12.4739311883, 12.5260688117, 0.00392156862] to_reference: ! children: - ! {matrix: [0.515121, 0.291977, 0.157104, 0, 0.241196, 0.692245, 0.0665741, 0, -0.00105286, 0.0418854, 0.784073, 0, 0, 0, 0, 1]} - ! {matrix: [1.04788, 0.0229187, -0.0502014, 0, 0.0295868, 0.990479, -0.0170593, 0, -0.00923157, 0.0150757, 0.751678, 0, 0, 0, 0, 1], direction: inverse} - ! {matrix: [0.412391, 0.357584, 0.180481, 0, 0.212639, 0.715169, 0.0721923, 0, 0.0193308, 0.119195, 0.950532, 0, 0, 0, 0, 1], direction: inverse} - ! name: AppleP3 sRGB OETF family: equalitygroup: bitdepth: 32f description: | sRGB specification display referred Optical-Electro Transfer Function with Apple DCI-P3 primaries. isdata: false allocation: uniform allocationvars: [0.0, 1.0] to_reference: ! children: - ! {src: sRGB_OETF_to_Linear.spi1d, interpolation: linear} - ! {src: Apple DCI-P3 D65, dst: Linear} - ! name: BT.1886 EOTF family: equalitygroup: bitdepth: 32f description: | BT.1886 specification display referred Electro-Optical Transfer Function with REC.709 primaries. isdata: false allocation: uniform allocationvars: [0.0, 1.0] to_reference: ! {value: [2.4, 2.4, 2.4, 1.0]} - ! name: AppleP3 Filmic Log Encoding family: equalitygroup: bitdepth: 32f description: | Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range with Apple P3 primaries. isdata: false allocation: lg2 allocationvars: [-12.4739311883, 12.5260688117, 0.00392156862] from_reference: ! children: - ! {src: Linear, dst: Filmic Log Encoding} - ! {value: [2.2, 2.2, 2.2, 1.0]} - ! {src: Linear, dst: Apple DCI-P3 D65} - ! {value: [2.2, 2.2, 2.2, 1.0], direction: inverse} to_reference: ! children: - ! {value: [2.2, 2.2, 2.2, 1.0]} - ! {src: Apple DCI-P3 D65, dst: Linear} - ! {value: [2.2, 2.2, 2.2, 1.0], direction: inverse} - ! {allocation: lg2, vars: [-12.4739311883, 4.02606881167, 0.00392156862], direction: inverse} - ! name: BT.1886 Filmic Log Encoding family: equalitygroup: bitdepth: 32f description: | Log based filmic shaper with 16.5 stops of latitude, and 25 stops of dynamic range with REC.709 primaries. isdata: false allocation: lg2 allocationvars: [-12.4739311883, 12.5260688117, 0.00392156862] from_reference: ! children: - ! {src: Linear, dst: Filmic Log Encoding} - ! {value: [2.2, 2.2, 2.2, 1.0]} - ! {value: [2.4, 2.4, 2.4, 1.0], direction: inverse} to_reference: ! children: - ! {value: [2.4, 2.4, 2.4, 1.0]} - ! {value: [2.2, 2.2, 2.2, 1.0], direction: inverse} - ! {allocation: lg2, vars: [-12.4739311883, 4.02606881167, 0.00392156862], direction: inverse} - ! name: Fuji F-Log OETF family: Camera Footage equalitygroup: "" bitdepth: 32f description: | Fuji F-Log transfer function isdata: false allocation: uniform allocationvars: [0, 1] to_reference: ! {src: F-Log_to_Linear.spi1d, interpolation: linear} - ! name: Fuji F-Log F-Gamut family: "" equalitygroup: "" bitdepth: 32f description: | Fuji F-Log / F-Gamut isdata: false allocation: uniform allocationvars: [0, 1] to_reference: ! children: - ! {src: Fuji F-Log OETF, dst: Linear} - ! {matrix: [0.636958048000, 0.144616904000, 0.168880975000, 0.000000000000, 0.262700212000, 0.677998072000, 0.059301716500, 0.000000000000, 4.994106570E-17, 0.028072693000, 1.060985060000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 1.000000000000]} - ! {matrix: [0.412390800000, 0.357584340000, 0.180480790000, 0.000000000000, 0.212639010000, 0.715168680000, 0.072192320000, 0.000000000000, 0.019330820000, 0.119194780000, 0.950532150000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 1.000000000000], direction: inverse} - ! name: Panasonic V-Log V-Gamut family: Camera Footage equalitygroup: "" bitdepth: 32f description: | Panasonic V-Log / V-Gamut isdata: false allocation: uniform allocationvars: [0, 1] to_reference: ! children: - ! {src: V-Log_to_linear.spi1d, interpolation: linear} - ! {matrix: [1.806576, -0.695697, -0.110879, 0, -0.170090 , 1.305955, -0.135865, 0, -0.025206, -0.154468, 1.179674, 0, 0, 0, 0, 1]} - ! name: Arri Wide Gamut / LogC EI 800 family: Camera Footage equalitygroup: "" bitdepth: 32f description: | Panasonic V-Log / V-Gamut isdata: false allocation: uniform allocationvars: [0, 1] to_reference: ! children: - ! {src: V3_LogC_800_to_linear.spi1d, interpolation: linear} - ! {matrix: [1.617523, -0.537287, -0.080237, 0, -0.070573, 1.334613, -0.26404, 0, -0.021102, -0.226954, 1.248056, 0, 0, 0, 0, 1]} - ! name: Arri Wide Gamut / LogC EI 400 family: Camera Footage equalitygroup: "" bitdepth: 32f description: | Panasonic V-Log / V-Gamut isdata: false allocation: uniform allocationvars: [0, 1] to_reference: ! children: - ! {src: V3_LogC_400_to_linear.spi1d, interpolation: linear} - ! {matrix: [1.617523, -0.537287, -0.080237, 0, -0.070573, 1.334613, -0.26404, 0, -0.021102, -0.226954, 1.248056, 0, 0, 0, 0, 1]} - ! name: Non-Colour Data family: description: | Transform to flag data as non-colour, strictly data, and avoid OCIO colour specific transforms. equalitygroup: bitdepth: 32f isdata: true allocation: uniform allocationvars: [0, 1] looks: - ! name: Greyscale process_space: Filmic Log Encoding transform: ! {matrix: [0.2126729, 0.7151521, 0.0721750, 0, 0.2126729, 0.7151521, 0.0721750, 0, 0.2126729, 0.7151521, 0.0721750, 0, 0, 0, 0, 1]} - ! name: False Colour process_space: Filmic Log Encoding transform: ! children: - ! {matrix: [0.2126729, 0.7151521, 0.0721750, 0, 0.2126729, 0.7151521, 0.0721750, 0, 0.2126729, 0.7151521, 0.0721750, 0, 0, 0, 0, 1]} - ! {src: Filmic_False_Colour.spi3d, interpolation: best} - ! name: Very High Contrast process_space: Filmic Log Encoding transform: ! {src: Filmic_to_1.20_1-00.spi1d, interpolation: linear} - ! name: High Contrast process_space: Filmic Log Encoding transform: ! {src: Filmic_to_0.99_1-0075.spi1d, interpolation: linear} - ! name: Medium High Contrast process_space: Filmic Log Encoding transform: ! {src: Filmic_to_0-85_1-011.spi1d, interpolation: best} - ! name: Base Contrast process_space: Filmic Log Encoding transform: ! {src: Filmic_to_0-70_1-03.spi1d, interpolation: linear} - ! name: Medium Low Contrast process_space: Filmic Log Encoding transform: ! {src: Filmic_to_0-60_1-04.spi1d, interpolation: linear} - ! name: Low Contrast process_space: Filmic Log Encoding transform: ! {src: Filmic_to_0-48_1-09.spi1d, interpolation: linear} - ! name: Very Low Contrast process_space: Filmic Log Encoding transform: ! @QRC_BODY@ olive-continuous/app/render/pixelformat.cpp000066400000000000000000000201301370472574300215050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "pixelformat.h" #include "OpenImageIO/imagebuf.h" #include #include #include #include "codec/oiio/oiiodecoder.h" #include "common/define.h" #include "core.h" OLIVE_NAMESPACE_ENTER bool PixelFormat::FormatHasAlphaChannel(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGBA8: case PixelFormat::PIX_FMT_RGBA16U: case PixelFormat::PIX_FMT_RGBA16F: case PixelFormat::PIX_FMT_RGBA32F: return true; case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return false; } bool PixelFormat::FormatIsFloat(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGBA16F: case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_RGBA32F: return true; case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGBA8: case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGBA16U: case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return false; } OIIO::TypeDesc::BASETYPE PixelFormat::GetOIIOTypeDesc(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGBA8: return OIIO::TypeDesc::UINT8; case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGBA16U: return OIIO::TypeDesc::UINT16; case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGBA16F: return OIIO::TypeDesc::HALF; case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_RGBA32F: return OIIO::TypeDesc::FLOAT; case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return OIIO::TypeDesc::UNKNOWN; } QString PixelFormat::GetName(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGBA8: return tr("8-bit"); case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGBA16U: return tr("16-bit Integer"); case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGBA16F: return tr("Half-Float (16-bit)"); case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_RGBA32F: return tr("Full-Float (32-bit)"); case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } return tr("Unknown (%1)").arg(format); } PixelFormat* PixelFormat::instance_ = nullptr; void PixelFormat::CreateInstance() { instance_ = new PixelFormat(); } void PixelFormat::DestroyInstance() { delete instance_; } PixelFormat *PixelFormat::instance() { return instance_; } PixelFormat::Format PixelFormat::GetConfiguredFormatForMode(RenderMode::Mode mode) { return static_cast(Core::GetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat")).toInt()); } void PixelFormat::SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format) { if (format != GetConfiguredFormatForMode(mode)) { Core::SetPreferenceForRenderMode(mode, QStringLiteral("PixelFormat"), format); emit FormatChanged(); } } PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha) { if (desc == OIIO::TypeDesc::UINT8) { return has_alpha ? PixelFormat::PIX_FMT_RGBA8 : PixelFormat::PIX_FMT_RGB8; } else if (desc == OIIO::TypeDesc::UINT16) { return has_alpha ? PixelFormat::PIX_FMT_RGBA16U : PixelFormat::PIX_FMT_RGB16U; } else if (desc == OIIO::TypeDesc::HALF) { return has_alpha ? PixelFormat::PIX_FMT_RGBA16F : PixelFormat::PIX_FMT_RGB16F; } else if (desc == OIIO::TypeDesc::FLOAT) { return has_alpha ? PixelFormat::PIX_FMT_RGBA32F : PixelFormat::PIX_FMT_RGB32F; } return PixelFormat::PIX_FMT_INVALID; } PixelFormat::Format PixelFormat::GetFormatWithAlphaChannel(PixelFormat::Format f) { switch (f) { case PIX_FMT_INVALID: case PIX_FMT_COUNT: break; case PIX_FMT_RGB8: case PIX_FMT_RGBA8: return PIX_FMT_RGBA8; case PIX_FMT_RGB16U: case PIX_FMT_RGBA16U: return PIX_FMT_RGBA16U; case PIX_FMT_RGB16F: case PIX_FMT_RGBA16F: return PIX_FMT_RGBA16F; case PIX_FMT_RGB32F: case PIX_FMT_RGBA32F: return PIX_FMT_RGBA32F; } return PIX_FMT_INVALID; } PixelFormat::Format PixelFormat::GetFormatWithoutAlphaChannel(PixelFormat::Format f) { switch (f) { case PIX_FMT_INVALID: case PIX_FMT_COUNT: break; case PIX_FMT_RGB8: case PIX_FMT_RGBA8: return PIX_FMT_RGB8; case PIX_FMT_RGB16U: case PIX_FMT_RGBA16U: return PIX_FMT_RGB16U; case PIX_FMT_RGB16F: case PIX_FMT_RGBA16F: return PIX_FMT_RGB16F; case PIX_FMT_RGB32F: case PIX_FMT_RGBA32F: return PIX_FMT_RGB32F; } return PIX_FMT_INVALID; } int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height) { return BytesPerPixel(format) * width * height; } int PixelFormat::BytesPerPixel(const PixelFormat::Format &format) { return BytesPerChannel(format) * ChannelCount(format); } int PixelFormat::BytesPerChannel(const PixelFormat::Format &format) { switch (format) { case PixelFormat::PIX_FMT_RGB8: case PixelFormat::PIX_FMT_RGBA8: return 1; case PixelFormat::PIX_FMT_RGB16U: case PixelFormat::PIX_FMT_RGB16F: case PixelFormat::PIX_FMT_RGBA16U: case PixelFormat::PIX_FMT_RGBA16F: return 2; case PixelFormat::PIX_FMT_RGB32F: case PixelFormat::PIX_FMT_RGBA32F: return 4; case PixelFormat::PIX_FMT_INVALID: case PixelFormat::PIX_FMT_COUNT: break; } qFatal("Invalid pixel format requested"); // qFatal will abort so we won't get here, but this suppresses compiler warnings return 0; } int PixelFormat::ChannelCount(const PixelFormat::Format &format) { if (PixelFormat::FormatHasAlphaChannel(format)) { return kRGBAChannels; } else { return kRGBChannels; } } FramePtr PixelFormat::ConvertPixelFormat(FramePtr frame, const PixelFormat::Format &dest_format) { if (frame->format() == dest_format) { return frame; } // Create a destination frame with the same parameters FramePtr converted = Frame::Create(); converted->set_video_params(VideoParams(frame->video_params().width(), frame->video_params().height(), dest_format)); converted->set_timestamp(frame->timestamp()); converted->allocate(); // Do the conversion through OIIO - create a buffer for the source image OIIO::ImageBuf src(OIIO::ImageSpec(frame->width(), frame->height(), ChannelCount(frame->format()), GetOIIOTypeDesc(frame->format()))); // Set the pixels (this is necessary as opposed to an OIIO buffer wrapper since Frame has // linesizes) OIIODecoder::FrameToBuffer(frame, &src); // Create a destination OIIO buffer with our destination format OIIO::ImageBuf dst(OIIO::ImageSpec(converted->width(), converted->height(), ChannelCount(converted->format()), GetOIIOTypeDesc(converted->format()))); if (dst.copy_pixels(src)) { // Convert our buffer back to a frame OIIODecoder::BufferToFrame(&dst, converted); return converted; } else { return nullptr; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/pixelformat.h000066400000000000000000000075511370472574300211660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef BITDEPTHS_H #define BITDEPTHS_H #include #include #include #include #include "render/rendermodes.h" OLIVE_NAMESPACE_ENTER class Frame; using FramePtr = std::shared_ptr; class PixelFormat : public QObject { Q_OBJECT public: /** * @brief Olive's internal supported pixel formats. */ enum Format { PIX_FMT_INVALID = -1, PIX_FMT_RGBA8, PIX_FMT_RGBA16U, PIX_FMT_RGBA16F, PIX_FMT_RGBA32F, PIX_FMT_RGB8, PIX_FMT_RGB16U, PIX_FMT_RGB16F, PIX_FMT_RGB32F, PIX_FMT_COUNT }; static void CreateInstance(); static void DestroyInstance(); static PixelFormat* instance(); /** * @brief Returns the configured pixel format for a given mode */ Format GetConfiguredFormatForMode(RenderMode::Mode mode); void SetConfiguredFormatForMode(RenderMode::Mode mode, PixelFormat::Format format); static Format OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bool has_alpha); static Format GetFormatWithAlphaChannel(Format f); static Format GetFormatWithoutAlphaChannel(Format f); /** * @brief Returns the minimum buffer size (in bytes) necessary for a given format, width, and height. * * @param format * * The format of the data the buffer should contain. Must be a member of the olive::PixelFormat enum. * * @param width * * The width (in pixels) of the buffer. * * @param height * * The height (in pixels) of the buffer. */ static int GetBufferSize(const Format &format, const int& width, const int& height); /** * @brief Returns the number of bytes per pixel for a certain format * * Different formats use different sizes of data for pixels. Use this function to determine how many bytes a pixel * requires for a certain format. The number of bytes will always be a multiple of 4 since all formats use RGBA and * are at least 1 bpc. */ static int BytesPerPixel(const Format &format); /** * @brief Returns the number of bytes per channel for a certain format */ static int BytesPerChannel(const Format& format); /** * @brief Return the number of channels in this format */ static int ChannelCount(const Format& format); /** * @brief Convert a frame to a pixel format * * If the frame's pixel format == the destination format, this just returns `frame`. */ static FramePtr ConvertPixelFormat(FramePtr frame, const Format &dest_format); /** * @brief Simple convenience function returning whether a pixel format has an alpha channel or not */ static bool FormatHasAlphaChannel(const Format& format); /** * @brief Simple convenience function returning whether a pixel format is float-based or integer-based */ static bool FormatIsFloat(const Format& format); /** * @brief Get corresponding OpenImageIO TypeDesc for a given pixel format */ static OIIO::TypeDesc::BASETYPE GetOIIOTypeDesc(const Format& format); /** * @brief Get format name */ static QString GetName(const Format& format); signals: void FormatChanged(); private: PixelFormat() = default; static PixelFormat* instance_; }; OLIVE_NAMESPACE_EXIT #endif // BITDEPTHS_H olive-continuous/app/render/playbackcache.cpp000066400000000000000000000113561370472574300217370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "playbackcache.h" #include OLIVE_NAMESPACE_ENTER void PlaybackCache::Invalidate(const TimeRange &r) { QMutexLocker locker(lock()); NoLockInvalidate(r); locker.unlock(); emit Invalidated(r); } void PlaybackCache::InvalidateAll() { QMutexLocker locker(lock()); if (length_.isNull()) { return; } TimeRange invalidate_range(0, length_); NoLockInvalidate(invalidate_range); locker.unlock(); emit Invalidated(invalidate_range); } void PlaybackCache::SetLength(const rational &r) { QMutexLocker locker(lock()); if (length_ == r) { // Same length - do nothing return; } LengthChangedEvent(length_, r); TimeRange range_diff(length_, r); if (r.isNull()) { invalidated_.clear(); jobs_.clear(); } else if (r > length_) { // If new length is greater, simply extend the invalidated range for now invalidated_.InsertTimeRange(range_diff); jobs_.append({range_diff, QDateTime::currentMSecsSinceEpoch()}); } else { // If new length is smaller, removed hashes invalidated_.RemoveTimeRange(range_diff); RemoveRangeFromJobs(range_diff); } rational old_length = length_; length_ = r; locker.unlock(); if (r > old_length) { emit Invalidated(range_diff); } else { emit Validated(range_diff); } } void PlaybackCache::Shift(const rational &from, const rational &to) { if (from == to) { return; } QMutexLocker locker(lock()); // An region between `from` and `to` will be inserted or spliced out TimeRangeList ranges_to_shift = invalidated_.Intersects(TimeRange(from, RATIONAL_MAX)); // Remove everything from the minimum point TimeRange remove_range = TimeRange(qMin(from, to), RATIONAL_MAX); NoLockValidate(remove_range); RemoveRangeFromJobs(remove_range); // Shift everything in our ranges to shift list // (`diff` is POSITIVE when moving forward -> and NEGATIVE when moving backward <-) rational diff = to - from; foreach (const TimeRange& r, ranges_to_shift) { NoLockInvalidate(r + diff); } ShiftEvent(from, to); length_ += diff; if (diff > rational()) { // If shifting forward, add this section to the invalidated region NoLockInvalidate(TimeRange(from, to)); } locker.unlock(); // Emit signals emit Validated(remove_range); foreach (const TimeRange& r, ranges_to_shift) { emit Invalidated(r + diff); } if (diff > rational()) { emit Invalidated(TimeRange(from, to)); } emit Shifted(from, to); } void PlaybackCache::NoLockInvalidate(const TimeRange &r) { Q_ASSERT(r.in() != r.out()); invalidated_.InsertTimeRange(r); RemoveRangeFromJobs(r); qint64 job_time = QDateTime::currentMSecsSinceEpoch(); jobs_.append({r, job_time}); InvalidateEvent(r); } void PlaybackCache::NoLockValidate(const TimeRange &r) { invalidated_.RemoveTimeRange(r); } void PlaybackCache::LengthChangedEvent(const rational &, const rational &) { } void PlaybackCache::InvalidateEvent(const TimeRange &) { } void PlaybackCache::ShiftEvent(const rational &, const rational &) { } void PlaybackCache::RemoveRangeFromJobs(const TimeRange &remove) { // Code shamelessly copied from TimeRangeList::RemoveTimeRange for (int i=0;i remove.in()) { // This element's out point overlaps the range's in, we'll trim it compare.set_out(remove.in()); } else if (compare.in() < remove.out() && compare.out() > remove.out()) { // This element's in point overlaps the range's out, we'll trim it compare.set_in(remove.out()); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/playbackcache.h000066400000000000000000000051511370472574300214000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PLAYBACKCACHE_H #define PLAYBACKCACHE_H #include #include #include "common/timerange.h" OLIVE_NAMESPACE_ENTER class PlaybackCache : public QObject { Q_OBJECT public: PlaybackCache(QObject* parent = nullptr) : QObject(parent) { } void Invalidate(const TimeRange& r); void InvalidateAll(); const rational& GetLength() { QMutexLocker locker(lock()); return NoLockGetLength(); } void SetLength(const rational& r); bool IsFullyValidated() { QMutexLocker locker(lock()); return invalidated_.isEmpty(); } void Shift(const rational& from, const rational& to); const TimeRangeList& GetInvalidatedRanges() { QMutexLocker locker(lock()); return NoLockGetInvalidatedRanges(); } bool HasInvalidatedRanges() { QMutexLocker locker(lock()); return !invalidated_.isEmpty(); } signals: void Invalidated(const OLIVE_NAMESPACE::TimeRange& r); void Validated(const OLIVE_NAMESPACE::TimeRange& r); void Shifted(const OLIVE_NAMESPACE::rational& from, const OLIVE_NAMESPACE::rational& to); void LengthChanged(const OLIVE_NAMESPACE::rational& r); protected: void NoLockInvalidate(const TimeRange& r); void NoLockValidate(const TimeRange& r); const rational& NoLockGetLength() const { return length_; } const TimeRangeList& NoLockGetInvalidatedRanges() { return invalidated_; } virtual void LengthChangedEvent(const rational& old, const rational& newlen); virtual void InvalidateEvent(const TimeRange& range); virtual void ShiftEvent(const rational& from, const rational& to); QMutex* lock() { return &lock_; } struct JobIdentifier { TimeRange range; qint64 job_time; }; QList jobs_; private: void RemoveRangeFromJobs(const TimeRange& remove); QMutex lock_; TimeRangeList invalidated_; rational length_; }; OLIVE_NAMESPACE_EXIT #endif // PLAYBACKCACHE_H olive-continuous/app/render/rendermodes.h000066400000000000000000000025231370472574300211350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERMODE_H #define RENDERMODE_H #include "common/define.h" OLIVE_NAMESPACE_ENTER class RenderMode { public: /** * @brief The primary different "modes" the renderer can function in */ enum Mode { /** * This render is for realtime preview ONLY and does not need to be "perfect". Nodes can use lower-accuracy functions * to save performance when possible. */ kOffline, /** * This render is some sort of export or master copy and Nodes should take time/bandwidth/system resources to produce * a higher accuracy version. */ kOnline }; }; OLIVE_NAMESPACE_EXIT #endif // RENDERMODE_H olive-continuous/app/render/shaderinfo.h000066400000000000000000000065251370472574300207560ustar00rootroot00000000000000#ifndef SHADERINFO_H #define SHADERINFO_H #include "codec/samplebuffer.h" #include "node/input.h" #include "node/inputarray.h" #include "node/value.h" OLIVE_NAMESPACE_ENTER using NodeValueMap = QHash; class AcceleratedJob { public: AcceleratedJob() = default; NodeValue GetValue(NodeInput* input) const { return value_map_.value(input->id()); } NodeValue GetValue(const QString& input) const { return value_map_.value(input); } void InsertValue(NodeInput* input, NodeValueDatabase& value) { if (input->IsArray()) { NodeInputArray* array = static_cast(input); QVector values(array->GetSize()); for (int j=0;jGetSize();j++) { NodeInput* subparam = array->At(j); values[j] = value[subparam].TakeWithMeta(subparam->data_type()); } InsertValue(input->id(), NodeValue(NodeParam::kVec2, QVariant::fromValue(values), input->parentNode())); } else { InsertValue(input->id(), value[input].TakeWithMeta(input->data_type())); } } void InsertValue(const QString& input, const NodeValue& value) { value_map_.insert(input, value); } void InsertValue(NodeInput* input, const NodeValue& value) { value_map_.insert(input->id(), value); } const NodeValueMap &GetValues() const { return value_map_; } private: NodeValueMap value_map_; }; class SampleJob : public AcceleratedJob { public: SampleJob() { samples_ = nullptr; } SampleJob(const NodeValue& value) { samples_ = value.data().value(); } SampleJob(NodeInput* from, NodeValueDatabase& db) { samples_ = db[from].Take(NodeParam::kSamples).value(); } SampleBufferPtr samples() const { return samples_; } bool HasSamples() const { return samples_ && samples_->is_allocated(); } private: SampleBufferPtr samples_; }; class GenerateJob : public AcceleratedJob { public: GenerateJob() { alpha_channel_required_ = false; } bool GetAlphaChannelRequired() const { return alpha_channel_required_; } void SetAlphaChannelRequired(bool e) { alpha_channel_required_ = e; } private: bool alpha_channel_required_; }; class ShaderJob : public GenerateJob { public: ShaderJob() { iterations_ = 1; iterative_input_ = nullptr; } const QString& GetShaderID() const { return id_; } void SetShaderID(const QString& id) { id_ = id; } void SetIterations(int iterations, NodeInput* iterative_input) { iterations_ = iterations; iterative_input_ = iterative_input; } int GetIterationCount() const { return iterations_; } NodeInput* GetIterativeInput() const { return iterative_input_; } private: QString id_; int iterations_; NodeInput* iterative_input_; }; class ShaderCode { public: ShaderCode(const QString& frag_code, const QString& vert_code) : frag_code_(frag_code), vert_code_(vert_code) { } const QString& frag_code() const { return frag_code_; } const QString& vert_code() const { return vert_code_; } private: QString frag_code_; QString vert_code_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::ShaderJob) Q_DECLARE_METATYPE(OLIVE_NAMESPACE::SampleJob) Q_DECLARE_METATYPE(OLIVE_NAMESPACE::GenerateJob) #endif // SHADERINFO_H olive-continuous/app/render/videoparams.cpp000066400000000000000000000062071370472574300214760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "videoparams.h" #include #include "core.h" OLIVE_NAMESPACE_ENTER VideoParams::VideoParams() : format_(PixelFormat::PIX_FMT_INVALID) { } VideoParams::VideoParams(const int &width, const int &height, const PixelFormat::Format &format, const int& divider) : width_(width), height_(height), format_(format), divider_(divider) { calculate_effective_size(); } VideoParams::VideoParams(const int &width, const int &height, const rational &time_base, const PixelFormat::Format &format, const int ÷r) : width_(width), height_(height), time_base_(time_base), format_(format), divider_(divider) { calculate_effective_size(); } int VideoParams::generate_auto_divider(qint64 width, qint64 height) { // Arbitrary pixel count (from 640x360) const int target_res = 230400; qint64 megapixels = width * height; double squared_divider = double(megapixels) / double(target_res); double divider = qSqrt(squared_divider); QList supported_dividers = Core::SupportedDividers(); if (divider <= supported_dividers.first()) { return supported_dividers.first(); } else if (divider >= supported_dividers.last()) { return supported_dividers.last(); } else { for (int i=1; i= prev_divider && divider <= next_divider) { double prev_diff = qAbs(prev_divider - divider); double next_diff = qAbs(next_divider - divider); if (prev_diff < next_diff) { return prev_divider; } else { return next_divider; } } } // "Safe" fallback return 2; } } bool VideoParams::operator==(const VideoParams &rhs) const { return width() == rhs.width() && height() == rhs.height() && time_base() == rhs.time_base() && format() == rhs.format() && divider() == rhs.divider(); } bool VideoParams::operator!=(const VideoParams &rhs) const { return !(*this == rhs); } void VideoParams::calculate_effective_size() { // Fast rounding up to an even number effective_width_ = qCeil(width() / divider_ * 0.5) * 2; effective_height_ = qCeil(height() / divider_ * 0.5) * 2; } bool VideoParams::is_valid() const { return (width() > 0 && height() > 0 && format_ != PixelFormat::PIX_FMT_INVALID && format_ != PixelFormat::PIX_FMT_COUNT); } OLIVE_NAMESPACE_EXIT olive-continuous/app/render/videoparams.h000066400000000000000000000040711370472574300211400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIDEOPARAMS_H #define VIDEOPARAMS_H #include "common/rational.h" #include "pixelformat.h" #include "rendermodes.h" OLIVE_NAMESPACE_ENTER class VideoParams { public: VideoParams(); VideoParams(const int& width, const int& height, const PixelFormat::Format& format, const int& divider = 1); VideoParams(const int& width, const int& height, const rational& time_base, const PixelFormat::Format& format, const int& divider = 1); const int& width() const { return width_; } const int& height() const { return height_; } const rational& time_base() const { return time_base_; } const int& divider() const { return divider_; } const int& effective_width() const { return effective_width_; } const int& effective_height() const { return effective_height_; } const PixelFormat::Format& format() const { return format_; } static int generate_auto_divider(qint64 width, qint64 height); bool is_valid() const; bool operator==(const VideoParams& rhs) const; bool operator!=(const VideoParams& rhs) const; private: void calculate_effective_size(); int width_; int height_; rational time_base_; PixelFormat::Format format_; int divider_; int effective_width_; int effective_height_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::VideoParams) #endif // VIDEOPARAMS_H olive-continuous/app/shaders/000077500000000000000000000000001370472574300166255ustar00rootroot00000000000000olive-continuous/app/shaders/CMakeLists.txt000066400000000000000000000021461370472574300213700ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . file(GLOB_RECURSE SHADER_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.frag *.vert) set(QRC_BODY "") foreach(SHADER_FILE ${SHADER_RESOURCES}) string(APPEND QRC_BODY "${SHADER_FILE}\n") configure_file(${SHADER_FILE} ${SHADER_FILE} COPYONLY) endforeach() configure_file(shaders.qrc.in shaders.qrc @ONLY) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc PARENT_SCOPE ) olive-continuous/app/shaders/alphaover.frag000066400000000000000000000012231370472574300214450ustar00rootroot00000000000000#version 150 uniform sampler2D base_in; uniform sampler2D blend_in; uniform bool base_in_enabled; uniform bool blend_in_enabled; in vec2 ove_texcoord; out vec4 fragColor; void main(void) { vec4 base_col = texture(base_in, ove_texcoord); vec4 blend_col = texture(blend_in, ove_texcoord); if (!base_in_enabled && !blend_in_enabled) { fragColor = vec4(0.0); return; } if (!base_in_enabled) { fragColor = blend_col; return; } if (!blend_in_enabled) { fragColor = base_col; return; } base_col *= 1.0 - blend_col.a; base_col += blend_col; fragColor = base_col; } olive-continuous/app/shaders/blur.frag000066400000000000000000000062261370472574300204400ustar00rootroot00000000000000#version 150 uniform sampler2D tex_in; uniform int method_in; uniform float radius_in; uniform bool horiz_in; uniform bool vert_in; uniform bool repeat_edge_pixels_in; uniform vec2 ove_resolution; uniform int ove_iteration; in vec2 ove_texcoord; out vec4 fragColor; // Gaussian function uses PI #define M_PI 3.1415926535897932384626433832795 // Methods #define METHOD_BOX_BLUR 0 #define METHOD_GAUSSIAN_BLUR 1 // Mode #define MODE_NONE 0 #define MODE_HORIZONTAL 1 #define MODE_VERTICAL 2 // Single gaussian formula (unused, mainly here for documentation/just in case) //float gaussian(float x, float sigma) { // return (1.0/(sigma*sqrt(2.0*M_PI)))*exp(-0.5*pow(x/sigma, 2.0)); //} // Double gaussian formula, actually used in the code below // Should be faster than the single gaussian above since it doesn't need sqrt() float gaussian2(float x, float y, float sigma) { return (1.0/((sigma*sigma)*2.0*M_PI))*exp(-0.5*(((x*x) + (y*y))/(sigma*sigma))); } int determine_mode() { if (radius_in == 0.0) { return MODE_NONE; } if (!horiz_in && !vert_in) { return MODE_NONE; } if (horiz_in && !vert_in) { return MODE_HORIZONTAL; } if (vert_in && !horiz_in) { return MODE_VERTICAL; } if (ove_iteration == 0) { return MODE_HORIZONTAL; } if (ove_iteration == 1) { return MODE_VERTICAL; } } void main(void) { int mode = determine_mode(); if (mode == MODE_NONE) { fragColor = texture(tex_in, ove_texcoord); return; } // We only sample on hard pixels, so we don't accept decimal radii float real_radius = ceil(radius_in); vec4 composite = vec4(0.0); float divider, sigma; if (method_in == METHOD_BOX_BLUR) { // Calculate the weight of each pixel based on the radius divider = 1.0 / real_radius; } else if (method_in == METHOD_GAUSSIAN_BLUR) { // Using (radius = 3 * sigma) because 3 standard deviations covers 97% of the blur according to this document: // http://chemaguerra.com/gaussian-filter-radius/ sigma = real_radius; real_radius *= 3.0; // Use gaussian formula to calculate the weight of all pixels divider = 0.0; for (float i = -real_radius + 0.5; i <= real_radius; i += 2.0) { divider += gaussian2(i, 0.0, sigma); } } for (float i = -real_radius + 0.5; i <= real_radius; i += 2.0) { float weight; if (method_in == METHOD_BOX_BLUR) { weight = divider; } else if (method_in == METHOD_GAUSSIAN_BLUR) { weight = gaussian2(i, 0.0, sigma) / divider; } vec2 pixel_coord = ove_texcoord; if (mode == MODE_HORIZONTAL) { pixel_coord.x += i / ove_resolution.x; } else if (mode == MODE_VERTICAL) { pixel_coord.y += i / ove_resolution.y; } if (repeat_edge_pixels_in || (pixel_coord.x >= 0.0 && pixel_coord.x < 1.0 && pixel_coord.y >= 0.0 && pixel_coord.y < 1.0)) { composite += texture(tex_in, pixel_coord) * weight; } } fragColor = composite; } olive-continuous/app/shaders/colorgradient.frag000066400000000000000000000007671370472574300223340ustar00rootroot00000000000000#version 150 // Inputs uniform int orientation; uniform vec3 color_a; uniform vec3 color_b; // Standard inputs uniform vec2 ove_resolution; in vec2 ove_texcoord; out vec4 fragColor; void main(void) { float t; // This very roughly conforms to Qt::Orientation if (orientation == 1) { // Horizontal orientation t = ove_texcoord.x; } else { // Vertical orientation t = 1.0 - ove_texcoord.y; } fragColor = vec4(mix(color_a, color_b, t), 1.0); } olive-continuous/app/shaders/colorwheel.frag000066400000000000000000000043321370472574300216330ustar00rootroot00000000000000#version 150 // Custom inputs uniform float hsv_value; // Standard inputs uniform vec2 ove_resolution; in vec2 ove_texcoord; out vec4 fragColor; // Color wheel uses PI #define M_PI 3.1415926535897932384626433832795 vec3 hsv_to_rgb(float H, float S, float V) { float C = S * V; float X = C * (1.0 - abs(mod(H / 60.0, 2.0) - 1.0)); float m = V - C; float Rs, Gs, Bs; if(H >= 0.0 && H < 60.0) { Rs = C; Gs = X; Bs = 0.0; } else if(H >= 60.0 && H < 120.0) { Rs = X; Gs = C; Bs = 0.0; } else if(H >= 120.0 && H < 180.0) { Rs = 0.0; Gs = C; Bs = X; } else if(H >= 180.0 && H < 240.0) { Rs = 0.0; Gs = X; Bs = C; } else if(H >= 240.0 && H < 300.0) { Rs = X; Gs = 0.0; Bs = C; } else { Rs = C; Gs = 0.0; Bs = X; } return vec3(Rs + m, Gs + m, Bs + m); } void main(void) { vec2 center = vec2(0.5, 0.5); float radius = 0.5; vec2 flipped_texcoord = vec2(ove_texcoord.x, (1.0 - ove_texcoord.y)); // Calculate scale if (ove_resolution.x != ove_resolution.y) { // Scale around center flipped_texcoord -= vec2(0.5, 0.5); if (ove_resolution.x > ove_resolution.y) { flipped_texcoord.x *= ove_resolution.x / ove_resolution.y; } else { flipped_texcoord.y *= ove_resolution.y / ove_resolution.x; } flipped_texcoord += vec2(0.5, 0.5); } float dist = distance(flipped_texcoord, center); if (dist <= radius) { float opposite = flipped_texcoord.y - center.y; float adjacent = flipped_texcoord.x - center.x; float hue = atan(opposite, adjacent) * 180.0 / M_PI + 180.0; float sat = dist / radius; // Extremely simple antialiasing, we taper off the edges between (radius) and (radius - 1) float pixel_radius = min(ove_resolution.x, ove_resolution.y) * 0.5; float pixel_dist = (pixel_radius / radius) * dist; float alpha = min((pixel_radius - pixel_dist), 1.0); fragColor = vec4(hsv_to_rgb(hue, sat, hsv_value), alpha); } else { fragColor = vec4(0.0); } } olive-continuous/app/shaders/crossdissolve.frag000066400000000000000000000016011370472574300223660ustar00rootroot00000000000000#version 150 #define LINEAR_CURVE 0 #define EXPONENTIAL_CURVE 1 #define LOGARITHMIC_CURVE 2 uniform sampler2D out_block_in; uniform sampler2D in_block_in; uniform bool out_block_in_enabled; uniform bool in_block_in_enabled; uniform int curve_in; uniform float ove_tprog_all; in vec2 ove_texcoord; out vec4 fragColor; float TransformCurve(float linear) { if (curve_in == EXPONENTIAL_CURVE) { return linear * linear; } else if (curve_in == LOGARITHMIC_CURVE) { return sqrt(linear); } else { return linear; } } void main(void) { vec4 composite = vec4(0.0); if (out_block_in_enabled) { composite += texture(out_block_in, ove_texcoord) * TransformCurve(1.0 - ove_tprog_all); } if (in_block_in_enabled) { composite += texture(in_block_in, ove_texcoord) * TransformCurve(ove_tprog_all); } fragColor = composite; } olive-continuous/app/shaders/diptoblack.frag000066400000000000000000000016401370472574300216030ustar00rootroot00000000000000#version 150 uniform sampler2D out_block_in; uniform sampler2D in_block_in; uniform bool out_block_in_enabled; uniform bool in_block_in_enabled; uniform vec4 color_in; uniform float ove_tprog_all; uniform float ove_tprog_out; uniform float ove_tprog_in; in vec2 ove_texcoord; out vec4 fragColor; void main(void) { if (out_block_in_enabled && in_block_in_enabled) { vec4 out_block_col = mix(texture(out_block_in, ove_texcoord), color_in, ove_tprog_out); vec4 in_block_col = mix(texture(in_block_in, ove_texcoord), color_in, 1.0 - ove_tprog_in); fragColor = out_block_col + in_block_col; } else if (out_block_in_enabled) { fragColor = mix(texture(out_block_in, ove_texcoord), color_in, ove_tprog_all); } else if (in_block_in_enabled) { fragColor = mix(texture(in_block_in, ove_texcoord), color_in, 1.0 - ove_tprog_all); } else { fragColor = vec4(0.0); } } olive-continuous/app/shaders/matrix.vert000066400000000000000000000013241370472574300210330ustar00rootroot00000000000000#version 150 uniform mat4 %1; uniform vec2 %2_resolution; uniform vec2 ove_resolution; in vec4 a_position; in vec2 a_texcoord; out vec2 ove_texcoord; mat4 scale_mat4(vec3 scale) { return mat4( scale.x, 0.0, 0.0, 0.0, 0.0, scale.y, 0.0, 0.0, 0.0, 0.0, scale.z, 0.0, 0.0, 0.0, 0.0, 1.0 ); } void main() { // Create identity matrix mat4 transform = mat4(1.0); // Scale to square transform *= scale_mat4(vec3(1.0 / ove_resolution, 1.0)); // Multiply by received matrix transform *= %1; // Scale back out to footage size transform *= scale_mat4(vec3(%2_resolution, 1.0)); gl_Position = transform * a_position; ove_texcoord = a_texcoord; } olive-continuous/app/shaders/polygon.frag000066400000000000000000000021051370472574300211530ustar00rootroot00000000000000#version 150 uniform vec2[256] points_in; uniform int points_in_count; uniform vec4 color_in; uniform vec2 ove_resolution; in vec2 ove_texcoord; out vec4 fragColor; /* int pnpoly(int npol, float *xp, float *yp, float x, float y) { int i, j, c = 0; for (i = 0, j = npol-1; i < npol; j = i++) { if ((((yp[i] <= y) && (y < yp[j])) || ((yp[j] <= y) && (y < yp[i]))) && (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])) c = !c; } return c; } */ bool pnpoly(vec2 p) { bool c = false; int i, j; for (i = 0, j = points_in_count-1; i < points_in_count; j = i++) { if ((((points_in[i].y <= p.y) && (p.y < points_in[j].y)) || ((points_in[j].y <= p.y) && (p.y < points_in[i].y))) && (p.x < (points_in[j].x - points_in[i].x) * (p.y - points_in[i].y) / (points_in[j].y - points_in[i].y) + points_in[i].x)) c = !c; } return c; } void main(void) { if (points_in_count > 0 && pnpoly(ove_texcoord * ove_resolution)) { fragColor = color_in; } else { fragColor = vec4(0.0, 0.0, 0.0, 0.0); } } olive-continuous/app/shaders/rgbwaveform.frag000066400000000000000000000046141370472574300220140ustar00rootroot00000000000000// Adapted from "RGB Waveform" by lebek // https://www.shadertoy.com/view/4dK3Wc #version 150 uniform sampler2D ove_maintex; uniform vec2 ove_resolution; uniform vec2 ove_viewport; uniform vec3 luma_coeffs; uniform float waveform_scale; uniform vec2 waveform_dims; uniform vec4 waveform_region; uniform vec4 waveform_uv; in vec2 ove_texcoord; out vec4 fragColor; void main(void) { vec3 col = vec3(0.0); // Set an increment default to 10 bit encodings. This would likely be // better served as a UI control, as waveforms will change their combing // based on how granular the increment is set. For example, it can be // challenging to spot 8 bit combing with an increment of 1. / 2.^8 - 1. float increment = 1.0 / (pow(2, 10) - 1.0); float maxb = waveform_dims.y + increment; float minb = waveform_dims.y - increment; // Intensity would make sense to also expose via the UI, as a density // slider allows you to peek past certain values or reveal very low // values. Hard coding it for now, as there isn't a clear way to have // the various bit depth / code values always display at a consistent // emission output strength. float intensity = 0.10; int y_lim = int(waveform_dims.y); vec3 cur_col = vec3(0.0); vec3 cur_lum = vec3(0.0); if ( (gl_FragCoord.x >= waveform_region.x) && (gl_FragCoord.y >= waveform_region.y) && (gl_FragCoord.x < waveform_region.z) && (gl_FragCoord.y < waveform_region.w) ) { // col = vec3(0.5, 0.5, 0.0); // int start = int(waveform_region.y); int stop = int(waveform_dims.y); float ratio = 0.0; float waveform_x = (ove_texcoord.x - waveform_uv.x) / waveform_scale; float waveform_y = (ove_texcoord.y - waveform_uv.y) / waveform_scale; for (int i = 0; i < waveform_dims.y; i++) { ratio = float(i) / float(waveform_dims.y - 1); cur_col = texture( ove_maintex, vec2(waveform_x, ratio) ).rgb; col += step(vec3(waveform_y - increment), cur_col) * step(cur_col, vec3(waveform_y + increment)) * intensity; cur_lum = vec3(dot(cur_col, luma_coeffs)); col += step(vec3(waveform_y - increment), cur_lum) * step(cur_lum, vec3(waveform_y + increment)) * intensity; } } fragColor = vec4(col, 1.0); } olive-continuous/app/shaders/shaders.qrc.in000066400000000000000000000001131370472574300213650ustar00rootroot00000000000000 @QRC_BODY@ olive-continuous/app/shaders/solid.frag000066400000000000000000000001511370472574300205750ustar00rootroot00000000000000#version 150 uniform vec4 color_in; out vec4 fragColor; void main(void) { fragColor = color_in; } olive-continuous/app/shaders/stroke.frag000066400000000000000000000036071370472574300210030ustar00rootroot00000000000000#version 150 // Node parameter inputs uniform sampler2D tex_in; uniform vec4 color_in; uniform float radius_in; uniform float opacity_in; uniform bool inner_in; // Standard inputs uniform vec2 ove_resolution; uniform int ove_iteration; in vec2 ove_texcoord; out vec4 fragColor; void main(void) { vec4 pixel_here = texture(tex_in, ove_texcoord); // Detect no-op situations if (radius_in == 0.0 || opacity_in == 0.0 || (inner_in && pixel_here.a == 0.0) || (!inner_in && pixel_here.a == 1.0)) { // No-op, do nothing fragColor = pixel_here; return; } float radius = ceil(radius_in); float stroke_weight = 0.0; // Loop over box for (float i=-radius + 0.5; i<=radius; i += 2.0) { float x_coord = i / ove_resolution.x; for (float j=-radius + 0.5; j<=radius; j += 2.0) { float y_coord = j / ove_resolution.y; if (abs(length(vec2(i, j))) < radius) { // Get pixel here float alpha = texture(tex_in, ove_texcoord + vec2(x_coord, y_coord)).a; if (inner_in) { alpha = 1.0 - alpha; } stroke_weight += alpha; if (stroke_weight >= 1.0) { break; } } } if (stroke_weight >= 1.0) { stroke_weight = 1.0; break; } } stroke_weight *= opacity_in; if (inner_in) { stroke_weight *= pixel_here.a; } // Make RGBA color vec4 stroke_col = color_in * stroke_weight; if (inner_in) { // Alpha over the stroke over the texture stroke_col = pixel_here * (1.0 - stroke_col.a) + stroke_col; } else { // Alpha over the texture over the stroke stroke_col = stroke_col * (1.0 - pixel_here.a) + pixel_here; } fragColor = stroke_col; } olive-continuous/app/task/000077500000000000000000000000001370472574300161365ustar00rootroot00000000000000olive-continuous/app/task/CMakeLists.txt000066400000000000000000000016561370472574300207060ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(cache) add_subdirectory(conform) add_subdirectory(export) add_subdirectory(project) add_subdirectory(render) set(OLIVE_SOURCES ${OLIVE_SOURCES} task/task.h task/taskmanager.h task/taskmanager.cpp PARENT_SCOPE ) olive-continuous/app/task/cache/000077500000000000000000000000001370472574300172015ustar00rootroot00000000000000olive-continuous/app/task/cache/CMakeLists.txt000066400000000000000000000015331370472574300217430ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/cache/cache.h task/cache/cache.cpp task/cache/footagecache.h task/cache/footagecache.cpp PARENT_SCOPE ) olive-continuous/app/task/cache/cache.cpp000066400000000000000000000052271370472574300207560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "cache.h" #include #include #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER CacheTask::CacheTask(RenderBackend *backend, bool in_out_only) : RenderTask(backend), in_out_only_(in_out_only) { Init(); } CacheTask::CacheTask(ViewerOutput* viewer, const VideoParams& vparams, const AudioParams &aparams, bool in_out_only) : RenderTask(viewer, vparams, aparams), in_out_only_(in_out_only) { Init(); } bool CacheTask::Run() { // Get list of invalidated ranges TimeRangeList video_range = viewer()->video_frame_cache()->GetInvalidatedRanges(); TimeRangeList audio_range = viewer()->audio_playback_cache()->GetInvalidatedRanges(); // If we're caching only in-out, limit the range to that if (in_out_only_) { Sequence* s = static_cast(viewer()->parent()); if (s->workarea()->enabled()) { video_range = video_range.Intersects(s->workarea()->range()); audio_range = audio_range.Intersects(s->workarea()->range()); } } Render(video_range, audio_range, true); download_threads_.waitForDone(); return true; } QFuture CacheTask::DownloadFrame(FramePtr frame, const QByteArray &hash) { return QtConcurrent::run(&download_threads_, FrameHashCache::SaveCacheFrame, hash, frame); } void CacheTask::FrameDownloaded(const QByteArray &hash, const std::list ×) { foreach (const rational& t, times) { viewer()->video_frame_cache()->SetHash(t, hash, job_time()); } } void CacheTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) { if (samples) { viewer()->audio_playback_cache()->WritePCM(range, samples, job_time()); } else { viewer()->audio_playback_cache()->WriteSilence(range); } } void CacheTask::Init() { SetTitle(tr("Caching \"%1\"").arg(viewer()->media_name())); backend()->EnablePreviewGeneration(job_time()); // Render fastest quality backend()->SetRenderMode(RenderMode::kOffline); } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/cache/cache.h000066400000000000000000000030251370472574300204150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CACHETASK_H #define CACHETASK_H #include #include "task/render/render.h" OLIVE_NAMESPACE_ENTER class CacheTask : public RenderTask { Q_OBJECT public: CacheTask(RenderBackend* backend, bool in_out_only); CacheTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams, bool in_out_only); protected: virtual bool Run() override; virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) override; virtual void FrameDownloaded(const QByteArray& hash, const std::list& times) override; virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; private: void Init(); bool in_out_only_; QThreadPool download_threads_; }; OLIVE_NAMESPACE_EXIT #endif // CACHETASK_H olive-continuous/app/task/cache/footagecache.cpp000066400000000000000000000031721370472574300223200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "footagecache.h" #include "common/timecodefunctions.h" OLIVE_NAMESPACE_ENTER FootageCacheTask::FootageCacheTask(VideoStreamPtr footage, Sequence *sequence) : CacheTask(new ViewerOutput(), sequence->video_params(), sequence->audio_params(), false), footage_(footage) { viewer()->set_video_params(sequence->video_params()); viewer()->set_audio_params(sequence->audio_params()); backend()->SetVideoParams(sequence->video_params()); backend()->SetAudioParams(sequence->audio_params()); video_node_ = new VideoInput(); video_node_->SetFootage(footage); NodeParam::ConnectEdge(video_node_->output(), viewer()->texture_input()); SetTitle(tr("Pre-caching %1:%2").arg(footage->footage()->filename(), QString::number(footage->index()))); backend()->ProcessUpdateQueue(); } FootageCacheTask::~FootageCacheTask() { delete viewer(); delete video_node_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/cache/footagecache.h000066400000000000000000000023131370472574300217610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOOTAGECACHETASK_H #define FOOTAGECACHETASK_H #include "cache.h" #include "node/input/media/video/video.h" #include "project/item/footage/footage.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER class FootageCacheTask : public CacheTask { Q_OBJECT public: FootageCacheTask(VideoStreamPtr footage, Sequence* sequence); virtual ~FootageCacheTask() override; private: VideoStreamPtr footage_; VideoInput* video_node_; }; OLIVE_NAMESPACE_EXIT #endif // FOOTAGECACHETASK_H olive-continuous/app/task/conform/000077500000000000000000000000001370472574300176015ustar00rootroot00000000000000olive-continuous/app/task/conform/CMakeLists.txt000066400000000000000000000014511370472574300223420ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/conform/conform.h task/conform/conform.cpp PARENT_SCOPE ) olive-continuous/app/task/conform/conform.cpp000066400000000000000000000030631370472574300217520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "conform.h" #include "codec/decoder.h" OLIVE_NAMESPACE_ENTER ConformTask::ConformTask(AudioStreamPtr stream, const AudioParams& params) : stream_(stream), params_(params) { SetTitle(tr("Conforming Audio %1:%2").arg(stream_->footage()->filename(), QString::number(stream_->index()))); } bool ConformTask::Run() { if (stream_->footage()->decoder().isEmpty()) { SetError(tr("Failed to find decoder to conform audio stream")); return false; } else { DecoderPtr decoder = Decoder::CreateFromID(stream_->footage()->decoder()); decoder->set_stream(stream_); connect(decoder.get(), &Decoder::IndexProgress, this, &ConformTask::ProgressChanged); if (!decoder->ConformAudio(&IsCancelled(), params_)) { SetError(tr("Failed to conform audio")); return false; } else { return true; } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/conform/conform.h000066400000000000000000000021671370472574300214230ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CONFORMTASK_H #define CONFORMTASK_H #include "project/item/footage/audiostream.h" #include "render/audioparams.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class ConformTask : public Task { public: ConformTask(AudioStreamPtr stream, const AudioParams& params); protected: virtual bool Run() override; private: AudioStreamPtr stream_; AudioParams params_; }; OLIVE_NAMESPACE_EXIT #endif // CONFORMTASK_H olive-continuous/app/task/export/000077500000000000000000000000001370472574300174575ustar00rootroot00000000000000olive-continuous/app/task/export/CMakeLists.txt000066400000000000000000000015411370472574300222200ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/export/export.h task/export/export.cpp task/export/exportparams.h task/export/exportparams.cpp PARENT_SCOPE ) olive-continuous/app/task/export/export.cpp000066400000000000000000000120051370472574300215020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "export.h" #include "common/timecodefunctions.h" #include "render/colormanager.h" OLIVE_NAMESPACE_ENTER ExportTask::ExportTask(ViewerOutput* viewer_node, ColorManager* color_manager, const ExportParams& params) : RenderTask(viewer_node, params.video_params(), params.audio_params()), color_manager_(color_manager), params_(params) { SetTitle(tr("Exporting \"%1\"").arg(viewer_node->media_name())); // Render highest quality backend()->SetRenderMode(RenderMode::kOnline); } bool ExportTask::Run() { TimeRange range; encoder_ = Encoder::CreateFromID(params_.encoder(), params_); if (!encoder_) { SetError(tr("Failed to create encoder")); return false; } if (!encoder_->Open()) { SetError(tr("Failed to open file")); encoder_->deleteLater(); return false; } if (params_.has_custom_range()) { // Render custom range only range = params_.custom_range(); } else { // Render entire sequence range = TimeRange(0, viewer()->GetLength()); } frame_time_ = Timecode::time_to_timestamp(range.in(), viewer()->video_params().time_base()); if (params_.video_enabled()) { // If a transformation matrix is applied to this video, create it here if (params_.video_scaling_method() != ExportParams::kStretch) { QMatrix4x4 mat = ExportParams::GenerateMatrix(params_.video_scaling_method(), viewer()->video_params().width(), viewer()->video_params().height(), params_.video_params().width(), params_.video_params().height()); backend()->SetVideoDownloadMatrix(mat); } // Create color processor color_processor_ = ColorProcessor::Create(color_manager_, color_manager_->GetReferenceColorSpace(), params_.color_transform()); } if (params_.audio_enabled()) { audio_data_.SetParameters(audio_params()); } // Start render process TimeRangeList video_range, audio_range; if (params_.video_enabled()) { video_range.append(range); } if (params_.audio_enabled()) { audio_range.append(range); audio_data_.SetLength(range.length()); } Render(video_range, audio_range, false); bool success = true; if (params_.audio_enabled()) { // Write audio data now encoder_->WriteAudio(audio_params(), audio_data_.GetCacheFilename()); } encoder_->Close(); encoder_->deleteLater(); return success; } void FrameColorConvert(ColorProcessorPtr processor, FramePtr frame) { // OCIO conversion requires a frame in 32F format if (frame->format() != PixelFormat::PIX_FMT_RGBA32F) { frame = PixelFormat::ConvertPixelFormat(frame, PixelFormat::PIX_FMT_RGBA32F); } // Color conversion must be done with unassociated alpha, and the pipeline is always associated ColorManager::DisassociateAlpha(frame); // Convert color space processor->ConvertFrame(frame); // Re-associate alpha ColorManager::ReassociateAlpha(frame); } QFuture ExportTask::DownloadFrame(FramePtr frame, const QByteArray &hash) { rendered_frame_.insert(hash, frame); return QtConcurrent::run(FrameColorConvert, color_processor_, frame); } void ExportTask::FrameDownloaded(const QByteArray &hash, const std::list ×) { FramePtr f = rendered_frame_.value(hash); foreach (const rational& t, times) { time_map_.insert(t, f); } forever { rational real_time = Timecode::timestamp_to_time(frame_time_, viewer()->video_params().time_base()); if (!time_map_.contains(real_time)) { break; } // Unfortunately this can't be done in another thread since the frames need to be sent // one after the other chronologically. encoder_->WriteFrame(time_map_.take(real_time), real_time); frame_time_++; } } void ExportTask::AudioDownloaded(const TimeRange &range, SampleBufferPtr samples) { TimeRange adjusted_range = range; if (params_.has_custom_range()) { adjusted_range -= params_.custom_range().in(); } audio_data_.WritePCM(adjusted_range, samples, QDateTime::currentMSecsSinceEpoch()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/export/export.h000066400000000000000000000033121370472574300211500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTTASK_H #define EXPORTTASK_H #include "exportparams.h" #include "node/output/viewer/viewer.h" #include "render/colorprocessor.h" #include "task/render/render.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class ExportTask : public RenderTask { Q_OBJECT public: ExportTask(ViewerOutput *viewer_node, ColorManager *color_manager, const ExportParams ¶ms); protected: virtual bool Run() override; virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) override; virtual void FrameDownloaded(const QByteArray& hash, const std::list& times) override; virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) override; private: QHash rendered_frame_; QHash time_map_; ColorManager* color_manager_; ExportParams params_; Encoder* encoder_; ColorProcessorPtr color_processor_; int64_t frame_time_; AudioPlaybackCache audio_data_; }; OLIVE_NAMESPACE_EXIT #endif // EXPORTTASK_H olive-continuous/app/task/export/exportparams.cpp000066400000000000000000000065001370472574300227110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "exportparams.h" OLIVE_NAMESPACE_ENTER ExportParams::ExportParams() : video_scaling_method_(kStretch), has_custom_range_(false) { } const QString &ExportParams::encoder() const { return encoder_id_; } void ExportParams::set_encoder(const QString &id) { encoder_id_ = id; } bool ExportParams::has_custom_range() const { return has_custom_range_; } const TimeRange &ExportParams::custom_range() const { return custom_range_; } void ExportParams::set_custom_range(const TimeRange &custom_range) { has_custom_range_ = true; custom_range_ = custom_range; } const ExportParams::VideoScalingMethod &ExportParams::video_scaling_method() const { return video_scaling_method_; } void ExportParams::set_video_scaling_method(const ExportParams::VideoScalingMethod &video_scaling_method) { video_scaling_method_ = video_scaling_method; } const ColorTransform &ExportParams::color_transform() const { return color_transform_; } void ExportParams::set_color_transform(const ColorTransform &color_transform) { color_transform_ = color_transform; } QMatrix4x4 ExportParams::GenerateMatrix(ExportParams::VideoScalingMethod method, int source_width, int source_height, int dest_width, int dest_height) { QMatrix4x4 preview_matrix; if (method == ExportParams::kStretch) { return preview_matrix; } float export_ar = static_cast(dest_width) / static_cast(dest_height); float source_ar = static_cast(source_width) / static_cast(source_height); if (qFuzzyCompare(export_ar, source_ar)) { return preview_matrix; } if ((export_ar > source_ar) == (method == ExportParams::kFit)) { preview_matrix.scale(source_ar / export_ar, 1.0F); } else { preview_matrix.scale(1.0F, export_ar / source_ar); } return preview_matrix; } void ExportParams::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("export")); writer->writeTextElement(QStringLiteral("encoder"), encoder_id_); writer->writeTextElement(QStringLiteral("vscale"), QString::number(video_scaling_method_)); writer->writeTextElement(QStringLiteral("range"), QString::number(has_custom_range_)); writer->writeTextElement(QStringLiteral("customrangein"), custom_range_.in().toString()); writer->writeTextElement(QStringLiteral("customrangeout"), custom_range_.out().toString()); // FIXME: Change this when color chains are implemented writer->writeTextElement(QStringLiteral("color"), color_transform_.output()); EncodingParams::Save(writer); writer->writeEndElement(); // export } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/export/exportparams.h000066400000000000000000000037311370472574300223610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef EXPORTPARAMS_H #define EXPORTPARAMS_H #include #include "codec/encoder.h" #include "node/output/viewer/viewer.h" #include "render/colortransform.h" OLIVE_NAMESPACE_ENTER class ExportParams : public EncodingParams { public: enum VideoScalingMethod { kFit, kStretch, kCrop }; ExportParams(); const QString& encoder() const; void set_encoder(const QString& id); bool has_custom_range() const; const TimeRange& custom_range() const; void set_custom_range(const TimeRange& custom_range); const VideoScalingMethod& video_scaling_method() const; void set_video_scaling_method(const VideoScalingMethod& video_scaling_method); const ColorTransform& color_transform() const; void set_color_transform(const ColorTransform& color_transform); static QMatrix4x4 GenerateMatrix(ExportParams::VideoScalingMethod method, int source_width, int source_height, int dest_width, int dest_height); virtual void Save(QXmlStreamWriter* writer) const override; private: QString encoder_id_; VideoScalingMethod video_scaling_method_; bool has_custom_range_; TimeRange custom_range_; ColorTransform color_transform_; }; OLIVE_NAMESPACE_EXIT #endif // EXPORTPARAMS_H olive-continuous/app/task/project/000077500000000000000000000000001370472574300176045ustar00rootroot00000000000000olive-continuous/app/task/project/CMakeLists.txt000066400000000000000000000014751370472574300223530ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(import) add_subdirectory(load) add_subdirectory(save) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/task/project/import/000077500000000000000000000000001370472574300211165ustar00rootroot00000000000000olive-continuous/app/task/project/import/CMakeLists.txt000066400000000000000000000014651370472574300236640ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/project/import/import.h task/project/import/import.cpp PARENT_SCOPE ) olive-continuous/app/task/project/import/import.cpp000066400000000000000000000077251370472574300231470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "import.h" #include #include #include "core.h" #include "codec/decoder.h" #include "project/item/footage/footage.h" OLIVE_NAMESPACE_ENTER ProjectImportTask::ProjectImportTask(ProjectViewModel *model, Folder *folder, const QStringList &filenames) : command_(nullptr), model_(model), folder_(folder) { foreach (const QString& f, filenames) { filenames_.append(f); } file_count_ = Core::CountFilesInFileList(filenames_); SetTitle(tr("Importing %1 files").arg(file_count_)); } const int &ProjectImportTask::GetFileCount() const { return file_count_; } bool ProjectImportTask::Run() { command_ = new QUndoCommand(); int imported = 0; Import(folder_, filenames_, imported, command_); if (IsCancelled()) { delete command_; command_ = nullptr; return false; } else { return true; } } void ProjectImportTask::Import(Folder *folder, const QFileInfoList &import, int &counter, QUndoCommand* parent_command) { foreach (const QFileInfo& file_info, import) { if (IsCancelled()) { break; } // Check if this file is a directory if (file_info.isDir()) { // QDir::entryList only returns filenames, we can use entryInfoList() to get full paths QFileInfoList entry_list = QDir(file_info.absoluteFilePath()).entryInfoList(); // Strip out "." and ".." (for some reason QDir::NoDotAndDotDot doesn't work with entryInfoList, so we have to // check manually) for (int i=0;i(); f->set_name(file_info.fileName()); // Create undoable command that adds the items to the model new ProjectViewModel::AddItemCommand(model_, folder, f, parent_command); // Recursively follow this path Import(static_cast(f.get()), entry_list, counter, parent_command); } } else { FootagePtr f = std::make_shared(); f->set_filename(file_info.absoluteFilePath()); f->set_name(file_info.fileName()); f->set_timestamp(file_info.lastModified()); // Probe will fail if a project isn't set because ImageStream and its derivatives try to connect to the project's // ColorManager instance // FIXME: Perhaps re-think this approach at some point f->set_project(model_->project()); Decoder::ProbeMedia(f.get(), &IsCancelled()); f->set_project(nullptr); if (f->status() != Footage::kInvalid) { // Create undoable command that adds the items to the model new ProjectViewModel::AddItemCommand(model_, folder, f, parent_command); } counter++; emit ProgressChanged((counter * 100) / file_count_); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/project/import/import.h000066400000000000000000000027401370472574300226040ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTIMPORTMANAGER_H #define PROJECTIMPORTMANAGER_H #include #include #include "project/projectviewmodel.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class ProjectImportTask : public Task { Q_OBJECT public: ProjectImportTask(ProjectViewModel* model, Folder* folder, const QStringList& filenames); const int& GetFileCount() const; QUndoCommand* GetCommand() const { return command_; } protected: virtual bool Run() override; private: void Import(Folder* folder, const QFileInfoList &import, int& counter, QUndoCommand *parent_command); QUndoCommand* command_; ProjectViewModel* model_; Folder* folder_; QFileInfoList filenames_; int file_count_; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTIMPORTMANAGER_H olive-continuous/app/task/project/load/000077500000000000000000000000001370472574300205235ustar00rootroot00000000000000olive-continuous/app/task/project/load/CMakeLists.txt000066400000000000000000000014551370472574300232700ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/project/load/load.h task/project/load/load.cpp PARENT_SCOPE ) olive-continuous/app/task/project/load/load.cpp000066400000000000000000000045461370472574300221570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "load.h" #include #include #include #include "common/xmlutils.h" OLIVE_NAMESPACE_ENTER ProjectLoadTask::ProjectLoadTask(const QString &filename) : filename_(filename) { SetTitle(tr("Loading '%1'").arg(filename)); } bool ProjectLoadTask::Run() { QFile project_file(filename_); if (project_file.open(QFile::ReadOnly | QFile::Text)) { QXmlStreamReader reader(&project_file); while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("olive")) { while(XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("version")) { qDebug() << "Project version:" << reader.readElementText(); } else if (reader.name() == QStringLiteral("project")) { ProjectPtr project = std::make_shared(); project->set_filename(filename_); MainWindowLayoutInfo layout; project->Load(&reader, &layout, &IsCancelled()); // Ensure project is in main thread moveToThread(qApp->thread()); if (!IsCancelled()) { projects_.append(project); layout_info_.append(layout); } } else { reader.skipCurrentElement(); } } } else { reader.skipCurrentElement(); } } project_file.close(); emit ProgressChanged(1); if (reader.hasError()) { SetError(reader.errorString()); return false; } else { return true; } } else { SetError(tr("Failed to read file \"%1\" for reading.").arg(filename_)); return false; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/project/load/load.h000066400000000000000000000025551370472574300216220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTLOADMANAGER_H #define PROJECTLOADMANAGER_H #include "project/project.h" #include "task/task.h" #include "window/mainwindow/mainwindowlayoutinfo.h" OLIVE_NAMESPACE_ENTER class ProjectLoadTask : public Task { Q_OBJECT public: ProjectLoadTask(const QString& filename); const QList& GetLoadedProjects() const { return projects_; } const QList& GetLoadedLayouts() const { return layout_info_; } protected: virtual bool Run() override; private: QList projects_; QList layout_info_; QString filename_; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTLOADMANAGER_H olive-continuous/app/task/project/save/000077500000000000000000000000001370472574300205425ustar00rootroot00000000000000olive-continuous/app/task/project/save/CMakeLists.txt000066400000000000000000000014551370472574300233070ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/project/save/save.h task/project/save/save.cpp PARENT_SCOPE ) olive-continuous/app/task/project/save/save.cpp000066400000000000000000000042721370472574300222110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "save.h" #include #include #include #include "common/filefunctions.h" OLIVE_NAMESPACE_ENTER ProjectSaveTask::ProjectSaveTask(ProjectPtr project) : project_(project) { SetTitle(tr("Saving '%1'").arg(project->filename())); } bool ProjectSaveTask::Run() { // File to temporarily save to (ensures we can't half-write the user's main file and crash) QString temp_save = QDir(FileFunctions::GetTempFilePath()).filePath(QStringLiteral("tempsv")); QFile project_file(temp_save); if (project_file.open(QFile::WriteOnly | QFile::Text)) { QXmlStreamWriter writer(&project_file); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement("olive"); writer.writeTextElement("version", "0.2.0"); project_->Save(&writer); writer.writeEndElement(); // olive writer.writeEndDocument(); project_file.close(); if (writer.hasError()) { SetError(tr("Failed to write XML data")); return false; } // Save was successful, we can now rewrite the original file QFile original(project_->filename()); if ((!original.exists() || original.remove()) && QFile::copy(temp_save, project_->filename())) { return true; } else { SetError(tr("Failed to write to \"%1\".").arg(project_->filename())); return false; } } else { SetError(tr("Failed to open file \"%1\" for writing.").arg(project_->filename())); return false; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/project/save/save.h000066400000000000000000000021631370472574300216530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTSAVEMANAGER_H #define PROJECTSAVEMANAGER_H #include "project/project.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class ProjectSaveTask : public Task { Q_OBJECT public: ProjectSaveTask(ProjectPtr project); ProjectPtr GetProject() const { return project_; } protected: virtual bool Run() override; private: ProjectPtr project_; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTSAVEMANAGER_H olive-continuous/app/task/render/000077500000000000000000000000001370472574300174155ustar00rootroot00000000000000olive-continuous/app/task/render/CMakeLists.txt000066400000000000000000000014451370472574300221610ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} task/render/render.h task/render/render.cpp PARENT_SCOPE ) olive-continuous/app/task/render/render.cpp000066400000000000000000000163471370472574300214130ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "render.h" #include "common/timecodefunctions.h" OLIVE_NAMESPACE_ENTER RenderTask::RenderTask(RenderBackend *backend) : backend_(backend) { job_time_ = QDateTime::currentMSecsSinceEpoch(); backend_is_ours_ = false; } RenderTask::RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams) { job_time_ = QDateTime::currentMSecsSinceEpoch(); backend_ = new OpenGLBackend(); backend_->SetViewerNode(viewer); backend_->SetVideoParams(vparams); backend_->SetAudioParams(aparams); backend_is_ours_ = true; } RenderTask::~RenderTask() { if (backend_is_ours_) { backend_->deleteLater(); } } struct TimeHashFuturePair { rational time; RenderTicketPtr hash_future; }; struct HashTimePair { rational time; QByteArray hash; }; struct HashFrameFuturePair { QByteArray hash; RenderTicketPtr frame_future; }; struct RangeSampleFuturePair { TimeRange range; RenderTicketPtr sample_future; }; struct HashDownloadFuturePair { QByteArray hash; QFuture download_future; }; void RenderTask::Render(const TimeRangeList& video_range, const TimeRangeList &audio_range, bool use_disk_cache) { double progress_counter = 0; double total_length = 0; double video_frame_sz = video_params().time_base().toDouble(); std::list audio_queue; std::list audio_lookup_table; if (!audio_range.isEmpty()) { foreach (const TimeRange& r, audio_range) { total_length += r.length().toDouble(); std::list ranges = RenderBackend::SplitRangeIntoChunks(r); audio_queue.insert(audio_queue.end(), ranges.begin(), ranges.end()); } } std::list render_lookup_table; QVector times; QVector hashes; std::list frame_queue; if (!video_range.isEmpty()) { QList existing_hashes; times = viewer()->video_frame_cache()->GetFrameListFromTimeRange(video_range); total_length += video_frame_sz * times.size(); RenderTicketPtr hash_future = backend_->Hash(times); hashes = hash_future->Get().value >(); if (!hash_future->WasCancelled()) { for (int i=0;i download_futures; // Iterators std::list::iterator i; std::list::iterator j; std::list::iterator k; std::list running_hashes; std::list existing_hashes; while (!IsCancelled() && (!render_lookup_table.empty() || !frame_queue.empty() || !audio_queue.empty() || !download_futures.empty() || !audio_lookup_table.empty())) { if (!IsCancelled() && !frame_queue.empty()) { // Pop another frame off the frame queue const HashTimePair& p = frame_queue.front(); // Check if we're already rendering this hash bool rendering_hash = (std::find(running_hashes.begin(), running_hashes.end(), p.hash) != running_hashes.end()); // Skip this hash if we're already rendering it if (!rendering_hash) { // Check if this frame already exists (has already been rendered previously or during this job) bool hash_exists = false; if (use_disk_cache) { // Check if this hash is in our "existing hashes" list hash_exists = (std::find(existing_hashes.begin(), existing_hashes.end(), p.hash) != existing_hashes.end()); // If not, check if it's in the filesystem if (!hash_exists) { hash_exists = QFileInfo::exists(viewer()->video_frame_cache()->CachePathName(p.hash)); // If so, add it to the list so we don't have to check the filesystem again later if (hash_exists) { existing_hashes.push_back(p.hash); } } if (hash_exists) { // Already exists, no need to render it again FrameDownloaded(p.hash, {p.time}); progress_counter += video_frame_sz; emit ProgressChanged(progress_counter / total_length); } } // If no existing disk cache was found, queue it now if (!hash_exists) { render_lookup_table.push_back({p.hash, backend_->RenderFrame(p.time)}); running_hashes.push_back(p.hash); } } // Remove first element frame_queue.pop_front(); } if (!IsCancelled() && !audio_queue.empty()) { audio_lookup_table.push_back({audio_queue.front(), backend_->RenderAudio(audio_queue.front())}); audio_queue.pop_front(); } i = render_lookup_table.begin(); while (!IsCancelled() && i != render_lookup_table.end()) { if (i->frame_future->IsFinished()) { FramePtr f = i->frame_future->Get().value(); // Start multithreaded download here download_futures.push_back({i->hash, DownloadFrame(f, i->hash)}); i = render_lookup_table.erase(i); } else { i++; } } j = download_futures.begin(); while (!IsCancelled() && j != download_futures.end()) { if (j->download_future.isFinished()) { // Place it in the cache std::list times_with_hash; for (int hash_index=0;hash_indexhash) { times_with_hash.push_back(times.at(hash_index)); } } FrameDownloaded(j->hash, times_with_hash); existing_hashes.push_back(j->hash); // Signal process progress_counter += times_with_hash.size() * video_frame_sz; emit ProgressChanged(progress_counter / total_length); j = download_futures.erase(j); } else { j++; } } k = audio_lookup_table.begin(); while (!IsCancelled() && k != audio_lookup_table.end()) { if (k->sample_future->IsFinished()) { AudioDownloaded(k->range, k->sample_future->Get().value()); progress_counter += k->range.length().toDouble(); emit ProgressChanged(progress_counter / total_length); k = audio_lookup_table.erase(k); } else { k++; } } } if (backend_is_ours_) { // `Close` will block until all jobs are done making a safe deletion backend_->Close(); } } void RenderTask::SetAnchorPoint(const rational &r) { anchor_point_ = r; } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/render/render.h000066400000000000000000000041001370472574300210400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RENDERTASK_H #define RENDERTASK_H #include #include "node/output/viewer/viewer.h" #include "render/backend/opengl/openglbackend.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER class RenderTask : public Task { public: RenderTask(RenderBackend* backend); RenderTask(ViewerOutput* viewer, const VideoParams &vparams, const AudioParams &aparams); virtual ~RenderTask() override; protected: void Render(const TimeRangeList &video_range, const TimeRangeList &audio_range, bool use_disk_cache); virtual QFuture DownloadFrame(FramePtr frame, const QByteArray &hash) = 0; virtual void FrameDownloaded(const QByteArray& hash, const std::list& times) = 0; virtual void AudioDownloaded(const TimeRange& range, SampleBufferPtr samples) = 0; ViewerOutput* viewer() const { return backend_->GetViewerNode(); } VideoParams video_params() const { return backend_->GetVideoParams(); } AudioParams audio_params() const { return backend_->GetAudioParams(); } void SetAnchorPoint(const rational& r); const qint64& job_time() const { return job_time_; } RenderBackend* backend() { return backend_; } private: rational anchor_point_; RenderBackend* backend_; bool backend_is_ours_; qint64 job_time_; }; OLIVE_NAMESPACE_EXIT #endif // RENDERTASK_H olive-continuous/app/task/task.h000066400000000000000000000102221370472574300172460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TASK_H #define TASK_H #include #include #include #include "common/cancelableobject.h" OLIVE_NAMESPACE_ENTER /** * @brief A base class for background tasks running in Olive. * * Tasks are multithreaded by design (i.e. they will always spawn * a new thread and run in it). * * To subclass your own Task, override Action() and return TRUE on success or FALSE on failure. Note that a Task can * provide a "negative" output and still have succeeded. For example, the ProbeTask's role is to determine whether a * certain media file can be used in Olive. Even if the probe *fails* to find a Decoder for this file, the Task itself * has *succeeded* at discovering this. A failure of ProbeTask would indicate a catastrophic failure meaning it was * unable to determine anything about the file. * * Tasks should be used with the TaskManager which will manage starting and deleting them. It'll also only start as * many Tasks as there are threads on the system as to not overload them. * * Tasks support "dependency tasks", i.e. a Task that should be complete before another Task begins. */ class Task : public QObject, public CancelableObject { Q_OBJECT public: /** * @brief Task Constructor */ Task() : title_(tr("Task")), error_(tr("Unknown error")), start_time_(0) { } /** * @brief Retrieve the current title of this Task */ const QString& GetTitle() const { return title_; } /** * @brief Returns the error that occurred if Run() returns false */ const QString& GetError() const { return error_; } const qint64& GetStartTime() const { return start_time_; } public slots: /** * @brief Run this task * * @return True if the task completed successfully, false if not. * * \see GetError() if this returns false. */ bool Start() { start_time_ = QDateTime::currentMSecsSinceEpoch(); return Run(); } /** * @brief Reset state so that Run() can be called again. * * Override this if your class holds any persistent state that should be cleared/modified before * it's safe for Run() to run again. */ virtual void Reset(){} /** * @brief Cancel the Task * * Sends a signal to the Task to stop as soon as possible. Always call this directly or connect * with Qt::DirectConnection, or else it'll be queued *after* the task has already finished. */ void Cancel() { CancelableObject::Cancel(); } protected: virtual bool Run() = 0; /** * @brief Set the error message * * It is recommended to use this if your Action() function ever returns FALSE to tell the user why the failure * occurred. */ void SetError(const QString& s) { error_ = s; } /** * @brief Set the Task title * * Used in the UI Task Manager to distinguish Tasks from each other. Generally this should be set in the constructor * and shouldn't need to change during the life of the Task. To show an error message, it's recommended to use * set_error() instead. */ void SetTitle(const QString& s) { title_ = s; } signals: /** * @brief Signal emitted whenever progress is made * * Emit this throughout Action() to update any attached ProgressBars on the progress of this Task. * * @param p * * A progress value between 0.0 and 1.0. */ void ProgressChanged(double d); private: QString title_; QString error_; qint64 start_time_; }; OLIVE_NAMESPACE_EXIT #endif // TASK_H olive-continuous/app/task/taskmanager.cpp000066400000000000000000000053511370472574300211430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "taskmanager.h" #include #include OLIVE_NAMESPACE_ENTER TaskManager* TaskManager::instance_ = nullptr; TaskManager::TaskManager() { } TaskManager::~TaskManager() { thread_pool_.clear(); foreach (Task* t, tasks_) { t->Cancel(); } thread_pool_.waitForDone(); foreach (Task* t, tasks_) { t->deleteLater(); } } void TaskManager::CreateInstance() { instance_ = new TaskManager(); } void TaskManager::DestroyInstance() { delete instance_; instance_ = nullptr; } TaskManager *TaskManager::instance() { return instance_; } int TaskManager::GetTaskCount() const { return tasks_.size(); } Task *TaskManager::GetFirstTask() const { return tasks_.begin().value(); } void TaskManager::CancelTaskAndWait(Task* t) { t->Cancel(); QFutureWatcher* w = tasks_.key(t); if (w) { w->waitForFinished(); } } void TaskManager::AddTask(Task* t) { // Create a watcher for signalling QFutureWatcher* watcher = new QFutureWatcher(); connect(watcher, &QFutureWatcher::finished, this, &TaskManager::TaskFinished); // Add the Task to the queue tasks_.insert(watcher, t); // Run task concurrently watcher->setFuture(QtConcurrent::run(t, &Task::Start)); // Emit signal that a Task was added emit TaskAdded(t); emit TaskListChanged(); } void TaskManager::CancelTask(Task *t) { if (std::find(failed_tasks_.begin(), failed_tasks_.end(), t) != failed_tasks_.end()) { failed_tasks_.remove(t); emit TaskRemoved(t); t->deleteLater(); } else { t->Cancel(); } } void TaskManager::TaskFinished() { QFutureWatcher* watcher = static_cast*>(sender()); Task* t = tasks_.value(watcher); tasks_.remove(watcher); if (watcher->result()) { // Task completed successfully emit TaskRemoved(t); t->deleteLater(); } else { // Task failed, keep it so the user can see the error message emit TaskFailed(t); failed_tasks_.push_back(t); } watcher->deleteLater(); emit TaskListChanged(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/task/taskmanager.h000066400000000000000000000065571370472574300206210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TASKMANAGER_H #define TASKMANAGER_H #include #include #include #include "task/task.h" OLIVE_NAMESPACE_ENTER /** * @brief An object that manages background Task objects, handling their start and end * * TaskManager handles the life of a Task object. After a new Task is created, it should be sent to TaskManager through * AddTask(). TaskManager will take ownership of the task and add it to a queue until it system resources are available * for it to run. Currently, TaskManager will run no more Tasks than there are threads on the system (one task per * thread). As Tasks finished, TaskManager will start the next in the queue. */ class TaskManager : public QObject { Q_OBJECT public: /** * @brief TaskManager Constructor */ TaskManager(); /** * @brief TaskManager Destructor * * Ensures all Tasks are deleted */ virtual ~TaskManager(); static void CreateInstance(); static void DestroyInstance(); static TaskManager* instance(); int GetTaskCount() const; Task* GetFirstTask() const; void CancelTaskAndWait(Task* t); public slots: /** * @brief Add a new Task * * Adds a new Task to the queue. If there are available threads to run it, it'll also run immediately. Otherwise, * it'll be placed into the queue and run when resources are available. * * NOTE: This function is NOT thread-safe and is currently intended to only be used from the main/GUI thread. * * NOTE: A Task object should only be added once. Adding the same Task object more than once will result in undefined * behavior. * * @param t * * The task to add and run. TaskManager takes ownership of this Task and will be responsible for freeing it. */ void AddTask(Task *t); void CancelTask(Task* t); signals: /** * @brief Signal emitted when a Task is added by AddTask() * * @param t * * Task that was added */ void TaskAdded(Task* t); /** * @brief Signal emitted when any change to the running task list has been made */ void TaskListChanged(); /** * @brief Signal emitted when a task is deleted */ void TaskRemoved(Task* t); /** * @brief Signal emitted when a task fails */ void TaskFailed(Task* t); private: /** * @brief Internal task array */ QHash*, Task*> tasks_; /** * @brief Internal list of failed tasks */ std::list failed_tasks_; /** * @brief Task thread pool */ QThreadPool thread_pool_; /** * @brief TaskManager singleton instance */ static TaskManager* instance_; private slots: void TaskFinished(); }; OLIVE_NAMESPACE_EXIT #endif // TASKMANAGER_H olive-continuous/app/timeline/000077500000000000000000000000001370472574300170025ustar00rootroot00000000000000olive-continuous/app/timeline/CMakeLists.txt000066400000000000000000000020771370472574300215500ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} timeline/timelinecommon.h timeline/timelinecoordinate.h timeline/timelinecoordinate.cpp timeline/timelinemarker.h timeline/timelinemarker.cpp timeline/timelinepoints.h timeline/timelinepoints.cpp timeline/timelineworkarea.h timeline/timelineworkarea.cpp timeline/trackreference.h timeline/trackreference.cpp PARENT_SCOPE ) olive-continuous/app/timeline/timelinecommon.h000066400000000000000000000025231370472574300221740ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINECOMMON_H #define TIMELINECOMMON_H #include "common/define.h" #include "common/rational.h" OLIVE_NAMESPACE_ENTER class Block; class TrackOutput; class Timeline { public: enum MovementMode { kNone, kMove, kTrimIn, kTrimOut }; enum TrackType { kTrackTypeNone = -1, kTrackTypeVideo, kTrackTypeAudio, kTrackTypeSubtitle, kTrackTypeCount }; static bool IsATrimMode(MovementMode mode) {return mode == kTrimIn || mode == kTrimOut;} struct EditToInfo { TrackOutput* track; rational nearest_time; Block* nearest_block; }; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINECOMMON_H olive-continuous/app/timeline/timelinecoordinate.cpp000066400000000000000000000027471370472574300233760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelinecoordinate.h" OLIVE_NAMESPACE_ENTER TimelineCoordinate::TimelineCoordinate() : track_(Timeline::kTrackTypeNone, 0) { } TimelineCoordinate::TimelineCoordinate(const rational &frame, const TrackReference &track) : frame_(frame), track_(track) { } TimelineCoordinate::TimelineCoordinate(const rational &frame, const Timeline::TrackType &track_type, const int &track_index) : frame_(frame), track_(track_type, track_index) { } const rational &TimelineCoordinate::GetFrame() const { return frame_; } const TrackReference &TimelineCoordinate::GetTrack() const { return track_; } void TimelineCoordinate::SetFrame(const rational &frame) { frame_ = frame; } void TimelineCoordinate::SetTrack(const TrackReference &track) { track_ = track; } OLIVE_NAMESPACE_EXIT olive-continuous/app/timeline/timelinecoordinate.h000066400000000000000000000025341370472574300230350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINECOORDINATE_H #define TIMELINECOORDINATE_H #include "common/rational.h" #include "trackreference.h" OLIVE_NAMESPACE_ENTER class TimelineCoordinate { public: TimelineCoordinate(); TimelineCoordinate(const rational& frame, const TrackReference& track); TimelineCoordinate(const rational& frame, const Timeline::TrackType& track_type, const int& track_index); const rational& GetFrame() const; const TrackReference& GetTrack() const; void SetFrame(const rational& frame); void SetTrack(const TrackReference& track); private: rational frame_; TrackReference track_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINECOORDINATE_H olive-continuous/app/timeline/timelinemarker.cpp000066400000000000000000000060511370472574300225200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelinemarker.h" #include "common/xmlutils.h" OLIVE_NAMESPACE_ENTER TimelineMarker::TimelineMarker(const TimeRange &time, const QString &name, QObject *parent) : QObject(parent), time_(time), name_(name) { } const TimeRange &TimelineMarker::time() const { return time_; } void TimelineMarker::set_time(const TimeRange &time) { time_ = time; emit TimeChanged(time_); } const QString &TimelineMarker::name() const { return name_; } void TimelineMarker::set_name(const QString &name) { name_ = name; emit NameChanged(name_); } void TimelineMarkerList::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("markers")); foreach (TimelineMarker* marker, markers_) { writer->writeStartElement(QStringLiteral("marker")); writer->writeAttribute(QStringLiteral("name"), marker->name()); writer->writeAttribute(QStringLiteral("in"), marker->time().in().toString()); writer->writeAttribute(QStringLiteral("out"), marker->time().out().toString()); writer->writeEndElement(); // marker } writer->writeEndElement(); // markers } TimelineMarkerList::~TimelineMarkerList() { qDeleteAll(markers_); } void TimelineMarkerList::AddMarker(const TimeRange &time, const QString &name) { TimelineMarker* m = new TimelineMarker(time, name); markers_.append(m); emit MarkerAdded(m); } void TimelineMarkerList::RemoveMarker(TimelineMarker *marker) { for (int i=0;i &TimelineMarkerList::list() const { return markers_; } void TimelineMarkerList::Load(QXmlStreamReader *reader) { while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("marker")) { QString name; TimeRange range; XMLAttributeLoop(reader, attr) { if (attr.name() == QStringLiteral("name")) { name = attr.value().toString(); } else if (attr.name() == QStringLiteral("in")) { range.set_in(rational::fromString(attr.value().toString())); } else if (attr.name() == QStringLiteral("out")) { range.set_out(rational::fromString(attr.value().toString())); } } } reader->skipCurrentElement(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/timeline/timelinemarker.h000066400000000000000000000036561370472574300221750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEMARKER_H #define TIMELINEMARKER_H #include #include #include #include "common/timerange.h" OLIVE_NAMESPACE_ENTER class TimelineMarker : public QObject { Q_OBJECT public: TimelineMarker(const TimeRange& time = TimeRange(), const QString& name = QString(), QObject* parent = nullptr); const TimeRange &time() const; void set_time(const TimeRange& time); const QString& name() const; void set_name(const QString& name); signals: void TimeChanged(const TimeRange& time); void NameChanged(const QString& name); private: TimeRange time_; QString name_; }; class TimelineMarkerList : public QObject { Q_OBJECT public: TimelineMarkerList() = default; virtual ~TimelineMarkerList() override; void AddMarker(const TimeRange& time = TimeRange(), const QString& name = QString()); void RemoveMarker(TimelineMarker* marker); const QList &list() const; void Load(QXmlStreamReader* reader); void Save(QXmlStreamWriter* writer) const; signals: void MarkerAdded(TimelineMarker* marker); void MarkerRemoved(TimelineMarker* marker); private: QList markers_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEMARKER_H olive-continuous/app/timeline/timelinepoints.cpp000066400000000000000000000032071370472574300225530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelinepoints.h" #include "common/xmlutils.h" OLIVE_NAMESPACE_ENTER TimelineMarkerList *TimelinePoints::markers() { return &markers_; } const TimelineMarkerList *TimelinePoints::markers() const { return &markers_; } const TimelineWorkArea *TimelinePoints::workarea() const { return &workarea_; } void TimelinePoints::Load(QXmlStreamReader *reader) { while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("markers")) { markers_.Load(reader); } else if (reader->name() == QStringLiteral("workarea")) { workarea_.Load(reader); } else { reader->skipCurrentElement(); } } } void TimelinePoints::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("points")); workarea_.Save(writer); markers_.Save(writer); writer->writeEndElement(); // points } TimelineWorkArea *TimelinePoints::workarea() { return &workarea_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/timeline/timelinepoints.h000066400000000000000000000024621370472574300222220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEPOINTS_H #define TIMELINEPOINTS_H #include #include #include "timelinemarker.h" #include "timelineworkarea.h" OLIVE_NAMESPACE_ENTER class TimelinePoints { public: TimelinePoints() = default; TimelineMarkerList* markers(); const TimelineMarkerList* markers() const; TimelineWorkArea* workarea(); const TimelineWorkArea* workarea() const; void Load(QXmlStreamReader* reader); void Save(QXmlStreamWriter* writer) const; private: TimelineMarkerList markers_; TimelineWorkArea workarea_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEPOINTS_H olive-continuous/app/timeline/timelineworkarea.cpp000066400000000000000000000053601370472574300230540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineworkarea.h" #include "common/xmlutils.h" OLIVE_NAMESPACE_ENTER const rational TimelineWorkArea::kResetIn = 0; const rational TimelineWorkArea::kResetOut = RATIONAL_MAX; TimelineWorkArea::TimelineWorkArea(QObject *parent) : QObject(parent), workarea_enabled_(false) { } bool TimelineWorkArea::enabled() const { return workarea_enabled_; } void TimelineWorkArea::set_enabled(bool e) { workarea_enabled_ = e; emit EnabledChanged(workarea_enabled_); } const TimeRange &TimelineWorkArea::range() const { return workarea_range_; } void TimelineWorkArea::set_range(const TimeRange &range) { workarea_range_ = range; emit RangeChanged(workarea_range_); } void TimelineWorkArea::Load(QXmlStreamReader *reader) { rational range_in = workarea_range_.in(); rational range_out = workarea_range_.out(); XMLAttributeLoop(reader, attr) { if (attr.name() == QStringLiteral("enabled")) { set_enabled(attr.value() != QStringLiteral("0")); } else if (attr.name() == QStringLiteral("in")) { range_in = rational::fromString(attr.value().toString()); } else if (attr.name() == QStringLiteral("out")) { range_out = rational::fromString(attr.value().toString()); } } TimeRange loaded_workarea(range_in, range_out); if (loaded_workarea != workarea_range_) { set_range(loaded_workarea); } reader->skipCurrentElement(); } void TimelineWorkArea::Save(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("workarea")); writer->writeAttribute(QStringLiteral("enabled"), QString::number(workarea_enabled_)); writer->writeAttribute(QStringLiteral("in"), workarea_range_.in().toString()); writer->writeAttribute(QStringLiteral("out"), workarea_range_.out().toString()); writer->writeEndElement(); // workarea } const rational &TimelineWorkArea::in() const { return workarea_range_.in(); } const rational &TimelineWorkArea::out() const { return workarea_range_.out(); } const rational &TimelineWorkArea::length() const { return workarea_range_.length(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/timeline/timelineworkarea.h000066400000000000000000000030661370472574300225220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEWORKAREA_H #define TIMELINEWORKAREA_H #include #include #include #include "common/timerange.h" OLIVE_NAMESPACE_ENTER class TimelineWorkArea : public QObject { Q_OBJECT public: TimelineWorkArea(QObject* parent = nullptr); bool enabled() const; void set_enabled(bool e); const rational& in() const; const rational& out() const; const rational& length() const; const TimeRange& range() const; void set_range(const TimeRange& range); void Load(QXmlStreamReader* reader); void Save(QXmlStreamWriter* writer) const; static const rational kResetIn; static const rational kResetOut; signals: void EnabledChanged(bool e); void RangeChanged(const TimeRange& r); private: bool workarea_enabled_; TimeRange workarea_range_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEWORKAREA_H olive-continuous/app/timeline/trackreference.cpp000066400000000000000000000023471370472574300224770ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "trackreference.h" OLIVE_NAMESPACE_ENTER TrackReference::TrackReference() : type_(Timeline::kTrackTypeNone), index_(0) { } TrackReference::TrackReference(const Timeline::TrackType &type, const int &index) : type_(type), index_(index) { } const Timeline::TrackType &TrackReference::type() const { return type_; } const int &TrackReference::index() const { return index_; } bool TrackReference::operator==(const TrackReference &ref) const { return type_ == ref.type_ && index_ == ref.index_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/timeline/trackreference.h000066400000000000000000000022321370472574300221350ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRACKREFERENCE_H #define TRACKREFERENCE_H #include "timeline/timelinecommon.h" OLIVE_NAMESPACE_ENTER class TrackReference { public: TrackReference(); TrackReference(const Timeline::TrackType& type, const int& index); const Timeline::TrackType& type() const; const int& index() const; bool operator==(const TrackReference& ref) const; private: Timeline::TrackType type_; int index_; }; OLIVE_NAMESPACE_EXIT #endif // TRACKREFERENCE_H olive-continuous/app/tool/000077500000000000000000000000001370472574300161515ustar00rootroot00000000000000olive-continuous/app/tool/CMakeLists.txt000066400000000000000000000014031370472574300207070ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} tool/tool.h PARENT_SCOPE ) olive-continuous/app/tool/tool.h000066400000000000000000000050741370472574300173050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TOOL_H #define TOOL_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class Tool { public: /** * @brief A list of tools that can be used throughout the application */ enum Item { /// No tool. This should never be set as the application tool, its only real purpose is to indicate the lack of /// a tool somewhere similar to nullptr. kNone, /// Pointer tool kPointer, /// Edit tool kEdit, /// Ripple tool kRipple, /// Rolling tool kRolling, /// Razor tool kRazor, /// Slip tool kSlip, /// Slide tool kSlide, /// Hand tool kHand, /// Zoom tool kZoom, /// Transition tool kTransition, /// Record tool kRecord, /// Add tool kAdd, kCount }; /** * @brief Tools that can be added using the kAdd tool */ enum AddableObject { /// An empty clip kAddableEmpty, /// A video clip showing a generic video placeholder kAddableBars, /// A video clip with a solid connected kAddableSolid, /// A video clip with a title connected kAddableTitle, /// An audio clip with a sine connected to it kAddableTone, kAddableCount }; static QString GetAddableObjectName(const AddableObject& a) { switch (a) { case kAddableEmpty: return QCoreApplication::translate("Tool", "Empty"); case kAddableBars: return QCoreApplication::translate("Tool", "Bars"); case kAddableSolid: return QCoreApplication::translate("Tool", "Solid"); case kAddableTitle: return QCoreApplication::translate("Tool", "Title"); case kAddableTone: return QCoreApplication::translate("Tool", "Tone"); case kAddableCount: break; } return QCoreApplication::translate("Tool", "Unknown"); } }; OLIVE_NAMESPACE_EXIT #endif // TOOL_H olive-continuous/app/ui/000077500000000000000000000000001370472574300156115ustar00rootroot00000000000000olive-continuous/app/ui/CMakeLists.txt000066400000000000000000000016261370472574300203560ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(cursors) add_subdirectory(graphics) add_subdirectory(icons) add_subdirectory(style) set(OLIVE_RESOURCES ${OLIVE_RESOURCES} PARENT_SCOPE ) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/ui/cursors/000077500000000000000000000000001370472574300173115ustar00rootroot00000000000000olive-continuous/app/ui/cursors/CMakeLists.txt000066400000000000000000000014221370472574300220500ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ui/cursors/cursors.qrc PARENT_SCOPE ) olive-continuous/app/ui/cursors/cursors.qrc000066400000000000000000000007311370472574300215210ustar00rootroot00000000000000 trim-left.svg trim-right.svg slip.svg ripple-left.svg ripple-right.svg rolling.svg razor-a.svg razor-b.svg razor-c.svg olive-continuous/app/ui/cursors/razor-a.svg000066400000000000000000013142121370472574300214110ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/razor-b.svg000066400000000000000000013137451370472574300214240ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/razor-c.svg000066400000000000000000013134731370472574300214230ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/ripple-left.svg000066400000000000000000013137021370472574300222640ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/ripple-right.svg000066400000000000000000013137431370472574300224540ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/rolling.svg000066400000000000000000013160441370472574300215110ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/slip.svg000066400000000000000000013137721370472574300210170ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/trim-left.svg000066400000000000000000013145041370472574300217450ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/cursors/trim-right.svg000066400000000000000000013144771370472574300221410ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/graphics/000077500000000000000000000000001370472574300174115ustar00rootroot00000000000000olive-continuous/app/ui/graphics/CMakeLists.txt000066400000000000000000000014241370472574300221520ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ui/graphics/graphics.qrc PARENT_SCOPE ) olive-continuous/app/ui/graphics/graphics.qrc000066400000000000000000000002111370472574300217120ustar00rootroot00000000000000 throbber.png olive-splash.png olive-continuous/app/ui/graphics/olive-splash.png000066400000000000000000000213341370472574300225300ustar00rootroot00000000000000‰PNG  IHDR¢Ÿzh pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFIDATxÚìwœTÕÙÇ¿Ë"M M°€‚JıG_Æ®+vcÁöŠkkbMTì5ú•QTš"–×(‚Qé RVÚRvŸüñ<óÙ»wïÌܹs÷îÎÎù}>÷³;÷ÜröÌoÏ9O/ {—‡ß×ïâàJŒˆ×·~iŸ7 ~Љ`gÔ1¢¥}þÞö‹enø’XšSøìù¼ðPâ†Ï!I"< <áù|p£>‡$—fï~ñ`/û\  ŒvÃè$A½q¦míóJ 0Û ¥CKs ó€@…}ÞxØÂ ¥C’Dx¸Úó¹— /NÙí(Ah½ÂËÑT·O;8ÔêÑ/¼Œñœ»ø‹V‡$‰šç# ›G’> xÑ ­C’DÄHø¡G’ÞüŽôñÒ±í½øUp¯õ,Ù/‡ºáuH’ˆ ùO¡J­ÓÔfÄýÜ;$µ4{q>ð(Uvè2à·¨×wC@;Ô©7êø±#Ðh´¶mÉ:4¬b šew©ç÷¹v|,wô«="üø«çójÔX¨‰áwNDÓ7÷qYŽ&1˜|a?§R¤±AµAD€;€¡žÏkcñ46£±:‡ÇH¾lØ|fÂßDÔ9yµ#bÏEö/óœ+G“~¾YÏǤ'ê™Þ¿ô¥Ü9ÂÀ2GÄhd|ø½çÜàlà…ú8h(Ä-&lÕ7¬3Bþ˜äˆ˜û—ûpŽçœ—“¬I°%ªïìŽ:övÚÑT­Ñ°Ù¦ò½½Z±&9"†G)ð$p¦ïümÀ µð¾æh ×¾&áîIUXlCB%ð¸Íâ«ÓñMÛø{ñš_§"Ïçï†:^:î6¥x0ÓþöYŽˆáÉø=5SÝF}Wåø¼Ð¼<§Qeë.V,D­\Žˆ!ð+`rÀù騮qnˆgü¸€ àòb6°;šrºQÂ 8ß 5öÍÐÏ3P…ïx[‚ ã(!²ZŽGÄp¸É6Ú~´&  /¶YôÀõhìM8Ç’ò6и e[˜ÊÏ9Û-͹áEÛ¦“‡ñ@]Êj›Ps[.Ç24p ŒúÚíר£G«û°u£+óIÿ;ØùmQ;wTÕ j‰z;5Gó•š–À1$zÚ¾°Ôf”JjƼl6ËᙨÒw%êd°ÀD"ïçU1ÿmLxêm¤ØU#µÍrß‘ÀźÁ­+"‚\n¿¯7B6 ˜­J#îËì¢_ïzf±ºÀ¶¶üvCÓ¸tG3ò¶3’ž<<º¡Þ'©Ýsаԭ|×Í´¦?Ð9âû*LØ™¼Š†8TâPôDµ¸xͯ¿¶÷]·u¼kv;°=Rülø³À8›•Š”ˆ;ØŒç%Ó¶d÷ ˜Ñ®îòœk‰†$¤ˆ¹}³å÷Fȇ/5Š‹ˆ • ¼:kÑ„ò·¢ÞÝ~ü8ª/z Šîþ&Á6‹Ø§u¨Îs„í-¿ 3¤C='bgÔ4åµjDº¸(àžÏQ}㜠Ïmê SÄÌÇ ¸ÚfË·ì˜å¨Óðˆp?p©ïÜ ¨‡ÎÀÝꥨŽ1lB7#ä#h‹<úûƒò ÛgºÒ „ˆP[isϹõ&)Ïú/¡~ƒ^lDíÎÃr|_3›qN²÷GE9ª¼Ž&ªr(P"b³ÞU¾sïÙì%¶ÿ{ Õ¿ùñ´-áQ%ßDÝóü5GþËŽïÅ ˆíì‹ÛÜw~ ¯ZCú%ÔÇOИ˜ßßõxîãßô™õ÷EÂy9"Öø£ÿRû±žT¹75Fã6.¸‰-µïE|/àý€-@¾¨´>=o3¥K„_c-©OÇÖ"R&5q]ÀµŠÈ†€k7ŠÈåyôáPY/µ‡u"2\DŽ‘&õlüëì¨o3"h©^¢øU¶[â;0Ü–l?^@í·k#ôáHàßD·Ú„Å2Ûß>J{W7Ä¥Ô½é;jÚœïþ7àúLbíÐöp|D¡áXTyÞ,¿¹ÒÔ@ÛßRt6ðFõ°O+©^z-… P¢ÉÉxÿhß³Æ\sá"õ¦¢•¬‚²ÿŸ‡<µ ðYó˜tÎuDL•¶_¼ÊömaQ†º~yTu4ÿM̶½_Ãm4TGϹïÑ`ÿ 1ÉñŽˆu73Þ‹z²Œ !ÄüˆæUô§øx›à‡gäЗ7PõÎm{št¾»çÜ4cYœ¬=ë_£!—=ЄMÓ<_ðÏ6[]c_TÔºœ`÷­#LøƒqvíB4bÐÿOÑÅ$êƒ<ç^³~ÿÓ84nˆD,6›æi,sxÆ\ój)"g¥q'['"Çùîë""Å`1ú !~7Å3›yŸZX2,Æ¢±ÒÏ •Aý‰:›¡á^Áb®IßCsÜïúñ‚› ÿh$"kÓ8žv ùŒ=á)'ܽDäÇ4N CžÑÅB ruþÆçøëfÄŪg¥M¡   “æc‡^ç}SÀ8 ¨Ï„M¨cÃÔ,×]G• r“àSØÊö‘{Ü÷êÀ 8¬ú&_ü>¤jä~Ò'kÚÑtˆƒ=çF¡Ö•”ZešZùƒ€û/ESϹ‚çþ=L‘̈íÐð˰ÿxGٞыM™.èþ}4üt‘}ÞÜtˆ‡\û´IÔnf,²ñÿÖ?œ»™Ì™´Ù1U¿e ê-äùs6êÀàfÆ"#â^9^ß-î's6üŠêîkë€cNšt^–m€[𠯢þ‡¹àyªÛ¡Ë©^¦-6 öè=ç6C“o ¸þoFÞþh&´¨y[Ô3hs[ÂW¢¦Ìå¦Êi‡æîiŠ*Л°µÊúð3°˜o?ç™ÚèkÔ~½#bò˜a_p.Xm_vÊ ò á ]ŠÖ˜ö¢MW2(H‹–ðÌXaÏT;>Eu¡kkË©™> Ž^±ß_BU@aðš-ÉA[¡‡ÒHð‹lÚ´ŽÆhš¿û=ÔC~"Éä/*"®%Ø¢’ £® …ËÃÚy>e\ ªO¼$ m°m#vv³Ÿ=m6ß<á1«D“™¦òFN®M)¿XˆXqéûÖ³7·=V˜le²Ìl%¨©ðЀ%sPáKlߨÃÚÃCÒ­ÃEFÈ×Ñ0ˆµŽˆ¹c%ÑËšu¤J78µ‡Û,íÿBk‘øx›‰Â “²'‹}Lä\gÛPõÔGÄðÿÍí#Þ;€*]`´Ðãn!ö¤Ûd¹fš7q5Ëô®5uÑ'úÛø 5+½Öæþ{¸‘òý¨Ëw±è—æqo/ßlu2Ù½e¦‡xn꣚•‹¨r¼[„þn²™û”„¤à­MøzU !B²Õb!b>żýjŸ/mé\ŸEjίð1µA{ÑDl±ß/¢Jù$‹u·­Ë|àÿP×8GDò©•Ü)àÜ[:´-žÌòÌ{¨žAâLàÊ2v£ºÙ0WLC­DÃï¦h¦Œl{ñ;²ùz‰/â¥yĈLËðÜ-EäO–Ú¸BD>‘_déË4ï9ÁRß=ÐöJ–´xaŽÁ"R.u‡Y"r~ºÒÀÅBÄ_ç1€KcìG× døÁdKDä±€ö;bxùVêKEä sT.ºP©y(cã¬Ù|qýbWSwE«Kù+j E%òÁd4þú1êέ šü`ž 6[“ú&%dìñÞ¸ìÀŸ“=¥Ý"S}iþ>©}€íQóÅoQËQ‡:þ^&—“‡öÄ<î+¨=L–†¨½·Z·ùßìüRDµŽo Y)^¬£ïcZc{Ю˜fÄóœ®$ŠŽ/lAðhƈ¯ŒGøf÷ýP—¯8p80,&‚a¾m ¦Ø1Ù¯Û-&"¶Aýò¢T†ki^˜ãR8õü^lºÉÃÅFÄkP;l.(¶Œéý¡þˆ¹bê"Ö õÚÙÛÎW±ÇúSlDÌVP<™| sEGÛ¤G~N°Íý–&̤làKQ¯›ù…üÅ[Ê‘™¶ùÏc|ÿB¢'Q†¦-^‰ÆMkçÛš$Ýı°ðRŽ×¯Šùý·™ôœ+Ú› ˜uˆgÜð~’ŽˆJÄò˜ßÿ D—Råç8ÏȘ’H/#8Jбžâ+ªçªÉ†Ú»ŠªdrEs48?…Y¶L§ü#Ÿ4I×±@ðL.Í Êê3‰¦¼À÷y½õqEòVŽˆñ<áã,6ÖRÆ¡5\rEwª'ŒøUÙ€&Šzº KuDÌK N„ŠZìÇȈ÷ÅL¿œc³ìÿ˜v`êÂÿ°ÍÀ2<³Äžû2Zšcm>GÃ_Í*ÅZ¨ZDé?7²–ûñpŸ¾·3<ï2ßß(Kòù•çÞ¯DäK·œº§»ˆ|â½³Eäâå‚ ¾^sÒÇg!ÿÍZîC«zŸkaôÒ Ï¼Ã®›("ãEd;ÙODž‘5žç|-"OˆHYoëCã;NªDDDÚZ¸A.Ø=ÃóJ¬ð¸ˆÈ]îÐÃÚZ‹ÈE"29OOëJyJD¶pDÌÿ(‘©Y|\B}éå›­²á¤,Ï+µº.ëDät Eèã»fB ®ÿ߈HoWU Ï-2êÁ’ IUzšŽ¦Á «ÒÙ9„5õÞ¹ÍÝ=Æ<™|ÑݤöÁNjΣдlé°Y‚}ü9äµ;†¸¦5êåÝÜ݃ÑÜ5ÇZ{YLýnj’õp"–ñuDÔhH†™¨EÂý¹øwˆë:f!à4ƒm_ÔUì4íÜeF˜sȯvNDã˜{äþ-÷Ñ{<˜fôYô¥…ˆ|‘eo–©_Ã=×-‘6"ÒͯR 笑ë}ª¸Pfucœ°áh™Fr}®ŽúÓ5MYµ¾Os_ï€k¿4É|o9×®ûƒµ 3©:nTŠÈµNXÉ«m?å7ý}TGý™cK]:Sd:ÿÃÓÎí†Ö«ž‰–iëÜ ÜˆÆZOA=‚âô’.nGKydõ•tD¬Ž=f²ÆÖaÞ³=]Ò96¤“„{¡Aû©ªO}« Gg¡žß™'ÎBcmZ¹=b´<1¶4Ö‡þ Xú6¤¹vI–%ó\ßõ­Ed†µ•›’zˆŒ±å5.L²½jÑ×âËG¡­N©}i L-~¬Ï².CËb¤T7P3¹ü&›=Ÿ@ØŸBôS/¾@y—×XÇ mmÙÜ1O"bËñŸì÷™À.i®›oÿŒ¢a¬Ç ©Jò ÄŸ„Æg—9".z)Z¢! A•~${rÏÅ@Ô×r ZO&6Ù>Õ›»q#äahhk®9»GG;"6Ž3…÷ ‚ót‡-nÔuÎ]Ri.ÛƒÀ>¨ÃîNvt4ª)š”t1šùa¢-û ½iì¾×‚Ã+¶¬JÓ>;G"†Õœ\m3ß…Tw#ÿŒ|þ(GÄÂÄ-¤¯s2Í–Ílèc?W¡µüÂà<»ö,bö\wzÄ„w§iû,ä3R…ŒäøîÓѼŠ%Žˆ™V!Ý&Gâzq6šy¢ÄÑ!Rº²!åÞ6%â{.B«#8":ä=+‚f‹Š+©^(ÝÑ!g"¦JàÎBu“Qqš¹ÂÑ¡Âx -ñü~sžï»8ÍÑÁ©d/c;ÛóûXÔ]+*JP7²C¼Ø€ºe#«ƒÉ¯òB4sÅ®Žˆ^¼•¥ýßçµh2§‡ˆî Û ÍÞÚÑ! × ýX\‚Vê »=êÔPâˆèjêKW•õe2ç}üØþ{+»D}jÖóKá‘ϺzíÜO€Ckœ‰*½ÃI;Î ¬Ac{4é»7Ü´BATdêµ}$Ùƒé¿5BfÕSº±aãª1_ \‘§4þ*ª3l‡†S1H.-*ƒ%ƒƒƒƒCC"C=Æ£ oÅ]KW0Þcc bšÀtY˜9’y!óK––[¬z¬­¬÷Ø,Ù¦±}cgßÍ¡ÄÑÅñ…3‘ó—#×nMî4}2ýüêë‚ïá?~úÓúÏñÿ 4:¹C pHYs  šœtIMEâ6s­ IDATxÚ¬½w”\÷uçùù½Š]Õ9FF#3E€™Ê¢H+Ñ cY²å ÉÇžõÎÌ9>{ÖãõœÙàõêxwå±Ç ¦d[kÙcYE‘J$EŠ9"‡Ð@çTÝUõÞÝ?Þ¯Þû½ÐÝU¯çÕawƒßíßïþîýÞô»W±â#ŠØÏn¶1H?m*' åýGaU(²”ÙO/[ÙLž=”©2H‰ÓT(q„'Õ«¬ò‘VŠä¸‘vºÙŠE'= ÓË9мÃ$‡çEšÔÌ*h´ ìa ÛédÅZ&ØÎÊTf†‹à~Ú¯ º·iÊnp9:¹}ÜF/½úM–ñÕÿüªú®X€@c KZè`÷°‹>šiõØdŠ…B¨r_ð£^É'ÙÎu¬×ï·0­¹ÚŸÀf– ¯òsÞæhc ^úØÇì§]_S}ÈU(&˜äyÞàIF^ÉÍä6šc„;LgŽŸð˜úyÃT »ÙÊ5tÐz»z…0Í<Á+ynÒD3ƒ\Ã:hòV ÜuØ\å Nó}µØ0D`-éѪĤò¾+±9Îëœå¬šj0®´Žíl HÆSWæÛýuÌ3ÇQNó&ÓzŸ²-lÕ„Ùð¾-ò&¯«7õÌÉÑKk øðßí«ú Xà6Yu¹ÿµÌ"e*ñC9Èý ›ŸsÀ>+ð„*6•¥@]-i-|šOQŒ³bÝýT©Ö¿ie'åFÖk“¡¯¦íS{o?“ÔÂü ™¤—-|½lÇ¡èmJ*d8X=8ÂþL=Õeõ›¬a³ŒQ£ÍZ9Ü+tÒ"k^M0O…Ì“ZRÄâٺ弟”íªÛ+PÌrŽW¨®+“4Ít’Â%|óT °§°™à™ª ¥H3Ù€žˆq²8ÇuºNt=sSÛ†½ò”AÏ×Î3V_TQüøKl\ÂP€«õ¦[äS|Ûà ° ˆ ’ØÌ3¬ìÞÊZ>IJÑ@¼Ïó—A_ - Ê"åhÝL:Bb€/ò»^"Þ+~‹eü;—PAÒ,¬x°†ø$·²CàQ«ý¬Œ·+eü.Š–¬P~ Yvñ>ÒK^¿Ñ!e¬¥öSx hEX©ø@ºøÞ£óhâ½ÓÿýÅ[ƒi@¹Šgp _“Ç–ÏÉ à ½z§Ä bNø‡®F§ÈÖ²“oÈ¡åÕ»tóaîÓÇ]ŒÏRÆŸ™åÙÎf³üµº¸Âf p;;ÔUX‰Üö9âukøëå»êÄ q€}줌Çs¥ù!¾›kp.¿#Ûù?WJ„H3ïa)RÆüµ(o-þj,ç³XÃílåay~y¥%ìa Í8Xˆ^E¿ÁýsžÝt±žÇåÔòêD ìfwˆñ\W¡¬žÅ:~~ylEc´™ôР<Ç*B£¦²:¸‹ynùt‹X4ÓCy6syŽÇo‰œ_y,î–5üh¥â/I3@——-õyaòÐÕÔ~Ûèå 9½¼Y-Úh&í× t˜Z8¨ú)ÒÉQ[A+¦(ЬW¡<Qû´²_Z8±R›XdÉh]+†t›?…ubmÏšXOQ†Wʨ‹òòãèß\X9÷ù2 EέääH?ÎŽó²~aJÁuø›¡…<“2·?†ø÷±>€}¨¿eèö8m¥PäÈPfŽò²€.;ø>øµýãÞ,y÷ÉcIiie"Í ðyî¢G{õ*ðfÿÏî×iþ5¢î-”T—ݬ}ÜÉ»Y£ßâè@EÊxsÌ}žâÿVÿŸ(±–¯á—Ý|™Ý:fàf‚,ïýqŠ$(,M¬§ƒšå‘¥£¤ÙÊG¸¬÷N_ÜUÈÜ ‹ºû}]4ñWrbi_Gù·‡”z@Ô¢Pü=òK—–Ižnîa/-†á&‘} ®D1ƒ|†ùo.#ˆØÅ^:4§}ÅîDÌÒÚ) Sº‹µò•åR²–{ðx^û*±`KÔsôÓF‰‚ür)/],zØÇV­Ú%…,é~ªj-í4ñ° /\”6ö°YŸØx¨%aZï§]¾¯.,‚Ml¢\€ Óµ”qâÒèæºågœ]Æm¡‹nšÏèô<Á ù8ÁXÀSÌÄ(±±–dÇ6à}ôovŒUÅù›¦åø"'šý²dÑ \ÇgÙFÖX…, †~ÃEâAîYr¯ù(7z;å|s5jIŘ¢‹ûù"7/¹Žu|Œú·wb»,±[A`ÿ(ÿAv,µ÷pͺNÓ1x§ƒF¢†·ó¶/cQßÀ^ZŒ•81*7lš(rÉ1ÄåÀ’4Ös+½¤p *è¯1zU(•ãRjæ ïæ¦%÷ª}¬÷“³¬g†ôZHx€ËÂù†Ð»ãM†x°u×rËà’ëhe#kÈ|vb騀 4eØÅ{Xj{è"ÃsñxÇËfYûeû2!ê ƒË󸍉És‹9! ak“›ØÄ^ú—ñΛÈ-Áq‰ÕVqYÜì‘¶%×a‘!‰òßÝ/+°W)zØDË2ΚŠD0ø½¼É[““"ë¥cɽº“?âZšnç³*ŽF\d†€Fq¯É6/¹Šíü>ïñðÃc–FŒ,‰q\EZÉ/á¡ËZ~ŸFkZñø¨ŸGÉ\ÔK—[x›õáUíQ¦¸ïz$¢‚½eIìmkYÿáFº 0· ‹T°±(“CQ&Ú,x™/©“ÚX°‰Í×Ëfîãf}Ñ1Bq¾(Z”(",Ç!ëñ@†ëé‘)õx,||„›Éè·ùáW"%1^³^yî¦U.q$j-J÷s“÷nkYõ®–ð×ÜÏ}”åO£WŽÄ¢Ÿƒl‹õ8 ù q"™»)Ë_ÆÝP—v²‰f/@ía^4Ï«X(ª¤ Ñ S*pó2wÓ^ºÙÇ&m^9Þ‰ î[™B ›TH­û¹]tÉŒz>6ؾ—õ¤5°pÜs›4Xª–E‘ãzšeœ31RX`ëô™2å<Ì›8¥¬oxŽü}4I!Š"ëè4vHK“w~eÉôA0ÚÄ^ªò£¸H€dé§ÕÛ+·JÁ1ãî ]ß-mä%ƒVEž-”¥wÓ^r´S¬]Î5’Rxr/šÓ~|.¾pj--²¨NÆúj­žŸ†qš‚ Äí´•æ›g.b‘çm\‹bŠ.™/´ é’çÜAK`“Ä ÄÍQä*—hg”2ÝT¹ }iÎ¥óMÎI0tV9Tp·50ôY2B;¯’g„vòT¢ ‡î@X®F¡‹_âñ¨}77J°&*Žç±+„ÃÌÓ‡b ­±‡XÑÃÝœàkœˆ)…{—§Ú— ¿Ê ÞZíó1ÆäŠ(ÅV®g'…XqPÌ£#Ež1ZÙ2Ý‚—Dr¼‡iù/a³A2ÜÄv/œè¯ÅUñe L3N ÓØtà°“):c ÐýéÝ”ù#¢¡ýýl÷b=–SJÓš¤…Ó䘢™6ëi:bŠ0mäù„¼u)0¤½sÇóCLÑU©Ð`ÑKÚ+ÇT¡;í\ÇE~@ ·2h˜ˆbì”Z2¬oEŠUÝngF¾áy–~:É.y²ÊX”H‘¡D51Æ•¿g®£$? §¥Ä¢—m&úÇŽ ¹a5‡ãü’G™ÄÂQUK9’¦¨¦äN®å}¬cM( Š2ãüOÙÌçX{5Åy~ÛXvð^>ÈŽˆ×éÒ9Êï©— žoáct‘ PIéKuÓ¼Ì)õŠ´PRU±”âÚ»m|˜{¸†œqÏÏFâOxÉçºtóa#‹¥½ÙÓfš²š¢ɪ²´«I¹…>ĵÆÅ?ßK„üoæ…&éçNúBUj‰Îó³êiR%I«ªæy úÙÍöÒFKÌ~]äÏÕ“Æ^ur½1WoÒ£œäó(÷2ŒXÊ‘y5'×°•›è¥+àGYZ§ùßÍ*ÒÁ~Z#'×]É4§9Wå/\Ë †›ÔÖrŽÿ×/ˆEÛhòºÙù*ST¨p‘q5,9*ÊÑ;åòª‰ëÙÃFÝB'Ø*Îñ¼ãÖ’cͨ©]›f”2¶*¹…­’VUiR%ÙL3ûÙX‡éè2ßSob}=ä#ŠÔýÌs…Šš”´{rõJr8´ÒÏÖQ0®gú™äQ %C ¹P5‡ßƒa–Iª(·8W”Q¤UEúèb£›ƒÒán ‡Eç¼±W)šŒôOP3Ú”˜»j,Íô1@[äÊ¢û[NñŒÙlF”n*]ÖøR¡ªÊf‘±¸ñ§ ÝtÓª¯z¦;¥˜âMÆ ­¸ƒ¯s3_QÿΈ ún‘`#PÓÔ¢”HJÙÒLš.Z¼krÁÍ<ÇÍØÜÄW¸.sžæVÿìxônÄ!GM¤É„ ,·ÙÌyÿ¿¤¸–?å&Ã|ŽTy•òmFB.¤Û@7M.@ÁÔ%6—™Wâ{èc[Àb¨yЊ‡xH½±Du‚P!{‡u”£ò3>ůEà\»ø4/^Ô]¤<ÏÙÒ?).rœQcî^ÕÑ勌ó=Þæ½Üm˜&–'Âûø8g¸ä©öýºüQ…¼ÁQNó"S̺þŠ>UeP“ ž—.žãA~#6 ½•åHMÔ%Çv}+ÃòüN¥ójOó,JÍ‚*¹¿¿æù ÈEF8Âyna§Vï&¥~>%Ãê¸ç©mÑ4ÌÊ€iÎp‚+”B<·™uH.ð6·²-¡{¿Š=¼‹Î—‹†T(Ãs>Æ;K]ÙSà Ë!îäîˆb·Plâ^ãTei'¯}åÕþ:(fç"³jÜZl½SÈ/s‘}ìÕ7ãM•¨ØÌmŒÔ´‰¤èÔQ_B\J Ìp™E*Z½S¥J NI3§¹‰;cc k8(õ̭X´ñêæ}λ)µPýfÇ[É"ÈÓŒ0ÅfÖx= |íÉÚ=h±ÈW?îP¥Ä¬î'ž¶E P#2ÍU6²–žÈ:RäØÂ´¡yÓ+i¦îa~©[#j–Ye#›c÷ª“!®ê΃µ0â%@lªnsÓ)R®w]–«ÌÓC'æéíbs蘉´òìAñ‡r3_Vo F‚¨æ €²AÍJšyºupWfÖÉLÍ ‘>Ãî@y«{y¬•?‘¯Æ×Ý+¤J•2UšuGù Á›§_½ªƒ>Îþ˜>›~Ä÷x#Z¡TElªäQÚ ÞÁOÑB…²t¹›bY~…¿T_]þ¾žrX´ßnÙÚ, ÞBös£—᪩5‡*ù{el¹{J°…€€û@•¥*e% )®a¯' Ž÷wlŽò8Ïrnéû겤øcr¢YnKÃz Û˯íd §®žà«<¾tW{µr’¯sžI>¤íÙ¿áKØFˆ_tÈr; ¥«tˆÇæ"?â‘åî0«Ë2ÆqNó¶i›Ý4nçHMõÊ^nörµ& Oòõð ?î‘—Õ ^ÍD«‘,PD-rŽK,.)ÂÇå W¹ƒW ;Ù./«ŠžQ0ŠÈ”g,Î1Ê$Ë\šU³bñ$£|¶P“f׌Ûó^Ö9ç¥ kpîj¬&–nA­ª “fŽ CXƒ;q¡‹­rUÿ†iÒ†¦Ï(µ™az¹+³ª$‹Ì0K–Ž Wâ×3j?éHç ·1Ii¥;åjŠ7džFÃ^¯¶Ëy£Ï^¼ÉàPY~`‰ª0)Ó,0H[l-zé‘aeƒ¤¸•ƒäà/Ë—Ôßž,{½XUEq‰E6ènÁu¸cºÜçfîöŒ8¼ìµ0Æ8 ѳ‹T˜ÆZCƨ…"O›””€d¸žd¼“%žw‚oðå8¢±q´—n [¤Ìx-°ü>štöÁÿ—ù?V‚s¬tAGØš+zévï¢LíýeNò-Q—Wîe¦lìP—[åÝó´´ís°Œ¸´føO¨·—oW lUÕ#œ¶°È¸)ð.ºûä~Nñg<¡–¿*©qžàoyÅ"¿¡~[{yú£+8[ØC_€6—ø>?[©’ª¨qæë¡~–q IDAT©}ßÊû½Ë~ûÉĬcœ\ Î5¿âϹ `¹Y´ƒ.ÍÿlU¸Ä¼¨&Vêe¦y„os>çŠÜI/à¶.éDéò? ¼Ìa5¼|Fe«*Oð'é#ØÃû¥Sg 7RŒÙ««<ÆÛÊ^aúÑ¢šæá­Hw:E/7³], G_€FçSâØJÒ¡l5ó<ÊYs3%p=·z•Á½º`,ø™çÍ•à\Óy”ÿÆtLçÀ¨LÞ»Bæ~llf9ð*­ÔrJUx…§ ´luWÒÇ~Ú5 Ɇ´•ƒC•+Œ«Ùåê(GÙá_¸Ó­ë¤Å« O®ÃÕÎÕ0“j…“ªªJœåM.Æôzoc¢tG5Ë»È)ž¾ª0ÍìJm­”£8ËÛLà6Û2û v±ÕãyÊÈ/ûYæj½sÎÔqŽPqÃÂ"Ë–`ì9PÀéVÿ—©®Ü½N9Œpž…HCfE kô¥¬ÞÍv½Hñ×òurÚT\qâ§%LpšRÌÙͳF²:ð!Öy×ñvë_æ{+j+Q6óL²3÷"OÍ¢€.ng“‡Nþ~å¿òÝ•9¢JÌRi/žw¯úY ×ónOíú›¿TQç£ôf…/!%¯óû)ÀÜÁa˜æ'u7þ¯RÑfC¸4ÎíKÔÅò!0·™äkü€óu®Côäœðå“´¦±‘¡ø¸È÷y¥Ná)þ”_pú¦D/›!Š>†"Š×f”‡y²¾~Êê ñ-ÎG‚É-ÜÈ­:¾7¢mªü@ý´nž?Ä_ÆÖ\Ü/ïÒµœëÉyï®QåY^¯o‚“ç¾É¥ˆæ¶I(ÒOÊ{»­ÿ™åç¼ÊX'÷5þž3‘ìpšÝú¶x'=Þ lMÃf‚×8[ß 5Îk|K‘æšy®a;ˆ¢Ù3}Ì•Ìrˆãuž«I^äÇ\„G‹ìaŸ¾Ú×â·»’·—ïÀ òS~Û>÷6Ù­“^EäöM† ŒÔ×ÝZÍò2?g*év1 îl³|Œ|”¹ÀUêjª*œåYF#êÓ¬gÃÜõù²È8sõuWsœãi¦Mt-,r¬÷êúÓ =MkšÙúfb¨yÎrŒ9£Á­›)αŽAm˜X±}êÛ¤Np4¶ðVY³ä¥GÑÞy]s T™Ëœ¡ìñܯíè£U°†(*ó?Ç«\£DÕ9À[9ÌpɃ[S Ûé`7×ëT‘côG9ÃßðD}ƒdU•yF¨D¤#M E‹Ü0±D»jÍwëÃA évÒ-R¥èB×­ÇÖý|Ký zŠ4Y±Úçy‰c4þĺ÷{BAj›9^àdÃÞäÆ ÿÀÇiUŸâ9`ÕnóR#Ã$õ"Þàû1Gnãé¡=px+®× Ï[<Æ\¤­ÉFÖS 5à™»ßwê|NóS¦C·m-6±‡.šµtøþs™sõNl2NÕçJDBº¤‰‚ñq¿/rž±†y~‚g"*SôÊ5ÒBk$ýa3ÜØ„vu’_ÆÌäÚÇÉê2j¦Ü³ ¯ã,¯°`Ì5siõÓK:Æ5°™i ÎuòëM“ØÜ–&Éy`kÒ˜kLµƒ¦9ÄlÄ_k¥Ûk!Ì:/Rmx¯®j#ÎÂm²N”×õÁôЫÏW£œåé-,¥_vñ ¾Ã´üŸ¢Åƒu§qLq ;B£•zØiNíðcór^ÝÑŸ«¡¸ŒÂ¢…vö°ÙH~¸Ÿ9~bÜÙ©÷)3N%"çy ôk½kF¦ù¯7LcÙ˜)y9i¶Ø*…sp¸Ìã$yæ=ÿÙÄ&öêò…`øêÉÆ–rÛF¤B¡Ë´ÎÁ¼Ê)^g>Á: V%§Yç)E¦.óRÃðᆩˆéRfÑOSlmF9Ôˆî…`ÌÆø÷«võoø·¢^”g^™ª}œ×ñüaF"«€ý j4·ÄÛÌ5ÌóyžáB¤Ê¶‡!ÚµÑ`<¿ÂùÆ=%<ͩЩR´²“nr 66SœM°SeNpÎù¹2ÒÅfÚH…¼g‡9.7âŸëg’癈(á:š#1›yFñüY&cÂîC^j” 4¼µÈ[Œ{0å'Éè½Ï̲Y`'Á:Þf$·MaQd9=uÀÌnW(% På²ÁšûÕB¯ÑóÜ×¼vãf 0Ï)#E„ŠM‘^ƒµ‚¸$ÏimüGÑöq…â#|›Iù>Ÿ§«Þ¼vLH|!°h¢‹-ºG£i–ᙆ"Œ1oœ«ZÍAÛé‰T4œçǯD9̳©ÉQd -…Z©ó/êËЇÛYµA,l±ØðÏ]"/ÄõË®«¸¡²Ü݆„[BE,66¯rºQûJǪ1S{[ ¢Qá¯5jU{yt+/Òcdžk%EgÌf AH\_¡½dâ`sšüP6§ø¤êU_àQŒ}oÀðq?ïDû°×Eå0¿Œ‰6ì¦[óÜŒœæjžó"oÆTuѧ›=úE}®rN%PYê‡cx¾IߣšXcj$Çr4Pàv]ßÈ ©@ÁƒÍ¸ºšèä^ⵈRÌêa¬æ¹uiÌ&â¹»Wár¯MäuÀÕ6èL³Èà=ƩМq‹Œ$KmE Ì'ðQ—8™™®è×M„ýz‡²*'âùE.âö8’Â"KFP¿¦+‰N®Ãgñ)2ôG â;7P£\2ÖPãz/×ÁpáCü WäÉm4®2Z‡;æîAÁb}Lµó$}cˆtRÐ#FüÐ¥M²­BÕÈ=? ›.CЫ88Àì„ëpB]Ÿ-Y: UUS%§ï•Ä´O-Ð1~Jœ NÔi “þTÊÝœSW([kc'È¥Öž—cÚ í k€­›Ý®&H¸O7)Eî6tÑc¢U}¾Æùj®¿6©ïÓ<7ëÊõõEüµãžÉ«Œ@r*Þ-3¹ÌÄÂåOÕ+1á¾b !åG’>Gcä|ƒî24y§I ä8©ÎÒ®+$aZLH.PÑyTÖ;¼™†u9!›Ëº¶(edº;åÁµ]«ŠJÈó3z )ãV@Îóƒ5RIŸ+žYâCÕZÉGÊî‰Î®d˜Ä_Ý,ºb TÑ XœH¬Û§Áà¹=igM &ã–'¾•X³ÏkùN®g§ž1jÒ™ãð2Ù–§11ÜS¤ÓôéÆfª£‰™¾¨¯w™3Àûô¼bñæŸ+H „JDÝÊÐoUßJÁè±í‚å4à ÃKµîlÊèI ݇ƒv‰Ë$j­ ýéæ­T=t'Â'±Eµùc&™¹O›Ñ[«Fe8ñ*{#üg=ðjj뻚p›æä2£z¤¢ßImP‹‡ÏsXd2±Êf^×¢ú;ÓJ^ˇÿï*Ì$ôQÝ—Û?BŠVf½=t)-[7¸Ž*9ï]î×"=\ŒŒß˜MÌóS9wЗ~ü6#îJ’ñ|AÆ™öúXø7éÃó®Ýñ;I}Œ2ÍmEÝøÃœè-‰5 ÌPñôUí±t“s˜‰³t‹¢:R-îDG³Ç`žÖ€É&Ä5€i$…g®Bi9/’ LËTÀÛ y^‘’žƒižÒ>=xÙã5ÆéÆ9úYЃULí—£Í8Yî.•’:9J¤Â(PTéÅ6t¥Bå²JªMÊFñÚ×LšÎ˜áç3½¢{m`}¯7n²¦°ÎQVÉÁVEÔI‹®¯ÅØ®iFT%±êU^Gw_§ãK]åž\)štj4Úô(FSåWGPÁñ·Š‚ƒµï£‰ßÒ螆§x›±CŠr‚ŠJjU_öDÁª<½Ì‡@¥ÄLbÌWüDlÍR ©«jb¹ªKïLþvÑÌŒæˆOc>! [lÎégœçzcø«[à‚!çµÇoò+†ÒIRãZ)š¿sŽ.SáÅÓ˜ÆllE÷ÜÊD¦^'öl•È´.ï3ùÛBS`t4úÖs2Ž8ŒæÆ+ ›J䢒úDÄ,<ëC{ÇXPIãóÔÚ‘ûÃJÛéõΔx³ Ï&I¦ÖÎ$iϱtidtœÁJ]a2ñ^U £¡vR×Åó#Z·Ÿ+aÑðî]IoJÓ‚×nMúT=T†E¤ @¯Y­åÄ4¯Å¡ SÙÐT'ÁY…¯{¸x*>M>„à$U¼úp¦ÀŽ®òÃa‘ä‚U21Ê=¹a2B4c֞ϯÊË©ÍZöWSÕëPÆTa{çjT×Ò›SŽ»hŠ”ñ­†Æ„Žaù»"´é kAvb ,D8¢Xˆ¤Jbã!¨u=[ ðC€ê*B¼%Ò¤B£›Eï•Ó©VFžöbŠæÙ͆æÇ•mÄh¨4|CQ³ÉYJ€FMòWßÑg.&îhÿÜ_›0µ }UñZx™z2gŒ÷uôNͯB>$B#«³ÛÊã„ÂYEJªìÑðOoV;£f\F/6ö^BfµÂJ¯J➨ w1Pî‚¢m zεðÈbdMÉ29Þæ˜ÊПà3µŠÝ«åœ% `r14²«ô¸£ðßñQQø@z¹#B%· lf”¡Px©-ÆðLa­b§Jšç¦Ð¤# b„â’«É,Í¡áÄ ›rH™ ‹«XG‰¾Èÿ=K»QÑ.ÿÝä<ø[ÛÞx\“&ML{åî}3ÆÜöÕŸcK{èbÈ¡h°•ÀÊ’ïY†‚±[µÑ¨ Qïyë(Óá9>p]Š©Ã(¨…Uñ<ø[¶1i eqÿ[÷*œƒ¬a`Õx²HÉëª^ƒÄÖUèD ;€Rî¹²B1alç+åõ/õß7¥o˜ÏU£9zã€Þ‰`Ùifi¬ÎÄ™áL Ó«p_Írϯ‚!éCÒžâãª4­Š†t‡yc5:«¡ayFCíE*‘à[6ÆHªßhP¡X† Iùˆ*)&·GcJyÜ[µ`æ!íUXM´éùM&´6Ä8k™Ä4zôär3š1ÍŒ—½óé$_G7­zÊS„ÓÌëFb¨2•˜F«‘ž¨à %ïìJdÿºBf‰k4øÃj;æ¬byZ`+Ú,tF°¬ ÖÛhõ4–x‘¤…˜½bühÖRüàô¼‘÷®/ÙSíÅá¦éˆÈe_¢+—®QŠìHÙsrÄóæÄëðÿJžg^û÷Õj5¢K !sTX Èy ”“ÓÈ‘3†âˆ>Ïec>œÒZ7¹.I{©g_·§ÒŒÒ€u‰=ï…`Äe.zùTÿÈõ¸3„€‡E> Ü]ÅQt'}“oV Ð}õ>ÅvH™äé”LÂL½['*†qŠqúCÂÝAÊŸЭÀ*@˜Ñö­yà:’º¨Ôœ6L|ž ’”’&Çá»ÔÎéNtKIj¹‹Å:<žû€~5 îĸ|b~¸€rH)­x¯D/dúzC¹×¾ŽëúÝZ HtH6?RdØÒ&ˆ%e*ñÉí¢ÕùQ£RbÊ{oP:“ Eã\¹o,S ÅÉ*(@‡6ûÍ»*#zœ©·$ôîFØ0ÚÜIëž]‹4ÝSQ€IµièÓ¶"¦Jýçè'ê¯Xà•PÿÁ ëŽFð£'@Ã]É(“,D:¦&䇲uT&(!‹Ó‘Þg{ds¢…4Ói0¼Fhšaæ#±6ÊÞD0˜£Õx g¹ÌŒÑÜÐ]KŸ†Ø8Óó¡n¿.ó̆ºÅ ýl‘l"¨ÍEFÙXØ\ ôòr¿Г¤÷’dÈ„ÖàVÍ_i,³Fº&©˜Æ26S,íXÜŸÚ½‹^G}ƒV>Éwö2U3E)Òö¥$'Š}\C!Ô1~cœòŒQØ›h“$^á6ö…)§ ¶±i"—Bäfö6(Î0ééMtr‘Üé©8AÅØ#Oõ&¡!)ÖqƒÑ½ÍÒÒqŠŠÑÍ«F‡$ÜÅ6¶Ñê9Y漎5Iæ­ °52¦5Åó”7ñ ùÓü={’@ºì`S ã] ›+Šiýz@ö$âùC1­_‡98Yî÷Ýrg¢€{'›##`„‹œd2Ô–UØœ EÑK/¹BÙŒp„)£º›ÖÙÊRH”é ì’Kk†·CNŽÍ6%âyn¸éÛ9‹wb:ŵ»S³~ú(ÄtšåS‘^Õ­ìN°YiÚÉÅŒò›c˜±¿fÓÂÞÆ}t±È{4| ªŒs)¢ÜÛØÐ¸§#ŠÙP¿;…`sZÿþæ”r‹­çŸEy½‚Þ³0Óú5ϦÄ1€hëW‡)J‘Û¥7‘zW¢(ñ]õIÚù8Ç Š4Ï0ͼÑ3Ìí땦7€ÙÍÖȰœqNSb&bUgtPc«hâ>6Gx>ÁQ&<·õÍ“–4ŠÜÆ`ÈPTLpJ›ÔÁ ß…D</ý‘‰ G©`GzUC:aÒÉmôDbiÞÐòôÑItob ƒPa1Ã¥€Gö6 ?À€V¼* +ˆZøŒü“|‡OÐDûèO÷ÙMÈs¶˜e„×!2Ò¤'âùµÚY š?üıG®öpPZÈàá5gà¥9Ç;º÷€Éónî•Ækr2ôÒe4âuéT˜æÇCâ„~ö7.!’f“¶~{Ù S¼ª ÄÍOŽÛô<öÆh¬¡%Òf½JÉâ(o„T‰ƒÃÙÒ0‘6bX>­¦å‚ñnWõf¹žÆãÍtEà\a«y.p>²ÅP˜ÊÓ­ÁÖôÑm*Ì0iŸi3Ä@Ãþs†¢Ñ°æµ9TÕU®† ÖÁf3} «Å ù€IâBˆƒ£.ë½²kÙÔ¸.–Ô7 %Ì2¡áž5NC¿_6ÿ¢>«Ú¹o«—Õ”gU‹3éh´:U,vñÛô‡®p‚r ki£Ø0?†ø­¡NîŠw8¬æÆOm-Åõûø m¡8ƒÅ.¨y]KT'MÒpò@öðÁˆt(^å6•B&A%ïîŠÌsS\QG”›X z‚Õ¨Šb¡+b4L1lÜv‚zãÏ ·ŠWyêÓJ¸U¾Ï$ñmuÞ˵ Ÿ«ÍÜB1PãŒñOÇŒO½_ö5Ìó ^Ä„Â3œã"ïDLŸ"ïáÚ±ŒÝ14fÔEŽñv$ ’áVö7Ìó®§%²W L2îᇒxÝ G:ØDÞ0I”>Wãê4g }X“ó[ØÞ0Ï;ôâ ~`yK ¯á~yO‚K[„Š)`„£,„FiÚôpK#>º(IÑCkDS „〸«x;9( ÑPtxù(4,¨E¦9Î\$\]äVºa»¤éÐ,7óçPV6ð6eïí5˜ê`#ù†hX4y1sN™;Øð\ÌøÔV£„¦Þ'K:f|ª€šaD‡Gí@@| a …¨E‰âQõ%À½Ažëžc43nfg ïìÖ¼À›j‘ÉPÐÝÁ!E/ùFÄPÖòevGLŸEžc˜0‚q~ (©†h´ñQ†óÖ-,ª¼ÂIÐÑŒàXÐTýS왢 ÅóJT•m˜4,2 ­"-yîawdnc•§t¦>èwBc;•"ͽlŠD«á¤¯„Ðu%²^v6a’n>Æ&Ã(qå¼ÂÛL·qO(û,ìät5D£Èí¬ä¶NpY O†Þïà°Ï6Ìó;ŒDE-Ž+á /z'Ë?]¸_Úá‡dØËú gáp ”𲺛`¸ŽO5’ ‹Ýô{•Ò4.ª«\áE#è^“÷n>͆F4–4s-=FÚ9¥Ëà®°<ÐW¶Þ«wÑÚHTQ²l¡32 &ÔŒ¼l¡Oê=ÒPhF¶±9†åŽdq˜‹¡Ò"Å5Ü%- „ÈÖÒå•’™¾³Û¢ï˜Î?› .lä@ž¦‡¾PþÜ¥±J¸äÙX&à®ãFZêe‰¤i£90…ÙU‹µŽpÇu5€Yq`±ŽÝ´4px ^vÐT»µá‰g=Ë4³¶É®ƒ}ùP>¸–¥G—µnXB/ëWX¢$¥óÀáûŒ3*½sšYÓ ¤ŽÌ¾»Ä+º¸h*祫~ ’>ýä##y/ò´²)}íÒ4­!GKýÞ­tðÞOS(®8ÇsXÀ\LÀÏ¡ÐXâK~‡_‹ÔszfTYqN@ù¦‚ôµ<ÈAÚ#ÕS< ठ­*kãƒKO£[PŸäßzoW(fy‘C8@™i ·fQ´ÑQŸ—.­|”ßgmd·„y@-•î~p1E‘B}qéåA~›µ~[(l^à”²5 'uÃîu×™ÈgùbÈÀr©ýD½¢Á¶løj¾ÿœ®7“.½ÜÃ'Té»÷?qÀº×RgºX²‘[ùdÀô©A¾Å)ï"¤jW"_á;tði~“ý+«wQRä. Ô¤twïcP‡xš m2øÔÖò>TLIwq?½Ä-Ž:Æ%eƒzŽï‡ªÜÝÏ¥n/]îå¾È ‹7Õ)PgyÖ¨t¯Éz7ŸæW¤®»3ÒÎ>ЖkQáx‡çu:Çü´ñQÞ+m+ó]”ô°[u!r*“¹Ä¨rïÔÒ—ŸMã$Åû¸¡z¼tɱƒ›h5b%5wäŠÛ§QàU£ž¬¶W¼›[¥«®½*0Ä5´Dnz)ƘU:óôL OXû´òQù@]Dv±—B„áÂOñ¾É…PÝÆ¦ƒÛ¸y%¸Kr °A_X ˵úÊæM†#yt›&ÞÇm’^^1Jš ] гŽ*sî(5Í.z^ˆ !;ÙJŸ4-—ËK,zðjÏ}f¤°)y|Žë:t1¼[¡™l‘敼X´Ðæ™ æYÇ×p2r•Ð-[Û%ÛêOÎòoÄÄ ˜u©¥)Ò´rà]ZøU~›M‘²>‹s<åM¹›‹DÜjÞ|}._âßÓ*…S(J<æ%/ÊúúOðã©\1”(Üǧ"Ûó<ãÉGÍG—|)ÔrÆ¢(i¡“»ø »",£¼¤N+ågÍE ×ʳü>‚PàAàYÖ\”i>Ëÿ@gHÎ-R\á9¯Õ½‹e~p?ÅF~ÉŠ‘)r/h.ÈÓrØkõ¯Ì… 8·líåwêâù‡yÐX‡ÿ©ðºþ+c<ÅñÏÖòi~e¥â8ÉH 7që<ÓÝß­1Þqy®*ü”c†±[ó£Ûø>Kz9¸%M4³‡ÛY0¯jŃgÔ(€åIŽyZÑ—ó÷r;;dÙ›-’‘4x¯wõÕÌmÏrÆkDõ g"‰/‹~ÞËÒ³’Ù Yv°—¶Ï-,æaA7±T/ÈÏxÈ’s!ýAéáIuvÙ<ÑÛtˆÐi<»|Xi@WU9Áaúu@Ö\PwÐ%¯q¹ø«R Èts ÀèH5m ³<Åô%&>[ÒÍÏdQM.æÐN7Í^;Zï`÷ÿ/-pF8ÁZ=`Ñœñ^daTæã‡"Hž4kiöVàÓÐ3½¿:L7}!‹×A(²•NË”š[Ò,ÉÓ¬;éÕlå ™1—J•cìˆÐpȲG œQSË^ t ³*ò&ª)GƸLÑð@j4ò¬#/W˜]jN–X¤´€‹î²l>æŸ'¸¢›Î„yÞGŽ‹R]ªŸ(yÒm^P7ÈWù]`·†óLRÐ}éÌKÑL†))c+'ž†®óÖ`s…ŸòƒFΛÆä€·‹)JR]‚‚E7ûx€÷‚vÊû=ÿÿÖÎ48®ëºó¿Û+¶Æ$¸‚¤H‰¤$Z»4¦d¹$k¼ÈQâ©Ô$Ž=“¸œI2å)HUÆOeÊI*)WMœò6™Ä3–ilylm–MË’%‘”eI)‰+À\bknôòÞɇ¾ïõ½ï½n”* AïôÝÎÿœsÿçœ×Øïeÿ«¼ähHeR4 ”Tƒ"ªrŸå³ºR^ð÷žVºX‰)“Ô'°æ{êvÄ’À©Ÿ•.ƒ¬çcÜÁfäâ'9ìç ?8Gb~ÑKEn䝸²dÕÙÈõnC±“°M÷n㤻”å]_†ˆ÷ýø¦1c«ù7ð/’+d£êÊ:ÚøOÜ¥gÉõ«AVWõm£h×ël磉§ Öñi6󴌨óuÖ¼ƒÍÜËmtùzPgþ(#^õ1µ[žà÷­çWGÛÇ“µ<¡7Xó<ȃV·švC½§%”å{"áYÞi_ÃgX'?á3uvoýÜÎu èRÑJ7a©º|gbWy‰!_ïšXõY6òMÉ©K‘kÞ„bˆYQƒN(1­c'ù7øû®¦ßûùëØÍi™!5饉ûÙh5xñö—pžÚ:b#[ }åÉXÁ‡d¯\Tu´U3+ØÄ:ÝÐÙ+ÜäÍù&•[«Jý"[Y¡…{’·8¨.Fch®¬‚ÕœÕn޽¬c“¡ª¼Á´r++8ÌAÉ¢å€Ä”+1RjQVÓÍ šHø ”è%¦k=Õ”#o³FÔÍV61À›2Å•—¤*K\9£‰2ÝtѪ;ûººP…§Xc¸R+ˆ¢Jò«¸NO¥yßÒÂJš˜`”iq™CSeIª²4¤é×ózusÄ(3TÝÆM¾ŠP~72ÞáI« }ޤ®÷ Ä&QR§©lça>ÉãLØûèÿ–„HÑX;±j‹)bâ*‘8)\U‰+G’dÔ´<ÈNîg•†¨§c‘iöXÚÄñ«šzùå¾.üNQ]‘6•“&µ(I˜å6nc ×Óá÷׮ɉq–ïš  D­òm~ׂCXI+8ÌÏ8*§€&5'jV;YÍ§Èøçã$ ‡ù…a`^àç<ÌZÝJÕäÒo¢‹›ù©P»¥‡yUª• —|„{ØèŸ)¥5Ju‡`UÆùqîd«è®ó§¹UžçgêxÄšq7÷°&Ð\ÇÓî—5gÂóÑÀnóÛ§Ô$õðI6ó ~,cÄpUY¯y‚5'·°‘›éÔÎ좲%æ8ÆŒ¿yžÜ£C×Ò(w±•ïË9Þ£¬f¤I-JJ•$A'y6³‰U Òì—¦!7ž𓧠ò$7°Kwu3ç«‹mtrŠ7‡Ë)•—•—nà:º¸”Ž º¾ãYÝócœ0 ¿ ÞàVè@&•p6Öó–œPoK†‚ªHL¹ .ílg#½:6èhMâÃ%Ægª8è{ òoù|„¿æÝ¯N3ÂY.2Ih¥‹^úYI“ÁÇ6Ãx‚ðŽ:P>äaº ¨ÂuœŒ£B&ZHЫÖÑÀìXæ@Ž Œ›•pEq3Ÿðe8~n¤'c”EÎQ"K‚9ZH‘ &R$ šip˜°­2ÙÌÃÚ+t}9^u¡" Ì3A‘<Ò”h:qiµæÉ\Î “¶G,)6±“ž@À ZÉ’cš"‹IRí¼ÓF«•údß›9ÌýzÙÊÎ\ó<ÓÌ’c‘2 Iš4)bÖ:Ûi=y»œ(Ö±…´aƹLþf)BYƒlRC­9‚4¸8¶_$Š~†H‡ Eo®sTXÀ¥ ¹ÕgÇ û¶vÓ«C¬²‰Gø¦]ÉP:üúåöþ½îŠZ¦×è1f„Q?Éwiñ}UA˜â¿ò¸9‰ÑF§.}ébe®®Xñ•±B”È:ÎDæL‹®ý?ù¿Ùj¥=ª¶%9¸UƒIšXÁF¶s+÷°"t[SÁ_R†Œ¾&#.dKA¹òU.pˆ$e&ée€6ne=ÉPñwŠ)k„ÿÇ3¶y)q¿©í_äË4á"ì%Ç+,pŠVN³–.2lc€•ôéÅöþupùO;‘Éî0«Ôæ¸Ä,\â9.3NY6‘àn`›u Í=9Ë·yÁÔ%’á7øcn øÏ^v}–“Œr€9Æ™¤ƒE6qw„².į0Å“¼Xó?à«Aξ±³Æxƒw9Î9¦€nV3ÄV¶Ói±kl÷å1õR`5~›/2`Ì’8ñ{x“$¨¥nšÙ¬¤bhÞšn¼È/yÓ\‰ñþ”UÖÞ0ÉÃÉs€<hæý´Ò̺頉R/ò¦Á“»ù2~ÔÆœ§ód™`˜Sdi'Ç1®CôqÐF!ÏŽšf²´°‹ßdH›Fn EŽ‹Œs’f˜§…eúbˆŠUü­†;Âï2¬/' µøùXõî•!­}¯éHnÐG¼ŒE~x€{õ‘cÓ›oµÂ89šp(ÓŒh"—Èß«Âà9.„Ž âíÐû\2aU8_àQ¾DJF·q”ï¿R"nD!×°¤ÿÍ_„ö®"MÒ÷}ƒ²Z9M7Â!¦èÃ¥ÄJúÖò<Æ÷ÂÁg‰û‘´ê¬~Œo°ÆÿËY ÓÉqÖ2Mœ5(â>˜ö,/¨¿Žäô‘ FëNŒ¿)#Ï%0Æ:&YCt`÷‰Y»¸<Îw‚gPø<D{䊸¸ä)q‘0F†!K:Ö‰\ üŒ§ÔTh=þ’?Œ0ã´X»BeP'zr~Ê¡5ïçsü.m¬÷ „dé¤B™n‰@¶PmUŠ¼Â¾ˆq|ž/ë„ÃybŒÒÊYúÉ¢èÃÕA|Ǫ‡áÁà{깈5ÿ-~‡•¾±ïXÎg È3 ¸ÌÐK–‰ûZ&¬_ç—Á ½tó0è˜0¦]*(k6ü iz‚Ðn–æç¬%ŒÓ³d¸'‚£jªl¬{:¯—WL7|ôÒ¯bœådxªTVöÑÊí:,áFa¡‡N==`>¿ÊHaŒbH†ÈAZØI‹e·Ö :‰C/%qhñ‹ÄÚR¼@\‰“‘×KÇéd™@pÆõ›HÄiÓ° m8$t0æßwyá‡Yæ" $ÏVÑ IÕ‚½ÐF‡”¶çU` £?Y‘|d°#¤X¸á¶ iˆ¿Ú„¨iJ‡D]`è´¬å žWPJZ«Z¯º˜Ùðã¢ÅÅ„Û+$èÕÁä äTßw ‡&’z_ÔžY å+£ÍHô=o–$íÚ_sˆA­eh\¿w¬{.gè§gùO„{,©ŠätI`°s¡ µÞ«.jNžã#›­–yžÇ¢îÉ£´i! æÝƼ`ÍŽùñ#þ!¼J¤„hÝ*ø8½Âvm–ãŸ1vlLÏå$ûy–¨q¸>W` Ác×fvPd%Âz*>ØZ¤úŒ ÎðLäš?Å>ÁÒØÍUªºSH³‡U”iÇ¥ECˆ§MbþíövG¬ùy’n>¡ÏR§Ò^Õ ©9p5­3¸sŒðV-ÜnŒã'tòqãòËþlÁaˆ";qèóûn8†N¯uŸœå "×üeVqÚ™2ãUþHŠMè.Ó„CZKðZýÆt$Ð¥È1ŽEܹgy™ܨ[dÙׄÕXSœ•TpèÒïcOaÌ™ Œ2R‹½ ]5Éx=dYE-¾ŠXl“ÏyãÑ­WÔevs€…€Rw ÷4 o,3!Çeš *¥ÜÕorLç'K ³Ð;,1Ã(Ábi×ds\ˆ¦Ÿ©¯1¬s<ÝP—À8ÌV­n[žUŒ jš#œõ¦l¢†ÝW©f^aÍ—ÒaÉsÑÔ0•ç0£!ˆRôXÏ–(D_TŽS\¦±æX½›ÌQ9í^~{ò™Zdœ™ˆ¹"dˆª9-Ä ¯G S®0«t\ Ô%¢#—ù¾A1ÊŸiý4/ñêX¤Œó¬‹e`‰â9k{¯çyž¿«#Ã!o0ê%ÔY,ô–óóyþ>Òd@¹”ý0P)áaKÅÇ"vnm ìå{j8ÊUâÓµ„_ðk“™cIúFg,°—Ì»Ÿoª#‘ãçoyŽóV‡7sLµyñÀs±ïæy›g¢¨zÊUÇø.?c¬¹²Fæ#fó¿â‡Ñfu‘¯ñ\]0—ˆSÖðÕ¯oòLØdÐ)Yßf7³¡Ûúð³³U‚RÊå5u)êªóüW™Ž”àI‰³c¯¶ÑĄӼÅ 5Ícìe,Âuó év³êG‘QÞ‰š+åªQ~Ê›çÃÖía½K  Ú¥á=5]ûÅ„=]òJÜ ãÑG=jáOs¸Gz‚ŸSf§& ¹!˜0„óšuZfœ3ÔíT«Æd7ev¬UÁ©2ã ®Ÿ“:Ådý¯ª GYàMÇ Ç1Äïy­BcÁ§ôÌ3Ö ›úy„Õšýìú¡V" F@#[dŽº2Ô¬¦b„*ë¯yÔ(¼ÿY¤Ð CxžÓTè·â޹¦"À×1’îÂãXQé ÅL¨BñýšZSeüVƒŸÊ‘Y*dô=wooùX¾m-p„¯ñm„óߣU‰ŽsTÒÖ4F;Ò`a/3ºœ®2ºŸ¿À×9QwÉ#š–ô ƒœX‘ sŒ?äkj¸® WÊ$|:cí›ùh€deÇ`b~„ÆašWøŽÁBCz•|˜à3ü^`ýÂ{WüïÊ0³'ù/×oO¬¦åûLðï¹Þjt^¬½jŸóEöòÑìeÞaxnƒ°X?&jk-ïµÃ~~Ô`®ŽËß²È#!ƒ!¸s£ 8/Ò°‡©º2埨ðÖ»aó¤æÚã‰ùnV…‡y‘©ºã8)O‘‡|’[ôÆNzÍq˜#\n _$ˬ @¹„\úñŒ #¼ªæëÎÕ ¦[BQ^ E‚l½k®‰ÃÞÅÊÜ dSª ò=²<ØÀ_ BHÎp¤QcTå0*?eŠ›5å+<Œ«YŠóLr–ùFmÕOÉ ÷†rU¹j Yé¾ËÓÕ¢8 dŒK—ëhÑañ¨‘H¤Ýîñί¨±†ÊdåEVÒaÀ ¨­([¿é\㦥jVQМÙz>› ©xóuú5Å;'§)Ч;\Gí(‰P¾5qp§U*qFŠ Dñz~§-g =©UA\\][Œt${5Ä‚(ožÊêŸåFæÔWJpqe–VR¾r³Œ­ø‡<ðÂá'yšÇÔHC)ŽäqIE2áhî€ÚÈþßj`–T!½¢K©˜{é!Ú Tq oïŽòÿÂp£¥¹è·òŸ5/ ì£×‹ú"Ç^ç'ê­†È"þ¬ŒˆÆHh¶l£ÁÅåQõ†rœo‘ãƒ\xjÔúc„Û=ä"{ØäæK–¿d‚ÏSý"toTÄD¡ø1ϪÉ*’op‘YyÎU`tF©h¿{Â1^æb£“®&øŠŒñ9mÚF™ïð£È,ÃT§®2W%*|ˆn?G'Hÿ•@lÔÓíÞ»ú¥ÚÓX“pAž!Çú¢("š©ÛkWÜYNrDÍD…Ó‚Ôƒû¹•‘¤ 7ÐuܦMLs4*"BF†mÜG¯Es"žnu)1Å%®[J—e¹Ži"¢­¹ ÆPÁa†)Îßri9Ê‘­¬aˆ É;XOÎ䟗(s®Q®·±XKNÜs"ä„ù›Õ¯E¦X¸Ú(´œ ¬§5’‰|ï6¥¨D®^V|ˆûÜÃjš­MYb1v]#  D¹1œlôA ·ÁªâõYzVSÛ®¶J$£óðƒöéc ln ´=.¥‰en(Á,X…íaž2þå$dz^ý‡«®HÊŠOV"nÝÀæQþ‰ÿ³¤èåúמú(Ÿ®Ë²¯}ç »y“áܧ+îóU/¡j Ц¹¼Å>¥)*=Óz~š¿Í‡x„"¡šhá]VÛSÌð5µw cˆ³»ù8·ÒÊ×p#¨ž¦¤ó|}jfIëñ~Íuˆkõ?…3ü$êîÈ¡öP«“`!+ó_‹¸œà¯’T‹W=e>ÌN>HIgIH£;‘2çɱ{)ç\b °;ÙL³¯]£°Ï‰À)ös2ì:ש@%CÜÍH…¤Ä0#KS$z¯fCôøR¼ úæ˜dôjg À·‹U´kî©Ót½‰Ë2Ê¢  -¬e€AJ!PK¬Âlžy.. h$Iëé¡•¸‘¦º5i‹,0Ë¢Zr(ébAíS\íx{Ç4Gn«¡ÈÐK†´ŸúæZ©ˆnDêY5Ð]œk0\A3I#­0ü¾m0×µø–:W'N³6‰„ ±à뢫MÄ-‚\ðöÞ»_£až¼ÊS¸š²²F’…y£ÝäÎ?Áãjÿ²Fó½ÍNkJ“I“s­y¬*ö'9µˆòAäËÜÉ: † 1ä`Gx›¸Â¹¥­Šô0ÀÜÅý,X î†Ò´¼qLq–÷øÇ¥˜í¾›³…ßävÖi¶x8,XçoQð*ÃË8…;ù¿á‡¬Ý† .šiÿ/Ö¿^‰ÐW7ð·³ÆgrÏyÐU(p™öqéjÆ•eºÿÛYI›Ÿi­s=0F9ÅAfEº¸mÜL¶«êv—9&å•¥¢H «¹‡-ô‘õ­‡‚‹L1Êc‘Ì’¢näfn´Ò0œpwqYä$§Õ“«#¡u\ÏšujÔ„Ë‹\fŠqŠK±Ù-)[¤ŸA-&uðU™9f˜ºZ9B)6‘a%½t¡üx€ð§]ôeŽy“ư$1ÒôÓEIÒݳÍãW¡ÂsKõÍ-9ýôÓ§KÞ4:âB…–¾q Ë7C—îõå5X¬àP¤BiyP¨wV ištÉ£š·ö¥«©’²tƒÁ©$iÝTž‰‘tå«äeA#Aœ$‚‹nzÿ™O1Á+<Ëkêò²W$ŽVÐgy†§Õn–ý!gä£< )ZÞ÷qfx•wÙÃäÒ!JËx„»¹‰{™¥ÍZ;r²Àçx‡_qŽ3K7}t„iÿ†ì E‚㯼½·²¤x‹w9¢^^öéèá.v°‹núC©‹æùp(1Ã~öðÞRÊs?ñ€®6Ì×9ö²O½±l }ìä>n¥ÃÏi2[›¹ÚÓÌqˆ“®GÝm å>¶³™›ÈiÓ!ø|Ï\(0Ά™`|92$I;lgëIЈSšÚwž8§å¼:ºÌ1$Ép=ëÙF‘µ:jˆRf3 s¡žásµÑCla3ë#›·¸:ÜsŽÑå«CÆ ¶²…Jˆ®ræø½ÒŠ”)2Á,—X¼ˆÒ–V}¬!F?Òº¹F…jw¨$Y©0É%ò×"C¤IÓO7)šic‘qŠÄ(é[f˜£Ì4 £XíK’ÑLŠ>2dtÍfÇÊî.áfÈ.GQ…ätêb õzž< ïKF3tê2eIð£C‰%œ:ijK9&)R´I¿˜d-]΢‚³ï?"œœò›àTS„8ËsK†Òí‚·ž^ÉO²§£yÚK6½v1Ñ€{y…—Ôë¼Q|¯P î'¡{ ΓgŽ÷fËñÓ¬ç¯cˆÜOš[˜¥‡ iJÄÉS “afÈóo’etiE¡}ÛE'w±ØD– mÌÒÊ `œ$GÈò'kÌià³­ ›]\ÇõdHЦ«/zÙì³”Ir†Wx¥ñMðUäÜÂÝÜÉB~zíÄ¿Ëö¿¯}µ‰û¸—µA׃«è8,ä(1Ïi.ðY&¯MŸÈ«ØÈH²…9ÚqpHP"FEZ9Ï<‹ 3Â×"CÒ´‘áz6¡‹r4“fy qΑãcdó®Ȩ–>ZÅjšˆ“¢¢k¡VõÕ1Æ9ÆñäÊ«º>†k¤ŸÚi!‰Ky²L1ÁøµmÚH‹n-ý$ i²1¦(3G–¼š’ص«E­à[覙R$‰S¡,Š9*ä'Íâr½ÿ€§“T‹²’412$P¤É£ˆÃ"yJ¢«¼/Gñ*W:HÑJqZppIQ¦€C…æUá×´ÚhÖ>¨Â¥L™"E)¼(·d4ÑF¯k•õ§Ñû>IDAT^Ô²œp¡Ók€©8)b$ý¬¥‹¿T¿–«õÖÞD)åJÊH¾ Bº¼¿1ø{«ö|1úñëy¾åGW_Š™eŒóœàï°ÿ×#G®ç^n$CœµôpEÇXà,#Lò.I*×f`é´ÐÇ ô±‰:i¦ÈFH2É œåUz¹²üÈR@ÁO³‹^šÙH+qVr™ffXä £Lsž+ïK“(T¸n†¤…q$ËEÊäæíZaâ÷¹â;ØÊFÖ²‚nšqÉ1ÉeÎq†ŽÿšÖ|`#-Äè§‹@’QòŒsž,§‰7ªñ¿$=ÒÉz:¤•VR”XÁEâÌ0I‘qÓNöÚÜ(?rÒÌ;è ÅM(º™"É. set(OLIVE_SOURCES ${OLIVE_SOURCES} ui/icons/icons.h ui/icons/icons.cpp PARENT_SCOPE ) olive-continuous/app/ui/icons/icons.cpp000066400000000000000000000072751370472574300205560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "icons.h" OLIVE_NAMESPACE_ENTER /// Works in conjunction with `genicons.sh` to generate and utilize icons of specific sizes const int ICON_SIZE_COUNT = 4; const int ICON_SIZES[] = { 16, 32, 64, 128 }; /// Internal icon library for use throughout Olive without having to regenerate constantly QIcon icon::GoToStart; QIcon icon::PrevFrame; QIcon icon::Play; QIcon icon::Pause; QIcon icon::NextFrame; QIcon icon::GoToEnd; QIcon icon::New; QIcon icon::Open; QIcon icon::Save; QIcon icon::Undo; QIcon icon::Redo; QIcon icon::TreeView; QIcon icon::ListView; QIcon icon::IconView; QIcon icon::ToolPointer; QIcon icon::ToolEdit; QIcon icon::ToolRipple; QIcon icon::ToolRolling; QIcon icon::ToolRazor; QIcon icon::ToolSlip; QIcon icon::ToolSlide; QIcon icon::ToolHand; QIcon icon::ToolTransition; QIcon icon::Folder; QIcon icon::Sequence; QIcon icon::Video; QIcon icon::Audio; QIcon icon::Image; QIcon icon::TriUp; QIcon icon::TriLeft; QIcon icon::TriDown; QIcon icon::TriRight; QIcon icon::Snapping; QIcon icon::ZoomIn; QIcon icon::ZoomOut; QIcon icon::Record; QIcon icon::Add; QIcon icon::Error; QIcon icon::DirUp; QIcon icon::Clock; QIcon icon::Diamond; void icon::LoadAll(const QString& theme) { GoToStart = Create(theme, "prev"); PrevFrame = Create(theme, "rew"); Play = Create(theme, "play"); Pause = Create(theme, "pause"); NextFrame = Create(theme, "ff"); GoToEnd = Create(theme, "next"); New = Create(theme, "new"); Open = Create(theme, "open"); Save = Create(theme, "save"); Undo = Create(theme, "undo"); Redo = Create(theme, "redo"); TreeView = Create(theme, "treeview"); ListView = Create(theme, "listview"); IconView = Create(theme, "iconview"); ToolPointer = Create(theme, "arrow"); ToolEdit = Create(theme, "beam"); ToolRipple = Create(theme, "ripple"); ToolRolling = Create(theme, "rolling"); ToolRazor = Create(theme, "razor"); ToolSlip = Create(theme, "slip"); ToolSlide = Create(theme, "slide"); ToolHand = Create(theme, "hand"); ToolTransition = Create(theme, "transition-tool"); Folder = Create(theme, "folder"); Sequence = Create(theme, "sequence"); Video = Create(theme, "videosource"); Audio = Create(theme, "audiosource"); Image = Create(theme, "imagesource"); TriUp = Create(theme, "tri-up"); TriLeft = Create(theme, "tri-left"); TriDown = Create(theme, "tri-down"); TriRight = Create(theme, "tri-right"); Snapping = Create(theme, "magnet"); ZoomIn = Create(theme, "zoomin"); ZoomOut = Create(theme, "zoomout"); Record = Create(theme, "record"); Add = Create(theme, "add-button"); Error = Create(theme, "error"); DirUp = Create(theme, "dirup"); Clock = Create(theme, "clock"); Diamond = Create(theme, "diamond"); } QIcon icon::Create(const QString& theme, const QString &name) { QIcon icon; for (int i=0;i. ***/ #ifndef ICONS_H #define ICONS_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER namespace icon { // Playback Icons extern QIcon GoToStart; extern QIcon PrevFrame; extern QIcon Play; extern QIcon Pause; extern QIcon NextFrame; extern QIcon GoToEnd; // Project Management Toolbar Icons extern QIcon New; extern QIcon Open; extern QIcon Save; extern QIcon Undo; extern QIcon Redo; extern QIcon TreeView; extern QIcon ListView; extern QIcon IconView; // Tool Icons extern QIcon ToolPointer; extern QIcon ToolEdit; extern QIcon ToolRipple; extern QIcon ToolRolling; extern QIcon ToolRazor; extern QIcon ToolSlip; extern QIcon ToolSlide; extern QIcon ToolHand; extern QIcon ToolTransition; // Project Icons extern QIcon Folder; extern QIcon Sequence; extern QIcon Video; extern QIcon Audio; extern QIcon Image; // Triangle Arrows extern QIcon TriUp; extern QIcon TriLeft; extern QIcon TriDown; extern QIcon TriRight; // Miscellaneous Icons extern QIcon Snapping; extern QIcon ZoomIn; extern QIcon ZoomOut; extern QIcon Record; extern QIcon Add; extern QIcon Error; extern QIcon DirUp; extern QIcon Clock; extern QIcon Diamond; /** * @brief Create an icon object loaded from file * * Using `name`, this function will load icon files to create an icon object that can be used throughout the * application. * * Olive's icons are stored in a very specific format. They are all sourced from SVGs, but stored as PNGs of various * sizes. See `app/ui/icons/genicons.sh`, as this script not only generates the multiple sizes but also the QRC file * used to compile the icons into the executable. * * This function is heavily tied into `genicons.sh` and will load all the different sized images (using the same * filename formatting and QRC resource directory) that `genicons.sh` generates into one QIcon file. If you change * either this function or `genicons.sh`, you will very likely have to change the other too. * * There is not much reason to call this outside of LoadAll() (which stores icons globally in memory so they don't * have to be reloaded each time a new object needs an icon). * * @param theme * * Name of the theme (used in the URL as the folder to load PNGs from) * * @param name * * Name of the icon (will correspond to the original SVG's filename with no path or extension) * * @return * * A QIcon object containing the various icon sizes loaded from resource */ QIcon Create(const QString &theme, const QString& name); /** * @brief Methodically load all Olive icons into global variables that can be accessed throughout the application * * It's recommended to load any UI icons here so they're ready at startup and don't need to be re-loaded upon each * use. */ void LoadAll(const QString &theme); } OLIVE_NAMESPACE_EXIT #endif // ICONS_H olive-continuous/app/ui/style/000077500000000000000000000000001370472574300167515ustar00rootroot00000000000000olive-continuous/app/ui/style/CMakeLists.txt000066400000000000000000000016441370472574300215160ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_RESOURCES ${OLIVE_RESOURCES} ui/style/olive-light/olive-light.qrc ui/style/olive-dark/olive-dark.qrc PARENT_SCOPE ) set(OLIVE_SOURCES ${OLIVE_SOURCES} ui/style/style.h ui/style/style.cpp PARENT_SCOPE ) olive-continuous/app/ui/style/HOWTO.md000066400000000000000000000013551370472574300201770ustar00rootroot00000000000000# How to create an Olive style Olive supports customization of its interface through CSS (Qt CSS) and icon replacements. To create a style, you'll need to create a CSS file called `style.css` and SVG icons. Feel free to duplicate an existing theme for reference. To save performance, Olive doesn't actually use the SVGs directly and will need them to be converted to multiple-size PNGs. You don't need to worry about this step though, `generate-style.sh` will do this for you automatically. You'll need to re-run this script any time you change an SVG to update the PNG. For internal use, `generate-style.sh` will also create a QRC so the style can be compiled into Olive. You'll need to manually add the QRC to `ui/style/CMakeLists.txt` though.olive-continuous/app/ui/style/generate-style.sh000077500000000000000000000037671370472574300222550ustar00rootroot00000000000000#!/bin/sh # Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . # genicons.sh # # A simple script that uses Inkscape to generate multiple PNG sizes from SVGs. # It also generates a Qt resource file including all of them for usage in # Olive. # # While Qt (and therefore Olive) can load SVG files into icons during runtime, # this is slow and lags startup. This script is intended to mitigate that, and # while it adds an extra step if an SVG is modified, it immensely benefits # the end user. OUTPUT_SIZES=( 16 32 64 128 ) if [ $# -lt 1 ] then echo "Usage: $0 icon-pack-name [options]" echo echo "Example: $0 olive-dark" echo echo "Options:" echo " -n Only generate QRC file" echo exit 1 fi PACKNAME=$1 SVGDIR=$1/svg PNGDIR=$1/png QRCFILE=$1/$1.qrc mkdir -p $PNGDIR ONLYQRC=0 if [ "$2" == "-n" ] then ONLYQRC=1 fi truncate -s 0 $QRCFILE echo "" >> $QRCFILE echo " " >> $QRCFILE echo " style.css" >> $QRCFILE OutputPng() { echo Creating $2... echo " png/$(basename $2)" >> $QRCFILE if [ $ONLYQRC -eq 0 ] then inkscape -z -e $(pwd)/$2 -w $s -h $s $1 fi } for f in $SVGDIR/*.svg do FNBASE=$(basename -s .svg $f) for s in "${OUTPUT_SIZES[@]}" do OutputPng $f $PNGDIR/$FNBASE.$s.png done done echo " " >> $QRCFILE echo "" >> $QRCFILE olive-continuous/app/ui/style/olive-dark/000077500000000000000000000000001370472574300210065ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-dark/olive-dark.qrc000066400000000000000000000162671370472574300235660ustar00rootroot00000000000000 palette.ini style.css png/add-button.16.png png/add-button.32.png png/add-button.64.png png/add-button.128.png png/add-effect.16.png png/add-effect.32.png png/add-effect.64.png png/add-effect.128.png png/add-transition.16.png png/add-transition.32.png png/add-transition.64.png png/add-transition.128.png png/align-center.16.png png/align-center.32.png png/align-center.64.png png/align-center.128.png png/align-left.16.png png/align-left.32.png png/align-left.64.png png/align-left.128.png png/align-right.16.png png/align-right.32.png png/align-right.64.png png/align-right.128.png png/arrow.16.png png/arrow.32.png png/arrow.64.png png/arrow.128.png png/audiosource.16.png png/audiosource.32.png png/audiosource.64.png png/audiosource.128.png png/beam.16.png png/beam.32.png png/beam.64.png png/beam.128.png png/box.16.png png/box.32.png png/box.64.png png/box.128.png png/clock.16.png png/clock.32.png png/clock.64.png png/clock.128.png png/diamond.16.png png/diamond.32.png png/diamond.64.png png/diamond.128.png png/dirup.16.png png/dirup.32.png png/dirup.64.png png/dirup.128.png png/error.16.png png/error.32.png png/error.64.png png/error.128.png png/ff.16.png png/ff.32.png png/ff.64.png png/ff.128.png png/folder.16.png png/folder.32.png png/folder.64.png png/folder.128.png png/hand.16.png png/hand.32.png png/hand.64.png png/hand.128.png png/iconview.16.png png/iconview.32.png png/iconview.64.png png/iconview.128.png png/imagesource.16.png png/imagesource.32.png png/imagesource.64.png png/imagesource.128.png png/italic.16.png png/italic.32.png png/italic.64.png png/italic.128.png png/justify-center.16.png png/justify-center.32.png png/justify-center.64.png png/justify-center.128.png png/listview.16.png png/listview.32.png png/listview.64.png png/listview.128.png png/magnet.16.png png/magnet.32.png png/magnet.64.png png/magnet.128.png png/new.16.png png/new.32.png png/new.64.png png/new.128.png png/next.16.png png/next.32.png png/next.64.png png/next.128.png png/open.16.png png/open.32.png png/open.64.png png/open.128.png png/pause.16.png png/pause.32.png png/pause.64.png png/pause.128.png png/play.16.png png/play.32.png png/play.64.png png/play.128.png png/prev.16.png png/prev.32.png png/prev.64.png png/prev.128.png png/razor.16.png png/razor.32.png png/razor.64.png png/razor.128.png png/record.16.png png/record.32.png png/record.64.png png/record.128.png png/redo.16.png png/redo.32.png png/redo.64.png png/redo.128.png png/rew.16.png png/rew.32.png png/rew.64.png png/rew.128.png png/ripple.16.png png/ripple.32.png png/ripple.64.png png/ripple.128.png png/rolling.16.png png/rolling.32.png png/rolling.64.png png/rolling.128.png png/save.16.png png/save.32.png png/save.64.png png/save.128.png png/sequence.16.png png/sequence.32.png png/sequence.64.png png/sequence.128.png png/slide.16.png png/slide.32.png png/slide.64.png png/slide.128.png png/slip.16.png png/slip.32.png png/slip.64.png png/slip.128.png png/transition-tool.16.png png/transition-tool.32.png png/transition-tool.64.png png/transition-tool.128.png png/treeview.16.png png/treeview.32.png png/treeview.64.png png/treeview.128.png png/tri-down.16.png png/tri-down.32.png png/tri-down.64.png png/tri-down.128.png png/tri-left.16.png png/tri-left.32.png png/tri-left.64.png png/tri-left.128.png png/tri-right.16.png png/tri-right.32.png png/tri-right.64.png png/tri-right.128.png png/tri-up.16.png png/tri-up.32.png png/tri-up.64.png png/tri-up.128.png png/underline.16.png png/underline.32.png png/underline.64.png png/underline.128.png png/undo.16.png png/undo.32.png png/undo.64.png png/undo.128.png png/videosource.16.png png/videosource.32.png png/videosource.64.png png/videosource.128.png png/zoomin.16.png png/zoomin.32.png png/zoomin.64.png png/zoomin.128.png png/zoomout.16.png png/zoomout.32.png png/zoomout.64.png png/zoomout.128.png olive-continuous/app/ui/style/olive-dark/palette.ini000066400000000000000000000004301370472574300231420ustar00rootroot00000000000000[All] AlternateBase=#353535 Base=#191919 BrightText=#FF0000 Button=#353535 ButtonText=#FFFFFF Highlight=#2A82DA HighlightedText=#FFFFFF Link=#E0B040 Text=#FFFFFF ToolTipBase=#191919 ToolTipText=#FFFFFF Window=#353535 WindowText=#FFFFFF [Disabled] ButtonText=#808080 Text=#A0A0A0 olive-continuous/app/ui/style/olive-dark/png/000077500000000000000000000000001370472574300215725ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-dark/png/add-button.128.png000066400000000000000000000026561370472574300246630ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÌIDATxœíÝOˆVUÇñM²[%Q+AÛ”…“ ¹i?0‹„ Z ¹ kQFiÔªÚECÛ¶MJEÙJkÝ¿M9‰.(§§Å{‡lÈœsî9÷Þ÷<¿ÏVÎ3¯<ßyqîÜ """"""""""Ò8ûŒÅÝw»€uàš™ý1òKE˜ÜÝ€ƒÀQ`¸›ÿýWÏ3»0ôëKˆÜý!à$°o‹G.¯›Ù¥z¯jšÀÝ/Û®g€÷ÌÌK¿®©h:w?,ö³lf/—x=S”úY17Üýú/`ÉÝŸ.0g’š|p÷í…F®O™Ù÷…æMF«ï'(·|ºYÏœ7Íàî÷W}ÄÝï«0wTÍ©4×*ÎM‹[ÝýÇšóÍloÍùCÓe]Á)€à@p 8œN§‚SÁ)€à@p 8œN§‚SÁ)€à@p 0w?®‚r÷〈hcù ¹qù BÙ¼|Paü×òA„p³åƒhÞÿ-Ú `­âìß+Î.îVˇ6¸:§³‹ÚÊò¡ÍV+ξ\qv1[]>´À—s:»ˆ”åC›œ§Îíl½›=Y©Ë‡èn›RcQ+%ïÌQZÎò¡Á:gëç]Þ*8¯¨ÜåC£˜ÙwÀkGž*ù¸Ö’ú, ÀÌ> Ì} —ÍìÃsŠë»|hð&Q›¹û1à$°=õ(ðŽ™½]üEPbù wßÏìY‡¶xä"p:÷ö«µ•Z> `ƒ»?ÂìÑj‡€=›þø2ððIÎ]·‡Rrù,€¹ûþyÀÒ•Ô'mŒ¡ôò!pó¦ÆòAÌ…ZË0y5— `Òj/Àd ±|P“4ÔòALÎË0)C/ÀdŒ±|P“0ÖòAŒnÌåü ¹ÏH ‚•lIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-button.16.png000066400000000000000000000006341370472574300245710ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ºIDAT8Å“± 1 EŸ;Ð J€Ž@ˆ‚îÖ`„kÀˆ:–¸O‚…HÄq–,9ùη¿“@G³ )Ð;3kZ1KZIºD_æòBcèâÑ/_Yg‚>¤-€Ã&>–´vë;°7³¦7*`S(4‹î­lŸÔ²ódIÂ;lÊKÆ 8:ì ŠoCRíÞAËûï5JªK7_?²Ò$UÑÖæ“ý¥¶}å`-\Ž\Jh}IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-button.32.png000066400000000000000000000007761370472574300245760ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…핽mÂP…¿ )\QÁ™ s$R`*:"QQ%²@‰5`&0%ÊIaYþÓó³± |$÷غç³ýÞ}Ы†$ êöðj )´v’ö’Þ%uaª¼I:¤®…O/ßOøœã½´ 0vônИz€ sKñ4›ís¯mU¢#°6fv.XÓ†ƒÓú4³U@’;`tc€ðdf‚nÖÀo²¸ÄD?-|ÿ¿=ÀCêæ¸-ÂIÃÁ!Ñ"üHš–ÿl¹$ò|3{¬Ú«ó9ÐÜ7€¤Yg’f€7À1Ç «†ƒÿ/Ø:z¥á„®ÚCà5®¿HM8—p𜄉†×s¤rxmW…·PðÈGr ÂîÛIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-button.64.png000066400000000000000000000014461370472574300245760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(DIDATxœí›MVAFïsD{„ (Èjðl@`²"u V£‚;ÀÌžƒj9˜êN§»Þ#éºÃt%ý}÷ä§ó*L&“Éø ª…ª.yfëªê 0v€—åÍWÀ ðYD®-ó˜ PÕMà °Y2Edh•ÉL€ª>~ë5K/€w"r›<ðÌâ$%ûÔ—x ¼OåKÛ‰Ö¶ÂRÀFƒµo’¥x„¥€"ÑÚVX x’d޼ɼx“xð& ðàMàÀ›,À;€7µ¡r’³¼% +̾©ÍÈ-0N¯u“¥Jªº|^uÏ– `P5cŒ PÕeà;°Ö}.SFÀŽˆüt°ê=àó_Âò0v°JÀn÷YÜØ‹˜(@U â³ûyd-¶{hÂ0OЉDäøcœ%%£²ÓT½œ$ ãA´KþŒÝ«Ü¥= \LÌ+Cà V¦».{uÛ„›y¸þ œßZ] w‰ªþj²^D¶Re§÷ß³ïÞd޼ɼx“xð¦×Tõ¨·Tõè§€ûòÐ×Àxy°Ðä·¿7)<.¶Î­ŠIåÁVÀYƒµ§]ž8Vl"ðƒ°ÁZÅ0ÃëäçòUåÁðP†”1.VåÁç/3/{u{aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(]IDATxœíÝËEÀáß¹ƒ&Ê#Æq‡¼VHb‚È$Æg¢H| ºþÜŒn4!. k4A #à… +g„°sň¸3(q'¯‹®™!À½]ÝUý¨éó%lîíºu¸}¦owêj0ÆcâSÕ'TuQÓq˜þ$öªê‹À0 ,t/ß~ÆEd"vŸ¦¼h  ªK€}ÀK9›žöˆÈµX}›ò¢$€;Ì ¬ñl2l‘1ú7åõ"}Îçøï|€µÀÞH}›Á  ª€7J4Ý¢ªëCû7abÞ+ÙN€w"ôoÄH€m7Eè߈‘KÚ.п #k¨­‰ ÖU€I”%@ÇYtœ%@ÇYtœ%@ÇYtÜÕ@U}xxXFó×ê·€«Àyà˜ˆüêÓHU÷¯UX"n“ÀQ¹t  ª ɪzoÖ^q§±¼R²Käãõ„”Œià°WDî€KU]ìÞXÛ\l…L£y“JTõ`e=!%åð¡ˆÜ™9ØG:;²X¿ðØîǪIÔ&`  §ªÃÀËÍÆSÊ«.öA.ÔIšvªêª°³éHìÈyª–(Ò4Œô€ÍMG`à@DþîÔKŠ6÷˜›º¢En6ò 6û¸¿óa HsÞ~ïÃ<²°GvÓFª®yÜ_°¸–HÕR¾Sg`쪺XPS,Iê‘ ¥j<çýuµD‘°ž»WïlÓ”ð“ˆLæló\-‘$læ$pi]3Oyl÷zÕ¤®àN¤¶§š '—'Éî+¼>pÃìŽ%«äxX9x=såàå´£ü7Y9øxrðWÀ+U6_#«êå Dž ¡ËB¿ÿù0dXtœ%@ÇÙ(YÍTu ÙJ/O»—ûÎÙ«šÖDU>Féä}`ΞÇçÚI`Û¹xŸÁßùðpPU©#6K€z|B6®âkvÎ^Õb$À­€¶7#ôßjî7?oêÚÃìTÕU±ã¹_Œ¸ÚPÛTŒPî{rm+#δ=¡ÿ¶ ™sYù|Í p¬d;¾‹ÐÛ=ÐvE´(úNWœ9]¢é)ßÂNâòæ,VÕÖK¬«€1ŠÍ'˜";3î‚¿Ú^‰EQÀݨ9 œñØü °£Cë‡Ì¹¬|¾fËÅ“]ö 3Ï ¸NöŸ9â1k^QÕÕd“X† 6¶ˆÈÀ‘¾Ð‘Àèµ7Çpf—GDþÝO*Dä’ª!á+âpÞÎÁnš¨Öýš¬äcØ%"w=>Ûjmç ;»€Cd‡ö~¦oðÜùQb«£3Ç ïŽ òÜ[ž +ú‹®Æ†4nBÛêéMëLTUOO]ã窺ß-ÈT´ÝUýÒsÛÖÖÓSsFÐdkò\¦Üâ ÷n·”ì¹BÉ–o[ ~3‚Tõ3НdrHD>-Ø&9ÿ à.0sý¿„>cy à~óORüh5 ¼%"¿l—”ÆX<éþ… 8µºžžºÆZ]OO] ÐêzzêRH€V×ÓS—B´ºžžº ÕõôÔ¥G\@égÚµ5´>ÜØ~™…¬j©§§®õ àì~)°ý$Ù³LŽ$ ÍõôÔ%wwpìzzêÚ\ ð  #·‡W¥Íµ“[!¤ 77aØ ¬v/_Nã"r»©ØÊ°Ÿ€Tup€þk_v‹Hmw=ÛO@MÜ_þ {ï€Û6 –þFñ[}|Ù²»I°ð·µÀ¶Û*‹"2KE–kY¿I;XT㿦ðe à¯ÈäÒdF#-ü¨hÛFYø'»ÎÏs‘ügµ†%€'7·›ÁI03”Ìmi6\€ˆ\UÕ·ÉV@ÙÆÜÙþoÀ÷dCÁÉì|°¡àäÙP° b Ðq–g Ðq–×øU€i–:Πã,:Πã,:Πã,:.FtåÉóÑõ ²†iÖ• `ëð¤k"F”]ÃÇ4k8ã¹e×ð1Í:,"—£w…IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-effect.16.png000066400000000000000000000006571370472574300245170ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÍIDAT8µ’MA„¿'Câ 6¶"±?Gv–³q!Gà DàÂBÙ´èôüe&Q›×ï§êUº$% © IIç²¼HÒhu'7`L øW“tšAãô€CÀËœƒ»âØ'`žCŽì›Iº2³vCÒx›ÙLÒ òú @–ßáŒ/0rqãoò‡Ã æ'ün=±) QZ1Ü$iêê«<•pà>R*Òzþ3žFIO_ tK lKÎÿlTH|ÂIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-effect.32.png000066400000000000000000000010751370472574300245100ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ([IDATX…í–=N1…¿‰( F ÐsˆHÊ\ˆ( ÐrA¨©H¡¤N¿I”;<Š8’7òJÞg)ò$k=#ç­güvá¿AÒ½¤ISI·©óY€À7ÐuæÂÌ.Rè|]o~’2yÂ$Ýäß<„%02³I}àµfî904ISà82hef=IGÀ/*‰¬j T3ñgàXD,^¸µ=ê¿=„6‘4Ë-0;o"QÑþÉn¤I_’&®iƒXzó˜Òá‰µŽœÏeŒ€•£Ú…¤¾;þOIWžæ¢ÀC7®=TM#ˆåDßIÖõÈÌì²*ßný[P†Àµ~gnÞ"I`à̱™åz{ÿƒ8žQ/žýÔz4yc÷ð¾s®æQÇž‹ÛvÕ)!ZïùóÉ6‚“<9 Ú{TÆ *¹ô©HŠvIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-effect.64.png000066400000000000000000000017771370472574300245260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíš¿kQÇ?s1…? ¶W‰bcj‰XX GÀˆV‚´H+ £ °›¨E A;›HP;5*A+-#æb¿»ÏÍeïíÝ{»{Þ~`9òÞÞ̼¹·3ófîH‘4R´¹#騤’>JZ“ôPÒ‰¢íòu»AÒà)p 1µ̘ÙZÃò¢æpÏ<»O<6ëלüqqÀ锹S¾ ) ìO™;èË¢pqÀM倢 (ˆsú,QPK{æ]ø¼î˜Ù‡ö IKÀÉ>å÷KXÌlÝ$èáI¶€I3ûÒ4Üò¬§W~0‡ÿÅCT'ÜHŒ½  §WÆ€9“´„ªï·q3Û†è,¼ ¨/+›ÃÕ»-W[¿~Lòüú@”o,ß4ÙJW:×Ìì=0 ¼À#š±¬i3ûš˜›ñ ß+.Çáϩ̎û3Ç?Ýìö 8˜T—´(ém|Ý—t¬Yû|Iu¢Õá¶á³À„¤†™}Ë"Ïe¤Æfež˜çßÅ·#ªj3áâ€×=Î…âLsqqÀm:ï‚&°Ua`”õ ]w}'—Dµý6°BtÒû”U¡VSæV² ëZ´Óz)’(os%ŽöOˆžùv6€†™}OÜï¯0³í"Û°4€çÀf|=£Ãâäù5/"NUóü J;˜úºØ’^É:X[9¶LÌìbâþNyâLÖ<Ý/>Ð. µýw޴ɳ€¤EàÜ➛ٕn:}ÒÍY+A—³¼×<š¼Ï™óthB8ÀkžM,¼$DݧRáݾóthªŽP^†dAÒ¨¤ë’Vã뚤ѺÊÚ¹ \jûûrüéýôYÊœï06BQYЉß!„–ÕËŽc}SÖp7þl= ËÀ½Šª4˜—!eeèÐ÷#0è ý¨P´Eãâ€"ÞÿåÅO¤ux—,°×›˜Agƒø%SéÐátJÝ¡ª¨¨¨¨¨¨¨¨È‹?ÓW Ú ´IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-transition.128.png000066400000000000000000000035601370472574300255350ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ŽIDATxœíÝÝ‹UÀñïó[»ð¥°‚’ô®,Á +z35©¨¤º°4% ’þC»BD-–èJ(é´Õèb•¨ô*eÅ«ºj}éNÚ¤;_a×õébfÛ4ýÍü朙3gæù\îoæÌópöàI‡s—z¸¾qà#îq8wž‡ë>`f s¾ª)K€–³h9K€–³h9K€–³h¹ÿͪêÃÀkÀSÀ½„¯Õ¯ç€ãÀ~ù-ÏIªºx®ÌÀ"q8 †DäÔü7Tu6ɬÞK•†×»CÀÖ¬©ä4‘TR4&½Àv™€4Tõöô‡EábëÉ(°>kQ‰ªþÜ_MHQÞ‘‰©1ÀñÜ|Hbý$Çq?•H¤–[:ªÚ¬ O!Ϧ±ws¢’Hâ´AUv€ ¡#qðFÆï£•D§>`mX:]{ù˜¨(–-ë0½t;FsÒÕÈÝØêã[›ß„Ašñ{_%QÄiv‡dÓF¬.t+UµÈê!Z­ļS'+ö»)a÷S“tHÅj_Æï‹+‰"bt¯Þ‘Ðð³ˆË8ÆVg˜n&®šyؒ㸘KÜJtÒÔ:à`Øp2)0L²¯ðb×UŸ ·íj­t³éà%LOÏ£ÓÁ‘Lèa:xXQf`Màui¤ ‚®£ª34ûæ«Edص¡‚© U’mçM]0N2u¿GD®ùh°1 ÞüWBÇR’ÓÀ{"ò»ÏF‘ér¶]À ¡c)_»DdÜwãÑ'€ª®" ÍK Æ€÷Ed¤¬ D™ªz°xx4l4¥¶‰Èù2/RûH_@5 ¸xä…Ë;CÆU¢ó$7Þy„Ÿ‡¸Bñ‡E—»ý¨ª³€_ ¶£’.¬ª úxp®ÄsÛò–Ñq’=oWyóÁOw87kp³À¡íXœֈȠ¯Ú¾>`Áóø.ãï‰kä0¼ê»¶ï…s¤“3‡ œz0ÇÄŽËÈêl xKDv”QÛ÷Â×\ÀVz[O0 |Ð퀴Ô[îTM “<Çwù×é—H7j®ç8ü0ðFŽ÷¯¤Y¥Þy`“ˆl*»¶ïE¯‹ï'Ù±ÓÏô(þ"Éν9–qMµ³xÌw|”VÞ9OÇû äf¦6môšñéãÝÏK ªZÞgïnTë("}òwˆøŸíŸ$™½;YæE\ V‚Ó)݉ûæ_ö¡GøyÔ&Ò›¿ x>t,Æ€-uáçQ‹%aé2®àÍб8¨Uy—Wð ]À¹“x—qU:{ç›/†ìN_ÈÔëy§K·‡ˆ÷æ{[œŠÏeἓç0š¾œaê˜>’š‹I¶k-#îM¥—wy/»p•¤{ìs]¯S#•”wyÕ¹ œÜUbûU+uqf(Á‘ˆ®¼Ë«e`Íý¼ÜÄ›ÖtsøHD¾H™,n®òÅ™¡X\oø ø"tyWK€i¥ì½«;&åÝ—^œJÛ{€Æ–wyµ¹hty—W{€V”wyµ-ZSÞåÕ–h]y—W •å]^M¶º¼Ë«©=@ëË»¼šØXy׃&õVÞД°ò® ØÀÊ;G1'€•wÄ8´òΣØz+ï<‹©°ò®1ôVÞ•¨î `å]ÉêšVÞU¤Ž `å]…ê4´ò.€ºôVÞR‡ÀÊ»€‚7ЄU‡Àd Ðr–-g Ðr–-g Ðr–-ç#²¾üaê뢰©Úxýé#ŽzhÄqÔG “Ú1Õš†||7ð°×=S±oD䌗o¥ßøžöÑž)Ý1`£ˆ\õõÝÀ `#ð5öï Î&IÝl‘«PÎwkI¾ °˜åû¦'—³$ƒõ!±é{cŒ1ÆcŒ1ÆcŒ1ÆcŒ1ÆcŒ1¦þE—Äò]îÿIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-transition.16.png000066400000000000000000000007211370472574300254450ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ïIDAT8µÐ±JQFáïJŒø ö6 vb´,|±ÓÎV´·°‚…`aá#¬„À5}z-Ä›Ø,k–þÍÀÌœs‡KNDìEDÇ_ƒˆ(åZ±ƒ5,gÑ1ÞðŒÃþ5ED«•Á'6ÑoŒ—pŠn©ÙÅ ¶æ€/¹¶Ó´Öq}¬TÀ îp…Ê‚N´pSóêg)¥^ÞÊËÓìâ5ðÎSJïÕAù‚a øË”Ò}uPwA5½|òhÎN­`Œkܦ”&óàß¹ED?óÚÄl¾Ê‚ml,(xZpÿòÁ§UžPÏØæIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-transition.32.png000066400000000000000000000012011370472574300254350ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ŸIDATX…í–=KA†Ÿ7ˆ`¡±·l´ µÿЍ…„ôA¬E‚ÂÂÂÊÖ í/ ¢]ŠŒE6èï#-|áànovŸÙ™¹¹…¿&3[5³[3«˜ÙrÚ_rÀ‹»rnl>üØ”tòB’Ëy ˜ nE  ©áY¯«Æ¾¤À5™ 0 ÌÛà°+©Òþç¯ ‚.iuÊ×^F?F †Þ¼¤ó8““:P¦ò îqhGÀq¯ OË'`KÒCp[Q~Fœý‚CøÀޤ›~Û K`= 8ô·ÄÒ¯Ÿ }TÈ÷ÉöäDàXÿú×ïê{[²¶_IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/add-transition.64.png000066400000000000000000000021201370472574300254430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(nIDATxœíš½¯TEÆÏ^•@(T:b_´v„+$*ü ,”`…Fʇ!„ ‚6¢…‰v4˜{ÑÄV¼bVkÉÇÝkr“½Å9kÈrÙ3gÏÌ™ίœ™÷wç¼Ï;st„c{Îö\n?ZÇö6Ûmÿi{Éö7¶wæö+ª`ûà2ðôX× pPÒR ÇÚ¢0æC\„kÀW’þ¸¿Ãö·À+ çoÊXNJº)Û»€K4_ø8+À>I·F ¶ßND¶3-w€ùpŒø‹‡¢Nøx¬í×v¦e3pL¶—€TõýØ%iÅYø=¡½º,·×·ls{¤Ý– £¿äY`CB{µéŸS$¬Ø x0¼–ÀN#z’®€+Ä Ä œë€¤¿ÇúE˜?*!Çá¿&N í1dûMà\ _1¸ |œž4¨•$hû%àx¶J½’.W LÛ²½‡¢ÐÚ’ÒVÉ*ððޤ~È¢gdÛ›€­ÀÀ~àåØ6Âð~ݪ¬°þ ïlo~«ã@ | —´Z÷Ç!À/5úž¯ë@CúÀaIŸN³x À)Ö—Çpr¬mÒõYl~Þ’´Ød’Ê”ÏÔ>àgŠÚ~\¥8éݳ­r\jîïIzWÒí¦“UÖ÷3z)2VÞŽúög›:TÁ"ðAh†‡ê:¦– ¬·ðÒÈ‹ÀguæªÉ*p8/i-æÄe°¬ð¾¤8_§`*y ¥2å5Öw§Æ¾¤¡íç€W)jûT‰o ¸@qµ6U†¡îY`H¡»©´}Šg½Q†‡êP·ž#ýâ£È[(³t9qøDÒm•Ô–·Xä@2y %gnPÈÛõŒ>dy5fà"°?÷â¡ýÐŽJºÖ²Ý‡ÒæÉÛÌ,ÚÙYä-”ÔÈ&o¡¤ @vy %EfBÞB‰™gJÞB‰µfNÞB‰±fRÞBiünðQç‰ÿJ¬ @nr€AõG–{!XHîF>®†¨Àvà{ÒÝûçâ6凒‘t˜§ÐûåÔ^µÀ2ð#0/éŸÜÎtttttttttäâ?òJþû£q»TIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/align-center.128.png000066400000000000000000000005671370472574300251710ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<ôIDATxœíÝÁ ! Asý÷ìáCpg Á}F½÷^d}·7À]ˆ@œâ'€8Ä Nqˆ@œâ'€8€d0€´OãC¼•IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/align-center.64.png000066400000000000000000000004001370472574300250720ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<}IDATxœíÚ± „0A>ý÷l:€à¤[gb‚åEÆbÖZëØØYÔ PÔ PÔ PTæé¯ßÌÌí;n4@P3@P3@P™¯ïÿjû“ ꀚꀚꀊÿþòV¨j¨j¨*¿L5åHIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/align-left.128.png000066400000000000000000000005541370472574300246370ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<éIDATxœíÜÁ AÀÀþ{æÊ@ZÏ4?³»û#ë½·'€8Ä Nqˆ@œâ'€8Ä NqxÌøpkfær¾‹ 8Ä Nqˆ@œâ'€8Ä Nqˆ@œã?@œ‹ 8Ä Nqˆ@œâ'€8Ä Nqˆ@œã?À±™™Ëù.‚â'€8Ä Nqˆ@œâ'€8Ä Nqx̆®uIDATX…íÖ±@Aøþ{ÆüÈ!¹M $ÁÑI¢¢×\N@’|}l{›×[@àüüÔ[@€€ÀÏ㪘€IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/align-left.64.png000066400000000000000000000003741370472574300245560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<yIDATxœíÚÁ Ä0ÁÛË?çuz4BUC3/±xvwû×5Ô5Ô5Ô•¹ý03sòýó/AÔ5Ô5Ô•ëï§ž  ¨ ¨ ¨\ðÀ!Ô5Ô5Ô•¿[5»ÙìŠIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/align-right.128.png000066400000000000000000000005511370472574300250170ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<æIDATxœíܱ AAãþ{æË@º©€`C`vwdý¯à–â'€8Ä Nqˆ@œâ'€8Ä N™ëü'¸e#(Nqˆ@œâ'€8Ä Nqˆ@œâ'€ÇŒûü6Aqˆ@œâ'€8Ä Nqˆ@œâ'€8aËsBIT|dˆ pHYsN½N½sjhtEXtSoftwarewww.inkscape.org›î<MIDATxœíÝ}¨eeÇñßjÆæúŽM©•6ƒNi Ñ”•:%ZZd¢FPHa¡á?ùGÔ öÞEND02QŽÑ„F*¡XŒe%9 ”Ac•’ãä\™oìsòzæÜórï^{={Ÿõùgà¾<ÏzîþgßÙ{Ÿu%Àç€õc§z½ÀiÜ3$Ý\á4~*°çl^]SjÐ@~ ¬®+Îë0è ’ÞÙÐ|iBM@’VKú)°XÑ༩iCNƒîNŠ®35»,ôVU§„A󧞨HÒ)’~l ¬aæE@’VJÚ ìŽ®e&E ïÝ’~¼&ºYSJ$éU’~ |$ºYRR$éHIßnŽŒ.f”€¾+%íN‹.¤ëJ €$½^ÒƒÀ{¢ é²’ IÇIú!°8"º˜.*=’d’>&égÀK£‹éš6 ï|I»€ £ é’6@’N”t'ði mµ©?Ä•’nôcà„èbÚ®è»TÕÿÞ]H›µ9’´FÒ/€«£ i«¶@’æ$mí]=<*º˜¶éBú®”t°.º6éR$iƒ¤ßï.¤-ºI:VÒ-yõp2] €ôÜÕÃ{€—ES²® ï-ª®¾=ºRu=’ôIwäÕÃáfå²BÕÕÃÛ€ES’Y @ß%ªN çDRŠY €$*é^àÚèBJ0‹¤U’n¶GGiVÐ÷UïPšÙf³I:S3ÜÌ"P9FÒ÷g±™Eàù®VuCimt!MÉn¦šYd†›™f€Å™¤MªGïl3‹ Àxnf‘˜Lg›Yd&×Éf€éuª™E`i:ÓÌ"°thf‘X¾V7³ÈÔ£µÍ,2õie3‹ @½Z×Ì"à£5Í,2~ZÑÌ¢ØÂ:¢øf€fÛÌ"М~3‹¢GÏ4kNÕãèÅ4³ÈÄ(¦™E NÍ,2±Â›Ydâ…6³È”#¤™E ,7³È”§Ñf€r5ÒÌ"P6÷f€²”ô7Içoò˜`¥Ç iIþ!éaIXðïƒf¶ÏsÒ @ó†è]föTD1?ÃôïÍlohU2Ë÷„žVõŠþWhUÊLnØÞmf…VµL€á•´CÒCêl3{<¶$€áæ$]WÚùÚC^nµ¤k¢‹hB`qŸŽ‰.Â[`q/–tUtÞ2£}²ÍoýžD`´“%µ¾ Ä(€ñ6«¢‹ð’ïIŽ.ÂKWpHÕµw/ŸjÓ{þ§Ñ…Ì«êûÿQÇ9Ö¨z3Gç´=ÿ–t‘™ýÀÌn—ô€ã\×»rÚæüYÒF3Û¹àc_rœïtIïw?D[ð+UÿOß!i·ã¼×w­{xp«¤ Í쟃Ÿ03$}Ñqîu’Þç8~ãÚ€oHºÂÌžñ5·ªºëåú’[¾L«- 9 é3»ÖÌúÂÞç¿ìXË«%µ®`£€íÔg/pñ”ó¯þXc ƒ¢#»@é‹xTÒyfvÇ4ßdf%mö)I’´^UߟÖ+9»%cf»–øýÛ$ý¥Æzݘãø(5w©zåïYêfö¬|x¤©NM3ƒåýp5]qŽþºüSþ¢î¯£ÎH%íHúŒ™]efê°· |µŽ±q6 7th¦ßöãô·{UÀžº_ú ÜçQwSJØþCÇcp3›—ô5±{68Žß>L¾<¼²z怿{mÀÝÞkð¹üRÒ¹föˆ÷Df¶_ÒŽS¼ 8Ïqüvaü°˜k¸¦£Çw»š\O]"v€þ ýMNÚk´°ÅqŠwov¿=Ùž<Ûš¤®ã€ÇwŸD®o)šÚöJºÌ̶64ßPfö¤ªÈË%ø77°ì6D×Ô<Ḡìˆ^ã4¼w€åÞЩ™ýGÒ·§¸x­ãøåëíwÇF×2 °xÒqؽÆPÀ»(üáIà+Ž8¬^c8 Øç‚ïE¯1|Ý1€3¢×˜FNþë‚ïF¯1|Ó1hàfWZàT`Þ17E¯1lu À3ÀÚè5¦€Wà» x^xJu¾ã€y`MôÓÀéTw,½xÞ„Ju¶9àiþ.à8%<Z’/¨ê7äaNÒÇÆNunqÜö'F¯q¡Ü÷yUoRñp”¤9êüÈáÕ¿ ø y[y§€C5øÀ¥tàÄ3¸½†Qô:Òg1ý.p¨œ³£ëO5 z¬m{þ¬èšS€sÇøg€›3£kMN€»‡øùÞ_]_r\°àÀ?l^]WjpðY`ut-uû óp)Ï­ùIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/arrow.16.png000066400000000000000000000005421370472574300236600ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs Ø ØÇ ¹­tEXtSoftwarewww.inkscape.org›î<ßIDAT8¥“±NAEÏÅ(‰…D£-Ÿ@eGAke ¤Á‚Îo ´±Ð/0Ô|ñ4ZX[P“í,C²Y–̺Þd’Éyç½7/Aê½úHU©=·«gÿ¨ÎÕf™¸£~ X¨UÀD}UO¢¥äZÈëC½ýkYµ¥Ú© ¸¦êHMvæq‰À_àø ë ¨iYÀ¸K’$-:<Ô x û0Œ¦ÉLá]­©—ê:x+õ<èæH}ÎŒò)8-ð®Ô4~Šî”ií%SÅ  à&|®¾º7µ ’uÒër4—ðIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/arrow.32.png000066400000000000000000000010341370472574300236530ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs¯¯cæŽÃtEXtSoftwarewww.inkscape.org›î<™IDATX…ÅÖ=HA‡ñgã.!(ba!…AÄ"`eg§M‡…•mJÁ"il…4‚66‚í,D½(!$µ‚h"…wäbfÉyŽ;ÿf—Þïì¢~RGBc±ó çú+`_)ñOÔ ÿdY}˜ úU}~µò¶àfÆ€º:™ Ðl«‹jWlÈ_ lÁÍTÕµnÓÖLp½%㩃ÀŽº PÕ-µ7 ™·@MMj æRÊÀŠº¦>JhfØS_¦¼ÕJ*@ðE]R»SN€jã<ø„”"ºŽ€À÷æ1˲óÿ-Œ¨fY6ÝÉÂX[Péä%Ô àø¸žï;“ó9>V‡ã»ñËh?²ÀAë÷_ÊùOX»À¦ú80§üV‡b–Ôà}¢¾ÉéÂj Àºú®yõà—ú⮀§mΫätaùN€v£fê·œ.<+ 1“Ó…ÏEºÔŸÀ©Z. 1ÛRøLý¨öR¼(yývœWŸÜfí¹m¡GÜwIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/arrow.64.png000066400000000000000000000021031370472574300236560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYs'_'_†ºjtEXtSoftwarewww.inkscape.org›î<ÀIDATxœÝ›]¨¥SÇ3‡cŽ9ã£ÁˆFr1rcŠ22Ie¦¤N©É…c† òÍ ¡ÄÜ(ܹq1‘ˆÔ(ÔHC£ÐÓèø¸ÐH>2q™ ÓÏÅ»w¶“9g¯½×zßwŸßÍ®ÝZÏó¬ÿþ¯õ®÷}׆>Q7ª·ôÛ~É¡N[±C=±ézj§GÕ}êyM×”ƒãì·øX½!g1M0¨SÀËêSêx®‚Z˼)0ŸÝêê¦k„aÐËÀ~õªLñj#—§oª«9㶃E¦À|vª§4]s?”ú¥6Q]%.)?%­ºxW½«`Ž¡)=W'€';»Çå…s D]‹ÕMÀ{êù5åë›:Wë‹€}êt9¥îËÕ àÅ6훸^p'ð¶zVùÿC“–Ë©vW7XC£¬Þhr÷Ø´cÀCÀNõÔº“·A€.×QM‰KëLÚ&Îv×¹{l›'PíŸS'K'k£]6{Õ K&i³k÷ÕK%h»'/¨Ï¨Çç> t¹•ê†êÜœAGI€‹©Ö…ks5N^W·«cÃE º¡ÚìRÏ&Ш ÐåJª)qÙ F]€³wÔmƒt^ ,¶«¯ª+S:.º\¼¤®è·Ã²‚Å”ægàS`¶çsDü˜dø¿ˆˆC9‚·I€?=ü;ÈY`6"æJ&m“l‰ˆƒu&mÓ"8Nµ¹©•6 0£®©3aÛî«3a||”Ð~K/LJ ð°x0¡Ïp™r† ñ„ˆê³½ïÿÔú¶¦CW% ðHDÌDÄ_=ß?šc¸'oYCÒ§ލ›ˆ±7Á¿««J+§æ€k"âùÚ<žo¸{¸’2²ˆ¾T×ö#Ô .øÕÂï s8à`}D|¾XÈx,!öÕY‚æ9†^1ñè¼:¦~–à‚_Ô“Kk< LGÄá”Nq”4¬îHÉQ„ü­Þ>d¬1õ‹üdÂSž"tøMݘ)ÞL‚:àCÏl¨Ôuã«8d ¯ËkE½-Ñ÷6]sV:.ø*A€ïÍü‡­FŸtîžHèr&°µP9Í N¨ß&¸à;u"WþÆŸEÄÒ\°¸¹P9Í .WHpÁ×f:-Ò¸"âÒ\ð Õz°tP'­®õ ±GÝÔt­ÅP8ÆÀw©ë›®¯8ê”:×ôQõ5GàWYé¸`‡zAùþœm¨aÐõ7¢IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/audiosource.128.png000066400000000000000000000030431370472574300251330ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(AIDATxœíÝOˆUeÆñï“•dAaQBDÙŸEBPZ‹hÑ" ÍË"AË6B$.$7E.B‚0)…úC†a´‰ Ë‚E›B¬¢L‚Ь0Ó_‹s-µ™ézæ=ï{ç¼ÏÜyÏùÁùÎyÏ̼÷˜™™™™™™Y-Tz€ÚDÄÀà:àà °øØ*iOÎy@&q °¸8iœÿvxX/é`޹@1ØÌò%»€å9"¯DK$"®v0üŘ ¬íf¢c9€EÄBš[ú¹-^¾4".M<Ò8€DÄ´ˆX<Loy˜iÀ¢tSíä®OP›ˆ8x ¸6Áá®OpŒ 9€„ßâ=ÌJtÈóg\^‰ˆ[€m¤»ø§'<Ö˜|˜¤ˆ°jðoÊ}[í&!"Ξn*=K[ ¥ˆ¸Ø \\z–Éð3@ q#ðSüâƒï'd°Þ߬¦'_<`H1ØÜ\z–”À"âBšõ~véYRëÅm¬KqÍzß»‹`B± x8³ð(ñ0†ˆ˜<,(=K×Àq"â<šŸç_Yz–¼%"®^§’‹à±x8§ô,9U¿DÄ©À#dØ|1Šª`°YóiàêÒ³”RíshÖûj/>T@ḐYïg–ž¥´ª–€ˆ˜<¬,=˨¨&€Ä›5{£Š:جÙ½ˆˆ[I¿Y³7z{ðz?œ^gO’áS]ö"â2`1Í g§åžÁþ•-€Á\fâ÷Ç[fY\üçð·`#'×Wâ:|ñGRç Öü%]ŸÇÚÉqXœé<ÖBŽ 3/Ã9¬¥tþwk/G32œÃZòÚ\9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P9P¹ü–áÖR޾Ïpk)Gïg8‡µ”#€mÀ¡ ç±:@Òn`k×ç±vr}°Ø•é\v² é °œæ5y9!Ê}ˆ˜Móé¡óh>.Þ#7I—tzü.^JŸþ`D×ôò'’~¦Yr¶”žeÔõ2I‡$mþ(=ϨêmGHz“æ™ãÛÒ³Œ¢Þ és`ðaéYFMHú X†Ÿ ŽQMpÌsÁjà@éyFAU!é àn`_éYJ«2IŸóOKÏRRµHÚܼZz–Rª@ÒŸ’ÖÒüi»¿JÏ“[õ!éààÇÒ³ääŽ"écšç‚ÏJÏ’‹8ޤ½4ßxGéYrpct@Òšç‚^ï_p<¬~)=KWÀÿ´¸Ø]z–.8€!Hú¸x»ô,©9€!IúXl'p$…¤-ÀJà×Òó¤àZô.ÍsÁ—¥g™,Ð’¤¯…À;¥g™ 0 ’ö(½x>ÁáR…4®^¾5lTDÄBàQ`z›—· ¶´wÆw€IÚN³åì‡/¡ë‹¾d3MÀœ!_²X!©ó_EûÁ`óéRà%&þ=Âa`3p_Ž‹¾d—Óì8šKóùû½À{ÀvI_ÏÌÌÌÌÌÌÌzìoç #jqÐ3IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/audiosource.16.png000066400000000000000000000005631370472574300250530ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‘IDAT8Í‘± Â@ç‘%B:pä Q‘û¡ #°™6 ÑË€d,ûùw€Xé’;íÜž~%µT/j;ì‰æp6ãÙ*Áܧ)s4ºÀ>¶à v@ý-ÕPã²ÌS€lýà– sƒØCUòµQïêã]¹)Q·êu1à)Õ^=/Ìé åJÝW÷ìõIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/audiosource.32.png000066400000000000000000000007721370472574300250530ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…í×=/AÇñï £G%ñð*WèTÞ¥B¡ÕI´\¼o@ኯ‰N´D髸-67q³³»‘ì?Ùfgg~Ÿ}š…®j*uO}TGj¯ÉàyõT}*m£iÇ/d_.þDÓjíu¸6fé7—)¼Üί€€à„Ä“I¨‹À°›:F2@]®­*áQ€ºœËUCb"€`%[P›¿í=8ÙÂc•å5ì ÔxkpÖbêT«”QÊTìØîRúWˆ/à˜ñšà»q@0„0Æ%Èñ-ynP ^ Ä}+€ñ 7Mï9sþT¥_³¡ºÝ8àßÔ]TfF´µ>?IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/audiosource.64.png000066400000000000000000000015501370472574300250530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(†IDATxœí›Ï‹QÇ?_? E’PÔ”l”R²Ñl¬,eüHbi!”Å(²4ÅÃÞQdÁ_ MF,,l…’šF! _‹{Õ4¦;÷}ç½ç93ÏêÖ==Ï÷|î{ÎûÖ=/ …Â,ÃvŸík¶Gm¿´=l»¯N-5®×ØÞ \–Múê 0 é]•zóš ÖklËö à&ÿO`9p¦jÝ3 –ÛK€KÀ®i†î¨Z;{¶7ÐúÕ7u1|ª+£#Y/ÛÛ{t7ùZd+Àö!à°²—}²[¶})úe%Àö`Ø’ªg6KÀö6à '™˜°ÞW¥îºl/.¢2„ °½¸lÊAlonë"úO$ù`{p‡ & ¯ÛóSÀñT=»¡–ÛkA XÚh¢ÄTОü#`EóqÒSgdŽLê èoÙ]@ÒoICÀiàGª¾Ó‘ü6(é!pø˜º÷T„<Hz ìF"úO$ìAHÒp ¸•29+Ü>"sX8ÓZÙn‚t8|NÝ; ’Fií ¯RöÍF€¤OÀaà~ªžY ôSÒYàð«×ý²ðö¾pëeŸlH€7½ê‘µI€ýÀ“.†W­Ÿ½Iß“ÀàO‡¡Ï*×®*Š/MÓziê}òP©i¿6wÕö ÛÏÛŸ×Gç* ³¿j£ñ Ó–IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/beam.128.png000066400000000000000000000032571370472574300235240ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsääú[tEXtSoftwarewww.inkscape.org›î<,IDATxœíÝ[¨TeÆñÿë¡¶'4ŒÔP+£4“ÈTHS4%EDÖ}7Õ]¡Dvuc7]”ÑᦛR Oá!¥™‘à! Ë)Xííaëîéb­ÍävŽkÖìyß,–Ìþæ[ïÌ÷Ìr­o k ¸fy iðrÑÃ]@gõ%àÐü üœ0³î–Ú+Iý[±Àøt=¸\×cÝÓ›f¶¥q•þ߀<7ž,¬ây’~ö{Mfög]+ë…¤›€EÀ `:p/ÉWêãzÖUf@µ†³Ó [ÒNà às3;YÏI<<Ìú׳·$-WýuKZ+ifê›*éI—3¨sy=ÞÃZôË»€Œô–»$m–4¹Ò$Ý-i °x†¾½·ìU« §ÀI«% -ÕXÒ I«€ïùY—7<ì–t[o$v¯’Á·ªÃ଑TêÇ$C3ô¨¤ãuü‚c’–åýúÂUH,éiIû2øbßIzJ-²Gè“3JŽÎo–êèª=]­â¹_€]Àq3»RE?¹Ê=’FS®ò§Á$?â<œä*Þ`0¸ƒdÆ®ç€9$ïÁö´ÿZtGCÀá´ÿà/à<ɯ’;hf§kÜnß&iyvÛÅ.HšÛ£†yéc¶<Ï÷|] (8,1³m…Ìl+0ø#¯¢òâ-?3Ìl{ñÌl70Øßðªrä%—w™fv¢·FfÖÌ^.5¦´|yÀFà3{ÁÌ:K56³ f¶ ˜ lʺ¸¼µjþÖ÷›Ù3;\ifvÈÌ“áS’½HËi¥t[[Ìì3û¶ÖNÍ쀙= LHûÞ–n«%ôåË$l{Óe‹™ÉjcéñÁj`µ¤I¾54ƒäÀñ>ÊûÆqÓi†œ6=ÖtI&P:INÑÚ߀“ÀI3Ë哘í³tAR`\ºŒ'™YEòóA@[úïâÉ«S *9„«ûî+jØ }$#IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/beam.16.png000066400000000000000000000005001370472574300234240ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs<<ê.¨tEXtSoftwarewww.inkscape.org›î<½IDAT8½“Á Â@D߈÷=Y„‚Þb Úˆ6¢•­Àœ4âÉìÃñ° †dQÐ9 û‡·ËòG4d»Šö ì[` i^Ï«c`Ìâñ8Ie/ P–”wå†]I¶}ïš'QÏ` | °=2 ‹þ3Ù.üVñÕólïlïú2¿ûƒ¿R{¼ Wy¬%Ém¹¶2- eZÓ˜¹B™N)@EXá ï:ou4ëüçÂJÅK@QÐIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/beam.32.png000066400000000000000000000007551370472574300234360ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsyy8µˆtEXtSoftwarewww.inkscape.org›î<jIDATX…í—»JQ†¿Q ë¨x'XØ ‚Vb$¥6 }Óˆx+Eñ=D;m$m@4‰µ(ò[ì†ã®{IØ ìÎ.‡™ofaöüF„$Uà h7À­™½wÖý5 €†™íE刨é·Z’*’Ì_»’^ÎÕ¢âÄ`8€Y¿²U`8–¶ü³À=^§^€z⊣$iLÒq@µG’ }OøÈ•“ü"³ÄÀ¦°‘6ÎP OÎþy_!ûÌú¢ ˆ3ŠHÒ°„7ŽÛ*IZͬÕ/¸0€rÀn«œ4ÞÀ?AjI*:•ÓÆxr€ ø×Ã!ûÌÜé7ßCœt’tíŒâË,OH: øžHOÏb$Üdzfsx&u…Î=âÔ±í?@ïª^7³ƒ¤PÝaætGsZñßu+ÒœÆé@Ï”ºöü.Äž¯%:ö¼eÏ¿ò6Cö½@ÌIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/beam.64.png000066400000000000000000000015441370472574300234400ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsòò”µ-‰tEXtSoftwarewww.inkscape.org›î<áIDATxœí›=kAÆÿ$`4HD…$(¢h¡iÄÂEŒÁl,ü"~¿†¦’ø‚½µò‚Zø’ÂFÓh¥E šh„Øä±Ø=<Ãí±ÉÞÎ_“ù5ÇÍÌÎ>û03{·³QIG€5E ÀW`Ê̾í?=G° Ølª©úlfãÍ8Ǫ‘4¢lf%=•t]ÒÞô¹/=晤ï ú)óÚòŠmd@-K’*éˆÉê먤Ѵm ÐR´ƒ`À0&iXR{µBÒFIw€WÀé´mÚB¨®½’Òï£Àa-Å–Ôt¤_7,RÝÀà 0lË8üeúy<£þð˜ÞÓ$‹ì¯´~Þ̦‹è/I­’ÎIz—s^KÒ[Ig%µzëo’Z$ÝÌqñ7$…\›Â"é^ƒ‹¿í­¯t$mQòû`93’:Cë >ÔÌìð¸NÕC3› ­Çk®½®S6\~Ôûàr;ó2`>gYé¬ÝÛMN¢Þ¼‰x ð&à-À›h€·o¢Þ¼‰x ð&ÈcqI—€=5E»ë4»¬¿7M>™ÙƒR……BÉŽÐJ©„жî§@4À[ÀºDR9ßï¡eÝ€h€·o¢Þ¼‰x ð&à-À›h€·o¢Þ¼‰x ð&à-À›h€Óy;r–•Ž—=uʺ‚«ÀÏ€cuÊ\Šç_{Y:8’î7ػ뭯4”$G†rì i%EÚ$]4™ãâ«LJ:/©ôÝëf‡¦ÚIBS=À~ 8lÍ8üEª!+45ËŸÐÔ’·Ì€Å´Þ?4¥üÁÉåŒKêT²(N¬²ÿ*8Ye ¸œ4³¹4ArZLHD2œûÌìš™U‡1f¶hfW> B@#Ê^df€7Àsà‘™}lÔØÌ&€A%Aë‹À)àÙÁËÂ4c\ŸÿI’øœjÖ%©ØIŸß\SU8>ÿCÝ<ZƒIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/box.128.png000066400000000000000000000023001370472574300233740ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÞIDATxœíÜMnÔ@†áÏBä ˆe$®qöd›kdk°CaÏP®€”-\!‹˜ž‰Ý实~Ÿ%¡íO’ Õ3%€^ ± Æq|/铤’ÞJ:¼Ä£¤_’¾Kú: ÃØ Æù–¼çÍÊ\ã8¾–t#éJÒYÌMVŒ2­©Ñrn-ïQž õìÀôº¢µ¼G¹ 2Iy,Ö|”¶–÷€·Hé{×'0VÒ\Áó-yÏ[uN`¬fZ«ïy«Í ŒUd® a¾%ïy«Ì Œ=¾líxÕ{^Ó|àtüá4¬Ž–:IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/box.16.png000066400000000000000000000005351370472574300233200ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ({IDAT8­“;€ D7Ä„ Ùãy<‡±%6ÜåÙ°h,„E¦œ¼ýM@d†€dà¶——X¼­0Õs¥Ç:0÷® W~)ÞnœnåÛ+E ÅÊë Ö+ᄄ釱ÎÊ7 ó’†èEÄ÷þåŸ FB™ä.ňQ°oO IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/box.32.png000066400000000000000000000006461370472574300233210ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÄIDATX…í—Ñ Ã0 DOY¢ t‹þe¯Œ×L‘Ò%®?ÁÈ­ÇÄ¢êA (‡$qÈ@°Ar$9“\Ô3“èZ´™N”ø àVèm‘Ç]‹6é´’zj {*/ÓGlÚâg´ ý –ìƒÈ½Ò\V~}«ñÞ‹ýüjb¿¦¹Þùƒóüj,'Ì­SÅü–z¸b1Í Ý‰ŠƒëVŒ«Yqï{UÇ\J÷‚êRêMª¥(íð÷‚’îyߢD÷DÓ†IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/box.64.png000066400000000000000000000012221370472574300233150ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(°IDATxœí›ÍMÄ0…Ÿ7¨a%º€2¶””‘ëvAÜ¡îHÔ°9ƒ€LœŒÇíû¤½øçåeÎêÉB.™  ŠÈ@àÀÍÄÞÀ €>„ð‘zÈB½ZºI½Q¢è€»£ßœ§ÌfèÕÒUõ®”…Aqm—˜·êÕÒUõ´<D—ìÉÑ«¥;Ú£à6CØ £wÓ Ãkæ\+ÝÖ(À@Ÿ˜ïãš½èþ¡¤€g$NjˆsǸvh¨«ëü‘÷ä†îs¶VÿknÑ ð™XŸšÛ &ÿZªŸ¼•1ù× 0uºÎÊ{¡Ü¿ˆDä$"oñwŠÿ½]àÝ?!„¦xÿŒXü[2ÁdF·¬þ-™à\F·Lþ­™`I¾·&ÿÖLÐC^hòÏ< µÖ°­ ´†hm 5,€2ÆT8!ÀT8ÓÔ–0öîŸBHS¼F˜ 3f*¼xŽ©pE#.¸¶nøuÏK¿@óEI/ýê\”ôÒ/ ²Öà¥_`„5ôNq&8…—~¢Lp /ýªÞ¨†{ø^úéB.“/ËmýÒíßßIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/clock.128.png000066400000000000000000000071441370472574300237120ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( ‚IDATxœí}°]ÓÀ+ ERŸm†¨J„f¦´¥šÐ)Ó*‚ðí# eLEt¢”)㣊¦ãùˆÑ'FG•4šb†É+ ÅóòòVÿØûö½¼{î½çÞ½ö9÷Ýw~3wÞ›{Ï^{ß³×Ýgï½Ö^ "’wb ª_Fõzí| l llïÿ||ìÿn6ëµÀ X+"Ÿgö%2¢%@U÷¾ç_û#€AÆÕto/Ëå"òºq™Ó/@UwŽ¢§Ó¿’SSÞÃ+°DDÞÏ© Óo@U·NÀuþ|[TÆfœ",‘9·'M¯ª:˜ƒ{n÷>‘äݘj4­¨êÀÙÀy·%UÀí"òTÞ I¢é@U.ÆåÝc^nžÍ»1%šFTu0Ø/ï¶Dæ%`Žˆü=ï†@(€ªîÌÎÀ~éÖ¬(ðpµˆ|gCrSU`2p°s^íÈ™€ß D¤;䢪:¸øNõ7!+Y"òNÖg>äªêÀŸ(:¿7©ê³®8³@Uç38ÏúzQ`pˆlÊ¢ÂL@UwnÆfQ_ ð"ð3ùO슢+€ªŽîv‹]W‹±8SD^‹YIÔ¡ØoãÞOÑù0hSÕ¨s¥h#€ª†[âl«ŽlÆÙóßð;p¶ý liÿ‡ÿ€¡þ5 ‰ó#íÿœUÃû°˜!"ÏÄETõ8à:²µØ)ðÎ"· X)"›VÝ7S3?!Û%tp‘ˆÀ%Äéü/€k€ãû[çˆÈó¸yÁµ¸G—5cY¡B‚F?ã¿#TNë€ócLðTu p 0ç>ÎÝû9àþ;oªº0øºµhà\YÒ¨€†;Î?÷Û±Ÿô=\*"Y õ^Å—§RyäëîæŠÈÆõæÇZÊÅùL‘unHTuîFYoSΑùÆ2Kn' ˳¬•À·åœEÔ’•Àiø6:˜‚mç+îWgÞùžËIßùøk/ѹ¸7ÚXqðã†ÚSoUÝ 7L[ ý›€ Eä1#y[àŸùíÔ¯ìÝÀq±¬qªz 0ØÊHä‡ÀQ"ÒYO¡FF€K°ëünÜw”Î÷T{æWc/ÿgâŒVì„Û¨‹ºnŒª~›‡š \-"‹ å%QÏÐoY¶&"òn¯ÀŠ©ªº=R+€÷⽪ž25˜/"÷ɪÆ×r*› in17øE½Òrv‡68áëKȾ|Ì=ýÿ#"767VU¿Ÿöâz`zIâMÜY€‚-¹ ø·‘¬™i/L¥ª:›e_ÎÿýY-…w^™‰Í¶ñ8U=(Í…iG€sÓ›ëó¶ß73þ(ùFâÎKsQMðŽ‚›ã¬zwÈiu~üÓ@Ρªú­Z¥N6hŒW‰ˆÕš·e‘.à Ü= å¤ZTUmëG yHDVÈxSò"Q½¤"µF€# Ëòî hA}ÌÃÝ»v¯vA-˜Ø€…ÍîÆÕŒxw¯‡ DUíÊ àC±¥ÞP¨@ð»@™Û·æ x‰T,B±µ‹ˆÕæÆ€CDÞÂya+ªÚª¦†{ d tÚ dŒ¯ôA¢xÃÏÁ•vàvÇÜ—] T2¬ƒ!Z0—¸Ãór_Glö ,ŸJþXIVñóSããý…sS·|t{™Qb &zoËú6Éjp5'GÁwÐlUmcËP±õæ6ÈÓb †C]’„:6¥”ðf™+KF–/ûq'=BG€Q>!t!ªº#ဲw’tî{v`@ù‚d&ÜWó­¾o– ‘Ïq)BˆmˆT<ß—’u¾o· ’F½XYhc Ê ½§¯$½YIB×ÌcT5z”Í‚ªîIøä:ñ¬F,\^½&ž•¥.xx/°Âü1ó‚pŽ ,¿^DWw‰ àuÿ-°Ò‘éâƒñÉ£GŠy®ÒÕ–çû¦Èèœf £â#½š,Áy a’ŸÀ4€ªîL ³ x²Ò‡@DÞþXù`à'22Ó ÏGü´ˆ|XéÃZ;KqêNòéT êÀg(?Ñ@TÕˆ£µà)ÂzlM¹l ¸˜ð„RÀÒjTU¿uh‘ÐéDU :6`ð±þ'ˆZ\ËO!qáAƒ†p…ª†>ÏZŸŒû*lÒñ.¬uAMðI þjИ18¯œ‚êüØÇ@γ"RÓ¦“Ö¼xk`cJ\¨ªãŒdµ>-ßùFâRe"K¥"²›¸?C€›¼sCA/Tu{\†q‹L¢/ˆÈÊ4Öã`p[ƒéËà×… /®Áîlaê”|õ(À3ÀKõ·%‘#°êZYÀÑF²V‹È³i/N­Þ@4;·êªz¦‘¬~‹ªNÃ.+[7ðËz ÔåcæWÕS¦—©ê±†òúþ»Ï6y½iùI¿#.}|Å,u5}|³â;ÿzìÒÇ=}¼¯àºzËUa+ÜÊ`Àì¨êé¸DZVpm½ î6©ê Ü‘¨TéIëàfà¦VÍ3àgû³°{æ—XLkä¾5¼óÖªvì%–?‘Œå抪~…MÆÞtÇ‹HCÁ)>hàÓš]Œ}X”#q8[fÇЧpmǾó÷ci82IPŒ YŠËukÍ MUÏñÆ‘~‰ªQÕé8ƒÚª¸CD*zû¤!x7Î[øÚ°I/ŸÄZàJ±0He†7éξ©ŠÕÀTŸk¸aL¶cý|`!á‰&*VóNš'"ïFªÃ/.‹ˆµÝ½8Ùâ^˜5PUGØMÀbà–J~îyáOB‰‹=P–™ÃNÜ/?ô?`¬¡ªº?ðGêºP/›q5Ûp–¯\–~YwÎu{"᜵؜."fù͇(U=¸ÛMŽj¼›a/‘Ž,*TÕ¸Ó:S?´‘–.àyÆRh”g”ªNÄmsf=ƒw e°¢‘±$üö÷wq'tÇãkfIp±ˆ„&,#šM^U€ÛÙ‹ý8¨D7n±Æÿ-½6àâå}BOÔ¬¡¸lÃüÿ£z½FžH+„À ë_~‰¨NÞÅéN`ç˜õ´0¸aU¬ ¢{å¨êhànÜæNAzÖáÂÏ™Ìö+}Xó_` ðbìºZˆUÀ”Ø=×ü†Å)8_µ,âööWøβ·>‹ 3wÌôËÄy„g'k5>ÄÍô—fYi.ž¹ªºðìý ú++€YÞš)¹¹fû]´ÉÀ¥ÄÝ>nf:qKå"’Ë£1wß|Ut&p:ñ·R›æV;»Ÿ¹+@ U \AëÇZ ÌñÖ¹Ó4 PBUÄòn‹1«€Ûq;šÆç±é „W„³Ãiâv¦`p»ˆ<•wC’húëýé¦ÇýåPi'Îoaaš#ÚyÒô PÂgç>8ç8š•¹9-›qáØ‹H–ù ¦ß(@o¼yöH\Tò @^A¨Þ¥Çüü¤•ù9Kú¥ôEU÷¢ÇVÿM`wì—”›qšWp¾\DÊR°ô7ZBúâ#q¶K‡ÛùWÉþ_Êq¸çð)𙭧LJ` ð¯ŒCDçP|½ÐO„‹IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/clock.16.png000066400000000000000000000011101370472574300236110ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(fIDAT8u“MJÃpÅkwU©;-´ü¸ÖM½ƒÀˆGÝèt­¶—PZÁmi«,.]Zy.2)iÚ<IfÞ¼ùgÞĘI³@ X|÷föæZªp8¶\Š;šÀ©™}Ž HZ.¼ëhÏÎY6€) ì™ÙËHgIw’BI—’ʯKªûsEÒ•sn%“G‰â|"Þ–ÔN¼ç%];÷p80I]¿Ê©™„’ÂT¬*©'©#©ø´s@ËÌÞÒSNÃÌ^G`¨@Ésݬ"ï¶•uü^ ˆ|†”¥Ž§ Í ÖÎÙ°6ḻ1·¤`OR%£`IK#Côõl-ÉIÒÆ ÅyàØ¹ 3û‰E_ŽÐ}®ftn:çFÒŒ¯ò9°üYÕóô*°î߉V9ˆOì;D>'ñ 4€33ûŠƒ“¬CRØ$ú± rêaøÍ üŠÙø;¡äIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/clock.32.png000066400000000000000000000017111370472574300236160ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(çIDATX…Í—;L”AÇs˜H#è|t"‰”ÚÁ]ZÚ J"4¬Œ•Xú¨ˆAШ…6RiBxUb µcÇK4Š 2»sËÞÝwç%úO¾äfçõ¿ÝÝYøÇ¤†ªZ´ 8 4yõ2ðxLs"ò»*Tµè.û¤I𠞉ÈVÅTµ ¸ 4&Lb¸#"ãePU®ú/ñ2ÁSOd§$UM€s‘@?I` ø‚[{€fàÐdúˆïàZH"F`膷€'À°ˆüŠ·þ‡€+À% 6P‰È½bÎ]ªº¨ªKæ{«ª'#¶íªúÎí}‹ªÎ±UµÓÚ‰q¨ÅM­Ýp«ÀY‹$˜Ò^\‘³›40fìÀ-[VD¶RFÑ$ßúbÉ=Ò~ïÂûöÛf¸¸˜Rži ®Î-‹È§ÉCD>àöE¯ßì»3ÐFþ!óxô·É †M#7§-là0Yj·—ÙÄ•¯EÆh ”3ÕJn0È-–À‘@¹Xnt_fÑ’ôX ät1ëå0qnЭr£% 2Éù_¨< !È;v0üÇáŒÄp+â·îÇcÏŠ5€Æñ¨QžÀ]6!"3À™DmL‹¯°7eG“"È –ÀT Ìú[­*PÕ:öÿ©iK`×FåPôU‹€Ugä `~—€o G§U ¨²¡ª­@O0<’kL*¾Ž&o^‘ä:öÝë ùgB#0¦ª§*HÞI®À`.yObxÄJ/UuÀo¦R‰ëTõð‚ýµ?$"y9#RÀ}à|$þ&n™¦€Ï¸¶Üå8®Ô2äo¸^×K6¥ž„àËB6e@qýÀÝDmy@¤÷0i*fW˸5Ÿ(däiv×Ãõâ:™$ØF€çvÃUDÀIáÚ¨Üã´½™YÁí ¸n>6Ýÿ%þúˆ$;yº°ïIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/clock.64.png000066400000000000000000000034601370472574300236260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(NIDATxœí›]¨UE€¿UjéõuÕžB´2 £½YWS¹¤ýèCd/•Ef‚T*fZÒ‹¢aJ$ú¤Pþ¥¢¤ù‰f”¢·§"³ÐÛÑPcõ0sNûž³Ïž™}öÙžÈì³gÍš5ëÌÙ3³fm¸Æÿ©wªÚ ÚO Ð 4Y±Ð œNÙÏ1à ˆ\¬§}uq€ªöžÆ÷ÝRªº | |l‘ß²±ð_2u€ªŽ¦mÀõYêþv+DdVJ3q€ª> ¼ <˜…>KDdO­Šjr€ªöÞžªÕ”læŠÈÏi¤v€ªŽÞz§Õ‘ÀlÙœ¦r°Tõ`ðlšëÈj`ˆ\ ©äUí, ©—#û€WE¤Ó·‚·Tµ°œÂ° À`?pèÀÌù[Þôúƒ€á˜µC¯m^‘³>Â^PÕf` aW`°Ø:4í_í1`"0Ê×VËqà9ùÓ%èTj Y‰ùU|Ù |,"?ÔI²án`*0. Úà%—ã}ðþ¼`Nós[Fó1V‹ÈÜ$ë ¶ãßù-ÀÓ>WÕªºLUØÏ2Uàª'"» ÀzO›&«ê„D FÞlÅ=Ï+°HD>ñ±Èvt-psYÑ9`’ˆœöÔó0÷(îƊȯq…I#`6~ŸëÛyË *;½7ÃW‰ˆ,Þ³6$Ñ ¼S­0Öö¿ÖîaÇ"Yã!edʲ Dd5°ØCt¼ªÆ>Ä«€7<”n üå‹$ªàeµ _¸Ä0— *`·´C ;€™öåÅ»ÀO™VUm-¿7¦ø4("|,Ë)‰Óååò]`—»m%›EäóòADva"GI´©jKôFù˜@r$GeáæåÆR’g…n˜P]‰rŒq4°CD~HaX.ˆÈ÷À×±±Ñ/%Øèí}ŽÊëÒ™–+.°}ºŽ€a@÷„ŠLªÑÙ$…Ò»™å¢¸×¡ø@è–öj "a‚¦I )^D0ÐQé@Z£®{奾F,\»±©Í @UOÚ˰ Xè»AŠà²µä€èèã¨jD­4ažØk}¶Êet8ÊK}: )F0ÊFdEÐ.Ñò»£¼Ô×åõ$h—ˆÛÖXä…3P™'Qx{­FvçPÇ{4‡8à–@#ª±þò圭­ŽòX¸ÎÞCŸÄ±Ø)m&Þ˜äô‚•ñŽFpÙz¦x]œ"y/0ˆŒ–¶C¯g¡« w9ÊO/¢#ÀååŠhJ3ÂQ^êkÔG•Zí)QC£ª7âé+^DpHÚìôœÕ5:=Ê/Ù,•`³±Ž8”O¬É´|xÆQ~8šyV¾rÅÔFكʆDUãÎ]ØýRî€ ˜l¬jæ”¶Q™FòQÙ`SôFØ<¼ŽFÆÙ“£†BUۀѱå‰q{íÍWÕ¬–Æ5c8æyˆVô­Â6 ñ CQàC/ëòap»CfŸˆTDµªí?òh´ÝQ_UTu*æ<#Q XWë›ä°Ñ£ýéª:ÙC®.¨ê󘟋õq¿>$'HôÃlFš]v`ÒVs=1²¿¼OçÏc$ÎÄV ˆØŒŠY f$,WÕ›<äkBU›Tu ~˜U­óàˆ‰È—˜ LÆŸ«jÝ’(íT·‘²ó½V‰È–$Ÿ,±ÀgÀCž‚YQ.µgu5cWxÓpÏóQvSDär’o¢doL¢ä=(æ r°ÍžØøW6»ºÑ˜µý£¾¶ZŽ“mÞ@"!©²-˜„É'¹ˆY[SeOS™*Û‚9°¸³ŸJò®®ß/fš*[ä?,½“,íy ‹Û´˜Wð0æÉ*L’tPؽ–&Ú¸× õæ<0SD¶¦©\ë+3}·'kÕ•’현­_Ò*Èꥩá˜<¼¼§ûÅÕ–·!dýÚ\+&mÙ¿6w«øTD\»Uoêõâd ]_œì‘RÕ%à0fO²QD\§¾ÁäõêìPLZÊà’_=‰9ß?  ]@]ãaü8AØ|Èè ÁIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/diamond.128.png000066400000000000000000000026151370472574300242300ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(«IDATxœíÝM®TU†á÷‚ muä ;8˜ÀÕ0…{¤“ CÇ‹0âÄ–‰:aÛ¨Z·çÔßþYkïíVA6ùž­:”RJ)¥”Rëj}€ž•R>΀»À7ÀWÀ{à_à-𸚦é¿a‡ìÜj”Rî[;Þú'p9MÓUûS/=€RÊ àgàá¿ô9ðdš¦õOå§Ô¶ã_?ù[¼Χiz_ïT¾J  ÂøVj)TßJ‹ €ã[)¤Ðp|+‚4:Œo¥B@Çñ­4Â0¾•AhÇ·Â# ÀÁøVh!8ß ‹ ‡ã[!„àx|+‚0Œo…B@ ñ­0Ü8¾kÇ·Ü#p Áø–k.$ßr‹À€„ã[.¸x|Ë7V0¾å +ßrƒ`8€Žo¹@0ÀŠÇ·†#@ã_7Áÿ£†!è@ãÏ6AWgÝt ñ÷®+‚.4þÁuCЀÆ?º.šÐø'×A3¿ZM4 ñ«× Au¿YMT ñ›WA5¿[UT ñ»W ÁÉ4þ°ª 8 €ÆÞÉŽ ñÝt‚£h|wà`ßmG!8€ÆwßÁö ñÃt‚½hüpíàÆ®7lÇ¿DãGêàb»Ýb;ßü<8ùHªw€ó]oZPJ¹<ªu"Õ½G¥”³¥7Ìþ ”òp|]ûTªkï€ûsa-ý pŸ¡ÛlnJûdKîT?ŠÕì–K¾op5¦ïæ^XðEƒƒ¨1}9÷€Òà jL³[.ø§ÁAÔ˜þž{a ÀÛQcšÝr À›QcšÝr À¯l.RV±{¼š{qÀöŽ.Hõ«K?\üYÀö õçµO¥ºõlš¦ß–Þ°ÏOŸ/êœGuìðt×›ôœíý}$,_õ?f ûÚ}(Ô·µÿX¸%îê÷ÅKÜÔÿ«a– oÜ—C-!Öø¯‡[BÐ=?ˆ°„ [þc Aóü>$Ê‚fùLœ%Õ‹ó HKªïQ±–œ\܇E[Bptño ÁÁå¹0‚½ËweŒ%;Ë{i”%³å¿6΂ZÏÅ‘–\·¾«c-!XñåÑÖŠ €U"p1>8«Bàf|pVÀÕøà ¤Fàn|pR"p9>8©¸€\Î@hîLJ $‚ãC A˜ñ! Ôø ¸Fn|\"9>®„BÁÀPáLJ`‚ãCÐAšñ!è‚ Õø 4En|Hš H9>$U¤€*RÉÀ5‚s6—`ïûç-l.Êøeš¦­Îæ¡ô¬í-ÚÙÜ¥»ÔÀå®›6²´p}#ú›»t¿nn_ú øx ¼ÊüW¾RJ)¥”Rjíý¡‘Š^(ßYDIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/diamond.16.png000066400000000000000000000005741370472574300241460ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(šIDAT8­“» 1Dß\B ǃtºjíP ¢ DB-  †Ä >öÊFŒ´‘ç½À^CÛƒíeÔ‰àÑö1ÍØ ¯xNs²=åºÊÁÀX|ÍÀFÒ¡(à¢ä)¨€³5Â_Ù€}üÈ ˜:Àà[:I`Œµ™­¤ë.±AR~Æ Iv‘²iYåHòûgz‘ô¶û¨sXˆþ`þˆ`IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/diamond.32.png000066400000000000000000000007621370472574300241430ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…Í×M‚0†áwÜã4ñ>Ê HaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÊIDATxœíݽ‹\UÇñï£î*-_ÒéÂV‚/1Vv¦‹ ,1hapóoèß Ø“ ˆ²Eì,c¥!ˆ©–¨ ZE$îJ">÷ž¸NXsîÌ9sÞ~HfNÎÌó½wfg'\‘Z¹©w0³û€À1` X‰½©í×€‹Àçι›™÷S´I˜ÙcÀi`=Ív¢ÛN9ç~ɽ‘R0ù[Ô3|ï'àMçÜϹ7R¢{&Üöõ àð©™=‘{#%šÀ±d»HOìcJÏ$ÛÅr>3³§ro¤$SXM¶‹åy’áL FSh…"Ø£Ç@ÜÖk €¾EÐ}Ðy `Ðm à_]F þ«»ÀºŠ`ÊoL¹™Û.ð=Ã÷ÎOýþƒhË6°éœû5ôz hË:pzüîFОuàxè@›^ ½¡hÓZè {`güÓšàïnôÀ.p xø#ïVòé5€]†—¾qÎ} œ¤Óz àöðý_ôAoÜ1|¯×z `ßá{=FÐKw¾×[=<|¯§Z`òð½^"h9€¹‡ïõA«,<|¯õZ Úð½–#h-€èÃ÷Z ¥’ ßk1‚VH>|¯µZ`iÃ÷ZŠ ö–>|¯•j Ûð½"¨5€ìÃ÷j ÆŠ¾WsµPÜð½Z#¨)€b‡ïÕA-?|¯¶j šá{5EPzÕ ß«%‚’¨vø^ ”@õÃ÷J Äš¾Wr¥ÐÜð½R#()€f‡ï•A)4?|¯´J`8™bøföB kÌ#x‡þkzîn2ùWb/<îL„¥Î$Šà °Éðd“;€ws—c/ºgø1.r±Jº.ïÅ^wŠœ|Çp²¨"ßKp¸š`Ý 9øØ9g14³çHsy›Uଙ½sÑñ9ø$æšSä ૘‹GçYàÁ˜ëÎX>Lp&¸y½`¹øÝ9÷[¬Åù³¢Ÿ œs×±Ö›"WÇZhIGþ¬g‚¿"®,WÍìþEIô†/T´7†f¶\|KÓå ÀGY`ɧýýÄz9x™9®äCÎ7óÞ1Ói?1^^µ™©rpÔÌž›z§Ì§ýýÌýr`f/Gão)LÎð™=z3;LyÃ÷|‡Cï0>ö÷Étú‡ü? lÝíÈ13gfÇs”9|o8gffö¿Cü-†ç ›R®bÀ— ‹~íœûsü7^ÞžgaçÜÓ mlþÇ}•á¾KãÏù˜Ù o~7€WIxä‡>îR˜u8<´èBØëp x8ÂZAB÷½©72§¥=QK²pÈ©ä~ ™)€Î)€Î)€ÎM û%X𯖧ðÑ<‚tÀÅ96"yÏjJç®M+eÛf˜UàÆ«Ro¢Jæ/}+ô“?‹6³À —']£ì_ΔòQpJ;À5à †ËÇ_DDDDDDDDDDDDDDDDDDDDDDDêöo3½Qƒ‡4IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/dirup.16.png000066400000000000000000000006471370472574300236570ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÅIDAT8Ý‘1A†¿·töÛ…Dá *'p…hqn°¨e §Pˆèö*ü O2&³Ô¼dò’÷¿ÿË?3ð%i-©ŽÎYÒø›7ó^$´°•4ù0O°F ý潕Ðvf¶ÌBh^³VÐþd6³ƒ'ؤ’¤¼™ÌìØ”$ܹ™$寡¤Ü!sßi\̬rsÌK‡TÀ54ÄoЗ´†@7˜€½¤ÐKjžßئñ=½º´nØûµzÑQ[°{*IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/dirup.32.png000066400000000000000000000010221370472574300236410ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(0IDATX…íÖAJÃ@Åñÿ'RJñíÁtgq-®¥·ÇDq[]ê!„ºro=ƒPä¹hBœ&“™(ˆyÃ7y?Â@]ºü÷Xv#i$ÀÐcß87³çXÀVáþȳ`\KÚkÐk¸w¸‘´ß $à*± Èw’|ç_©™-!þ ¼¥W“ YŸ7b+à ˜ òó X33{4³§@D0 /ÏbMßÊcMËc¾€ÚòP„À»<QxNËå’ʃåµ1>bs3[8ŠÇlâ@,€ÛÀç†ò¾c¶ïB”ŸÑp"i,©'iRQ^F¦{ÆÀqUAÝÇh¸¬™q!.|‡‹o ò°´œ¼«x`ý«õÓyî¡§K—?’/®:qPþÌIøIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/dirup.64.png000066400000000000000000000014551370472574300236600ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(KIDATxœíš=nAF_ûgøä‹,9DÀ 09 2|ˆM™#ø cÉ¡9΀Œ•¦,0Ó³=Û]Ý#¹žÔZ©{TÕßÓìì¬fÀqÇqÇqœËH蛑UàpØ(Ôë8^…~ª™MLÀsà±QÏ÷À“©HXŠÌoö¼¼‘+†=’‰ (uÚǸ ¼ž‚„˜€LBBK0 ­@c S %Ä~OjoĽÿØ !ü¼¸8•3À’ þÜÓ<í[¼ ”{}“­u£×ú&[ 8;À§V›h%àxBøBø<¤‘„ÎÃëDK µü^i%¡¦€hx¥…„Zæ†WjK¨! 9¼RS‚µ€Ñá•Z,,^©!ÁJ@vxÅZ‚…€báK ¥¯XI()À,¼b!¡”óðJi %÷S‹ÈÕÇü%!û¯t®€`§ÛÐ ]°ý„šû#%|N¨%WÀ‹‘ág 5g¤Kø¼L¨%GÀ/à㼃F†W’%€ß#jÿCŽéFü€ÅÂ+©÷0«Àfl13¼’"aX^´Aî5`WDÖ.NŠÈ:ùá•°ÞÓg ØÍ)ž+àðVD¶DdIDVDäp@™ðÊ 8‘Û"²Ü-à]nŸ’O†ôB4x:†®­'ôNê“Ú{el‘þ¶ìÓúÁHsbN«î¢_ú&c 7ÒŠÞL±kÀ^÷¹ýûBÖœ¿ž×z#Žã8Žã8ŽãL‡3|kã'•£ÉÅIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/error.128.png000066400000000000000000000070271370472574300237500ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( 5IDATxœíÝ{¥EyÇñOŸ³ ;ËAQÑ%HQ°vgf6Q.&V¼±jb!‹H4• &Sl4U&)Ý\ŒX‘«wÝAMÁ"IVDv.;RhTH"+(C@ YXörNç3cÆÍÎ9ï{N¿ç}gö|ÿ™ú}ú9óüÞî~»ûéfÀ€ 0`À€¡lR³™úJŽÛËÊ'5[‹Š†Ã±|æ‘gðTàéÈ®ÀÓx$²#²c);vðÃõ4JûQ²à°•ËŒ5 œ8$e‘=‘kL`|“«ZBYð,HLqJä¼ÈN ÔûYlµß l[–3¸¿Ÿõ§dÁ`+Gq>Þ8¥lö㻸e7Ÿ?‹ÿ*Û™¼š-X¶3óQ)l¤vçD~·‚Í|WDþ-pÍÃ|±Š_•À×9y/XU¶/ñ\1Â7Êvd.¥ `CõVS¿AÅûø4±ùþ|;Ëv†’0ÅùM® <¯L?úMäG÷pGÙ¾”"€Û8ôh®À›Ë¨¿*DnmrÅ»Êò¡ï˜ä%ø^ÚﺫHäÁ&ïkÍ%ôZ?+›à\ÜlüŸ8©ÆÍ“üRIõÏÌwý»qi?ê[¨D>2¦~Î.€ÍÔOà½5ÞTt]‹„ÏóžÐ§9ƒB0ÍÒ½lªqA‘õ,Bî|‚ß{5»‹®¨0lc¨ÆÕWUÇ"gb—½ì\ˆ¦YÚ༼û“+¸èöUAò™·HøZ#þ½qünN<ž/¥ aòÏÀ þ$ðÚÔvV¿|>T”ý¤ç’¥´9€À†©‚þ¯ÉÆãœ¸&T`i‘ÒŒ\<Ê×RM¬iŽið%<7…½&òDƒ×œÉc©löÜl¤ÖàƒÁ/œÀÑKØ´9áà½g\Àoã̾ ÈÆè \’ÊXO]ÀvNoðÙ¢6kÆÖ$ÈÒÔûüûȳZßð‡§4iÖ§Ø]Ôµ6S?‘[qr¯NÌ%òÏu6ïfòåüLpl“³êü*NMY_jb+(Ÿâ««fúê ¯3Ül­‡¬KTÏ·¿Ïë{Ýgص&ù \ÙKås‰<ËÛr#a;ë›\UµV!²'pÕ07µ[Í›hÍŽ~0pt¯u6¹j-ŸêÅFW˜l9§DM[äñÈ›×òP–òÛnpmø¿ü¾R‰;ÂÝdÕ¸p¼‡qXn4¹,ål_äsÝ>[¦z þ›¸R ¼£ë‡ó¾›•¬òMöòp"H|Ø•£ÛhGàü{8±›gs àÐÖD²¤ÈÎQžêÕN?E*ø°Ž'ù\¯ñönÌÌ)žßL¼Ì›r©"HüYRu§×MplÞç2 ò›¥y+èÀÐ= ³‚ŠAÁŸùíC)l ­¹™\dÀÌâïäö*KZ§|$£|¨¥ß2÷Ú9»èL…_ÄZåïE~=&ÞCRE?j¼5¥M{.£yȪ–BÞ~¬šâ©í¦AQÁ‡í¬WÀáõœ±êøæÍlïž,xÚuwàmÃlOmx’Õ‘ëóú_dð§X¹‡¦¶Ù¹‹Ñu­•ÈŽtl¯ìÜû¡M®›dujÃÝ´E’ÕM®S@ð!°bˆ_ÈZ>‹ÎêÍ¥l̈ì†qFRÛa:ò¶˜-ÉbWä’"‚?Á‘ëŠ~¡òÄ,‹†{s'C5®-Bk¹7rQìj²am³“b‚3´º¢ÃRÛ>™‚m0Í‹p\Ïîä£,,–àÃñŸ¥`[4s~R$¤ß"XLÁŸ%Óÿ®­bÈA¿D°ƒOÆ—·ígà['¤ñ§;Š‘Ó$a»›ÏÏ„<<Â/v*4¯¾Í!;ùÕ8º­°·´J~ógi¬àÔN™Åóv;y±jŸ»ƒÔT$øPß•¡õžW V¦õ§g*/‚ ìËÃyPoµU£²"¨ZðgxI§í¾:>\•AEƒOȽ»¤ ®)bí /3>ÜPÁà ¼°S™yY‘Ö´¹v•~Íí÷ÀQ Ì+€**ú”ÖT¸ÙŸË‘ ´ëªªêýé»HðÅ þµ@¥Ü~ôM %ø´6Šv*Ón Pù¸…‹`!†î0àÿ+|ùS·´.´›1 _/ȸ©¤Jtœ¡çî ðú~4÷ñ÷Ý>œ[£|'¤ýn?oœŸÏûPÎáë©;¸‡5MÎKàÆæ1èöá®’C#ˆüw·•Î%7Í ²>³á²ƒ?ˬ¶ç8T{š,áo4ÿOÂz1ЕFZ=ÿu/Ï%ð¼7wz“"aŠ75¸± ÁŸ%°¼Á“\Øéú›{XÓhµ )®àÙtzŸÑ]+p3õ¸µ–ðúøH¬qGƒ›žebvN{Ï©svä­U©ê+‚È7Ÿâ®ÙK·²l£¡5Þ97ÅÀ/ò­ïó†Ò®‡)^Öäs¡ Ecë¸4TüÀªù˜™äÙ2Ö”“}‘õ£|³WC=1Ì}øÛ^˜ÀQ 5ø´®o) øðW)‚O‚B¶ðÜ“À—Ù˜¸kRë¹/‚iŽið%<7…½&òDƒ×œÉc©l&9#h5þXÚiâ?K—§ > ‰æ®ÀŸ¦²7àg‰¼”¯¥¶›ô”°a>…ëSÚ>:Ê EN~LÜ0f"ÿp{³}íH2ÜŸ­,YεÒߎ}°1±‚‹³$yvK!E®c_ƒË"waÿ` 2¾ŒK‹ >ž:Æ®%¼·UÇ"æÎ³aU²ˆ =*v5{æ÷ñÙ"ëYLD>};ï|5»ûQ_!c€ý‰„I.¼£õ-DfÎ!þðhÂUÖ,ôE³lç•Mþ‡÷³ÞªÙYç=k¸½ßu÷U0΋k|HÂeä…L“û›¼«Û=}½Ò÷ãâ×òм1ò±~×]5"·FÖ—|Jhæ2Á¹¸2ðü2ý(Gk¼w ÿX¶#¥ €ÖÞø%\Òä²ÀÒ²ý)’ØÚ½óÉ!6õã/ ¥ `–m¼´Æû§—íKD¾Õ䊱օܕ¡2à§›>×áwpjÙþ$â\w;_ØXÁåòJ `.ãœøƒªomÃý5®^Í–Ôéï)©¬f™â¬&¿8KÊö§ûbk_Ä'GÈ:Hå0Ë4Gìã‚Àë´NüªßÅ-un^Íãe;“‡#€¹Œsrs#c‘—µ-½ û"÷ÕØ¸c ÿÚçú“± 0—i–ïc$2üœ)çû±;òï©&Û–2µº¢×ÄäeÁ `6R;ŸÖX‰“š­¿Çã9£fnD]2›QGº™$ò¹ÍÒfCff¼ìÓi± ÌáEF9 Åâã2Ψ 8Ê·˜%“y·Zl—4Kšù‚Û¹±¯Pœã;>Ô‰‚;ùÌ‘nI³ÍNƒ»™À›„§Áó¬¯FŸùÚ°ÀL¤Ûg¾¢‘`¿*ºIèß"•< i&EÅ£^:ÄŠ‘ד¹Vkò¨ƒÌÀÐc)°8›¥öñ6²v!óë?<¶81LßyÝËü‡û BãzßKg*fIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/error.32.png000066400000000000000000000020171370472574300236540ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(-IDATX…Å×?h]eÆñÏ››„¬VŒqÑ\Ü!ÍM¬K!ƒƒšŽº8è$ ¢­±jÁ€Bë"âT0Ò!DRB@+6i¤(tPp°ÚŠ¢š&ͽ¯Ã9INNÎý—ú —{Þó{ßçûþý—;¬Ðj…ox “G#½žÀ-\‹üq•+cTöà:8 <޶¡ÿæo3}„K{X ý.^ÀëžfÌè»6&óó®.sp•37Y‹¼5ÄtKßòH'Ÿá¡Ýšç@>äâw;ærƒ|º_æxõ{^n)uóqàÐ~™g ÞXd¨.À¥dÁ=™ƒš¹IWR~¾ ¯¹U†:é¯2›(E&—éÈ%Z «›y<˜1+>Ê¿ési‘©Àh‘sd¦ÌxHÏ‚Ÿ¸o%·|±cºx>kž‡û3J™ñÈL#sX)XcU^›È”gÿ õê&ïEJõ ŠÌc2ä§òízG“Ãl àbýYä£<ÄUÆq®ÊlÞü,¥%>Œµy:Ó ™y©Q©°—@Ù²zë$ÕeŽA{Z©·QRŒ.&±›!—xš4éÛøß–þô6ðÏBl›Ž e†½®yª{¶$PÍ)¶[GkÛªüÕL­*³ƒIfÜ‘óǨüÆqœkÔN×·„LA-EfòæéVÛœŽ1*/:'rmmv¸ Ö¹¹]«B½­Vo‹Ö¸¼ à)n–jÄÏõüSx.ðì"SE#¡Fî(%Gþ@Ú˹Òˆöyº;¦ò#±ÎÛþ×føqÀ-¾Œü™îlò©±^wf‚jæyKKŒE&s¾îâÄ :ÚyÏô*«ó«œl§ÒÆ»Ùã8ru…ᣰmg)õ%ŸbG˜´¬˜ŒäKƒ\Ì–ï8—¹·’|DöåßíQ§Ê|ž/Ü‘¯ûùoW"¿ï‡kºO™Óà³|Ó(ïÁ|-ðf™¯jÅÔM‚éªÑ./&x¿Ì/õ‚šºš-pww’¿‡ñ„W³ÈߘL—Yn¦í–/§ËôTx £+-¾ùu7—Ó;®ÿy IØáIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/error.64.png000066400000000000000000000035211370472574300236620ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(oIDATxœíÛ[Œ]Uðß>[:㥩ú`H *ÁBé\«Ò¬5xé“>€ÔMLTú%ƒ1š¶j¢Å`©×jcT*Ƥ¤iéÌØ…¢\ˆ&F)ÑZÑ9gùpÎèÌž}Î^ûrÆ&öŸœ—µ×úÖÿûïõµ¾µÖæ<ÎãÿI¿;8ÀÊA®mp9.Ã¥,KXx1á Náœhq|Ãky¾ßüú"À!Þ8À&\7•±x²Áƒ ö®å¹ZIvP«Ó¼«Å-Ij´ Ó »F9P—]j"9ŵ¸ WÖa¯G—°c„é:ìU`Š;ðþ:ßx:#bo“í¼PÅViÒ¿a´Å×ñÚ**â…ÀÖq–5PJ€)¶àV,)Ûqh¾6ÎÝer là΄O¡Q¦Ã> ‘ðöñšUx¨={D#zÜEc;>P”á"â'£Üž!ú-¾›;ÎqçaÓ·i%À$›l.Çiq‘ðñIn,P¿7&y~˜0X‰Ùâb&áC£<šW±§ûY¾ŒŸã ‘·I¿Öù?Êv๥ܰš—zÕëñYqÎ?Þ䦓\y–·à“x:†h O7Ø2Ú“\Ñä¦À±^m.þŸÉ³ÝU͇ysƒŸ&9SeàX‹Opvnù$ÃØ°:DŽý£Ø<ÞÎçò[šp_£-x7ÌnçÉnºŽ€·å9ßÁWÓÎÃ8§f¸¹ã@)ŽÎpsÚy˜àlÂŽI;GéŠL&ykÂ;#86˜êöp§ËŠ0ëü:Nw«3ÄtÈ™ó×î1Jº€["I6Nç(#BŒóðlÄnBÒàÝž/`?¯ÒÞÈÈEB²,b¤!ÖyXÉ;bx6á•YϰŒEæüÀç:x=#Bç'nrg Ç„ ZlÈz–ï1:ÇøÅØ}¡¼º½D(â|§¯Ý «by†.~Íà.ÄU±Fg‘°z€ïv§'æˆðŸUZàØu~€{KL¯×tü›‡y¬`ŒJ1H¸b){ ˆ°9ðhÇù¬åïyí*8®Ìh—J‹–Ž÷‡Í3ܸ΃W§ËÒ\VÖø,ІCŸ‡}šÛ%é²y„ö¡Ee ‡<Ôå<´2ü›'@Âëªv2ÇVeêt¾Ãéõé²t,«££9–¡nç!pQº, *TEúá|½è#ÂPÁÝZÅë—Bú? çîI™çg1wP3þ¥G@­t–·Qó|sD(½ŸFÖ Nÿü¥®ÎŠ,o»!kÙ\‘ÓŸÓeéx¦¦Ž ûn¨9N¤ æ ÐʨPE†ýA†Š,›k‡Þ4*vP&««’EEƒG2Êþ‹“ü/—1^6«+›E– øòó<–.œ'Àƶó TÊCÑaŸ^ä”É"K„Ñ/7k!ô‹‚†Ÿ*²“Óm…×É"ïA[„èׄ²Êp†}ÅÆ—êJi‹ˆ0Ω_Ž!øg‹}Yϰž¿áÁØåá¼JEÖöEDx‰ChFØüeÖá ]rAvå8Ð>¬üBN½2‰M¬%ä‘ „fë3™\ÃïEÜÇK|O{1U²º.aMÄñÝþ Žw{Ø5LØ"†W`Û\.Ÿd¸jJ;+BÖ¹Ãí½þm9&fZììU¡«cü!áÛ$¯:Í÷1rý L²>áþ:òùŽûs]`É},™fä4?ȳØ3ÁS9ö»c?Ë—ò³Øˆ@³c°_×çš‘§ÖϾ‚÷Uº ±ž[|:vZìëçÝÁ%‘ÎÏ`kžóDìMðxÂövç ¾8¹RŒÚc¾U‰ÕâáîQ¾[9zOpÛ{ËqZ4üx”¯i¯¾É¯ÿÄrGL羳ϯï×UÙ¹˜jß Ùê¸,Ý™yvŽqO™ö¥ïóM3ø†ÿáuùÀÉ·NDä#ÝPéBãc¼ú,Û›ûƒ‰?dÇÕíä­4j!=ÍH‹m}8ÉY€À# ;Æ8R‡½ZßÚ$ë¶ÆêþhªmÞ®*_‡d¡/ÃvšUM>ØàúÀåeÄèÜ >ÞâW {Çùc?¸ö=n§Xñо¬xiÒ¾„1¬}=¤½›t&´÷Ot~¿k1Yõƒ¨ó8óÈÅ¿lñeQ€IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/ff.128.png000066400000000000000000000026531370472574300232120ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÉIDATxœíOhU‡¿3F\)"Ô*ºìBE·‹‚”VЏQ\Y(u[DõÒ‚\êÊ"Q7±’¢‚q«¨›‚ hÑ.„B!êqñÞ ©MMÞëÜ9wæü>È&!÷žï½_îÌ9y „B!„B!„B!„B!„B!„è7¶Ù7Ý}Ø< <Ü Ü\¾¾–Ìl­£:;%“ÿUp÷}ÀËÀÝ[üî*pÜÌΖ(,Šlþëp÷˜M¹Æðº™]j³°®Éê¿1óÀá×Y^0³ïZ©*€¬þ ¬{³ÊÜ|ìî‡Ý}ÓûŠšÉìoî~#°ÜÓÒšß/šÙ…–Ö+JvÿxŒöäv§Ýýá×,IjÿØ[`ÝÛ÷Ý}~üV3©ýàþBk£ëê§î~o¡=Ú µÜQxû€ÏÜý™ÂûÌJjs÷Ÿ;Üo8jfv¸çÿ’Ý¿éx¿ýŒnêxßZ¨Î¿ëÀ¨gþÄÝŒ§oÙ¨Ê?ª€€#À)w/} ®‘jü£¸øÜÝ ®#Špÿèܼçî¯ÖÞ3"Ô¿†À¨g>Hå=sAÂük À„ª{æèÜ¿ë9À4tÒ3g÷¯íØHu=sÇtâ_s ²ž9€âþ}xQ«é™ƒ(ê߇L)âß§€f­û÷- ™A«þ} ÀÍ Zð¯y0 3÷ÌÙýû|lD3ƒý‡ÐÌ`&ÿ¡½PšLé?´LÐÌ`›þC hf°-ÿ!43ØÒè˜0陟Œ.$ˆkúg À-ÀÛîþZÒ.aSÿŒ/ijÀÑè"¹Â?cºûžè"Y÷Ï€cã‡Ae嘻ÏeÀN ó)°Ø“9¢ æ@öìŠ. ˜]Ù°#º€`vd€GLÊÈFV£ f5{ÎE̹ì8]@0g2`XŽ."`9kxÅÌþŠ.$ˆuÿ¬8efßDȺÆ|¼]D WøgúgÈ%FÏõ_ˆ.$ˆMý³à'ày3û%º ®é?ôK€3:òžJúæoé?äà"ð’™}]HÛòjzõ¡ ضÿÐð7ð.ðŽ™ý]LSû)½ýখ˜É(7‹À‰ßü™ýû~¨·¿Nÿ>@½} þ}¼¨·oÑ¿o'€zû–ýûõöüûõöýk€zûÂþ5ߪ·ïÀ¿Æ@½}‡þµ@½}Çþµ\ÔÛù×p¨·ô€zû`ÿ¨¨·¯Ä?"êí+òïú&P½}eþsÀeàæÂûÔÜÛ§öo€? ïñ#£ÔW'?&µèÀ8pxÚÌÎÚ£ Rû7À—Ö½$@ èJÚ—4í1– é•Ý.%Í;BäòU µ\KÚp°ø†³I8¨rßÇñ&iàlð ÌÆðž-Õg,à<–÷øvÍì4–÷Â>°mfONó_|• ˆtäëNó\>tïÀž™Ý:Œ ù=ÒýzsšòE¾€càÈ̾ÆA|ƒt<­Lý™ô <Eñ p’©]kæÄòÃGiXœÒ(¾V­‰êà;ÁŸÇ|:)IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/ff.64.png000066400000000000000000000014641370472574300231300ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(RIDATxœíš¿kAÇ?sj£ØXX úÄÂÖF AÄF± ±„` ¤±Ma© üÑ ZÔß_F» ̓ΛP<aÜpÃÌÌÌû'ÔߘÙÚ]SÚÞšåô&Ü?¼tö”v‚vq\¡ì%Cý•J¥R©T*•Êã/^7ÍìG“„IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/folder.128.png000066400000000000000000000014621370472574300240670ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(PIDATxœíÚ¿jTAFñ3‚‚yAMéB^&)5Ø®o•V\ ‹ø2Kb:A´—b1»þC„™uïÞÍýίž›|0'»E.H’$I’$I’$I’$I’¤)(½ÔZ§À10n{Ôº.€sàm)åvä={­+€Zë#à 8fÎÖ-W¥”ÏcÙWͬÿòßqw.ÿ‡ÀËRʧ±‡ì£{gO¹{—p¼®µ>{È>ê àx°Ã3‚è àÙ`+vãxSk}:ö}ÒÀÁ`+vç «O#Xë `*Œà7‰€ü”A|¬ÄF`¿DF`Š‹ÀþAϯ†¢Ý—¬ÞXô¾ÿ`Ó²楔/­ø0-GÀÙúÝ&0=GÀóÖÃ0M'­ `šf­ `ššßÝ0€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂõp=Ø mÛ×Öƒ=|Ø`ˆÆqÕz°'€ó †hÍwÕÀXöoÑŽ-YÝU“æJ)·À#ØgK`^JùÖú@éý µÖûÀ à˜½?C[u \ïEÏåK’$I’$I’$I’$I’¤éø^ìnì|ÙÈýIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/folder.16.png000066400000000000000000000005351370472574300240030ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ({IDAT8í’K @P@Ïņ” ,ÆÀ‚ì©%0VÊ@Ù‹LtM”¼ù$§^wpzçN.|¨ª„†BD†3ˆ,¾’£ˆ·LwÇ@¦ª•Å5"Òyaâ/ϤbçD`àI€?° L7þN°R ôå¥/0g\éÈJIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/folder.32.png000066400000000000000000000006041370472574300237760ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¢IDATX…íÖ± Â0EÑû¢DL €ÄŒÁ¬ˆž&¡'ŒAó(¢D.M’æÝÊ…­d¹087sÑ-$ÕÀ ¨2Î5À1"ž¥€E²Þg¨‹¤í˜€Õg7ÀUÒn,ÀÖÀ¹±,tˆ›¤Üýoà ”ßÀ*Ú÷Æ\HÞÛ\€> 0À HŸ çö³RÀƒö³ùï^À}‚9ÎåõB ©îà%IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/folder.64.png000066400000000000000000000010151370472574300240000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(+IDATxœíÚÁiA…ño‚!Än$-dÓDð¦ûØÜ’*¬!}¤XBrºdþ ¸³o`ßï"ÌŠûüô ˜™™™Ù<¥ÒaÎùدÀr¤{€=ð‘Rúé5ïØï•îù ¬[‰ðœwïù|土*ÞãfQ€±>ö‘ðÙB„(Àšˆ  DPq„€0Bô5ø3õІß}Jéÿúb+Ÿ€š–œ~ÓlJç`ðV:œS€çÒáœ9€z€š¨¨9€z€š¨¨9€z€š¨¨9€z€š¨¨9€z€š¨¨9€z€š¨¨9€z€š¨¨E“®˜Æoé0 °¯8D¥øžÁ“ûócGýÿ Övù‹®zˆ™™™™µämÙ3~Ž–ûIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/hand.128.png000066400000000000000000000064671370472574300235400ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( UIDATxœíyUÇ?¿%B°äà€TH8$Tà.Áû…Š ÁB9J‘R <@¤(ËÒ€ ¬„äP‡‰\b8²$„M qwþñëÙLfg罞éžîÞ~Ÿª©š~Ýï·ÓßyýÞïýÞï TµØ˜ìl Œ¿¼ <,žÍÂΤ‘¬ ÈUݘ œìàyÚ+À;D¤/-ÛÚA© ª“±¹[“—X œ-"/$gU{éÈÚ€¬PÕÃßÓü͘ÌSÕ#“±ªý”²PÕ£€«IîМ)" º^Û(Tuð[`D—~8YD'|ÝT)´Tu 08è&ŠõÚ—‘%QùaÀ_€I)™´8NDz›±/ )UÌÞïyÊsÀ€€‹Ò²+âB`9MØ'"÷¤fÕ Jª:¸Ø¿ÉKô›8ʬnžÄÆþÛŽ6O ŽÁx8OD–5y~l #UݸkJÓâ?ذð­AŽoœ 옢 Ë€9"òlŠuôS¨ê¾ÀÍÀf)V³k¾»åÆß#ùNd5kÓDäéë àPÕ Àµ¤{óæá¾ù+[S¶epªn—r=ùpæ—O›E1Ê>™š\žv%¹€ªÎ¤ù_¬ªðûõWx;-Cj8DUK³‚ai^¼TU°¡”‹àNàQ  ë׌ŽÁ¯GÞ½|é‰Y¶ûæ÷Ǩ/¹íªêTl8ÖˆØøþõAŽoœlå¸N/ðùæ p£G¹¤ì;ZDž÷7ÏŸ×wÑ4yÀŽãwÒøË­°¸«usb“¤}´nN}ò,×è‘×ú[+†4I’öwoš" `yŒkuµbH“$i߸V iD.GQ˜V#O[/ð¿—\ßšE±IÚ¾‘Ðÿ½ìÍKtb-ƒbîã.,fñ‰Êl¤¹@`¢ªß޶t”}[Uç׊Èk® çùØ@p"î›6¤<X ªßRÕ†.ô €¡Ë¦Àç€[TuÐhç €¡ÏL;Õ;P¶~©ª!AåaW,Ža#‚ÊÅQªzpõaXL–a®f&ã·Èå\,ö(뀟Oa  Ï÷ûsh=5]Uw‘!<ŠD/p¹Toe²O`QÓ®•ËýKÙ‚ŠÃ]€Ï"Ô%€k‰Zÿìb@qx Á²*o‚ŠCœÙE×Â’þ™Ö €bôìâ¨Ê› €’Pr‚JN@É (9A%' ä”œ €’Pr‚JN@É (9A%' ä”œ €’Pr‚JN@É (9e€b¸cMÆ×ËŒ²àï Žý#×Ë„2 `¶'@-ÝÀm_/³¥LX |xû²×bI˜¿C¼Lái]/“%—É¢£|xÏ5(7¹s \Œ®ù¼¸˜x¢r%³î‘Ý!äÈ•å,$XâÇÛh®Eñ" _¬®^m¡L}€@¼[€è¹¼ð1`_l³ƒqXõ]à%¬³òðhœ|µìp @U‡³€3©¿åê˜è58(ú¬[Uïþ < "q–6ÚHC¨ê®À°l“qØ8>z­RÕ»…À½"Òh¼h3ƒ @Ug—áÞ*ÕÅ6ˆau$†ùX˰®ÅkZ¤®Tõ,ÛT³{àÆh`vôz·J ÷…–!@U§?$ù›_ËXßb°VUïöv¿x/åº @U7Åv«l·`ptôZ‡¹Wm ÖðI`r†T±90#cJCÿ/=çÚ㜵À±ýs—c~çN`*–¯v×äÍ ¤EuS8–t¸/cÃÂÚ½s_^ ­½€ã—¼8!ÕpmÔ¸ÛÉ{•£Ü[Xââ{±®=1Q\_B  T `?GÙ[pßüZVbsä÷cþ€Šö §SÑe£Z-e,j±®UXŽû‡0ÀžX«3ø“R…‰¹Ë;ÕÙ œ’ìœôjlÓ‚‡£z§abØ ?ÿCabîòŽïx_°mÈÒpÝ®^#±Ñć°™ÇzbèÆ½­|À“j¼ ìÒ ìNX.ú4YƒEÁ<Žù¦b¹í§c­ÐcØteÊv”†j¼Lc ü÷nI±Ûã‰6ÕWJª;_®M¦3S´%Õ¸÷¯ûØ´n ú "¯bûÒ¸8 Éž–QöQ;þ¾ ‹¹wqp66‹(0 ÚKî§žçî|óð J=Ü5øïP5 ¸ˆªMˆ¹ÀåYíoå‘>,ø~ÏÊ:±õpa8?¸:éýWu•ÅçÍÁº}|óï²ÇåáíßUlЦ"Šåÿð‹•~8³| =F9Ž÷Ïë4|VˆˆŠÈåXx¸P°°²à+È–ÚƵ¬¨¼ñš†‘ë±_·ï ŸãÏŸfÅ6Žãñ "w`7µ^VŒzœCðdÁ8ÇñW*obbˆÈ#À©¸÷¦­Pñ¸š¤@²¼Ïqü¥Ê›ØËÃEä_À‰Àóž§LÂ2\tÆ­+ÐØ¯ý÷®©ü"òp26oïC'–ý¢Þêâ@²Œ£qtW°¸òGÓ "D¤ð'ÏSF²!ýI ¦:Žÿ³zQnKBDd=6:¸Éó”M€¯`“It8Àq|£ld-§ˆ‘>ù.p)Ðçs ðl¨RÔ$K'°»£ÌÝÕ$vDä×À\âù >Eú«Ë„«e]EMDu¢¿@¹ yÇó”_¥õ$ût”™/"=Õ$Þ‹ÈÃÀIØZAöÎ'Ä´ÊGp;Ýn­ý •g°ˆ,N^ð  ­söª:*úÖ;ó4úøÊÆØDÛÎŽr/¯íýWh{Іª¥ ÛÌó”0OcÝ ¤t_ÆíVïN‘Aûam÷ĉÈ|àKøû ÅÜÇÁW` Ãæ`|æTnltó!ð-U ü Ë1ìÃKXþ¸YJ†Ã/âö÷ƒ ûf»²±f·§ª;7à?ôë®ÞLͨü2 ÒõI¼µ8UDžrÌ.Æ9—‹ˆo(>ý‰*/NqÚZlñÊo»V4K«w:îÜÕüND.ˆ[Q®PÕ3€s‰gÛj,oÐ#øG-畱p»i1Ïû pIÜZr'U-F‰›ƒ xó,¢8¾ƒ¬#< ËÄ®‘Ÿ4Sq. ª‡`KÕ86â,©Ô“Xn£<öFcû/Ž;”»=À"ò‡f È­Tu7à:ÜîN½À³ÀÓ˜?a)U $ÛÌh¬W Ѭ3n)0WDí8ê$×PÕ1ØŽš³¼l/æ(YŒ­’yË|žÆFc°{“°¡îÎ \óàbi¹¿“{TPÕÀX')-º°ty]X.·0Ïc7ëØƒ‰ç=ìÙ»öŽÀU£°uy°mõvÁ6ÐJŠ•À¥"Rwj· #U†‰Ï"]!ä,Y÷•"’h’ÌB  B´µÍ)˜_Ü•äºÈ(¶‡ÒeQþ¦Ä)¤*¨jÖ™:Ûoh¨Ìöaû-\#"O§YQ¡Pªn¹MŲŽqÑÉJ̽}“ˆ,mG…CFÕ¨êX,ýüØT®”)Y²Û%íV`A»·Ù’¨&ê/Ldž`ûF/ŸYµ4Y܇eb{PD|ƒcgÈ  Ulx6›[ŸŒ¹a·'ï£âsx óJ.ŠÖMä‚Ò `0Tu$&„‰X”Òxl­ÂDÌ{7ëdnýÝùs;/Çrï¬þ‹y_^,"7ü­tì™ÿÙNñIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/hand.16.png000066400000000000000000000010351370472574300234360ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(;IDAT8¥Ò±KpðÏ;"M¤¡­ÍϨÁ- §qÈ"‚V¡ÁÁ¥ÅÅ!hw¨é†&!¸©1¨¡ã("! „ê{þ”ãîÂ;úÂã=¾ï½ïï½ßïú 3¯`×°^èg8B+"þœ×Žþ£¹†JÙ(©m´ð73—#¢­u£Šc)ˆ1 4&ÚY@e¥"Œ²Œ/¢1ñ`D‰Š†Ý;ç\ýXî.ßz÷nbâ$_Î9sæÎüïœ93sB”™ ±·TÖn<?·Õ³4x–×å^<‡+¦ˆíÇ:\_×{"⛾dæØˆ]VýýØTçëpQcþÀ“ñj/½C-Uã#ØŽí=8‚_0Þàwåàéê½h¸ ÜX½‰WüÛÐi¬'긣‡Ü2lª¸•pn¿oð¾›A¾—Ü}™ùFf¾ž™ë3s”ö˜ º¤1¿Wgæêùð-žW‚s-–byÛ#˜ z ?(dz»ò–Ì'€‰ó‘ùГþðŸð%~WjÁL¼cSÆã¨Ÿ<ðlÁÛ§DýÓÈÌEx«”Üþ!^ÃΈ8ÒHJ5Ÿns83Gð–4ø«êw,3ßQªà@h+ªñϱ“u½×bå ŒwŒÕù{J]§œÛ>Œâr¥»¹ÊñÁ5g>­ó•x‡ûGñ~ýBCJGó¶RóŸÂyƒ2Ö n»ÖŠˆŽruválÀepz‚ˆ8а §á1\7@Ýþðë¿3aDLFÄãØ‚Sðn€ñS•€î`ÿ ©8"¶à å:Þ‹»ÌòýpZ¦xyoDêY "b+Ö(·àvÜonúÇóqònxŠQDìÄjü¤¼†Æ}Ã#JV}9"ÆiáÚ̼XIÕ*9b>Æo- *±t‡âÅ]X­T‹ð,nª¬I|„ø ?*eøOåž…Ÿ7(gžx›"b²«{¶Ó¸7ûçx2ê(]ðæˆ80uó_Ewfž©ÄÅ•JáZ¬$±³•zrŸ(õe{DœN×_På½?œHIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/hand.64.png000066400000000000000000000032551370472574300234470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ËIDATxœí›klUEÇSJh‰ h¨ ÆR‘Œ"Љ–ÐĈZi| D¢1‚~ÀW‚DÔÄÔ'Dåƒ è1&­/Ä€¦Q@«(! EÀ  )­”ñÜ[ÎÝžÛ{νçÜÓ–þ“MîΙ³;wÎîììì¬2Tµ ¸¨ª=òn`ð¶ˆH²I²ñ|PÕ뀧€Ê,­Àù )RS€ªÖKðŠÈûIÈ‘˜Tu86´¯j°?² ø øx¨Ù\+P\™£½•"òw!r&¢U‰}Ý!¹Xœ¾[@‹WŸÜI¶‚Üwü8„’µQe]ÞŸoÊ"¼¶ øÖ¡],ŠÐFpOT%D2/¼a¿´€v¿ µкÃàyUå¥òˆäÃ\²‡ýØÐÞìÕ§ó~ûz.‚hùÚ;¸x)¬À±ŽÌ@ù±hÚ½ò%ðfí‡iÏ•¡[Ä­€j§¾)€ç›"ÚÓž+C·ˆm ¨ªƒý$lȺ¢…ê"d{§¨j=0S†¿`žåi÷3ÇmzxÖ¡MÀ|ˆEªºXD:GMÜS §ãL`¥ªNÏN6 –©êPè›Sl }؈M‰‹€:N|ðáØrÙÐWGÀ[@#°Ø|¬txfBßÍ´¯œz5ôM„^.¡o* ú¶i£_i 6ú¶i£_i 6úBŸŠmR2Ø_$_QHk¼ðÊEò¥¨ØF¼˜à? Y—〻½ß¯9rd dGUDÆõ•€ÈàB^ì¢/T4;t˜äñìÂbð߉ˆ,jC–Tu6°8Ýá›è•À^Umš€Í"r¼‚&…Nx±ôgÈoFó¼²OU?ÆÂO“1Y”¨êhàq¢Å*à6¯ü¯h¥AfÌ#;M¥ ,¶Ç0+;¸„Üé,î´éÈ(àr‡þ*ÙÇÓ[½òpvv?/®Ö›‘QÀiý§üÇ€Ÿ½² Ë e uxñÜâFF­€?± ’ü‡˜Øú»Ë÷ƒ)cæ-SФQÀoÀ(}°&B;ÀN¯¬ŽG´Ò ³XåЯfsì3°Øã<«ÃÒÜ”T¢£ ÀK¸psíj…À ÒŠ•ÜÙ¾!."?·{ÆóGèjå{Üxœ9."Û±ŒLw;Y< ŒHJº`°Sïªù¸øÚyT<‰9B½#ú¯ÃÊ‹ÈaÌ=ntUbÓaRÌ•g;õmÐÍ2çÆû±=Ř÷×›0Í©o<뼈‘§±¬+D€»€kòµÑC0ŠìÐl€Â‹È ,q¹Íyt6Uzzhm–S_/"ÿ@„¯'"MX ûçÑe˜¯6÷¿Ô…ÉèG§çiøŠH3p3ð§óh ð¹ï¤…r,Œçw‚¶`Y£@óWD¶ì+Œ£çø eÀ­d/Û ¼àêdÀDäwà&º&*WO1a90ÛÕú±ZD6¸ŒCU/W9ÚWèz ¤¨À óÅ};P/"ÿú‰EŸ ©jJŸðxW8Xl?!13Ôî4ÜÌñFnâ<[<Ðfð°K[O⡸3Æ.öóEdWЋ±^šRÕ«1§ÉÝxd°Ûcü€Ý=ZDw#€ÉÀ¥˜‚° X("9ã“I܃مÉ!Øwca´=ØÒz8ŒÅ#Û0#]me‡gaÝD`t7í^D$èîQ'’º7(Ø…û€ñIôÑ >ž‘a˜¿:«ªb~Ã,’s”ÚOå"t/'JvwXU˱¼ýZ,|~Åí!Žb†µ X+"®‹ i^ž®Àæòxà\lnWg`s~f {å æ}nÅöò[E¤µX9þy1iTÃÍàIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/iconview.128.png000066400000000000000000000016241370472574300244370ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(²IDATxœíÝMjQFá÷*êt.®@A³‡ê8ë ]‡‚h ™¹]‚:W ”XªÀQuߪ®P?ç<ãÜä~Cw2©/‘$I’$Ieè¦iî'yšäq’»InN}©‘~%ùžäc’óRÊ—)¿ùVç® išIN’wUÝ‹ð:ɃÑW›Çç$Çc# Ì][ôIÖ÷"$ÉÃ$/8¿ù¹÷¾tŸ}ï³ü·¿>—Iž”R¾9D™»f¸g•_·T×Óþñ6bîš~—Ù8ƒ˜»&€;\dncf@Ì]À­ .2·Û#Î æ^ógœ&`pgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpWÀÅ•ßâêýq1wM?&¸ÈÜÆÌ€˜»&€\dncf@Ì]ÀyÚgЮÕeÚ†B̽7€îéÓ§SÜh&ïJ)߆¢Ì=äaѯÒ>ƒvM>¥}hòŸ1‡ sWýØ=uú8ÉÛ´o-Kw™äMøå'Œ¹Ç,Œ¸—ö´Gi',åŠù¿8álÌÛþ.Ô¹%I’$I’$IÒº¹=¼ÒVçv{ø[ŸÛíá;æv{øn›ŸÛíá=(s»=¼bn·‡÷CÌíöðiÏ,ÛÃ;nï±æÏ8MÀà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îà Îíáýs»=|Ú3KãöðŽÛÃ{¸=¼bn·‡÷ Ìíöðs»=|ÂÜn¯D[’$I’$mÇ?†8öaLøWIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/iconview.16.png000066400000000000000000000006161370472574300243530ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¬IDAT8Í’1Â0 EßGœ€ 1#!g``æŽ]+qDOÐæªá é€+„ •P–zròlçG߈1–Àαœ¬¦Ž×’Îs;øf€X[î›ö³ÿEÆt„‹vÿ´ÜGoVÀÆ´’ã[`éx#©û‚Fµ\ù¶*G«¹$I‡aR>‹×.üRSÀ”lÌP'XÜé=¹å>@å#èù»ÁKIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/iconview.32.png000066400000000000000000000010311370472574300243410ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(7IDATX…í–±JC1†¿ÓjKWusÖ'phÅ:¸).>…“›ÐQû"‚Ø­Ëñtu»\…^/ÇÁDŽ…šŠæŸNNî—ÿ‡p“À—øBUws`5ÀT@œŠÈÔ±m`ôå?"r;àXK&"—Ž=.ØRDº ÓL1X_Ûøé«ßPä6@•ÈNçÔI¬ P$,ðÜ™ñ=P'ð7¾°Gq 86ðPˆÈ³mªê&ŸwA'À¿#dÙ-hÀJ€©Gy²MUݶf€ÅlÁ’™ûq¹©UõȇpæWæ^;À |ÿ ú‘0ΨgÆÝs€=_Ø¡—̬Zsê}yý©“0Èr€I"[.‚µ‘ UÀ™ÞµëÅRJß¹kg?˜ |/ „ÿçhç$(²Ÿ‚… 0½÷=3¯ž h ¸ó–™UÏŽ,ñßåØefÕ³#›ÂÔÔX€º€ PPcêj,@]@¨ ¨±u5œ …33³êÙ‘€®p‰¯Ì¬zvt+ü œ(s9y)¥k4Td?|Óµq \€~¡ð8GÖ’mŒ1f‹x=>SÀëñÀëqÀëq¯ÇW…¨ ¨±u5 . ÆÔÔX€º€ PPcêj, 8óz¼p ¯Ç½ŸÁëqcLmþuÒwo×§‘LIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/imagesource.128.png000066400000000000000000000034651370472574300251240ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(SIDATxœíœÏoEÇ?…ZQ©†-൑Hˆ ”1QBø»<`4ÁCüšx!¢ÑD“&¥^ŒÆHð"•`¾vÛ¾[Ø}wf¼ó|’^únŸt>ïìì3Ï †a†‘"nµ$­.SÀ80RW£Œ <æ€ëÀ5çÜü‹rô"ð °7ZóŒ:™®8çn¯ü GÿÍŸÁ:И¦WŽkr.¼ˆuþ ²—¬o—‘'ÀTü¶ ÑÓ·yŒ×Уzú6O›í.=}›'€‘&@☉c$Ž 8CU8ç^ Ñ£?$ÍWù{ÇH qL€Ä1ÇH qL€Ä1ÇH qL€Ä1ÇH q*פޤ§ÈÊ­_ž6ùîw€y`Î9·ÐL  Ð'’†€ÃÀ0œsÉÿ3—t¸éœ{T_+ŸŒ Ð’6ÓÀKÿd8 ì‘4㜻­q%±9@I$m.Q¼ó—² øÈÇh&@ ü°?ÍÿÏù~ØLûXc”c g8 NeL€‚øÙþá€!'}ÌF1г›üÙ~¿ “½:6Š PœûL€ñBGb–Â(Ά17FˆY  YÔtL€âüÕ‘˜¥0Šs§#1Ka§Ò.ÜU¸!f)L€âÌÿŒ·@©JÑx>ZÒVàM`ðð¸ü üäœk|˜pÎ-ø%Ý£BÞhC@cHZ °üÈÚ!ài`+0!éàë–¬£ß$ËV]øø¶zsªÓÈ#À¯„]ò˜ËýgÀ9I?®¼„3dÕ>ýr˜i‰ÐÍÎc%®ßœŒÔ–R8çîWɾÅeùøÌ9×øëß"µ éýF½_ÒžÐíéߟ_Qlb¸à¯ý´MÕ@Pó@ÒnàH…§$ýÚ†oÂoHúlQ'¯(ôO²W½[m˜ðåQ›’¶g+†!{||Q½Eaðû£ÿéµ<|å`]€pc’ˆcPƒ~Æžjut+9&©ñ¥ÔA Žà4ðrà˜CÀYŸK0*U?ã#RøQàH±“!šfüE˜”ôJä{ 4Q4ã/‚NK Y¬™Á<ã/³Àñšî5p ÒŒ¿ûÚ’%ì¡G€3þ¢œò£Q‚`Džña1Kh” ˆ5Íø‹`YÂ’T ÆQ,KX‚#@3þ",f / é!þI­9ì` £´ã‘Ôzù[bY ²–%,À –%|"ï ¨}’æss1o²dÃN²ý È*€¾oËþ†•¤ Àû’~sÎÝXÒ:à=à-–—¸¯%ÛÛ°8(é;à˶”ƒ/2è€E¢d }ä2½›[ò8H‹N[$^ ™%”tø˜ì4ТŒÑ®¤YR@€,¡¤I€dÃ|YöHz»JB’š•j %í®PýÀ¨£’vUŒ„Ô€>j %­ñ« s®>hÚEŠ@‰,¡¤ÍÀ‡d©å'MôÊ0 œoú°ÈT(”%ôËÜ—í‘Ú±˜’R¬R¤*<&K(iHÒ àû:¼ù«’²SKèŸË—¨÷0çIIý옮LêÀ’ZBÿn™,{W7g$…8‰¼­ÊJ5ÄÙ«á¿dQ4ÅÙI(Ws×uS2vÒlç/²™ìÍ ¶=&@ûØNKØ&@;9 i72ÚËÉ:JÚL€ö²†,IôLì›íeY A´²{ ýl#â–7 D«!0ºC” ;D©!0ºEð {­!0ºI°[ ì.“’nW b#@·9]5€ Ðm*gM€Ä1ÇH qL€Ä1ÇH qL€Ä1ÇHœž5eIóM4ĨçܲãmlH qL€Ä1ÇHœ<ÔÞ £.zNÉ ê±êF£ÜZù‹<®×Уzú6O€kÀlü¶53KÖ·ËèÀ9÷ì@d“`p˜®ø¾]ƪۋ$­';y ';NÍèÈæs×kyo†aFºüŠ‘»ìÚ‹‰^IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/imagesource.16.png000066400000000000000000000007061370472574300250330ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(äIDAT8¥’±jBQDÏÄ1_F»€M'XÙˆˆ&þ‚Uš|™XBúT¶B,ü ù›û’‡øäåfš»Ë°³3ì•í:ð@^ð¼$ T I7™´½t‘¸ù¡ä¶0V’Þó\YM  ´Ï:°} 7IŸ9ê#¾ëBxÎ1P&¶·’¾$mù)kùÓ8L´{o[çr \q  ÝÝÚ~¶=,ŒP€¾ík û®íoI˲•Üp†í]Ö¤|$ÿ¨eEëY‚°.ù=aYìÅЬ>Ðm·ÕIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/imagesource.32.png000066400000000000000000000012461370472574300250310ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÄIDATX…í–¿JQÅgýê&¤PPH‰ø‡T)£ˆ¦QdØÂ"uòyŒ¼Ay I!iòé%°‹Mª€V ²93ãŽîõÎ’ÝiršáÞù¾ïœ{¿¹çT Øþ¼&JâíŸ%}ÊœS%‘gèHÚ¨¥ƒ²Éo8'ïÎJZ'«íV~\»/°,üÐ÷ Û«ÀPZÀwIW¥°=¼¥·«ÏÒçQ,o”-XÔ{Z”4J¹Ë¢¤h l¯û$Öy,é4þ ø $fœ£mÀ%`6¦b¢$gø]Äd X0³ Ÿq B$µ3¸ ÷ÒLJjöq,Jræe`ØŽ>—y3[õé¿@Ù§€¤&\’Rjùp X¬Ì-‡™­¯}úH¢’p8ŸÂ4vA)KI£¸\< LHÚï4É ©t¸^fÿ]À­2ÛT•TH:L»•VC’.WЮ*$ ]ñ­ãŒK:âÑþÀH3fð¿oØÜóìã@H#À¹ŒÆê“4’Q_™QíZ`,Ê sCµ·Äšû’^šÙvš’ŽãVŸ³¸‹ð*ðÆÌ~dáPˆj°%&"i÷ÔÊ®öïÀI³ÑÊäM¨r¸d–(©UÒ$p—ýgið(Z¡¼%@Ñ,QÒÜQOʺqE—W !7Dve‰’,Z%“~ÙíÆ|œ}_`HÒ ð˜ ]‘µ—+’¾›ÙûJ-À8 Ü>B¥Ü–ôÍ̾–Û0{‚møî@ÎHê*·aÈŠNœeÍêZà4néLM­ æ¨EnF8‰ÔªaËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<HIDATxœíœ1‹]UF×6FÄÂ*I£…}¬D„4±LÈõ/ø'ò% b)±‚!?A4Õ¤ËFcv ŸÛ7oæžsö>ç|«Ÿs÷Ì]ì»æ>fŒ`ÜÝ£gè3³%_ÿT©ADŸH€É‘“#&GLŽ˜ 09`r$ÀäH€É‘“#&GLŽ˜ 09‹>Kîw? üNá?2³Ÿ¢‡ø ?|IŽïõ.p=zˆÇÉðC©Š»¿|=ÇŠ«föOô3¼Àà™è!¾‰âIfàbô+nšÙnôO2´îþ>p*zŽ_G°Ž¡¾ˆ`Å}àZôëVw?œžcÅwfögôëV`x6zˆ)×? ü"ÈÝ#ÇóÿW3{'zˆ½r$‹¿ËÑlbHÈßG±‰áH?˜Ù½è!61œ(þÄPèîÆ¿Ÿú½= ° ¼ef£ÙÄhà49n>ÀWÙo>Œ'@–øûø6zˆmF€dñwÍÌþˆb†€\ñw%z€m&½ù» ¼ÙÃóÙÉÞü]éåæÃ  ø;4Ý  ø[F÷ ø[D÷¨ø[F×@ñ·œ®@ñ·˜nPü•¡[Pü¡ÛTü•¡Ë  ø+G— ø+Fw(þÊÒ(þŠÒ]*þÊÒÕPü•§+Pü§uèFUè&uèb(þêÑ…(þª‘^Å_]Ò €â¯*é#PñW—Ô@ñWŸÔ ø«NZmH+Š¿&¤@Å_RnÅ_;R €â¯éPüµ%(þš’.mIµíI%Š¿æ¤@ñCPü…&1¤ØŠ¿8R€â/Œp±„ €â/”ðTüźñD?Á„  øËAäØAñNX*þr²yˆz(þ’Ð\Å_."6ÀŠ¿44@Å_.šnÅ_>Z?Éh&€â/'-7ÀŠ¿t4‹@Å_NšlÅ_^Z=I©.€»¿@žøûQñ÷Zl€s䉿ËÑd£zºû/À»µ¯³Š¿5TÝîþ9n>(þÖRûp±òùÛ¢øÛƒj¸û1à“Zç½ùÛƒšàcàùŠç½ùÛƒš|Vñìƒp¸=DVªàkœ}¨µ>'ÁŸ¡øÛ—â¸ûà|és‰âojl€Î= Š¿}¨!@–ßýo?G‘¢¸ûKÀ™’g.à’™yôÙ1w¿¼Qè¼ç€— µ”;Àƒ×ùÀÌv\§ O¯¯GRW]çh£ëT!úÿˆ`$ÀäH€É‘“#&GLŽ˜ 09`r$ÀäH€É‘“#&GLÎ#5i‹Š^È·IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/italic.16.png000066400000000000000000000004141370472574300237710ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<‰IDAT8Õ“1 Â@EÿTLbËX(Xx «\(•w‘©|6:†°c*_9³ÿíòa­@œaÛ’´(9<Å—À/$m$õa}|ÛOìùdªâ§]´™ðxA“œCø’ ¯kœ2‚ÃHyuFðçåõsÊÛýRž›¤eÁ+Û÷8œýŸf‡ó48úÕñIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/italic.32.png000066400000000000000000000006011370472574300237650ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î<þIDATX…í—MjÂP…Ï­ Õ‘óй‰ºgNëÀEˆ.@º g:j‡:¾Nò@Ðä¾÷È# ù ƒäÝœûwÄäàŤ`fv{ÿÒ¥xCÙ[Úù&¥’¿W§€eŒVî >$œ˜M¦v;À89ÝÅêåL`!©rb>3tãöN÷À¬Tòó­R4SWc¾u¢f]›/2Á|š/»‚ç3_ fƒùŠ˜/à­àyÍh›@ïæÛ9ÝÿÓRÉ«Òæ 4­à]=šÏ€£Óý¡«||KºÝ¥Iš;ï]$Î*3k:»c\'Ký’½Ö×#¬áùCzÿ5ë½€ŒVFõ¡šoIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/italic.64.png000066400000000000000000000011711370472574300237750ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<öIDATxœí›½JA…Ï b!B"Ú[ììímímüé} ŸA°V_$•X ±H‘«[$º{ÏÌdÙùÚ$wîž>¦YC’ŒÎH‰™ÙªÏ¹YWj¥(M  ô¥©”^ w<$¹`ŒÉ=Å>%p `ååäÜ›ÙT±LVHI~ÿ}’aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<éIDATxœíÜÁ À0 ±ºûïìÑG ' ¾§ñìî>d½§?ÀYˆ@œâ'€8Ä Nqˆ@œâ'€8\fÜh³'€8Ä Nqˆ@œâ'€8Ä NqˆÀe܈³'€8Ä Nqˆ@œâ'€8Ä NqˆÀeæïî œ53¿fh#(Nqˆ@œâ'€8Ä Nqˆ@œâ'€Ë|Šüq»2IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/justify-center.16.png000066400000000000000000000002601370472574300254760ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<-IDAT8cüÿÿÿ %š` ƒÑ0````„1H FFFF†aU¦ˆÔìªIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/justify-center.32.png000066400000000000000000000002761370472574300255030ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î<;IDATX…íÔ! ÁÿÿsÐà™ neMbÚ6ƒÖd¸¤$Áø¾€äX@â>¼ÞàÈÿ Ha ÷gŽ.IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/justify-center.64.png000066400000000000000000000003671370472574300255110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<tIDATxœíر €@ ALÿ=› \¡Ÿ‰ ö/BžÝÝë`wP3@P3@P3@P÷€Ã ¨ ¨ ¨¸Ô5Ô5Ô5Ô•ùúàï÷‚™y}ãñ‚¨j¨j¨*–1 _DwIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/listview.128.png000066400000000000000000000014771370472574300244700ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(]IDATxœíÝAjAGñ)šè^<‚æ .ÕuÎ!YzÑ€Ùyzu+ž@"(c»èAwS_ÇÎôŒïýÖÕ¤ ^zf6õ%’$I’$‰¢M}`†;I%yäV’ësoJ“|Oò%ÉY’ÓÖÚÇ)—†áZ’ã$O’\™òG´5¿’œ$yÖZûQy Àúð_$¹{á­i›>$9ªDPýO>އ¿Oî%yZYØ}¬?ó߯×þ¾Y%yØZû´iQåP×i·\Íøe}£ÊÁÞÿ÷½h!‡½•nΰ-£{v•n̰-ã ·ÀÏv8€38€38€38€38€38€38€38€38€38€38€38€38€38€38€38€3¸Jç—¾ ]–o½•¾Î°-£{v•ÞͰ-£{v•N3ÞA«ý²ÊxvuXß>}2ÇŽ´U¯[kŸ{‹¦\ý<ã´Ú}ï3^ý³·°ô3p}ëôQ’W_-ÚM«$/S<üäb#ng¼ƒö0ãÀ/’\ÖyþŒxSyíK’$I’$I’$§‡ï?§‡ë§‡+‰ÓÃñœ.§‡Ó9=\N§sz8œÓõ™ÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÀœÓÃÿoN‡sz8œÓÃÁœçôp0§‡C9=Èéá’$I’$©ä7çƒ{ùífêIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/listview.16.png000066400000000000000000000005151370472574300243740ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(kIDAT8Í‘1€0÷¢€)xD C€†hU†´ÿirýîÝÏCcsÞÅÈFI[Ü®v) °N?‚ä`_ø¿0Á(¸$=-'¨^p£Q$­e˜ §76 ¢ƒ=[Ëø§¦±o)OdIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/listview.32.png000066400000000000000000000006461370472574300243770ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÄIDATX…í”-Â@Fß×ðã1€ÃrBP8¸G¨DsAp,®U ŰɖP;!é|j²;É{ÙÉt= EÓ4+`Œ3K —ty¸“ÄðBÒ ‹­àÓPdߺ,â.à±@mÈ­> œ ΡˆWñسÄð;p”TýjìFâ 0JÌ| ]€ubxÈØAûn@ßH –4‡ö7´‚·Xµ ]À\ 4äŸr#‰âÅòðtî%ó42 IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/listview.64.png000066400000000000000000000010041370472574300243710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ("IDATxœí™1NÃ@gÓ‚8D8EÄ(s”Sp”PSÐ"åÔ”’Ú¤°6«TxŸÏ”ß.fGv³DdΔÖp†{`¬€›®FÿÏØÏ¥”úáI€ãá·ÀÝôn]ùÖu„EãÅ ×wxø;ÓS=lXMïã¡´\ú?ŽÛzÐ 0+ Hc€´@¤Ò -Æi4H ¤1@Z ³Cw‹~üÔƒV€]‘ïõ u+¼^¸¾‹Ñ/à±”ò9ž|Çkã5ðìû¸MÊx¥qx™;®Çëëq×ã®Ç/ýŸ?‡ëñ¤Ò -Æi4H ¤1@Z Òi Hc€ÆÌõx‘®Ç]‹ˆŒøÊu;çýÉ@IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/magnet.128.png000066400000000000000000000052341370472574300240700ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( ºIDATxœí}°•EÇ?? ê^›  ­Tò¥ÉÌѤÀœ& D*•JÑš4_(íNcBÙL½0d6 £MÔÔ¤dÅ€SÞÈFÈi0ƒP«! ¡B«¡îeŒ[Àå×»v/žç¼ì>û<Ï9g÷3sçÜ9g»¿³û=û¾û@"‘H$‰‘ª(U}>p2p0Åþ? 8豯/z­É`?ðo`ȾþØeÿv»Dä¿e}‡²è ¨ê©À4`:ðZàx`LàdŽ{ß›DdGà4J§# ª™˜Ÿ¼´"Wþð°ˆü³"?¼é¨ê8à|à]À,àyÕzTÃ0F ÷ŠÈPÅþ´DÛ @UÏæs0ív'°ø °ZDž¨Ú™F´­Tõ\àzà‚ª}ÉÉàë"²¾jG²h;¨ê›gWíK`~¬~."Zµ3ÏÒ6PÕs€O¯«Ú—‚ù-°DD«Úh¨êx ¸ŠðC·vE~`iÕ#‡Ê ªÌn^R•3Ü ¬‘#U8P‰Tõà+À9U¤ß†ü¸YDž*;áÒ«\U½Sý¥Âa*°VUg”pi5€ªŽóKJ÷`'f.ÿIûú4fÞÿÙ¹ÿ6l/#k½ÀdÌúÁFÖ^X‚Ï | ¸CD—^9PÕÉÀ]ÀY&³S•nÂÌÈm5ܲý•ÓYo˜J±“R[›Däo¦” »PómàåD?<€iR‘áÒ¨AUÁÌS\ ¼_@2{ŠÈ“Äý €Û˜0Ú#ÀàÀz90ngìÒó àÝÀ[ Û¯®-rΠ0ؽ¯1²æž—#ÀCÀòv]†UÕS€…ÀÅÀ1¢>""Åw…@U/¾D˜LîVˆÈŸÄW8ªú*àC˜Z!Dn‘ˆë(‚ ÀeVæ‹on‘íâ*U} °xC€è C×A`—nïÅl»ÊÃfÔPÙ Y(FÍx~˜˜3ºÿ‘-¹³€ííŸü¾‡€OŠÈ`~¯ÚU,ÃìdÊÃpE¨ÑA¨êñÀàe9¢9,‘•!|jGlm03!66GT{y"òt^Ÿr ÀÎð­"ß$Ï OD~—ןNÀ6•ËWäˆf+ðÞ¼3†!Ƭ‹ÉWøO—ÅRø"ò8¦_°5G4gËëK.ØÿüQl®ªzM¼ Dd¸øEŽh®UÕ\} ï&ÀÎï¯Å¿Ó÷#`qY‹íŠmBoÇLù0\""õ1öªTu ¦ ó-ü~ÌÄFÔ… "‡0UùZÏ(Æwئ3¾MÀø¯çoníôñ}Hl^,¿9˜ \æ•¶«Ï®^ì‘Þã˜6ÿ@Ó¢ª=À=øý¸€Y"ò/#Ÿàãøþ`A*üúØÓD ¿x˜Onq5r€¿¾Ç5Ì<öͶç›h€õ‡<Ì/WU§ó- Àv2–¸ØŒbi»ìƒïìq²Û=LÇŸr5h•øÚX|ÇÃ.vî~êa÷zU}K«[îªêÜkí.ì¶…²ÈÑáÞ,"W¶°¥@U§ãwVï‹©ðý±}&Ÿ¦à\U}c+[m>ìáÄfà‡v‰£¹s°Ô•–ʬ©lϺcâØ´[ž7ávb˜-"»lM°M×á¶×r˜Þhë|³`&î'`֦ˆìÁ‚qa¼lÁÜ€âBf3PO®Õÿ£e]ÎAðŽ Ò ÜTAºØ¼~ÔÑ,óG]O®ëþ8†‚íðUR–¾ ;†¿r FÖ›5°mÛ䌰Øä>7ªÚ‹Y$©ò²K>«ªÇV¶kžŸ`§ö"«8©Îûõx3iR6×QÝsF3¸¦‚tÿ€y²I«ŒNÌzó¹œìèÈβ—}í,e™^ëì¬ciس»ÍjÊ6KS#Ýå>WcžûãÃvàs˜QÙöï"àóø×d½ÀûÃÅ"rˆì‘!û·CDîÆœÏû ~[²}|Ê‹ë¯æÇ%×vµT¨ê‰À©ŽfkD从¤‰È°ˆÜ ,À]§«ê+mòâš÷53¤Yp½Ö-÷-Žø‡þ‚ˆ´'‘ílÛjG³B½q}ôk]Yè/Á‘²ñ]º:?²° ØV¼/…³ ó]òÒÕùQ#û4Êtö—Þ,ðx²f ÝžRÏBUÇW—§=…¹†!L{ݬ Qø£Iù‘H$‰D¢›øqY…PÙ|WóIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/magnet.16.png000066400000000000000000000010111370472574300237710ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ('IDAT8­’½.DQF×aÈ™ˆDFF$£­'  …y …NB"¢÷ $t …Ÿ ZB¡ÂÒlrœ\Q°““»ïú¾o›¨(u˜ÆGà,¥ô\zSlÀ*P+¼¯À°ŸRzªÚ:­ž¨Wê¶ÚQûãt‚]©ÇêtnDøT©ºVøÚá9VGraO½TÛ?…3ï¬z­î~‚!õFÝ*ŒCj7N½ÐvbHuQ½W;Eø(ø}ôõLŸ ¾Ð4ƒßeK– ` èF¿”é·ñlÖ€€”ÒKf vÆ>Å”ÒK°Ážß>Úoõõ³¨ëoUx[…çû /*L+%üóþe€¼¼gïïÁʲ}@o!>dý&0UèoÀáÇúÏÝ·N–?IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/magnet.32.png000066400000000000000000000013431370472574300237770ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…í—¿kQ…¿;k“J…ÕàŸ`ŒÄÊ*D‘ÔÑZР…¢v VÖ j„-,RJÚ€MÀ)lM#âf@H)‚豘7zyîüØdq›½0pyïœó¾y3ó` Ïeu…’À8p8 FÃtØ>kÀ–™ýì €¤!à 0ªÉ» ´€çfö}Ï’¦àhÍ…ãJûf¶Ú€¤¸ ÌGSm²-~|vÂø(p˜¦øûh,ÌìW%²¤DÒ#IÛîz'i&¼Uþ†¤K’Ö£Œ‡áÆ*îFÆÇ’†+ÿæŒHzeÝ©2MG†…ZÔÅy‰¤{.‹Eâ!IoøÉ~ –\ƒ„óÑ3ïzÛK F$m¸ü«± !iÓ fzµ¸[ã²ËŸ¿Ðù‡CßV*Â&$= wµú‰ †dçd§èipÁ _–£’nËdß|3\“À²¤ëE¾¹æ†¦<À 7ñ¦dñ3ÀMçó•·$-ò“`yy€¦›øTpÍy^ç•C'Àl‰ÿ³ë›E_KÆ\¿hf©™¥À¢?UâO]ÌüùäÌì[I@ÓéR×ïtÒÄe{€¾Õ ïâIÛû í&£ï;0 r€]ú:é÷”‘´€Z?“A×ê0Þ‹Œÿ_¿ ·paÇÊDIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/magnet.64.png000066400000000000000000000026071370472574300240100ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¥IDATxœíš]ˆUUÇË)CÓŠð#¢ô) n”¦õ`/ÉDèdQ ÔK怘/™Ú‡ö1ØCh•dP:ô`NáƒöaÍ@X™LjcÆêáì¹¹sÖùØçÜ»¥9¸Ì™½×^ë¿ÿwŸµ÷^\¨1±!í ªS€…À`.0¸¸˜êÌΧ€Àû|‘¿Úɯ-¨êL`Ð 4€ <]{="ò{5 ÿC¥¨êb`-°èªÒ7ðð9°SD¾ªÊi%¨ê­ÀàÆ*üåÀ!àe(먔ª: ج,KÄŸ[E䘯oTu9° ˜æë£"œ¶ˆÈ'>ƒ  ªO« ;ŽƒÀÏÀ00â8L%Úæí7·3 ÄxxNDþ.0¦˜ª:x¸9‡ù0ð°[D¾)'¯Üô—å2¬‘?óÆÈ-€ªÎÞ®Ë0ýؼ[ÕîΫ€^`V†ùQàA9‘Çw.TuÑ[bvÎÙ¼$"#yü…¢XLN1ýX-"§²|f àÞù×Å)fCÀc"ò}–¿* ªó>àš³`MVN˜”#ÞS¤O~/pw§& "G‰¶Þý)fK€'³|¥  ªw«SLÞÖ·kɧÁ%ºG])f÷«jOª«CUg}»Ö>¿KDžÉ"Ú ¨ê6ìmù4Ð-"¿%u¦­€-Ø“ÿx67Ãöc+öë0Ød L\îlÿ–1fX)"gŠ0l7ÜNµ›äĨÀ"òek‡µ6íg‰²ýy5yhæ„õDÛñ¸nŒ9@U—`ßê^ëd¶/ ·;¼it/RÕE­I+à!ÃÁ/À+~Ô:Š> 1á¢Æ`Œî¸»Ô¼£Ýå©*à^ÏF÷mnŽM´–ªzH®ä ï•%§ªËÜg>p%Q‚:FTÜô‹ÈÙ’¡Þaüª XNì5i}º ‡{Ê~ûªzÐO´DWG§]…ç‰ßìs¶Þp\?6ºÇ̱)€»h4ŒAú’QÕ.UÝ l'ºïgá*`»ªnRÕ\ÂÛè3¶›/6Ú›s p­a<ä|pµÑ7aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(;IDATxœíܱjTA†áwDs¢1•Ioë-ÄRƒE¼µ´‹@ca/ÁN°_¢ÁF#Ö&$‘±8P $›3¿sæ|ß)÷ŸaÏ›Ùä,»`fºRô9ç‹À ° ,—¢×,äØ6×)¥ÃÊû @Îù2ðXŠ\ç?˜RJßko¤´°¦¿ùohÿâùjðˆ¬ÕÞÝ'­×#ûhí¨Á  aŸ´vâ€8 N1€ƒÚÅ>×ÞÀ(ð®ö†D1€ÀÇÚ› Å~Ïp€î­à=º{ô·;ÀuÚùë¢T€î$x?ý©a­ÒºQ| °?8q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ9q@œçÄ¥¨Á9çí¨ÙŠRJ7"æúçÄ9q@œÀ~àl5{Qƒ#ø8[MؿԑlÎVö\F°L竘Ð=—!ÂH)«8‚>&ÀjJégÔa·‚äœ/÷»À"0½fãö-à-°yñÍÌÌÌÌLÑogsÛ[nª?iIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/new.16.png000066400000000000000000000006431370472574300233210ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÁIDAT8íÑ1JA…á¯UAØHa3³=€yÅ‹-Éâ^`Á[¬wPÌÍŒ]C-“¥ÇÄp]õºê/šN²"bSìø®À"¥´TÐF+?Â)FØÎqˆÌ#â¬Ðèw9²Wã¶)Jšá1CÎÿ8Æ3>qUs±Õ3øŠ\üð÷ñ2Pã²UW¸n7 }B§Ö€”¾qŒÍŽþƒßïù¼°xÕ$©íFÄ»=Ão)¥§¦øzÂ)· >6ïIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/new.32.png000066400000000000000000000007701370472574300233200ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…í—1kB1Çq´ots§n~‚NÒÕ¥øiêÖ½“Xº:ÕIÄaAÁ±«“ÎRΡ¯^{÷^¤KþBr—Ë»„‡G"R@Ëg÷èX:ç>”þ?r€{àÉ댜sË¢Z`¾mÜ ^EäÖ²¨®ðy¶Û°0nQgB°V €#pÃW&^´¡”Ñc†rÄØ šÀô/ˆ˜¥ b|CŒ ñÞ,Í!ÔjzÁ–}à¹h¨š“Á·á›¬ 03BüRÕ,òÒðp)À5¡I $€À¿hžã.åßün €^Þ®¢P ÌŸL…¼1CxËûN¤ÍwÀaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÝAˆUUÇñïßÒ$!("ÈŠÚÙ¢¢v"!n ]” µ•‚2a²)Ô*[e¢‹¡i¡RA`ÈìŠlã.Á´¤Ü ‰“óoqïÃ&™y÷¼wÏ9ïžûûÀlfÞ9÷?ssî=ÿaîé6ËqPw¿Ø<< ÜÜ\~¾N˜Ù\Žúbr÷5Àf`°ºþôà4pØÌΦ¬'yÜ}ðpß—^v›ÙÉøUÅçî+€)` °l‘—ÍÓÀ3»š¢®dp÷eÀN`[àÐ#À»f6Û~UiÔ'ÿ°¶á`[Š,–Äv~ò6_»ûc-דÒÍO>õk§"Õ²@’ ^ö÷9Íðð™™ùøU¥Q_óþË6<ûž ú àîË7[˜j9Õ%ä»ßÕÂ|©,uÍ_ʲzlT).O÷·8ß:਻?Þâœ1…,ýmŽm$EÖG˜óNà€»ï¬W˜Ivo¦±¤ÀÑæ5àà w Ò1Ú°2ÓØFR öõú!àKwßù8EJ€[c°ÛÝ?v÷Û¯)û)l¤ºAìrÏ ©ÒÕÓawß^we ¥þ€n¶;Ö3H®Ô ¬¾r÷'s2©JÀÀ§î¾«=ƒäú¨z[™üžAr} À€zÿÓ·€z ô1êÐï€z½ô¼g \×Ëž°Pïz ÀzÕ3P׋ž°´â{ @3Åö €æŠìó$R\Ï@M1=`tEô €ñt¾g ´cÐ3Ø”»P @{Vºû;]Ú%t¦Ðy™DÿÛß Ž­îþDî"šPây¯~ÖDS⹘øU@ˆëÙÜ £Äõ`î†Qâº;wÃ(qMüÓÌ€¸.æ.` ®¤Ïý…×±Ü £Äs8•»ˆa€8xÛÌþÉ]È0 @Íì‡ÜE4¡´ïð~î"ššø?VtÈ,ÕûÉ]H ¿¯™Ù¯¹ ¥KÀxœjÉ¡‹'´Œã2°Ã̾Ï]È8€ÑœÞ0³K¹ —æð °ÏÌæsÓ ¹óÀëföcîBÚ¤›ÀfŽÏ—vòA+À0ÜÛ‡P×Ù½}]nÔù½}­ ±·¡\WÌÞ>„PàÞ>DßPäÞ>DŸo‹ÝÛ‡èã PüÞ>DßЋ½}ˆ¾\zµ·ч w{û¥ —{û¥ ×{û% ÷{û¥Ýjo(Å pXùÚÛ(Å ðWäùÏPýÖëä EÎDš×ýÀ‹fv.Ò1Úðw¦±¤À·æ¼ ¼jf{Íl.Âümú-ÓØFRàðG‹óžéPcg&ÓØF¢ÀÌ®´0Õ°Øff¶0_*ÓÀ(½ˆùzlTI¶fvø|Œ)ÎQ]ë÷›ÙÄ?yë¿Ìì,£ÈézlTûõ#Ôw/=BµÅ›m¿ª4Ü}pXÛpÈ ÕJw5^U•dp÷ TSöÅ‹Àn3;¿ªøêL[X|å,û{Rœ|È€ú=vÖ׫ë/ýü |ïÀ~0w_l¦zã©Á÷}êW‡S,û"""""""""""""""""""""R’µØw‰[ü‘IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/next.16.png000066400000000000000000000006221370472574300235030ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(°IDAT8Í’1A†¿AGT²• к‚Æ\@âJjJ¥Fâ¢Sj”JWàÓ¬d³ÙDÁ—¼L2ÿ{ßä%…ÚT»‘N3|IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/next.32.png000066400000000000000000000011031370472574300234740ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(aIDATX…í–?KÃPGÏõÝœD\tpòtÜ?@Q·nŽŽfAt\T\§‚“ˆœº ÑŸCZˆ¡Ió’Ò·ä@ /ɽ÷psITTxƲnJZ¶™=¸$–4Ô»Ë3ûv2“´%é5vJª9Ä±Ø í¹ÔHj3‰ËÀ®™=æx&ºËÐÌæû=7–‘#Y`¸Ô”K¬xò<·@ã@8“ÔOÒ‰"=V[Ik¾¦IMI“> äMàRÒœ Àµ¤ — Ôé,H 8pù^ ³q¶} „¾Î} |{fvš7`˜CØvÌìÍ%hQË×]‹Cùt€}3»/š Œ@‹è}–ÈQHà€#3û-S|@‡ègçhОsäcùS¿ YCxœX_õœÅîRÎÿ1hSº,O#ß”VTŒŠ?°¿–܃ÚIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/next.64.png000066400000000000000000000015271370472574300235130ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(uIDATxœíš=hA†ŸÏŸFEÁÂJÐëca«‚i‘*vA+A;±±°H§W) A0Å)‚ha*Åø–*XYˆS‰¾{’Ü%;ÃÎÏâpÕÌV|´kxw€`תÒ2pÊÌ>¹èmò˜À$ã0<–tÀU»&]Ö.žÁ]W1ç€ó5Æì$ÍHòñXÞµ‘øLn¢æ¸ÍÀ 0/i‡Ï8vxÖFâÀ6Çñ‡€'’Žyx§éí9ŽÝÀ-IW$mäY‹X@uâL%íè».12<’t6÷R°¸&醤‰æ¤ `Èqªžá`ª ¤`/ð Pϰ!9áz† É%€!Ñ{†Ü€È=CŽ@Äž!׆ {†©P¹UÏ0'i6„ø–¢¸(i©iÑ6ì€9×´`Ûhü)SÛPÓ‚m à}Ó‚m àNÓ‚m ঙ½hZ´ Çà Õ{†~ñÜø\2³Ï¡ r½ÜN‡\<ä¹¾—Íìy ³ÜXºfö-–a.üzTwú?1sà+0kfoR˜§¾ >N¦Z<¤ÛAÏvRülw!æ%ílw!Öˆz¶»à³~8Ž_Nä¸xð àcÍq¿€ëÀtÃÍOÏÚH|¸[cÌàŒ™Ý6³¦Ÿâ¼ô¬Ä93{FÕµ£Ou¶7þôfÀÕ'q«YÔâ éèàãÈW’–Úú¡d¡P( …B¡ðŸò+ð7sKª0IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/open.128.png000066400000000000000000000024661370472574300235620ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(TIDATxœíÝ1oE†ñg F„4( r‚ ¡Ð ¥ _!”ÑP„¯A ””(…¥(")ÌG C¢¢±Q@2A ˆ£ k)öNâØ;Þùgvö}’»½ÙÑíã½ÓÞÝ,˜™®½ƒ®ëžÎgUàhô> Ù®À—)¥{•ç"4€®ë^.k‘ûy6SJ7kO¤´°ÿùWhÿàß·¼ŸRú¥öDJz*pìsÌçଗº®;Q{"%Ep6pìZfAd¯Ž]Ó ðE×u/ÖžH ‘<8vm'éÏÍGÀÜÍ"0Nó8€ñšŽÀ”Ñl œ&#ˆ¼x-ó!DÌcëÁãß ¿bøsð~Šð ¼¦Î F38€8MDàvcÄcO§üÙ8ØÇÀ˜7t“þìÀì6ð ã"˜ìËf¶8€áfÈ3»@¾YEàg68€Ã›E`œæ#pã5(£Ù@9MFàÊj.P^S8€·O)óQòr™)íÍĹE&Á ðùâ—Ö!@¬¬ΣŽD <#ëµ'@ÿKë‹û Іעvmû¥µçÄ9qŠlמÀ”(p½ö¦D1€¯kO`Jøø¾ö$¦B1€à3 {)ø/úkôoo/ÓÎ"ÖE©ý™à›Å_ ë•öûÅ—Û%û ¸þÿ™Bãì¿¿s¶²hdýÿ§ã‹¿?è×úß©:£ ü°øÏŸúÁØóÀ)`©öD¦*ç=@«ëÿÞÀì)'€–×ÿw‘@ëëÿ;‚=ä0‡õÿÁC¯8‚]GðÕÀÚ€#Ä#p=ÙÀÿ$#p’‹ÀŽ=Ær'øqø¾†ðw[&–®ÃWQº³†ÈP`ýyŠšÀ)p6uº Í€màEÉcÍOààKÞ~!B;AÍõÿ6ð áz¤!ÚëÿÑH°< F!ÁúŸ ¹k`,!`(!¦Óá6%í|'®`î9ØuÎ]MÖÆ24i3¸§a;«³ Flf56I@æ W“d’X°& °`M`Àš$À:€5I€uk’ëÖ$Ö¬I¬XÓx™ËÐ9ÏÔçÜâd[ãg@ ¬ï«¤(—¿’b©€_Âz ~KŠCÎíà;q΄>ƒl@æw èÚç€% %ŠV -ÙB×;O²CÅ»Ã÷ ª}ZTƒñÙÖA¢äb&ˆ*zöA"IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/pause.128.png000066400000000000000000000014271370472574300237320ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(5IDATxœí×±mÜ@Fá· «Á¹ZÔƒs9U» eÆ)wµ ¬PpTÂÀNl-Žäzü¿¯€!ñ°A’$I’$I’$I’$I’$I’$UÕF/0MÓ pÜ×ÀUçGàxžZk/Ënø»jûþͰ¦iºvÀWàb¡cOÀøÖZ{[èL Þ¾5$€ùe>·+8K½ÔjûöXªä^;Ö{™Ìgï<¯Ú¾¶ù 0C°~|'àË¹ßØjûöq,ù ý“‹yÖ¹ªíÛ=tkk^¥k̪¶o—|.6«Ú¾]Fð©Ø¬jûvõ „„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@8gá œ„3€pÎÂ@87"€c±YÕöí2"€ŸÅfU۷ˈÅfU۷ˈöÀiƒ9§yÖ¹ªíÛeóZk/ló ûyÖYªíÛ«m=`š¦Kà¸]iÄxh­½-qXµ}{ ù œôøÎ²×ëi>sÑ—YmßCn€_MÓtÜwÀ5pÕyÄxž§µ¯ÑjûJ’$I’$I’$I’$I’$I’¤ÿ×;ùø{{^­<´IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/pause.16.png000066400000000000000000000004671370472574300236510ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(UIDAT8íŒ1 €0!ß±òync•&?I168„vÜjîFZk@p%øb×€¶Gc—”ÌGðƒ“o¦×û_ TIÝ|?¸ûf¥ÝŠ·#1Xzú‚IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/pause.32.png000066400000000000000000000005201370472574300236350ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(nIDATX…íŽË € ÷Ù„Åx£/Ë“*lšX/†#?‰·„˾ @Q¤#éIžÙó$ÝŒ›c€Àúr f¶}us–Z@áÃÒ>âvüŽ (@ h„}ÄíØÄÇï}ÆB$.G¥Fàn™çÛIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/pause.64.png000066400000000000000000000007441370472574300236520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÚ±MA„á9R¨:L.åÊp)n€ê Kv|ÞÀÁž8Ýêé—àÿâ}£ÑÄ›H’$Iú¦‘ãeYÞ’ÌIÞ“<¯<»%ùLrš¦é›ÌíÙ=@+yNòºñä’äø[ÙªÜ5O{Žš9ÛK¦½ÁÜ®‘E7U¹]#¼ÝTåv ð'8]€ætšÐh@ 9]€ætšÐh@ 9]€ætšÐh@ 9]€ætšÐh#\‹nªr»Fø*º©Êíà”û¥­.í†ÊíÚ=@û•uLò‘û—µ5·öfÓO®ª\I’$IzôWM5ßî¶ŒIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/play.128.png000066400000000000000000000024331370472574300235600ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(9IDATxœíÝO¨UUÇñï²¢ ‘AÿÈ¡ƒŠš EAˆFD“‘‚ØT ÂØ"!…†5Jˆ"hò²à=± 0šÙ$h ¼”r«Vƒs_äË÷g_Ͼkÿù}À‘Þ}Ö»çç¾{­÷€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÔÍ¢ ¸w¿Ø <<ln.ß_‹f¶Vd#Š €»ï^îÝàŸ.GÌìTþªÚULÜ} 0ìO|é<ðº™]¿ªö•€9àÀ”/?¼hfßXR¶DÿnûÓÞ|€{€Ýý€»ê„¿Yî~°Ü7Ò’ß/™ÙÅ‘ÖkZ ;ÀŒwóv'Ýý‘×lV Ø™aÍÛ÷Ý}n²ÃÈJÀ™Ö5†sŧî¾-Ó5ªWBîȼþýÀgî¾'óuªTÂ!ðç^n8lfÌðšE+a˜¥Ý 㣠)Eo€afð‰»œL»Öëpp8áî¹Ï Eë5+v_¸ûcÑ…Dé=·ï¹û«=Î €ûèpf \­»™Aos€]Ì ´¬­‹™°¾ægMþP#kzf l^“3 Ms3 ]S3`zMÌ 4Gµ3íã¨vf Œ§Ê™A5…V¢º™G53 Ÿ*f @^ÅÏ €ÙX™<]Èj ÀìÜ ¼íÔ%SHGö‡£‹X¡ÄØçîF @¤7'_†Jˆs7¾ (±žŠ.@ˆµ=º ÖÑ(±<º ÖRt @¬Ÿ¢ Pb}]€ç¿;’îÊ ŒÔ俀 ÛMÛ!=J üÆ(ÐÎlÿ$Y¹@Æ"pm{)•Àpj»e{<…ôô:pe{:…@Æ Ð¶½šJ ìÛ^K%±™Zà=µÀɰ‚±Š‚߀I—)ºÀ–¤§â˜[`àX ‡x+Ðö$Ýüub °+éµÈä2À1p$é³h“ýŸÍ ÏÀ¶¤‡¢Á!‡0—ÛÀrŒp”.sÀý¿?Jkjªæ ‘)^Ø‘= ¹IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/play.64.png000066400000000000000000000014331370472574300234760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(9IDATxœíš¿kUA…¿ÑØhgaÐ? ¶i± ˆØ(vA+±F‚M[ K…@‚?:A‹§éÄBÒ*F°±0*…ˆ*Äc±y`‘ÄwÙ¹÷î’ùÚ·ïÌî¹³»ÃîBAAHÌKHÒEàpØV%3ûè£ \ 4ÜÚãçðÀÌ6=by“mÀΗ_øO³5àŽ™­æÆóæƒÆÍÚœ^Kš‘äÓ ømð—`ÎÌ6rc{àñ5š `x'é¼CìlúJÇãÀ¢¤û’ŽôÔ ? M¿ià•¤S}u¢„ix#ézÁ=ÁïÙa˜7³ßŽšûRBüËðVÒÙ®–fÀ8𲫚¡D3ÀsI'Ú TªCZ¯J7Z®j0Z¬j1`Ȱf¸â%X›Ç€G’îzˆÕhÀÛ’.äŠÔl¤#¸,j7àL®@íüɨ݀ì3ÆÚ xš+P³ÍìC®È˜CGºf“tÏ0ð«Í€¯¤û…^‚µL/€«žƒ‡:2à'pÏc¾ïFé´~‰RªÛÀÒJŸ]ììG‰¬³fö©‹`¥-‚ËÀå®åd€ëÞÞ„ pßÛ›ÐçhmooB_ÐêÞÞ øÕ°ý p©„ÁƒßFl·<¦Ky><¡ÍpÍÌ–ÌL1ÝÈ6ÀÌÞ“ª¶½ööâ^ˆïCÉs¤SÚ Òâú™ JAAÁå/˜T˜Ç—¿õ(IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/prev.128.png000066400000000000000000000030211370472574300235610ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(/IDATxœíÝO¨UUÇñﲞÎ"¢ÄA3ƒŠh&B¦dfƒ"!H¬&ýÕ@zTZ&Aá4±°B“þZê "x¼YP r–‘¯)$üÓ[ ιùüsÿœ{Ï>ûáãžsìßÝç®uy炈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ¤Íº¾ »¯Ö+ë?/sÀ!3;ÞuM¡¹û °¸¸¸8ü|||ifç»®­³¸ûr`Ø,ëó²Eà °ËÌÎvU[Hî¾ØÜ0䥿ošÙ‘ðU]ÐIêÅ߬ñy`[Ê!p÷À+À憇îö˜ÙbûU]®ß;±m³Œ¾øÔ¯ TKpî~+ð1ÍàIà…v+ê/øPßó?¥yØRúLàî<<ÌLxº§ÍìèäU ÖÅ0èž?ȲúØ$¸ûµÀ»Àv&_|€ë[gP] ÉÖßæ±q÷;ÃÀÝ-žvpO‹ç»¢.°*Ò±Á¹ûŒ»o§ú€{]€K¬ p΋\úÀ5‘Ž ÊÝWow¼Ì-Ï t×dÅÝ7Ÿvñaøì`b]ìÙ˜ ·׊ÐPFT÷öï7E.¥Uº áîæî[ÉlñA;À@uo¿‡vÛ»©¢ôáîk·¨¾¹Ë–p w¿ xx–n‘ ÀõöS%û„ªÃÞ~ª¿Dèí§JÑȵ·o¢È[@î½}Åí%ôöM€Rzû&Š@i½}Ù ÄÞ¾‰¬ß ¥ööMd¹”ÞÛ7‘]ÔÛ7“Í-@½ýx²ØÔÛ/ù¨·ŸL²Poߎ$ Þ¾=ɽsÜ}3ð9ZüV$³¸û2àeà±Øµä$¥@‹@p÷»Ðâ1õ¨°´3v¹šúP wnŒ]D®RÀÆØä,…Ü»€œ¥€àÿ#_²à± ÈY ø=v9K!?Å. g)à³Øä,…|Cõ4q `ê`f稞¾©ƒL}Ìlø v9J"µÀØEä&™˜Ù¢™½Jõ(õÓ±ëÉE2è1³€û©~jE&”\ÌìWªßÚKõ»2¦$`fÿšÙ^`+ðGär’•lzêa#ðuäR’”|ÌìOà)ªNá\är’’EÌÌÍì}àaàç¸Õ¤#›ô˜ÙÀƒÀ¡Øµ¤ »˜Ùi3Û<ü»ži–ezÌì `šô•u@3ƒa²hf0HèÑÌàrE43¸TqÍ –*2=šÐÌ øô”:3P–(qf \¢´™ÐG)3`€f À¹Ï €å:3Pˆ03ø'ô€1Ô3ƒ‡€_êTàów€IRü0.3;<ì#Ü?®†X'8éØàÌ윙í'ÌÌàX€s^¤‹ÌG:¶3õÌ`ðm‹§ý 8Úâù®¨‹d¼±êb}lÌì° ØM;3ƒ7ÌìL ç(xÌì8ã-äÁúØdÔ3ƒ}TŸ NLpªfv¸¥²²..âîËýÀš™¶™ÙÙpU…5ÁO×½¼nf<¥“Àÿ!˜¶Ðçémû»R^ü¥Üý>à%†?ðrxÍÌ‚ð[ª³ô¸ûjª¯\×+ë?/sÀ¡Ô¶ýQÔO<߬nãBNßG€cfv>N…"""""""""""""""""""""’®ÿè¼_/†,W IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/prev.16.png000066400000000000000000000006311370472574300235010ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(·IDAT8Í’! A…¿_l ‘Í¢ˆÅCx“Q°x“<‚`´Ø¬Æ=€˜ @¼€áYFÖqØ¢¦¼7ïã ü•$å’òHÞ—ÔŠ IE…ŸIZKºJ:úY³t·SQ ë¬Ÿ7"kLÒØ{啼Ëm`ŒCÅ(ØÃoeˆäf Ý!à*0Úã‘[’&RãnÈË8«'O÷»ñŒxkb{xDïÉœ³}05vŽ{3Û’±-ÛcÀ}`G]ΤjlJílÎlKÂöVàp ¡ÛHªNŽáØÞLÛ»¥jµÊÛ ÀEò¶g2­1Àöv`ØÝ¤n#.¯…íÃtþå<^}äöpŠ`{pØYj P` ,Ëí(ä‹PÚ­fIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/razor.128.png000066400000000000000000000025741370472574300237560ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(šIDATxœíÝÝnTUÆñÿ;¨¡$‚‰)©=‰&r ØF›zÆÄ ñ¼L¼¿OˆÑ´ž!µØª ÕÄ*pBÆ×ƒ½Ä‘bÇÙûݳ÷ìõüNÚ™‡Å^O÷W×@DDDDDDDDDDDDDDDDDDDDD¦›=ùw8ô9àà„Ç$±»Àð­™í óqÜ}XÎó”bH'8°|nfH&ÿàdsc“ º |dfƒ^ú šüœœÞè¥cþùfÇ# ¸àîÇ{蘟+Îõ€SMD³ÐŽ4= iÌ‘p¨éQHcõF¿FºLÈœ 9 s*@æT€Ì©™S2§dNÈœ 9 sš@ƒÀ}Š‚ÃÀL³ÃiFnØn›föÇð7Ü}xX¤X…\ ° \1³Ÿÿëf¶ ¬kî~XNLfxÍÉáàkàò~“ÿ$3Û.7kUKt}ð±™­—y£™9pÍÝwÕØaµG—÷_•üaf¶F±餮àp-0ï `g䫦PW pÝÌþŒ KY_FåµI °cf›Ñ¡fvø5:·iÌìƒý^àî)n”€ÓÀ± Œ­¬ïkÌÞž­1¿ªŠÿððÐÌí÷†RO¹ûàp¼Ìûkö¡™Ý­#ØÝOïÖ‘]Ñ=à†™]þR—f¶áî›%¸X&£F»Sš]Ö:ðiÙsžÒ÷Ò_ØÆëä‡5f?¨1»ŒOÒeji•OÓZsÇlÔ1¯­Ù%ܬ:ùwpø1(KFÛ¦Øæ•… Ý6½‘%ÿËÕ´Í+ »`f?Q\~H½¶Ì,lo}#èvpžìu+2,ºáwàd;‘a¡H‹*‘™ò/3û=2°Žßܯ!S áÛ¶Žè§¦H˜­!S ÏD† ­¬Íryõ„̸{è‡zEïNçÉ^/F†EàLpÞØÒú…©ËÃbdXXÒZú~T^‡kÌnÃùM?më!pw–#²ÌMiö8–Ó6¯,j°ÌeUµ0¥Ùã˜Þˆª\w¿¼0–(už‡4~Ž3äbÚö•”.€»÷Ü}‰v­8–Ö,†r÷EÚ· tÕÝßv÷ÒóXjI˜»Ÿ¥XØÖÕÁ—Ü}3êÙ€´_ȪÁKÀ¼»ß0³qß<òD"]úÌR, ïSìÛö“ð4ߘÙgAî¾¼‘U³_(–…ÿ@±€õÁÈeáîþþ$FÖÊ‹&Óq¶m‡¹0]|2hت»¿Uö’ÉÝ_£Ã“Ý<ààyw¿šžû)ÝhY¦=—¶µÉ¡PLä{î¾|ÜI‹Ws÷£s–vÜÑœˆ\ ð·~úƒ»øçAY2ý-fn6ƒþ¿¤ÎŸÊ*@æÌÝë|ž^ZN{€Ì©™S2§dNÈœ 9 s*@æT€Ì©™S2§dNÈœ 9 s*@æT€Ì©™S2§dNÈœ 9@DDDDDDDDDDDDDDDDDDD¤þ´  Y¯[;IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/razor.16.png000066400000000000000000000006071370472574300236650ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¥IDAT8Å1 Â@DßO¶ Z‰gPÔô^Ç+ykKK!Úy‚íØl`]q•l‘iþÀÌŸÝù04LÒ˜ôÜ¿9`T=žEÆ2@墀0`åçpFÀ22Ìl © ÃÏ@ëÌlïMêÀôø=z¸é‹D…ò ¯ i LE¤Í$=ŸGZ-©®&i›øÅO˜¤KN@êÁY†Ç ÇP,!u=j5IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/razor.32.png000066400000000000000000000007611370472574300236640ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…í•1NÃ@Eß8n"|  )¡…–D%7á܃û$éT 4DcñSØFÖÊàe YEÚ_­¿4óß®f×”Y&)fÀøÀÙÀ6n€³‡7:Í€I¤p€IŒ"Œ²ˆá ÐP€<°®VÀ0ª[´é °1³§Ö÷£¤ Xþ¶‘5 I'À¸ò»7³÷¶!©n{êJ`¼4õ_Aµñ é¸þ‘Ú ¯½7©w$VÎÉuᶯË=»F€uxÿ¦.€ó¾¢z^\¯ðÈ›} ©t Ì=M==W Ií ˜¤;BW%°¦z :µ9×:àÏd’^cýÏ(?@RRtíþKRé4XIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/razor.64.png000066400000000000000000000014131370472574300236640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ()IDATxœí˜½NQ…¿±S»¡ e€2”á%B*¤ð< ‘ÒżDŠ ”Â"EŠ´.Øl¤¡Øëˆ,x÷’½¾#áù$7ÖØsæøþ/8Žã8Žã8ÎB"ªÚö€×ÀŠ¥  Œ_ÀW)$ ¬šÊÊÏ ð¹CùË/ÚðPÎü®C¹ì•/Ï×ÑíX+°Æ °``-ÀkîÂËŒ%ƒž7À0‘?ªºl;@7§˜ÜÀ—éàSDä8UÕ!°ôr ʹÆÀ :üC‚'À$—¨œ\„k‘ßÀy=e¿êªºL¹7·Àr¢^ŸDdS¨ªëÀÇD}ÇÀp "òÏêzt„‚0RÕïÀ{ÒìÉbNµMßsVÕ“ÔnðÁpÛVIÕù†ÚqÛ~”šuÃCÄöíYA¹ùsæÄ‚Öb,ˆÒe@pÒ4±=“IÝuûë(¥à”Qx7“`úaâ¾çÀàªÈDU5Š¡ LgO”ðk¥ŠÞQä>Ù{À¡ªNˆ\ƒí‘Ü+ Ê4\™]±Öw»uDUZ‹°ä¥FáhÜkÖ¸Ö¬q¬XãX °Æ °à8Žã8Žã86Üàÿ“Œé…*­IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/record.128.png000066400000000000000000000026511370472574300240730ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÇIDATxœíÝÍkuÆñï)º1j£]ûÒWÅ… %ÝTP_@íÊ*Äî­Mÿ KAQ¶©V¥)ˆ"(Š®‚+j[*¨KkoëJr\ü~Wc¬Mosïœ3“çÙî3™'¿;÷ÎÌ‘ì,:À¨¹û`Øl6뀱úk`8[Nsfv®éÌMêdÜýn`°ØÊÕo§SŠðpÒ̾NÂ<:Sw¿Ø < lÑËœŽï˜ÙŽF£Z_wöÏP–ö&ÌG€#f6ßÐkŽDk àî<L7Åè¯GÍl1(ê´²î~0Ü¥úxÑÌ~Š2¨uÑåî’gçÜ œt÷G¢ƒ ª5+€»¯£,÷ÏEgYÁÛÀt[ÞZQw¿8Dùh׳À~3û3:ÈJÒ îüׂ£ êsà…ì%H} Pô_¦};àA`¦¾u¥•:px<:Ä*ìöG‡¸œ´p÷‡ÉÀw%öº{Úc—”Çî~+p‚r¦ €I3û9:ÈréV€ú¾ÿ*ÝÙùP¶åPݶTÒ€r2'Ó—<Ã2AÂã™T¬'v>nŠÎ2"ç€fv!:H_¶àYº»ó6PÎ\¦‘f¨çó¿ ¹SºQzÀýY®'È´ì¦û;`x::D_¦< AOEèKQ€z ß¶è ÚâîwE‡€$ =gù†i2:ä)À}Ñìˆ P¯Ûß#Àîþ‘7¼”oÈÒ|mÛ£Cd(ÀZ:ø[nkt€ Ø ÐÆè p{t€@*Ýþî%Q7´ü-CÆVþ•Î ßv Vø¶g(€ÊP€§Eƒ„o» +|Û3à|t€@¿EÈP€£ ßv ÖÙè p*:@ ÓÑ2`Ž2k­Y¤l{¨ðÔ9|áÿ ¾7³ðàðT_Gb›³`6:@€Ûœ¢uçZ:ˆРw£ô¥¹ÏÝÇ€/éþÝAº5ìRêähtŽβó!Ñ àîë)·‡‡_)3"¿Rn_ˆÒ—f¨ƒ—g¢sŒÐt¦É P§ÌÞíš9ÊÜ£TR½ôupHÔàQ ‰ºBuêöTtŽ!šÊ¸ó!iÌìcÊàå¶{ÓÌ>‰ñÒ zx?:Ä*ÌRFÞ¥•ò`)w¿xƒöÍ þ اaÑ«Tÿ€ÏïEgÀ Z°ó¡+@_²ù°7:Ëe8ð0cf­¸È¥5ès÷À4ùÎü4³¢ƒ ¢up÷[(O™ˆÎRÍQõKtAµ²ð¯ÇÆ LàŒÐ£åkË’¿\k Ðçî7RÆ¯î¡ alB8LypdªïöÕúô¹ûuüóèØQ^9Eù4rÌÌþÑk4ª3Xªaœ¤Œb»ƒ«ÿ¸»ü@yxôl–˸†©“XªŽbÛNE·™2–eœK?>¾Ç~鶈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ¬mäÐTŠ[2¹IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/record.16.png000066400000000000000000000005511370472574300240040ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‡IDAT8푱 Â@çiBH݇; "è(¡K°DŒ«0!T0¶õ:ré’½ßÕÝ=ü Q7êIí§:«Uô6Ef VYëlSJÃ\\¡ûÀ °v¹ÔѨïzQ@ ¿ ¸º\ˆŽX ãÎsîŒG¼•‡äõGõ:ÕA]4þ(Oº‰9û K,IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/record.32.png000066400000000000000000000007531370472574300240060ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( IDATX…í•KjA@_EÌ!¢[ñ ~®àZp«·P·ÀDÜzÅ;¨K1‡ˆC¹˜4àtÍôd•~Ë¡>¯»™*ˆD"ÿÉ› ªM t€ºû|vÀZD" ªïÀo/Â`ÌDä§4×ühYâ=0´H¼:Éo¦9š´±%Ð{îÍ7Øeï$@ODŽYA–¢ýÍ*.7Kánææ\‹ÀG€@­  ðæZ¾.el¼¹5é/•—Äå† ¸Ù¾* °‘“·¾¥’ªV9é²°F"rõšŒ›é#à‹ìçH€…µ9[Ç Ò ×åyoI×±÷Ú#‘Hä‘V?;‡þº$IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/record.64.png000066400000000000000000000014561370472574300240140ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(LIDATxœí™;kQF×Vð¢…P0 Ä`a™t[Lk£#ŠþQƒ„ØØXŠ…•Æ+XÄF;AÁ˜tIÌE#l‹9ŠJ7s¾9ƒ¸W{¹kÏùæµg‚ ‚ ‚ ‚àÃJr÷~` †€ƒÀÞôó2ð˜:À33ûRâ¸ÀÝ“À)`wë)3{ßС à«À9`{MÍw`¸nf_E‡öà[À‘ò pÙÌE¾_Èp÷aà.°O¬^&Ìl^)•Îü}ô‹ÿÉpÆÌ–TÂm*‘»ïnÒÜâöwÒóE‚,àpTèÛŒcÀE•Lr ¤WÝê?í·ÊpRq+¨®€IÊ- ¸¢e_©ÃëÐ{“£¢ ŒävŒŠ+`Œò‹'Õ<‘+Q0*p´V[ÀÀÑZmEƒGkµô uÙ“+P6Bÿ$ŠVŽº¬ä |8Z«­`Nàh­¶"€ŽÀQ——¹EO©ÚÒÒt¹’ìÌlj€YšG©vª×àÕ³ëÀm…H@]Ï(\=2mf’·l&˜Fb÷€ã*ç&ÌgÍì›B¦Š€Jïo,R E?«„ÒV8¨.PMoÕ|Î+ | ¤¹ýiàµP; Œ›Ù;¡hvklp ˜ þÄh˜n¨îù¿)±9:@5Àgk›£©6GýÖ(¹=ÞG5?†Ùx{ü-ð x®hr‚ ‚ ‚ ‚ 6â¹+„%¥IMIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/redo.128.png000066400000000000000000000030451370472574300235440ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(CIDATxœíÝ;ˆUÇñï?ÑÄø€(j\q >רÄBDŒbá,´Iã#D,"D¬!BP´ˆ j°íŒ."ˆFE‰ ’hŒÁGD£‚/\þ3‹A7wfÎãÞ3ãïÓ¤È=ÿ9p~÷ìÜ33g@DDDDDDDDDDDDDDDDDDDDDDDDDúÇ&ݾq÷åÀ 0 ¬ŽÌìljv,Ð’»¯îÎý×/Ϙ١q÷-†Ђ»_ìÖ5|tØafsù{•†ÐÀÝÏ^Övh¶ËÌveêRRË&Ýx„nƒ0ëî³9:“šf€ê©ÿ}à”ÀÅÏšF»•ðÁ‡Ì ÀhÔ(: Àhg'ªSl€Ñ~MXkÖÝ·'¬—„0Ú—‰ëm-- Àhog¨¹µ¤? Àõ²î»JsN u€î>Eµx~†ò_'Ð ÐÀÌŽ[€ãÊO|&Ð Ð’»¯æ€ÕÊ¿`fOe¨ÛHè`ˆ!P:Z€C h(!P" ! @¤¾‡@H Ï!Pék€„ú ±¾…@È O!P2éK€Œú ³ÒC0ö¸û2àrà*`=p10œGõ´íéãîSÏEÝT2–¸û àzà¶úßsÆqÜÿ‘àd €»¯¡zœz3y¦@ùGP²ÀÝW÷ÛД>NÏ ’ÀÝ ¸ x˜<7QJ³N3A²ÔÏÑïnIUS‚µž ’Àݯž¥:£—2´ Aômáî~° ~iZ=w¿ê›¿"¦ŽLNðŸw¿x85]w$¡V'ƒAp÷i`8+¤½d×ú—@çÔ¿ñçK»¶•±èô30äà14ø¥ê¼Ø)î>CµÐ#å Z n€ú*Þã]ÚÈØ_ ê2˜7W‡D²ŠºÜe¼ûCrG©¶`ÙŽ¿›Ùω3Qõ*éËä¹½ÁD«¸û`cÌNðð$ð–™y¢šE*}ð¡ý pgìj³föK¢zÅêÃàC‹u€ú ûøïù]6›Ùo‘uŠ×—Á‡v'‰üàQ ~´ä›Jµ Àu ޳§ooÒQßÜ›Á‡v¸6òEo™žBýÍÏuûw¶íäF þû¿>òï˜Ù±ÈEëã7QÓ °XyŒW"Û­¯ßüEM˜Ž¬ÿ'ðqdbõù›¿¨)S‘õ÷›Ù‘5Š”ù‘¯±m!Û€5‘õ¿ˆl_¤¾Oû'j @ì3ŽD¶/Nß~ç7i @ìmムÀК»Cö÷‘í‹1„¾¥4àÛˆÚ|ѾC9á[JSޣȇÌìh`Ûb¸û…ÀK pð¡!õËÞ¬½;°]ižf o v×vRݽÓÅ^ƒS wß\“¡tƒ-POã÷QÝÉÓÆ^à¡Üís{†šÅ >´¼)ÔÌwÏ?äc_ÛtÝ?Å«cOTÔàCØ“A˩j÷ãÀA3û:m×&ÏÝ÷¿º¨¸Ám7’»¿Ì$(Uäàƒòhòi‚Å>(Mæ#Û=ø ŒdfŸo6/~ðAçÜ}5ð*ÕIo[½|PZq÷‹€Ë>ºì0³¹ü½JCh©Þcp/°j‰|E:&·p‚Áwyn6 "[jÙr˜y;ìJÿ1€n¹á ðÀçB`.…\#ÈøÑ]¼ER/©–tÞÀ ιp²p+é‘UÍO«ÖÇ„çû€ÊÄ 8ì G†äŸmÁ»ôpÏ ÿþ¬ÈoŽsxOpIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/redo.32.png000066400000000000000000000010211370472574300234460ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(/IDATX…í–±.QFÏbƒhT"‰^J!Ñé4*l§òJÙJ©Õ©@!Â-…HDAw4³2;12³¹;É|É4ÿä¿çÌÜ;w.4iÒ$RÔ1uC]—IP•TÃÑAEÍïmÙUH9ðµ þ}•$eH=ðXÿ°j¢\!Ñæa@€™ý.Y]þ¶™=ª“¬Iàp`x”7Åÿݙٜ¤Ià$ýÁÇ0kfOê& `_`\´×ä™Ãfö¸#AI>ÄDýF U/G9†7Úåý„™}Î_þp)öæ¡¥“ž?w¤]`ý3âN¢ä8Žã8Žã8޳2ø 5[ìÇŸ] IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rew.128.png000066400000000000000000000030511370472574300234050ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(GIDATxœíÝ?ˆ]UÇñï\Ý*`!"  b+ˆAÔ$blÄBP$`¡½)TQ\b@±^b#ØѨ øÁV0¶ñO XJLt,Þ»úx»áý¹çœ™sÏ|º@Þ¹ó[†sßìÞ?B!„B!„B!„B!„B!„B¨›X‚ªnû‡€{€›ËÀÀ·ÀÀ§"rլȌ†ä¯¾Tu?ðpË‚ÿú#°)"góWUÎÐüÕ6€ªîއWüèpBDþI_U9©ò_Ÿº°Tu7ðpÇ?ü ¼‘²¦’RæïÒ••ŸªŠª>`½ð½çTõá4U•“#5§U½8ìM´äOÀ>ù+ÑzYåÊ_Å ª÷gHàvàÁ„ëe“3¿ëPÕ U= ¼Ü”á®O%ò»ý¨ª·o÷f<ÌîŒkR*¿Ë@U’7<,žM”Ìïj0Û®kW¡ã,Å"¿›8ÛVÏ*¿ù)`:Û>ÃðÙ¶JÖùMw€ ³mU<ä7kU½8Éä/WÍñ’¿x¨êuÀóÀ 88•æ-Ñ(4Ûºå1±,8Ûºä5öÀ`¶uÅ{þ¬ ³½ÿüYNÖ³­µšò'ß<̶–jËŸ´¼Ì¶VjÌŸ¤¼Í¶¥ÕœpxœmKª=ÿ nõ:Û–2†ükíÞgÛÜÆ”å¨a¶Íilù—>Ô4Ûæ0ÖüKíµÍ¶©9ÿ¨q¶Miìù¯Ù5϶)´’Ǩ}¶ª¥üÛ:[UÓ@ø´–ÿ¿@U;àà)»rì´švh.üœ&ówªú †ïµœ_¦ú¸Õº#wÓpþŽÉ/7š ?µ—†ówÀAë"Œ5¿î².ÂXÓù;œÞ#_PÓù;@­‹0ÖtþøÍºcMç‹0ÖtþøÈºcMç€‹Ö…j:'"W€£4úe¨õü€ˆ|¼g\‹™–óÏþ5ðUà”U!4™Ûâ§DÃÙ3ôr‘;gÿÝZþmW‰ÈiàQ&¯iNkùw¼ØQD~žÞª~³Æ:ZÊ¿ð}c¿,zþ0oìù^î<ý†|ø2{5=ÿÒo QUž^6²UTØ¢ 7Úü«~`l7G.Û½±å_ùŽùx x?}9þ-ÿ —FMðpCšrÊ[u˜5†üƒîy‘O€C423ÏCþÁ7=¶43ï¤öüIßXãÌ<ä0¯ÆüIo{û̼Hù³¼9´¦™9åЫ*ÎÅk˜™s4@¯†üYŸ|1¶™yU5ä/öòh¯3sÎ`–×üÅž}3†™y¯ù‹>ü¨ö™y(ù‹æy™™KæyÉoöø³g攼ä7ÛzÖ3³ÕÐ3Ï_ú€×b53[7@¯Ù—G÷j˜™s²Êïf˜UpfþSDöd>ÆÊJæw³ÌšÎÌç3êRæõ×R2¿Ë‘ ÀÀùnÜÌý^[©ün&wîŠÈ&“oÉ¿g8Ĺ k&S"¿ëèMgæCÀ× —ý8›p½lr毢Däð,° \I°äë"r9Á:EäÊ_MˆˆŠÈ“sã…K‘3‰Ê*&Gþª '"ç™l‰§×øø»Àñ´••2¿Ë߬BU÷/³øã"âú‹ßª†æ¯¾¦O`[ŽNMü!j_Í¿õßå ÎKnåZ7‹IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rew.32.png000066400000000000000000000010511370472574300233150ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(GIDATX…í–!KQ…¿3®É(ˆÁ`°‰‚MÖbĪI“IÍþQl‚A‚«A, ‹f‹`1ù<†Y]†Ý™we·ÌIï}÷—{jÕ²T°½ÌO’ÆÛ³}lûå×·åK½€í9à˜î:úÔ ñ}@[À>0ZtGÒL„oô€Ç`¹—É(_hÀöpL$6/Íÿ1`{Øv,¡qe¾cÀöù ,Tmá³6¼\š'ó ÛÛäSš¤(/ÛwÀdjà=Âg€͉òp4â3IçÀð•R Êgí"7ÀÐJ4‘Ìw–…¤7`8¾L$ñ…ad» Qb•…Q¾p]JºVÛ~¢üÐã¸g`H²¤ `x-¸òåK%–¤gò)¿ê::‹ò©?¥ó@KÒàùZµþ]?Yý´¯ ßIIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rew.64.png000066400000000000000000000015201370472574300233230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(nIDATxœíš±kA‡¿ß«€……• …¥AmÅ"؉¢©ÄNÄtÖ)‘€,$iE› ˆ ¶¢Ñ?@°›TŠ/Å]ÂÙÜìì̼pÎW]±sßã1³ofÞB¥R©T*•J¥ò_¢Ü3;Üf€ƒÀ`YÒûÜÙ4°Ìµ<ò\Ò¢·?KÌlx óè3¡‹¿I,–™Ý^Ènzû“Í3; <f; Û”tÊÓ?•H~XŽt:ííï•3;Üæ¤Ë©”?:fvxœ‰ý>¤òGeÍÌ.oúÊcIéï4jkVrøƒ`f'ÔÖã©ä]Èå»FjëëÔòrû÷œ‘µ5%ü­ èQ[“PÊÿO&¡¶waW&¥¶wa'Ãf6¼-)ÅË?5”ßî–âéoÌì¼—ÀÛßøL«_fö™DÇÒH6=ý `^ò!®þØð ÀÛßËžxûIkÀ3¯ÜýÛ?†‘ ¿$ðôïì%­O%ðöï:lHú\–€¿%ñò·öJG·—€—¿õ¸)é#p XÏ€·lgÈÌ\0讦  eó‡>˜ëRr\rûƒo\$}®/SàíjŽC½œ¹üQwn’Þ—ñÛ3$óG_:NÊž!É÷}jvÌHéOríÜ£fÿòö'»w—ô¸ <~ûæíOÚxd’^WïCV¼ýY:/’6¼¥W[1`IÒº·¿ä‡’§? ®ÀV$}ÈíÞþJ¥R©T*•JeŸ²Ä ,Tw€£IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/ripple.128.png000066400000000000000000000033501370472574300241050ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíK‹U€¿EMˆº˜¨ ÁHŒ ˆøZ¹‘YDtÄM^n’¿@ÌJA7.\å%Š%YdéRÑ…“Q£!ÁDˆFñ¸¨éI¦{ª«Î¹UÝ÷|Ëž[·ÎôùúÞîû*‚ ‚ ‚ ‚ ‚`ú‘®ȪÞ̳À†ôò"p8""W»Š­ Š@Ug€ƒÀÃCŠ,»DäB¾¨º¥Ò'ÿÓ`[)-Áª®ÈÈ+'ŸTfÎ9–ÞP’³Ne'š’ذr‘Fe'š’XãTv¢)I€`B€Â  '(œ pB€Â  '(œ pB€Â  '(œ pB€Â  '(œ pB€Âé…ªºZU×vG.Tuª®î:€[»º±ªn^žfÒk—“ÀQà Ñ®â³DUxx xX›^¿| |*"ßw[ö!iƒÆ>ª7cÔýç7¬vé¨ê㔑‡Œî;¼<1ªð9°/÷†”¬¨êÀ`KÍKÎs"ò›Á½³ ’ÿp_ÍKæÝ"òWÛ{×%Ûw€”üCÔO>ÀÀ»>ù’šý÷¨Ÿ|¨Þ›Cé½ÊB’¿¹ÁåO©ê³¶eá9àÉ×m&£î´Lþu^6 ''¯´¸6›®¨ê`?í’°55©AŠuœ®n96ªê! ÅM€”üÀVƒêÖ®o„1ëuõl{Jà"@jºc“üÒÙôêÌ0êóoä’ˆ\6¬Ï¹üaX¥ÛwSœ’ðµq}9øÆ¸> ÌpL¾×™ƒê4—ÀDÇä‘Óõº""'¨Î$²ÆT‚Ö8'ÿð–C½¹x“ê°ÆL‚VþÎ_ŽSTãâÿ8Ô…ûNà[‡êMÆ  `ü;ÿFN;EäO‡º³""W€ÝøHÐzœ ‘‘üñè³c ÉoF_%K€H~;ú(Am"ù6ôM‚Z3lÎÉì9 ì¨óZQ€HþÄRK‚‘Dò'ž%*@$j)Á²Dò§Ž¡Ü$@$jYV‚%Dò§ž›$ø_€H~1,‘ ›Cƒ¬,Ùo]@YÜ4â_ËaÙáöøXCçZb hú9ÑCÁÓÍŠ³¬14½Ôšbéàé¤öúŠÚ;n%¨=Ý”®ŽˆKo×ÔêÛJ–I¥Oɇ1GC‚vô-ùÐ`(8$hF“ çB‚ñèkò¡ÅdPHP>'ZÎ& ^§:ÝÓšMÀþt°äD¢ª·SmœõHþI ~9µžN‡îÄG‚-ÀÛõæâFŸÚ”“TŸüÖJš¬HìÀ§;˜UÕgêuEUŸ^t¨ú°Ëê4Q³!ÎÝÁ^‡:½ÙãP§I³?ˆéŠ Çî`£ªÞe\§ªzð¨qµfÍþ æKœºƒ[ïÌÝ®¹Û÷Ö´ÙÄeM SwÐÙ³ `«y³?ˆÛ¢P‡îàœQ=9øÙ¨—f×UÁ†ÝÁYùÝ ¤,¤‡\,´¬Æ­ÙÄ}Y¸Qwð‰Q89isN k³?H–}-»ƒ3øœ·çÍ1à»×¹7ûƒdÛ2 Áü—öˆÈ¿>Qù!"רÆÎqÙ<“™w¥l;p¼Fñ3À6«‡FuˆüJõp¬:-Áq`{ÎäCO »NÞÝ <ÆRÏRõùÇ,?ù]. SÕUT"¼<2ð§kT¢ "_YÝo: ‡ªÞ Ü ¬~òú¶ß—5i”ðAàoà—t´|gt>¸""‹]Ç‘‹$xo~ÒÆîà  '(œ pB€Â  '(œ pB€Â  '(œ pB€Â  '(œ pB€Â  §$®ŒQ6ëÊÜ.)I€Å1ÊþàEÏ(I€:{š”hJàõ6l.¤²EPŒ"rØÅh ¨vä^ÍU÷t¾1$7騹9`Ø^^¤jö””ü ‚ ‚ ‚ ‚ Já?‡Rh;õGIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/ripple.16.png000066400000000000000000000006751370472574300240300ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÛIDAT8µ‘=ŠA…¿ …½„‚·ØhóÕ@/¦{ö,h0W03ÿLjDÇÆÁ•}ÐôÏ{õªº þêR]>ÒT=ï¹þlЋu¢~ªÑª•:W'E'u¦ÖjÓŠÔº»2oR3»© 6Àø…‡ä†À¦5 u l·BP“û¨À€ÕëMŒˆ_`Žd™ãˆGà˜çqr—ìQWQ«$>€R§§É]‚ïÙéy;ÆÎB]tÇ8¸¾DÄØ—þ_w=(‰ŸÁ ‡ÿy5A/οz4'O¶HIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/ripple.32.png000066400000000000000000000011651370472574300240210ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(“IDATX…í–¿JC1…¿_©ŠÚgpr­à¦«n"ˆƒ.Rñ…tZqÑÅÎ.‚. 7'Ÿ¡øÔã`ÔÛÛ{{“V‹Ð$$'çËÍ ôº¬]£$]³jfú$€%I÷®,µ;O®†±”z×~E}€ÿ © iWÒ¤Š¤ßI%JÚwÞI… g¨ó@˜–}€`Öy€JD@$¼ëzx‹µ‹i -Âo€“€cçÉ„ø4 ì%„×€ 3{ñM7³g`¸Ê‚°Hx˜ñ nÉ„ºj@ÉÌê¹6Ã;Õ÷—øÚ‚îÞdåÌì Ø¤y¿þR?[Q¦Ìlð8p4/$ܪkÔS@(þ5pÙìXnòŠÅÌv€Gø%lÔI¨0ªÅ´)¡kT,þ¢¸E·Ïì0ÆÅtI80ÅtH0˜¨â N%ƒ Âg’tÞ œ\I^P ‘ާVyw ]ìªÇà¸J¨œ¯T®®"%T>_ëhº!R꣕ÉZåL°íéfÛ´9Sí¹U mOÓkWƒA“ÐQ?f€uIîË8I×€-Z\£ôÝ,ã“0 ¼t´kÊ*þ¥¹kæÚŠ”°(©õ¥¤+ÀmGÓ¨Õ©{O0B‚q>?½ñô½4ÚvJØ63ÏÀ…™ý¾×4i´/ý^àŒ„ª½¹?À‹Ø>#xb”9¤á¦L£Wc!Ðð‰‹¨màž™ýhÒ§3î.p( ðxÐtGjà{UÒ,0sÙ·4œŽÍ̳KÜ“‹ƒœ 0hÄmeœÉ¿H@j²€Ô ¤& H@j²€Ô ¤&•€ªILë (©¼sO&þOS™L&3*ühúz/¥=¯IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rolling.128.png000066400000000000000000000047721370472574300242710ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( IDATxœíÏ‹UÇ?'ÊØ: ê,""£ C &t2Düµr#-Ì 71:›dã_ fe@7.\ÅQÄ(éEpåRQÁÎ2d!ƒŒ0FÈŒ? u;T§ßªºçܺ¯Þý,_WwºÎ÷Ý[÷×9P( …B¨ê‚ªnìÛT¨ê&U]èÛéë‹Uuð,ð0°9||8 >íÉ=STU€'€¿;€U±_>>‘¯ûð-¹TõÀª‡1éûW€—DäRÇœPÕÍÀÀ_']|‘_“8H*U½x ØÕð– ÀnùÞÏ+?Bð?þÜð–àEù¿ŸWkÙê‹Bðߦyðî^óñÈ—Ðì¿NóàCõlÞÏ* IP þη?¤ªÚz”„Ç€;Ü·“„"p@dðWyÚÈ”<qo2¸¾¨êÍT}þ‘¦~vZŒ ÂKèn` Ø>>ŽZ¼„…æÿ4°)ÒÔiàyù_¬Oãp€aðWÙ."Wb „—²ÃÀÖ1—œ^ˆy¨êmTÃY \EàÒ„¦ëvÁ&üò'Ÿð·ÃáÚ\X¤òÉ¥;0€QŸ=—cýTÍþ¤à¯²5\Û¹LÕmYáöN`*§à|n`cÉéÚq|a`£Ž‹Ìà|Þ5°³eú%®Ç{6®Ç\&p >À19m`çf§kG""'€åX;#0A´œƒxÅÁn*^¦ú¬1A”ÂPï>Á?E5/þ‹ƒí$ß÷_9˜ß ¼£ªŒ1ÒYãü:§€½ž ©‘Ÿ€ñÁ"p$FP‚ߎœEÐZ%øÝÈU­P‚GŽ"h,€|rA£Å çàìi¼€4U%ø3K#L@ þÌ3UcP‚?&Š`¤JðÇX¬@ þ`)‚5(Á<ëDpM%øsÃ$;RȆ5;«K0_¬›q-/óÃÈéö2 œÆ®µ”‰ á3q¡­L›©«¬e1h¸4Zb/ËÁäñþŠÆ‡CEà~ VUÿÝæzù‹£/Ùl®i<”ÛN–Y%§àCË™À"‚8r >t˜ ."èFŽÁ‡ŽkEíÈ5ø±TDÐŒœƒ‘«AÿÀ.JEàPfÙ:Z¡ª7QœõþI FNÑËÁ!©á^|D° xÕÁn*29ChWNRýò£JšìŽ|K>¶y z“¾xÉj*¸¯‰ P­ô &ïVà#à€EéÚ6$@(rôÍKÈ_v‹È÷ß\!øÒ|;Û U¤á-Õª‹5 >À=Àk>ùšý×i·—q KÇC"D––{HUµõ( v¸/YéxH £º‚O¹“’g"îM&WÖ| 4©3AðµMW7 “º€Óp€ñ©Ø[Y:)|+°ÉÀŽû)i„¦ë%©”‹Àa¯îÀ\Nµ„/‹ÈC{®„M?št{'0€c!éÏí¥à c{."0€cðxרf bÎŒÃ\&p.!LDN;ØuEDNàsžÁTÑpþ ໩x™ê°ÆLQ0çâÕ¼ø/¶“|ß‹Oæ“y‚ÎÈ=ûU.äžM­“JðÛ‘³Z  ¿¹Š •JðãÈQP‚oCn"(#†Iãú ¥dÌpi$‚R4jØLA)7|&Š ŽœÆŠ ”ŽFŠ ž/Ö‰àšJðç†5"Èâph!)kÎ[–.`¾X7ãZ^燑Óíe8Œ]k)AÃgâB[™ 6SWYËbÐpi´Ä^–ƒ‡IãýOÜ:‹ ñúuWrÉ|ÉfsM㉠Üv²Ì*9ZÎÄ‘[ð¡ÃTpA7r >t\ ("hG®Á‡ˆÅ "‚fä|ˆ\ t.½ ‰%gU½‰êà¬GðMJËE/;Œ†*ÑÒ«vSqÉB»bVZÎd?€SÁèU–B©X~jqmôƒUÕÇ'cíŒÀ´¢¨Ù†çî`¿ó-®ý—Á÷í3°q=æEMw9vÛTõ¶HMjv¹v¡2Øý16FàRQÔ|K˜SwpírîŽâ(Í :Ÿ ׯp7¶ÏÖ­´Ëž@§î ª¶AHÃþ“EpŽêAǦl·¬ÃàZHÚ5ýªqþ ]E%ðr7°l Ÿ§jöZäëi⿌µC‚BÒîùw&BΊÈSF.%AU?¶F˜HrdÞ}[¸Qwð¾‘;)‰ÉèÚì×Ir. rtpŸ|{Þ,Ó¬jøõ¸7ûur/s‘.!¯ªwPÀº³á-Ã-×Z‚=4gŸa†ƒ "ßQÇjÒö¤ >ôX>>Lïî¶³Vˆg©úüeù­߬QÕ TBx¸¯ö§«TBSD>ë÷ޫp¨êíÀ]ÀðÅP/gÂ,á½ÀÏÀ·!µ|¡P( ©ùÚwo¤‚¦:ŠIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rolling.16.png000066400000000000000000000007021370472574300241720ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(àIDAT8Ý“1jÃ@EߨäÆ`b‚o‘*}œÂ|1§ð |)Rè îÒ¿4³b³Y’2„–ýF³¿ ‚ºR_Ô :¨[uÕrE°QGu*"u§îªæSj6¥n(ÅÀ¸ÎÀGòOù{çÔK“P×ÀpßlÊ÷¢Ã}û¡{ž_`ˆˆwàÉ1—±.À%×Ë保GÄ8DÄì“xzN¯“›‹(Òém¹Fõ¤žrêk{=¼rܸÁ]ÍA=ÁŸrPã¿æ`îÔ˜ø{õÏôØ3ñÚ4\7_bAâÔ²æa IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rolling.32.png000066400000000000000000000013061370472574300241710ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(äIDATX…í—1KAÅÿÃD4~†Tiƒ^ ]Ò&¥E°PzB>LÚ!p—ƒ`s‰µ`šv‚V~†#*˜¼NιÙÙ½™…{00»ÿyûÞÎìî¼…» Is’>K:’Ô’4›Á}$é«ã~’47ŠxGÒ‰×ÞcLÒ¢kÔÖn§ÌÄTLhõ ô78^>º¾ß½ÚŸ`lhIj˜YÏ/ÔÅ€­àÜã’>@Çqb&f¢o@Ò ð%"ÞÞ™Ù‰0³s`ø5Ì„yâMàyªpÌGú)è 3ëÕF¿)ú3ñ 4FñÔÌì X§¸^·‰ë%b¢ ,˜Ù¿»Þ˜ÝHý)°_%Þ[àL¼w|Ô¦¤‡©·'ihS|®Ä 8= 1ñ XN5¬8N¥xÁÀ…¯f¤ˆG &v¸zCö€Í ߀ŸŽ»S&wå$M™Ùe†8föXMáFg ¸X–x.·ÔÀ¸ò@Ô€·+¾âj™^oR KÀ Ç}Md,5‘ªP– &n’ª0ÉÃ0É}LòÀ½Î§%}ÈÈ…ÝÐÌz’?HáØ\?¼ÛA-9”ÂmF’ŽÝÆ2“Á•ÔvÜìŸÓàb9I(›ûÙÆu•­&ñˆIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/rolling.64.png000066400000000000000000000020561370472574300242010ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(LIDATxœíš¿NQƃRX€ÄW€h 1ú¤3B|5;±ñ ¨%Q ï Fƒ1D©´6Q(ŒŸç^¹÷îÝsvC`9_²ÍÙÙ™3_ÎßÙ2êA’æØ#5‚OJZ>HÚ”ôTÒ¹ºrÄ=/iMÒfˆ½$i2Õ_ƒ’.+Àxß«ßÀ¬™}NíPEÜiàp¢ïÕ60ofc}F€ü*ƒÉ:v/Ögî0˜<¡/«¡oQˆ"`Oòc%fWªæ¦¤QI ’Þ‡gAÒhÅ7Ç€«%&c$à&À™<€ÌL6wyàdxæC[þR=e£Ip‘<À‡Í5g[Ô×ßQ$T™ü6ðÈa7álëÇbˆQ7 ¥„mm_ò;ì®Äß¶I0³oÀMà§Ã¼CÂÅ2£¡„䟰;G«°Ì¥lC±0³Mà~VÊH($à &ßA“$ ¬ª‘É&t¦èÆÞÆZœ|$t 8ÉwÐC‚Á‘J¾ƒ. EPá9JôNivGç@r˜Ñ³kõ/‚m'a`Ë.ÚÛJBáy¥ðvIBáþZI[Eíf6ᣑÃZáI°éãfÓhò¤:ô.pPIhú˜^z $ÜŽª0,KrãXH: ¬ÑॲÌá#axè°KÅ"þ«¹ë‚æªE’pYRã'JI§€KÓ¨Û©»&A‚‘Xnwø­BôÕ<ª*ì$aÃÌ< gÌìð©Ä$©.ý_` Eµ¹?ÀƒXŸ¸bôc›Ä¢LÒ¯±hxÇÿKÔpÝ̾¤øtÆý ÌD¼n¤V¤jÏUIãÀH̰oè$8ü53O•x(Ž×ù njÄmdIþ;ÜÔ& ë²> .}@ê"˜õmѤ mú€´J¶éR‘õd}@Öd}@"²>€¬²>Èú ë²>Èú€¬Èú€a_T²> %ú€¢Qåi­Ñ¬;Ûºh›>à1»eõ_áY mU~«}5®Þ:Jdf6ë×{8?äuÖìgQIS’žKú*iKÒKIgö!îYI¯B̯’žÕù5ÖD‡ÆÃ¿úýŽ;´ uðì $(qAxIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/save.128.png000066400000000000000000000023141370472574300235470ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(êIDATxœíÝ?kA†ñgEEmEc*1°´õ+ÄRÅÆ"~õ¨¥¥X‚ ‹ø´ìƒ°Ñˆ¶&QÂZìE£‰dçnÆÙ™÷ýÁu·³ûdoÙË퀙éjRï mÛƒÀ`˜§Þg$À+`xÜ4Í÷ÌóI"imÛ³)÷ó¬×›¦ù”{"±% `ô—ÿ„òþ–÷ÀÕ¦i>æžHLûŽ}…z>À4ð°mÛ“¹'SÊæŽKu¤ àL±sšµm{*÷DbHÀ‘„cç6Ew&(>‚”Ô®ŠÀdŠÀL®è@ÅFàâ)2‚”wßnr-Åøf¦î'¤DÛa¡IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/save.16.png000066400000000000000000000007041370472574300234640ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(âIDAT8íÒ±+…aÇñÏs»)u‡+“åfSv) ¦›Í`ó§¤LºñˆºlìF¥,&›"‹âƒçÍKïÛ‹Ù·NÎóœ_¿Î9I&"ºØÂ¸¯öSJg*h•ò,ac9¦±ˆ½ˆXn(8ÄnŽó\»ÂN•H•@\f‘þ_p¶#¢W<´ïð†õoõ)ÜB‚ˆXÅ ºxÆ+^p„‡RcXK)]”ô1Wá`›¸¯³X88À|ÍŸGÜ伞pœR6Í&jÜ0üéjùø¼ƒÇóNá É8Ç™"¥IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/save.32.png000066400000000000000000000011021370472574300234530ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(`IDATX…í—±JA†¿ "Ø$!•EÀÎRß V'ˆ•`#–>‰vö©BÄÖÆ‚ˆ¡¨`#؉U¬EÇâ.ç±î^v³lî‡åØ›Ù9N°HUÀ6°l³[ô܈ȫçþ\âØNß5Dä1Ä©áX_ ÐÎTu-ÄiÁcÏ=ðä°íó&0PUï“ð¸n=>€éIœúB¸R0‹Ž2HG•ïDNƒ¨`&ˆª&ÇÄ@U­7˧}5,±µ蛆Øø Ø»h[Œ8„ø£<Fÿï’Þ€Ð3üÆÀp —6}/€,¸­ÿ¯;|¯HOà»,À4SÚÿ·€]"Ó[I,D×0–€‹­Ão-uUõxF"¢Uld£Lf-]À|:¡òzû/€\5@ PÔ5@ øÏ6By¬â×p”=Wçü¸œL~ÇÃV3¸³QšIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/save.64.png000066400000000000000000000013671370472574300234750ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí›=Nä0†/°œ® ¢Ø % Pì)¶@07 EB!q.œ€?y‹ÌŒÄÑx&_^‡ñ#"ÅžøÍ#Ç™qs\Leïý°,³yž€ àÀ9÷jpüoÄ ø leùÌ °Ý„„_‘õ—MR|g8öÞO[7+À¢Û‡Xެ%Ä hs © c ±ƒàC hmˆ¶;‘õo-çÜËmiCèaÒRp_Q¶zï×ÕXŠN€»ŠòZo‘) øÎ¨–PÛå¢hPBª ! ) €$¤.Œ%´AÎ1¸E¶EÀ;pJµ„E`'æ “£$2¢3â÷W€ƒVnS”™˜Ê?Q@J϶û(\ ÛºÛ?D^·u¢ð\v?ÃÒ5D©€!æÿ òLÑí¯(N> BcÀ.°A½³À3À*°LÔxÜ‘ °œÿŸ§›„„ëùÿ9‘ ¼ &!AýKP.A-ÄRB ¥O†*žµ‘Þšƒ}çÜÛ×ÂTz€%³kvË ÇA@•²ã$ ô×8 (% PP“¨¨ÉÔÔdêj²u5Y€:€š,@@M  & PP“¨¨ÉÔÔ„<5š¢Ëv†\QQzN¡UbûÝí2;-jAÿ…lu$ùw~+4Ë8IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/sequence.128.png000066400000000000000000000016401370472574300244220ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¾IDATxœíݱmÛP…៯œ÷YÁÈîãÖk¸Îé¥ÏWðÎ RP)d A§1tß…Ïÿ•nHè‘È{’$)ÑòïöûýGà3ð ø¼¯>©7î øü¾/Ëò0ódNØï÷ï€;àÓÎ(Ë ì€/˲üžq œ†ÿ¸šq⸂ã7ý‡?Ó‡”[žïù?ð²?Û \WÿO0ðžßÅqåõÒßGù,pY}P½¨|¸¨>¨^T> ïýá @8΄3á @8΄3á @8΄3á @8npxO]=”ÏbÕÕ‹Êg18¼“®Êg18l¦¬ÕÖÆqK¨Ôx~½üÀÚØÍØt5¬‡¹«aϾ¾áí ÒÊá3Ÿ2|p=|†Vëá’$I’$I’$émÛ< êÆ‡S¯ö߇Om`wñYlº‰[ÀTÎîôJ×o–ÝÅçuê&nw°»¸Ì \wü½ç×ÀMÇÚK«Ž°»¸ÎeÇØ]\ç¢cTÈ„3á @8΄3á @8΄3á @8΄3á:Àîâ:O`wqÇŽ°»¸Î}ÇØ]\cví`wq™Ý²,íCÀÕ°½WÃì.>›M7qË+Àß\5»‰%I’$I’$I æGÖkõpæ»y§Øt÷VóÇ£{˜ûãÑØÍ;Û©»·Úb7o+p]ý?ÁÀ{~ÇY”ÔK峨ÍÛIù,vóvR> ïýá @8΄3á @8΄3á @8΄3á @8n`7o'峨ÍÛIù,vóvR>‹Ý¼]·„J »yÛØÍØt5¬‡¹«avóN³éî­æzx½Vëá’$)ÓÓµ¸#¯z†¿IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/sequence.16.png000066400000000000000000000005461370472574300243420ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(„IDAT8íÒ; 1à/ÁÇU¬¬ÄVO©{;o²•'±±ð±Ð• &¤uº˜ágþ )¥ ÊðÀ1„p„ v˜ÀÝ@b¥f9‰¸VÜrÞ¬ Íòš¾…”Ò{¯²~¡#â²Ð «±€*Œœp/ô÷­|ÞøŸrÔŸÃ&5Ýš®©IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/sequence.32.png000066400000000000000000000005561370472574300243410ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ŒIDATX…í–¡€0÷Sƒ£.pÔ…£ MÀ›"~m˜»3ì<üŒ•RF`:AþLf¶¾ Ø€^P~“ÍlxzLâr¾ò“¸ü“€,îxÍOÀLý]W~Ð.æùH¤ëªiç•®³wÀ.(Q ð ÒuöPè:4ÝqÇUâ*þ@~2@мXÙIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/sequence.64.png000066400000000000000000000010411370472574300243340ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(?IDATxœíš±mQDßÿ©‘\ƒë°s Ê ¥ 7@nrwà þÿ¡ÕŠÑêæå·š™»àv´`ÖMc|{à x“*zžðZkÑ!m1ÿ ¼g){1` ¡3ß|Uó0µï£wà3O‹Œ°‡l…¨{è™**âÔÔ8µ5@-@M®j „=tàœ(DEØCÌ…¢*¦‡}Ù¢vÀ‰¹bVáÆÔÞ1Ƭ–9¬H»ü¯MN  `»<Ûä¬icŒ#°Íš÷"N™üR¯`½f®ÃÕÌlܨ¨qjj€Z€8«b»œú#T±]>¯~Jû µËn“1Æ,øV¸àÌ#¾Ʒ¾ö­p  Æ¨¨qjj|+LÍ6÷ß Gö­°Y9w)ÿYÕŽÄF¿IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slide.128.png000066400000000000000000000033651370472574300237200ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí=ŒU€¿³(¢Bð‡ŸÂ¨‰¥$‚ˆã_ec,ä'vüÙ@cB£F*I´±h Ñ,¥¥‰ò—Õ€v&²#¢®Ác1—õíîÛ÷ÞÌÜûæÎœó•»oΜÙó½{gî{ÇqÇqÇqÇqÇé>ÒtUQÕ%ÀãÀ£Àjàö1§ðp¸L‰ÈÍ1Ÿ? ­@UWÛ€5Mç˜&Eä÷¦)ËDÓ ”%|ós*>ÀZ`kÈ­U´NŠf?§âßb-°¡é$ÊÒFÖ5Àrέ/màþ¦Àª¦(KXÚtÈ9·¾´Q'".€q\ã¸ÆqŒãÇ0Ž `À8.€q\ã¸ÆqŒãÇ0Ž `À8.€q\ã¸ÆqŒãg¬¨ê2U]>Îs¶ U]¡ªËÆyÎÛRŸ@Uׯϖt©êuà,0 |."š:QU^¶OËÃÏ/_'DäÛ”9$[¬ªKƒ7è<§×Eäòˆq߈^2DäÐ(ŸSÕ5ÀÀ“ƒ>|‘™é- I ªwÇ)Vñ“l3pBUW§È%GBñ?epñ¡øÛ펇¿it¢ =JQØQyx/v.9šý÷K¶8šB‚¨ôS…ßVÕçbæ“)ÏOU8n $ˆ&@Íâßb{¤trfGc£KEU½8L½âl Md' ×V¦kìÇ&Š{‚»#¤T_€Pü#À–úé°ˆra™²X!ÎFàX j š¢cÄ)¾SŽÀ‡u»ƒÊDêóçsMD®GŒ—"r ø-bÈÚ÷•HT|€/#ÇË‘¯"Ç«%Ai_"ÇÌ‘Ĭ,A)ŠÏ'ˆ›"r8™ t% F qñÏï$ˆ›+oS\slJK0’ŸóûqØ+"'ˆ%áZw_'_jœ`¨‘ŸóçsØ-"$ˆ5"ò'°—4Œ› nV¨ê ÀK BŸö”)>TX”¸;ØŸ fnìK³T³ßK¥ÙÀ„ÝÁzU½'rÌlPÕû€Ç"‡-Ýì÷Ry:8Qw°„r{ç´‡ˆ»-O¥f¿—ZÉ$ê’ï]Ø 1¯­r³ßKmt?FŠ“#?EŠS«Ùï%Js±;¸ "¿FH)KÂf˜ß× S»Ùï%Z©;ø$R:9Sg€(Í~/Qß ¬ÙL‘fÝ|nœ¾©p\´f¿—è/…öHpºÄa—€}"òoì|rCDnRŒ\*qØiíÝ œáãSÀ+£nÝDdšbíQZ‚SÀÎŇ„ÿ/@DfDä°‡bÚwþ·ûð&°ÝRño$ؼ\œ÷ë›ü?£w ÕNáp»øù¨ê½ÀÀ2à‡ªwû]z —0JøððsØR.9ct‘«ÀÕq¯m„/ÄØ}eq\ã¸ÆqŒãÇ0Ž `À8.€q\ã¸ÆqŒãÇ0Ž `À8.€q\ã¸ÆqŒãÇ0NH¶H"­ûï§mà—¦@ιõ¥\h:Ì_â•=m` ˜n:‰>LSäÖ*Z'@X^=I^L“!·V1¶Å¡±QÕ%À`° ÷V³3Àà;`ªÅwÇqÇqÇqÇqÇ ÿ:—ñ8¢ajæIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slide.16.png000066400000000000000000000006551370472574300236330ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ËIDAT8Å“1 Â@Eß—TzÁÊ{Xˆµ½ENàìZÙ{„ÜÀ#äž@«€'Ñâ[!Y³"DðÃ;ûçÏÌî t„Úœ¶GÀ¤vo T†Ü$"<®¬Ž²²zß–Ãïl§¶¶§1²íYÅI_¾ä d_$402ÛHÊe{lhþÈ8ÁC`ˆ­»¾o-,+Ï9¨£úÀ®:g’ò@Rn`Ü?d¼`+)‡ø$NÚ*T„ÜÿRlNÀˆæ2»&kÅ7¥FcÄla@IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slide.32.png000066400000000000000000000011421370472574300236210ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(€IDATX…í—±JÃP…¿“讃>8ø ¢á E:ˆqPqAÁ—è øº8;ø-º õ8ôVÒ6isCÁž1ùÿs>róßä—bŠmÏË#ú ¼JjýÀ607¦¬%鶬gP"`>Æ0`âšLrl¯Ù~²ýl{½ª¹íÍàñh{µ€í àX ;v'ÃEà&x„‚K Í\þ¬ ÉtwÆžRàrâ  ¼U: … áëÀÕ@xžîJo¹ßö%5g"Â'©¸°MBÿ:ýºIÀýkõÓú^‚ @Ôs :@MÒ’¤¥²î™úZg]R2S é>"NmGçŒá©ª‡,úF@$Dþ¸ôìÆ…d v6ð4$E¿¡§¼¯Áðe®ÂVšdÃm” ?Ïô¤Àg؇43ÂÄL`2Æ=½¿ù9žüe€2'žÒ§"¨v4[f J>€Iíßÿ­//”ÙnÌIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slide.64.png000066400000000000000000000017441370472574300236360ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí›ÍjA…¿; ":£ø ALPDüÁ…O êNŒè+ˆ"îŒà#d!11 ‹¼„˜(HÄ ºÖµ I6.ÌqS»3îêNõ”:õAIîœ{ÏI§»ª2D"‘c¬-aI{€KÀ$p°¡Ì° ,›Ù¯P³ei3€ËÀù@roÍìu ­6D“µ¦jåh3€¦—}jåh3€‚@ìb“ˆ=@lR±ˆM ö±I4y‘¤Ö6QMi:S­$MHš>HêKz!)䦧’¦$-Jê»™f%MÔÑð@ÒI` ¸t}ÀEà•¤ãuš†@Ò à%pÁÍÒu³-¹Y½ð À ν‚oïîû6 È=×{;=`Þ7„Ê2æ»%egGy_p§MçJJºx†P€§y™™ªšd“êÓ,¯v  †y€eš`¸°ßx”V†P@MókÀºÐ̸ÞU”†0€{¬Íág~¸mfß  ‘ånÁleð…­+ °ù¿•.ð<{%t`lÌÈ…Ð3ó¶Bèrãˆ:fÖnáw7ý_X¦Íìc`ÌBØ2™§À˜„3ëi·Í\{ æž«»t3{ZУΠ|È<¬Ý•pǽ Š.0'é¨GmP$Ù…yØa/à §ñ ¡<ö¨ Í þËõBóP²¬ÂI#[GH:œö(-5ç5B0Z|·Éýª¨4'Bž!¬˜ÙÈžföøTRâe<Ï3!í¿|tóÐõÞÎžæ¡Æ©°¼¼çÏÒy¸jf_|uBafŸkÀÀ¨€wÀu_óÐð÷VRè”]ö£Xdz6ÍÌç„(ÇÞ†ÃÔnÔ&»¹ÿ¤¿ Æ 6)€ØÄ&{€Ø¤b›@ìbÓfµ|eÑf«µúµr4Ú y2xÓDš 2Q"‘H$òü‡Èm“/’ÉIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slip.128.png000066400000000000000000000034321370472574300235620ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(8IDATxœíÍ«UU‡Ÿ÷¥¥XAN¢‚!‚Œ›)Dô5j¬4šøÕD'ý‘£‚š4hd~P„·ÐÆE ò á‚EP’ƒ40-ÁÞ{=çrî¹gí½¾ÎYï3’ãZï]÷üž»Ö>{¯½†a†a†a†a†1ûHÿªz° Ø ¬s/ŸŽó"r=ýðŒ¶L𧏯kÀcKÔ[v‰ÈŘƒ6Âà“§8SŽi<Øi‹Íeã›gfšX®1®Í¶nÃ3à•gf˜Ÿ¶F¼òìqëa|Úyðʳ¬ôèàÓÖȃWž½hÃ0¦ rL€Ê1*Ǩ rL€Ê1*Ǩ rL€Ê1*Ǩ rL€Ê1*Ǩ r¦JU]¡ª«rc)Tuµª®È=nÏ=€åPÕõÀÀsÀZ÷ÚàpøJD4ÓØxxx Xå^¿| ‘sŒmRDUöê òh¬Á ânpØGóæÊ˜¦'€·Sßµäî¾ùxz\3àK`_ªj|ó,r PÕ»€ÃÀkŒ`#pDUï=®>.ü/>4cß v¿Sq'€{£Ò;)ÄÑ0nÚÿxУÛFà`‰%À@øZtVU_;¢‘¼< ” :†ßçõ@ÃÇÖ}‹“ Tu%°ŸnálrSt\mŸ¥ihŽ î0¤ÎdÀ…ÿ °)@¹5@Ì7v °:@9àP dÀM…‡þ´1Ƚd К¿˜Ë"r%`½!Dä2ðWÀ’Ù ²)|€o×Åwëe• ¹ÃWàÓÀ5GñY„šÙ$H*@ÄðŽŠÈ™u‡‘“4Ïà M ’ 9ü“À»ê.Å;îg†&¹Iø9§Ý"òo„Ú#q?k'ð}„òIÏD ðçüÅœvŠÈßjED®»‰#A²óQ˜Õðû̂јõðûL»Q¨%ü>Ó,Apj ¿Ï´JtKXäð 8ì÷mK˜…Ÿ„à3A,ü¤• ³~‚IÐI ?+A$h-€…_%h%€…_$ðÀÂ/’Ödßj£Õý‘ÞD>ãe´£õÒV3€IPN·^L‚"è|m¤Ó1€I• Æ:šYvU4ȧ“ )A/‰ûh$!ø~ˆ Ï‘kªº›x'Š–½ž“iÜ üDдîŒéÊ4†‘ÎÖ&Á´†O×"Á4‡‘¯̺Ó>$¸4«ÌBøèj “à-š§{†fØï,™U½“æF×áŸ"á'd—ƒEä*Í •1$ؼ¡îR¼Ïò‰lÃ)š¿ü«j$é~÷‹í Îr°YUŸPwU} x%BéÓÀ®”áC† !‘—ƒ½j.fO„šI§ýA²ìЏ¬WÕ{×¼‰ªÞ<¸lòil[Â"-·á÷ __"ì{–eÚ$ëžÀHËAÌï@Y;Û´?HöM¡–ƒ_ÕÅoêdöÉ.]Ήȟ†4÷¥ ËdŸö)B¶|h8ãèòœÀ"¦ýAŠ:/g‰óü¾Å~hѯ˜i¢€! Nxt»ì‘ÿâŒê"rƒæ\Àn'(0|(P¸)ÁvàøÍÏ[R~i”ˆüAóeV“ÌÇí%†kXwzw/ð$Þ£Yó¥øË_bl=Þø¯4b~,"ß$“_ž¥ ÐGUïV¿Ä<Úoƒ;Køðð»{´|ŽqxåYüGö‘KÀ¥ÜãX 'dQRNB‘ÇF:L€Ê1*Ǩ rL€Ê1*Ǩ rL€Ê1*Ǩ rL€Ê1*Ǩ rL€Êé×<Ú¹³ÕÂ+ÏpÞ£ÃOžƒ1Òã•gÉöÞ÷ñikäÁ+Ï0Ïd7<.¸¶FÙxåÙ‘ëÀ®e:-ÐÜÑz=Àˆøæ)ýWÜcÖ¶›uîåó4Sʼ…?]Xž†a†a†a†a†aÜâ/ƒŠ€ùµ"IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slip.16.png000066400000000000000000000007161370472574300235000ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ìIDAT8¥’¿mÂPƇ¨RhÀò.¼‰D¤Ì‘ÞcP™"Š€hh˜€(e¾4ülGHØ×œôý»»§mKR&)iàK$e` ¤ f§À´ÓÀXªZ€¤¾¤7I½ë9Ö iäÀ;0 ¨±c¹kêN¬€8»@·u,VaH×û ðá¼%ýwv ¬}í„'KaÀ7ðêkâ=1³ÈÌ" ©p3àVÚÀÌÎÀ‚âÖq0mBñ6 ×ÅÜC$Íݼ ¨/àØšÙ%ô”<ä,+صŠýUëŸØ>Cï¶]€_8pV´×ú3¸IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slip.32.png000066400000000000000000000011671370472574300234770ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(•IDATX…í—=NÃ@…¿qr.€Òp@A$‡ EJA!JRDp”H¡¢ƒŽ@—€ NãØ»v‚ÃßkâLÞÎ÷ì]¯øó’Ô’t ©µ ¦IºÖ±™mÕ e&~@泥̤FhPÿ~FImIw’$í”øöÜs+i{‘Þ&é1ýb¶hº €†—žÌl3à3àXóÒèšÙUÀ›2K¯@0 ž‰™eJ `à=¢ŠˆÀ'ÀiI¿÷,"Àç9?6³ëX3ÿ­ ±“_¿ÈÁ—¡Ù ³ÌfÖñ…p¼g_Ò\1?¢fÍ0³Å9\–Ò)È›y—™$u€K‹p˜“Ud£cƒw_‰.ÅÕÜ—Ô.·#ðn,xtð,âLRaœ×Î#ðÂnX $DXÈþYxe€Lˆ#àxzfVX¤^ë¯î=¬‚ã™üa“„à9_˜ú³!æ oD¥IßVÞžUóú/$¿>ÀØÇeÆ%냹ê¿fu1¿¯ÞD†ä§²Y¥ôIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/slip.64.png000066400000000000000000000017451370472574300235060ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí›ÍNA…¿;ÂÂH|Œ5Cô=Œ²3@|5wâ;°”;ßAwþc&°p¥k ã†ãbªãd螮꿢¥¾d’IwÍ­{NzºnÝžD"‘8ÏHš•´.é³{­KšWÓ霞kcc³÷/»O³Uruš¤OÀÂÄàC3[ê*³.(Ò9È9HÁ±¾“«sÐygŒd@ìb“ ˆ@l’±ˆM2  ’¬1¡a$-JÚ¾HJz-ézx7$íJº˜›’›Ëx´øž{ÂìJH I7m`~âÔo`ÙÌöã]Þ'Nkfö50^®ÎF®'~‡Óâa$ài…°9-7ÇŽ›³6µ ?7eØï°¤ ÀÝ)CæhÈ„ZxŠ™) ô PfX#&T6 @<ÀûØÎ¬wCk›PÉ€@ñGTë.m¸Ï–QË„`ܲ¶…ŸøcFw쟡ó˜Ùà!pè1<3áVèÃË„Bz.>£Ô„iW€Üë PG¡wß³Jéj4õÐs¼–âÒU §&x×!3>ÑÌl(i…ÑMÑç¹á©u¸maÞ•`eimW A{®Mè¢üÞ :¹ ˘¶$õ$]viyïQ©à&ZÅÏ„yàE…i6ðßrWÞxUîš°$É»¢”t¸í1´ö®³VO0À£¼Ç79¾ŒF¶Üµ»Âž&ì™™waf¿€oS†4Öohä¹À˜ y=¼?Àó aŸ¹ÏNrDCâ¡ÁGc.¡eà#ÿ6{À=3;¨o¸dB|4%|46ޤy`rÙ—Ä[NÌ̧K\#W§W)JD âµ¶I¿ˆ@l’±ˆM2 v±IÄN 6ò»;}j€ú’«s¼Í9‘w¬ïäë<W"‘HDå/Ói¤«æÙ¿ŽIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/transition-tool.128.png000066400000000000000000000022001370472574300257500ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(žIDATxœíš;ŠW@Ïk°@Ú€6`h3VàÀR>±£Ø ˜D¼™F¶7 ÜH OAÏÀx<Ÿî®÷»ïEqûÂ9UEC%®É9?Þ¿Àsd$¾«”Ò·C@Îù%ððªÄP©Î¸L)}Þ:(]ßùP~4öÀo[Ÿ;}åÇãðûÖ!;ï|‰Éë­vÀ/‘>\l°^XDú°ÙÝ®ÄXXXX‹÷­ÐÆá}JÉ¥‹|0€è&  7]åƒô¤»|0€^ !  ÃÈhÍPòÁZ2œ|0€V )  ÃʨÍÐòÁj2¼|0€Z„Pƒ0òÁJJ>@IÂÉ(EHù`%+ `+¡åƒl!¼|0€s™B>À9L# àT¦’p ÓÉ8–)åƒôòÁžbjù`1½|0€‡XB>À},# à.KɸÍròÁnXR>,, `iù°vˡuPþ5+ ü[¬€òï°RÊ¿‡UPþ¬€òaö”ÿ3 ü#˜5åÉŒ(ÿf @ù'2SÊ?ƒYPþ™Ì€ò7=åo$rÊ/@Ô”_ˆˆ(¿ ÑP~a" ü D @ù•ˆ€ò+2zʯÌÈ(¿£ üFŒ€ò2ZÊoÌH(¿£ üNŒ€ò;Ò;åw¦gÊ€^(z üh€ò£eÊV(PZ ü©€ò§fÊ@­”„(?¥P~0J ü€” @ùA)€ò³5å&çünKÊLÎùpvÊÌ|8ï üÀÜ–rÎÿtÜG6’RúùØkïʇþ…J#ɘžÇäƒLÍSòÁ¦åùpàKýu¤ÿÞwòXùpàï’ISþ÷þùpàcɤ)ÿqwª|8pì .%mØspœ'`—Rú\b‘Ø—)¥ïp¾|€tssþ x¼.€Û÷”‚|>W%äí$[僄¥„|0€”’Ž’òÁBQZ>@jÈA-ù`ÃSS>ÀÐÔ–0,-äƒ I+ù`ÃÑR>ÀP´–0 =äƒ A/ù`Ýé)àèMðzªOÃIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/transition-tool.16.png000066400000000000000000000005621370472574300256750ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8Ó» ƒ0…áÿ"F¡KA‘%²I:†ñ0Q†±”Ò¥ÉIcB<Ž¡ñCúþÛ˜ô:ê¾7€¶àð6q \æ î œÊú4æT€iyéV±ØÄN`ñ^ÀÂ[¯ªð2Paz‰_à#én˜ë¸‘4ÄÙŸ xC¥›&KÊ’rœÁóÉ?•?1KÆ•‰IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/transition-tool.32.png000066400000000000000000000006701370472574300256730ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÖIDATX…Å×=‚@†áwHô$V^ËžÊkØPs/OÅX̆ð³ËÎŒ_9Ï›l…¨êx|7½ˆ¼Ò£¨ê;Ÿ7ˆÈ==48ÀuyhÐnï£w@'" 8Ä=²p¯€lÜ# ·(Æ-NáV§q‹€*¼6 ¯ 0ÁϘágLñÒs¼$ÀÏ pÃs\ñ£w|/ ß Ã×BqUmEU?Q €ˆÜfh¦?–¨ )ÓôA#Ч8€À¿-ñЀ5<,`  ØÃ¾¬K‡­ÿÑ}IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/transition-tool.64.png000066400000000000000000000012261370472574300256760ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(´IDATxœíÛ»MA€áo®p ¦ 7A†ä€*H€Œ*nCnÀ´@0øJ‚ûØç­V³Òù~m¶Ú”sþ߸ĹóŒ-îSJ/û¦œó-®›¬Õ~žRJwûlpÕh™óëÐ8¯ýGóóÐM‹-Fžï½(4KŒà1¥ôe¬Â3w€Õxæ PÏœŠá™/@Qç|³/@xaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¶IDATxœíÜAnS1FáßE,*[€]”°‹,¤ã ¶‘]º Ø؈šÁË •bçÅñ½çžoú’Ê’¯Ò6¶Ž –t΋sÎ/%­$ÝIz+éVÒ ƒua¾¿’v’¾Iz”´M)ý™ûæÙsþ é^ÒësWW?$=¤”>ÏyñÉÈ9ßhÚøõ… ƒ¯¦Axª½èfÆbóÇ´Ö´wUÕØì³ùãZï÷°¨ø+`ÿߣ¤7½WW;Iw)¥ßÇÖ>Vbó¯Á­¦ÿÚŽª ÀûþkÁBV¥µxg°,£¸—µxe°,£¸—µÈ Á2ŠßÔà§ÁB°Œ_¥µøj°,£¸—µøb°,c[zP€­¤ïý×g;M_èU€ý‘â'‹ÁÕÇÒ·€Ò‰³€ý‘â¦û’àesêXxÎiàƒ‚m4í]B®Oß !‡¸ö_ºèJ¸ngyãðiŸ>€7ŽŸ›Ù{ GÐM·>€76¿ËûÞèt×ÞðFÀLsÀ=Í}oôì4õ¼Ñ#°ÓÔðFÀNSÀ=;M}oôì4õ¼Ñ#°ÓÔðFÀNSÀ=m}oôÌ´÷¼Ñ#è®KÀ=‚>úö¼q!¤ÙØBq%lú ˆÃ ñÑÀ3cÓè†>@pô@ô£úÑÑŽ>@pô‚£}€àèF 8úÑŒ>@Pc_9Ä•°Yè€"ƒÆGÏŒ}L úÁÑ}Ð>èDG 8úÁÑŽ>@pô‚£}€àèF 0úA}!äWÂf¡à ÿÓÍÀ$D yIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/treeview.16.png000066400000000000000000000005141370472574300243570ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(jIDAT8í± €0 ï!¬@Ë Á¬Âdì’6+¤3M $(b… q¥¥{ù_f63>¢¤¤"Àè ÈÀÚ9¥‚¶ @RR ëjRÂÃm¶ 7›ÙK\qTˆ’RóÿŸØà 2{*àˆSIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/treeview.32.png000066400000000000000000000005731370472574300243620ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(™IDATX…í”1ƒ0ç¨)¨“'¹È[Sð$¨)Ò;ElddRø ÅNeY'e.Æò!Æ8è/`4³e}@’?»³<33[ºtN”“\ ;t'?`äó-g1%çîÞœå3_K(ìx¤y#Êü o݈¢5<ñ¨áш²57BØ ¨ê€PÔuàrÞ“²X%[wfIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/treeview.64.png000066400000000000000000000010321370472574300243560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(8IDATxœí˜1N1E¿)9LÁQRD¢æÔ+Qä(‚ä,)1M Û Œ¬qF~¯óZ}Ϯ֣',Mº÷0çü"i/i'éÙ5Ñx.’¾$SJŸíæMrÎo’^‚Í`K)½—ª\ßü‡k$å—ðÔlîÃÌ :cÛ€cYTglƒÌâ»\´ 89™Å¹\´ 8:™Euƪ׿ãæÇ—­–„`eî^ƒVôúüŸ°Ä#ô}€•`¡ë¬Dò]`%’Gèú+‘ÀJ$ð»°È#üÍX‰8ÀÊ, âFTÅàðø€Au<À” |ÀÈê!X™å¯A|Àˆªø|>0¨Žø€rY=â °8?¸ƒ5AœôIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-down.128.png000066400000000000000000000026611370472574300243610ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÏIDATxœíœ=‹$U†Ÿ«‘"Š»(‹°‚ ‘ ¹àDfËŽ©úSöø‰»ºF&FŠˆ l¤°l´ÃŽ ¨ºÇ ª–²úVwuWÕý|nwu®÷™s««o !„B!„B!„B!„B!„B!„Bˆ,q‡ldfGÀ%à©vèWàÔ9wg™²Ä6–<þ“0³‹À ððôÈÓ΀/€ι{û#ÆYëøïÀÌÞÞ™T-ü|¼ïœûwâ6ÂÃÚÇ«fö8ððòÄùxÇ9÷ûÛWMˆã?*€™= Ü^8pç··œs¿Í|ª0³'ëÀó3_ê'àŠsîO߃mÙðóÇæ \oߘÀ‚áC“áµ±½˜ÙëÀñ;ïY8üŽã6Ó 6¦3sÀ—Às Ðñ3p¢éÀ™=|Ì2wÈ)p윻ßôu€WY'|€Ë¨xiÉ'¬>4× ^úxm¥:4 X©íûØÈÖ'ÀK+ͽ! ´ýX?|€‡>ž Ph:Ñö‡<;ð ðX€B:ª¶ý>Ùúð^0X‘ꦃÀm¿Ïßw2¤šé BÛïs6ð ðc€B|?Djû}6²õ ðu€BÆ(v:ˆØöû|5ð ð q¦ŽË&ÁÊWø¦røv8¸!€sîšï’cRÌ9Aä9¿Ï{ι¿‡ƒcß~ÜZ·ždNÀœßq‹&Ó ¶­¸|Îøò£Pd¹ž ¡ðÏ€7sç¾G×´œÞ ’]'H(üsšo_G3ܶ „v•隈˜dóé ‘³}hV ŸìZ)Ô>Ò— Æð! ®µ†€ô$îSiøAx ÁMàBŒý÷¸Ýþ޽€óœæ_¹Ý ½ã(@R 6Qþò;¢ ’€ÈáCd j ¢‡ UJDøˆP•É„ UHTø˜P´É… EJdø¨ÔÅ¢¹D»È3…­·‡Ç$¡[Óç0éí˜$Û:2ž’mû}’²” ‹ð! + ² 2² «ð!3 i ² 2’” Ëð!S ©ëIÎßE²×v‘Èu‚ä?çï"ÛÐq:ȶí÷É^ˆ"AáC!@P Š  ‚HPTøP˜°ªÅ… «HPdøP¨°¨ņ ‹HPtøP¸0K‚âÇ €ƒ$¨"|¨DØK‚j‡Š€IT>T&l• ºð«ÅÌŽÌì;3û¥ýùÞÌ.Å®K¤'¯•V‚£Øu!„B!„B!„B!„B!„B!„B±7ÿåµË š= IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-down.16.png000066400000000000000000000006171370472574300242740ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(­IDAT8ÕÁ Â@Eߨ 6ì%ìAðlVâÅÒ‚‚=xð¦ ØBø^&°l6Äóa/3óþü˜¿$’ÎþÊ?æËh¾X{ öþVÒÁ̾C0Е—î à´^¨€&—$·Î‚¤ZÒSÒÛßMÒ&‚×’®Qÿ%i—nÈšŒÁ–˜à,½ô‰¾ÖÅ>šÙ%k0`Ò©JRð¨qì0 &&ÝMú›`&ožŸ~)o½‘ohRöIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-down.32.png000066400000000000000000000010631370472574300242660ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(QIDATX…í•MJAF_%Ð ¸scx†ì!âDôâÒuÞA/ ºò"(‚rãRŸ «cfº;èÆù``z¦»Þëb~ M›ÿ '’v€¡ïÌìu h}IIcI?Æ’†µ•ÊàÚúðHº¶+ëfÀ™™Ý®?F@·rkbf{lÕ¬í#/°nøœžjK$àsf¸¦ë’È€Où-`foÀðž8Ì€ï'àÀ©3^C_ܮ͆Å3àÜÌn"ðËüÄ̞«Î(•(× ”H”–‘>KáQ—èWÀFD‚| ›ÙK#*à©N4%ºól—Hu¢šäÎC:© ^(öXLxÏ“pÈì@HF'²w’ÕD'–ÚùJ‘Ô“ô°ð”´ûëà‰¿‡/Hôý¹hÓ¦Mq¾ŠŸá0ù¶¹BIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-down.64.png000066400000000000000000000015051370472574300242740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(cIDATxœí˜1nA@ß§a ‰Š"g@ RGˆc`9çà ‚”*Ü $ˆÒ j* *$$ Dñ)ÁHþxo‹Wm…;à °±ÐYXèSÆ9â™2ß¡ÞÊ8Í)ó]àY|på—¡MŠPR†¿ 6PZ„šE¨!# Õ#Ô’‡5„ªE¨)kƒP[&€²ZÈÃÄP&B+yH¶€¿4’‡Ä`ºm†üííKIù:ŸÌî„’¯|OVh![ @“&òðÿ"É„÷ß.ó÷ciN€gò`tôT¸Ì®|i(Á\ €"ŠÈƒÑgÀ2ÆŸ ¦ïùeŠÜ=wB±+ßS4dE(.@R„*òP)LŠPM*€µ"T•‡Ê`0Buùf¨j§ªûªú5ü¨êÖsU%Špõä{B„nü•Žã8Žã8Žã8¶ü&pƒÎÚÛýIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-left.128.png000066400000000000000000000026161370472574300243440ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¬IDATxœí±ªTW†¿/ˆ¥MDˆÆNRY,ÀR’àERXÝÈC)b“ÎÂ<ˆ…½BÀÂÆÛ™ Ml"B AÜ3CŽ×¹3gÎÙ{íuÎþ¿~öÚð³Ö9{æÌ€B!ZÄjo`ޤ”ö€kÀàp8¼^Ï€ÇÀ3ûXi›€ÈJJép8¾îñ’—À3{Ttc™H)~¾ðò‡À/fö_Þ]mGd ¥ô-pøfÄ2ÏŸÍìmž]õCŒ$¥tøƒ~-O[fö!ÃZ½øÊ«ÐY†Ÿ<á\ngZ«êÉüÎïò¸jfo2¯»u€ à$°_`ݵH€)Ðö×q=¥äÒ%ÀtÂ?S¸ÔYà|á€èM§í—ÅE" Nmÿ(§=ŠH€-8¶ý/J{Ùó(2U _íoÃåDPà*µý.‡E$À*¶ý¯Y|l\€#Tnû+˜™Ë5€Ž‚; _GÁ50óWÜõ 4€0ï|X|ü»gÁæG@ ð_7½¿ÒôÔö_ûÞáCà À­ÞŠUøÿÖ(Þ¤ ÿš@áNS(ü/iF…¿ž&PøÇ3{þff-€ÂßÎlPøý˜¥ ¿?³@áïÆ¬Pø»3þ0f!€ÂÎäPøã˜´ <“@áça’(ü|LN…Ÿ—I  ðó3~&!€Â/Gx~YB  ðËV…ïCH¾áPø¾„@áûF…_‡{D»™ð!ÀãáÑn&|¨ÜÔöëSM…ƒ*(ü8¸  ðcá*€Â‡› ?&.è>?.žç.¿}»…_‘hq²øAFuÚ½”KZ¾ ”è ¨y tܸú0hA³T¿-’u©.è ¨&!u‚Z„$A B ’À›p€$ð$¤ ¼+HB ’ 4áIP’I’ “$A &%H‚ÜLN9™¤ r1Y@ä`Ò€$ËäI0†Y’`(³$Áf%H‚]™ va–€$èËlIЇY ’`³$Á&š$Áq4#H‚u4%H‚£4'H‚.M ’`E³€$€Æ€p¦ß4³·žE«ÿ_@mÌì/àGàMå­|ü–RÚó,Ú¼ð™ÿTÞÊeà¶gÁæG@— ãà=pÕÌ\:’:@‡ ãà$°ïUL!È8¸žRréÎ` K ~¢žgó…$À1t$¨5.z‘¨<N{‘[¨8\þ_Aô Ò8p9”=©0=ŠH€p¯W…k`gœÆÁ3s¹ÐQð@ ë(x ¼&¸ë>¨Œ&s'x Ü2³Öê…:ÀH–àncxx† fö7pøsà©ðm ÐÈJJé è7^wÌìQÑm@`ùµ®kÀàp8¼cqÿ x <1³•¶)„Bˆ†ù7™žH^ÞÀ’IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-left.16.png000066400000000000000000000005451370472574300242570ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ƒIDAT8½“Ë Â@ gI9 ôAU¤*áB-‘ "¥2¹®V{ØÍß,{ž2šzSµ-ebø®Nê¬¾âØ¥ž@³·ò¬¾Õk)Ü'ðGíþïj»N¯°F~Èäœ8B$Ò«ßMK Ò¼ Ú¼ ÃÜ eîèØjo½æM€Ì•7²W~P­þÈw)¢k3{IØC¤–¢ù Íì¸~ !sàAÒÍ€èFÔ]ŽŒVÜ‘u¹!2cDö…¤ 1t-Ø¢Ãs"o.Ø÷‰;`SÉŸ E…MFˆê\®ÞáôèÚÒ¹g„AIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-left.64.png000066400000000000000000000014101370472574300242520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(&IDATxœí›;J-A†¿RA1p w &&¢ ÐÀÊõ™»s t.@q‚‘pázŒÚ਌_]]3SuNÿñLuÿÕ=Ó‚ªÉ–ôÝß*¥´l‹Àpœg"òO×=€”Ò,p¬}ñÈp "·šø®¤”æ€`å‡Gÿ"rŸÛÆ”¦c](Ã<Àp¨iÇedšÓX‘眶ÜeÀ«ùcòÌÃpbü“Ûž+ ó«Ú¹/Ì(2—2í›0ü4fÉE˜8Ïÿà`42ó3hdþØÑ˜‡ÌöM={"r£ ÐË0˜íah~WD®JúÒ9Oæ¡cÞÌC‡<š‡Žx5ðlZàÝ<´ ‚yh @óЀHæÁ@4ó` ¢y0Õ<0\Òn‹ÈuirU´6^Òvn 2 rÚ7¥0.æA ú˜•vÈÞ‘Ó…1LT‡€öÅqPô0êPi{ÀEA˜yà4¥´\ÚŸ\ÕÅe°ˆê†HA#A¨›¢m†êÁˆuÀÏäB=µ ôy„P/H”ÐȄޮÉyÐë=AÃ¥ô–ö¦X½(YШ‰û —aâ× ]–Ž[/`°³¿^àÂ>zÙç®À¹sBÜzQ)'Ƙõßi¢Ëæà=vVˆ~¥௶^Àu4ÕVélÕ¤ëPDÏ{ÂòIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-right.128.png000066400000000000000000000026531370472574300245300ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÉIDATxœí±‹TW‡¿³Y°#²ˆ‚)¬´·€uHPSÚ¤øGøˆeb4„ØK:ÑÞÊFPPÜÆQX;““bfu}8;ïÍ{ïÜûîý}õì=~ßœ³{çÝB!DXê ¸ûp8 œŽ7Àsà!p¸kfom³X’ àîç€+À‰/Ÿ×€Ûfö飼ˆ$¸û§ÀUàÛ5~üð³™½vWu.€»~¾é±Ì6ð£™=fWõ*€»o7€Ó,7~0³§¬U-Áõ.3Lø[ÀŸîþå@ëUIXp÷-àp`à¥Õ zÙ.1|ø0ï¸û#¬]TÒÔö—S¼ Š@᯦X~;Š@á·§8~7Š@áw§þz!€Â_ŸÉ  ðû1i~&+€Â†I  ð‡cr(üa™” x&#€Â‡I ðÇ#{þ¸d-€ÂŸlPø1d)€Â#;~,Y  ðãÉF…Ÿ†,PøéH.€ÂOKR~z’  ðó ‰ ?Âp÷CÀ-ÒßÒÍæŠvJB¯‡»û&p …Ÿ Ñÿà2p:¸f“¬îç§&l¸ûp8Uó#èß ²\BágGˆînÀùˆZKPÛ_BT8 ªÕ¤ú?õöc3¨ÎÉ :MÔöWÕÕÙ‹Ú~ ¢ð :»¨í·$jìÕµýNDu€GAuÔö;"€™=¶G.£¶¿‘AwF\{|¯ð»SÂQ°f~Â:€™Í€ë/«™ß“Ðçß`˜Oõ΀ЃÍì-ððwÏ¥¶™Ïü§½7U9áß`f¯‹À_k.ñønñ—…èIê§‚ÏW€-^>cþ4Ñm3ËáÛ=‹ ‡{Àà,p 8ÞχÀ}àîb„!„Bˆžü–e 3ôöÁIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-right.16.png000066400000000000000000000005531370472574300244410ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‰IDAT8Å“Á Â0 E( …EºX¡+t’^:K£ ± }\¢ÊŠ”6…¨øhé=ÿIJd 8Ðê›Fà‚ à6x®CŽ@ҼߋÒ&ô®áè/ïð„7 xÛ"àÕQð*H8ÖÐkÕriíûðÑ¡µ¸ÂK©¸¶£Ö^à^Ͳ9D9ýó|ä5¸lñånsIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-right.64.png000066400000000000000000000014341370472574300244430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(:IDATxœíÛ¿jTAÇñÏ¢(‚• ¾‚ Ûø>G¢˜^_&š6`¡y€4!`ae­±q,’ lâÎÜ™{f³¿zfgß{î™;[Ýl¥šÎ9ç‡ØÁK<Á¾â0¥ô¹þïµW1€œó3ìãÑŠ&Gx›R:+£‡Šäœã\Óôo"C¸UØïëÍà ¼Ï9ß-§¹ÖŽ€œóœbSa#¡$žZÏ<ç‘ps¾W0^S•È…c-ð!„ßœOw%Z`?RNX@Jé7¾TŒ*1¶ž¯RˆÄX4 ¦”¾c?+Æ µŸÂÏñ÷+~æ¯RJ50‹U€ñ!T`l“`\“`L“`<“`,M0„fBSćб!t@\ÝBWăPº+\¬”Ò)^«[JO¶³Ô=–Š ³ „Y0?„î9à²æÎ ³¸Ðåç KÝVÑ›ô 즔~­ÛqS’`‘y6c,6ÏL9 ç¼À:óÇØ©1ÏØŸÂUO~©QC“˜gÌåðdæoCdRóŒµ%6¹yÆÙmbž1¶Å›™'þÁHSóÄ>knž¸‡£]Ìóx¼›yâ]èjžXWdº›'Î%©YÌS±Ž´¤­Ñö¢da¿ÿ­X¥æéW/ð¯Â˜§_½ÀR'Ø‹bž¾õ³fûUêU/0{¶_¥õ¡ÞùËÚ–Í•tº¨ØÅ+š nžméìV7^ÚQ/1B2 IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-up.128.png000066400000000000000000000025451370472574300240370ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ƒIDATxœíÝ=‹\eÆñÿmL#f‰6m­ò‚~ +M±?H ±TQl,¬"v¾N l‘Ô&$ "ˆ¢Åž[Çó²{fæœçõúAœa2÷ÎuíyvÏ>' """""""""""""""""""""""""¥ !\ !\J=‡$Ð…ÿeá›Âө瑈¶Â¿Óýi¶–z€ØºSþ‡ÀQkfv'úP 5U€SÂwÍ• ™Ìß5U‚& °Cø®™T_€=ÂwM” ê¾«¾Õ`ð]Õ%¨² †ïª-AuX!|We ª*ÀŠá»êJPM"„ïª*Aˆ¾«¦Å Aø®Š]€„á»âKPlºð?.$åðŠ™}Ÿx޽œK=À>¶>óS‡'3|\ê~‚âΜö§¹U€ŒÃwÅ• ˜¾+ªE  ð]1%Ⱦ†ïŠ(AÖ(8|—} ²-@Fßç*ëëY^ÈìûüCe} »3@§ý)Y.Y âð]v%Ȧ „ï²*Ah(|—M ’ Áð]%HZ€†ÃwÉK¬ ÿ_IK¤]ä9îþ~&é /E¿”ÑEžc`\n%ž%ÙÅ¢¨g€ŒNûÇÀÆÌ~!< ¼<›tªËA´ä¾kµQ {ø®Å¬^€RÂw­•`Õ”¾k©« Ôð]+%X¥¥‡ïZ(Áâ¨%|W{ -@mỚK°Xj ßÕZ‚E P{ø®Æ\€VÂwµ•à ´¾«©{ Õð]-%Ø«­‡ïj(ÁÎPøÿWz v*€ÂWr f@៮ÔÌ*€ÂŸ§ÄœY…¿›ÒJpj2Û½›}ø.„ðð>ì6ž,@áð pqù¹vRTø.£Ü^2³cŽn !œ®£ð÷Öͼá¿{R¹\ï2˜º/àeàòj#ÍSlø.£\æ$ÓÁBxøxbå¡NS|øÛ2ùÂð>pÅÌþÜ>8vx…¿(3ûx´w Wú§ Juá»®¯“v9x¡`¬ÏEdLµá» ¾&d;V€'# ÒW}ø®ûSÝ:XÚÇ ðH„A¶5¾K¸œï+ÀoqÍ…ï-ƒlÇ ðc„A áð]‚åà‡þ±|aæÃw‘—ƒïúÆ ðùÊC(üžˆËÁ Û±|Ü^i…?!ÂrpøºpP3 ÀÛ+  ðϰòrð–™ýÝ?8úà 3û ¸±à‹+ü™VZnt™_oê!„óœl9ô  î'¸ÅɦßÇœüoâº'l€›¼øMàªÂß]÷ž]åð÷3>ÌÛøð&ðó¯þ¼ ¼cfÍ|ŽŒXûýße[øð*ð"Ó;…Ùý¹ÿ¶œm­÷ÿ[ÞïýÜÍõ÷âÔF￈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆð"šŸ8ަˆIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-up.16.png000066400000000000000000000006101370472574300237420ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¦IDAT8ÝÁ Â@Eßš°€€U„\üw©µZK®Ô.bûÍæN½FtSNÂ8YÒzûB;)0B¾ÅwýNäE®Ûu¥.Õ69gû¹×Ÿ ê8'¶›Â=YR§äœÝ(çÈñ¯éå’%j®#ŠA8ìŠÞ|>7ÿõ¨¸zw^ü…IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-up.32.png000066400000000000000000000010311370472574300237360ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(7IDATX…í•=JA†ŸOo!†ÏÖ"ö6z›¤Mmãükã9#Øy‚`^›‰™ŒÙÙÙÙÕ ì Ëóó<óÍ~,´iÓ¦F$õ$õ¶ïJz”ô$ép[ðw÷dKX¸ö‚¡OàÌÌžMÀÝ÷5Ð)˜2NÍì¥qÈÉÃTªD’@ÂÉÃ$W¢T ÂÉÃ$U"*pò…{Vb'ïW%ð1p鷱ÝX„²/€±™Ý»ùGÀ%Å•(¼ŽUáÞº,‰5\x‰oºð\ s‹ö;âÜÈ̦1¸'q \D$æÀ‰™½-»`ÒÀÍïŽ ¬Ú°ß¼‚Dßøhž(±bJHšyÿ÷™¤a.8Œ¤á†ý°ÞÀú`f¯M üÅþmÚüß|¢bÛsiÒðIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/tri-up.64.png000066400000000000000000000015001370472574300237440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(^IDATxœí™¿jQ‡¿kcÐJ°öl$ÍÚûò–JPò4Ö*D±²¶²°! y«Ô‚p«c‘{‡³³»sÿœ;óÁ;Ëœ{~ßœîî‚ã8Žã8Žã8Ž1"²#";½ûèB ÿQD>‰È­Þý˜¢ÂÿŒ¯n‚õ‚qäßGû!„¥e?¦Ö„O˜K0°Eø„©Â'Ì$4>a"¡©€‚ð‰æn´*ÿ#?<À.ð¦åf©ÉT¸òcšMBu Â'šH¨* aøDu Õž•îùMT&T™ƒ+?¦Ú$ è>QEB‘€ŽáŲŸ•îùe|åRüLÈ ®ü"waà x¼þÔYrO˜| Tû3àeá{¬ùxÜ.¨™u;LÐ"¼ªÝEÂÖZ†Wk˜KØJ€Exµ–©„,ë5Í$¬Ð#¼ZÛD•z†W=4—ð_s¯zi*á’€9…W=5“°"@moKvx˸ÐQAKˆÈ.p”üƒô‹ ó7o…_3Ãð±æ>eß\dˆÈàQAñfá•$<ŽYÕ xVP´yøD% CV-à~f1³ð‰ †¬Z@Îwjóð‰B CV-àdb‘nᆬZÀ× º‡OdJ²û¹|în8y6á5ö ¿€§!„ß & 8Nל|Ê ÃÃ0 ÏÙÜÿA £PáØ>çê£óxloŽá!„lîÿxåœ«Š‰ÈMà^|{¢·×ëÞ¿ã8Žã8Žã8mù„a±ËŒ³IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/underline.128.png000066400000000000000000000024271370472574300246030ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<”IDATxœíÛ=ˆUÆñÿ«’@¢\u‰ ÆÔ4…6*b™FÜ ET°c!*ba¡•`!¢"(‚…¢E­ü×"âGata£¸Á䱘•,+nÜ{Î̹»ïóƒ”÷=ggþ¹Ü;37($I¥3JDD´\¿ôïo½ÿÓZ.ní9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$W#€?+Ì™¤u ×^_8b¾ÊF Ôà× 3Jln¸ö™…¯ÿ­Ê. ¬…¶6\û‚Âׯ‰~®0£Äö†k_Yøú¹*»(P#€/*Ì(qCõo,|ýÁ*»(P#€Ï+Ì(q«¤MC/*i#pSá˜5À'f”Øìn°î4PÞ×56R"j ‘tØVcÖˆf #bU _ÿ“cNgGÄ‘:»M­ A¯Wš3ªs€û\ïAÊN>ÀLë“_¤+ÔÞ¼¤ëø[wJ:Va¿Oô½×AIz¿ÂA)5'©ô»ùr㤤ÙJ{½¼¯}®DÍ{OVœ5ª-À›’JßžÿEÒVà`¢Â¸™ˆø²Âœb5Ø|VqÞ¨.>•t}­’vÒ}Û¹¸ÒÈç+Í/’®‘t¼Ò[d©yI©àf‘¤õ’^˜UË/’6Ô<îcEÒsV ßIº[+¸X$i“¤{%ýÐÃ~ööyüWªÊu€Å$m¡»:x^íÙ…~Þ> Ûß÷œ¼‘uÝM¥ít—–o¡»ÀTÛOÀ¶ˆ8ÚÃì‘T@ÒÕÀ‡@³{õcjWD¼Öz‹õòDPD|Lw±ÄNzwÜN>ôôðIO1ìºquØ?¶ÞÈR}?økõ+Ïÿ'àÎq<ùÐs!àà¥>×sFÄ­7ñ_z*8"þ¢»]ûXßk¡g#âñÖ›XN¯Ÿ–’´x(}šv5x¸="Ž·ÞÈr @Ò¥À+ÀeC¯= = ï~cmð†DÄ~àZº‡zýž x$"îZ '¼,&i x˜j¹Jæ€Ýñvë¬*’ÎtŸ¤C=\wÊ>Iç¶>–«š¤u’¦%}Ûö\®È!IÓ­Ýš¢.„]êþWË­å¥f%íUƒÇÑkkúàT$ÜÜ\Eû_3ÏÐ}x}!"þh¼—*Æ:€Å$M7ÓÝ®.¢ÿ NÐô÷€—#⫞×ܪ `)I›t€M.ú7Aw¡iÝ/‡O?ŨcÀQºg߀ýÀGq¸ý›™™™™™™™™™™™™™™™õ%$­µgóS‰ˆ¢‡zZ?cg9€ä@r 9œHÎ$ç’sÉ9€ä@r 9œHÎ$÷7?õ`²èH°ÝIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/underline.16.png000066400000000000000000000003741370472574300245160ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<yIDAT8íÓ± Â@ …á35$û±OVÈL» (õGc¤ÓI ‘R@Á_ùüôžlé%RQ¿ßzÛ?”ü~-`ªtUÝg9¯Œ6 Oó½ëâ(8áf™Ϋûàˆ îx¦qÆøÑü5¢½ÂÍÆ¼ÊÝÿࡉ_™-­_ IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/underline.32.png000066400000000000000000000005411370472574300245100ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î<ÞIDATX…í×1jAÐL ­‚6iÒ'·H¡7/"äâ)r Ï‘*Ø$!­ ˆXX<›-–É2cÖ%œ¶ØùgøÛ,n¢@¼VO!¤æñùÜþÛÔð/RPPPM€mêz‰Y?ZÚµ¬3gF‰Ù8zÿÌ~3é¼cØpn€u´wÞÐÇWñ)zÕ3i(?âñ×€ ñŒC‘Ë¢Uy 1¦eù w*Ä=^«ÏyNŽXtRAð‚%>°¯•îð†9ž:-.¹ŠÒwÁÎ £»â¿ü^à§$‡kÃ[“IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/underline.64.png000066400000000000000000000012011370472574300245070ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<þIDATxœí›¿NQ‡Wº†„¤°BË#ñ=´3Äøçôä lmí4´– ˆ/`4„ˆÛ| JˆpgöÌìèù’­öž{~ç›In6;ST ¶æ,J)%R_ëÝÿB¤ø_ ¸¸IînR€;€›àà&¸¸IînR€;€›àà&¸¸IînR€;€›àà&¸¸IînR€;€›&~F—µƒÊ’P6©™€¯Á×{¬ýØ[R3ÛÁkÚ;•ïw{Kj&àC°Ç=`ªm0-éneÙÖx‘þÐDÀË`%I÷Ǩ[—t³²æõû¶xKŒ!p»E¿µÃš³Ø.ö9÷ñ@«AG0ºµOë3 5ÜãX˜´€ð¹# Qžv5W«‡ ’6%Íu` ÞKºUJZºKÀÓ•ß®Z?!aŽøÉЖ`Ñ=ûo€)à £ã¨oÞq®üß®Ï= ~<fÜsVfÝ[ ¾l0£.ô¨ùió’V%­HZ”´ 銤¤“¿ †’¾IÚ•ôQÒI¯J)û}dK’$I’$9¢@ì½ÀóNí½ÂügÈÀM pp“ÜÜü÷~á¥`/ªè™,IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/undo.128.png000066400000000000000000000031041370472574300235540ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(bIDATxœíÝM¨UÇñïcFI`æâV‹ "Ó”VR`-*ŠFF‹ z%„wa«–E‹ŒÞˆDsÓ A/FѦMY¾&J¤uüEfjݧÅüoÄMç?3眙3Óﳻ̜g÷y8óòŸsDDDDDDDDDDDDDDDDDDDDDDDDD¤¬ë4åî‹åÀpØ ì0³¿:íXÏô®Ü} ð ° 8mÎæŸ€—fv¬í¾õQ¯ ÀÝïÖóßÄϵ¸ßÌ~Lß«~ëM¸û$0Y£ÉàV3;’¨Kƒ0¯ëTÑ ù—ëtgP²&ÖŸÀ5:œZÖ#@`òæ7FêÎ e[’?ky„ƒ•eDL>À9‘â Rv9ùº (‘U$H>À7‘ã J6(ùï&ˆ9Y@Âä¿gfJtþ aò§€[ô  \§#@ÂäO÷)ùãuV “ÿ+p¯™íJ{p:9$NþÝf¶=AìAj½”ü¼´ZJ~~Z+%?O­€’Ÿ¯ä äç-i(ùùKVJ~?$)%¿?¢€’ß/Q @ÉïŸh ä÷S”Pòû+¸”ü~ *€„ɲ#À Љ¬ýÀ.àK`·™y›i\J~‡€O€·ÍìDê6*%¿‡W€-f6•ê µ @ÉoÝÀfà93û-vðZ äwj xx#æuBåPò³ñ>°ÎÌ~‰¬R(ùÙù˜4³/B-%?[Ç€Ìì£ U^ ×bKy:xÞݯ 2¶Ìì`CÈA$™Ó§Ýýê¦ê\®jz Iê°ÆÌ¾­Û°òÌ ÑHðDÝH+΢ ÔmXkj˜NY»x´n£¦‚u:ÈÓ p[ÛÃTyúŠâz`¦ÊÎgët­eÀuUwÎù…ià.3Û‘ vgÜ}!p&p.Åj¦+€ëGÇò™™Ý^eÇÜ_ dÌåîó€(–¶½ RØ›«üߢ,afHs:Xlv÷¥ bgÃÌfÌì`5Å !1¬©tìH4Ä0º—¸,0Ô°jÜ4¢.£‘ œ™¡¸¥ 1\1n§èkŠ ÅÃEÀwüÚ¿£‘îõ¡®·C’E¢Þ".6þFà)ŠåîC\9n‡d«„i$3zôƒÀ0Ëܽôó:I—‰ÓHìµÀö €‹ÊvH¾N F‚ ŸþBÎ…e(2áOÉ MC-3;N1c(Äùe[[)T§ƒÆv¶?¯lc«KÅê9A#Û/.ÛØúZÁ*‚Ú~l_šãN‹Ö…a-?¶?T¶±³ÕÂ[¸&X’ vö¶ß_¶±Óï$>¼äî¥@}`f€Ý ›ÏÛÊvèü“1 ‹`‚b2弨°ÝÖqÍè¼ i¬t÷U â¶m+ðaÍ6ÇÇí”E@Ò"¸)AÌV¦ƒORý·ýÀ=U–Ȧ Y¬ˆ¯£÷Ö§š4 <¬6³=•âÆé^\‘ß,:`fçÎåÊÝ/–gSL Ûl÷Ð\óãw-œ™mp÷cÄ™w0È/‡™Ù^`ohœ¬Nÿñ9Áçb V¶Q® x3Rw)ë€à"xËÌBM´,/O¦Á\Äï(æÈNÔ¥AÈ~˜5º&x ¨r•û5p‡’?^oF€Yî¾XÏÉ'N6ÏŽî›eŒÞü3—îrŠ÷ÞS¬¦¹ Øff¿wÙ7‘ôþ€ÙÚ”K¹¬IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/undo.16.png000066400000000000000000000005501370472574300234720ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(†IDAT8Ý’1‚Pçc0Ñ›p h´1^ÀDcãMŒ· !!$ÜÄbl°0òÁŽ×îÌËn²°Î¨Gõ¶T.ÕN­ÕíR¹UÿÈy¬¾2PFðo !„'@2kMH ¸«ÅÏ$æ~u£ž{î5Ä”$jÕsû©’FÝ”œ&ÿD½¨×Q`]ù€SžH=’„IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/undo.32.png000066400000000000000000000010131370472574300234630ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ()IDATX…í–±.Q†¿#!HDt*•Fc_F¡Ðyl«ò¶Ñ*$z…B¥ÐmáˆH4ˆNbWõi–ŒÉÌî3#a¾d’¹çæœÿÏÜs&  ®¨ëêÔoˆïª×êz¢FâípòY*£öÄ8â@;~+7#þìDÄ[†Šg|ö+µU©ð¿ÿ2J9gþ^;à8Žˆ§\ˆ§é{q– ŽÃ™Ôíd°ê#È¢lFÄ}æn™M¨Î«j7UoTb©“ n¥j]~ìeö@Dt€N*<}ÓÄ9ÐO¬Õ…\e›ˆˆ>p› O50ÂÄ¡:[ÄpšxïcgæôÄrA¨-uM,š›u!©óòibu0Võ_Éþ,ïç#T™½°pIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/undo.64.png000066400000000000000000000016111370472574300234740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(§IDATxœíš½kÖPÆ7i©EüD\Ô¹upqœuP;ÅÙUС›]qè “c ]ª?°ŠŠ¨´ iµ‡´߯ä&7¯ià4°?ã/Ÿ£­ ²U´Â}3a3 ­c©—$=HïÈuœ‡€)3Û‘3¿4’~‘\´—2R·îÈ}Ü&¬·2ÒÚ^Ìõu7¸üî6³‘ôŽàF¨Î&Hú¼ÎHÛ•Þ(Ô ÖÙà]F|0½Q¸®± Yo WÒ¥ž ˜p½L½œÌôˆ-OÒ;J? š0jf•¾•4ÜíZ®HúñW~¬ÂÍÒUI·cÕíq>‡cÀ°HòF[Ÿ0« ¤I3ƒl–cÕì…¤9`.+/êz@Žéðx³fY¢/ˆl˜p°–Ð p¹nï«üHêp ž7%}¬ªžã8Žã8Žã8ŽÀ{ZÁÖ¤ðIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/videosource.128.png000066400000000000000000000024011370472574300251350ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÝ;ˆUÇñïÿFÅ´PwÓˆ/‚­‚ID°•XãA –Š>PlíD øÂ<·UlmL h+±0®6ZøZCÜý[Ì&,²ì®÷ž337óý”ËsþÜócf˜ÿÞ9 I’$I’$I’$I’$I’$I’$I’¦Iü÷™y°Øl¶¶]Ô”ZÎÇùˆ8ÝE™y+°Ø Ìÿ?¯Ôu$"άþ|¬:ð àEà!`ÔVÁ—¨%àðZDœocÂM®ß2pxu]±êà÷»ê—:(_OÔAf^îØä!'€¹ˆ8!)/áâ×°x¡æ™y=pˆÍ/>4—÷çbåšÿ žökYöDÄ·¥ÎÌYàCàÆ1_îÑÜð¹øõl¡ùŽ‹ÊÌ›€£Œ·øÐÔõÀˆænQuýŽ3óvš›Ì&êî03yIÚÀl©2óNà pmáfFÀUÒú¶•$3ï>®.1°Íkÿ”ÈÌ=À;À•%Ç5S 3Þ.+=vñUVfîžeÇö%€žÊÌžž¬9è¡Ìܼ àðAÐtó 0p`à ÀÀ€3gÎ œ80p`à ÀÀ€3gÎ œ80p`à ÀÀ€3gÚó2ÍÛº{Å´$"Ïм¿¿7 @‹"âSà)àï®k¹À´,">~ïº0ˆˆ¯€G_»®Åt$"¾¡ÙÞå§.ë0ŠˆïhÞø}W5€ŽEÄÍ._§º˜ßô@Dü<|ÝúÜ—êÏžûf3?£ïâE‘žz$"ýÀgmÍizfeÁ§i^W衈X¢ÙËñ@í¹ @OEDFÄëÀ@ÖšÇô\D¼ ¼B¥N¢˜5;‰`JÔê$Ž€?K¨5ýQb ÄÅ7#b¡Ô@…;‰ #à‹i}ÇKV°“xrÌÓl%®:–¨ðPg¥“¸ñ;‰ËÀÑQDœ¦yo½ê8Uú-ñ#Í™`œNâ|Dœ ¸¸UÙ{À®‚õ©9õÏEDÕcé“4uÁÅçÏsÀÇx9(a‰f ê‹¿‡XÿÑ2ÍFsqÖØ63oö»í¸½üfýœ¥¹©ž¯uÚßHfî ¹,ìfiýàplå’/I’$I’$I’$I’$I’$I’$I’¦Ô¿â ój±IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/videosource.16.png000066400000000000000000000006341370472574300250570ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ºIDAT8Õ’=Q…¿Ã„=LM­ˆ^g³³ V`"vC£R[ÀT~ÂQ̈ÉÈÈÓqšûrÞû÷ÂßK¶Ç@7àml$Ýl¦lïVà‡SI[Û 0®Q ^~'@ ´m§@Rø-Ù>HêÔѶWÀؽò]#°ô§zUãÛoú6Á®jDÏCÑÙ:ÅEœC^M$.ä“H*8KZØÎÈÇx’íЀÀº´H#àÀýº÷9+ÉAlIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/videosource.32.png000066400000000000000000000007601370472574300250550ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…íÖ­JQ€áç[Öà¨Ý1¼m¶m ŠEüÅf0Ûl &ƒ˜l^†}ýI&Á…ý *.ãÏÊ:‡-óÆs¾™÷eÎ &2s˜©éž}\c="^ª›™¹ˆ] °™yƒÙšäÃlFÄyE¾‚=´Þ—zíBr˜«È;Ø@ Ï´ ɇÅñ.î|·ÿ% "æÇuÑ­¬µ°åŸ®+ù¦p„¥ß†J¬bzÔPkÔÀ?)/ð'š€’Ï“8Áå$úXÃÙoC_Î̼­« "™¹ƒ'?ÅÅ_ˆȈ8Ä!ò»€»Bî^%äØçÀ÷-lÕÑÇ.ªqêíƒõˆl×èmhhWŒkDvÛµßñIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/videosource.64.png000066400000000000000000000014141370472574300250570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(*IDATxœíš=hQ…¿3þ€˜ `¥e°²²ÐFí]+ VV±ÁBQ°^±²‰–),ý«ED+Q;mb”]QðçXÌ.&;3»#/o½_}î™{Ï_€§@WÒ›¦Å¶÷#Àö?¼Þj0ü=`w‹ ÿ+>IïëØ> Üf×ñ:]PÞù†Ø\ª+¶}¸Ãßý–dû%›sÙoD_ÒÁ*‘ípØ:Ê« ¯áfª¶çŒ`¦J¶€%ø*¦&Û¢|¡IÝT`{ p 8Û´¶2IûÇijl¿n ÝFù°;1ε²^¶w7cãzd€íYà6phŸ,°½‡òçÀ¤^Y¬smm˜$ •á!ßZ#HÝ@j"€Ô ¤&HÝ@j"€Ô ¤&×ooD®Ì¯Ú0Ê2I«À9àŤ^Y ©œOâ“m’¾€ãzTî4ÙŸK¤ï¶clŠf½†Hú \–›ÖNE’,© t×­›š†HZ®¿êè Êï9Ñ«HZÒµ‚ò°@N<©#’tŸò ñm„ì™lÏw)ÿ—ov>QøP·`ĉ5àL18rÒý¶:m™>ð†ÃHzœ¤œï#°:ð:%é]Ë}AAAY𦄚‘ÀJˆIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/zoomin.128.png000066400000000000000000000072771370472574300241410ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( ÝIDATxœí{°UUÀŸ`#‰æƒ«Q‘&s4ÔÐL3Í44 $1i¨é4 ùÊ¡éá¦1Ì‘DÄLcT|¤W±ðêØ8– MV*LÊãb"~ý±Ö=œ{î9÷ì}Ö·öÞ÷Þý›¹Ã½‡½¾µÎ^ß^{­õ=”””ô_$ïä…ªîìì ö> ¶v>î/ïÖMÀ{ÀÀ*`5°ZDþaóÍè  ª€ÀQÀH¶v®ÀJ  X¼$"[Œë0§Ï*€ªîœ Š{ª³d#ð,°X,"ë3®?}Jü“> 8øn8/KÀc"òaÎí©Ð'@UwÎÆCrnN3Þîf‹È{y7¦W+€ªîœ œ›´õ&:€ùÀ"òv^è• àŸøK€±Àv97'”MÀ½Àô¦3D䣘ZTuW`*ð¥¼Û’mÀ¤˜“ÄÂ*€ªŽ¦»åÝ–œY L‘¥1„oCh(ª:˜MÙùà&»wªêù1„jð³ü+óònKA™ üÜr^PPÕm›€“ònKÁY\aµ\PÕAÀLúïd/-O‹È¦PA¹+€òg‘Oçwí8»~çÏ[þóõ8‹8Kâ8òPœÁ0ÿïHò1:= \:䪪º n™—Õ°ÿðgàÜ«=Ôf¯ª8+ähà`²»¯‹€ËBvóV€k€s2¨jð°PDþ³"U |øn„ˆÍ™ÒjáÜÀ/õ.‹\ÍóÀLùcäzºáW4GâF…˜Ü$"¿n¥`.  ªGwob0MDVD’Ÿ U=˜LN‘¿%¹8“À¿ÿ¦`ÛùíÀø˜¯ª;©êàXòEä5àÛ¸ÕŠŸú{Þ”¬^§á|ó­x8SDÞ5” €ª¥ª·©j;®c^PÕvU®ªæ»•ÞðàIC±‡''ªß°ÒºxÎG]ŒD>\huãI¦G7¹ôqÜî›i ‡ßQœ™ þ¤¬Žk6/Êb¸»Î¸4Bçæ’ìæÌUUÓH#¿§).¼Ì‚!¸IwDU¿æk$îUàû"ò¾‘¼j®öKqýþÀ/¬á­{築ïc'{8¿ýà’~óªz.†0-'ªêëöøyÍD¶Z"C„ šiH4ðïþÖϘcpz‹ågð1ǯl®1w–ß|ªKÌà,l"rç‹È"9øb@ÙÃÌZQƒˆ<<` j00¡a=tÃoù.>(*ÑL6U}‰Ö:6‰È–í©Æ?¹>‰^Qoòk8’ðθ!ƒíÝož¨ž@~Îs³¨!¸mânÄR€S d¬Ày¼ôwîþb §nŸ˜+€ªî|Å@Ô´¢™tóÀ߃i¢¾êû¦ 1F€ _ú­,Š3G‘6œ/cÛÇ×~CŽ51Ý@F_ãÝúÆTüìÿ@1«p.Ï%]yx=PÆ¡¾*X#_û/(ßýÝñ÷$tR¼ðùê¬ ÔÛGß[4¤²wBè²yU4x^DþiÒ’>ˆ¿7¡KÂ.}d¦Þed ˜g,ÚÒÇ ½G#«½…,G€¡„§_Mí×Þy6°ü`ªvi- 4 ªxÉ¢!}œp©åB¨ôÕÀ@AÕ ,ßÞJ¤«ªŽÄùŽv'ãH]Uý{Ê"›pÈm8Kg{šÂ"²YU_$ÌŠ9Ü×oª¡#Àª4{—¬ë¯Ö›5ƒp)ê÷Æ©êÃÀÕ"’Æda °wç/–¯€=Ë'V¿§=Þ×ùõ8˜WoŸ¾R=,uØ«óKhèu’4_j*Î/¯¯°?é̾¡±•¼Ê– ºx+ÉEÞ7ßÂÚX4ŽMwðŸÀº*Á.– A“ô8>°ž"3.áu뉢¡6€¤ P׳¥tõ®ôU¯Rï#—õÑ/Y2ØG(5£ E”Q°fú-;-4b§é“íD-&ŠÊú„1‡f£m¯RO”¤É!éw+¤„îO'ýRsë)2÷&¼.tÅUYEX*ÀËïžä"Ÿ6ýñÀºŠÈc"²,áµC늢¡›iÒ¤\¼X_‘x¸<Åõ¡†·J°M‘ ñ—ò¥±¸ìŸ½™N¸±"’fs'ÔðöFç/–ÖÀ,G¼õ쇪z[ÍÁC)Îi¡Ø„»WmÀýiÍÁžÐ¤R[‚¥¤µ‹×2BU·‘Íi ùØÊMZ²ç×ÖÿÙòiñÙÕCR+¡ö–¯€Ðwò ¿XÀ"=}e°T€Q5¹h‘hñö}ˆPÏë ÕédÍÀ.„Ž£-ÚÒÇ92°ü ÕXïß·–?XU?cÒ’>ˆ¿7¡®÷]<¯‹¦B‡ý”S ÏêU,\–Ç$MsÚŸð÷$ôáX¼\ý©ˆÈ„ûàNÚ(éÊÑTyó¶Èsµy‚bØðÈøŒ¾ÆDKj?ˆ¡K€T›9uéY)¡rÄÎżU= wi(ëqÇÎ×%šˆÈZà#q?ó,Å`~‹åøeC*‚U÷űdÁÝ=yÇö埅Í(0˜c>àý n¡èC-:sôˆªîŒ;I̱¥wNcC¢*€ˆ¬æ‰ÌRÕ?W“Î’ù ðcëFøïöÂ}þ:™#"=:ëfÍs.]¹·ú–ÌðîegPg§¬K€q):4ŧéØ,ùÀÍüg4»(“U=—ÍÊeÀEÖ•ðóq¸@ÍNÿû ¸Í­¹)\·ÓÔ9øðeC±“DäÁfe¥Ûà>ثٵ)X œãìÀN:5#X±3nØ·<¨ ˜$ãjVG^€mçƒ{Ì‹¸:@DÖEîü}q»¦–¿˜’4ÝntPÕ‰¸@Ž ªªÅ™â×ù`7áëäÖ4lE}DîüZ®‹ùJ°À/e¯Åf“§–¥À¹iަªú=àÊXòð.n&=;ÍMÈoÙ\…ÝIªÕ¬ÁþNšB±N ËòɯÇJ`ª?i#wTõpœQÇü IÏܤﹴÍ _ÍJÜZø©¬Ï ðOüÑÀE„{ò6ã:ùm+M §a? oâIï‘7š]‚ªîsÞ< û ^=f‰È­6S€‚=ùP\¾ý¥8K^{ÚXÄn]¬ÞH\TÓhÿ{VžL ËCF7“†ö’ίÇ&àE\°äj\¶Ò·p)TÖ³5•Êö¸ãV»á–ŸÃpÌ’ODòSÀÄVlW¬½¸ó{3OáNS¶´mùw~ÙùÙ²÷ä[˜Ù[W€Oøú2wãÞùAÃ~5-½Êa?s¶7¶ºÔë‰ÔvõrØÏœµÀdŸÍœT#@9ìgÎrœ]?Õön+@9ìgÊfàVàŽØ6D“Àu~Ô]¼‚Ð|CDffaÐjªzçOÃ~}9mHÌ‘wpßmB{~(=¾Tõ<œù2on‘Û;ÿPÕÁ8#ËŠŸ°8Ïé 3…›ÒPTõxÜ{(+·±FL‘ºÞ­ÞŸnp.á ”³f#p?p{ÌI^3ê*€ªÃ¥0Ý.Ûæt£Ë“ßUÝ—:ö àSÑ[ÆÛ¸'~vO|-àvÜû6Ou~5ª:çZ=çÖý±íj…M8¯è…À²FšyÐMTõÄ’gHêίŻtœ€3Õf=WX¬Àuüâ1 ÔS€+€óshK'Á_KÍþàs„tYË\–´åþçå"=騧žŽ¼UÌ;¿ªúi`?`_Üa{øwÆ‚9ç°…­þp³öuÀëlõ!XU~µ7ÑEü;ô¯À€ÚÒp¶_Ú%Þî”߯¨µæÑù™ û%Ý©Öf\ÿ´²ó󥋈H.º& n)‡ýü©·Íûtõ–O~A¨§I²d„P>ù¢žêüBãÚá`#ÀÐ<ÐxHuk¾úh-ÇÀ’™Õ¡qÄ™_à`¦iüÞPÊfvñƒNRÞwªJZõ‰þ,I`ÏíO`ß̾þCð *xÞ·»aÓÈIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/zoomin.32.png000066400000000000000000000017751370472574300240500ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…½—ËKWAÇ?GÓÞTšP‹ ½¤m¢|ôÀ?@þƒ, ‚"P(ˆŠ6½6¥‹v­z®¢h!e–’˜ B AEa"‰(­¾-î½6¿qîï¡å.Ì9sæœïÌœ93ט$$Í* `Q¬þ¼ÍìG>~lkz  ˜“bö èn˜ÙýB@R%Ð lÊwLŒà”™ Nš€¤àPR`ð¿€fv¹`’)ݯ>¢½X l–§Ø·™ÙiW1#Gð]àî­fö,eÜj  ¨#s’’^™ÙÕlq'•’žKr¾'’¶äü×ÇVI}žg’Ö&6EYÆ7“¹B_€3{èÙ)©GÒcIÛÝ>3ë€G]´äb^ë±~‘6sI]ŽÝ£›ªØ‡ë³ÒW Þ“oû3wPæ´ËCfö¸Š1@\áªKÓ¸à¨jg`&0¨Ð¶ |¼ "UI”U½x· 5ŽÓDäóÐ!À/rO a/O(°@Dæ†(çM€ª6^Ê×Vñ>0]DÎÄ)•äÓƒÿäÓ:¿ ØlÅ­èG€/k…‹ º}@Ÿ„öGûß/Æ)å5Tõi’MûcÀ`©ˆìKØW)0´NÐt~ÜëšU ,T?,ŠÈ±´}ú~Û€q„Í`‘5QÂT¨j`%Ð&@}0YDv¥é+f ½€¹¸pÚB50LDå .IÙÿ«„9¿ 꼪–øEÕ„ˆìÄ…Ö_¨·fD à#¼ ç#`’ˆü`óFU­¶ÛUõ=U½Áj'"'IÀÇã¹]Uï©g# aö@›ß`‡·«pÎÿ`ó:àS EŽè0JDvØhÌî6T«€!"r:ó é (Ãv~ðLˆóÏSßyp©ñ”~¯Ÿ ì6T;óà÷üG µSÀ“~j†b`Œl@¨ßçdà´¡Zî}’Í€~Ø)í¢«}Ô§ŸA«$†D¤Xl¨•·dþIB@™!?ŽËÏ›oá®8œ} ‚ðSf°¡V!"‡Ø+&| õ¡6$ó„Î€ÞØÇXËm5–ò+€îN@C¾MDöÚ*:DdPi¨Ýáô2äëí4&6òžžw3ä?F=ôÑÜÜv·Ú7Umho? lfûÕ?[€GbL—B8×òz©­ªö>$¥ãhÜ PÕa"²ßS:Cø+`åß¿F<›FñœÏFK`zÄó#F»ÖN€Ôdÿ£ª%À­¶ YdM¤f-ZA8±çjç3B ¨6äufˆÏ¶6§Q:¬8ü šµ¡üiȯŠx6—Ò5D¯VÖz 7êm“"ò3îs-Å!¢ÆÛ)"BÆ”ƒ*ßwŸšÞLÄÑ”?¶*3³Ïglô`úò½>¶òÆ®†ÀÓN'`«!Ým~,½ µNÀà7CgD ­ÆÀ(C~”$¯€¿‰aÕßÇø¢E“BUÛQ[k_en—$9²òýÖ¸ŠMSc"v °2óG0"²;Çç+6I·EZáløìs¬¡¶‡¬E=é±øbC^ÌUÕ$IЦ”²:ð}άÊÒÂìËUI øwÀ¬Ðð&ѳ ˜bÀ÷5̃*²¦?$$ÀÇÛ!ƒ Ì!ÁW~†áîøœñ?ß⊙æ»ïcpWÀ¸^ËÍW‡Uµ°¸,@ýK`jh¡$C˜u«#K¿%n…8¿NDÆç>LZìT]4Û+[ h"øoö´ø 7£ç ‚ Hé|§q èÛ"b%VÖ8Úᶺ±Ø ¸ ‰ÈÚ(ay:Ÿj¯ÈìIÒPU{à²ËÑ$+™Í‘o²˜Ðù\T⎮ö¿Pÿ’T7\V7;¶B…ˆ¼§K@o T/[eú 8W`žˆÌQŽ$@U;✿¶€k ž‘{C@D ä?ù%äç¼y/¨XÜ—ÄyÈ! ë“ÏgÚÄ&åØas!P²Ž«Ñ]Ÿ‡Ý(ì+C#Ç(d0wÑ(-ê8Ÿ _+,î.OÙÇQ` °ØRЯ̨êj|Å4bÏ…ªvnÂíñÝö@;ÿÓ T‡¨ýÒÔ&±n%†ø] üDº«³‡pÎ'ú¦Æ¹‚K²~_t΃'À§«V99Ñç³óPwLò­«Dïü¹ŒìE°îÎî•F› ÆyÈš"òî*ìÑýJ`Ì…âaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( IDATxœíkŒ]U€¿E©´<Ú E RB0Õ¤@Á*òPÀ‚)òR@iA@BjÔ ¯N!}Hh¡€´U´PZ¡¤…VKAРLÁø¢´Xú˜AJYþØ{¦wîÜ;sÎÝkŸsîó%“ÎÜž³ö¾g­ý8{­½6””” \$ï ä…ªî Œöö»»Ÿò—w›€­@'ð>ð6Ь֊ȿ3¬¾ÂTugà0`p0†ʵ¢X ¬–¯ŠÈvã2ÌiYPÕÝS€€#q­:K¶/‹…"²9ãòÑRà[úQÀÀI¸î¼|,æψÈG9×§›–0Uݸ8‘suúã]àa`Žˆ¼ŸwešÚTup>p!nÒÖLt³Ed]^•hJð-þ*à`ל«J'ðpO=BS€ª 0¸žsu¬ÙÜ ÌͪЦ1U=ø1ptÎU‰ÍJ`šˆ¼‘Ea…7?³¿Òÿìœsu²â#à`†ˆ|³ B€ª¦Çæ]—œXL‰9I,¬¨êQ@°wÞuÉ™ ÀTYCøN1„†¢ª“9”Ê7Ù½_U/!¼P=€Ÿåß\’w] Êàg–󂀪îÜœ–w] Îàz«åäB€ªf2p'{iy¸RD:Cån¾åßK>ÊïÖàüú]?ïøÏ7ãzön`ÏÀòŠÄ0à®êUº>Ý ÑWÙÒBßÞIxÝéÀÁe‘C€S^ûŸÀ²†týbiCú¿¤O’AZÄ•¤ßmK`9Q ÔЯøYÿ—Ë)2cné îÖUSnÜÿd`9Ef0ÉæR…4€,vEMœ\2õ„Z*íƒÀû“ô › Ê)2¸ïØf½mS€_1 *2«ÆBÒB×§“~)‹ÍEåW ¯ }ãê~‹°4€ÿÞ¿OÂë~ ü9°¬"ò:°0áµ#ËŠb¡‹‰–B½ÃèœC¥UØ\“bÛ{¨ã­{žQ$Hü¥üFÑs€×Ë,Α4ëû¡Ž··»~±ôfÒt!"kUµë„Гq©Ãiwðœ_ÿ)`QùÿCstû, ào÷®ª»ˆÈ¶¤7ø·äcgÓ㳫(¦{«½åð—ÀûþÅéé»{KøÉ1úb\ÿ— xB#¯·T¦“53¿€Ú Œ·¨K‹s\àý/Wþa½~¿"ðþ±ªúY“š´ þÙ„†Þ÷ˆ¼.š PÎ$<«KT°Yž˜4Íé@Â?“ÐÆ±‰ªµS‘ ïÄ´QÒ“ TDó6ÈKÕ«1|øïä?0ÑjL6±¸úƒ°H¼˜S‡1þ˜•ºØ …ûxºúCsðY½,:žZκ㠧ˆZ$"›«?ŒÆõ¨Œ±Ä9V¥ÙøÎÏʼZÆLù,nûSZá\€F0Lµ¿ŸY¢H_Ð\Q{?2Ӭ܌Mªý‡êÅÄŒäKøšÀ™ª:Ñ@NS¡ªgáN e3îØùšD3Ù[ûS>dtr¨_Íz†ŠÌ¬.mö9óïÃf±§‹À¤$»Œ²:8ò2l•ðEÒ§V)~¶ÿ(¶ÊßLKšn7º¨êdÜAÉ1 Ì÷ááM…Ï» _w§9`+ök`LåWópKч¿¼{36‹<Õ,.N•v.B%PÕï7Ä’_‡¸³æ4°Ù"*Þ³9¸»“T+Y;5üÝ47ÅreÙòk±˜îOÚÈU=˜ŠíX_Évܤ若7š@”_Éj`°4ë3|‹Ÿ\Ax$oÜ""¿läFSÈ©ÛOÂ?'GEäíþ.AU÷Åož…ý¯÷ŠÈmÞlfkùõP\¾ýe¸ðè5iö"ÖèöêÁíjïÏ*’i>p]HïfRÑ&Q~-:qI›ßÄí—kÇ%¬ÜŠs£v¥RÙ wÜÊ`oÜëç(\óaä³#y)09tI<ØšXùÍÌRÜiêÁñA A~Ì/•Ÿ- p-ß"ئq(ð„¯•y7æ›yBÊn?s¶·5úª×©3„”Ý~æl¦ŠˆÅ^‹^¤êÊn?s–SÒ.ï¦!±”Ý~¦lÊ1;¶O#Ñ$°@ʺŠWV§ŠÈÌ,Zý@Æü6Üé××ѺÄy÷Ý&¥ñç‡Òç ª—àÜ—ys§ˆÌêúCU‡àœ,“(~^ÀþèÀENÏHÃgM]PÕ“qãPVacõh‘µþÃÇÓM.&½Va¬Ãµø9y´øjêÀ,Üx›'‰”_‰ß•üœ1 |"B½¡=x!ERèèô2U=”:{É3$µò«QÕݯáNçGös…MÀJœâŠHè9?Q¨e×—æP—.‚•_M•Ïþàó„tYÍ\–´åþçµ"µôzÔ2€E„§#oså×CU÷Ã@yî°Š}ý¿{áÁ„‹ØÎŽø€-¸Yû&à-vÄ´W¦_m&z€C_’ajIÝÙ~I<ª_ñö¡Tþ€¢Ú˜‡ò3ëöKzSÝlȸü¶RùùÒÃD¤·»& î,»ýü©µÌû\å–-¿ Ô2€^ùd)[~¨eOSq¨1eË/½ À¯^Ý¡¬²åš®^Y—Ž//~ÒCzÃC¬eIÀ`Ѷc{Ÿ&Ëa̹íÒä’í‹<oÙ;oå‰Dn誒.@° Ì&õodn7 æ‚üDö#ÕU@®}STeIuÈLœn"ï+À0Eö¼d†Hºlžk6 ¹³½ý;ÚÃØG’~þ¨o‰_³ƒ²26²(/IEND®B`‚olive-continuous/app/ui/style/olive-dark/png/zoomout.32.png000066400000000000000000000017441370472574300242450ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…½—Û‹NQÆfC9Š §‰ ¹Á%W®Ô¤üÆ)Š”M”ä†qïBÆáŠ‘+9Õ.H!Ê!)‰<.öÚcköþæÛŸÃS_ß~ßµÖûQ/yÇ#»ÙvcÞ 4Q™á^íö2ôx•qäé‘ý0}°½ØCrÞkÁ{`¿¤‹Á~LÏ´OË[)‘ý6 ØW‚œÐ·=Œí•åÊ04²K¬–”ž€8ÖÏ<#{@²xW‚üm“brÔþ.o<ìE郤. «„€ #ûMÞ ô}{FÈíÛs©Ü€Ÿž$}®EîÍ*ØÙW%õeÂÓ‘½Úvœœj†íÀªÈ}ŠSñ2çŸd÷ …¥,ùlà•'àVHÏ…HîuYŒ:ˬD˜y\ û€ƒ©1àŒÛn:€æ¢¸$…åxH¯yÄó€M$’»%ÉPyŒW$éõ}°Ó+Ùô‚þ’gýl7Ç€•5’—A°7;óCy#IÉm©ä&Éå3.Vƒá°URw^cš wP}Ù»$3Y´†ÿ¢kúg’\r6ÝíEP¨TwqÕÈ%õf¶Gó™Àxà;É^H?Ízã@Õ<Æä´_ÚjýΫCB•»ÓÖ lø—äý°=Òö~Ûmßµ½+lÌÿ‹ÌÍå¿á+áÓ8YIEND®B`‚olive-continuous/app/ui/style/olive-dark/png/zoomout.64.png000066400000000000000000000034441370472574300242510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(BIDATxœí›{ˆWUÇ?ãá_ô²4tÍG¥ašBiiOL“ÐÉÈÌþТEÑ{!á3Â@Pb5JM¡²Ò !R‹ZÃŒmuµp×Lzmº¬5ýqκ¿ýíÝ;çÞßýýÖG_Xv÷Μ™3ó;÷œ™3óƒ3Rj…ª*À``$0(zÝΞí/ 8ìª/€jÑ,çSx£G“€±@¯”¢~>Ö_eጢ:@UÏnfý2¿xØ "i…ͪz ðpA±tx^‘÷Ò ÎܪÚx“µlŸOŠHm’A™:@U¯^Âmhí£À"ò~è€Là7¹9YÈ+ ,‘Å!Ì;@UË€ç€; ••1ÖψÈ?qL Ñà?ù´Æï¶;q;ú! ÁÓºàbƒ~Àp`404¡ü©þ÷SqL­U}ˆdËþ°X+"ûê*n¦] ]÷:¤v€ªN–²7+€å"r$­N¯·0˜IØ Và~ÙELåUí lº°Ì‘=itÅÌa°N[¨n‘º|B‡”úŸ'ÌøMÀ䬑j\hýA{w`~!±|„ä¼Ì‘¿“ê…ˆæo°_«ª7´’‘D¡í?Åo7áŒÿ7‰ü´ðGñ`¼ÁZ Œ‘ãM’®€IØÆï-•ñþ¬Øk°ö&¶ªÄŸù›‰Ïêq›Mæï|Tu°øÓa0¾)•N²F`§´+ÚËx©VlåÀUMÿ$qÀ$ƒ~—Ÿ·7^Å\q8ñ9À/ÿ±[…ˆü"¯˜ðÖ›Û8oSð Œ}µ.PV)°Ö Ÿ €pŒ4è»Ed_ ¬¢CDj€*ƒíwÀ ƒþy œRb›AáépƒþMÔCUÌ.:ê Å1`°PD¾Œ WwÇŒ/‡ðp‘Ao•Úªêh`p5Ù—9xCU¯™Sú@¸¬üûçˆgó(ðÂ%G"ž2Æu…pt1è ¹ÿ¨jà²@ÙY`˜×™‹†HÎftpÄÞ«Êu@½Ao±B|"ômª¥CeDò´jCð»A??âÙBàxÄó¬Ñ,ˆxne­G!»ÐꘑÀt`;îÈÊÇpgýtÙ2§<ÔBø.½CFÄÕ”?Ÿï Ô‘5†ô}¾* z©ë€!°æT áØiЇªê€@YE‡ŸË`ƒm;„;àGàƒgr ¬R`ŠA?L’WÀ_Yõ÷i¾hÑ®PÕ4—ÅÚÂæ4WbV¾ßW±ioÌÁŽ66ýìù;Çžé+6íU½˜a°Õ³©'½_iÐ;‹UµÙ_,¼ÎE@™Áº<·¹*©ÞÁÝûÇa °À+J¯ëü5W jÉYþоvæc0¿Nð:æ×°¿˜ß0‘¦8Z„Ôû¦KŠù:¨jg`)ö±°UD>̘´6x!PôM0l/®!Ii,ñM8ŽÛ@_+±²æÑwÔÍÀÞðÀ5HÜ'"ŸDƒP ñ¹h ¹E¦&É@U½×"3ûœÏÅ"i³“Åt@†Æç£ —Î~ üüDë&©þ¸¬n vl… y:Ž!ÖE4¾¨žµÊôm:à6^%"²4„9ÒªÚgüÅN¬8<."!}C@Dà?ùÕf|Ñú‚b°¸)‰ñ瀜O¾e•Í›³@-ð€ˆÜuÎ[8ñ øˆmv!4€;›&âÃÔ‰¸ÝäF¡Xl´úãë€Ù¸F£´ha|>Tu(®Ëäfàœ”:[p}@•™~eFU?ÂWLS Öø|¨j?àJÜ?è ôð?e¸x ¨£ùKS;DÄêK ñ:WÉIÓ:[‡3>Ñ75NtÈù}ÆÞ¾åÔ*'çã0õT6ZƒI¾u•è?™‘» öÞÎ3Æœ6ÆCÎ ‘߀{qGM[¨¦.ÆCÄÆ§ª=q÷û7âRRpAÇz`U1ÛßO:¨j'DþÓÿôBÖÖp÷ýßIEND®B`‚olive-continuous/app/ui/style/olive-dark/style.css000066400000000000000000000020761370472574300226650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ /* Hack that forces checked QPushButtons to use dark color */ QPushButton:checked { background: #191919; } /* Node styling */ NodeViewItemWidget { qproperty-titlebarColor: #4040a0; qproperty-borderColor: #000000; } /* Timeline playhead styling */ TimelinePlayhead { qproperty-playheadColor: #ff0000; qproperty-playheadHighlightColor: rgba(255, 255, 255, 0.2); } olive-continuous/app/ui/style/olive-dark/svg/000077500000000000000000000000001370472574300216055ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-dark/svg/add-button.svg000066400000000000000000000645551370472574300244060ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/add-effect.svg000066400000000000000000000711521370472574300243160ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/add-transition.svg000066400000000000000000000676171370472574300252670ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/align-center.svg000066400000000000000000000002721370472574300246770ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/align-left.svg000066400000000000000000000002711370472574300243500ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/align-right.svg000066400000000000000000000002721370472574300245340ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/arrow.svg000066400000000000000000000003041370472574300234550ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-dark/svg/audiosource.svg000066400000000000000000000642061370472574300246600ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/beam.svg000066400000000000000000000013741370472574300232370ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/box.svg000066400000000000000000000150151370472574300231200ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/clock.svg000066400000000000000000000622611370472574300234300ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/diamond.svg000066400000000000000000000641701370472574300237510ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/dirup.svg000066400000000000000000013136101370472574300234560ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/error.svg000066400000000000000000013117371370472574300234740ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/ff.svg000066400000000000000000000672001370472574300227260ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/folder.svg000066400000000000000000013133701370472574300236110ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/hand.svg000066400000000000000000000662021370472574300232460ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/iconview.svg000066400000000000000000000636051370472574300241630ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/imagesource.svg000066400000000000000000013145701370472574300246440ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/italic.svg000066400000000000000000000003161370472574300235730ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/justify-center.svg000066400000000000000000000002711370472574300253010ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/listview.svg000066400000000000000000000622721370472574300242050ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/magnet.svg000066400000000000000000013152431370472574300236120ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/new.svg000066400000000000000000013165361370472574300231360ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/next.svg000066400000000000000000000646551370472574300233240ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/open.svg000066400000000000000000013230321370472574300232730ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/pause.svg000066400000000000000000000623561370472574300234570ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/play.svg000066400000000000000000000640671370472574300233100ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/prev.svg000066400000000000000000000646561370472574300233230ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/razor.svg000066400000000000000000000626161370472574300234760ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/record.svg000066400000000000000000000614701370472574300236140ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/redo.svg000066400000000000000000000130151370472574300232570ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/rew.svg000066400000000000000000000671731370472574300231410ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/ripple.svg000066400000000000000000013172341370472574300236340ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/rolling.svg000066400000000000000000013253771370472574300240160ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/save.svg000066400000000000000000000167511370472574300232760ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/sequence.svg000066400000000000000000013122471370472574300241500ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/slide.svg000066400000000000000000013241771370472574300234450ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/slip.svg000066400000000000000000013177021370472574300233100ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/transition-tool.svg000066400000000000000000000652571370472574300255120ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/treeview.svg000066400000000000000000000633431370472574300241710ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/tri-down.svg000066400000000000000000000616101370472574300240750ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/tri-left.svg000066400000000000000000000615761370472574300240730ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/tri-right.svg000066400000000000000000000616001370472574300242420ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/tri-up.svg000066400000000000000000000615671370472574300235650ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/underline.svg000066400000000000000000000003421370472574300243120ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-dark/svg/undo.svg000066400000000000000000000127711370472574300233030ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/videosource.svg000066400000000000000000000644351370472574300246710ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/zoomin.svg000066400000000000000000000672161370472574300236550ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-dark/svg/zoomout.svg000066400000000000000000000671421370472574300240540ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/000077500000000000000000000000001370472574300211745ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-light/olive-light.qrc000066400000000000000000000162701370472574300241340ustar00rootroot00000000000000 palette.ini style.css png/add-button.16.png png/add-button.32.png png/add-button.64.png png/add-button.128.png png/add-effect.16.png png/add-effect.32.png png/add-effect.64.png png/add-effect.128.png png/add-transition.16.png png/add-transition.32.png png/add-transition.64.png png/add-transition.128.png png/align-center.16.png png/align-center.32.png png/align-center.64.png png/align-center.128.png png/align-left.16.png png/align-left.32.png png/align-left.64.png png/align-left.128.png png/align-right.16.png png/align-right.32.png png/align-right.64.png png/align-right.128.png png/arrow.16.png png/arrow.32.png png/arrow.64.png png/arrow.128.png png/audiosource.16.png png/audiosource.32.png png/audiosource.64.png png/audiosource.128.png png/beam.16.png png/beam.32.png png/beam.64.png png/beam.128.png png/box.16.png png/box.32.png png/box.64.png png/box.128.png png/clock.16.png png/clock.32.png png/clock.64.png png/clock.128.png png/diamond.16.png png/diamond.32.png png/diamond.64.png png/diamond.128.png png/dirup.16.png png/dirup.32.png png/dirup.64.png png/dirup.128.png png/error.16.png png/error.32.png png/error.64.png png/error.128.png png/ff.16.png png/ff.32.png png/ff.64.png png/ff.128.png png/folder.16.png png/folder.32.png png/folder.64.png png/folder.128.png png/hand.16.png png/hand.32.png png/hand.64.png png/hand.128.png png/iconview.16.png png/iconview.32.png png/iconview.64.png png/iconview.128.png png/imagesource.16.png png/imagesource.32.png png/imagesource.64.png png/imagesource.128.png png/italic.16.png png/italic.32.png png/italic.64.png png/italic.128.png png/justify-center.16.png png/justify-center.32.png png/justify-center.64.png png/justify-center.128.png png/listview.16.png png/listview.32.png png/listview.64.png png/listview.128.png png/magnet.16.png png/magnet.32.png png/magnet.64.png png/magnet.128.png png/new.16.png png/new.32.png png/new.64.png png/new.128.png png/next.16.png png/next.32.png png/next.64.png png/next.128.png png/open.16.png png/open.32.png png/open.64.png png/open.128.png png/pause.16.png png/pause.32.png png/pause.64.png png/pause.128.png png/play.16.png png/play.32.png png/play.64.png png/play.128.png png/prev.16.png png/prev.32.png png/prev.64.png png/prev.128.png png/razor.16.png png/razor.32.png png/razor.64.png png/razor.128.png png/record.16.png png/record.32.png png/record.64.png png/record.128.png png/redo.16.png png/redo.32.png png/redo.64.png png/redo.128.png png/rew.16.png png/rew.32.png png/rew.64.png png/rew.128.png png/ripple.16.png png/ripple.32.png png/ripple.64.png png/ripple.128.png png/rolling.16.png png/rolling.32.png png/rolling.64.png png/rolling.128.png png/save.16.png png/save.32.png png/save.64.png png/save.128.png png/sequence.16.png png/sequence.32.png png/sequence.64.png png/sequence.128.png png/slide.16.png png/slide.32.png png/slide.64.png png/slide.128.png png/slip.16.png png/slip.32.png png/slip.64.png png/slip.128.png png/transition-tool.16.png png/transition-tool.32.png png/transition-tool.64.png png/transition-tool.128.png png/treeview.16.png png/treeview.32.png png/treeview.64.png png/treeview.128.png png/tri-down.16.png png/tri-down.32.png png/tri-down.64.png png/tri-down.128.png png/tri-left.16.png png/tri-left.32.png png/tri-left.64.png png/tri-left.128.png png/tri-right.16.png png/tri-right.32.png png/tri-right.64.png png/tri-right.128.png png/tri-up.16.png png/tri-up.32.png png/tri-up.64.png png/tri-up.128.png png/underline.16.png png/underline.32.png png/underline.64.png png/underline.128.png png/undo.16.png png/undo.32.png png/undo.64.png png/undo.128.png png/videosource.16.png png/videosource.32.png png/videosource.64.png png/videosource.128.png png/zoomin.16.png png/zoomin.32.png png/zoomin.64.png png/zoomin.128.png png/zoomout.16.png png/zoomout.32.png png/zoomout.64.png png/zoomout.128.png olive-continuous/app/ui/style/olive-light/palette.ini000066400000000000000000000004301370472574300233300ustar00rootroot00000000000000[All] AlternateBase=#D0D0D0 Base=#F0F0F0 BrightText=#FF0000 Button=#D0D0D0 ButtonText=#000000 Highlight=#2A82DA HighlightedText=#FFFFFF Link=#2A82DA Text=#000000 ToolTipBase=#FFFFFF ToolTipText=#000000 Window=#D0D0D0 WindowText=#000000 [Disabled] ButtonText=#808080 Text=#808080 olive-continuous/app/ui/style/olive-light/png/000077500000000000000000000000001370472574300217605ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-light/png/add-button.128.png000066400000000000000000000033341370472574300250430ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(úIDATxœíÝÏoTUÆñç=LŒ‹vfÂTJgîu$DCRÇ‘D7n\±4qƒ.²1Æ•Æ *Jtã?`ÜêÂ…bŠ1’¸æN!$m0gXˆ¡Ì}]XMc´öÜ9çÞÛsÞÏÎË%ï·?N!„B!„B!„ž‹Ê~€²t»ÝQí®×ëìÙ³çîêêê¸ìg*•ý¢v»½@DÏ8 `þþDtÀR–e‹ÃáðbIÏX¸ hµZ+¥Þp`+¿ŸˆzY–½;{Ž­tÞH’ä%¥ÔY» ŽÍ*¥^œžž^ÓZïêÙªÀëâ8~À«È÷žNX¨Õj ­õ’Õ«oˆãøe¯X5_«ÕFZë+fUŽ—ŸÄqü(}ÎÌV'¢±Rê…~¿ÿ“yU¢Ê~GNÙZ>0s”eÙk¶æU‰wt:}ž±=—™¶Z­‡mÏ-›wŒÇ㣎FSE®f—Æ»t5˜™Ÿr5»,Þ@D³gϹš]ï`æÆvœ]ïpÿ6] $€ÀI“'Nœ8 p@à$€ÀI“'Nœ8 p@à$€ÀI“'Nœ8 p@à$€ÀI³zEL§ÓÙ—eÙf>HD-f®ÃÃÿOW°;Dô+3/ÑwJ© ý~ÿª­áVH’äf>àˆybsDt^)õ;‹&¾G'I’cÌü ï®O©°€cë÷Nt™åD$Iò3Ÿ„|.Q+÷æ I’ãÌ|<ïyaÍüÔÔÔï£Ñ(×{‚\Ÿ´Ûí®Rê3f–·ü ¢Œ™¥ij|­m®*¥^—åWÇú.ÞDŽ7hã%¶Ûíf~Ìôœpî@ÇO˜2`ý¾}QADôœé™<ïÆç8#ŠqØô€Qû÷ï¿Àƒ¦ˆ(3Ï®ïhËŒÐZ7áé ãž Ñh´Ëä€QDÄfÏ#Šfº#£fffVHÕÅÍfsÕä€Q½^oˆnš=“( Ýèõzk&gò|ðuŽ3¢Æ»1 ˲EÓ3¢Ì|ÎôŒqÃáð"yÿóô¶"ºœ¦é%Ós¹¾ŸÏ̧‰(ËsVØGDcf>çl®F7§§§ïXÈs^ØÅÌï ‡Ã/óœÍýz­u¯V«5Ìç!&GDŸ¦iz&ïù‰^¤µ^ªÕj+ž†¼*¨PD4&¢3ƒÁàýIæLüš@­õFcþ4î‡ ß*vœ‹¢èĵk×&þŠÌê²æææöîØ±ãÙ / o@^>©;Dt‹™‡Dtq<Ÿ_^^þÅÖpïÞZã8þÙåü4M÷ºœ_4ù¸8 p@à$€ÀI“'Nœ8 p@à$€ÀI“'Nœ8 p@à$€€%IrBT’$'˜YÑ_ËäC@p6.‚òÏå@0þmù€„ÿZ> xo³å~pÇÕ`"úÍÕlþoù€‡Ñ-W³™ÙÙlÛ¶²|ÀØù†Ãñ×ζf«Ë< €ˆ¾u5›™Í¶Ådù€‡(¥.ÀÍu¶ÌÌ̵Ætù€‡ôûý«DäbQ‹6oæ°-Ïò"úÀ=‹#ïEQtÖâ<«ò.°pITi­oÕëõÛÌ|ÈÆ ¹®`uÍÆòÏ­õSSS—ˆ¨`v+gˆè2€“iš~áöéò±µ|ÀÃkâ6Çñ“ë?Zí3Ïmü5"ºàfþ*Ï­ÛE±¹| °6êv»;WVVv@³Ù\5ýIe°½| à¶Ë$€mÁÕò  ò\.*Íõò  ²ŠX> TRQË$€Ê)rù€P)E/*£Œå@%”µ|@(]™Ë€?W6ûþ,ƒw|IEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-button.16.png000066400000000000000000000007111370472574300247530ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(çIDAT8Å‘1N1Dߨ­h"Û5T¡¦)\c[Ž€hs„g éI*›Žn÷š$XÈm”‚©¾5žù‰“=ÜÈ9wWUÕy×uK@xï§fö\×uÚ¶ý,né30³qvt½Ïì#†âhÛ…nÓŒ›Hº0³w`žqß1ÆW`mι{3{“¬µ]àVUÏ‘Wàa2™|Tíµï ª#àÊ©¯/à¾j/¯%‘AwêÓË @UƒM¼Ô© h`å&´ÖvUu$"ßǪDs`lŒ‰â8þÌÍŽ;¢ßïß7@¯æp€à$MÓÃårù–›îˆªží xE"r‰³òMœÌ-\€ü­¶k½š+g ‚÷,ËzÀ?{V§fÀ“1&Z,inz}„aùÓéô¸j¯ÆïàXk‡Xk‡ªê 0/ðfUÃÁ Æz¥áàù_`Œ‰’$éˆÈůõlŒy¬ž7aÁ|-µ&¼€´.üOʾô[lwáIEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-button.64.png000066400000000000000000000016721370472574300247650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ØIDATxœí›AoA†ßo,‹´bO\Ö-»U’þMÕ?`­xìÑÄÿÒ6†x3šXÿ ‰‘] =X%hìx€&Ä0Ë»ó˜çØýÚyß' )3,`0 ÇÉyž÷˜3é^°T*=íõze"z-¥|6úqƒˆÎ³ÙìiµZý«3VÅbñ¹âLJé(Fꎂ ¨éʤM€mÛ›™Læ;€â”Q0ì7›Í®Ž\BÇ"`YÖ¦—Oñ.í<÷hàeÜA!DìÙEÑ&@J¹;Ãì‹4³Œ£óÈ¥4»:aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÝÛk×ðïïŒm­×‰[¢•šà=³ZE6[pŒ iê@éÅ…^H!mìÈMiiü? yqóPSŒJžÓB„ì:éCˆiš€¡vK›amºÕJBÄ]l¿X{³•_²+|ÓîÌÎõh~Ÿ'¡³çÇî—Í9gŽ!„)e…ùæZë¯nݺuK«Õºf?btôj­¿Í̇‰è fÞDÔdæ0ó™ååå A÷)FXŠÅâεµµ—|g`‡D޽P©TVƒê[Œ.LLLÜ—Ífÿ`Æe“ùN§s¤^¯7ƒè_ŒNñ&ÙlöÜù°gûöí'ƒè[øã;ù|~?€zmÇÌ?¶m{Ÿßþ…?¾ÀÌOØ”Çù™ßþ…?¾@Dùhþ¸ßþ…?Aü °ËGÛè_øD¶ÇÔV »a. @ÊIRNr€”“¤œ åîš ÔZ?ÊÌ?ðM“ˆÿ^½  àc¥Ô›µZíS7´Ö¯0ó¡pK3BÀ €‹–e]XXøìÖ×099¹#“Éœ𣈠ô„ˆÞm·ÛLJM%÷‚üVTu™€ˆºNŸ,—Ëk@/333÷w:ÓöÄY ó™LfvØ¢­õߘy*ª¢ òQ.—ûM¹\^SÐét^†9_>ì¹qãÆ†ÄÌïGQŒ¿víÚqP»wï~Àwc.È3fþ~¯ö )¥>‰ª- ÓŠˆŽÆ]ɨˆè™A¯[–5U-¦af«ÛíVDt0îbFEDÏÕjõ €µˆÊ1ÑAÕ_ºm"f¾¯X,ît Éêã ÑCÆY–Ń^gæÀŸ}Ø,˜y‡""“—f¯ºx¾àþH*1”bf“ŸÔXûÔÔÔ.["ªÅHŠ™OÇ]Ĩ˜ùÌ ×»ÝîÞ¨j1•Z^^¾@DÆ]ˆWDô÷åå勃ŽaæoDU©Œ½À¤{æùf³ùâ°ƒˆèQc2•JeµÓé!¢sq4Ñ;NçÈ•+WƒÌçóûe`¸»n‘lÛÞç8N:øA$c:øør:ø-ÓÁbæï…[šù|ß#çóùªŸöKKKE¿5¤™ßÏßø á å$)'£d³m{ÆqœÃ¾àáÞ¯7\³6 @DJ¥Ò¶f³ù[fžÅÝgÞiÓŽãüRk}Ûš½°É% ¥Ri[£Ñx™ÁÌ~æÌl1ó³W¯^}íÀ[£¨MF£ñ¾Wqk}Í^Ø‚@{Ô†DÔ  ÿD³m{fØÒµ - Ót‡ Pµ!3ÜÖŽãtÚßHÍ^5Ý*ˆ|ì£íGôŸh>×\†¾^Ów”RoŽØ”•RõÛ¿¾6jC"z(ÈBîÅwjµÚ§Dô®×vDtÎíÄŽá®Y ±­+Ü´Ûíãð¶ž`¾Ýn¿D߸ÏÌ¿ð­/Øèýü3ÿjqqñùa‹96˲ÎöžÊõ„ˆºÝn÷l5ÝÖO˜oÞh£Z­^³Ÿ¤ÓZÿŽ™ŸõØìõ¥¥¥ß;(ÑëªÕêõ´ù0>>~À?ÝODmÛ>bIëd(8åry-—Ë=GDo ºô^{]kýÜùó翈¢6yl*b…Baº7Âwˆf^p¡Ûíž]YYñtJ÷{ 0.I›O[jПO0»ÑØú½öÀÙìbÿ#PkýŠÖúQ¯íòùü~­õÝ›äùtÓù^ÔÛŠíÖú¿Ìü¾Rê˲æ{›3¬›ššÚå8ÎŒã8Ñ!fžbv7Òéc>ý„‡6©æs_Ñu`æØ lÞ °m{†™ßñ:¥JD]¥ÔOþã¥ib¿ °…™`æàãL“ôùtÓ%~ éóé¦K|ðùtÓ™€Dϧ›Î„$z>Ýt‰@ÒçÓM—ø$}>Ýt‰@olßóFVÌüg¯+i”øÉžO7Hò|ºéŒÛ"&èùtÓùýü{<¼7¶2î:6 #."<ÆâÖ[˜2ËÌOx¤÷ëÏ”Rog³Ù3sss7ã¬Ï+ €¶mO6Wܹñ>Çqö5§mÛ>V«ÕŒyêY..•J¥mŽãÜëË¿Õ^Çq^-•JÛ¢ªË/ €KÍfsƒ¿ü¾½«««G®'(—z×|Wˆè§aÖ$ €KDäz»"zdøQÉ ‡wnI\bf׋K™Ù˜ÑH €KJ©·ÝËÌ®›À¥l6{À%‡^š˜˜ø¿Œ’DàÒÜÜÜM¥Ô1 Á%¥Ô1“K“xP«Õê¹\î)f>àßDÔêmvù/f>‘Ëåž2i0p:XÜ.ÉO HRNr€”“¤\ìw"^rH9 @ÊIRNr€”“¤œ å|€ˆRñŸ?6#"jqy/fþÜw|îá#âuÁwFÝÃGÄ«¿‡’‡ˆW¥@î¼îá#âuëJVoxùòe§X,žk·Û_!¢¯Cn/©w©~öíû{(þCîÜÇ™³A÷!Ü#¢Vš÷PB!„B!„B!„B!„B!ÒâÿZ@!u0hª»IEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-effect.16.png000066400000000000000000000007631370472574300247030ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8µ“AJÄ@E_ÅvˆÈ ÒíÂ[\‹aÐDpå)ܹ›#è!<€¸P\:`æY‡dÊ…ÉÐF33ü«êªúU¿ÓkÔH’ä(Žã­<ÏßèÓ"r(°Ók€µö@D¶UuÀ9—ªêkUUƘá"²ª¾ˆµö ØhÕÞ‹¢ØÃðq‰€©Î] ­“#à>Š¢Í²,G È)0æd­}t2™tzàœ»fY–XkÇà™¨ªg"¢K$Ïø2zŽù€ ëðÖßä7·Ï§`¨ªë?6uÁü–lorÎ×ùëN…ÿ c¹\…¨ªðý S`ÐVćÿNUu¯¹ëÓÿ?ø)i^a î+IEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-effect.32.png000066400000000000000000000011651370472574300246760ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(“IDATX…íWKNÃ0œgå •²I½à]€*$XöBºÚ%Gà”u%XÂêfÓz„*ÃGŠÒ¤1ù4fe[ÏÈóü¬-CÒ ¾ïß+¥¦EÑ( Ãy“Ô#‘’g$ÏEä±IñL:‰ñEN ñ}ÿÎu§€»%9Ãp®µ|©¨½‘@Ù‚+€Žåb¿ß`E]’“RxžWU<Æ¥Š¢h`ã@ÞÙqW¸ 6éõzßÉùr¹¼ªC(o¯ÎÍSB·&("1æ#‹—UÛÄØ%š<<á·tINòHHŽEd'";ã œpíý•û¿ˆ$§¨” ryé­õÀ§ö1ï€{¦E(,Œ߂8SØLoÊH£õ·ÀÙ€ˆÖVÇ2ý+œû€ÍüúEi­‡–;ƒã[Q[#ÒZI>Û1Œ1¯.ßµ^µ€1f¦µ†ˆp±X¼Üº{…¯aÓh½² ¬O¨¿Êú/ˆNóâ56´ü£4~îàdD:ô IEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-effect.64.png000066400000000000000000000022301370472574300246750ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¶IDATxœí›±kGÆ¿ooc°°Šm„@{‚4N+[B…JC !a—®\bÔI*Qr©ÿÀI » jdD,Pm‡Ý®àP0'âöRänž‹9—ãîv÷væveí–ƒ7·óÞ|7;oæ-$¢¤¯OÆù’ïû“$×ÌÙ°†á ›Á ƒH&''}Ù‘‘ÿÝHž’\ªT*Ø Ï>NÔ”R«ƒQJ-Û kxD €Ö´ï Ƀ±dB.÷j‘+cÉ„8|Òd@Ö|ß¿`À ú<ó1ùÀï$ ‚àe{C¹\~$"×SöŸ ’ïì)¥6ŽŽŽ911ñ%ÉŸ‘~àŽN,AœÙ|ß_ðƒI?)¨˜wH®ÀðàÖ>ÀZ»­Ñhì›ö“‚«V’7,:™EÛÙ¡Z­“lZô—’sz‘Ï}°±‚RjÀÇ_||||LDrušt¬ëË($ß—J¥µv›ëº¹Û:;a¾pç€Bè4³ã8έJ¥v´-¥íß4‘Çaß÷_õkÃð sá˜'*þ ½€›uƒàûþ€U’sÚôqg—´¯s7ôà·|%"Wôu“䯺-‘ô[õ‚7lVŒv±_°’´³HDäù m¶h›ö‰Úz)€ã8?v›:Ïo$uh‘¤÷D  «¾ $Ÿ‘l’lŠÈ.É…ÃÃÃ?Š4{}Úv“v+ è#í]üw°Éì@£”Ú 9Ö3ßÎ’ëIûKššÈpð SÝ<€§$ß‘|à Éù þJÚ_¬7CI1™§ ÄÒw')€.cýÒh4ö«Õê1Ð:Õ¹®;Mòvw:žåéÎTU0†áq²!¤#J€È5@×ð®»®‹r¹ÜÔ¶’þìvKTž¾ås˜$Ú Ç9Ë“œë•ÉÓ¶êVxaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(#IDATxœíÝ]h×ðÿ¹£EÚõVM*«ŽØ]mjCI*ÚÔØ8©iJ[“”’ÔvòØRÈkLœÓb('-¦ô)´Å”~€R%¥v(M0T®B@<˜H±*í,¢ªXûŶ´kkgO²jܤÙݹóqgÎïuwæ˜?WsæÞYB!RÊ òä¶mß•Éd†677o9Žé>¡mÛ0ó":ÀÌ;€ˆ6˜ùïÌüJ­V›Õ=¦œ¶T*•Ñ­­­³¾Öu@¢·†‡‡Ÿ_\\¼¡kl18-Ïçr¹?Øãñ…f³yt}}}CÇøbpJÇIr¹Üx¿ø°7›ÍžÖ1¶ðÇwŠÅâC¾ÕïqÌ|¸T*=àw|áï0ó÷<”Úíö“~Çþø=ìãð}~Çþè¸ø¼cïÑ0¾ðAG²+4ÐÒsIRNr€”“¤œ å$)÷‰Õ@Û¶dæ§|À.Dß«7¬x[)õêÊÊÊ{^²mûef~,ØÒŒÐ° à’eY3ËËËÜùá°k×®###g|;äûBD¯7“½–’;A~-¬ºL@D.€é±±±Óóóó[@'{öìùL³Ùœ°7Êû°022òt¯M%¶mÿ•™'Ã*Ê s;wîüþüüü–€f³yæ\|Ø{ëÖ­Ÿõú3¿F1ÚwíÚµ“  …‡".¨oÌüõNíŸJ)õNXõè™r¹|Ÿ"¢g¢®dPDt¬Ûç–e-„U‹i˜Ùr]÷ˆ"¢ýQ3("ê:,--Õl…Tމö«í­Û&bæ|¥Ríö"’ÝÇŸ‚ˆî5þAeYÜísfôå“1óED&o;ѣ´t!ÒN1³Éoêt­}rrr ¼ý”$Š™§£.bPÌüJ·Ï[­ÖêÅTªV«ÍÑ[QÒ/"ú[­V»Ôãk²ë¸ÃÃÃÏ0©g^ØØØ8áá{ƶ¸aQ°¸¸x£Ùl%¢ QÔÑùf³y´^¯ßìöÅR©ôô÷ºZ*}â©T*=Ðn··—ƒïA<–ƒÿ—ƒ_óº\,Ïx$ÐÊÀ÷r±X\òs¼ã8¿5|\ç}Å$»¸Î̧ˆèç~Nbüƒ ›˜˜ÈÑ‹HöÅŸp¸V«÷{¢! ÅÄ Y–u:Á{n8ë8Îo´uœ0I B¡ðcOD]H@®8î8Îû:Ošˆt¶³½à›Q×ð»|>ÿÒåË—µÿØ–ñ(‹‡ˆè3ßu-Xð‚ã8sA `d¦¦¦2õzýQ¥Ô™ùKÌ]DD燆†N---]rœØ`||ß½{w.“ɼÛjµ ½àwšðB­V[ k@X`r 3¯wû<›Íæ·/~Âioï¼Òñ èmÇv½¹iµZ>ÎmŠ+žtçB¾ø€†(¥^ðPVJý©Ç¹µ?&Ž "jѹ|>ÿݽ}?|ÿ XYYy϶í×™ùp?ÇÑ…^ ;ívÛÏ/ÅÙ€ÕjÕÏì©…–µ€F£qýí'Xh4?êö…©©© €ƒ¾ ‹!":ŸÉdÇáâš°¾¾¾122ò4½Ùë»Dôææææ±^/wÖëõGÜ­£¾˜¸ÎÌÏU«Õç‚îíû¡í9@gwî³…Báëü\|ˆè&3Ï2ó´ã8½¶q”R?HPÛz{çU K¦Û/mô›øb±xÀ¯)*\·w~÷cú$p©n||<ßy¶DIaZTJ_YYYŒºnâ¶!„r¹ÜOM^ع£½ûnÜ/>¯µ²mû3#êB|ˆM{çU,011‘íìä1v3GX«wºE€b±ø½hð6®PWïtóÛ¶_ðËjµún?Ç•Ëå/»®û,€ƒÌlêÎØ¶w^ù@ç§Ø³mûŸÌü†Rê˲:?ΰ͚œœ뼫·À~×uM~i#²Õ;Ý‚|/ ED×™Y¸Ëï81«öÎïs€ ÛÀ!fþ’sñÀoMi*ü&ÐkDdT{çUÜÅÑ_ˆèñ$^|@f€nnø‰ã8Žº Iþ¿9|¸ߨöÎ+ ÀÿºMD¿¨V«¿†áíW€\p¼Z­F¶?/ røQ{éæÌ¨¤}Hl{çUšg€D·w^¥qHE{çUÚšöΫ´ uíWi@*Û;¯’|˜êöΫ¤Î©oï¼Jâ í]’4H{7€¤@Ú»™iï|29ÒÞi`âM ´w™6H{§™I3€´w0aö.@q€´w‹k¤½ I í]ˆât(í]â2H{‘8ÌÒÞE(òÿ(¢‡@DHr€”“¤œ å$)'H9ß ¢®ÿùCÄÝÔ1ÈR­¡˜ù_¾À̳:Š‘˜õ˲fˆÈÕQ¹®ëÎøÀòòò¦5Ô$BÄÌX]]]ÒÒŒðçÁ#¢K¥Ré X:N¸¶¶Ö®T*Æg‰è~H{K?Õ¿/•J'.^¼Øø·qårù>×uØODÌœÓ=†ðŽˆ6™yÀ¬ëº3«««²|/„B!„B!„B!„B!„B$Ða›ã¶HIEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-transition.16.png000066400000000000000000000010331370472574300256300ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(9IDAT8µ“±JAEÏË®I Y +;m ?AíÒŠöÚ‰…Ÿ`aá'V‚ ¨w+ëh1²{m6°ÆuM o3ûsî{30©êõúr­V›lµZÏŒ ¿¿1³c@ÀôHιE3›’4Á¦¤§8Žo|ß_/‚%=šsî˜ðÞã8žó<ïöz%`8ÉO€Ïóæ À‡t-[¿âœ»T­Vg:ξ¤`½{¾³‹æ;<ÏÛPJ½ q·ƒ 8¨Ò€J9"z-"×EämU Ï4 >ó|s–*ò<ïÑ4Õõ bE¤Áïûë"²S’}DD5-¸‹àPŸÆb< % Ü‘7…¶Àq»$<ÑmÇqÀÀ x "mˆ¢è>2^á"J-Òh4~϶™¹9Ûv]wͶíO"r7'ëTD^Ñ»ÙNã-hµZW=Ï{hYÖ^xÀã ¾Ìdíå1þåšÍæµápxH”;ë€mfÞg¤2 "]":!¢]ˆ¢èA^2€ŸJ©g̼ó?8`PH®ë®Y–µàŽ •ˆb»Žãl÷ûýh~|¾ÆR[àûþ:€o¶m_™L&÷Dä…ˆÁ„"²ÉÌ=Ãø´ä„F¦k$Ú'¢®ÖúOžI‹8PÎl1óç"“ËèØdæ°èE DDô^kýçTxU~x®µþQœ(Ïe$>Öjµ§Ì¼8`žˆ^j­¿. œÈ$ûDô¤ 8`pV­•f8Z"?Ìú/è,ÉD¨”ê,s©K¯¿’µM–IEND®B`‚olive-continuous/app/ui/style/olive-light/png/add-transition.64.png000066400000000000000000000023621370472574300256410ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí›¿oEÅßÛ³ˆO±~¤°ç|g hh‚ R Ž„‚”‚‚DP„ E0BtPDP …‹4(M,QZ! òÍœt::âÉ·7_ _Ðbî¼³ÞÝÃìGºâvfçûwsóvfw’DTúŸc]*)¥fH.˜ "²`ÉsÛgry+ÀÌÌŒ‘U9ñÉ]’¯7›Í;þÒóOWÁZûîÁ΀ˆœ°Ö^ö“V~Ä €ýa?’g2Ì¥\xtXˆŒg˜K!¸p¬)(:¢!(¥žpÀòŸwäO·H®h­‰ÔjµoDd.eû© ¹`ÍZ»Üjµ¶8==ý Éo‘¾ãíXÐZë‡Ç”R¯ø8Ë8)Øðj@ò 2î<°`1z, ìã¤`À•€äiAæY;´ÛíÉžÇx‰ ùBÞ“ É9æPD¤ô6^°Ö®øûo4óï(–úV¦Ü©T*‹ÑcÝn÷¹¬ã¤%0ÆÜ‚à€YÑ·™A\h6›æ@ÙÅ´ígMìrX)õëaåÆ˜Y—@J©³¾pÌ+ î‹È{$?=¬R.“`½^ ÀÕHØVöH~¦µþŽöæJjTJ%ù‘ˆLd‘ÐŽdo®Ä Ð߯ú. Ãv»ÝÐk4‡axÀEó>V¸$-€kããã+G±7W\lpÀÜØØjµZOD$ CßWIeo®$Z ˆHþ/Ÿ3±7WFisâ€÷1ßçtTHloYQ´ÞìÍ•"¸ à’ֺЇ,Џ5&¾ªV«çGá “¼G@‡äÛZë[9ÇJž#à:És£Ôy ŸPˆ½¹â[€ÂìÍ_no®ø`$ìÍ•,'Á‘²7W²#go®d1FÒÞ\I}oð¿Îÿþ)±R€¢(šXÞÿ;f99¹ àÉSñŸ›?Hþà’oh­+:Ÿ’’’’’’’’’¢ø Õ{‡÷.·rIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-center.128.png000066400000000000000000000005731370472574300253540ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<øIDATxœíÝÑ DQ¶ýW¥“·Eø˜s ‰ù¼˜k­oõ»½î@œâ'€8Ä Nqˆ@œâ'€8Ä à1ótï ܵ÷>:CAqˆ@œâ'€8Ä Nqˆ@œâ'€8=ðöû‚µÖã;n4@P3@P3@PoÿÞÿÖö'AÔ5Ô5Ôÿü*ä_ ¨ ¨ ¨Üô` ûôaËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<íIDATxœíÜA0Á¦Jâ_NZÌäv Àãž çÞûûõÝ^€]ˆ@œâ'€8Ä Nqˆ@œâ'€8<æø°kfÎæ|Aqˆ@œâ'€8Ä Nqˆ@œâ'€8<Æ€8Aqˆ@œâ'€8Ä Nqˆ@œâ'€8<Æ€e3s6绊@œâ'€8Ä Nqˆ@œâ'€8Ä à1  ;Ó¼ŽcIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-left.16.png000066400000000000000000000002551370472574300247370ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<*IDAT8cTPPøÏ@`¢DóàŒ¤†Áƒ‘ù#1 ÐÁH ƒa˜¢é ËxoñýIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-left.32.png000066400000000000000000000003051370472574300247310ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î<BIDATX…íÖ±0BQÈ$î?•›$˜Ê£ù¯µOWÕUÐI.' IÞ¾Ýíio€õ;ðoþ«X ÛêÀ=ŽIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-left.64.png000066400000000000000000000003771370472574300247470ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<|IDATxœíÚÁ À Á˜Jì¿*;IŠð°ˆ3÷ÀòNòɘs~ÏÅÞ: f€: f€: f€: 2N¿¬µÆÎ÷׿ PÔ PÔ PTŽ¿ìºþ%h€: f€: f€: rü=Àÿ› PÔ PÔ PT~ôo û§uÊÍIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-right.128.png000066400000000000000000000005521370472574300252060ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<çIDATxœíÜAÀ0Á¦Jâßd+ƒnW{çÞû=d½Ó0Kqˆ@œâ'€8Ä Nqˆ@œâ'€eÎôþ̲'€8Ä Nqˆ@œâ'€8Ä NqˆÀ2Ç}~› 8Ä Nqˆ@œâ'€8Ä Nqˆ@œ–9ÓøO0ËFPœâ'€8Ä Nqˆ@œâ'€8Ä NËüëùyê ºIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-right.16.png000066400000000000000000000002511370472574300251160ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<&IDAT8cTPPøÏ@`¢DóàŒè¤†ÉpƒÑt0šÏK‰¹d RIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-right.32.png000066400000000000000000000002761370472574300251230ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î<;IDATX…íÖ± ÀÇIØIÁÊPxW“ð ä«»w­Éå@’ÔmàõŸ¿ ôï€> ðY™\ñúgIEND®B`‚olive-continuous/app/ui/style/olive-light/png/align-right.64.png000066400000000000000000000003721370472574300251250ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<wIDATxœíÚÁ € A±úoR‹à°!¦³y' ®½÷÷ öÖ5Ô5Ô5Ô•uúÛ߯Ÿ PÔ PÔ PTÖí÷ùSãO‚¨j¨j¨*þ¨j¨j¨j¨*?O ¹>fŒIEND®B`‚olive-continuous/app/ui/style/olive-light/png/arrow.128.png000066400000000000000000000047611370472574300241410ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsN½N½sjhtEXtSoftwarewww.inkscape.org›î< nIDATxœíol[W‡ïõu“ŒÑ8 £¬J}ÏM+ DÕåÏVV+ Ð6@H jÓÒÔÁ¾°ˆU+”v[7ZÄ -âOÅàØÖUmÐm ˜V`ЬYµT´8öu›hÊH°»Æ+iì{øBë$Nrß{ν÷<û=?_?9¶Ï¹÷5À€ã8d³ÙŽÚ†`±8ŠÑ;ˆè/Bˆ õ ÁÁ"Ñåö !ööôô,âǰ0ؘÂccc‡…"„± s$ @DïpDñ‰0Æ34O(ÔépH±@*Äq 3¦@6 !žs]wiÈc¶øˆïûGÇY«h|CU€ˆºüQ±IUƒB€ˆl;„»»»ÛUfI*J˜Âg|ßÿkww÷jÕA’†.ÀÛ}ßÑqœ;TI: mDôˆã8vuuµ©“t@D·Û¶ýB6›íV%îh)@÷X–uÔqœÏªgtÑ/„»×¬Y“V&Žè.0¹zø•ÑÑÑçǹRu˜¸.p=õe³ÙõªƒÄ‰( o%¢g„Û½ìZ¹ƒX_=Ü*„øU6›íP'êDN€)ÜbYÖÑîîî÷©e¢,8¾ï?ïºîªƒD•¨ ­RʽŽã<ºlÙ²ËT‡‰qÀäêá¢E‹¯X±b¥ê,Q"6Ô¹ºV«½äºîçT‰ qÞ,¥ÜoV›#ŽõÕÑ‘‘ß/_¾|™ê0:WDt]*•ês]÷cª³èJ¬¨s…”òi³zؘ¤€­®ë>ÙÕÕµDuHŠ)åM¶m÷ !®QE%@åþ „¸[uH¢Ð`—ëº-]ºôMªÃ¨$©¤”·µµµIr3‹D PçInfa@²›YþŸÄ5³0\DÒšY“˜fF€éID3 #Àìĺ™…  âÜÌÂÐ$qmfa˜;±jfa˜±ifa˜?±hfaX Qofa†È6³0G$›Y‚%rÍ,Œ11Ñ?88ø/Õ¡804¦µµµu³nïטu€ÆtŽß¥:D¦AJùµžžžËUçàÆ0 Dô–J¥²QunŒ3sO”/ýn#À̼-NG¾ ÄLfÁ÷ýM+W®lQƒ #À,QWµZý¢ê\ÄEÀ«ŒõïÒ5ÿs!Œ¸ˆ¾Ä8†322r;c}eD]€Q˲>êyÞ…Bá))守h3b¸rY¤”9Ë²Öæóù¦Üü-Æ!W¸®{+c}%DU€?§Óéµù|þäÔ‹ÅâAǸõ} bÖ=<ЍV«ës¹Ü?üMxˆk`"Z)„ø'g½ãü3mCŽ]3èþ$†ˆh]±X|zŽ«ØÁ¨NâÆú¡¡³ÇlÛ¾Æó¼¾ù<¸³³ó1…€3Me+&/íŽ4º ð¬mÛër¹Üà| ôööNàü,ðnÇq>ÉX?´@Jùˆçy7çr¹×Z«³³ógŠÄj}“«vXè$€p_±XÜ DÁÞÞÞ "úNµ¦áa7t]p«çyÛ‚.œJ¥~`(躨#ˆ,:ðß Žâ¹\nÀõë¬B|˜±>+J¨oè\{ц?ïù[k³¢R€?µ´´\›ÏçÿÁ=çyÿ°‹qˆ\×]ÇXŸ U°>Ì (Ï;÷6AJù ®Úœ¨`çyêÿ•¡1<<\‘RîfâÆl6ûAÆú,„&@}CçËMnè°N§¿ ÄU?•JÝËU›‹°8‹É ½!×úâÒ®úRÊ›tüM€™C€!šÇ† –e}@™«¾ïû›¹jsÀ-À‚6t8Èçógˆè‡ŒC|ÚuÝ«ë §Ï¶´´\· .Ο?ÿ]L¾-q@Rʯ3Õ–ÛÛÛ+ÅbñþÑÑÑP?é7ËÙ³gϵ··w×§öU‹/þå™3gؾvË P,aò¤ m±,ëaoð•·"ñY V§8Ï…r¹\Éd2WàêÅû®ŽŽŽýåry”©~ è°¤’¦=Ãx¤¤”Ú¯ $v€r¹<ÖÑÑq%–>¼V/Y²d_©TÒ¶ÃXÒgÔO!?ÏT>U«Õîaª‰ž T*½žÉd–XÃQŸˆVg2™Ÿ—Ëe¶Å§…ø,Ëz|³@€¶³€@>Ÿ?àqÆ!îp]×a¬?oŒujµÚöúŽ%‹|ßÿ*Sía¨súôé˲ösÕ'¢*~p6ŒSð}ÿAð«ÐjÛ¶v³@ä/m !Ä~\=ÞH¥R®N-æÍ p–emÇäE*\æûþ˜jϋį\L©Tz-“É\`UÀ¥_&¢M…Ba/ø›3æ- Bˆ«¼„ް³P(ü½ð0Lƒã8OÑÍó}<&¢mù|þ·Aæ #À4d³Ù5–eý s;FRJù"ÚîyÞ‹\Ù‚Ä0Bˆg|¼‰»úRÊCRÊm§NêåÎ$±ë|$RÊûˆh&&¤”OÑCÅbñï¡ 3Ì‚âwn¸èæóRÊý¶mß?00S‘+(Ì 0;àTü´Z­~{pp­ç@˜˜  „OJ)ûªÕêî¡¡!­Ïñ›+ÿßߘKïP¹IEND®B`‚olive-continuous/app/ui/style/olive-light/png/arrow.16.png000066400000000000000000000007261370472574300240520ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs Ø ØÇ ¹­tEXtSoftwarewww.inkscape.org›î<SIDAT8Ð1KÃPàsÒˆÔ'µ¡(XJ^ˆ™ìfÁÁIpr×ÅÁMppWtv±£øÁÉÅÅ:\ mKCƒ"&Ä%)Zls¦ çòq¹@Ó47¥”»3J<„a˜%y!¥¬–J¥ìØ@’ÛªªÞëºn¦¢,)ŠR“Rn¥ GòÚ0Œ³J¥2‘Øït:·RÊù4@œ5’Oº®¯§`ŽäaGÑe#ßlW$OH>—Ëe—ê€+„X¶mÛT»àÀy4<ÏÛ¦.…¾ïx’‡Åbqj‰MÓ¼4›Íƒv»¸®û™Ïçg¬˜Îd2oÝn÷! ô¿iYÖd½^ÿú]Z–5ëû~€ðªªêBr§ã8ARwçCÓ´€¹ ½^¯ößþ$ ÃS$wZ­V5Ùÿ‹G]€—ôǤIEND®B`‚olive-continuous/app/ui/style/olive-light/png/arrow.32.png000066400000000000000000000012651370472574300240470ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs¯¯cæŽÃtEXtSoftwarewww.inkscape.org›î<2IDATX…Å–?hSQÆ¿/IÅB0ƒƒKÈ=ïµðp¸(.Ý¥T¡“à&.JAŠtÕMprq ":ˆÑB‰Bï{!•X3‘„Þë’B׿OŸ½ßöÎßçrÏ»€CJ©åR©¹|i+ã2’]k·Ûë""¾@ò4€M9ï §£^ŠÈ €¬ €%yÁ1»š3Æl*¥ÎúÉ"€·"²ä ‘°""«a OŒ1•0 Oú€cLE)uÕ&ùX)õ¤X,Nû\Ìårë¥R)ôÐÓ©L&óI)5ï Ž|&"Êåò”€o$× Ùl:oH.¥F¿|&¹e­­’Üêv»Õz½¾=,1’kZë…IrS9kíü$Kh€m’wvcnÿom­=§µ^¶Ö¾wø/Nò BòL’$_{ß÷]µHŽýg`µÓéÌi­¿ï’$yàÃ` É+aΤ ð0Žã…F£ñÛÑìž#>kŒk ÿØ!y=ŽãŒ+@kýœäG‡kQ)Œ à|\æóùZ­öfXr¡Ph’¼4X“ät«Õz1 G Ú+_D¾Ü]’ǵÖɰû]Dî1àÖ(ö;ÈŠHÀì€ýÇñŸ½’ÓXÅ;$û§ðÀ]cÌì°æi*§”zÁÍ(Šòã$þ1쟇'²ïIEND®B`‚olive-continuous/app/ui/style/olive-light/png/arrow.64.png000066400000000000000000000027041370472574300240530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYs'_'_†ºjtEXtSoftwarewww.inkscape.org›î<AIDATxœÝ›[hUÇÿßì$ÍvÛ&Û¤]]6;g¶ ò¢TÁ»T‘z©P„‚¨}©E¤”^ÐÒ'i-¢íƒP >¢Pox¡J•V¨ˆƒ,[$Ý3ºfKÉeRÓ4»óùÐDjmëÌΙÙYÙs¾ÿ—_NfΜI—är¹µ†a<ãv|« ¹ÈÌq"zË0ŒC™L&dSaâZÀ"Êf³(ªªÀr"úJ±GqÝ@QÚ(év !>Ïf³I•µƒ"¨ŸÔcš¦Êår·T_A.UÃqœï„ÛÌðM陼q(N/ 8«!B¹Xцöööþ+VäÃÈóB˜Wë›ëõúϦi®1ó? ûvµ˜™?ŠÒî±÷k°ullì›ÞÞÞtòÿAÓ6,Dtw,2MóÁfõ4ǶŒ™5s÷Øl°Û4Í#™LfiØáQ`æGu]BÜfndÌÑ àÛ0wQ 0Mó½T*•:,ŠÌüT<Èf³}AæDVÀ7ÑBˆ'‚ ˆºÑ" !ÞìëëkW]?ò.ãÙ©©©~!„PY´•€ˆn0 „xHUÍ–0G7€£Bˆ}¸´‰òE+ .=PíB7M3å§P« ˜gµã8†aÜÙhV"Ê8!„ØÕÈü–ü}¿OñY.—ëô2÷!à2Ö9ŽóñÊ•+» ÙMÀLÑf.8£iZA×õ¡ááá1/EZAÀ¿¾Q"úedd䜊âQpÀ÷Ì|†ˆ DT˜-”Ëå‰ C£$€˜y“eY¥0C£tl#¢†ne~ˆ’Øhš¦f`Ô´9ŽóB˜a8MDƒnѦ0_˜*€™¿Ö4íÇq^ô0­#‹í ¬©+RÀ;===‹ÅªeYÇüäaîsaýÑUÀKRʃƒƒ³ó_$¢—=Ôè°CygWAµ€fÞ ¥Üså¥RéˆÇkÁæ|>¿LiwWA¥€ k,ËzÿZÇyÕC½D½^ßî¿­ë£J@À]RÊ×dYÖa§Ýeæ-A¿/T!àd,»CJù«‹± ൗ躾µÁ¾\áWÀáZ­¶ÚË“™”òndͳ]Ñå½5wøpPJ¹¾\.O{œW'"/« “ˆ¶xÌpM#ê̼EJ¹ €ÓHh©TúÀ°Ûñ̼ÃË)< `æ)MÓÖY–õ†ÏÜ:3ï÷0~éÌÌÌfŸ™WÅ‹€³î-‹_ªîééy€ô0åù ^—»~³bÛöoÕjõ¬ªàJ¥âtuu]°Ö唄®ëãÕjõU=M~îîî~€åv<íTý[¾ß­ù¡R©8Éd²àa—Sišvζ퓪z U…EÑ`€Û3€ €œ”ò‚Šü¦®°m»ÖÙÙ "ZãrÊb£¶m¨Èoú €t:½°½½½`¹Ë)¿'‰|¡P¸è7;g‚£££xÍÔòôôô *²#± •J%âñx À5ψ¨ÀþR©ô…ªÜ¦_æ9þül2™\àþ+?cæ¯<-¥ÜkÛ¶ë-´"³ ŸÏ/©Õj@€ÃÌGc±ØÞb±èå<Ñ‘Y0111“L&Û˜ùOZ–uprrr4ÈÌ¿2\€è‰?À IEND®B`‚olive-continuous/app/ui/style/olive-light/png/audiosource.128.png000066400000000000000000000034501370472574300253230ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(FIDATxœíÝ_ˆTUðïofWÉÝjcÖ-¶Ý½÷άY,Q(AiÑCø'Å?E‚†½aô¤ ùK&©Am¨šAA/iYKÑ‹!íî9ã¶™&54SÄxﯗ)Ôlܽ{ï9³÷ü>¯»sÎîwî¹sçÌ „B!„BWí®ñ<ï."Zàf¾ˆêÎ1óašœœüÁd)€!K—.m¿xñâNë™9w­ÿ!¢ÀÁB¡°{tt´n"—À€R©Ô†á^f^2͇œêîîÞl¢ù´'p]÷„a8`Ñ Ö_«ÕnªT*Ÿ¥•ë×<‰dxž·:Š¢ƒnécs¹ÜÆb±xG ±®œ'í •÷<ïE¯˜gf·a¸&ÙXÿÕ–ö®¸…ˆ^pÃ=˜ÀMIÔx‰·™û’ˆz“§YâyÞãŽ$uð€™;’ëÿÈ`öÈ÷ým̼ sðeµ`.\ØÙÑÑñ*3?j;K\R€˜<Ï ˆh?3—lg™ ¹ˆÁó¼G›ëÌù¾¿•ˆ¸Ñv˜$È0M½½½ ÚÛÛ‡™ù1ÛY’$˜† ¼(Šöcf÷óçY®#‚‡¢(:† |@ Дïû›˜ùM7ÛÎ’Y®appp~½^™™WÚÎ’6)ÀU|ß¿­^¯ïp·í,&Èp™þþþû‡#üË÷ýu¹\n„™»mg1Éù%`hhh^­VÛÅÌ©o¾hEN T*õT«Õ7Ük;‹-Î.žç-¹téÒq8|ðG àûþ #zlg±Íµ% ïyÞvfÞj;H«p¦ oÖÌ ' ôfÍ,Éü5ÀÀÀÀHx³f–dù ÷EÑJ_ÚÎÒjœ(”Ëå_µÖ› ×Wp¦ ¡Öz˜ˆ^ð—í0­Àµ”Rx ÀyÛYls² µþ¦­­m€omg±ÉÙÀØØØùÎÎÎ Dôží,¶dòN`¾ï¯cæ—Ðb?§+w QJŽ¢èi"úÅv“¤—9{öì×VøÎvS¤WQJkoo_à}ÛYLk€&|ß_`3çmek‹”R‡‰h €Ší,i‘\ÇÄÄÄÉ\.· ÀÛYÒ ˜†‰‰ ]¯×Ÿð±í,I“LÓÔÔÔZëmD4LD‘ít¦«ÉÛÁ”J¥ž0 ÷2ó’éü?3Ÿ,—Ë[¤þQz9066v¾P(l$¢w›½ÐøÛþb±ø, |@ÎÆù¾'€õ̼ @€*€sN0óÑr¹ö™;°ÖÎB;U] =𑳪. „k@g„d£l ¢ÛXÀן˜ÖàcMÓØ, IDj[Uô²xïOD´!¢G_½(DçÜ•™×Dtp)ñëÉ\8 rñ¥IEND®B`‚olive-continuous/app/ui/style/olive-light/png/audiosource.32.png000066400000000000000000000011171370472574300252330ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(mIDATX…í–½JQ…ÏÙX„(¤ «ÍîÆŸ°·0…UžAE,µ Úi°Uñ| ÅÂÇÐ݉Å€lÐØwlD$$+¹»É‚æ”3wæ|÷{ÿ.Žª±ã8ë$k>HAp3.€œçy{ªºñ#ö("+ýO¥é\*•f …±ªVzRsƒjRpgÞ²¬U]¦ÎJÃÜuÝ É‹aÍä+@Ïó6쪪ÑdŒlÛžÎçóuU]3ía P.—Ý(ŠN,%1p]wÀ»7EQRßoÅíÛa?ó´0;jó߯¢ À`ð”)Éýq@}ÉL#Yì7:¾ïK·Û­¸4©O Ífó]DvHÖI?IoAp¦ª[^³ˆÈµªVIÞeFã¾ÓéT\e­VëMD¶Iž÷¤žÕäÒø’†ax[,}’Ë^TµÖn·Fàõô n«s£K®.eIEND®B`‚olive-continuous/app/ui/style/olive-light/png/audiosource.64.png000066400000000000000000000017751370472574300252520ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíš?hQÇ¿¿KRA…‰ÿÍ»´Á% ¢ˆtÐÉA°`Õ"¢£ƒ Òºu°8ZpS»w©¢ V':T:¸äþPJŽD’ËÏÁ ¥$m/ͽßÞg½Çû}߇÷~¹$HHHøŸ!é½ ”*˜pŠˆR̼`Æq+è\± ”:KD™yï†G€± ŒþE RJÝ"¢Ù‹€,€»A'MÁÌϤ2¹+¼v%î€ÌNçŠrìŠmÛóÌ| Àwݵ#!\×ýdÆ(€Ï:ëFFX–õ-“É\%¢ºjF¢tb­/L#à†Xö€Nض=oÆu"Z ³Nd€eYK†aŒøVH €jµê6›ÍKÞncx-èü©à‘ôS¯×›žç-är9ŸˆN¢{ïúàyÞ› sÇBÀ_<Ïû˜Íf—‰è € kDt§V«Ú±žçYÙlö€ýø à}:¾mY–+›.!!!nü«â×}‰ÃðIEND®B`‚olive-continuous/app/ui/style/olive-light/png/beam.128.png000066400000000000000000000042641370472574300237110ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsääú[tEXtSoftwarewww.inkscape.org›î<1IDATxœí]lW†ßwfínW6Ñ&Z{fclL(iZú“6jU~"@‚ à‚+rW5 Z PABUr“ *ÜTT@)ýIMK.œ´A$$1v|f½(µ¨/صãÌÎDžוã&Ùµ÷gÆóG²¼žýæ;¯½Ïž=kÍÕ0î½½½÷’|dù6’ fI.ˆÈ¬ˆ\"yd@†á¿''' €r™¯‚ÛÓÓã»®›#Ù+"9ÙLò’E¤ÀÒ÷w‘' …‘˜22q®ën‘=W»OD$¯øÙu]ø¾?+"o’<."#mmm/ý§™ûúú>†á}$w’Ü!"°ñz™—o[Âqœ_·"ïõˆ]€:ØHr7€Ý$†aÙ÷ý×üÎuÝgÆÇÇ'9X___O¹\þ"€}åryI¸ò^¬gVâ¸Àårùçžçý ÀO‚ 8VOSÏó†ìÃð+$Óô÷.–ã|ÀCù|þH¹\~¸P(üs5 z{{Ç9àžæDLNÜšˆÜë8ÎIß÷vV«Ïår|ßÌqœHùƒ( B€‡gffŽyž—¿VQ.“ɼà‡nhYºÑ"€äÉß÷?½ò>Ïóv…axÀp ÑbC•Þàß÷ïZÚàyÞÝ$_pSl©b"ö… ß÷ovghåvÙ`€néÐ àÃn0€ú§èi×uïFQt@Wý.8à €³¦I¾`Àɹ•;DQtÊóVãÖEì¬wëÖ­[£(Úà~bQU!"E ™[C†i’Ïx‘ä±óçÏŸGrV&kf½ p¾ïg|À~ŸlòpÇH>)"0ÆÌ7y¬¦“ –ãyÞƒ$èkd_#ùcÌŸÙ7nܸ4šR©ô¯ÎÎÎ_8޳ :¢‘§H~Æs¶ý’Dêf€åxž÷(É×ÙæcÌO(¤nXN©T:ÚÕÕÕIr×[;;»§Ùy’‚H~£ÖZ©¹v½£âdÑžç “<ŽÚ…¢(úD¡P8ÑÌ\I õ3ÀöíÛÛHÆê~WÇu݃H×UÕ®Šw€f“ÍfàKkص·»»;;==ýr£3%‰T Ïç "êhq{WW×åR©t´a¡F*r¹Ü†L&sÀ×ÔòWa~»X,Î5¨_bHÝ Ïç?ë8ÎïÜÝÀ¶ÃŽã|yÓ¦Mç/^¼8ÚÀ¾±“Š`Ë–-mmmûÇÙ/"Û›<Ü€'Ã0|6 3Âz “Ïçû¢(ºä^¸qµMD¤$skÈð_Ïxäß&&&Æ„kè+± àûþÍŽã ­Ü.""²dWEºIÞà#> ½Î¡§]×½CDEÑ«ºëì· "£$ψÈYÓŽã̈H‰ä;$ß3[DQtÊóVãÖEìïsIèékÝ/" îé<€ÏŸß÷÷añÙ\ÏUÁÛIZÊ+"ï~_º½’_ð›:Ƭ›Ô/­DDÞ&¹×ó×¥mƘ¿ˆÈ=¦bŒ ÚøÉ¯®¼#‚c™Lf€7bÈZ¸ àÐÜÜܧŒ1æZEcccÅ0 wxÀ¥V…‹ ¼àVcÌw§¦¦f«‹Å9cÌc"2 à¥æÇ‹—´ ‰ÈÜfŒÙkŒ9»ÚAœ1ÆÜ`XDžÆâ,’:bÐ@ÊŽx6“É<366VlDScÌI_ëïï4 Ã/Ø`7R²Šºn‘’o‘‘ööö#£££o7k¼ŠPܶmÛöÜ)";DäãµüÇq‰]€r¹|ä¹’\0+"ó•”YS"Rt§ "“ALbñYßr*¢ý¶ò®ïû=${¢(ê­¬,Þ`ce1+[¹}ÅâUEZ›ÜbYÁÿ+‰¼íg¢IEND®B`‚olive-continuous/app/ui/style/olive-light/png/beam.16.png000066400000000000000000000005621370472574300236220ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs<<ê.¨tEXtSoftwarewww.inkscape.org›î<ïIDAT8½“=NÃ@…¿g»p—tT‘ÇG@T¤äáˆZzÚÐÁ1¸A áGÐp[9†íЏHLX $xÍNñéÍ›ÝY1™½Hzjšæ&Ïsu]wéîs€ªªŽ·ùlhàîWI’ÌÜ}‘eÙ{Û¶¯’îBë!“ÌìÑÌbЗÛa€±.1€0fŒ¿6(Ëò˜“¾Þ«oGp÷[`Ñ×SàôÇñÌlifËówwðoc{0Ú f àÍFª?÷B;*ŠâDҌͳõÌpïî뺮WÑ’®àîÏ!„swWš¦’Î$%ÀÎwþp!GXÉ‚ÖIEND®B`‚olive-continuous/app/ui/style/olive-light/png/beam.32.png000066400000000000000000000012101370472574300236070ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsyy8µˆtEXtSoftwarewww.inkscape.org›î<IDATX…í—1kQ…¿óÖ€M`QÜhV™7!‚"(’”‚ÁB»ˆ6ZÇF±U5´2âo°j¥(BÊ™'k¢Å¦Ñ̻٠ë2ÙU„=Õ½3wÎûæNqçŠ yïïãÀ*°bf‹’^åyþ½§noŒqÊ97öËyž_ßÊOp8V&’¾&Ir;„ð MÓkf6ëœkô<»Te^ `fO€TR“õ7; ŒIz$ÉI@f6Ó)ÿ¼e½SŸ¬Ê_U½j6›ûGFFîWznÍ­­­Í¶Z­Õ~üú(å½\ô<˲‹ƒø¸A€Ç]ñü &Ä?•qQ­¨ÕjÅfñŽü- †Û™¿É{Ð9w¼(бÎ\ Æ8=11q4Æø1Ïó/ÿ@Ò¹ã³òðε…#’. ýøíú'x¤iš˜Y ÉgYñÙõ †C€ÿ (ŠÚfñŽHJ6Lœ;²W»ÒÞaÛê»u“““FGGïw&_©õz}¼Ñh¼i·Ûßúñ«FI’Ü`}5; Œ›Ù)IåŸ73IºÜÉï€e3kYáîVþ•ÿ’fØd95³[!„¹ä{I71àLWÝðgÀKà°*i%Ƹ(éuac=!<ôÞ?5³³Î¹i3+×ó•*ó_Ô¸ª9RËÕ IEND®B`‚olive-continuous/app/ui/style/olive-light/png/beam.64.png000066400000000000000000000021611370472574300236220ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsòò”µ-‰tEXtSoftwarewww.inkscape.org›î<îIDATxœí›ÁkUÇ?¿· Öa…6˜tß$ô`‹RD¬­(Fc¼hO^¼hÁCð–[=xQ{RKÿÁè)؃Öbz±ôâÎl‚”bM·HC„Ìûzèn»M7Mèfç Ïe™ßû½÷¾ûÝ7oØ™ù}R¯×ŸrÎ=Ø9!¬8çþ !,5›Í ýŽßžcÄÌöJÚåœêšëÏf³ùc?cWûgf3’Žt# 3Ã{ø8çù—KKKlẻ‰‰‡ò²Î™¥iš~1hm…<ô&0µIÚM†HZnÀ] ”Ä›"Œ\'I’C’ÎÜ$Äìpš¦·Ü,4wý ( ˆ- 6¥±Ħ4 ¶€Ø”ěҀØbS[@lJb ˆMi@l±) ˆ1©¤[‰A¬0Ò#¶»pÄ3àðú€™Š!¤ð»ÂÞûÐàZ=Q7Ëιñ¢ßޱ>áÖ/0,飢ÅY/PñÞÞ¾MÎãµZm¸Õj}KA5EœUïýËÀ1àÑ-öùÕÌfÓ4Ö'm›‹¦€ÕjuHÒð0°_ÒKÀðÝ¿kkèY4,KšwÎ~7³ kkk+À*lOÑTßÇ%}ꜻ^9–K}Î9ç^ !p x²Gΰ™½Ñ©•„s7¶-IsÀkwªâl‚ø x®Ñh\iW< œ ÀZ¡E `8˜eÙ;Y–­v²,[Ͳ쨤ƒ\[ …1è7Dþ~’tZÒW‹‹‹Û%7›ÍsÀôØØØDµZ}UÒóÀ6.¼ì›¾7Áõåó’þqÎ]’´ÔïÕÁ{¿Ç97BØef÷uâÛQ>ÿͱ[¤@7EœIEND®B`‚olive-continuous/app/ui/style/olive-light/png/box.128.png000066400000000000000000000025031370472574300235670ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(aIDATxœíܱjGÇñÿ8AÄì®ÃÁq`p±y“G¸pçgHHç×pç(}ü®Œ^à ƒA\á4jTœøˆ'E6»Þ»™ÝÿìŒæû)-fçÇÜ߻ҥ¿(…ñ]°ÙlžXk‘­µß‹ÈCÏKÜcþ‘wƘ?®®®ÞûfPÎ×—zÞIùœ  iš³ÛÛÛ_EäÜZûÀ3äðæÆ|‘‹ªª^n·ÛOS®¥‘¯/õ¼!ùœ  iš³ý~ÿJDžN xÂe]×/B5B¾¾Ôó:çûÆåjUUý&"?MŽuÜêp8<º¹¹y²8B¾¾Ôó:罴Ϩ?µn«_‚óÙóÌ÷+__êy]ó†°Öª=S{û<°Öž¬‹’o`ߤóºæs 빺WÌ|sìÔyºÜVód²WÌ|sìÚyºÜ¾›!‹+iÍ\RÏ;úÙEvžbŒùcÍ\rË;$©‘ËHkæ’[Þ¯$Sí-ë.ÚXT¹å=&™‘‹>{»Æûƒ˜Any¥R—UU½ ]Ü®ykÍ-ïQ‹@{}=¥¯."²Ýn?ÕuýÂóZóöš[^£­àõzýaæ=S½Ú—[ÞŽÝn÷øÔ×Õ `,NÓ>ÿT¾ÀB(€ÂQ…s)€» ן²ÿR=ÿјһN­ï#íów¹LiX$ÑìÈœêù»Ü‚zס½rtiŸÿhLè]õÊÑ¥}þN?ô®'õÊÑ¥yþN¿~}}ý÷jµzs8c~#Äö¶ó{]׿Lýà üOóüçøÓ0Ñì•£‹ó>x”™¹ÏÖ9sÎÑC—ÖùkÍ œ4G]šç¯5'pÒ=tiž¿ÚœÀÐ9zèÒ>µ9¡sôÐ¥}þÚs—œáw_¨ž¿êœÀ%gøÝÚç¯='0æŒÁûJõüùëàÂQ…£ GŽ(P8  p@á(€ÂQ…£ GŽ(P8  pÌ N³‚KƬ`0+¸dÌ .³‚Á¬àÒ1+_pþÀ/ƒ2ìàB1+¸`Ì .³‚ ƬàÂ1+Ì .³‚Á¬`è¡ Gî[í Öëõ‡Þ?Ýi¾;è•?œxÉÜòzm |€óm>ã»—^ùT¹åÙívO}}ÑG@Û¬x¾ßï_5MszÿzåÖÚ皇™[^©|ð´ýߤ]³é”[Þ£R)‘óÍfóÄwQ»f‰–sny%S¡ïB{åSå–÷˜d‚´Bn‹KÞJsËû•¤ ¤ï½äû†ÜòÑžèËFZ3—Ôó.;'ÐWÈ^KÎ"L=o s}…ìµä,ÂÔó.7'ÐWè\ÁXùöM:o s}ÍŒ˜¯/õ¼‹Î ô5i®`„|}©ç]fN ¯¹æ jåëK=ïRs}__æöz5õ¼ªùÀýñ OT®8TÏ…IEND®B`‚olive-continuous/app/ui/style/olive-light/png/box.16.png000066400000000000000000000006041370472574300235030ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¢IDAT8­“± 1 E¿£ Æðïié1X‚2\{¢õ¡‰¥ !]|ð+Ëyß±¾dàG ,µÖ#€—ˆ\ÌìÑõ "³™Ižj­w;ï%p0¢ª.ªºŒš{>·¯‘ߣüºH’e Ÿxˆ=Ÿ"Æoòçˆ)ʯ‹äDrÚÂ{ˆ·övÐó¹{PÕçè-ø°äÀèú®¿ùÂN6*ölIEND®B`‚olive-continuous/app/ui/style/olive-light/png/box.32.png000066400000000000000000000006601370472574300235030ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÎIDATX…í—1ƒ0 EQÏ@Ç,= ç*S{®ž¤‹Çö ÈA6Vh,†úM(ùúXz"À¿sšRJ€€ží܈èiäj²E®cw¡´Ïë0r5Ù"Ǹ¥^,ïê¶Rø׸Zóú/Ùþ ¼ø]áªÐúù ¼•çVˆý|€ù¸¤£lw°É„ÀÊh-Ðú%JFkد™ÐÊb¿eBwb€Pqp8¡âÃU|ÖÒùÎã^P`™Ðã^ àa?Mr<îa‚ ‹iduL¤­IEND®B`‚olive-continuous/app/ui/style/olive-light/png/box.64.png000066400000000000000000000012751370472574300235130ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÛIDATxœí›ANÃ0EÿbÝ!V·€cô ,rŒ… T,ØÀ-Pn@$ºba6A*ÍÄθuÓÿ–¶ççw¤8ê— BŽÑ«ªºP‹ÈƒsîB-Ù8ç^¬š¦ùð=dŒ^*Ý^¯è€+ß÷h,‡ÌFè¥ÒUõN”…µAÝÚÚ3oÕK¥«êõ "÷Ñ`MŒ^*]­¦×çÜ¥U¸´ß¦½1Âo1s¹t·9DZ+Ïüª[3Ý?D7@D6ÖðìÔÐÍ-¬»š,ºƒÏÛ¨ªêÝWÐ4Í]ìæÀêÿ {@ÉhŸÁ¯¡Å¾¹¹`õ¯}“ï¼)±ú×^¡Ý5´+Ï“ÿÓÞª¶ý\,Ï®EäFD¾¼x ý9™¥û'„2%ÁLÆftsÁâß’ z3º¹`õoÉCÝ\0ù7e‚ûä{SaõoÊKÈ ­þ™ä66 ·Ü°¹ ä† Ø`*ÌT˜©pÑ©jéþ !„L Sáb¦ÂÊ8Sa¦ÂL…ÿgÖ‚ßsx¥Üa>(©PÊ}iJ–r_@å {@)÷4L™`éì QÊ}}3Á!J¹/— 8×Ôº3úÁ¬m¬^*ݱz„ã䜪e1«ØIEND®B`‚olive-continuous/app/ui/style/olive-light/png/clock.128.png000066400000000000000000000113111370472574300240670ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(çIDATxœíp\ÕuÇ¿çîJØ–íÕ³-,í¾÷VjéD›ß6VPè4`~ãðk¦¸SB¦„¤Z2BLÒIph)™¥$CŠâL€1fè@ÀiC¬B 1‰[h$í{»’콕%«Ñî{§ì3±½»ÒîÞûvW«ýü£™ÝwÏ9zïì½÷Ý{î9@“&Mš4iÒd.Bµ6 zzzNÊf³&3›Lq"ê`æ6ó,°Øÿ GŒù'‰h‚™HÑ+'~Sýÿ&XÂâñøïd³ÙÕD´šˆz,gf¡Ryö1ó/™¹ßó¼þááá•:jÁ¬t€ÎÎÎ¥---—X `53/«‘)‰¨@&“y}ddäP쨘Yã½½½­ããã¸ÀeÂ56é8ˆÈÐÏÌ/º®ûêðððd­m*…ºwÓ4Wzž·ÀåÈÛ³1¯!¾ŸH$Þ¯µ1ÓQ·FÏBÜà’ZÛ"ífæ'mÛ~£Ö¶¢î ‹]HD_pf­mQ ½ËÌOضý&®µ=G©ÐuýL"z€™O¯µ-ó "ÚdYÖÏkmPÇ#®ëÞED·ª~u«cÀK®ë><<<üq- ÕP7éº~-€§¬A8c!¿'„¸AÓ´)ÇqÞG†…šÜôh4º< =ÊÌg×B½ADï0óݶmﯶîª÷º®_BDψW[wÓ `¦i¶ã8U]]¬¦„ Ãø=ˆÜz|“ã9 ÀgÚÛÛÛ{zzví߿߫†Òª º®Ÿ àq+«¡¯xˆ¾`YÖ¯ƒV¸D£Ñn!Äwœ´®ã€â¶D"ñaJLÓ\ àYAêiPÚ˜ym$ÙN§›Ö†ÑÇÌÿ„÷þæL‚™ý¿ !&„G˜yLÓ´#0::º€ˆ»®Ûæy^“ˆ äâºÌ\«WæI"ºÓ²¬!<ˆÅbWÑ×QÝ;ð!r;r»Z[[ßS!¸§§gñÔÔÔ¹D´¹-èÓPÝWè,3ß“L&_V-Xù?¡ëúž…*=|"aæ—C¡ÐóCCCÉjè4 ãW3óõÈEUƒ,ÝaYÖN•B•:€®ëg"7æÝígl'¢çj½¦îÿÏ7ÑUU&&‰èV•ÿ³2èêêê …BßЮJf2vÑã–eYê)›®®®ÎP(´ÀzóTåxž·>•J ª¦Äü÷ümNQ!¯LD?…BH‡º»»Ov]w#3_‡àæ û‰hŠuiûúú–emaæ³deáf~ ™LîH~ ø-››0ÁžeË–}v÷îÝ!Òc3߇\¸–j¦|ݶí¿N§Ó#È”±±±}étúùH$r„ˆÎ‡ú5—S&''Orç-!R=€?ãJVΉÑ€/1Á3Mó4fþ,€ ˜y¹¯o€ŸÑ÷‚Xy‹F£§ !S,š™ùóÉdòõJTüàüq;Oúˆè5!Ä}CCCi•r{{{['&&þÀÅOüØÿ­mmmíÝ»wJ¥þŽŽŽ…mmm1ó*åH»®{ÕððpE½d¥Ý’Ð4íi(ÞÒ%¢Ç,˺ttTé ?¤ü䆪霞œ155uvWW×ËtUÙpäÈ‘)Çq^Õ4M8O•\ó„§§ÓéVÒ¸"0 ãf¾¥’¶E`"zز¬'Êü„¶¶¶ûQÞ<¥+“É´;޳Sµ-ŽãôG"‘…¿uCgg$Ù—N§ÿ«Ü†e‹Å4"z êºþ €¶m¿¢HÞqøcþörã ‰È#¢+ƒÚÓuýr›´(9JD—Y–å”Ó¨ì L!Ä_AÑÃ÷ÇÜ{‚zøÀÌEÇüÚ f¾1›À¶íW˜ù.ÓJ3o,·QY7Æ4Í3üI¹J¦áaÛ¶w(”WˆÕ5j;#Édò5fÞ¤J­7 cU9mÊqbæU…nû¾ï¨5ÌÜU‹¶¥bÛö"ú¦ Y~¯õ·å´)ùaêºÞ§ðÐÆ«–e=¦HÖLȬ˹¦ÿ –e= à߉[išæ§K½¸d ¢;*³'ä¼yó¾¬HVÃÐÒÒòe"V!Ëó¼»J½¶$Ðu}¢þ,Ýýá‡V «¡#¢»{+’åÌx<~n)–Ú|^˜cy¤Öû÷õL"‘xŸˆþA…,Ïóþ¢”ëft?°ói‹€lÛþ¶9 aÿàdå0óEñx|ÅL×ÍèžçÝ k B<@ÙÒj£²sçάçy÷CÁYAÏó®Ÿéši §§ç$Ÿ‘5„ˆ~H$Þ–•3WH¥R?ð¢¬f^ÛÛÛÛ:Ý5Ó:@&“¹òiY¦B¡Ð£’2æD´¹˜"OwÁLCÀ5’€ˆ¶Õ{W=â‡{½ @Դϰ¨tvv.Pò‚B²™LæŸ%eÌYÂáð²{Ì܋Ŵbßu?Ÿllÿö‘‘%‹s‘ÁÁÁ3Ëi!¢¢‰¶¦¤7Bˆè9YsfÞ¢@Ìšb_sbæó%•Z–eí‘”1çñ£¡’bŠ®ãt€x<Þù½/ ŽÒ¡Ífˆh»¤ˆ“c±XÁð½‚Ífe»Îf³/IÊhâ#„x’?&ÿ`k¾ì"Ë:ÀÍÉŸ:†††’D${¬à3-æ²ûþý’í›ä³K²}o¡óÀ0ŒyOç"kl“|¤~TDÔé/íG¡À û""·¥¥åg•¶oR˜p8¼KfQˆ™CžçåLÊ{Ð~™ª2s4ù-þ=µddxž—÷&Ph¥Oê´3É´¯7t]?1qãdÐg §! [¢}Þ»PW/Û4”`>3w3ó­Ì¼Ý0ŒM3m¹*DêÞ2sÞ;ψH¶þN£;À'øaØ7?S 'ðïÇ]h Û˜ñx¼®&‚€aí^³Ùl^dqž„B!K6ö,›ÍžSiû&E9_6VsÞ¼y©?Ï800ðRuêœ+h’OÑó}¥ÀÌ#þ³=Ž‚ÅÌ¿”QIc›Döžî-ôa1}g>­³³3ð,›sÓ4õBñ|eRð¬FA𕈠f,"º(‰ ¥Óé_©7ÛÐuý "ú*Ô ‡[mÛ.ëT%Õÿ èÚr9øAŽø¥Ô纮_à…µ˜?&¢o”Û®ì…ÇqþoÉ’%ifþÃrÛNc÷··O¤Óé÷ɬkb±Ø-Bˆ¯B¾"˱|Ŷí²ï_E+sŽãü·¦i«tVÒ¾àÓš¦ ÇqdQêÒu}#Ý µoAoÛ¶]ÑÙÄJ—f¹½½ý-ä¾Ê=Z5çišö©%K–üÇèèh^ól¦££caGGÇfªI9®ën«hÓ®âµyÇqÆ5MûrË–*½9àÊH$òót:ýk…rkF<_‡¿ @EîcafþR*•ª¸4ÔæŒã8–¦imÎ’‘S€E®Õ4-»jÕª=–ežà!úúúÂn÷fÞNDÛ,˲ª¡3.…BW2ó:ÈÚ(•,}Îß”SF cT,[KD@íJ׌Ñ€]D´‹™ß¶,ËQ!×0Œv":™×XÃÌ=*ä–A–™ïM&“²$ólOÞ0Œ?`æÇðpP ×2\‹„çy fN!&Âáð¸ëº‡æ5>tèP[(Z”Ífzž×FD¦ŸÉD./T!-I&‰èNÕ¿ü£”á‡8=ÍÌK‚ÔÓÀ8Ìü9¿~p •F»C¡Ð·ýŒ\MJ„ˆF\×Ý j¶_ŒÀ»µT*5HDë̉>ÑîP(´.è‡T)Nßqœ‰t:ýCMÓ˜ˆÎE3° àYÓ4ÿò½÷Þ“*S*U±XìB!Äff–­NÖhŒѽ–eí¬¦ÒªŸÔI§Ó©H$²À ¨‹'˜í¼MDjY–lr®²©eWLº®_CD÷¼|\Ï8Dô¸eYϨɎgMÏê¥Óé–,Y²™çÑ Ì6@n¬‰™ÿܶí~Ô°ÔLÝLÆLÓ\éyÞý=¯Ð!ĦD"ñ~­ êÈŽFÏBÜà‚ZÛ¢"ÚÍÌOÚ¶ý&꨸TÝ9ÀQ|G¸ÀŨc;gâ˜ÿF­m)DÝߨx<¾ÂuÝu.0[•:D´ÃuÝm©Tªê3ûr¨{8JoooëøøøEÈE"_Š*m7—ŠŸa½Ÿ™_t]÷ÕááájÖ+¬˜YãÇbF»çy—úYÉ/P«$T!—OqýHÕös5™•p"±X,NDk˨ý)"êTãG! —u{3÷'“ɼ,³†p€éíímœœ4<Ï‹#·—'¢“,`æÈÕÐ]„ßÖÒpÀ8ñ<ïˆârñ !ÄÐüùóíj†jÒ¤I“&Mš4©ÿu•r%‚߈IEND®B`‚olive-continuous/app/ui/style/olive-light/png/clock.16.png000066400000000000000000000013251370472574300240070ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(óIDAT8uR»nQœ¹¾YY²P¤ÐÙ«ìf8’;BBE—@HT„"€òÐà.U¨Mò|ä!B¬ønäˆDâ"Ž÷Ev#ãÇéî=3s^CL‰$Iæ½÷k’ê$à—µv¿ÓéüÇrôÑh4îZk·<`ǰC{’ÞýžH’ä¾÷þ½¤:€!ÉCI?ä«’*$Ï1›§§§?À”•K2ɯƘuçÜ+’_H~vÎmX'y,©á½ß ÃpáVÀZ»U’kµÚF·ÛÍ@Ò¶¤mpιZ­ö’ä7IJ¥ò˜$É|žçG`ŒY/ÉEQ²,»7ò·Dò“$_­VWŒ÷~ €%y8JžY–u%˜ kFRXä¾Ï"EQtÇñÓÛÍ“'འ_dx¿EDs:ÇÌMFõ Rª¥¢D´ ·EdRö@ÌÝ£ƒ ض°Ž„- aæ‰vv7  ¢Õjuý ðQR ^¯¯Æ¨¡¦ÄÎè0 ;ùL·Ûž‰¨Õj£TÓ€ˆ´ÌØ4Íìëx¶ä:Öü.˜¦?+Ö€XàFñöRo¼çW:0 0 ÃÙYhy ìÔÀC=™™Ït:p§‘ ½MDšÂ0œ%Oær¹£ÜZày^7€–I)¥šJ¥Ò}"zªÅ{*•ÊÔq¨ÕjSº£6=)‹¿7 •R·cý.X–5Š#ÂuÝ1tNDnAßÀÌwè{Õdæ¯\×MüÒuÇq†”R_8qD´œN§g›ºÑƒïû"šFë™0¤”º722òÒAÅ]בï±ûB2݀إ´\.ç3™Ìs^ÖèDäÍL&ó|ÿÃmìÏ󺻺º®ŠÈ4bwC"ºéûþw-\Âì8Îg"òFBl À<3Ï×ëõ¿Ã0\Ã0†S©Ô‹J© Ð NÿÁ÷ý÷°ß¥4âǹ,"×öÈé`&‚Oââ@ûÿ”Ëåßz{{Ç!ÿ ˆh™™ß÷} ÿ@³ó<ïDµZ=ÇÌ—D¤¯Cá'"r+NÏêw(8›ÍŽ3sôsÚ`¸[‘ÇDô@)µÐ8dv-÷ÿÿ,•M€V~ÁIEND®B`‚olive-continuous/app/ui/style/olive-light/png/clock.64.png000066400000000000000000000046001370472574300240110ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(žIDATxœí›ml[WÇÿÏInçÖµrƒm"%©›†fEÆú2`£EhÐQuÓ´ „! :T ª‰ ±R`â›6Þ&¤EšÔ~Z‘ØXµLZÕjï}aÀZPIkû:©«Ð9É]Hb|íóð!7–SÛ÷Üë·Ñß'ûœçyÎÿ<>¾÷ž— \çÿjuýýý+5MÛÈÌ71ó €A" 3s@Ð1›#¢YfÎHQ‚ˆÎÚ¶}zbbb¡•úZ’€¡¡¡h¡PØ`3ß  ³ÎP6ýÀ‹ù|þ¹L&óNóT.ÒÔ ÜÊÌ;‰h 3w436™ù„â©d2y²iq›$‚ˆ¾ËÌ·4#ž ":ÃÌO˜¦ùzñq^»víû …ÂCîiTH°ß4ÍËõ¨{˜Æb±»Œøp½1š€àóº®[–5VOß#`hhèÛ¶à‹õ4Ø*ˆèP0|äܹsy_~~Œ{{{W­X±âIf¾ÝŸ¼¶ñf ØuþüùY¯žÐÛÛÑ4mÀz¿ªˆhž™OÑIfcæTggg6‹Í@:Ú¶Bĉh3o&¢Ì¼ªŽ¶þnÛö—.]Êz²÷b4<<Êår‡á¯ó à8 ƒÇüMç¯öi÷ØêU+°˜„¹¹¹/]¹råßJ[BFlö*ÀÑŽŽŽß$‰úð©‰aÃRÊÝîôáöúêÕ«¿®J¼ò. …Øæ±Ñ€Ý¦iœžžö4½033“µ,ëhWW×"º€îÁmmÛúÌÌÌq7#×Ç·ø•G/}^.@ñxܰ—ˆnf~À£¦i&U¾===Á@ ðSw{%„ø^2™|¶V}͆ÑẠ̼̃ZÑÑc©Têw^9@×UU€û½$Á‰óM{ þÏvvvn»xñ⿪UŠZ^RÊzé<€ý^;ï°•‡S¶×kÓ4ŸðcGƒ¡B¡ðƒZ•U‹Ån°]%‚ˆ3Mó°Êî*ŸÛê©«†iš‡<îÁô.Ã0ª^Ä«&@ñmUD"zÞç/pUF\ÎHø£ÂŒ¤”{ªUT$À™ÒnPLåóù}5¶œ\.÷0Sa¶iÍš5›®.¬H3ïôÐæÃ™LfÞ£¾–3999ÇÌûUvBˆ+ÊÊ¿ôööFˆh‹"ÎQÓ4_ó©±å¤ÓéW¼¨0ÛÒ××./X–MÓîV¬ä°â·ujl¿†û]¡SÓ´åË@DŸU4p<™Lž¯S\Ë1Mó^v³aæeOµ¥ô÷÷¯dæ¸9Ñ‘†¶•Æö÷÷¯\úRJ€¦ihµ¼ˆh. k\_k!¢—¸-¥kBˆÒ]®”)å‡Ü3ó)¿SÚ÷‚T*•#¢3n6Bˆ›JŸËÊÝœˆèTƒÚÚÉn•Î €å†Â©®EG¿Äãñ Àâ_ÎÏ,±)å‘ë©”€Ò ¢ˆ"®/ÂÌA,®C<ãÌ ýø¦ÜêËûZJ€Ó ›Ó´MÄ×,ˆhÊ­¾¼¯å×ׄÃá9?"š‰ßYb(Ri­š€¶@DÊ…ÊvRž×¬e³Y×âf~µÕ>³³³*­¥¾–_]ÀÌÝ~D¸ð(—¿¼b9>žaæ÷¹Õ—÷µü"¨Ú{÷u%®…sK»À¨[ÒºQøX',óUÝÒ¯,}.H¨9 ¢uXÜm§CßjF¬j!>À\{RHD‰’mY¹k–™¹b5åæVE}©¯¥!Þvó ¢MCCC74(¬å TKzRʳKŸK °mû4€š“f^åìÕ]ÓH)?`¥‹‰-¥,M–J ˜˜˜X ¢¿*âß× ¾vp¯¢þ­ò“gW?©ÖÔ¶†1\—¬6Ç×/m·ÕBñ²ïå_òùüsDTtñ'g—öš„ˆ¾÷­²B>Ÿ¾¼`Y2™Ì;Ì|BÑÎÎÎÑ5…a[˜ù7":qõÁ‰Š¹€â)UcDô“žžž¦<7ƒááá”ò€Ê®X,Vô­"Édò$VÄŠŸûÐØRr¹ÜkfoŽW¬jU 2ó/=´»ÝÙ¢~O‰Åb»¡>+ÀRÊ'ªUTݱ,k¢»»{À:Eàéº>eY–ëCT«ˆÅb_!¢š[ße<›N§GªUÔÜ ‡Ã–R~€ÛÓø”®ëÒ²¬¶.šÆb±Ý;ÿ®¦i»¦¦¦ªîeÖLÀôôôœ®ëi¨Ï €ëº~c4}yjjê?DÕMOOO0þÀW½ØÑ÷‰ÄßjÕ»’²,ëBwwwގî•R~®««ë¢eYi/âübÆ–ŽŽŽƒŸß ßC›]Dt®ë7꺞°,«)çûãñøúîîîŸ1óT?^S½‰Dº|ù²tµó,®ƒ‡™ùƒ^ì‹•Gˆè¥T*•óá‹€”ò"ºÀ'½j":»°°ðåÉÉIåB®ç }}}aMÓF|&a‰f>-„8)¥cædGGGvi¥9›Í‹Åb˜ˆ…C–N©¸ÍêªBDçlÛþZSÊ.ñ?pXúùùù]^ŽÈ.ákY<“É̃ÁoÑ!ÿÚZ 3?‰DðÓy 7FœS¤Õ£I¼KDûR©Ôh=Îu¿1bYÖX4ýƒ”2`mx¯ Ljhg*•R-äÔ¤)¢ ÃØÌÌ{Ú¸pzRJùxµÉ_šú« n*‹ÑÖf¿6 @D'ŠÅâÁññqÕlÕ3-¶Î-s‡s éf+ê •ð–bÔ¶í?MLL¸îúÖC[^BlpŽ¥̼@‹ÏÒ«³fd‰è€””òm!Ä¿P×¹Ž?þ ÐdG5êï¨{IEND®B`‚olive-continuous/app/ui/style/olive-light/png/diamond.128.png000066400000000000000000000031531370472574300244140ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‰IDATxœíÝ;U‡ñç˜%Jçq‚ñüüü†1æ]à kí«Æ˜§ÖÚsàp:›Íî-—Ë'‰­Á¨ëú}kí-àõ·nF£ÑÕju/ƹR÷BêDhT×õMkíÀxû+k퇓ÉärÓ4ø|I+Àh:Þ>9âkç“ÉdÖ4Í} FP27þG=þ«¥#(€ñ]E#(€Ïñ]Å"( @ˆñ]E"( @Èñ]Å!(@Œñ]E!(@Ìñ]Å È@Šñ]E È@Êñ]Ù#È€„ñ]Y#È€¤ñ]Ù"È €Äñ]Y"È €äñ]Ù!È@㻲B€œÆweƒ@:€Çwe@2€œÇw‰G @ ã»D# ¤ñ]bHPâø.‘$(y|—8R a|—( i|—© q|—) y|Wr©èøÏKŠ ÿ¿%C€Žß]1èø»‹Ž ÿ¢"ˆ@Ç?¼hBÐñ/ ‚tüþG €Žï¯ BÐñý o:~¸‚ ð @ÇŸw¾èøñòŠÀ?~Þô ã§Ë ‚>tüôõFp,_N½@Ç—×Ñ ãËí(‡Ðñåw0‚}èøùt‚}Œ¦ÓétüœºZUÕ•¶mOÙ`'€º®?ã¸çíki»VUÕ¥¶ml»i+€º®ß³Ö~é÷\ZÄæãñøqÛ¶¿uÝ0꺰X,N.Þ±£å›1ÆÜZ,']7t~°Ö~|äXZ̪¦i~nÛö—ÿ»Øù¸è@Zü:·ÜàÑdŒy»ëÚ6/8‹–¦—».t0Æ$xæ­Î-;Xkÿ s-At]Øö#àQ€ƒh ²Övn¹ À΢%ÈÓ¹e'€Ùlö° r"-fëõz}¿ëb'€årùd4Ý s&-RÖZ{xÚuÃÖß4Móëd2¹ Ì}ŸL‹Ò7gggßm»aço›¦yXUÕàš·ci1ú~³Ù|Mß_¶mÛÓªª^Cd‘1æîf³¹ üµëÞ}ÿ"Hd’1æîz½þ”-?÷ÿÙ!¨„wèøpø_+¡3>÷¹E ¬cLJã?¤„Ôg|è÷Ù@E¸¾ãCÿO+‚Dùü<@DÎ×øàï !Š R>Ç¿ÏRó=>øJ˜"Tˆñ!ÌsçBឪ<r|û¬`EгÐãCø§…+‚#‹1>Äy_€"8°XãC¼7†(‚=‹9>Ä}g"ØQìñ!þ[ÃAG)Ƈ4ï Tÿ*ÕøîÍ¡Šà¢”ãCÚwAêñ!ýÛË@Âø ”ñAIãƒ0ÒÆY `Çy @RÇ™  ’ǹ ÒÇÙ c9Œò@†rò!Èi|Èd€ ·ñ!/ AŽãC~@ ‚\LJ<€ 9ùrò ”0>ä (e|(DDPÒøPˆ€ ´ñ¡,A‰ãCy ‚RLJ2€G%åJÊÏ\âÙK/̾_|»Ùl¾bG®ç\éà‚ãñø±1æM ÚqÿÊZûùÅ›6Šwâ¾ÿ#Šh±Xœ¬V«ÀucÌ[À+—~·ÖþdŒ9½xÁR±ßò5MÓ4MÓ4Mz­±”è{&ýIEND®B`‚olive-continuous/app/ui/style/olive-light/png/diamond.16.png000066400000000000000000000007121370472574300243260ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(èIDAT8•‘ANÃ0E¿ÇH,eÕV²Æ¾H¥ŠEËQ*PCSàH°#ñ–ɲªÈ° Tj»Î_zþ{Òx€DŒ13fž¦:0ó‚ˆvž™yëéУsn."Onܸ/Šâ£ëºÏ«çܼïûí>õ”R«DgÀI‰Î„£=J”1fvüíø<{¥Ô‘Œ¡¦i¾ˆh `?‚;ˆÈ¦®ëo mÛ6UU½‰È w¿?zï_€³+dJð@!¹€/ I þ%eY¾Xøðཬµvb­¤:¿J>ŒAón¹ÅIEND®B`‚olive-continuous/app/ui/style/olive-light/png/diamond.32.png000066400000000000000000000011521370472574300243230ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ˆIDATX…Õ×AjÂ@àÿOYH½À¼HWÖöl-í t׋ÌJ îšf1(¾.ZÅjgb’ÒY&3ó dÞ ðǃU‡ÃÞn·€RjaŒI[$I2‘gÑ@Ò’œ-—Ë÷н¢ÐZ뾈<Â@Dô~¿M’dº_Ð h­ûNçEDúSÖQMCNÂà^ áF\TB”n÷Fj÷Bäj ¿Š¸4^Šøh0¼q´ž‹ ŒF£;çÜüôzmr´J©‰1&À97i+ø®ι B1ªÓq(¥æ$m[É$m–e‹#À“n·Û)ÉU ùk’³Ífó ñáiš¦Ýn÷-Žã{½¦ÂÏ?ÃøômÈ܋(>ŸÕ¢ð*¾4€(-F¹€WËq! „WCR ¸áÝ’]T@5¥^€Dp[î ð@‡Š‘µvEòñ´v´UÂ~Nzˆ1dY¶8Üíÿn|O¦¤,yXIEND®B`‚olive-continuous/app/ui/style/olive-light/png/diamond.64.png000066400000000000000000000016251370472574300243350ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(³IDATxœí›9nA@ß7P·Óé¾À²oA`î qƒ#$ß!2"pî©tÅMâoÍ´gé¥ê÷¼¬iê=ÉòL-°gÏôñ¡³Ù왈œs)˲ü œ;ç¾YÅ:€äyþº,ËWkŠœ-‹O@i5 {VH–eo—[Þ9I’äÈ{ÿÝhLfTþywç–,4‘WÌ"ÄÐF^1‰3@y%z„XBÈ+Q#ÄR^‰!t€òJ”!Ä”W‚GÀB^ !DKy%X„®úW‚Dè Oy¥s„¶† ¯tŠÐ&Àä•Öš¢¼Ò*B“C–WG¨` òJ£uŒI^©aW€1Ê+µ"l 0fyeg„M¦ ¯l°.À”ä•îÈóü Û§®ÇÊp²î¹ˆœÝL]OòØp»îpEä/ð øP]´Ø³gOtþ<‡ô$pbôIEND®B`‚olive-continuous/app/ui/style/olive-light/png/dirup.128.png000066400000000000000000000031541370472574300241250ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ŠIDATxœíÝÏoeÇñï÷[e•LÁ`w:» ’4{ ÑŠxò&œ4!!HâAbù74œ<›xH5GxRˆ‡¦ñG²ÛíENa©2_ô\mxf÷™}~}^G²óð¤ß÷ÌÝ%C¡âªt:éÁ`p\DÞ#¢}D´Íþ¶Æ²ND?‹È•íÛ·³¼¼üÀõ†|V)€v»ýJY–§‰h¾¦ýضÂÌ'{½Þï®7â+eúÂN§3Øð‰ˆæEäbžç¯ºÞˆ¯Œ Ç)¬ák¹Rê"øÆl¾ç‡ lÁ8f~­ÎL@žeÙÅÙÙÙ¦ëø¤Ê QçF&ADf§¦¦. ‚'Œˆ"ø·ä BOK2"D %" J<"D|DiG€6¥xJŠ €!©E`üqpQ¿Õ¹Ù:ý¢”ºÒh4–ª~ÿÄeE)µØívo›€·€¸Ì—eyºÓéL›€â3÷îÝc¦/Fbæ÷M_‹"ÄÌûL_›tÌ|Ÿ™ï»Þ‡mU¾»‘rëDtRD>bæë͸’jë̼Øëõ~X]]½)"'R Åþ¾þƒ”#H-€ÿ _K5‚”ØrøZФÀ3‡¯¥A _K)‚ب<|-•b`äák)Dkc_‹=‚°6|-æb ÀúðµX#ˆ)€Ú†¯ÅA,Ô>|-¶b`bÃ×bŠ ô&>|-–BÀÙðµ"5çÃ×B ļ¾r¡àÝðµP#)o‡¯…A(x?|-´B ˜ák!Eà{Á _ %ŸvøZø@ðÃ×|ÀÇ¢¾æs¾Ýð5_#ð)€h‡¯ù/D?|Í·œÀÌ÷˲_‘FY–çæææŽÒ3†ºyæ_¦Ç?gžsù—oÚ­”ºXÅ·Ì|‰ˆ¾ïõz5›Í—³,{‡ˆ>‘ýn·ilš™?+Šâf>_–åÕ~¿‡ˆ¨Õj½@D7ïÞ%‡g¾æCD‡Eä0QQw˜yJD^r¼¯qì‘ýÌL­V랈<‘®75Ì—†í±ú1S>‡ìúC‰C‰C‰3À‡/0‚™*- "¿Ž¶˜41~Ê«qJ©+£m&MDŒge@£ÑX"¢•‘v“´²k×®%Ó°¼¼ü@)µHˆÀg+J©Å7n<4= Ò¿ºÝîí™™™#"rŠˆnáÆÐ½Íü("§fffŽTyr8„íoTÈ85¿hIEND®B`‚olive-continuous/app/ui/style/olive-light/png/dirup.16.png000066400000000000000000000007341370472574300240420ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(úIDAT8Õ1RAE¯Fã¦ïl UÜ è! ( Áè H(cŠ/aD‘ôÌ oà®Å,ÆtØþ«7 œýxï_HÞw‘/Ïföq PÉA¼ðV×õÝ¿UU-ŒB‘ïvq$[˜Ù´è%ÿ–ŸH>¶ Ìp—§Êf¶l !"¯ÇL ò2„Ö}&EVN)¥‰™-Uµl÷ªZ†Ö)¥‰ˆ¤^ÉMŒq¥ª¥snÞîssU-cŒ+’ÛýNç"2òÞÏHÞîE7ιwïý'€k’]€ˆìHŽ›#=äÿlfHò*"»žwç6?Á†m Ñ%_¥IEND®B`‚olive-continuous/app/ui/style/olive-light/png/dirup.32.png000066400000000000000000000011161370472574300240330ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(lIDATX…íÕ1KÃ@à÷»Š`SÄ_ëÍ‚àèèè,ÎÒ‚«£ÿÁ?à&U\ÕQW„:¹¦^~CBQè}.M(gl/w¥ æŽã;Þ‡äB€&Mþ{¨X(¥¤1f v8§™ù4MÓ÷P€(Ì|àX’ˆ®ã8Þ^Àzͳ[Dt£”ÚYÀ'›Æ˜«ÄZ  @ÜK)]çS!Do4i ð QFDYÍcñô¾!0Bœ0sÏQÞ7_À¸Õjõ“$yÕZ¿y"¼ey±‚¨ øQЍøµ<á XXî‹p8—û >ÛåRÊ]{ÐÞ›"ú¾¼Dt«µÚED4¨˜T †î¼ƘIU93wìYfîT!ˆhbÏÎfî¿€ˆŽºÝîsE/yžï8¯*·J©³v»ý”çù3zl0óe–¹ÚÌÜaæ ×3³¯`îeYrÊ®@Dô Ê?„+èiÒää+ÅGÊxô IEND®B`‚olive-continuous/app/ui/style/olive-light/png/dirup.64.png000066400000000000000000000016641370472574300240500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÒIDATxœíš½oÚ@‡ß3,…dr3a%W¢ ÍX•þm÷ªI—¬­ºähçd+S;d`íÈÒnH‰KÄX>†–käÍI:ãƒûBÍ=’—÷¬{ï÷è0F€F£Ñh4F£¹ R±^¯gg³Ù»8ŽŸÀ§^ch …‹^¯rš“™ ©˜ËåÞÀ)ìrìµ Ã0|X,¿N&“ǹ7ÆH¨¿Øóé|>o:Ž“؃š$¼¶=„Г0 ?mƒ„$ÂÙ Êl‡¥ÔKP.@­â{@©TêË^ˆ@ÆÐ¶,ë¼ÛíþYÜŠ ˜8N§oIƒ÷Aæ%©¨ZÀõí%ƒ¤¢Ê÷€›L&óÆ4Íc¸Rµ%B7†a¼ ¿<Ï››¦yŠ$Hp7<®©” U)aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( 5IDATxœíÝ{¥EyÇñOŸ³ ;ËAQÑ%HQ°vgf6Q.&V¼±jb!‹H4• &Sl4U&)Ý\ŒX‘«wÝAMÁ"IVDv.;RhTH"+(C@ YXörNç3cÆÍÎ9ï{N¿ç}gö|ÿ™ú}ú9óüÞî~»ûéfÀ€ 0`À€¡lR³™úJŽÛËÊ'5[‹Š†Ã±|æ‘gðTàéÈ®ÀÓx$²#²c);vðÃõ4JûQ²à°•ËŒ5 œ8$e‘=‘kL`|“«ZBYð,HLqJä¼ÈN ÔûYlµß l[–3¸¿Ÿõ§dÁ`+Gq>Þ8¥lö㻸e7Ÿ?‹ÿ*Û™¼š-X¶3óQ)l¤vçD~·‚Í|WDþ-pÍÃ|±Š_•À×9y/XU¶/ñ\1Â7Êvd.¥ `CõVS¿AÅûø4±ùþ|;Ëv†’0ÅùM® <¯L?úMäG÷pGÙ¾”"€Û8ôh®À›Ë¨¿*DnmrÅ»Êò¡ï˜ä%ø^ÚﺫHäÁ&ïkÍ%ôZ?+›à\ÜlüŸ8©ÆÍ“üRIõÏÌwý»qi?ê[¨D>2¦~Î.€ÍÔOà½5ÞTt]‹„ÏóžÐ§9ƒB0ÍÒ½lªqA‘õ,Bî|‚ß{5»‹®¨0lc¨ÆÕWUÇ"gb—½ì\ˆ¦YÚ༼û“+¸èöUAò™·HøZ#þ½qünN<ž/¥ aòÏÀ þ$ðÚÔvV¿|>T”ý¤ç’¥´9€À†©‚þ¯ÉÆãœ¸&T`i‘ÒŒ\<Ê×RM¬iŽið%<7…½&òDƒ×œÉc©löÜl¤ÖàƒÁ/œÀÑKØ´9áà½g\Àoã̾ ÈÆè \’ÊXO]ÀvNoðÙ¢6kÆÖ$ÈÒÔûüûȳZßð‡§4iÖ§Ø]Ôµ6S?‘[qr¯NÌ%òÏu6ïfòåüLpl“³êü*NMY_jb+(Ÿâ««fúê ¯3Ül­‡¬KTÏ·¿Ïë{Ýgص&ù \ÙKås‰<ËÛr#a;ë›\UµV!²'pÕ07µ[Í›hÍŽ~0pt¯u6¹j-ŸêÅFW˜l9§DM[äñÈ›×òP–òÛnpmø¿ü¾R‰;ÂÝdÕ¸p¼‡qXn4¹,ål_äsÝ>[¦z þ›¸R ¼£ë‡ó¾›•¬òMöòp"H|Ø•£ÛhGàü{8±›gs àÐÖD²¤ÈÎQžêÕN?E*ø°Ž'ù\¯ñönÌÌ)žßL¼Ì›r©"HüYRu§×MplÞç2 ò›¥y+èÀÐ= ³‚ŠAÁŸùíC)l ­¹™\dÀÌâïäö*KZ§|$£|¨¥ß2÷Ú9»èL…_ÄZåïE~=&ÞCRE?j¼5¥M{.£yȪ–BÞ~¬šâ©í¦AQÁ‡í¬WÀáõœ±êøæÍlïž,xÚuwàmÃlOmx’Õ‘ëóú_dð§X¹‡¦¶Ù¹‹Ñu­•ÈŽtl¯ìÜû¡M®›dujÃÝ´E’ÕM®S@ð!°bˆ_ÈZ>‹ÎêÍ¥l̈ì†qFRÛa:ò¶˜-ÉbWä’"‚?Á‘ëŠ~¡òÄ,‹†{s'C5®-Bk¹7rQìj²am³“b‚3´º¢ÃRÛ>™‚m0Í‹p\Ïîä£,,–àÃñŸ¥`[4s~R$¤ß"XLÁŸ%Óÿ®­bÈA¿D°ƒOÆ—·ígà['¤ñ§;Š‘Ó$a»›ÏÏ„<<Â/v*4¯¾Í!;ùÕ8º­°·´J~ógi¬àÔN™Åóv;y±jŸ»ƒÔT$øPß•¡õžW V¦õ§g*/‚ ìËÃyPoµU£²"¨ZðgxI§í¾:>\•AEƒOȽ»¤ ®)bí /3>ÜPÁà ¼°S™yY‘Ö´¹v•~Íí÷ÀQ Ì+€**ú”ÖT¸ÙŸË‘ ´ëªªêýé»HðÅ þµ@¥Ü~ôM %ø´6Šv*Ón Pù¸…‹`!†î0àÿ+|ùS·´.´›1 _/ȸ©¤Jtœ¡çî ðú~4÷ñ÷Ý>œ[£|'¤ýn?oœŸÏûPÎáë©;¸‡5MÎKàÆæ1èöá®’C#ˆüw·•Î%7Í ²>³á²ƒ?ˬ¶ç8T{š,áo4ÿOÂz1ЕFZ=ÿu/Ï%ð¼7wz“"aŠ75¸± ÁŸ%°¼Á“\Øéú›{XÓhµ )®àÙtzŸÑ]+p3õ¸µ–ðúøH¬qGƒ›žebvN{Ï©svä­U©ê+‚È7Ÿâ®ÙK·²l£¡5Þ97ÅÀ/ò­ïó†Ò®‡)^Öäs¡ Ecë¸4TüÀªù˜™äÙ2Ö”“}‘õ£|³WC=1Ì}øÛ^˜ÀQ 5ø´®o) øðW)‚O‚B¶ðÜ“À—Ù˜¸kRë¹/‚iŽið%<7…½&òDƒ×œÉc©l&9#h5þXÚiâ?K—§ > ‰æ®ÀŸ¦²7àg‰¼”¯¥¶›ô”°a>…ëSÚ>:Ê EN~LÜ0f"ÿp{³}íH2ÜŸ­,YεÒߎ}°1±‚‹³$yvK!E®c_ƒË"waÿ` 2¾ŒK‹ >ž:Æ®%¼·UÇ"æÎ³aU²ˆ =*v5{æ÷ñÙ"ëYLD>};ï|5»ûQ_!c€ý‰„I.¼£õ-DfÎ!þðhÂUÖ,ôE³lç•Mþ‡÷³ÞªÙYç=k¸½ßu÷U0΋k|HÂeä…L“û›¼«Û=}½Ò÷ãâ×òм1ò±~×]5"·FÖ—|Jhæ2Á¹¸2ðü2ý(Gk¼w ÿX¶#¥ €ÖÞø%\Òä²ÀÒ²ý)’ØÚ½óÉ!6õã/ ¥ `–m¼´Æû§—íKD¾Õ䊱օܕ¡2à§›>×áwpjÙþ$â\w;_ØXÁåòJ `.ãœøƒªomÃý5®^Í–Ôéï)©¬f™â¬&¿8KÊö§ûbk_Ä'GÈ:Hå0Ë4Gìã‚Àë´NüªßÅ-un^Íãe;“‡#€¹Œsrs#c‘—µ-½ û"÷ÕØ¸c ÿÚçú“± 0—i–ïc$2üœ)çû±;òï©&Û–2µº¢×ÄäeÁ `6R;ŸÖX‰“š­¿Çã9£fnD]2›QGº™$ò¹ÍÒfCff¼ìÓi± ÌáEF9 Åâã2Ψ 8Ê·˜%“y·Zl—4Kšù‚Û¹±¯Pœã;>Ô‰‚;ùÌ‘nI³ÍNƒ»™À›„§Áó¬¯FŸùÚ°ÀL¤Ûg¾¢‘`¿*ºIèß"•< i&EÅ£^:ÄŠ‘ד¹Vkò¨ƒÌÀÐc)°8›¥öñ6²v!óë?<¶81LßyÝËü‡û BãzßKg*fIEND®B`‚olive-continuous/app/ui/style/olive-light/png/error.32.png000066400000000000000000000020171370472574300240420ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(-IDATX…Å×?h]eÆñÏ››„¬VŒqÑ\Ü!ÍM¬K!ƒƒšŽº8è$ ¢­±jÁ€Bë"âT0Ò!DRB@+6i¤(tPp°ÚŠ¢š&ͽ¯Ã9INNÎý—ú —{Þó{ßçûþý—;¬Ðj…ox “G#½žÀ-\‹üq•+cTöà:8 <޶¡ÿæo3}„K{X ý.^ÀëžfÌè»6&óó®.sp•37Y‹¼5ÄtKßòH'Ÿá¡Ýšç@>äâw;ærƒ|º_æxõ{^n)uóqàÐ~™g ÞXd¨.À¥dÁ=™ƒš¹IWR~¾ ¯¹U†:é¯2›(E&—éÈ%Z «›y<˜1+>Ê¿ési‘©Àh‘sd¦ÌxHÏ‚Ÿ¸o%·|±cºx>kž‡û3J™ñÈL#sX)XcU^›È”gÿ õê&ïEJõ ŠÌc2ä§òízG“Ãl àbýYä£<ÄUÆq®ÊlÞü,¥%>Œµy:Ó ™y©Q©°—@Ù²zë$ÕeŽA{Z©·QRŒ.&±›!—xš4éÛøß–þô6ðÏBl›Ž e†½®yª{¶$PÍ)¶[GkÛªüÕL­*³ƒIfÜ‘óǨüÆqœkÔN×·„LA-EfòæéVÛœŽ1*/:'rmmv¸ Ö¹¹]«B½­Vo‹Ö¸¼ à)n–jÄÏõüSx.ðì"SE#¡Fî(%Gþ@Ú˹Òˆöyº;¦ò#±ÎÛþ×føqÀ-¾Œü™îlò©±^wf‚jæyKKŒE&s¾îâÄ :ÚyÏô*«ó«œl§ÒÆ»Ùã8ru…ᣰmg)õ%ŸbG˜´¬˜ŒäKƒ\Ì–ï8—¹·’|DöåßíQ§Ê|ž/Ü‘¯ûùoW"¿ï‡kºO™Óà³|Ó(ïÁ|-ðf™¯jÅÔM‚éªÑ./&x¿Ì/õ‚šºš-pww’¿‡ñ„W³ÈߘL—Yn¦í–/§ËôTx £+-¾ùu7—Ó;®ÿy IØáIEND®B`‚olive-continuous/app/ui/style/olive-light/png/error.64.png000066400000000000000000000035211370472574300240500ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(oIDATxœíÛ[Œ]Uðß>[:㥩ú`H *ÁBé\«Ò¬5xé“>€ÔMLTú%ƒ1š¶j¢Å`©×jcT*Ƥ¤iéÌØ…¢\ˆ&F)ÑZÑ9gùpÎèÌž}Î^ûrÆ&öŸœ—µ×úÖÿûïõµ¾µÖæ<ÎãÿI¿;8ÀÊA®mp9.Ã¥,KXx1á Náœhq|Ãky¾ßüú"À!Þ8À&\7•±x²Áƒ ö®å¹ZIvP«Ó¼«Å-Ij´ Ó »F9P—]j"9ŵ¸ WÖa¯G—°c„é:ìU`Š;ðþ:ßx:#bo“í¼PÅViÒ¿a´Å×ñÚ**â…ÀÖq–5PJ€)¶àV,)Ûqh¾6ÎÝer là΄O¡Q¦Ã> ‘ðöñšUx¨={D#zÜEc;>P”á"â'£Üž!ú-¾›;ÎqçaÓ·i%À$›l.Çiq‘ðñIn,P¿7&y~˜0X‰Ùâb&áC£<šW±§ûY¾ŒŸã ‘·I¿Öù?Êv๥ܰš—zÕëñYqÎ?Þ䦓\y–·à“x:†h O7Ø2Ú“\Ñä¦À±^m.þŸÉ³ÝU͇ysƒŸ&9SeàX‹Opvnù$ÃØ°:DŽý£Ø<ÞÎçò[šp_£-x7ÌnçÉnºŽ€·å9ßÁWÓÎÃ8§f¸¹ã@)ŽÎpsÚy˜àlÂŽI;GéŠL&ykÂ;#86˜êöp§ËŠ0ëü:Nw«3ÄtÈ™ó×î1Jº€["I6Nç(#BŒóðlÄnBÒàÝž/`?¯ÒÞÈÈEB²,b¤!ÖyXÉ;bx6á•YϰŒEæüÀç:x=#Bç'nrg Ç„ ZlÈz–ï1:ÇøÅØ}¡¼º½D(â|§¯Ý «by†.~Íà.ÄU±Fg‘°z€ïv§'æˆðŸUZàØu~€{KL¯×tü›‡y¬`ŒJ1H¸b){ ˆ°9ðhÇù¬åïyí*8®Ìh—J‹–Ž÷‡Í3ܸ΃W§ËÒ\VÖø,ІCŸ‡}šÛ%é²y„ö¡Ee ‡<Ôå<´2ü›'@Âëªv2ÇVeêt¾Ãéõé²t,«££9–¡nç!pQº, *TEúá|½è#ÂPÁÝZÅë—Bú? çîI™çg1wP3þ¥G@­t–·Qó|sD(½ŸFÖ Nÿü¥®ÎŠ,o»!kÙ\‘ÓŸÓeéx¦¦Ž ûn¨9N¤ æ ÐʨPE†ýA†Š,›k‡Þ4*vP&««’EEƒG2Êþ‹“ü/—1^6«+›E– øòó<–.œ'Àƶó TÊCÑaŸ^ä”É"K„Ñ/7k!ô‹‚†Ÿ*²“Óm…×É"ïA[„èׄ²Êp†}ÅÆ—êJi‹ˆ0Ω_Ž!øg‹}Yϰž¿áÁØåá¼JEÖöEDx‰ChFØüeÖá ]rAvå8Ð>¬üBN½2‰M¬%ä‘ „fë3™\ÃïEÜÇK|O{1U²º.aMÄñÝþ Žw{Ø5LØ"†W`Û\.Ÿd¸jJ;+BÖ¹Ãí½þm9&fZììU¡«cü!áÛ$¯:Í÷1rý L²>áþ:òùŽûs]`É},™fä4?ȳØ3ÁS9ö»c?Ë—ò³Øˆ@³c°_×çš‘§ÖϾ‚÷Uº ±ž[|:vZìëçÝÁ%‘ÎÏ`kžóDìMðxÂövç ¾8¹RŒÚc¾U‰ÕâáîQ¾[9zOpÛ{ËqZ4üx”¯i¯¾É¯ÿÄrGL羳ϯï×UÙ¹˜jß Ùê¸,Ý™yvŽqO™ö¥ïóM3ø†ÿáuùÀÉ·NDä#ÝPéBãc¼ú,Û›ûƒ‰?dÇÕíä­4j!=ÍH‹m}8ÉY€À# ;Æ8R‡½ZßÚ$ë¶ÆêþhªmÞ®*_‡d¡/ÃvšUM>ØàúÀåeÄèÜ >ÞâW {Çùc?¸ö=n§Xñо¬xiÒ¾„1¬}=¤½›t&´÷Ot~¿k1Yõƒ¨ó8óÈÅ¿lñeQ€IEND®B`‚olive-continuous/app/ui/style/olive-light/png/ff.128.png000066400000000000000000000032021370472574300233670ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( IDATxœíMh\U†ßo~¢ ØÌ$ª¶÷†nºÐªÌÎ…Œ›´•Zu¡èƂܕ b ­V°àB—ºR¤‚›j…¦ˆ¬tü©›@ڜӔI™X*±Mæs“„6µM2¹÷~gæ¼ÏjHÈ9ï3y97ß $!„B!„B!„B!„B!„B!¤»‘ÿû`µZ-\¾|yˆ<ài%ˆÈU¿·ÛíŸ7oÞ<266v+˰Y’ÿ]ˆãx·ª°u•¯mˆÈ çܹt¢ÙšÿíÈEQtÀ[ë\ãôÜÜÜñééé æ² HÿüÒ‹8Ž8ÐÁ;ŠÅâ‹›6múcvvöJrѲ%Tÿ<°|ìÛÀ:x¥¿¿ÿßÙÙÙß’‰–!ûK¥R)6›ÍQBk^( ï]ºtéjBë¥Jèþù¾¾¾]ÞHpÍ­ªúR©ToµZõ×M…Ðýs"2œô¢ª:Øn·¿ŽãøH¥R)&½~’„îŸSÕ'SZ[Tõí™™™ïâ8ŽSÚcÄGÒÜ@UŸð}ǯ§¹O§ïEÑD†û-‹G'&&þÎpÏûº.ãýöÌÏÏÿEÑ3ïë Þùg]¨êã"òmÇ-ö·Æ7“ªšWÕƒQܾ}{ªÏ`ñÉߺÏ.,,üÇqÕ8‡æþÖ€ª–UõË(Š>ð}fNkó,"öû>3§ˆ™¿/àÿÌœ6þY߬‡LfæÐý½:VàÝÌœ1™øû\ïfæ¬ÉÂßû7Õ§™Ù‚´ý½/Àm˜ÏÌÆ¤âßM0Ÿ™­Iÿ« °ï ôïÆàARþ>߬‡ŽgæÐý»öXï :ôï•ðΠCÿžz£xg°~ÿž*ÀmðÎ`þ½Zެѿg °ï Vñïõ¸cf~Ù:‹÷ó¢ ª©êgÛ¶mûy/q/ÿàÞy3Š¢£Ö9¬Xé\Ù?44ôœuC–ýC-TõãjµZ°ÎaÅ’Èxlrr2ØS`É?Ø,²×:€1{C/ÀëÆì½[¬³%ô¨uc4ô4¬Ó½ãÖŒ½g¬s&؈ÈÔÐÐÐyëV,ù‡Zm·ÛÇFGGç­ƒ±ìjNÖëõ_­C²ìbNÕjµO¬Cr‡0¿ ‘Ž;çN[g±à^þA@DþpÈ9笳Xp?ÿ^(€S¯úÍ_Õ¿gO¹à}çÜh­V³Ž“9kõïÕàB>Ÿß뜵bÄšý{ê‘_8ç>жΓ5ø÷LDdJUß­Õj]õ?{’¢Sÿ^yœ- ûBýæcþ]}p¶ß¸×€³}2þÝøàlŸ Wœí“÷呂³} þÞŸœíÓõ÷ºœíÓ÷÷ùÀÙ>ïNÎöÙú{UÎöÙûûòàloäo~p¶·õ·>8Ûû›œœíýñϼœíýòÏúÀÙÞ3ÿ€9¦¹‰ç³}Ðþ9™Iy‹"²ÏGyÝ?§ªSZ[Eä«ÁÁÁ×&''½ïB÷Ï—J¥>ÃI.*"×Dä sî›F£áõOù¡û猘NjAU=óæÍºh¶Ú?ßjµæËårSUwmp­[>­×ë]¿~ýŸ$ÂeAèþyhµZã¥RiÀÎשåóùι‘ä¢eGÈþù¥­Vë—R©Ôà©u®qznnî©©©©d£eK¨þ²òqïVÕ£Xý(6Dä„sî\:ÑlÍÿ®@¥R)6›ÍaVÕ"òèâ§®¨êŸ¹\î§r¹|vllìV†Y3#tB!„B!„B!„B!„B!„BH7ñüñ:è² ½IEND®B`‚olive-continuous/app/ui/style/olive-light/png/ff.16.png000066400000000000000000000006661370472574300233160ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÔIDAT8ÅÏ1 Â0àÿÕ -•Ò¥[é+pö.^Á (‚GÑ;8êàìê(‚C îB¡t°‡Rc‚“ozäûó’ü»zRÊÀ÷ý¸,Ë›.`ó^;"š‡a˜¸®{¨ªêÞØÜQJÉw?ñÈŸiˆè €ycŒÉÒ{˜?«-À^‹ÅkB?Ôhè€{Ƙ k­o]j¿ï ØŒ¢è²1fógl¿— ¢€ÇƘe‰‡+¿óQ‹™¬µ]¯íÃïz ¬Çq|EêáÇñ;©€iëíi˜8ÓØÛÓ0ɘÚÞž†±*`Ú{{r~¦œãº·‹úc_œaì.€GÖÚ§pû"CÔŸð|„q6Š¢ëÖÚU—ò=DýQ·ÛýV("g†Œ©õz½;­V«åR¼´ÿχ’ZëóªÌaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ªIDATxœíÚÁjQ†áÿ?!"nBÁB ÂÜ‹.¥ûzÞHé¶´‚›Ü‹IP éÒ.„b .æ¸I±ŠÂ™˜LÒùÞg}fø`^2Ä 4W½ Ïó½¢(cŒ/ÌìÀÌ­Ö¹5³1ÆI§Óy;Nl{Ð.«Àp8Ü/ËòÄÌÆÚ³nsw}yyùyÛCvUH=˜çùÞ{øffããY¿ßºí!»*9€¢(ía=ü;ýÂ)ü]rËwþCEÿ€»?ßäô[­ÖY¯×{¶í!»¤Ê'@¶É!uˆ1öÚíö)ü’@SÁïä0#‚û$0#‚;²˜™xfD €™v°¤Ü£üA-‚䟃ƒÁÅ&‡`e·fö1„0ɲì¼êÿ Yæ!„£Åbq•z¯€f—ey’çù^êÐ<ã›››W©‡  ÜýeêYh w?H=K Tå¿ ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€¸äÜýû&‡`}Üý[êÙäbŒŸV›ƒºÅ/RÏ&B˜¬6u‹1&?«ä²,;7³ùJ‹P§y·Û=O=ìUî<÷˲<1³qåY¨Ã<„p´X,®R/hU¹ûõõu1ÞEñÅÝŸ¸ûc3kWž‰µY~9c<îv»of³Ù×moõû ˜ú Ú5ö“IEND®B`‚olive-continuous/app/ui/style/olive-light/png/folder.16.png000066400000000000000000000005651370472574300241740ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(“IDAT8c`hÀÈÀÀÀ //oÈÈÈh†&÷ãׯ_«Ÿ={ö100XaH22žùõëW>CX 436Éÿÿÿ›°²².TPP؃Eúäƒ.°`‘@†ÿÿÿ7Ä"~Œ!މpfJ `5Õ€¿dèýËÀMHŒŒŒ}ÿÿÿ¿LŠnFFÆÝdXJ^Ò&õ7¡=õIEND®B`‚olive-continuous/app/ui/style/olive-light/png/folder.32.png000066400000000000000000000006201370472574300241620ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(®IDATX…íÒ1!…á7ci<„ÚÄ{x /à•ÔØ[êI¬Ža1ØÙ— 4óWKÞ— €¦ ŽòÁ9gEä ÀTÜ )¥SŒñÕ à|H)*ÇÀÑÕ³[ `ýçÝ-Ýœsû¥sڈȥ±jdÄÝZ[û}dæ£÷>í`Næ÷Þ0 LÞÛ(@I P€ €)àÓq·l=„ãof~tØÑ´º¾aF'ÏIBY5IEND®B`‚olive-continuous/app/ui/style/olive-light/png/folder.64.png000066400000000000000000000010661370472574300241740ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(TIDATxœíÖ=N„@Åñ‡F,–rÜŠ„†ÒŽm7^A½Ä¶/²ÛÉ)h½%ŠnŒÁÊÆ ‰Q†GäýÊ!aÞþC±€ˆˆˆˆ¬Sà:̲ì¢ëºÇanl'º«PDQtªªÊNôÎ?;w†aøà`3á];kíuÇ/MÓ|Løî_;9¿óxçMß÷yš¦—ïø±±S}öNAì­µÏKˆ0À»¥D –àG ¸œÿ’$y{ˆG5€Âs,ËòýûÃE|žmÚ¶}p=\C€/÷®Ã5¸r®)€“°°){›°°){›°°){›°°){›°°){›°°){›°°){ÛX€zÖóxsŽ(<aqþ&gcÌ@Žÿñ%Ôrc̉=DDDDD–äŠnCO¬OIEND®B`‚olive-continuous/app/ui/style/olive-light/png/hand.128.png000066400000000000000000000102741370472574300237150ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÚIDATxœí{Œ\Õ}Ç¿ßsgÌcýØ1kl0;3»6(xyÚ„`J‰Ë+ •ÒFIš¢”*‘H”&$"U•R4´ T*})ª¢HB€(c P㩨™×®yØk{ÖoعçÛ?æîfmfçÞÙ»3ã{?’¥9çüÎÏ3ß¹÷Üß9çwˆ˜1L__ß™ÖÚËœ À"¯ì];H¾Jòé|>ÿ:µÊÑfÂV;Ð8™Læ’_•tJÀ6%’÷ …GØ0 ›H  ¿¿ÿ4×uïpêM¼a­½ippð­fú5“8­v Ud2™KÜà¤i˜Y`ŒùÃT*•+—Ë)‚H ›Í~‚ä½’Ži‚¹Y®š;wî###¹&Ø›Q"w èíí=Ãó3Ç5Ó.É’>],ßh¦Ý°éhd2™ÓI^.é|’ P½œ À»’ÞðŠã8Oær¹-°jÕªD>Ÿÿ5€¾\ÚR,? ÀŠ­ #N§/3ÆÜ"iiÀ&›üdZÒwÃôä­ÖÚá©øW,Ÿ Ó·Zt”z{{O6ÆÜà£SiOÒ•ä7î9$闎㬗´Ãkw¢ëº+H^ àØ&ô1/c¾‘Ïçß›bû†éd³Ùs$Ý`AˆÝ­µ÷ÜU«PÒ Æ˜›ô†èÃ{ÖÚbãt„2™Ìr?ÐŒQûdì­T*·:Ž3âS/Eòhò òc>›Ïç7…ØÀ„ÝÁtÉd2'‘¼á~ùð`€/v[k ٗ㬵÷-Y²äÄûi¼[ROØýHÚ´®1f}˜¾x,t]÷ް;ik¤ÓéË%MiÀ× øë£š'tQ__ßÅaö‘Óø4¡÷(åW¯à1I/c¶K¢µv!É Œ1W‘“´®ëžÔ±ÖVŒ üÛ™–’n°6hgÒ¶ƒÀt:½Œä/ëÕ1Æìt]÷‡Þ©U.iq"‘ø†µ¶»ž’®µö† ¾I¢1æ_ýê5Ë?×u¯ÚÔ¿FhÛ[€1ærŸ*•z.ÜV©T~HÒm®whš‰DÂﳘ2m+IøTy u>Ü1H‘|¢9^5DÓü³Öžß4¯Ž m î#¤ß5$é¿§ïNc4Ó?’‹ê•O‡ŽÉá †Œ1Û§ïNc4Ù¿…ÓtgRÚõ)ÀAH›7h jlttôƒFíÓ¦Ùþ‘ìòþt²ÙìG%­ðf¡:»øž¤íŽã¼šËå^ƒ7„v@Ìá0›Íþ¤+$Í€ZÇ®ë"“É”»  C0Æ<´®$¿ºãbctÖÚÀ³‹Žãøm,ŸiÐx»š]ô±7{ìïX'@ĉqbDœX'@ĉqbDœX'@ĉqbDœX'@ĉqbDœX'@ĉqbDœX'ðvÍœ¬\ÒþVÚk%‘üŸ:ÅëZm¯UDFÖÚì­Q4à­´×Ê+Jd€jžÿÛH¾€ê‡}ÀZkí÷%5’)<{­º¢Dj{8ÉÖÚûQ=0rì½¶°g­}ä9æQ4¥+TP¢thwš}… D¤®íN³¯PAˆ¯§‘+€ÓÛÛ{®1æH.°ÀBo„z@žä:I¯‹Å—Ñ@¾Ú˜Öá+€+V$‡‡‡Wø2¼#WÈS;×û·HÒJÈd2#ž𫞞žç×­[xksÌÌRW½½½K†‡‡àôíÎp-€k‡‡‡÷d2™g<íºîš¡¡¡IŸwcfžIN§W“¼>G¥`.<18޳7“É<#éqcÌó…BáÐ4mÇL“šÈd2W‘¼kgàNÆ×¼Àl6û €Ç+•Êsñ•¡5|H½½½gø»¾üÃt<€ÕV;Žs0“É<à×£££Ï¾ýöÛï‡ÙwÌï8L³öíÛwÇ‘ïÏǸÀ•ÉdòP6›}!Ày1Mà°8À¾}û>à´ù2Ʊ’.k±‘aâ/Ý!ù…¿¼ƒÖÚ‡1뽃‘HrëºË\HrIhÞÆ4q¤ÓéK$ìS¿ éG$Ë’&ÆÞñþ=m­oŒ9 Àï!Xòâ˜2.’uj$¹¿R©ÜmŒÙãSo—¤5ÖH‘ï3™LΪT*MÝ’ÜàeI/[k»,sçcέ%’#ÖÚºÇÊÇgâ`›¤þÉ*º®›Fõ¨’ÐðÄðªµöUTç –‘<ÀÙÆYk_±Ö> `w˜~D‰‰·€€IàjIoÖ:­"$xMÒk@õXÔ˜æ3>ø pÈÀÙ.ט™f\ÖÚgàÖÌ“¼VRüw”0.€¡¡¡mžÐæZÇqn ™ Ï­˜™â°çoIw“ô½ÙJºˆäM¨ÎâÅt0‡ À;Kî'AJ ùMkíÜP<‹™>+ ?0 £Ïqœï’<Ñ¿jÌLá8NÝȪ¤ñ«|­ŠÖZûekö·À÷1ñ4pûà7H_qUS)CCC{zznð«€'é/1g¬"ÖÚº^’ã§ŠMwçwìÈÈÈã©TêX+ôk¬4Æì“”ìmLÓ‘ÔMòŠÉÊI¾[.— øo S¡P¸Àíð‰ŒÙ–ô¹8VÐZH¹ÃøHvŽýh¶X,Þ/éë‚îð¹ÖóEcL¼ù´5œP¯PRc€R©ôÉ/¢vVŒZ\ à/Ç fcÌÂzå$Kãu1\(~Cò3üΦpX¬Àï’Ó\2õ ­µãc´†·‡ …ÿ³Ö~ŠäÖ€MúÇùÉöÓ8Þêªzu&~wSÊ088ø¶1æÓ$_ ØdÉÛàí.Ž ’ }VwUH¾1öbÊ "r¹ÜHWW×H>¤¾¤.cÌ­öH3u–ù”ÿïÄM¹ÓÚÿ·cÇ·\.?ÙÝÝ=À9š’çcvJ*ùWi’×è©SþX¹\~aìu36€jdddm*•ÚCò"ø‡! `9IHÚ2ƒ+ŒŽz¼qÖg|êÜU.—·½nZŽ B¡ðo$oAc±‚ÏcBÝ…%¬µùTÙ“Íf[QÝÔ¿\.oîîî^Oòr³4Éc2ÞžƒJ3}‰‰DâX_0éBIoܸñ¿&¾×ô,aÅbñ%cÌ¡ºWÐkí9$¿¯+˜®ë~>A7Iù^(iâr¹Ü×u¯'ùVÀ&Ùx]ÁÔ!9—äu>uÞüP:ÚÐò mó®cˆ×L•ÏJª›Ë‰ä?£Æ„^¨‰"s¹ÜH2™ü[l T×|+^WÐçø˜OíŽã<\« ôø®]»\o]A7ª{ üp¬° @+¨C¥RI9Žóuø¸ÿ6ŸÏ×ÜÜ;S`*—ËÏ¥R©÷\ˆ±/©áÝHƒã8Ç'‰›%Õ7‘Ìõõõ}»P(ØšvÂq¯6åry]*•zÀ¥°1•äéÆ˜ù$_—Tó?EÇ1’n”T7ìKÒº®û•M›6 Mj«ùîÕ§\.o7oÞFcLÐXA@:‘Hl°ÖF>V`ŒIHú<ª·Éºü—R©ôózuZ…œ?þ3’.0;@“E’¬µëIF6‡ ·ëÏPÍ¿äW÷-_+—Ëu4- ÃîÞ½{çìÙ³Ÿtç÷ÌÐ$eŒYArªÙÉ#…µv¶1æfg¨þ1æÏ …Â6¿Š-ÃïÝ»wOww÷£$WðËP]$/$¹EÒ®°ýkH~ÄóMTSôû!I·‹Å@›{Z>S.—uww? `)€ A Y.&y,€­8Šç¼ûýu$o@À¤Ý’î,•J? ÚGËår¹âÅ Rv‰€¥$/5ÆIƒ8Š„ ‰‰Db€¯¡è ÊÏK¥ÒôÕðP¹\^“J¥>@u„d_AÕ427ÆT\×Ý1q×K'"©—ä—\‡Ÿ 6)$ÿ£X,Þ†`û7~×®1÷f†l6{¤ÛQgj³$­¤×%=oŒé˜ÇFIÆqœ%VK -=¬9É( ?•¾ÛRN§/2ÆüÄgc=öx…äzk훨æj+¬µsÇYàø,åž„ €ï‹Åÿœªm+èïï?ÕuÝûd§cÇKzñ[kí&T·’Ô’[É9$?‚êmîœ)$ɳ3äºî-µ¦x²3Æ3ÁÒ¥KçV*•¿’´ºY6Iº’Þð†¤’¤w“Éäp¥RizÉ›«Oè“´Ó³gó‘cŽ9æ{›7oºKkr[Ó50S¤ÓéËH~@oˆÝl'Y°Ön·Öî6ÆìòRÜŽHµÖV’ɤ;::ú>I%‰c*• QÆîJ$³]×=Ás’¤Å¨¦Ý›×Dÿv“üëB¡Psjw*tŒ`ÕªU‰|>ÿI_E¸Bh7*tW©Tjj’ÌŽÀ³8p½µöKðIrÝáÀ³’n÷ò75ŽÀL:^é­‡»Ó?â®-ðg×c~œÏç7…ÚW˜Æg’SN9e~"‘¸FÒÕ^ÖñN<y7€_T*•ß¶mÛ¤søÍä¨ÀDÒétÊ;åR’—I 2åÜ*>ð€‡zzzžšécvJLd```ÖÁƒ϶֮´ÀrÝ-vë=IÏcÖîß¿ÿ…;vìk•#G½jÀÞÞÞ~cÌÙ$O•tÉ%Þc[Ó?±˜É$דÜËåBM»ßQ@M.\ØuüñÇ/ñNN[„ê*¤$O–4@ªƒÌY$çxcŒ=¨Æâ÷I°“äNov2 L&s[·nmÛULÿÄi„¢o€IEND®B`‚olive-continuous/app/ui/style/olive-light/png/hand.16.png000066400000000000000000000012231370472574300236230ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(±IDAT8¥“½kTAÅϹóÍ~váñŠgá6vŠbµˆ…ÿ‚élÑ.à_¡Uê€,RFÓƒ] ·H‘Ì*—·s…»²!nð43Ü;çwï)†8AEQœK)•f6Gò Hzáî?CU¯×û=y˓̒V$ÉÀÛqë¹¤Š¤7ÇUU ÀŽ$]•TX–´ ˆãû²¤º®ë¥<ÏÙqÉÉ¡»Ã̆’fv´v‹äí¢(.OfÔÊxÛSÎ(þ/§F´BØ€”Ò*¸ûWw!„6dyžß$ù@°&©OrØFÞîø\33ø 0³§’Þ§”ºfvÃÌÜýà,¶HÞ !lKZw÷õ½ cÜh·Û×<‘ô…d=‹ÛÌæI^cüÔétæÌlÉÝ7Iþs<¹às˜bŒ­V+šÙKwß&ùã”é×Üϲìu8Ú ;ÍfsÇÌ^‘¼Dr(é0˲‘»Ÿ'9à!É{’žu»ÝïS¿ʲl¦”Ýý.€+.Ø'ùMÒǺ®?ôûý_ð;|ΫÀ©IEND®B`‚olive-continuous/app/ui/style/olive-light/png/hand.32.png000066400000000000000000000022471370472574300236300ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÅIDATX…í—MlTUÇç¾yƒ˜b;%MÔ±™©•4qDd!U*RRŒ{7nÜ6†…&,4‘D.LŒué7ÊÂ&jbU0 ?H„hJfF‹5ú¦µ…fæ¿‹ÎĦÐRÚÄÄÿæ¾{ï¹çüòîç1V b±Ø<'i'€¤£!„W*•J²T¶œ€ù|þŽ8ŽšÕÀk’î™cvÆÌöýõzýØ… FW P(^Ö5›Ô_IÓô@Eì ³ú®˜ÙþJ¥òÞB~£¥ïííív÷C@6³2p'`’>0³sÀ´¤uf¶¹9¬e· ØÙÖÖöþÄÄÄø\ß™¥¤iú°Î̆Ýý°$BHÚ xËÎÌÍò“¹vÙlv;ðîu]î>Öjp÷‹f ÏàBv’ö‹Å=ÌLÏ‘F£ñÆèèè奬X’zgUh ðÄš˜Ù¯’^—dfö °­§§g ¬@š¦ŸKºŒ¹ûQI¥5h-ÐÙßîž]3€Åô?À „P5³©BåjmfVŸ]ÎÕuŸî>ì½V›¤“@#“É|Óh4˜« @>ŸßÇñ³’†ÌÌo2™Ìg###ó.eê p|¡à™R©”œœ<$©Ô$†êõz½P(|ÉÌ-¸*ÊLMM 6ƒ—Ó4=hf)PŠ¢h°UÒ®&Ôê¸{7€¤S!„Öï>éî'õÀÝ!„~I÷†*³ë!üäî˜Ù.I_Íê¿ œv÷ÓMÈ ”Ëåc’¾º¢(z¸í†G™/03€»û^àˆ»çÌìŦU¸¹ ðw0>>Þ¨Õjær¹[-f6 i¸¸ÑCC@^Ò;³¥J’äÓ\.‡¤ͬÊ72xš¦qáI3 q¿<ïUœ$ɉÎÎÎ1`ØjfYIg{ÿ-WQíî¾.—Ëo/ø,O’ä‡ööö³Ànf¶a—™‘´¢=EÑí’žfæÚ_«Õ~Y4/¨ÕjåÎÎÎãÀ#’ú$õJú~±KåZ’ÔÝ̘6oU«ÕÃpÄ$I’KÃÀ ™m2³í!„ wÿs ëGCOmÀ‘žžžç+•ŠÃS³|>¿1Š¢WÍl@ó¸þÎÝÏ™ÙÏîþ‡™MIšŽã8›¦é-@¸x¸‰™|àÍjµzH[¾—µ²ŠÅâ 𸤇ù7G¼ªÌÌ%V«Õsóú—ÐR__߆éééI›Í¬$)ä€v`ÜÌ~~t÷Sq|þüùßóõ »(Fo*IEND®B`‚olive-continuous/app/ui/style/olive-light/png/hand.64.png000066400000000000000000000042401370472574300236300ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¾IDATxœí›_lWÆ¿ïÌ:NHœ¬‰’ì®kS¨Ô@HKSTREI$*XHBªFâ¨/üQ¥B@"¨…„R¡¶!HmRQ¤¤PJ*ŠJ[ÅMÒ8Ù]ÛrÛ8$^W¶ïÎýxص½ö®½ãuL~OžsÏœ{|ffï™3çu¦µµuu¡PØ `+€dIœp2ŸÏÿº··÷r”ó3JãÓ‘J¥¾ éG–”Q6³GÓéôï£òÁ‹Êðt$“É]žÐ0…Zƒ¤ÍÍÍÝýýýg£ð#²; ‘H4›Ù^Û$µ€4€?Iú#€ç,®ÐÜ0Év;'³àh&“韉Ÿ‘ ‘Hl'ù8€¦2* Í=Lò°¤Ó@r£¤‡0>@ás‚ä|7›Í¾\­¯5‰Äv3;„©¯î¸DÒ“’Þà8I½Þ!yw¹sB,&ù¹+V¼•ËåÒÕøkÕ(OG"‘h&ù¸¤ªìšÙ¿Â2çÜéjlHò<‘J¥âÕœ«Fy:Ìì’‚·}ÞÌ;çÞ’›%=šWÎ9?l‹äYöV8çöøEÅ>WªX ’¶3nvØ÷ýS’F$8ç^!ù«™Ú¯Äž™m+wþ¤6gêÌdLs¯‡u$ý}¦ö+±')Ö™ŠZ>”ôñ¾(VrÎåÍf÷Jí-K$í$ïG1³€¬¤“MMM/tttŒ•kzÌHò €> àv;I|iýúõ›ƒÊ 1e‘ôa3;šL&·ŒÊþ¯P¢ÀÏÛÚÚ–5^ç $}I¿õ}ÿ54³»ÌlW ?iÎçó{Z¨wÀIÇͬÏÌ.8æûþÑ ÉíÀ}$ ËÌìo!$°0Pv¹ ‰– 3Uq3õv ÞÜ @½¨77PoêÍÍÔÛzs3s=aéƒF_@Ô7½ÙR—;€äS.¸LòéÙèÍ6Pu©8çÎøHšµɧ$}³ô÷ÓSé†Y‘J5ÐÖÖ¶¼P(<(i3É;$ŤI¾"éÅl6ûO+­ ‚qhiiy P(<*i%0.š$m°?™L¾ à„sîDww÷è÷¼–±$‰vçÜ1ýã[ì3³}ÉdòÉ?8žÉd^‹ÒѨˆÀºuëÖ’| Õ._-i7€Ý©Tê?Õ>óxž·ãÛT†Q,,žvÎ>âœÛ à”ig}ln4b@ò³¡«÷ËÑf3ƒïûgœ1³ßHj° À”êj721ôÁü­É”sçœ3³gÜJr“sn €å!õH2·Z3ú#8 `¬±À÷ý%f6¡²¤ôMÿ<€ófö<€”¤M$ïVñvz&*§kÉhº¬zžw¿¤*5R Æ$=W[£Å€ä³!ùAòç\øWþ†Â÷ýðE|Õ.^¼ø6€v݃´xž÷}’«¢s1ZÌ,ؾ’Ùlö†††¯x54´Àͬ52/#„ä-ÁcI]@™ŠPggçÀ²eËö8Z"é3»#/#Ä9—‰ÎS´Êöõõù¹\îÅx<Þ`c`Èp™õIꮽ«Ñ@r€ã#ýýýÓ-qÊår‰Çãƒ>ƒÿ½-Å÷_Rg©.7ŸYCòKãëCCC T´Æçr¹477Ÿ° É‘l6³7%ÍÛÂHéŸo ŸìííýPEU8“Éœ ùJËG€û$ˆÅb•öþÏ5kHÞHË|«Ju3™Ì)’_ð^hhc¡Pøžs®Üþ€º`f1ûKä’ÿÎf³'Çtª5šÉdÎ:ç&ä $oõ<ïó%Wd’¾N2¸lË9÷SŠº3ÊóÞ_¹rå1IŸ°60´À’(î⨠’hfí(¶Ëy®««ëHP0ã«W¯^_µjÕ1ç\+€¶ÀÐ"÷èA(­ž#›Ù~÷‡äo_»víáÁÁÁquŽY½é]¹rÅÏår'âñør„r’Ÿ&pm6óTŠçy·ø6ŠMÒA.9çv÷öö^™pN æÍ†P¼òÁÊrÊ̶£Xm4QÎÐBrŸ¤/£øŽQzÍßÛÕÕ5iÒVÓ]cÉdòó$†ö ésνêyÞ›¾ïg0‹;ƒä*Iw’¼5>¤óz,;ÐÙÙY¶>Yóms©T*%égîœN×Ì2’.Hê1³÷ …BNÒÀ¢E‹òù|þºçyæûþb±X,îœ[G2áœÛ@rí¦ $ŸÌd2‡L¶÷hŒ¨6N2•Jí”ô0€Û"š£vÎý¤»»ûB%Ê‘ï^¿~ý§<Ïk—´å7RΖ/™Ù3étz¼©˜³ÍÓ[·n¥Óé»PÜ%¾ ÀÇ1»Ïó×HþÀ‰ÆÆÆ—Ï;NÑ+¢n»ÇS©ÔbIHÞ&©dBÒjÐH²©Ôõ=@rÀUIçœpÖ÷ý3===óõã¿VýEY;g`IEND®B`‚olive-continuous/app/ui/style/olive-light/png/iconview.128.png000066400000000000000000000017711370472574300246300ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÝ¿nÓP†ñï³%$â •Ò‰f°: JÙ ÀÂX˜¹V$–r,P‰lˆ ` 2v$w©XºtˆŠ„å–¬ŽÿÄ­›¼ÏowtÞêQ¢.>f@…7} MÓƒ‘»? !ì™ÙÃ[8WÍìÒÌN£(š^\\üìò÷uwí&“Ƀù|þÖÝ_…¢¦§¼Kî¾0³“$IŽÏÏÏÿ­óYÛ¾»VË?Â3{²Æùúp6_·@aw\çÓƒÁ;3{¾î©z0Îó|çúúú[›‡vW~¤iz`f_îû×_w/¢(z‘eÙ¯&ϩ쮷X,^nêÁÌ,„EqÔô9•Ý•£(zÚÍ‘zuØô•Ýu ÔÁAzåîm6Hì® „0èæ8ý !$-ž‘ؽ±¿qèˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@\eî~s¹Mî>oñŒÄî:ß:8K¯Bm6Hì®óŽ ïݧW7¨ì®óš¸éò´ÉÝ‹8ާMŸSÙ]ÀòíÓ'œªŸ²,ûÝô!•ݵþ H’äØÌÎÖ>ÒÝû1Þ·}Xaw­—E_]]ãñøkžç;î>±{þîþqww÷Íl6ËÛ~ŽÂîÆFìïï?^¾ƒöÐÝ÷îË Ýý&„pif§qn󵿊ên°Ù¸=¼¦mÝÍíá¶}7·‡¯ °›ÛÃWPØÍíá%Tvs{x •ÝÜ^Be7·‡—“ØÍíáåÏHìÞØß8tƒÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÛÃËŸ‘ØÍíáå$vs{x •ÝÜ^Be7·‡—PÙÍíá+(ìæöðvs{xMª»Àöøus­>iøIEND®B`‚olive-continuous/app/ui/style/olive-light/png/iconview.16.png000066400000000000000000000007001370472574300245330ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÞIDAT8Í’ANÃ0Dgb+hÔ]!â°à UÛÞ‘mÅ-è @"Ù¢†øÿé& ÆD)›þ•ígÏŸÑ7°°MÓƒqÀIâ{89³áÌ£ÙX0êà +°ÀäR“^{ ·¹šÐ?‹1±¿éô´_Ï×Ü´·ÀÙ¢Õj¸°—ÁhãF£q3™L"ð}¿¦µhØÎà—DÔ›N§ÀΉ~ŽáX¸ðkqwtr €¦ˆôí+ÐÌ'aæ}[‹H!@ÂrÚU¿‘R (\]6Ô…XW`\àŸ"òdŒ1ÏDàl‘ìATÃ0ìÑAü`<›ÍÞܦRêˆÚvÒ`™zž7´ûH™d |߯EQtÉÌ»i€ˆÄ"ò2ŸÏ_ݾR* ¢#"ª¤ñƘww ¶ì ­õ€ˆ:"’iÍ̱RêÊJ(¥f¾‘JODX­V§®ïoA;sò:"RaæGèXDRŸüGÎÖiæù™pSÝPçI2ëO} KR X1 [Q!@Â&DÔË)¡Œ<ÏÚF½^¿0B¾ŸšÅzVÀƒÒƒòÞ]\ÄIEND®B`‚olive-continuous/app/ui/style/olive-light/png/iconview.64.png000066400000000000000000000010661370472574300245440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(TIDATxœí™=NÃ@„gl‰—©¶Ê)"®Á%R#®@“£pèr d¹¢hwiRù¯1ëAò|徕fôiÝøƘ5áî,Ëû”ÒõìòÀ)ÆxlšæmêîÒÙ=!„]QO6sÃ8§”îÆ$(²‹î­‹ý`Cò~l¨Èî °ÏT@òvb¼xvOÀ_|wS¤”n&f‹g½€Uaêj,@]@¨ ¨±u5 . ÆÔÔX€º€ è\~"æäkl Èz§Ì%^'f‹g÷ÄΙ |’|*²ËîAÛ¶UU=“ܒܸš›LòÀ ÉC]×ïc÷”ÙÆcÖˆ×ãC¼÷z<^{=þ¿°u5 . ÆÔÔX€º€ PPcêj,@]@t¼÷zÜëq¯Ç1«áÆlj‚hIEND®B`‚olive-continuous/app/ui/style/olive-light/png/imagesource.128.png000066400000000000000000000043621370472574300253070ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÝ[oÇðs†”h‘t¸aä ²vfE“q ¤©eÄ1*ÄL“&¨mÄðåÁH‘®û9òAø!E ¤~È'¨ ¤E ´ª!Y—UÑ:uÉ€-˵œ“SA"2ö.wöBÎùzųí_Üáðì€1Æc6Âz ÑhŒnoo_ÕZ_€Œ%7,fÀcXB|^,?›ŸŸoõú¡ž˜žž~Ù÷ýp<βÄÜÎçó×———¿Úÿ€ØÿF£1Ê'è÷}ÿF£ÑÝÿ@W¶··¯Ÿüat¼sn¿§+k>B½ÎmWàé„ §®sÛ+<Û^]ç¶W˜E8–ãXŽ`9€åòQ ¬­­UM „õÇqœ¥(ÏçWËq,ǰÀrËq,ǰÀrËq,ǰÀrËq,ǰ\ä~ÛI) bMk}Lñc­õA!ÄC­õ×Bˆ%"Zô<ïIÚcí…Чf³™_]]}NQˆñéí–DtQ Þvç–Rꋹ¹9?Õï×€>4²çy¿AÄ7 à)D<ãyÞ‡ÕjõGq/ @HõzýàÖÖÖGð“>ž>¾»»ûa½^?hz\ýâ„Ðl6ó;;;—±ïˆˆwvv.CF.¿€VVVNÀ¥ŽH)O¨ )å!ÄëKž–R0X¯/€€±Á&|A„Ç Öë  ­µñûÚí6`P âK¦k !Œ× =†´0(ˆ¨dº¦ÖºlºfX€!"¥=@@Bˆ-Ó5ÑxͰ8i­¿„šaqBDº ·—|>ÇtͰ8Ñ"ì,ù¤ÝnUX©¯GW«ÕJ«Õú":ð""¶ˆè".ŽŽþkqq1õ—IÏóž8Žs Ï*y+ =i¾ä”R¿ò}ÿwBˆ“ˆXAÄ<±o´Z­ëŽã¼*ÀÚÚÚð¥¾ô<ï¯êD–JšÍf^Jy…ˆfà;–"â)¥ÔEÈÆåÊ/ 7‰èa¿ˆèA©Tº ™h Iå—êyÞ9PAžˆ¦¥”ïÆ8¤À–ËåOàË>ž~oddäóóó©¿ýÛ“x¦¦¦f¡¿Í¨_“R¾bz<ý˜ŸŸßò<ïO0Á&†O`Îó¼?,--=ˆup!%zmUJÕ‰h6B‰÷*•Ê××׳ðä{žwKJù!ıv»Ý«)t#—ËÝÑZßÉ„¯—Ä ”×ZŸßkšìÓX©T:·¾¾þgS㊪sbÿÙù8‰\*•JYk}G ”SŽãœ0P‡A2È—ËåKQúèöBü²V«¥þQê0ˆ=J©³D4a²&å[­ÖyÈ™¬k£X0555KD?©ü¥Ô/bªmØ ”ª !¢ÌøŸ‹ˆN»®;ç1†],Ø›ñÇQ{ÔZŸ­V«&›5­b<†güA¼°»»ûvBÇ:FÐl6Ïøƒ@ÄW³²J8hŒ`mmÍøŒ?„÷*•JêM–ƒÆXbžñ1V*•Î¥xüd$IÌøâUÂ" Á ¼JNä$<ã®ï¬f¡$ó"ÿ’’žñtD)•…KRæ í_ ¯3´^% d˜À«„Ï•‰vë8!â«®ë.­¬¬,ÆyœïÜß …/‘OD„ÿù{VîoØoè µþõøøøÿîÝ»÷Ètí™™™‘ÍÍÍ·|ßÿ¹ˆ ‡ˆ"ª´Z­¥ÔßVWWÿiß3ì—€=cÅbÑø*¡Rj|ssó€gßßD4#¥ÌÌî`{l ‘kr•ÐuÝ“ð[":âiJJ™™E3‹`f•prrrL)uEkýõÓ’öŠ”ò(c0ɪDí%TJ9¹\î:EÝ0êÌÑ£G§#Ö0ªtôÓK(\×%¢«ˆhâ#gÌårïOLL¤þ™…µJèºî!¥ÔZëYxÎD/¤B¡P¸”öf‘V®*¥êZëkD4Ç :È `6X¡Ø€g¬6›Í¼ëºïÑEˆû/TI)ߌù?Èæôì%¬Õj/­®®~¤µNr3çÓŽãôsÇtdV ãÛ^B×uOîîî^ëìP’´sRJ;‘‡’©U©”Œ•J¥óår¹­µNí­Yg{œ‹ŸÞ½{w;©ãò+ÀS’ˆ²ð¾üP¡P¸ ÞóÈÈ"šTJ%ö6 ƒˆè„”òµ$ŽÅÈ®w“hiãd— ¢ qÿ›9@†QÉ÷ýË333±µÝs²o|cc#¶[Þ8ƒ!¶Ààˆ¥‡€08bé!à ã=€cº‡€0˜Œõð§ƒë´ã8_E-¯ƒílÔ€fbc€å8–ãXŽ`9€å8–ãXŽ`9€å8–ãX.ò§Dô{aéàWËq,ǰÀrËõ ÀãÄGÁˆ];ô @¬Ûª³ôÑýßë €âód†Ã’ÖëÜv X,~·KÒíιýžžw—LOO¿ìûþ Heï:fÜí|>}yy¹ë>‚ž»QÝ¿ÿÑäääMß÷7ˆè8™ù߀,Çðo!Ä'¥Réã………iˆ1ÆcÙñ R¨ZN5@IEND®B`‚olive-continuous/app/ui/style/olive-light/png/imagesource.16.png000066400000000000000000000010141370472574300252120ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(*IDAT8¥Q»JÄP=3÷fÑÆÈ&¹\*j§XÙÈ">Àþ‚•_&[ bïZ›¤ÚFü€Ý;cá.tc²žê0sÎ0Çq?Š¢3,Édò`1Wªz·Œ€1¦g™™TeYæ]–³,{gfâeœë°m†’$Ùfæ#f~FOõ^«̼ND=UÝjLà½ß‘ª>–eù:¯ѳªBUß äyÞ!0NÒ4WUõ EQŒÜÿšnN¦Ó鵪š™cˆNПçÕøj½AD‰snœsY–ÝzïM?@Dι —D´&"»Þû½úLãg'mÖk"r˜¦éG«‹‚1óù`eN¬ˆ(AUoºªˆˆÚÂÐZáûÿ]BÃ/îaÀHzÄIEND®B`‚olive-continuous/app/ui/style/olive-light/png/imagesource.32.png000066400000000000000000000014071370472574300252160ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(%IDATX…í–ÏŠÓPÆ¿¯I‡ª£«0–K“¶¡ Y¹óbÝ(ˆtÄ.\˨Oàcø2.fá^ÄÅ  _ kǦ\vÙi“7™!´&ql›nüv9÷žûýrr8¹À†E°,ëÉ"bäbJ†"òFkýºÅöò2€ÈkŽŠy™ÇTs>ªµvÖéjYÖQü¹´1/ýXèeÔh4Z"rWD¶I‰È§Á`ð+€jµzi6›=FTUqIÀ‡´¼•}‚R©TŸ?ODšYy+Ãp4#égå¥~¥”cƃhtj­½¤½Zëoõzý§ˆ¨È<$ù% ±¶mKò<€2€'J©‹)gÍ<Ï{'"ïÃ0ü<™LÞöûýïY¬€ëºÛ£Ñ¨KòdD“,š¦Ùp`–¡µþše×BÚí¶éû~7zóyíÔjµ›§185€çyW …Û–e%®/ @²••Cr×uÝ­Uüë *û¾Àa<õÎ}u’?*•ÊÇ^¯7M;h™9p])uòë¶mÛÇÏH¶¢æ½6e²Ô 2Mó¡ã8lÛnx*"çâë$¯Z–ukmÎN§Ó—n º_΋äf³™xÉYz“Ìê#AÐqçòZþF$·‚ è*¥Îl R9š¤€ú¦´q€…‘çyW u\®IÓ8À>É0/çÈk?/¿TýæaŸÅö,jÚIEND®B`‚olive-continuous/app/ui/style/olive-light/png/imagesource.64.png000066400000000000000000000024041370472574300252210ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ("IDATxœí›OkGÆŸwvªÈnÒT!ÅÞ?£Í"Óƒ‹SêKˆCÿ$…¦Æqz+‡~†B¿B¾CôÔçÞ-4zwì•lz©i+ÓË^íÛƒ×B[»«]iTI¿‹„öyŸy4Z½3#Æ:{²°°ðÎþþþ÷¸¢OR_iø©\.?ÛÜÜ<ãìJ¡PøÀ:€¢&qƒ à£ÃÃÃR£ÑøDÇÅ=š´Ðk§W5ÑE{¬¢[Ô80öȸ€Z­æ BH¿pg«Ûõ±Ÿt ÐÍÄÝt31@·ÝÄÖ:QJ]°ÈÌ7‰¨ÄÌo‰è €W¾ïÿ“GŽ¡ŽãT˜ù)€y"š ¢Çyf~ê8N%aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<„IDATxœíœMk$U†ß[ÓQLjvº’@W.ÜϬD7ÎF˜¿Æ¿àŸðÌ(*ˆKW Œÿ@p¡«Ø©4Æå01ÄÔq“8tú#uÏ=çÞû>ûÜz»y¨<] `LÛ¶b½!gö÷÷ÿob !yB*‡T¨ P9 r(@åP€Ê¡•C*‡T¨ P9 r(@å ú.9¶¶¶^‘ßà@xy«ëº¬w<Âü Iˆ| ¯õÏ®ëîY8‹‡7E•ÝÝÝçܰÞ"ò%€ëg)^€£££÷Ð[XFQÀOü‹È×Ö#V¡œÅßÝ®ëþ²± Åà)þBw¬7¬J18zò÷Çt:ýÉzĪ!€§'î ƒø{D€ñwa²€ñ7Œì`ü #{ÃÈZÆßp²Œ¿Ád+ã/Ù Àø‹C¶0þ⥌¿xd)ÑÈNÆ_\²€ñ—ì`üÅ%+ñÉJ0þ¢“Œ?²€ñ§C60þtÈBÆŸYÆŸî`üéâ^ÆŸ.î`üéâZÆŸ>®ãO·0þÒàVÆ_Ü ÀøKƒKép)Ép'ã/-î`ü¥ÅŒ¿´¸€ñ—W€ñ—70þlp#ãÏ70þlp!ãÏ€ñg†¹Œ?[Ì`üÙb.ãÏSöXßƘ Àøó™Œ?˜ Àøó‰Œ??XÝNH.ãÏÉ`üù"¹Œ?_$€ñçÔwÆŸ3’ ÀøóI2>I&ãÏ'I`üù%Õ€ñçuÆãñ³p"ò=ãïÿ¨ 0nÂIü5MsÛzƒ7Rü ø0Á5Vñ7U¶··_ðšæ5Ö€ñ7Uú¾÷òÑñwjŒÇãËÞÕ:MøäïÔØØØ¸à­ó×OþÎGMùXëì5aü-@E€Éd²àªÆÙ€ñ·š¦¹ hœ½&Œ¿%hpIDÞS8÷"0þ–]€Édò&€—bŸ{ˉ.€£¯}ŸN§?ZðNTvvv^ðvÌ3ð±áжí=;‘Î{À‹‘ÎÊ€µ/rrròÆl6ÛÓ¾Ž#cÛÖC¸’â"MÓ<‘â:ZXÿ>1†T¨ P9 r(@åP€Ê¡•C*‡T¨ P9 r(@åüQ#„üÙhúIEND®B`‚olive-continuous/app/ui/style/olive-light/png/italic.16.png000066400000000000000000000005401370472574300241570ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<ÝIDAT8= Â@…ßþôÑ~Oá±K=”Xicá=l‚GH‚H™BI ÉØ¨¬ë®®¾nÞ¼ùA3‹î™Ç1@Ë%üId[0sODNDÔ†‰æQmÔœõ™¨Çò²,÷zÎ ¢¥6oÓ4½8|ß©^Ó4kSÖ‘%^û9$IrtAÐ0Ó€+Ó±PUÕÀ@±ò¢(vÎ"Zhó6˲³à—òŒ€_Ê{ÜË›k@kyo€º®ÇUm¿L9|LýÙ]óùüžˆ‘×(ŠÒ,ËÚ¡9£N@kÑùPÆZ»æ6 `ŒY˜ØË¬13"º ÑcY–Ï"J©€˜‰]¹Îs—Ì÷÷¦i6"ZëÀ)[×uý!à"_×>3}œäËóüI`jù¼0±|^òyHÈç "Ÿ3€”|Î’Ï @R>'Iù\Dåc¤åc¬˜Þ·¶mïD’$‰œ1½·UU}Š„a¸„°|Cd­]2}•ïg3¥Ô €£í5'L߀ÇoŒ‰}~ͬßìØµ¡¯ÃþùU]×y]vö~5Û;À7§WwÏ_Vx3IEND®B`‚olive-continuous/app/ui/style/olive-light/png/italic.64.png000066400000000000000000000013631370472574300241660ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<pIDATxœí›?‹a‡óFR˜ƒ‹XZì& [\+~ÁBmüÓûYìÄ€ß@°V¿‚}.d#’î«€«YÎã8³;ó·O{·3sÇ“4KP’ç9kgÄd³ÙÐU?mÒU©HÍ õ©¤> 5W~FÆ`6›0óåî_ãñøÎr¹<ÓÞÓú3¿‚^ü{‹?hYÀ|>?ðP;‡ˆçhY3?pS9æ[Y–Ÿ-îÚðÌ`ÌÀoƒ9ZeÙ'Ê1ˆèÁ9­ ¢—c>–eùÕ`NE+ò<ŸÂ&~o Îù‡VÑ(ãÇÌg£ÑèƒÑI­°ˆ-V«ÕO‹{Î]€Qü8„`öÙžè,âÇÌŸÖëõ©Å=‰*Àê›_áÁ9—ÏŽ5°ùæ+~BlŸM@×ã'DÐõø Qxˆ_µ#ÆPñb è|üs^â'˜ ð?ÁT€§øU»,‡yŠŸ`-ÀMü3Þâ'˜ ð?ÁD€ÇøU;-†xŒŸ`%À]üµ¯ñÔ¼ÆOP ð¿j·æaÏñ´ÜÆOh,À{ü„ƼÇOh$ ñ«nhòPâ'4à>~Bm}‰ŸP[=×.íBü„ZŠ¢8bæ^ÄO¨%`·Û="¢#Í®ÄO¨% Oñçù=÷•û:?á`DôB»¬KñPŘ™«—…ðZ;Ãʲ씈nÿç÷€cƒ}?ÔzÏp¿ßßÝn·ß v_Ê S·b-¸À´î“É$êK×þ•™A@êR3H}@j®½€¿ô óôðµ‹IEND®B`‚olive-continuous/app/ui/style/olive-light/png/justify-center.128.png000066400000000000000000000005601370472574300257530ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<íIDATxœíÜÁ À Á˜Jì¿*;IŠð!¸3ˆpûaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÁIDATxœíݱŠQ‡ñsf@0“b!©Ü!…,¤·Ð}ËÕÚw°]°YŸÃFL'>€… n‘2… “f±I³EXÁar-Œ­÷†ÌNŒÿïWßÙ\¸ßNHsPá›>0B'îþ(„phfwoa_H÷ÃÌ®Ìì"˲É|>ÿ²ÉÃÉŒÇã;ËåòÔÝŸ…²Mw‰Ûçî+3;/Šâl6›ýLz&eÑúð_›Ùƒ-ö‡ö\v»Ýç)ä)­Óé¼4³ÇÛî ­TUup}}ý1¶0ú‡Gföž×þ~q÷:˲'eY~ýۺ衮V«§þþ !äu]ŸÄÖE6˲‡Íl ;p[òŸ}¯`Ü=zvÑBf¶ƒ¶…ŠØ¾ÛÅ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄEp÷›66‚æ¹û2¶&å ð½½`BѳK¹#èS3ÛÁDÏ.嚸ÉúZìw¯ó<ŸÄÖEXß>}ÞȮЦ·eY~‹-JúPÅ™™]n½%´ås¯×{•²0é²èÅbQƒUU¸ûØøùøOr÷ÚÝßôûýÓé´JzfÓF÷×wлû!I߄®Ìì"Ïów)¯} ƒéáûéáøéáøƒéá☮Žéáâ˜3¦‡kcz¸8¦‡#ŠÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q Žéáÿ1¦‡‹cz8˜®Šéá`z¸0¦‡+bz¸ ¦‡€T¿uʸ=™öŽIEND®B`‚olive-continuous/app/ui/style/olive-light/png/listview.16.png000066400000000000000000000005441370472574300245640ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‚IDAT8Í’±Â@ ÷<_4ð@@¤ôHJv$_nAGò8 Ÿø2»º #€ZëÃö9JKkí>dáÎ\¦,ø›$­YPÒ ôá§Œ ”òÚü“ˆÐÖÀöSÒ!#°½×ï¤àÎa7gHZ² ¤yt9%Ò'S@'¼aIEND®B`‚olive-continuous/app/ui/style/olive-light/png/listview.32.png000066400000000000000000000007031370472574300245570ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(áIDATX…í•¡Â0Eï[ ˜Õ`jˆýŽ/A¡ç†æ_ø|Ä|ݦ0›ê’= ]º0Û¡WÝæ‰sDÛü{H—8ŽWŽf–™%¥RÊÆ s€ˆ™3}0"pùÀGâ¼€0‡\5$pq(pÕe¤K†‡ªªîD´°Iff)„8ÛdüVºuœ$ÉD)µ ‚`jضíCqÎó\ÆhšæDD[f¶É¡®ë%€=Ðk«ä~6º˜c‡ë«~B/à¼@é[¼ QêH¢x±|O¹Â2êÎňIEND®B`‚olive-continuous/app/ui/style/olive-light/png/listview.64.png000066400000000000000000000010461370472574300245650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(DIDATxœí™1NÃ@Dgl‰—©¶Ê)"®Á%¨W ÉQ8tH9²\Ñ´»4©¾­T°C’yå$ÅË‹ÓäƘs†scJiÕ¶í=€u)å²²Ó¯BòÀ6缆áuòzRJ«¦i,jVdWJ¹‰šø®ý7j$ïâ8 `]AFÉë¸Mûoþ¥”«¸Í=g…¨Ô8€Z@¨Ô8€Z@¨Ô8€Z@¨Ô8@ö"ž*Ÿq˜{¶DT¼Äa ç¼°«¢S—’qlã0Žã{×uO$—$—.ªèý$¿<“¼íûþMícŒ1æ?áóx|÷yÜçñ£þÍÂçñ@- ÆÔj@- ÆÔj@- ÆÔj@- Æâàó¸Ïã>ûaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( [IDATxœíŒeǿϻ»W{×Òk®¥¶··ïìöø¡ZЈi±*¢€R”€" ‚!"1 €( @¤,ÖÆh["ÖÔZ¸»™Ù.-EJ÷š^[ngæñ[ —Û»Ûwfvgïæý$—&÷yŸgß÷;ï¼ï¼?Ðh4FG(êjAggç$Çq² fÎÈÑLfn0@ €#4—MØ À!"êgæwˆÈ`°’ɤÙÝÝý~ýMm™ÈårG9޳€ˆÑÇÌaf¦"òìbæm̼Ùó¼M…B¡;LQ0.ÐÞÞÞ–J¥–X`3ψ(”ÿÑf"ÚT*•^* ïE‡oƺººš8p€s,Œ8¤!‘ `33?ãºî …BáPÔ1UCà ›ÍžàyÞrË0øÜìð!Ħin:˜ÑhXtttœ$„¸ÀéQÇ"ÚÂÌ?·m{}Ô±T¢áÉdN%¢ï81êX„ˆ^cæûlÛþ3Ž:žhH)çÑMÌ|\Ô±Ô˜Ñ-–e½u @ —ËMs]w]öЭak]×½-ê‘C"Bß$¥<ÀýÎE.Æ:BŽB,Ÿ>}ú@±XÜŠˆ ‘z:nO&“?eæyQøo4ˆèf¾Æ¶íÝõö]÷@Jyºâ²õöÝÀ´8¯µµõ;¾>«žŽëÖÌŸ??õî»ï^à’zø%¢ÌÜ‹Áwù=åßBBdæýÓ§O?ûöík&¢#<Ïkö<¯Àl 4 GDYfžRë˜0=hÆO6lØàÔÁ_} ¥œ à'ÔÐÍ~"zÀ&›-ËÚðž«dÆ1XÈÌ'£¶/¥þ!„¸Ú4Í=5ô ÈårG¹®û€Ö û>Ï3óÚ|>ÿ:·>*‘èèè8QñEŸ0-lD´ËuÝoìܹ³'켇ø©eæRÊyìå·†•'y̼ˆžniiY¿mÛ¶°òöCyêy13ŸGD‹Bʉ蛵|gP3d2™S…÷2sóةǦ\ñ/º®»¦Q§aÓétg"‘¸‚ˆÎfæ°:؇ˆèÛ–em)¿!ÔDÙlö Ì|g…@D.3?•L&ïëééÙF|µ&—Ëe<Ï»Ày! Áaækóùüs!ä5„Ð ¥\LD÷…Tù¯Ñͦiî#¶zcƱnaæù!dçÑa·¡  Á+ز¬‡„_!¢‚ïL˜ç0óÝ‹- ¼,.pG­©©ézgÈb«ëº ;h,ã…b±¸§µµõ'cðµ³f÷õõM*‹ K H)¸þ%>¼b÷îÝûƒÄ1)‹‡§Núœâ8Òg6ó¦M›¶½¯¯¯×o¾å÷ûwÂåÿ>›Í^ºgÏž~¿1Œw …¡3f¬$¢g}fADtG:n÷ƒßʆa<`>­mÛ«1þ‡xa! ø‹™ÏöcLD¯X–u!|L~ùj ø @åoœ2eÊõЕÿa<Ã0Vø‹cf>9“É|Ù­r `F+3¯0݇¿–J¥‹wíÚuЇí„'NON&“¿òys™yi>Ÿß§bä§ø.üU~žˆVèÊ™B¡pÈqœ+|[‰èZU#%d³Ù|IÕ ßc_cYVчm¬( ïÑ*%U[":_J©´ŸBEÄÌ·ø™ïBÜÖ(ëàǦin%¢«Ú•ëæF›ª+SJ¹Øç¦õ¦i>âÃ.ÖX–õKôaú‰l6ûéj«ÜÍWªFBD{‰Äj4ÐV¨qÑ ”:uÀÌߪ6mUR.„½zÌ|ÇD›Õ«'–e™ÙÏ£à¤l6ûÉjÒVÛT­¨ ¢WmÛþªf(ù|þ)"zMÕ®ÚV`L”{þ Uœ‘KD7C7ýaÀÌ|sù £Ór¹Üñc¥SåÔ`æ'Çë2®FĶíížVµs]÷ü±ÒŒ*€ÎÎÎI<™£jÊwÿ*6š±BÜ«Ú 8««««iÔ|G»X*•–@q 3?kY–¥b£›ÞÞÞ<3?¯h6­¿¿ñh ÆZQrŽ¢CN$÷+ÚÔ…\.—q]w)€.³‰¨™gƒK¬˜y/€Ý¶%‰—z{{óQÆ[ Ïó~–H$>¯ø2î/ŽtqÄÉ òQl—w¯·mûr…ô5¥³³s¦ã81óRG+š¿ADëJ¥ÒÃo½õÖÞZÄç)å)˜”˜ù”‘&‰FTR*•Z¢º¶Ÿˆ”;*µ NO6 c¥ã8ë˜ù*¨W>ÍÌW%“É RÊÕ3gάÇîàjP-ã€ÏŒtq´¦Diè ¯¥¥%ò“°¤”Ë’Éäf^Ò–îÉV677¯3 ãŒò D*•ú¡«"Z0Òµ‘@Ìü)'žx£&†±’ˆÖ„°£3™ù)åj„°šÚ/ÝÝÝï3ó Šf§Œt¡âÉårfªx`浊A…F:ž,¥¼»|×ײrÀJ)åÃ0>RC?£’H$žQ49²££cn¥  ‹™U›ÿýåýùQ@Édòv[š®Ê2f¾ ±dšæ": b#„¨ø¨(Ïó”š"zõ;œa†a¬bæ³"p}F&“¹:¿à2óËŠ6oêŠ "ÕyÿÍŠéCAJ¹Œ™£ªѪ;†WLßUé?‡  ülSÚ­BD›ƒ Ìœ9sšËNQž/H~0kÖ¬–z;ff¥2'¢öò«ý!Tj •Ž0Mó •` ©©é²¿ð˜¹mÒ¤I—ÖÛo>ŸÿU½©†™…çyÃv «hfV:¿¯|[]§}ÛÛÛÛÔ½ÐGBqYgg§Ò¨)<–’ç «ÛJwzN1S1}`R©Ô×ÊßÿñÃ"ú¡ëºgº®{|ùïL"ú_-37;Žs¡Ïx‚ º'p˜*M©žàé{c¢_˜ù³>ÌÜjÛöc¾+©»ü÷H&“ù*}Šû÷Ë1­ñ—o<Ï3‰ªï•? 5„a-©>Wë*€l6+¥h6@D—Ú¶ýkŒ¾%ÍÍçóXõuùÇÌ;·CÑ&(ªe?ì i¥G€ê±nO©PÁóÖ_ [!—4iF@ æhÄ-€˜£s´bŽ@Ìш9Z1G æhÄ-€˜£s´bŽ@Ìш9Z1G æhÄœÀ_ž”Rv‡ÈDa¼•‡nbŽ@Ìш9Z1G æhÄ-€˜£s´bŽ@Ìш9Z1G æhÄ-€˜£s´bŽ@Ìш9Z1G æhÄ-€˜£s´bŽ@Ìш9Z1G æhÄ-€˜£s´bN%ª{5‚ˆ|1ìCLèò¨$_ŸPoD˜YõÓ¯•˜Ðå1LBˆµõ §ö„ñ[&zy @ssóã¶×%¢Ú²½ü[1Ñ˃*¥œ;wã<àc5«6lO&“+zzzÞ #³‰\‰J©÷íÛןN§ë8Î^fn0 ŠŸ”€Cþ-„¸¿¥¥å¦;vì+c]F£Ñh&ÿdêmwçzÆIEND®B`‚olive-continuous/app/ui/style/olive-light/png/magnet.16.png000066400000000000000000000012431370472574300241660ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÁIDAT8¥R±jQ=÷å »(Æb‚“°Ã0ºX¥’Oˆ ‚E´6¶ØÙYlïh'XX¬Fò ¢…•n²,;³ËZ ²³óÞ=6Î2Ž ¹Õ½çœ{î»—'8&â8>¯ª$/‹|±Ö¾ ?êZ©a¶¬µÜ`kZà¥÷þÉd2ùöAÇWTõÉ ^cö‹¢8€ ®ªêM÷Dä«1fg8- Â0lAÐ#¹$"÷G£ÑçãVk·Û×<§ª·³,ûnÀZ»G²`ç¤fHÓôÉ$/ŠÈH’$ËEQ¼ð1/ß×ÑÑÑ–ÍfßWðfþ zîºî½ÍÍÍBÆ{"—Ë3™Ì|8Ñ)/}6‰|Ïd2+¾®4ÇqB̼o~D´ µG…¹5Âqœ'Ì|Ñ[§1C‰D"" ÁîåI …©&˜€Íçó“~zë.!Äp‰Î{K£~’™g’Éäï&˜ÒétN1S2bÌóÜA,;gŒy ìüÔ´ÖPã¶{ú›ú½ÔW)å³ÕÕÕ58¤Rj@7Xk¯ÇãñŒ1—}•wªš+¥Æ­µstzÏ µvN)u§€!¢Å”CÀîŽûBˆåj¢Ñè"ºËÌ¢|™Môööž¯±Ð÷:"·Z5Ý ˜¿#¢"°ìC0óhµzkm<Ы³à/`kkëWø3Mk­SZë€éÀÉNV+ÞÞÞN–Ý%f>âg÷¹ý%PÏàºîz%My{ûžÿÌò £pèmå ¥ÔJ%a#ÑHCÿ-€@ À(6XWIÿ_=|€Y"ªïÏäŽn¶ÂV3z|üý:%U%øëIEND®B`‚olive-continuous/app/ui/style/olive-light/png/magnet.64.png000066400000000000000000000034031370472574300241710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(!IDATxœí[MŒe~Þi§fé®iv»`šÙvÊ6!‚²Æ‚(¼@ è…"› ဃ¼5fƒ 4#&ÊÆ@êbH–îÎfwqm7m–ngÚ×ݦì~ÓŸi»c¤Ïif¾÷{Þgžý¾oæ{; ´poƒš@Q”6Y–W1ó f^  @'€û,*„¥Ü0 BD"ÒuýÂøøøífêkŠ¡P¨[×õ-D´‘™û8-RDt À™l6{jrr2Ö@™l€ªªk˜y'­cfG#¹‰(ÇÌ?K’ttddä·†ñ6‚$¬%¢½Ìüh#ø*ˆ.xttt°n®z:÷öö.6 c?€gëb?8¤iÚu«–‡©ßïß à€•V9€ €mg,™L[!¨y„B¡ût]ÀöºEœ'¢Ëù|þš$Iã’$Åý~êæÍ›Çår¹NI’”“âO0³·ÚDtÂív¿544”­å~j2`Ù²e™LæCUðÃáø:‰üQKžYƒÁ¾\.÷ mà©¢Ë`:ÞFoU›£j|>ŸW–åc¬:EDG Ãø¬QÏpEQÚœNçvfî°¸\,]Ñuýù‰‰‰éj¸«2 »»»ÝívŸ`æe '2™Ì{SSS©jxkEÁˆ~fÞÀU&ôª,ËÏ ߨÄYрœÿÀS¢3ïÑ4í¯J|€ßï_NDÔ2aƒííí;*­ ŸoØT&äL&“Ù9111Y‰«QH&“Q—Ëõ•Ëå Xj¦èºîI$?•ã*k@ x À~³v"úRÓ´}©Tj¦’èF#Ng‰ÄiÇÓàa“°•£‰D⪩Á`p €ã0ŸkŸhšö®Rs3ÀÉdòGdzÀCÂæµ^¯÷d<®K’)3ó«ÌÜnÒü¦ioÖ®·9Ð4í}oÒÜaƳ¾BÀZf~ZÔFD]×÷ÈÕ.µiÈ¥R©}FMÚ·¨ª*\Ä…Ñ^"™÷LNN¦kר\D£Ñ[Ìüî<Žç‚ïižªª>^fW÷ÑB=ê¬`llì µ1óêžžžÕs¯Ï3€™_0áÿ;—Ë}PŸÄæ#›ÍøGÔ&IRÿ¼k¥'>ŸÏKDëD‰èH³ËS@azµÑ“>Ÿï® Ö]¥*Y–·šTrâ†a|^¯¸p8,Çb± D´Àrfö¸ÎÌC¾÷z½ç.^¼¨×“'—Ë}êp8vcΊ™.—k3î<ÞÌD´QDȨ̀êý뫪ºizzú€fÞÂ̽ژyQáx+€X,vVUÕrož1>>~›ˆ¾µ1ó]÷X4@Q”¶BsœNçÉ:ô8TU=È̇™Y©"¾‡™«ªzeÞS*ˆÌ4÷)ŠÒ6{RL Ëò*ˆ«·ÑH$ò§U!@à•2 «)˜y§ªª/[Í;22ò;‰¶Ä.I’³'E˜Yø* à<,¾î†ò+} šúUUNËjºM%I*nëK 貕ìápXffÓT 8‡e‹}/™\/Þké Š"‰(b%s,ÛÀoÂy™_Ìd2}™L¦O’¤Ýfy˜Y‰Åbë­h`ÆY4 8ç‰ÈË<¤‘f1¹P4]s:ÛæTkΆB¡AÃ0¾0‰ëœ¶ A¨ˆºgK§€pç—Ïç+–•L’×”|>ÿލTU¸ön-\•Ïç“¢ëÌìž=.nA,ººº¬Ö÷–ˆ.ÎÌÌüjÖ!•JýbÒô€fÚ…«oe¥.—¢\ÁÔ¬œmÆU eêÅ"åÿ ZØ-Àn´ °[€Ýh`·»Ñ2Ànv£âçk@ÀÒ§'F³tÜó# e€ÝìF˻ؖv °-ì`7ZØ-Àn´ °[€Ýh`·»Ñ2 ä8±ùªÉ± :J ¨ç; jQMŽÕQ4Àëõ¾;ÿ&üI¹N$+ä(‹ÿŠŽîü Í[Q9 ;0IEND®B`‚olive-continuous/app/ui/style/olive-light/png/new.128.png000066400000000000000000000022241370472574300235700ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(²IDATxœíÝOKTaÇñsžQ!Áh3HMÃ0`…Ü÷â6¤M‹zí³e› Z"´ñ-´Zú‡JÒEµD½ É<§I vŸÓ½÷ùý>k=ÏÁùrgð:ŽáR˜*ËrÑÌD䶈\ñ>3‘cyofk333¯777Ô½׆ÃálŒñ…ˆÌ{žól«êý½½/u/’Zð\ÅT&¾ˆÈ¼™½ê÷û7ê^$5·Ê²\”<ü_ú!„•Ü"p àô9?7ÙEà€ªÞòš]³~§ÓyÕëõnÖ½H žW€i¯Ùu3³ÞäääJ¸»\"`䨨í0€ÚH¤­¸ý*x0ì\æëÍì¾Ó*PÕ—ÎóG'''÷F£ÑgÏsRá ±¶] €ƒ6EÀœ´%p3UøÞÞÄÄÄr“ï0€sÄ‹H•t¾wÀÎB8ÇKR!‚&?0€ È9pA¹FÀ.!ÇÀ%åø9EÀþQ.0€ rˆ€TÔö@mŽ€$ÒÖ@BmŒ€$Ö¶€ƒÓž¤¸•< ®§Üí,à$„pc\ªˆôEäyQS©ö:‹8JÁüáááÝdK1á58UÿЏÓ館aAD–+ú ^Z@UïxÍf-àùNkŽ€cà8®{& ÀÌ>Õ½C“À ªoëÞ¡Ix'"êÞ£)àˆ1ŽÇãñSa"€ˆHáHU—bŒÏTuC€_ÂÞ ˆ1ŽUu=Ƹ^ÇùÞÿ©ä¢ ¯ôÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p ÇÀ1p \c>=¼)Ÿ¦†Wp ÇÀ1pn¨êw¯ÙhTõÈk¶[föÑk63Ûñší@aÍk63sûYº0==½*"Û^ólw»ÝU¯áê5XDd8ÎÆ_ˆÈ¼ç9Û!<ØÝÝýêu@Çk°ˆÈþþ~977÷¦,ËoªzMU¯ŠÈ¤ç™mwúâyÃÌžw»ÝG[[[uïDDDDDD9ù ¯b4 -½(IEND®B`‚olive-continuous/app/ui/style/olive-light/png/new.16.png000066400000000000000000000007141370472574300235060ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(êIDAT8í’1JCA†ÿ™'‹€`¥`Ø}M: –)¬<„Á‹X VAâ¹Er%`ùàu©Õrÿß& YòXúU3»3ß°ì6„Î<8Å."9kÛv¾%$èè‘ ’nÝý-„p×%ÈÌININÝ}¹9[˜”$%A‰Wï&1Æû£’nH~J¢¤—º®ùwmfIÒƒ™eH^h;$WÆ97³€§£ŸpˆÁö¾QÒ€ªT,é2ïÞ ¥ôãî0³Ç®©$¿s¼£‹1^§”ú‡š«ªújšæ#ç¿[[t`1IEND®B`‚olive-continuous/app/ui/style/olive-light/png/new.32.png000066400000000000000000000010571370472574300235050ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(MIDATX…í—¡NÄ@†ÿ™äqUv 9…»'@!‹!< 8<êr‹C] $¨ 'Qœ&Ý¢”]ºÛ6`ú«vfvæËÌ6Û„¥Æ˜}›ÿ7‘,UõÖ9÷’_•„ŒÆ˜C’癹ÞHž,—ËÇœE±oe€±ˆ\Ykwr­5ˆÈCY–O!ŸªÕL#ïý¬(ŠäN4¸‘»ˆ¯ °°ÏN\¦BÄFÐF§"²úzNGo$_IV!FÞûyDŸhÑ+@â¬1³Ö¿¬”M˜$™×@ª¯c’{.êëºvà=#v=dìཿ΄ø¡N#‘ÉE̯ª»$ËÑû&ÌÕ0 À0ü;@Êq<‘¶gþ¤3É)€i›êµß² b#Ⱦd&(˜3x9 Ƙ’Û}TVÕgçÜ €æ–üµ>ëÚ{„oyz;IEND®B`‚olive-continuous/app/ui/style/olive-light/png/new.64.png000066400000000000000000000013561370472574300235140ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( IDATxœí™±NA†ÿ±ÉQàòHeÉ;§sZDÁ ž€.tñ4ÐD±@7 µ„¨P$^À_[®ì&gn— çÄ$·÷¯a¾òn´óëÓìíéøàˆ¦¸Ûí~šL&GÞûo>È3pÝh4΃A`ýWÔ5ÅI’ø`#LløšeÙ—f³ÙÇy > jÊúÝ )^³=N{ív{=t#­€c¿Ùʲìgh Z•R…„¨á%¨NV«5\vÝ{¿¯n,r¥©÷Þß%Ir0ÿh{ý<jbpÿ·"²5ŸÏt:¤¬fÑ ‘sù]PRêç\àW‘„2·Ct€j%D)¨NB´€j$D-/!zÀBÂ%‘+!œs"r ¶g³Ù¡fݵÿ‹U>E¯ÈÞû·,±àä­ýVfljŠß£Lcbï4ι[Vï—Ђõzý&ÏsÔjµ(÷m™Ð8çré{ïûÿº†ö£Ê2ì!ÈÀư°1ìlL;ÀÀư°1ìlL;ÀÀư°1ìlL;ÀÀư°1ìlJù=^Æoj~L€²~$E¹aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(RIDATxœíÝMleðÿ³Û*±+ìB1*3H )¢d/†DSC„ у.’€ÆÑ…„ƒ¨˜xSãACà$z@$¿’*†piüÀðÀÎ6µ€mÉ4¡±v»ûx âF>vf™wfwæÿ»²ï;ÏvÿyÞ}’ """"""""""""""""""""¢ö&q<´¯¯¯ãâÅ‹ëDäI(¸WDþðs­VûnáÂ…§*qÔg’ã8ËUu€5ªºDdÀY9V*•.DYOä°mûiUÝ à¡/½$"û]×ý*ŠºLëíí½grrr7€Íªš¹ÕkD¤àhWW×ÛƒƒƒÓQÔe2–eí°5àºãSSSû®\¹2i¢¨(ôööÞsíÚµƒó¹ä\.—ÛE²¦ð/Û¶wØÖÄÒÏÌ›7ï—‰‰‰Ëa×…®®®½ÖXÒS©Tòžçõ*é†H0Ûö÷ÜÅs<—Ïçÿž˜˜ø)¬º¢à8Îrï `·‘•…BákÏóÆÍTvÝ-Ï¢0‹ÅNU}=„­:ì²,ëðÒ¥Ka¿H¨êmÏüë2ªºÙDMõŒ`llì)Vˆ[®©V«'Çy<Ä=Mò{Ö㑵a頻ݵZí mÛ»ŠÅbgØû‡IU{âXë—ñ¨êƶU}i||ü3Û¶mCÏܘÖúE0z^«êJ_ض½Éäs’*Šp_ÏèRÕý–e}°lÙ²¹¦Ÿ—$Ʊu333',ËZw!í"i€ªöˆÈ1Û¶·#ï/l‰ü©jVU·[–u¨fqHdꬩV«'mÛî‹»V•ô@Uç«ê'–e½Ùê3ƒ8$>³À–6˜D.-À™Á­¤*gÿ—ºÔáÌégHé›®—ö™AêP'•3 Ng ÀÍR53`n#-3àÒ03`üIìÌ€ð)©3ƒÄ¼‘($qfÀ4'13 II™0w§íg @êfÏÆ]KP @Hfgï/Y²d/ÚèçÚ6…¶ yѲ¬Ýq×á`ÆÇqžˆ»?CTõ­¾¾¾Ž¸ëh„0DU—J¥–ï €Yâ. À¬qÐ`ÖƒqÐ`–Æ]@# €Y—â. À¬Hïo3³¾Œ»€FCDdØqœ3q×Ñ`†Öjµ=ýýý3qÒ`Æ¡¡¡¡ã. |‡Ëåò»qáWËÿgE»‘Iû\×=w-A0!‘߼꺮w-Añ¸; àð‚ žoÇ`hšˆ\ð†ëºýår9îršÆМ³Ùlvƒëºýqr·Ø‘*€\×ý@-îzÂÀø$"êúZ¹\n«¿YÔNuttlLÚ‡°ÜQ»Þíƒ`n£ïöAð¸YÛßíƒ`¨“”»}ìÿIÌÝ>ˆÔw€$ÞíƒHu’z·"ÍG@bïöA¤®¤ánDª–»}i9Ru·"ñ wû ’ÞRy·"‘ íwû ÞíƒIÚÀ»}@Qt€)sL>€wûæï"2nøçEd#?ü怪ž7µµˆ|ÚÝÝýB©TjåûÝ_1­õ%Šð­=¯ŠÈˮ먄½˜Dä8ÖúÅ—ÀÓ®„µ™ªž™žž^ßFwûs1­õÅx\×Êd2ï…°UÀ¡¡¡­###c!ì 9*"g"R‘£&jª—5ýð<ïB¡PX`U“[”³Ùì6×uO‡YW<ÏÏçóÝøÞEäˆëºŸ*ë†HžçýP(ò ¸ôøÔÔÔ+ÃÃÃÃ&êŠÂâÅ‹ÏNOOôø\r.—Ëí­š¬ ˆ0Ôó¼ï …ÂïV¸¿Áë/‰È®r¹üñäädKÑkdtt´ÚÓÓs²R©äEd%®ÿ¥‘›Ì¶ý#¹\nÇàààtµÝ²ÓŠÅbçØØØZY«ª«DdÑì?]VÕ_3™Ì7óçÏ?Õêßð›á8ÎrUÝ`ª.pVDŽ•J¥–ÿÕrDDDDDDDDDDDDDDDDDDDDDÔJþ´wL¿hœIEND®B`‚olive-continuous/app/ui/style/olive-light/png/next.16.png000066400000000000000000000007371370472574300237000ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ýIDAT8űJÄ@†g²Û, á¸4H^àÀÊWÄÖÒ8| K­¯+9¸Â°µ´“$X&ͬc!®Ùîþfwçÿ÷›Ù8¶Ôðçù‰µvÕ4M=βlDZ­ëúë· ÌüEÑ Ý%Ib}€snçœÛ k"’÷ÛKcÌžˆÖž¿‘Eà…Wˆø˜¦éf*§CFQ°!¢S­õ-3ÿËɞΘy;fÌ5𪵾3&ÿ<EqßD4€ˆŸ"rS–åÛTÿ ïýúÜuݹˆxNжí•1fYUÕÇX7¥ÔÅÔ4ÇÑþºQ92Ú»IEND®B`‚olive-continuous/app/ui/style/olive-light/png/next.32.png000066400000000000000000000012141370472574300236650ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ªIDATX…í–!HA†ÿ7§àqÍ“ÇÌqUD94X ‹`S A bR,V›D›`QÑ(˜£h>ÞÆ g6Üú[.èy»îz§[îO³oæýïãgX誫”%Q›…BaÌ3,"/ªú˜ÄØ9×'"s@òZUýVçz" –In7 `­½ô}·Z­¾Å ¹Or¦ñ9 `­Õ9a°ÚTšÏf³·ÖÚÑ8¦CÖñ ´€‘sçÜú½À×tC“þÉä›HfH®[kOK¥Ò7ȤJ ðIAÜ8ç¦ÒÉ~’ÇÖÚr¹Üûï €¥Z­váœsiH¸rÎ-&é ½¿„ÈØ³Öæâöt,&­¤ "õTHž¥ "o"²éyÞIÜžŽ]By°¡ªš¤¯ ÀY>Ÿ_H:h3y°¥ª÷žçýÊ£2™Ì¬ªÞ·á‘< ªê€÷v†GˆÈ+Éþ¦²gŒÙ¨T*Ï1¼ëŸüCÿ Q/¢£¦Ò¥ïûs1‡À]Èú‹"¥Åbq<‚cÌÓ_=J»ê*u}þ{œ¨âÉÅÕIEND®B`‚olive-continuous/app/ui/style/olive-light/png/next.64.png000066400000000000000000000017711370472574300237020ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíš?hAÅßó"•˜x r³ùS&…¤òOa‘FBÅNb%!`§i,c¥©Œÿ:Á1‚Fˆ"6*ìâÌa“"r98HrŸ…§Ä˜‹;Ëîì™_¹3ûÞÌã[æcXÀãñx<ÇãÙ•0ê‹…Ba€ä0É>Y#¹X«Õ¦‹ÅâBœ Ü¥T'€q’§@DLc¾ÙjE @)5àjƒáÙjµ:±¼¼\‰¢»À €ƒ[†ÊÎÛ†°Çv…Ba7C­­­s]]]}¶Ú!Ç¿›GýÙ¸­˜u$¯„˜¦jµÚL#Q<þã*ÊX#¢ÐfžˆäDdD)õ¨»»û°­Ïº¢Œ5Â:ÙgùÊÉçAœ±õrA¬åÙ9$"÷”R7úûû÷ºð ‹“êÀå•••§A}wÄeéð,‚K®½·Ãy "ûEä–RêNOOO[køM*lâìúúúœRêxZ H;ˆÈ1’O’èÂz@r=C2À&œ÷ Y ÀyϹê8ë²€¿z†¡¤<2ð§g˜ ‚`, ý–$D“@D®)¥>Å­›ù ØÂpÜ‚Í@ì·LÍ€Ä-ØT\Œ[³©ð nÁ¦ €ä]­õ›¸u3 ’¬˜ÐZÏ&¡ŸéH~0ªµÖIydõóùü…$7d°Hþp]k=oŒIÜ/kð.—ËÓZÏ»2ÌDÜ0¥µ¾  æÒ;õH~‘1cÌÇ4üÓþ^´´´ ¦µy ¥ Húl·Áy.Îv\~ÎÎvœT€ë³Ý†(P²œïül·!J|p"ļ5·1÷ãEÉÕF‚\µÕ‹RCÌ1¹\î¢1f1ßâˆÈÛ(c°ÀóŠäÔSf«ÕêàÒÒRì·7u&ñë—¸­”ëcV䢬 T*½ïèèøL2 ä:É"r³X,NW*•µ(ºa(—Ë¥ööö—ŽaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ýIDATxœíÝÁkeÇñßóNì†H ,!Æeˆ•¸Ò½ø7Ô£/꟡gãÑ‹PrJi=ä_ðVèIº V1h…BlvLi2ïãÁ-¦163Ùy;3ïóûžgßyÙýðîdwóÀ³›„>Á`0˜É²ì†ª^pÀ¥Ð笨C?«êÆÜÜÜwÃáðyÝ QPiš.xï׬„<ÏkhKD>ÛÙÙyT÷DªÎ…x0ÌDòâÀŠªÞíõzoÕ=‘ª  ˲ˆãÅQÏ9w'6ÁŒßóc+:ÁˆÈ;¡Æ®¹^’$w—––Þ®{"Urè„»îTuizzúN ‚ˆ½XÀÅ€€&¬í ‚ÚŒ€*ª­‚}Üï÷-s¼ª~h*/%"ßïèè蓽½½ßCž§ª¸T\ÛVP›@ Ú‚€ÎIU÷&xìÒÔÔÔí&w@çä½ÿÀ$tþî€ÎÉ9wçù*&@Ðä·(PÌ `±" €ň€J¸@1! €  ˜ À„µTP›@EµTX@ŵ hŒà«*¾Jî÷û‹UÎít(çÜSïýê$ôÜ 3UÍët°Š¬|\Ù¤N5jàXšôWÄI’T1‡ënO<ÐqhA"òn¨±  …üOk0ŒgÀaÝhRæ¨êouÏ¡I™ "?Ö=‡&eÀ}ëžGS2À{Ÿçyþ5ˆ€Aàœ‰Èª÷þyÆf¿ ðÞç"rÏ{¯Žó‡Þ©¤h&Wöo¥W€Pûÿ;ç>¬bUÍs?‘'UŒs¥¤iº0½¼ˆ$ª:Ÿ$É|žçûI’lyïóºçÕÔ ¿´qÿÿ$I.‹ÈU™®{.M­0€¶îÿ¯ª³Î¹÷‰àì hóþÿDðÿÐöýÿ‰àìʬ­ßÿŸþ›¹Ïˆàå̈àd&Dð"³"ŒˆÀ<À6gœÈ"8•5fôªTuVD> vK%¨j©ã_q¦CsNg}8>/3.W€öw À5ïý£Ñè‡4MÊ<˜âjÅ{¿VfGˆ¯R;Š@„‰ÈGE%€‘+E%€+óÛ 0ŒGÆ#ã€ñÀx`<0ŒGÆ#ã€ñÀx`<0ŒGÆ#ã€ñÀx`<0ŒGÆ#ã€ñÀx`<0ŒGÆ#ã5f¯`U½Y÷,ÆÀx`<0ŒÀ³€c›JDþ 5vHŽm*Uý#ÔØ!< 8¶©D$ØsÀ €Ý€ã[iWUß 5xaxš‘YÁ$펟ÃRŸØŠHVôØÂTõ—2“?fÀ¢ˆü`¼0,Ò3Ûãçlqü–ªÌkUX–snÃ{­ìdL©êÕ <ÎjoHËÞWðdªºQôØÂ+@§ÓY°u¡±×ÙV·Û]/zp©[c¦iºà½_Ã?x¬ym9çnnoo?.ú€¤ÌèûûûÙòòò÷Y–=‘Ë"ò&÷Ømjã‹óªz«Ûí~¾¹¹É?¿cûyú¦­—ôIEND®B`‚olive-continuous/app/ui/style/olive-light/png/open.16.png000066400000000000000000000010361370472574300236540ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( gŸ€³1ɘ`Œsà8›L&‡ÿ-HòÐöç$Nr:N÷æµµw¿Jꓼ”4—aû>0û%h­=ØÞ-¥Ü²í$_’Ïm’ö€W‹/¬ ÖÃ$Û’¨µn]­•RÊݾﯓ|_6â_3°½^k} i_Ò¾íÝ¡ôb˜zeØ^—t ÖÚ L%Ý.ÿõ—ró‚?2H²%éÛXs’Í¥‚RJ—àhX—²ÐûS éð øô+¦®Àޤ÷?…ƒÅÔ¨>IEND®B`‚olive-continuous/app/ui/style/olive-light/png/open.32.png000066400000000000000000000013021370472574300236460ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(àIDATX…í—1oÔ@…ß‘R„4H¤8³n ˆD~E€’¥ä—@GOÑÒU„øA€Des4ˆŠ¤$ÚyäN‹YëlŸQš{ÕzfwöÓÌî¬Läe!„=×[üIR4³wUU}í2?sÆÂ}IÏzÆú)i:~ê³ÈZì7zn[$_–ey»Ï¢µEH~ˆ1~ÎùÌìaôéîEQtÎÄBÇ$ß·øR€Wñ'/ºB´•`ˆž<9w.Çh’~HJ!6ÝýpĘ1*@ñ´qP–eöfu9„Dò°’~nIº àysݲ8ë1÷Jθ€»¿ê ñÒÌû¿¤"±¯“¼ÖX÷ËÝOII:j nfw$=êBØ›õ’dzšÙ†»ßÊŸºû7’júú(-A¯þO²0³‰¤ìƒ6 ·Æ€Xú’,H^&yšq¯Ï’ŠÂcßëº~@£€™mØÎØ7bŒ3ÐRÒ! ®ë×Àè„5?o0× `°¸p€…0Æ81³8$xŒq²4€]wßÐEÙ¸û¥±7j‹™f`þgKrGÒG’ƒRß”¤5’;Ù½#C÷$ÝcÓ6™Ù—ªªÞâü9þ [áÁѡʕÒIEND®B`‚olive-continuous/app/ui/style/olive-light/png/open.64.png000066400000000000000000000016471370472574300236670ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÅIDATxœí™¿nA‡³¡˜"Òá*’ Le$ S¥à O@ ƒ&ixÜZBT‰&Eª¸ $ÿ!…-!ÎöEˆ…â;Ë·7k|_¹7ÚùùÓÞíÝXqHR\¯×ÏõûýGÌ| @ÙAž€f©TÚ?<<ŒÌ?C )Ãð1€]ënâ`Àõ8ޝnnn¶ºÝîÄQŸ)FXÛIŠY¶ƒA£Z­žwÝH*ÀŲO„ˆ¶â8~æZ‚T@®ä!Ák€{ ¢] R©´“Æ™ùޏ1ÑkI=3¿Ãð~»Ýþ)í5ïWÀ)®V‚>¦] ¢­Ñhô´V«…Y5óN='¢sJ2Ý"½`­x9OB–·ƒw€|%x)ÈO‚·€|$x-p/Á{ÀTÂ+8Ø"—BXkÇDôs$؇$ó®ý[¬ì™÷ŠÌÌ‹L±àÉ¢ý–f¸$)þˆÐÐUì=EM€µöVï?Q{Aðv2™ÀsÂû6KÔXk'DÔbæÖßÎ!=TI"Q€ôüßscšãñø+€oò˜îHÐëõ¸—e#kícÌef¾h­="¢…6uפ=ÿQÙs…™Eç‘®Hàôüß' jÛ /Tß} þ*¬-A] +Á›Ïa"*A zø¦}Ÿù« EÑÞÁÁÁèl­+À1e»¿ßmfX§ì$ ®’€Ä®UH!@;€6…íÚ´hSРM!@;€6…íÚ´hSРÍÊ ÈäT˜™ïf1+¿ Âúc')2„ˆ¾Kê¥> ës‡™¿HêÓtRÆk>ÁÏ•pŒ“lµ”뉿)M@3e| À5¢hù°“li;Û›¤ÁDQíh }%,(ŠöµƒxÉ/ù±ðܵ@ÙðIEND®B`‚olive-continuous/app/ui/style/olive-light/png/pause.128.png000066400000000000000000000015531370472574300241200ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‰IDATxœí×1NA‡ñ÷@BA»5r³Åæˆ# ¥‡6gH)×HÓ“¤B¾ÀT[…Æ [–XÅ“ÆQR$"#fw2ù¿Ì{FŸÞ 3P*Ͻ@Ó4g!„+3»!œšÙqä[w4³{w¿íûþ!ý–?•¶ïs²жíÑf³yof×!„ƒoºûÎÌæUUÝt]÷”âÍJÛ÷¯wÈ1´mÛ£õzýÑÌÎG±¨ëúmª?jiûÆ8œz ™YUUÌìrijaNV«Õ—•¶oŒÉ/Àþz—êŒþ‰»ïÜýÍK¿±¥íkÔõ;!„dßÐgæ„®¼SÔ¾±&ÀÆûŽŽ5«´}£ä¸³’f•¶o¬àUa³JÛ7JŽð!q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâ@ˆ#q ŽÄ€8Gâr°-lViûF™<wÿZÒ¬Òö•ã, ›UÚ¾Qr\€¹»ï&˜³s÷y‚wŠÚ7Öäô}ÿ`fSüÐù~Ö‹”¶o¬,ÿTUucãž»Å~F¥íã0ÇÐårùm6›}†áÄÝ_›™§xwF?Õuý®ëº§oš•·oÔ9†þªi𳕙]„NÍì8ò‰­»?šÙ½»ßŽ}FKÛü¿¾D`õZiîÈ IEND®B`‚olive-continuous/app/ui/style/olive-light/png/pause.16.png000066400000000000000000000005131370472574300240270ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(iIDAT8íŒ1€0÷˜‰( B2°€", T(x)ž&a2éè€a«û›û…×£úˆ1Žî¾AÒnfSîWw€$i6³­üt°@~ É!o.ZÁm~Á$í¥¬rÊ›/qPgð\J•IEND®B`‚olive-continuous/app/ui/style/olive-light/png/pause.32.png000066400000000000000000000005211370472574300240240ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(oIDATX…í–± € O‡Ð’]œK+œË](e ‰!—Xù®ãq!WBüîéÒ97+0dsæÂöÖÍé þö éìÝê€Ñ°[Üê€ÏQ€ (@¥€Ý°[Üꀅó[•ÓÞâ !.î¾(¨oT™IEND®B`‚olive-continuous/app/ui/style/olive-light/png/pause.64.png000066400000000000000000000010041370472574300240260ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ("IDATxœíÚ1JA„áz & N&FƒçÐcxƒ9ÆÅ˜è9dn`ƒ÷N`ÐC7Mþ_¼¯¶(˜¬%ÿQôÏó|'i‰ˆ‡œóeñ"Ž9ç7I‡u]?œ¹ÅœÖí䳤ë'IÒãoeGåÖœµmí/©í·‹1·¨y€ˆ¸q3*·¦y€œóÕˆ›Q¹5=ŸÀŸÀîn à.àÆîn à.àÆîn à.àÆîn à.àÆîn à.àÆîn à.àÆîn à.àÆîn=$¾F܌ʭéy ñ>âfTnMÏ'pÐ÷¥½ÒvãÊ-:o=L)}NÓô"é&"n%]”~GI¯’žö¼ä• ?àcp¶.OnIEND®B`‚olive-continuous/app/ui/style/olive-light/png/play.128.png000066400000000000000000000030041370472574300237410ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ("IDATxœíÝMh\eà÷df¢ ØÜI*øÓÞºéB«2;2nÒVjÕ…¢ VpW*ˆ-¤ZÁ‚ ]êJ‘\nâ$E„`¥»àOÝÒæ›!¦LÊÄRó3Ç…-„Ð6¹é½sî½ßûl“ùî™™—sçœ@ """"""""""""""""""""¢|ën§^¯—/_¾¼_Džð€À}"rÀïÝn÷çíÛ·OLMM-ÛVš™ @EûTõ€ü꜈œrÎíE]E•¥ô…axÀ›17ÖétNÎÏÏßH£¨¢+YpKEÇÞÂCwW*•¶mÛöÇââ╤ë*ºLàfÛ?qG<àåKª.˜ßjµZ¥ÕjM:ò|¹\~÷Ò¥KW:¯ÐÌ;@ÿ^¯'xäU}1‚‹ív»™à¹…Ôg]€ˆŒ$}¦ªu»Ý¯¢(:^«Õ*IŸ_$æPÕ'R:ZTõ­………o£(ŠRºFî™@DJó|U}ÀwQ½–æuòÊüC`†Ó=¼Üx¥Ržžþ»‡×Ì4óÐcûWVV¾ÃðiëB²Â·@U‘o¢(:Ÿÿz^¾ªZRÕ#ažÞµkWªŸA²ÎˬñÌêêêQÕ­ ±â{ ªUUý" Ã÷}Üx€›À!w À>î |ÛÄáÅ΀àμØ0wáÃΠO*IEß0›WÈCw @|…Ú0[T”÷ÉÈí΀ ¹Ý0 ÉëÎ 7…æAw @:r³3`R’—®Ìï €X³3xɺ–õ€QÕTõÓ;w~€ ½î™)Ä"òF†£ÖuÜÂØ84<<ü¬u`FU?ª×ëeë:#ªúèÌÌŒy`l°.€°µÛºÀÖÃÖ0¶ÔºÀÖœu €­‹Ö0¶~°.€0""³ÃÃÃç¬ë`lh·Û=199¹b]`ãt³ÙüÕº€°p¦Ñh|l]Ä-æŒð…ˆÜpÒ97f]ËZ @ˆÈ_Ž:çœu-ëñ.pfppð•,¾ù;@jDä€÷œs“Fúœ;bHÇùR©tÀ97i]ÈFØ$"«>wÎ} k]Ïf0 ‘YU}§Ñhäê;‹x HÆx¹\>˜·7`¸'Yíã`¶(˳}¼Ä—ùÙ>v€ò2ÛÇÁ°y¹™íã`Ø@gû8€»Èëlow–ÛÙ>v€uŠ0ÛÇÁ¬Q”Ù>ÞþW¨Ù>ï;@gû8|ï…œíãð²}¶Ã»ø0ÛÇáÛ-À‹Ù>Ž,t€€ûÓ¼€o³}æ@DR¾Ä9È7ÿöÌ ªÒ:ZD¾zuffÆ¿ùn“JÖAÐ`$É3E䚈qÎ}=77çõ§ü˜wæ“:LUÏ---=ïól‡yh·Û+Õjµ¥ª{ïñ¨eŸ4›Í¯_¿þOµùÀ<Ðn·/A0`Ïh”J¥Ãι‰$ëòA&ívû— <ó¡cNçíÙÙÙÙ4ê*:óï \/Š¢}ª:Šÿ‰âœˆœrÎíE]E•¹@­V«´Z­QÕ="òÈÍ]QÕ?ûúú~ªV«ãSSS˦…™ûÄGøùw˜nIEND®B`‚olive-continuous/app/ui/style/olive-light/png/play.16.png000066400000000000000000000006441370472574300236640ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÂIDAT8c`hÀŒ. ¢¢ÂÇÍÍ-óéÓ§÷dÀÇÇ·‘‘‘1_@@@Žƒƒãèׯ_ã3€ ]àÿÿÿ*Pf''çVyyyC’ @3L†‘‘q…‚‚B.µx €Âüÿÿÿ“þÁ ‹Å!€ÍP©AÝ÷}Òá@ÌOi¥RY7Ƭ8Žó‘ö§4'Ç:ßðr|AÊÚÍýIEND®B`‚olive-continuous/app/ui/style/olive-light/png/play.64.png000066400000000000000000000016131370472574300236640ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(©IDATxœíš¿kAÇ¿ÏÙk´:Vr36 ´QÄF±Qìäl‹%؈äÐ.‚`üÕ Zœ"¤M!i#Ø\âL¸æ„ˆ'r·ÏÂQ¸˜eÞÞîù´7÷}3ßýÎÌcY ‰D"‘H$Ù“”P£Ñ8KDM":ÂÌ›D´œeÙüÚÚÚ{©E b€ÖzÀ!?·Ò4ív»µ¤ñ6`ëÉ?úÏ0§”š^]]]ö­'Í>_"º¶‹a:Ë²×Æ˜)‰š’x'Àó‰™÷çøËR’$3+++ß|kKàý4r.NƒwƘӾµ%(%ŽÌ|™k­ïMNNÖʘÃÊÜàêúúú+cŒ)k¥HÌ<à1æJõ½A­u[b"[,Ôjµ»ívû§ æŽ”ž€8×ï÷ßj­ª`Õ 3&¢—£ê*g0³bæ)­õóñññCEÖª¤Û(¼g¨º…÷ •7`‹Âz†P ðWÏpQJ3(€™0ó}­õm ½à ØÆM­õ_‘ €¦¯@ÐÑQ_  `æÌW#hx¿c Ú"zꫬD4g­]ôÕIæ2RˆhÀ¬µ¶%¡”DôÀ´µÖJi†²À‹±±±K’‹H}pÇZ»èœׯz–”Rç%»aT2D4ðÐZ;À»ÙÙ‰Ê@Df¾åœû0ŠzUÛ I’\ÕâŠ$@únÏCéq·ç¡Ì-PØÝž‡RPôÝž‰üÈ9¾ð»= øàÄ.Æmxàœ{‚ßñ¯ x¶‹1N)uÙ97 -”¯@¯×ûZ¯×€ãC†´Ò4½Þét:¾µŠ@ìCIcÌ)Mfž ¢ÀÇ>”ŒD"‘H$‰Dö(¿Šï¨AZ1IEND®B`‚olive-continuous/app/ui/style/olive-light/png/prev.128.png000066400000000000000000000035221370472574300237550ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(pIDATxœíÝ_ˆTuðï¹;³-Ì»ºj¹³Ì_ ÆŠš—"‰-3{(‚Äè¥?OIH‰P)™†¯‰™ õ d™úÐT´ø² ÙB‚8÷^w·l¶m6Z½»÷ôà,˜îì{çþîù<Ïï÷;Ë|ç7sÌ, „B!„B!„B!„B!„B!„ˆ7 ûÀ|>¿’™7XÍÌË€ˆFôÑñr¹|1ìšT+‹éJ¥²Î0Œ'<ÈÌK\ð7€óÌüÝŠ+¾-•J“a×Z …B{­V{Àf6f,†Èp,“Éì¼Vm*™¦¹Ž™w¸gއ:Dô¡eY§Ã¨kZ(( í×®];à‘y.9×ÙÙ¹-Î!X¶lY¦££ã]›ü¬#¢ƒ–eíà©©ìÿÚÂ8$“Éìð”%Y×u»ªÕjIQIJõõõ­J§ÓŸaþ¿ÕÃÝÝÝwU«ÕŸ‚®k&Êo€ú{þW®ýFˆÈ#¢gbö™€r¹ÜËÞ^ÈF†a¼Z.—ÏSÖ,ç¨>€™¾çϱÎ`æ-*jR!›Í.ÊårŸØ>ùÀÌo …ö…W6;å@s×`kC“ÏçK¥RßXԞ̜­ÕjOµ_#aÜÙ(Ö†¡X,¦MÓÜáyÞ!fî zf^ôž·K©>@GDk•êííÍŽŽŽîðª3ˆ¨ jïia@;¹\n=€=îV|Ô\³ƒ“øÐloß,fΨ>C0O}}}« Ãø€u-A £ ˆ;2Ms«a_@³'`VÙlvQ[[Û>f^u-ªHÈår«|`iÔµ¨$¸S›iš¯x½™ fÜHnÑÛÛ›M¥Rû™YYoßj$u!öö-%ñ»·o5‰€®½½ÚÈi@ëÞÞÄÝIèíýHT’ÒÛû‘”$ª·÷Cû$±·÷Cë$µ·÷CË$½·÷C»HoïNˆ¤·o‚7€ôöÍ‹}¤·_˜8@zûÄ2ÒÛ'v¯Ó47¥Ó鯡ð I§À0Ms3¿u!:‰Í O¾±€išË“¯FË X,¦™ywÔuèªåP©TÖ¸7ê:tÕò0 cCÔ5è¬åྨ ÐY ü;òI‡pÔè,ø#êt‡üu:kùxžw2êtÖòX²dÉ÷õ_ ´|\fÞù0¨DËlÛîgæÏ£®CG±8޳›™D]‡nbžã8ïÑv"ªE]Œ.â€eY'\×}Àù¨kÑAìÃÃÃC¶mo&¢õ3#šËÔMY–u€™·ø3êbâ*Îp³C˜ššÚ u-qûÀÐÐИmÛ¯ÑnnÔõĉ¨c˲{ž÷<+êbâB§®\¹òëÄÄijŽG]Kh¸zõjͶíÞðOÔõ´2-0ͶíS“““!3ƒ†´ 3ƒ¹h€:™4”™ÁL@f·K\êdfP—Ô™ð23H|¦%uf ¸Eg€;%jf h )3 À,’03ÌMë™`žtH|ˆ`fð¯ê$M°mû”aϸ ø¨QÅû‡€…¤Xù+ YårÙîééyˆBÝWUL}ˆh8еap-ËÚ à%(˜0óÙ ÷¼]7À¹ˆÖ†Æ¶í~×u72ónû{{{û™÷›Q7À±fƪDäÑ15©0222ê8Î6{ÌÌàƒK—.]`ŸYµ©> Z­þÕÕÕÕà?ëˆè¨eY_**K™ñññŸ/^ü3?  «™=˜ùˆã8.mF¡t™Lfü]ççêkbéòåË&&&68ÑÄòOÇy?èšQ~@¥R™Êf³']×í"¢Uh¦ÇÕ¯ý£Ûo„Q›*µZÍ?ÓÝÝ}@@çl'¢f~ËqœÃ¡8}n˜‡@>Ÿ_ÉÌ›¬fæåÀÍ?@?/—ËîIµb±˜[ïyÞZ"ºõ_?eæa"ú…™Oçóù³¥Ri2âR…B!„B!„B!„B!„B!„±ó1@eM«×g IEND®B`‚olive-continuous/app/ui/style/olive-light/png/prev.16.png000066400000000000000000000007151370472574300236720ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ëIDAT8Í’½ Â0…ÏM ‚ƒˆYÚRLÅÅptuÒÅQpñA''AptŸÀ‡—–vçBIãÒ!`[=Srnîwî…%)e[JÙ.«;Ž#}ßo˜^ͼ(¥Žùq`úBˆºeYK“4M¯F…­u« µÏÛðr«kÖYÙ¸Èó¼9clo4?©VdÚ¶Ý䜯µÖÊ€rç| ÷ª¨^á-”R3§¯qßÃ0\Ñ @ú1 —‚`›eÙ@ð€ˆnDt3½(ŠÎI’Œò7—ÒÈW_ÙuÝŽ¢^1õôzq6ÓLý‚IEND®B`‚olive-continuous/app/ui/style/olive-light/png/prev.32.png000066400000000000000000000012151370472574300236640ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(«IDATX…í–1hA†¿·»Å‚ÂÂ+«#ˆ•b£`!‚©ÄÎ 1}ZEQ„t‚ÚÚ¨•ÊF!ˆýÞ w׈X¤:ÈÝ<›$ÜÙË&ÛÜW½Ù7oþo™f`É’š‘XÃZ›‹H@U?9çFe¶Ö^UÕÕÂ~¿ÿ=¶/‹5Tõ…ªÞš.¯[Ç n4çò<¤ªkI’Ðét÷z½w³ö'sκ©£´Ûí‹yžÖþÿBx›™'EêYˆµv=I’÷€Ñ¿pœ…hµZçÓ4}¦ª7™?‘€1æðœ9xZ©µv x¨ªó®±zf³Ùʲ쥪^>IðBƘÛÀS`¥ŠðRƘ `§ªà”¹¿ûU‡—­U@UßÖ*འlµL%>Çã.°_‹Àp8xïï‰È®ˆ„3˜2qÎíªê:ð«¼÷_'“É`¯€Á`ðÇ{¿)"O€Ã*Æ‘zêœ{“¦é]ÀmŠÈïE¾Dê(EQüF]àÑ֫ØÌi>J¯„.eY¶_Å·2³K–œ) ”¯°Í IEND®B`‚olive-continuous/app/ui/style/olive-light/png/prev.64.png000066400000000000000000000020121370472574300236650ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ((IDATxœíš1hA†ÿ·{/ñ\2kjSØj ±%¦P± ¢ ¨ x¥M@Aä ,$ZJ´‚Š$…ÚZDÛ8“\ŠXHV<9¸Ü= ÏÂhðf²³³ê|åÍÌûgþ½yoXÀãñx<Çãù/!“ABˆÝ*D4Ìü@U)õ!ÉÉýŽÁÁÁ‘ N3ó0å™y™§—––ž›ÄÓ6 ³ø‡ŠšbÇl™P*•z …€±MºÜVJUuãs©à×Å£ó[Å Þ. °ùâà¬â nlmˆh¿I›!EÑx«Õš ºèJW §;€™·™´éR.—ûÂ0¼Á̺CDú:Ú¤b€*€:㘹GW+k„Qp™MþŸ´ÉŒýýýå\.7ÉÌ{ÓÔÍ„BˆC®Øž¶¶Sº8Û­ãÌ€=Aܹš`–mŠ¢h<‚p¼x å`r¶Û&5LÏvÛ¤a@êg»V pu¶ë`í‰DQ4–ÏçÈìâK;@q™™ÏÙˆ4‰ï€NMþW,°ó h×ä.IÜ“šÜ%6v[ˆiÄ `æ…¤cÚÄÆ˜¶Ó‰ ”š#¢[Iǵ…•DHJ9ID"ªÛˆŸ$Ö2A)ål³Ù< à­-$°Zœ¬¬¬Ô”R'‰hŠˆÚ6µLI£:kI)§˜yÀÇô´H­@:Ðÿ g74ËËËïÆQ÷]Íph¬®®Ö•RW\ðÙÅ2qG§”z²¾¾> 9C& Üå ™1 Cê9CÖ °¥œaMWËä™/&mºüÈ\G—9½×ÕÑ6€™_š´ÂJ©;až ºèWWÀä¨âû'q‰;m‰³¸¸¸Ðh4FÌnÒ…‰hJJ9¯;ÔÇñZooï3%"ÚEDMs.ÙüP²^¯7ã8~Z,ßA°ƒˆú|eæ×aNH)gli{<Çãñx<ÿ ßèÿ¯Ò:xIEND®B`‚olive-continuous/app/ui/style/olive-light/png/razor.128.png000066400000000000000000000032431370472574300241360ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÁIDATxœíÜÛnWàµfŒQ)ÂvœVEN5‡¸£¥®T.(©ˆ¾A_ ÑGèëôZνAQRUªØã%iUÒÔ6)\Ä™½zá)JbâÙ“fÿŸ„aç×Âþ±÷Œ·‡Þnüâ_,..¾/"§EÄUJÕ˜ùPƒ"2&¢‘ˆ„Õjõçn·»¹÷ö½°]×½LDÑ+Š¥ D´†áu"ЉˆìäÛqœ¯˜ùáÉ/3&¢ãµZíÃÑhô+‰MDäºî•äÉ0s­Ñh¼3{vòžÿ%á¾i>˜ŸŸh)¥ðžo&ÞÙÙ9m‘“÷$fö,¥Ô±¼Ü³˜¹š÷f®ZyùB ‡0 `8Àp(€áPá†C ‡0œ±`æ˜&›%·“ŸTÉ{€уÇ÷VWW·÷Þàû~-Žc?Ùçæ1\Œ(3¯+¥nDQôûÿÝ'‚-Ñr«ÕZ¨V«Edáà¦Ì‡]¯×Ïå=D–,˺ßï÷¿FÛÓï=±½½ýd8þR¯×+DTê”} p5‚ë4Ù¿_†ám¹¦{¨")mDä§0 WÒæDQ´lYÖ}3Q) "£(º­+/‚›"²9ýžoŸR@)u‡ˆ”ÎHÛ¶Ô˜W¥+€ˆl®­­õtçAð™·tçæ­†á·¯»C§Ó94 ŽˆH]D<i3óüA ¸_ÌÜÍ*[DQ3«ü´Dd“™»Ì2ó°Ñh<[ZZ¿îw¦žHFÉŸˆˆnû¾"ŽãóÌüžžÑõ±,«ŸU63÷EälVù³‘Ç•Jån¯×Ûwùg:Á#"ê¹®{žˆŠö€Œ² ‘̲SX‰¢è{šqÍ“f  ŠxœÜh4že•Ýl6Ÿf•= ¹†áUJ±àM½Œ¢h™ˆî¥ÍÑeÚ{^Q³gp/yìSÑr†áfÞБÓ1óz†wtdé: ”ÝÝÝš²`Šñx|‹f;½ýmçÖÖÖ~£ÉÇ­­p}}]Û«­ÖA"òPg¼ÒaZ `Û¶ö3pð_•J%Й§µAŒLÞ^•5fŽ»Ýî™Ú? ‘¿ugÂDmÀ§Þ"Ú `YÖ»º3a‚™êÎÔZß÷k"bO¿'ÌBDìv»­õ¢^Z °»»ÛÖ™/Ç‹:ó´À²¬:ófÑét2»ºy–ÙoJ÷%}µ Ýn/P¾P1 Žd•½µµU„õÛjµ´mU×UŽãø’¦¬´jY3sfÙûQ­V/‘¦Ëûj)€ã8E¤¥#+-¥”—U¶ˆd–½"Òr]÷‚ެÔpç 3¦cD$³u3ç¾ÆÙã¬ã8gÒ†¤9d³\×½ÀÌÓ¡3™››ûc0ü¥3×ó¼S"ò‰ÎÌ´˜¹]¯×‡Ã€füxx¦=¾ïŸŒãø<rwp2[ô}7ÀRJ}Î\È“œ;ŽÓ²mûn²Ws_¦þ‹:Ρdõ['"—™OˆHa·Fÿ‹™—úýþ:²<Ï»,"YYbæ?E¤›ì^5›Í§Ó¶±±ëºßÐ|ND®¥Ý7—¬q®èš©hJ÷Í ½˜ùŠïû_ÐŒ‡L¾ïŸ+ó“OdÀ"”RŸzžw|ggçÖÆÆÆú›üN»Ý^ˆãø’Rª‡¶Y*õ[À+„"²jÛv\ä9×uë"â3óI*À̓RúW€¸Ìì*¥Èó¼X)õ”hò¶ˆØ]ågÊ´<—<áÇ’Ÿó'7¥^Ât(€á*"òuÞC@~ð `8Àp(€áPá†C ‡0 `8Àp(€áPá†C ‡0 `8Àp(€áPá†C ‡”À?l£éŠ¥-ýIEND®B`‚olive-continuous/app/ui/style/olive-light/png/razor.16.png000066400000000000000000000007061370472574300240530ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(äIDAT8Å¿JÃPÅϹ¹(uqÑ!!K@ãî3øâæ+ù¾@gÇîÕŽ!™EQá[¾ã`ÅKÛH‰CÓ…ó‡s?`ß°®ë3;Îóü%šÙ-€É˜3û cÃ+&ñQ’H²Àm¦`B˜ºûyj’ôØ÷ý ªª¢»7iyáÉÝ?b×uP…H^ü8²,{OokÓmÛÎ íw÷lÛ{–eyIòXÒYú’¯$ïW×Ó$—’ž£¤IÍ’N4¯~ |ñjÈ´ ƒ7Ø•Hòî¿%ûå ½U‡y¦lßIEND®B`‚olive-continuous/app/ui/style/olive-light/png/razor.32.png000066400000000000000000000011471370472574300240510ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(…IDATX…í•ÍJÃ@…Ͻ“¦ÈtUf×?ÁºèTÀwpéø¾Oí^tånÚPº(BCNæºÐJIKBS5ùVáÀ¹çp™™%%C‚v»Ý‘½? &ZŒÇãj6›çDtð—áKDä…™y¿ˆp`æ}UTQ\Tø’] È®‚\©"À R©<:çÈ{ß%¢"Úz^®J©áh4º_‘î:{ïO·EËk­ÖZŠH_DR‹-‹ëÉd­jƘšÖú2Í'"N)5Œ¢èyéÿún†gæ³´AÉp˜N§s­uš ‰Í­Â0 ²¦ä…ˆž’ÚZç%µßd­@ÇGY&kíÚ®1µ,Ÿ÷¾›Ô¾_AcLÍZÛcæþ¦b«T«Õùl6{M”êh§ù˜¹Y¯×ßÃ0|‹¢è¨Õj]e5OBD.Žãf~>·ÁqÖíÙDÞ‡(øº)g ”‚H¾G1‘‹\ÎâßÿŒÊÿ¿@IIá|FT„˜{ïIEND®B`‚olive-continuous/app/ui/style/olive-light/png/razor.64.png000066400000000000000000000017201370472574300240530ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(îIDATxœí—ÁNQ†ÿÿNk1e:$ºh3Ü„HŒ‹1êÂD׸Wî|Áçp'¼„’”ÄE+&$„Ó6†¤”vŽ JR‹”s Üo99Éùî?sï=X,‹Åb±X,w@­V›+ oÌ“¼gVéf‘€p0|ßÛÛ‹Y«ÕæŠÅâG3¦år¦Ûï÷¿ªá›¿k‹€ÇqÞ(ó¦MLAR«Û¾ç/¡¤L˜Æ`ZÀ46Ó¦1€ˆôE¤oÒ¡` gWDÖÇinoow@kí&I²¤”z ”§L®ŒI~;[øa¶üÐZ7I®ˆˆ——Sn[@Dz"²:¾øQÂ0lƒ59ÉË+·Hn ßôD¢(j‘läá…0 ¿Œ>‚ DZ'"‹",fшäæÊ·¼Ê¢¯ˆôHnÜôaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(NIDATxœíÝÏoeðïóîn»–Òݵ4$Ýdg¦0, \Л¿0‘¨±Š­&þ&€‚1<áhb¢Z.%&àÑôPN ô€¥ív·’&Å΀˜uÛÇC[Ü4(´tçywû|ΛÌ÷ÝýîÌì»óÎJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”²I¨·l6Û™H$ö‡a¸ÓÓÀbæ­¶,¿ì.Ý(„aX0ÆŒ/,,ŒÞ¸qã–Tö(4e<ÏÛ†áKØõ“Œ‰Åb? …_7*£-š¦]]]ímmmGˆ¨Ÿ™Ÿ¨Ç6ˆh‚™Ï—Ëå³³³³w뱨5|\×M`æ·¤"Úl@DCƘ¡B¡D´Íºhäã8/чÌü¸PŸˆ¾(‹g„BICÀó<‡™O1ó>é,@DW1G …´t–µŠIX+Ïóž Ãð®t–Ý^ëèèø=‚ëÒaÖ¢‘ `Ç9ÁÌh•s-DôB:n‚à –~AX¯! Ð××—hmm= à é,!ŸN§|>ÿc±X´þ¼Àúôõõ%æææ¾ð¼t–5Øåûþž|>ÉöØ^jiiù À!é ëàAàø¾¬.€ã8'¼)ãìÊd2ù¾?"ä¿X[Çq8!cìK¥RS¶þ:°r §§'W­V/Ø*eƒÜ‰Çã‡'''g¤ƒ¬f¤Ü…axÍóáÀÖjµú9,üÂYWÏóúm™áÛH̼ßqœW¤s¬fU#]×M3óeé,õ@D·âñø³·¥³¬°mðšôÃfî¬T*Ò9jYS€®®®vf~K:G½ÑÀöíÛ·<ø•Ѱ¦mmmGÝÿù’ÒÉdÒš)mk àUéQ!¢×¥3¬°¢žçí°S:GT˜¹7—Ëí–ÎXR€å 87cÌaé €%ð”t€¨1óAé €Èf³z¥sx2—ˉÿä/@"‘ØË&¤"BƘÒ!Ä €Mtò·3ïÎ`Cz¤ò¤ØPW:€ -šxîÿAˆHjAË=â`fkæÅ£fÃØÅ €—hoFâc·¡J hŠeÖë$>vñ‘ø› ņ±‹À¼t)Ìü‡t 0%@øØÅ †¡ø› ¨ @¼Æ+WÌDÁ3.žA:ÀÂÂÂ(,^=#¥ˆèãÉÉÉ_¤sÔ²jÓÓÓç‰èªtŽ:-‹¤C¬f]°1æ(€;ÒA6Ðíx<~ Ny[uX1??d2™€¥³l"zjjêgé÷ceÀ÷ý‰t:Ý /åQÑWËϰ’µ€ F2™L€ké×áb©TúîúWØxP‹]×= `X:È:üäyÞ1Xþ$‘FY•s]÷Sfî—ò.xžw|xxxQ:ȃ4J€\×=ÎÌïIùLD_‹ÅS°x·_Ëês€Õ|ßI¥R׈èiIé<µˆèOGK¥Ò t–µh¨@…mÛ¶]bæ=²Òy–...¾;33ÓpXtXmå±q0s§PŸˆN‹Åsh]þj\@oooG¥R ¢éˆ6ëL&“Cccc =cÙðXÑÝÝÝ–H$ŽèÇÒó‚ëá:}W©TÎݼyó¯:m#RMS€Z¹\n·1æ03$¢]̼®ù" ™yŒˆF˜ù¢-—qm¤¦,@­\.—1Æ`æ^O`é¶,i,=âÞãã±ôç“¥Õ:cÌxµZµáÒm¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJ)¥”RJmnÿ³'ÀÎÛÃ~dIEND®B`‚olive-continuous/app/ui/style/olive-light/png/record.16.png000066400000000000000000000005711370472574300241740ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(—IDAT8í± Â0DßÁ¸MåIØ€EXô4'-RÆ@±èÀ-…MAŠÈ1 =¼ò}ÝéôáJÒZ[µ¤í ºc㽿, á0Ù);çÜu,W…u! °¹œŒfO(ÝJ >’RJßt3çÅ‚cÃûa9IÇ\®sB¸cZ ’TIz'Iû¾ïo3ë~–Ýï&Ÿ°ïÖ‘IEND®B`‚olive-continuous/app/ui/style/olive-light/png/record.32.png000066400000000000000000000011061370472574300241650ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(dIDATX…í”1NÃ@Eÿx¥iR8„b#£戜‰:-w ¢ Š¸ H‘ÜÂŒ”@• reá6E"°;4.Rv섊}¥53ÿíXÀãñüw¨nƒÖz`­8Ы>çfJ©$˲×?ˆã¸µZ­®œ3sðã0"`†áx>ŸîL ŽãÖr¹¼p,ô}év» %™Ön·¯œ Ãà ,ËÎb±xr:7 µ0óæµoLd‚ 8˲ìí·:çPkí¨n80³2ÆŒ\uÎÁD4¬¾†³Wò²½¦éD´¿ n* é•Ó™?¶`æiSÎ^§€R*©.\-ˆÈc’­ªÛ>©+ÀÌ÷yž¿o-aŽDÔ`æ/–˜y¾Õj½®Õj?{1®Ì9FD×™ù"€|‡5‰è%€™J¥RÉntEQÀ-—™y_—KD1ÓI’´‡·I&DQ1ó}Ç…”‹Æ˜›¥RiMÈ·‰xÃÃãžç=bæƒÂêU"ºZ©T>JJEˆ¢(ð8ƒÉÿaÕ÷ý‰$IÖ¥„ž”(ŽãýÌ|/ÃÉÀ!kíl{A,kím'¥|;Á̧Üò‰,öQ7ç°Ûï "Ú0Æ\X "o@ûœïÉ䀙û¬µS.çÂ0 ÚMNOaæÉÁÁÁ~Wsíö¶ÓO’|.—;ï*‘XcŽ=«ípu8à\[â 8*àè "r®-@ àè f.¸:Ä¡‰~8º‚ˆ¾»:$ø,àè fv®-À’€cÏj;ÀÌó®Þ¹ œ°Ö¾ÐtõtA3MÓ·®çªÕêFûf¯y^­V7\%RÇà +äê„Ôó@B$ò [¯×ëýÎJø:`¶\.ÏIˆÄ!cÌ4€E)ß_X‚à®”Lô§hÇaš¦O–ônaÍó¼‰r¹\“жÂI’¬Ñ5«’Þ6_=Ï»"9y@hØJ½^ÿV(žzžwÀ!í‚ïû—VVV> ù6Éä?^£Ñh‹Åišþp€ß¥*0Áååeç¾;2¿ã8´ÖN1ó$vq9 à™1f¦T*eú­Ñ³ëñ¡¡¡>ß÷Çœ0ºÃõøïÓ4}#Ñä(Š¢(Š¢(Š¢(Š¢lÇo°×ìu?t¥IEND®B`‚olive-continuous/app/ui/style/olive-light/png/redo.128.png000066400000000000000000000035741370472574300237410ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(šIDATxœíÝ]hUà÷›Ýn›¶»êšV’Ù¶þ¦ê…•¢RZED«Þ¨ /D!((x!‚x¡XíE©ˆ T‹‚ˆVA± bQK0ew–Bi)M6ÿÒÌç…)„ÚÎß9“Ù¾Ïmö|sÂyç̜ٙY€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆŠGzÝ*5›ÍªÚ‘Šª ‚à`§Ó™êuÇÒ`bÚ°aÃò¹¹¹ÇDd‡ª^¼øo"2¯ªßØåûþ¡u1•R¯;Pžç­™ŸŸÀ=.8ËGMy`ÕªUÝn·{pi{˜¡^¯U*•\ã㎈l«Õj˜žžþ>ë¾ÙÀD¨×ëÏØš°Ù梄€áyÞ;ñߟT!Bæ;ŸÜ  œ¶±ªŽ{ž7n±?Ö1á®5-÷0áj6Šä9 @UýÃb­q×uŸµUÏž†¨Õjël¶XrSµZ]ÞívX¬i„±zõêY.»)O« D·Û=Q­V7hZ.›%"¡Z­þàn+,—ÎE€Ýn÷÷jµzÀv–Ë÷< @ ‡‚o‘QzybÈÄ”qz¶:`èÇ0 õ[€ú) @JýÀ@?„€0Tô09 €%E `QCÀXV´0(R€Œ% @†Š‚^<긮{…ã8רêÕªÚ°@}áiÛ³={Gç "»ÛíöîÔímvæ\ÆÆÆ*³³³[Dd»ˆlQÕ —b»ç “d€f³9Á¨f¹­ó]Úd€‘‘‘Ár¹ü0€'9¥/©·|ßß™¤í“@i4÷;޳Àí–Y®Oáßrn-õz}¨^¯ï‘ÇaÿZŠ/Ñ=†VÐh4Æ*•Ê^×Û¨GÆb/àºî­"ò.žÙçK¬ÃÑážçmð€ŠIÊF‘ŸI×uoQÕ=–§­AÙ‘ÝN'rY˜jèºnÀ>+Ó´§l©j¬ÁRÌ###ƒÞ?—’ >"årù—%mGÙ‹;í/–èH£££Ü—¨W´$Tu·ïû‰/'™Çq^TU¾V&g’Nû‹ÅÌf³y€ëÒl„²“fÚ_,ö!@UM»‘s8&"_¨êOAüV©TŽ‹È_“““3–·ÓSFcLDÞC߆šÞ Ä @³Ù¼6‚M&Z¤#"¯¶ÛíϨ¥š¹”÷Áb@Uï5ÝÐBoÇ'&&fmÔ˳" >/%w˜nHD~™ŸŸbbbâOÓZyW”Ábœzž·éÌHHjáž;rä߀íÁb̪z³éFTõ£¢ý’F®ë^ “ÁO»Îgx£á6N•ËeëÏ›F£1`/2ÚóM–za¢f€€« ·ñåáÇÖȵ"îù§…ÎëÖ­[ï{ÇùФ}ÞuÏ?-t‚Àô©ÿ”J¥ž¿5+EÞóO‹:XkXÿ§ÉÉÉ¿ käÒÂàg²ç›\ÛO**Æõ5lŸKEŸö‹ €é/f5lŸ;E[çG‰ €é“C}€~| z8mR\DN˜´Ï“~8á;›Ð@U}ƒÚ*"mƒö¹‘å ßRóÏuø)¿²‘C­VëXš¶y2::z)€wÐGÓþb¡ð}ÿ¨ˆ|š¦po§ëR¾”J¥×\b»nˆñ]€ˆ¼ Ñž,"û;Nªàä‰çyÛTõÛuó2ø@Œ´Z­c¥Ré8Edÿ©S§žBÜí£ªwÙ®™§Áb>:55u²R©|¼lÙ2à¿gþ÷Â#™ð²ïû¯ÍÌÌÌÙífoÔjµg`ñ¡×¼ >n_r]÷:ÞÂÛ?¦Eäß÷[–ûÖs®ë~ó«¡ò9ø@oÞVžç}¢ªMë,åµý¤øG¸M ôz…á8Î>“öyöã›BCLMM¯V«âaØ" >À ’ˆ¼ ¤ªbðΑ¦§§ÿúÊqœ›\öÙ…Ûß_êt:…¹ ÊÄ0;;;³råÊ}Žã8Æp–÷ŠÈÏŽã<Ýn·?[ú¦Çe`BÃÃÃ+¶¸À€ˆœ‘­Vë úàê'Á¿/RÁ÷æXäIEND®B`‚olive-continuous/app/ui/style/olive-light/png/redo.16.png000066400000000000000000000007151370472574300236470ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ëIDAT8Õ!NÄ@FߟÙ&+:£ÆÍ˜Þµ`Å*€†„„+pÄZ.°Ï H0 :h:!UdûcvM ­Ü§¿÷þ8yŠ)£Â]UU!çü9;P×õb†'Y;çèºîmV mÛ½µ6‰È…ª®Æ‘I_È9Yk¿Ed­ª+kí"çü ÇQŒqÜ5pö_TD¶MÓlÍA¾¦¼fŒ9Ô®Uà>¥´öãaŒq#"ªZ¯ˆ÷~Y–å;ð“R:†©2@Ñ÷ý¯sU}É9ŒeïýÒó ˜±<™ãmáj¶xü [CUôúîIEND®B`‚olive-continuous/app/ui/style/olive-light/png/redo.32.png000066400000000000000000000012751370472574300236470ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÛIDATX…픿‹AÇ¿ow5fÙ™ƒ3…1›%e =äJÔ Â!Xù'XØúèaa)‚ÖVÚªà ^¿ÙM!Š?˜€Ù̳ÉŽ˜h6lÒ\¾ÕÎì›÷ù°óX`•UŽzܲµÛíã¾ï_’RV1ß—-à!ž¸ঔ’1»Kð àîpI.*¥ µ~¿¥Ô>Ýàç¶/Ì"QŠ€Ö:SJ}`æ«*E$JB­õ× ÞÑ'òRÊŠ1æÝBÀó-‚·$ÎO“(U` šÔ$Š¢šµvÀ…ÌìOª›'D´“$ÉÎÁú¯/†á5f~ `À:€ceÁ‡94˜NþM£Ñ¸à€jÉЩ]A«Õ:“eÙËEÃǯÀ;xè÷û·‰¨š+üi­½çyÞnǦ$Š¢³ÖÚ'Nþ ~H€ˆ.ßïv»¯‹€‹Âá Ôëõ5§rû¿˜ùÕ¢á#×u+câ$Iö  ¤iú…ˆ>æö_×j5a­}\ü™Bl÷z½MÇq~t:OE„§ƒÁzQ80åO8GÜf³ùœ™Ï`Ó4}4ËAïÿ%3eàyÞ­,˶ÇùÇñ^I}WYåä7#ÎÂÊà%ûIEND®B`‚olive-continuous/app/ui/style/olive-light/png/redo.64.png000066400000000000000000000020761370472574300236540ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(\IDATxœíšÍ‹ÜdÀOÞÝØ]³â*f’¡ÑÅ‹3¥¨7¡¼Š¢žÚÓÞÄ‹âŸà©•éAQÑ£'±x°+ŠèIðë´°™EGìû9²Ã”}<¡N3“ÌÌ›4mßß1yò<ïó#y“¼ 8‡Ãáp8Ç=ˆÜî$†áÃÀ+@$"ªêWívû§0°K€§———ÙÝÝýÑfÍR ¨T*'UõìˆS¶%x¶Ù@UïÏóZ†oتY*Ƙß2†®Ù’PªK`gggÏ÷ýx4CxËÆåP* ßÎÌÌœj§žJ'ààà _­V¿ð<¯ <’áS¾ïWööö¾Ÿ¤^éìïï__\\ür ­I%”R'¡´  ¥ùK(½ÈWÂ!ò“0ÑÛ`½^ozž÷ ð$©ê}Àâ$¹òFDÖã8^ºŒ\&Š¢—€3ªzbú¡Ç( ™.z½þ¸ïû/©/,%dècª€0 _‘ ÀC¹ ­8%Œ|Œ¢èeàm ’çÈn'Cç€0 Ÿ‘Tõ޹SŒBU×···o™Ï€•••*pîni^D›‡!æçç×€•\GUcßWWWçºÝîw–§~>ö<ï÷^¯w­Óé\v°iÔjµù¹¹¹Tµ•%>­y€™Á ‡‡‡§I¿Õ]l4¯oll\Ï2äÑ<$_ϧs¹ßï¿y74 D¤™’ü½N§óO–ä6ȳyA-á£ÄÍÉϳ&Ÿ–¼›‡ƘG«êfǻ㘔"š‡fþ?Æ-0 E5·ž)…þš¤È8Ù< ð<ïg¹6"þëI eevvö¢š‡›››=U}KD’fùOã8þfšbiAОÍk£yHxj·Û—ÆiàUU=!"W‹qÿ0m±4Œ1O¨jjœ­æ!AÀÖÖÖßÀyÆáøøøŠÈèE*›ÍCɾ÷z½KÀЉÖvóP²Uán·Û_ZZúUDžãÿ‹0ÿý"ó®íš¥ûGn<‘cրǸqF|VÄäp8‡Ãáp8÷ ÿÅ5y‡yÆvIEND®B`‚olive-continuous/app/ui/style/olive-light/png/rew.128.png000066400000000000000000000034501370472574300235760ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(FIDATxœíÝMh\Uðÿ½É¤'cÒÖ’„y).TZŠŽ¢UÄ.ĶXJ]èÊEîtãF? HAŠP麠ե(b•j :µ]-(¥.Ä™7b•fhz'Т“ÌqÓ”!™Ì¼ûùîùmºéÜ9ÿäpß;aÞ€1ÆcŒ1ÆcŒ1ÆcŒ1ÆcŒ1ÆcŒ16áº*•JannnŸ”òY»ˆh €Ì¸DD?lß¾ýÛjµºè¶R3²ä¾’$ÙGDo¸¯ÇmH)߯ÕjgmÔeKÖüÁ6ÀÖ­[7ŽŽŽp¨Ÿ× !NÖëõc:f*³CWþ!Å™6==½£P(œðÄ/dlllD)5«».[tæ­D¹\~EqÀx†u-‹W”R¿ë*Ìíùƒ¹LMMÝ;44t ÀMKþ±iÓ¦½—/_þWÓzF™ÊÄ033ó´”ò€‡4.[l·ÛWnܸñ›Æ50™ßë¨T*… 6¼ADGl4ðm¥”·SüÃÕbrrrªÙlð°©÷Bì0µvV¶ò{Ùåry?€£î1üV½fg'læ÷ªmED&¶Õ¹ÈïMLOOïR~ q]‹ ®òK›oö?D’$‡¥”Ÿ!Î_¾ÓüNw€åÙ–ˆö¸¬Ãò;k€r¹ü$€lqUƒK¾äwÑCI’¼ à5"òád›Wù­6ÀäääÔðððq"26ÛúÌÇüÖÀâlë%_óoÛ³­o|Ïo´x¶÷?¿©›žíɯ}ða¶u)´üZÀ—ÙÖ•óëj¯f[‚ÍŸ¹|œmm =¦ðu¶µ%ùjßg[Óò”¿ïa¶5)oùû¹a f¶5$—ù×µ„6Ûê–çü= ÄÙV§¼ç_«‚m5‰"ÿª úl›ULùïêì$I …o`ðŸÅ–¿{I’¼KD/;«Æ­(óßÙb ß-Öü’$y&ÆðËbÎ/*•J¡Ùl~`›ëb\˜˜˜x0æürnnn" ±ç—RÊ®‹p)úüp]„cQç—ðôy‹¢Î/ë"‹:¿ð·ë"‹:¿ð«ë"‹:¿ìt:_».Â¥ØóËÍ›7ŸB\u]ˆ+±ç—/^lÑ›ˆôf(öüÒ4%¢O]ãJÌù”ºP,‹Bˆ]. ²M)uâö¿Qæï>*–”RçK¥RCñ€WEٴ܈4ÿ]Ÿª×ë_¶Ûíç\rPs±å_õ°è………–Rê‹R©DBˆÇð7‹ôÒµÜSþµ>íºT¯×OÑa×,Õã“(ò÷ü¸sš¦³KKKT͗㟼ç_×÷´Z­[J©Ó¥R©`÷z_‚Õ.+å9?<<\àí.¬×zv€nyËŸéî6$¤izÿ ¯ÍCþLϼ¥izfqqñ "™™WÊCþÌ73¡ÏÌý^V =¿®§^£˜™×l~­=ç}fî%ÄüÚçÙÐf欗€•BËoêàƒ\ÎÌ}&¿Ñî afÖ½t !¿µ;V_gæ,臯ù­}“‡™9 _ó[½Añqf6y XÉÇü.N¿ vfÖÄ«üÎŽ? qfÖÉ—üNgTff›—€•|ÈïÈÁÌ̆8ÍïÍ_©\ÍÌ.w€n®ò;¿ ]Å™ùVš¦; ¿Gßlæ÷áp—4MÏH)_ð‹á·j^ 6ó{ÙP«ÕÒ‰‰‰—„'aîÁMÓ?àÙÊïå%`%SG¶ÑëFã´Î5M0™ßÛ [š¦³ívû ]иì_###g5®gŒÉüÞL½,,,ÜTJ}566vÀãÈ>Á¼U«Õ‚9ÆTþ``™Rê§ñññ‰h7€±AÖ ¢OÆIÍ¥Y¡;p óóóË3ó6ôÐãGF㨉ºlÑ™?ˆ›Àµ$I²—ˆÞA…W;Î{F㜥ҬȚ?ø€J¥R¸~ýúþN§óœb'nÿ0ˆèO!ÄÏDôÝÌÌ̹jµºè¸T#bÏÏcŒ1ÆcŒ1ÆcŒ1ÆcŒ1ÆcŒ1ÆXÜþô˜®ˆl+b¾IEND®B`‚olive-continuous/app/ui/style/olive-light/png/rew.16.png000066400000000000000000000007101370472574300235060ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(æIDAT8ÅÒ±JÄ@ÆñÿÎ^¸*Wd›lŠ\c-ØÙZic)ø*–Zù‚¥à ÜC66íIc$l´9árdµÐ¯ö7ì2ÃÂG‡ÀZ»Ÿ$‰/Ëò}Ìg»`Œ™GQt œ·mû œŽyïkí¡ˆÜùæè`ÊeS¨<ϯDäq ·t•¦éBk} œ Íê½?ó™ÖúX!À”K¾ñÞ_«PÔ뺮ߪªzŽã¸ŽÙùι›1ÿá£(Šû®ë.€bà¡ ÷vàœ[7Ms<(¥^~â½dY¶gŒ™ÿÖÿ.ŸÒZHrLásIEND®B`‚olive-continuous/app/ui/style/olive-light/png/rew.32.png000066400000000000000000000012431370472574300235060ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÁIDATX…íÖ?KAðçpA¸½%7ì W¥Q°˜habJK¯±J>…`,üj)h“"mª4µîvš@‹½Âææ&MNäØcÿ¼!6÷”;û{çfXd‘gŽW(¥6‚ xßh4¼,Ë~q=•…­VkÙ÷ýC§ß„‡ƒÁàœãK5ÐétV­µ=jfh¨µ~Çñ¢À’Rªk­½ÈÁð’ëå<EÑ )åçÜvÁ$,ŸÛ@Ç›DtŒâ榊ŸmÀSJ}ðÙ9W´=y©ìˆ¢è•”²çœ[¯1qm/ Ýnp QgrŽ÷â8> ¢#Ku&‚àãí×Óp½à8¸^8c6Àòž1æºÙlÞØB}ÔZw9^ü-òm<︩Z€ë¯ãÑh”c®Â0tDô@©‹ÊsÂñ³§•M’äÄ9×0,µ¦Ï=.µÖ?¬µ;¾×h¢’Ÿû"ʲìÁó5 à ÀÛyÿN· ®/º0\’$§Bˆ=zvˆî¹¾Ô›0MÓß¾ï_J)W¼~R —¦é-Ç—~N£”Ú˜L&kRÊ›~¿ÿóûEùçùÊÙ!©Ï®IEND®B`‚olive-continuous/app/ui/style/olive-light/png/rew.64.png000066400000000000000000000017251370472574300235200ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(óIDATxœíš?kAÆŸ™Ù“ƒ€dzÈ]²K°°H@ ÿb'ФÑ:ˆD+ý60&ˆ$¶"†€ˆˆ…؈`>@f,ÓdgZäö^›$$?{{³û&:¿zvï=Ìî;;s€Çãñx<Çó_"Ê ]–RÞ%¢Q!Dˆ~˜5Æ|*ÛÇ_ZF£¯^¯?0¶ËƘIn) fY6 ÚgèD3¡¿rìqw:çrŒ?f­çô®Ì­Vk@)õ”ˆ®ä½F1Êíw@EL8ÞÍuDÔÇíï5Çñ}ˆHöx/ášÍf+‚gDt¦è=zÁ•¿PQ]ðÀÑ^äEqéï*€½µTÊðç`pppDJ9 v%üy^"Žãq)å[×òœ”êßsé­.©Â¿kE{«+ªòïÀ¡ïíݰ-€¥·wÃfÂqÕjµX~<—?€(Šѽ*Å[áô‹(Š®xÉ!_g‚Ó/Üá’¯Ãê—.¿É‹Àí—ˆ³n¿$¢EθýÀ,gÜ~e­Õa*ç8 0Æ<äô+H’ä[†¿„—©²kí4§s%¨µ^X[[»àG•pû· ¬®®¦ÖÚù0 IqYk§9ý;}meZëi"°\vÜþ]?71_³,»àsÙEpú÷<KÓôµö}†)€ û/ÂÖG€ÃŸgô֯;Î-ÚuÜþ܉¦iº\¯×ßAqUÀ^3  ¡·¬Ëƒ cÌIN¡=7cÌÇv»}Lk—þÂ/W=;ï#P–¿×]×C¿fp²íÜCÏN¸ýÎúêFÏîïïÿ àaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(oIDATxœíÏoeÇ¿ïìtÛ.Û€&…¸®ìÔm$Í&bKbŒ¿N^ Q4^ à.þDNšèѱ@44pà¢ñ¨Ñƒü €ÅmËf -6ÛÝÒÎìã-.é¶;³ó¾ïìîû|ŽÍ;Ï>ÙçÓ÷ÝyÌ Ã0 Ã0 Ã0 Ã0 Ãt?"êt“ËåâårùjµºÀ3µ?_·,ëL"‘8yåÊ•…(óÓQd³Ùõ®ëŽY¡ÉUÛ¶÷Þ¸qãŽÎ¼¢ÄŠ:]är¹x“âÀˆëºã¹\.®+¯¨1F€r¹üV/þ#µ¶F`Œµ1_zÛNÇðÿ>Ùm;“èWÔ¶£1I¦,€á°†Ã `8,€á°†Ã `8,€á°†Ã `8,€á°†Ã `8,€á´…Žãô &£ÎC›6mp§/ê<ÀŽêƒ‡††6Ñ»Dô­O$p§DDç…§&''@Qå'‘Éd^°S±u~~> ™LæŽâG!ĉ|>ÿ{$‰éþÀ\.Ÿ››;DD;›|þYÛ¶?uJ'“ÉLi?555,ãs³ÙìzÏó>#¢çWiF¾M&“‡tMÓ:¤R©D©T:FDo¡¹|£®ëžÔ‘› jGѾiR|àÁw±«T*K¥R ¹-¡M€T*•ˆÇãGŒ¸,ãºî'ªrRŒp]÷SO¸f4Ñ)–ŠODÛ‚^KD/:ŽóŠ‚´”’Éd^ðBÐëˆh›N ” ¦øKÑÛ2sÒbW«×ê”@©étº¿§§çp˜âרŽÎ:Ê.ˆ(ÈP·ŒšÇ6lذFVRP&@:îÅb_âAñ²vppPé!ÇqÖ‡ˆ¶ô÷÷U)R©T¶í£S|£©I0®j8.€Œ1¿÷îÞ½[’O)“““÷ü++žÊßRPT|!~–O¿È ¦Ji¨*>"¢¯$ÇTNµZýZvLH@añ!„8555uQv\Õܼyóœâ´ì¸²%-€Êâ8gÛö‡ âjÁ¶íƒÎÉŽ+S‚PH¼Ï_†âÂüüü¾‰‰‰û²cëbbbâ¾çyc~•[ÖRW ®ë~  ÙC"S+þX±X,‡%e?@±X,»®» †;ÇyYA\¥d2™×ˆè ÙqkÝþ^Å$nQ98  ¦jöË(«Û¯GêŽ …ÃÁfÇqÖIŽ©Œt:ý¸âY™1evûõHߦb8 ¢˜eYAž¹)¶mo$"iß­ìn¿%{U žçEönƒ ÈÌUE·_²M¡²‡Ïó¦dÄÑA<Ÿ–GU·_Ò]Á²†!ÄåB¡ð¤´”S{ÉÅÕ01Tvûõ(ß.c8¨V«Çeæ¤˲Z~N ên¿-çB—¦§§¥?oO5ù|þ4€ß‚^§£Û¯GÛÁ% œ pÙ-Û¶÷¨*JK%žeYûÜ pÍYÅ4Ÿ *‹åd2¹ÀÍ/Ù¶ý¦¬—FEA>Ÿ¿mYÖNøë Î$“ÉÝ:‹Dø†ÚôîÏÕß3 !.W«Õãµn_Ú~Ä[¬¡¡¡Dôå–þ(„ð\B|žÏç’øy¾‰ü-7n|ŒˆžÐGD©úµß.{k³„O˜Åb…Ú£å##òÉ•ééé3Qç¡‹šàmsK˧ƒ ‡0ÀpXÃa ‡0ÀpXÃa ‡0ÀpXÃa ‡0ÀpXÃa ‡0“¨øm(„к37JLàºß†Dô§ÊDÚ c°,ËÏY„Àm;cH$'áïÀæÕZ[#ˆü\€N²Ùìz×uÇŒ¬ÐäªmÛ{;ù4RPš>-¼›˜™™™K§Ó§]×ý›ˆÖX Àð‡eY_¬Y³æàµk×f#N“a†a†a†a†aF2ÿˆÐ¨2²¹IEND®B`‚olive-continuous/app/ui/style/olive-light/png/ripple.16.png000066400000000000000000000007761370472574300242200ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8µ‘1NBA„g6”$žv7!( · ¢÷5„Äsh£ÁFð*oA¢ öÔtÔol y<ŒÄ)wþù&ÿ¿À*Æ8Ž1ŽO͸SfY–ò,‡üFï}/„p €ÇfC™÷¾wBœIzòÞßÔÓÞûkI$g!„Á`÷0•Ô$™›Ù²0³%É\RÀta«Õê;çž\ÕC$?@R爷0¹üˆëõúäÝŽˆÝ ]3ëHÚHÚ˜YÇ̺$ój{Jiî ¥40!¹•4j·Û½zSŒ±/iT •_H)Í%e$ï‹¢ø¨V«Õ€IÙ> ê™-,~XWföòíçŽtNS¦sîõÒ‚³úLz‡køõKIEND®B`‚olive-continuous/app/ui/style/olive-light/png/ripple.32.png000066400000000000000000000013701370472574300242050ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…í—±‹AÆ¿·Ù(»¹&Å’&¸S¤K!9P,‚…׉ ÚÈ)Øiý›+ñAl´²>!…"X\°³Øb9–4Û¤ÈÎ)Ìî³0·lö²·s{Ñæ«3óÞ÷›y,3 üï¢óä !n€ïûp•"µªîBˆ;ÌüÀV³Ù<œL&?ªÔ1ª¸Tÿ3€¥h °r³hÂqœ Û¶Ÿ¸ÉÌ_•ROÇã±Ô)Újµ–e½dæk>I)Ÿ…a8]´vá ÌÌ÷Ü`Ñ Ó4ïꘀeY÷˜ù:þlp˶í=Çq6´2æ½ì8%ºI’Ĺ¡^ÄÀ)æõzýƒ.€aï‰è@"h·Û–mÛ¯òæFQ=ò<ï—.€ïû?•R|+ƒ cóZ­¶ àŠ® }gæËùXS#)åv†S£Šù”žÄq *ÝdËÁQÇq²_Si Ò÷À¬¯\-ZœB ˜yD´ãûþNvþ”ÖÎÕK¿‚ ޤ”OŒr ½F£±Ûív/èn¯Óé\4MóM™ù„a8•Rnç!˜y3Š¢ûºJ©̼Yf~ ¢ðÞÈ+I’ºŽùB€,í`"úÇñ;]¥Ô["ú2ËÝ/2×R¿ß_¸s!ÄÀu]Ïu]O18KnV¥ïáp¨Ê1«ç®üA²8ÀaA|&­ü×l­ß]!û§Ý¸ãIEND®B`‚olive-continuous/app/ui/style/olive-light/png/ripple.64.png000066400000000000000000000022141370472574300242100ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ªIDATxœíšAoGÇÿóÖrŠ^Û» ©Šè™/PT¸U%êgê­ô¾ B‚ýí©­"%¢Ivm+· 5‰‰6;¯—5$ÊÚy3Y{™Ÿ´—ñd潟vggÞðx<ž#Œr1éÔÔÔ±µµµ»näM/kµÚÌüüü£Ž%õ„066vÀ4€ùuykkëÔúúú…F=aη¶¡ãJÀiaÛÐq%àÐà¸À5^€ë\ã¸À5^@ c89O”5wÅöÃ0ü2‚;Ì|À€y­õL·Ûýû A "Žã‹Y–ÝpÀ¿J©?²,{Ôív—mƳº¢(š$¢Ì|@ÀqßÑóf³yÎfL Fã|–eÏ\Ëç¬2óu"zEѤ͘Æ¢(šÔZÏ/øù¤RêžM ˆè€“?k­çl$ Ø‘|µ_fþÃY‚üqëGÕF‚X€$ùί²ÑØ_¬±‘ƒä¡”VQƒü&èg$a_&ÉØ‚àÉÄ6AðÀ† «XÂ@a^ÐZ?†,ùM"š^^^î úZ±²²Òaæïü#è^ÕZϵZ­Kƒ:õ†á"zà Ád›Dt;I’EAßÑét^3óJ`æÙA Öä{”)aϪj˜ü§Ä¦Rj:MÓ…»|ÆÉ÷Ø#Ⴠ#|]p¤’ïñA€RjX»·CKžóÇG ÑhœWJ=£#d×[k×"x$ìyeïy ~Æ ÷+…§+C …ï×A4›Í¥¢öv»=!£¬ÍZáN°ìífÙ”¹Sí{8¬ÊÞ¦< v:×Dô#€MÁdUf~\¯×Å·±)qŸ%¢§(ñŒ²o= I’E"º ™„ñJ¥ò³ ŸZë‡ÍE4QEÈD3Çqé;Êz½~†™¯ºNÅ5A Jk]zQ”™%cͪÂB išJN#VWWßx5 ‹U]Âø»À Eµ¹÷J©ŸLÇ4à€÷í¶E«/CI’,fYvK)õ>¢ˆèFš¦omÆ”Ðn·ßø@/Qð§Öú¦mEêÀÏêÄÄÄøöö6™Üöeì[­ÖéJ¥¢—––$Uâ¾XíqÐl)kñÿà:×x®pà:×x®p+E›˜ÒP\ øUØ6tœ¨Õj3f¬ç×lÞæñx<žQò?é£:©CíÅIEND®B`‚olive-continuous/app/ui/style/olive-light/png/rolling.128.png000066400000000000000000000061071370472574300244510ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( eIDATxœíÏoEÇ¿¯§fb϶¬ä ¼î6¶ˆ¢‘ lbÄJxù!.!É^Â…¿. Á…'H@¬"~(¢•vŇu (Q$vÂØŽ5Qb »{ÞҎƱ=Ó=]¯¦g\É«úõ“ß×U]U¯ê‹ÅbÙ¡äzíø¾?”Ïç‡Æj¯}1Áž={FFFFœëׯ½ö…zõ≉‰}Ìü"3?`7Q™ÏÑ©ÙÙÙ/p¯üÓ yž÷€i"z™Ýè÷׈è+"ú¤Z­þØÇL¿°\.–––Ž1ót‡÷Ï(¥^½téÒ5S¾I099¹; Ãw™ù/mš1€Ï]×=v᣽ Q”J¥b>ŸÿÀ˜Ìåóù*•Ê¢¤_RLNNî‚à3ŽùÈÌÚÚÚ‘Z­Öô«ÇÔ‹J¥R±P(œ@üà€ÁÛR> CA¼ƒøÁ€…BáD©T*J9u;F°|f~(é³Ìü¨ïû ¸%ŠçyOx$ésÌüIˆ Mð×aæçtúd"z¾ÛgMŠ@IÎårï§ ~Äøù½’zVP.— Fã…f³ù €û¢_ÿä8Îéb±ø©¦0bæ$CÝ&"|t÷Ýw¿|õêÕ% >m‰ØG`üp3x©i4,..ÖÓØˆ>ÊŽØ»M“‹J©Ãig¾ïßÉÌgÓØX‡ˆ¾_^^ÈP*•ŠJ©¡)ø:(—Ë…Á€½A/—ËS~u‚™÷—´ @ǘ¿×Óþ÷7Ð>øëìÚvÍìììu¿¥±ÑŠä7VDôMZј¯½m¾Õ`ãR"Ð&©à`fþXƒû:7éªí–4›Í¦µq;"Ð"ÁàƒˆNÍÍÍ}¯ÁÔ°PÛ-¹|ùò"ú"­ÛÑ-‚Ô >€3J©×ìA)õ€3ºíêA*Œ çóyóüMÑw+++G*•Ê Ý¶MQ©Tn„axÀuÛnY'øC;] @÷<¿"únyyùäˆ)–Ã0<ìþ0º€ ~2²,‚İÁïŽ¬Š ‘lðÓ‘EÄ€ ¾²&‚X›A’Á·è'ÉRǬ`ü¾äOù|þá]»vý{iii­]ö°Áïkb‰`[ØàE°¥lðж"Ø$üd[l€ þ@³¥n ÀG°IƆX2ÆÌê[=Àï¿ÿŒŒŒüÇqœŒwË"ÎV+®¾¬—í–Û7ͬv{-[®X 6Ú¶] ´"èâì²¶Ý °"è_ân±wÜ ´"è?’äWÄ>*œ"z<Ï«$i?777%åK–’kb/e-“¥_ÉRð„+VéÈZð.–‚­º#‹ÁºÜ °"HFVƒ¤Ø ²"ˆG–ƒ¤Ü \XXX^[[ûi¹¥fÞ?44ô~–nëHÊÔÔÔ®\.w2Á?»ººšzæ”z;¸V«5VWWIˆÀz½þ¦€]#Að€v7„vEüC:.”Ô’P«ÕA¼ áÀ3¾ïÿUÀ®(žç=ÉÌOë¶uû‡uÝ&ª-!Dr8ðŠ€MiŽê6¨«ÛoEkFàp°Ï÷ý;5ÛcllìDt¿N›:»ýV´§„I Ìœs'É»=E)5ÎÌÚþ¶º»ýVDr%†ƒ0 Eo5Õ‰N_%ºýVÄ’BuaÎé°c‚B¡0¯ÃŽT·ßŠhV°®á€ˆÎ/,,ü¢É-q¢«f/¦±!Ùí·"ž®c8h6›'uúdÇqº¾'PºÛoÅȹ€”ÃÁ¹ùùyí÷íIS­V¿ðCÒçLtû­;².3 »¢”:  )ä–$¡ã8G\IðÌŒÉà†OÕjµ†ëºœŽÑüœRêÙ~.U­V¯:Ž3x=Ái×uš >ÐòqÑòî+h3Ñùf³y2êöµýç÷8%Ì™˜˜˜fæ—˜¹¼þK" œ#¢÷ªÕê×ß›ž `ñññ»˜ùCÌü³Ô×~Vr£UÂ{¬är¹…èjùžÑóÅ•ùùù_üÚk?L <3SZ{:x‡c°Ã±ØáXìp¬v8™€ïûC£££nç–ƒÁž={F|ßêµ@§û˜ùEf~Œ™w‹Eø¾_gæ³DtjvvöKh¨šÈó¼§Lу+++.xžwˆ¾"¢OªÕê=qÌô Ëåraiié3OwxÿŒRêU]KÁ½ZšœœÜ†á»ÌÜ.;˜|îºî1M¥kcct(•JÅz½þ3ÿÅw ‚O¦¦¦FMø&ATªö³Ánþ-ž¯×ë™,Àzu1IŠ*{A¼-å“0Á;’ä20Y:0$€4¥å˜ùQß÷pKÏóžðHÒçL–Ž @G]Af~N§O& ¢ç»}Ö¤D ±®àÃÈÀÎeˆ™“ u›ÐU°bÐ|*öŽÑÑѾ9)ìûþFÒÚ1qJZD¥R©¨”úöâéÔD"8.5h€P-áë‹‹‹uöD‰’<~ÓeOò›@«¤ IÑ7:íâ[ƤD M‚UÄ™™?ÖlSœf³Ùõ¹€íH–'¢Ssssßë¶+ÍåË—Ï‘öó ºEZ’ÁpF)õº€]#(¥^pF·]"H%óüMÑw+++G*•Ê Ý¶MQ©Tn„ax2iiY'èZY¿ý*+dý6µ®`ƒŸŒ,‹ ±lð»#«"H$ütdQ±`ƒ¯‡¬‰ Ö›-*Ù_$©¿Ð±bˆ ~_«t<ÐA6ø}M,l+ü £¶€ þ@ÑV›`ƒ?l+‚ °Áh¶Á-Øàï6‰ ‡C-FÙpÞòV`+„>[­¸nø°"\¶[nß4 °"<Úíµl¹`E08tÚhÛv%Њ ÿ‰³ËÚv/ÀŠ ‰»ÅÞq7Њ ÿH’_ûÄ­pBHìýënÉÊ]Á@¶’kb/e-“¥_ÉRð„+VéÈZð.–‚­º#‹ÁºÜ °"HFVƒ¤Ø ²"ˆG–ƒ¤Ü ”,ÍÌû‡††Þ/—ËݶM155µ+—Ë€Lðµ”–K½,X0Ôëõ7ì!‚·tº$21:KËiÉ(ÝÂ3Q©´,ÇmHD©ÿ°žç=ÉÌO§µs;º+ŠjK‘p³ºXZ~ŠÛ™ÿ§á}G5ØØ€DEQ­A‚ÃÁ>ß÷ïLcÀqœ8µ ·ÝЍ2ØýilÜŽTEQí)aÃ3çÇIrçî&ŠÅ⧈WÐùbÔ¶k”Rã­µÓ"YHZ$'Pb8Ã0Umƒ .¬*¥£½.*¥§½²=­¯­H’K Õ=„a8—ÖÆ¥K—®¹®û¬ã8oàf9×åèçÇqÞp]WK©ÚB¡0ŸÖ`¦´øý»:Bˆèüìììß4º%Žçyÿ°·ÛçM™O ×14›Í“:}2ã8]ß(Ýí·bä\@Êáà\THº¯¨V«_ ^Õð ˜èö[1v0d]f°D«„÷XÉår ÑÕò‹Åb±˜æÿ\©žRC¡sÕIEND®B`‚olive-continuous/app/ui/style/olive-light/png/rolling.16.png000066400000000000000000000010211370472574300243530ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(/IDAT8åS±NQœyµ‰_û.!( AEïY¿Cý´á®â/H4Jar·PÓQߨܑã8 k§|»3»³ohÀÌF1Æ;Ä9BŒ15³Qóñ˜cœXHº0s÷ï$I Ïó÷Š˜‘<˜E±€Ð&“ÌÜ}eYN˲œ€»oHfUEÅ{½Þ8„ðàºÝ3É4èˆÌC‡×?!ìv»O’•"* CwHÚKÚ»ûÀ݇$³fõ¢(ÖªÌI$Íúýþ¨])I’±¤YçkI)ɧívûÕÈóüÀ³¤´&Ÿ4  vIò,vˆ1NH.%½šÙm;ÑÌn$½\Ö_x¸´Mü×=!¬B+àòœ :çÝçL3»oŸó/6nÎ@”üúIEND®B`‚olive-continuous/app/ui/style/olive-light/png/rolling.32.png000066400000000000000000000014711370472574300243620ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(WIDATX…í–±‹ÓPÇ¿¿6$¹5t©æ Ý J…â cqÐENÁå Ë þ "Ürà$Þ!ˆ‹.7¹ÜAÁናtRºd)¥y§ò’ŸK/$¹¦ÍµrÐïô’÷~ïûyùñÈøÏ¢¬ Û¶WLÓ|à.3UJ­÷û}™gÓr¹l†ñš™oØ—R¾ðäPJ½'¢ƒqí^–y.5‰'B´Çé:ŽÓB´ÎR×Ä/W»ÝV³1Ï_›Ixò@¦’¦iQy SË]Õ™ ìÀ >1xH‚ox)ù´“±,HLÿÁªº3E€FðBüÄpùsì(€¾µH˜J€Nðö,ËúšaWgŽÀ²¬öþÙ$d`Ûö9)å-ð‚ß'¢öÆÆFŸak„ÍÍÍžRê#; óª”rÕuÝ·²Œ&`Ûö9"ºÁíÍǽ^ï±Rêc0IPJ­d‘JÀI ~ˆ$¢«à‘P«T*_1ìŒ ¥¼~iÎ*ÐX!”Roû¾Ÿ{FÙl6_VJ]`˜jU§ìž  BJ™ûa‰RŠãóøš¢›„N†œS [[[ø5ÃĨ/¡}.p„„´ÞÜ!Ä—º>5ð€')ã{¦Mm€ q_B<À³"ªCD—Â0üÝÄ'ɉÓeÃ@€_¤”šv¤f^«AÔHgÚç‘ º®[¯T*r}}Ó%žˆÊ,_€YÀyí3FK Hȃ€¹Ö/¢èŒf€çy‹DtO)uƒÔôEïÑ]ÇqÞ4ñÉA«ÕZˆãø€÷’{V•R‰èžÉÑ8Pêôà”*¥ÞÁñì V²Ü&AûhøŸô†(”>À…Ò¡Ô”ú€R Ô˜¢Ô Ô(õJ}@©(õÃRfYêNèÑø¥> ÔÌ¿> mVMiEÒÜgŽ¢Pú€F£± `ÀnòYIÆ&â¸ôÚÝ[F‹¬EÑe]¿8ŽsÀù —K}€ISÆ2yŠ?«Õê÷–e½àU fR‡ˆ> ÃðŸìîîn×ëõ,xƒî”ò³ãú·êTAPs]÷?O›]×­Av:UBÿ†¢Ù‘œß”IEND®B`‚olive-continuous/app/ui/style/olive-light/png/save.128.png000066400000000000000000000025511370472574300237400ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(‡IDATxœíÝÁkGÇñ÷fm“ z&Q…Xp]„ò·¤Çzé¡ýšBïu¹‚…âB/þÚS ÇȦn¨}¨ =L¬­K̾×CݺqS<«ÑîÎû}Ï«Ùúx%$y–!d7Ž}‚Éd²VÅ=U½KD[DôVìsꌈ~PÕ½õõõo¦Ó髦ŠQTyžoˆÈcžg 0ó'ÇÇÇ¿4=Hè\¬…'“ÉZ"O>ÑXUŸ ‡ÃÛMºhŠ¢¸Gi<ù7tÎ=N A4¯ù©•‚h˜ùÝXk7Ü0˲'ƒÁঠQÌ+@/ÖÚM§ªƒÕÕÕÇ) ˆ õRA5JÔ¬ë @]Fê*‚hF£UŽWÕ"òZÌüuäõgçççÎf³Ÿcž'T¸®kWˆP—@¤º‚®IUg5;XYYyÔæïàšDä "ªó†®ÕßÀ59çN˲ܦÚür¥Œ‚7ç  ËûÿÁÿç  ëûÿ3ó ˲ÏDäfÓ³´©*W€öÿ¿•eÙ} ¸Ìâç@ð¯, ‚² €ˆÈ6" 0€È8ø+³à2“àõÌ!€ÿf ÷=ƒªÞ-­3":tÎíõz½ÝétúªÊƒ ­œsýêû¼¤ÕXDvªì(éUiGH0f~ß÷XH0fÞò=¬Êo7Àx`<0ŒÆã€ñÀx`<0ŒÆã€ñÀx`<0ŒÆã€ñÀx`<0ŒÆã€ñÀx`<0ŒÆã€ñÀx`<0ŒÆãy`æßc‚ÂÅÌsßc½¨ê‹ƒ–ªzßáÍ€sno±qвSUïçÊ@¯×Û%¢ƒ…&BËì ßïïúì}ãH"¢<Ï7Dd‡ˆÆ•ÇB˨ò#³*«Ÿœœ›››ßEñ3¿ÍÌ7‰hµò˜(XoΟ«êÃ~¿ÿùþþþ˦gBu¥?cÝèÿ(ñÂIEND®B`‚olive-continuous/app/ui/style/olive-light/png/save.16.png000066400000000000000000000007751370472574300236620ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8í’±JAEÏ—@º+AÂ$‚66±K « XØëŸXˆ`$þ€ X vú‚ba·`‘ÂFȾká®DØÓ{ªaïÌ}3c”¤”"p 4ùÜý2Ïó{jcëIÛ’€Ðp÷$i+„p‘RÚ™&¨¸r÷»BåÞЯ“Ô ê8~»ÝîÍ,´éî/’\ÒY§ÓiUµlJï›™’ͬ’áî‹@þ#H)»fö*i/„0>‹¢¸1³£Êff-àxü„¬´ö€îXäïb–­J:q÷÷IçbŒûÀRÍìÍB×Ì–ÍlX3³`=Ƙ ‡Ãçiw€»Ï×¥¸þë3Nä_Pþ3»F3öÞ|-em|ÔšIEND®B`‚olive-continuous/app/ui/style/olive-light/png/save.32.png000066400000000000000000000012061370472574300236460ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¤IDATX…í—±JÄ@†ÿD°ÑÃÊâ8'¥¾V'¨•`#–>‰vöV‡b{ ‚ˆq¢‚‰W‰•Örû[5&^b"6ù!ÙÝù˜ÙLXAºÔÌVÌdø¿ˆä@U/Ã0|Ì3ß—¤Ílä~Á½^Hn÷ûýÛ"‹4Ã>[084Dä8‚ù"‹ÆFM‘ëÁ`p—æSÕÍ„iÒ9×iµZ¹31@OD®2|>À+€)|dâ(/DV ~£]yßs—£2’Ï$}ˆIçÜá(ˆ*3ð+ˆJ<ˆ½D'‚Ô/+Ï!Ì%9L€øÃÉ6€ƒäº²x+0w<ÍX À9×-ñM~ †ýŸd@/¶O‹ÈbbÝ‹sîFD.H^dm®ªË$·r˜ÙjZÿ'¹±ù¹s®+"䗠hÿ_QÕ ’¥ÊXö¶ËBTñ¶UuÀCŠoñY"Ù4³OQ`U°?_”è Ÿc3CE'Àtœž·ÿª¨j€ ð ßlKhË¿‹™­‘œûËȪz†áâßñ;Ö§o”\1IEND®B`‚olive-continuous/app/ui/style/olive-light/png/save.64.png000066400000000000000000000015341370472574300236570ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(zIDATxœí™1o1†ßÏס¯"eɶ ÁRuà@'FZ¶ñ3XÚ€5RÕ !±dÌ–?@r™’¥Î õb8ßç4~FŸåïÍ#ŸÏ±-‡l:w»Ýû³Ùì53?°ï Ï@¿Ñh\ŒF£ÌÁø·ˆl:ÇqüÀ €]7q° àa–ešÍæ`:æŽê¬P–ýŸ9Iq›Ãù|Þk·Û;® Ù p1íÑA–eï]K°P+uHðZà^‚ÕW ÕjMíÌüº0Ñ›þÌü5ŽãWãñøÚ¶VÞÏ€\Í|/z@DËåò]§Ó‰«*æ"ú@DßJºTú‰ôN€Ö:ð©LB•¯ƒw€z%x)¨O‚·€z$x-p/Á{ÀJÂg8øDn„ÐZÿ$¢(‘àp±XœÚŒ{ïÿbUOÙ™™×âÀÛuëmÌ °`Ϧó]`…¤€©`íb´ÖWRµÿDlŒ¢è2Ïs(¥žÀò½­1Z뜈Ì<ø×1lULØžÿ¯dªµ¾Š¢èò÷ÆÆ Œk@š¦gÌ|ŒjO÷”RÏ™ù¥RÊê>Â%E‹ ËóÿÇÌ|ì‹„"®Ïÿù"Arà…é ¸i€°‚Œ7CE7@Ê@?I’óáp¸üû¡/3À%ûNÒ4=3=Ü7™·I€ñ×6 0H& M @š @:€4A€ti‚éÒÒ¤ ¤HH& M @š"“ZSÔÃSc‘€¾Ã R“Q@’$çz¸3a —$É…t/ù_ìáj|ÈIEND®B`‚olive-continuous/app/ui/style/olive-light/png/sequence.128.png000066400000000000000000000020201370472574300246010ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(.IDATxœíÝ1n“AÅñ7k„‚>©‘›TáG@¢'-g C¢Ë5(1=€ ù)R¹ Mš‰"a‘¡Àù„‚C<;Êü¥›]yž¼–>ï³*²Û/ìíí=s÷×’^¸ûSIOâ·õ ]™ÙwIßÌìÓr¹<é¹™1ûûû///ßI:t÷ÖqOe˜Ùµ¤ù0 GÇÇÇ?ºìAú=ü‹‹‹’zlZL§Ó7=B0‘¤aÞKz½8F³Õjµ{~~þ5za[ŸùŸùØïËÌ®ÍìUôw‚æîœù ¸{s÷Ãèu›8÷3 ŸEs÷Yô¢Ø¬Ç,š¤èEq§ðYpöGŠ#Å€â@q 8P(ŽGŠ#Å€â@q 8P\“tÕ{…Ï¢™Ùiô¢Ø¬Ç,š¤Eô¢¸Sø,š™Í×7TÐÑúgáóèuÛúwèá ã/ó÷›$ Ãp$Ž‚žë„›HÒÙÙÙÏÙlöeµZíšÙsm¸5Œÿoý±ÿq:¾íz9ôO\ߺT×ÃÀÖþ©§îퟟҀîâÿoS7qÊÐ]¼uc7ñ¤÷N6¡»xëÆnâtŸtǸé&~Ô{#·Ñ]cýf|£9÷㤠ÝÅqÜ}–.¢»8ÒNÆ (ŽGŠ#Å€â@q 8P(ŽGŠ#Å€â@q@wqœ«t »8Ž™¦ €(¬Œ´Hº‹cÜt§ ÝÅaæËåò$]$º‹ŒÝÄ)¯†Ñ]¼›º‰Ó¿±\¿7º‰(Œ?ŽŒ—êá̺yãmêî ߃D7ocwoô‰nÞÆîÞè…nÞnº{£¿4ºysp÷æî‡Ñë6qîg>‹F7o=fÑD7o&á³àì/ŽGŠ#Å€â@q 8P(ŽGŠ#Å€â@q ¸&ºy3 ŸE£›7³h¢1“ðY4ºys¸éî^·Ñ͛ƼÇ=Á&ÑÍ›ÀØÝm"ÑÍÛ˦îÞð=Ü~ëá[—êz8¨é!ipË`ÂIEND®B`‚olive-continuous/app/ui/style/olive-light/png/sequence.16.png000066400000000000000000000005651370472574300245310ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(“IDAT8í’; AD_ «^cB##1Õóx Õ#˜x“<ÁÁÄÀ”.,2,3ljeU𪛦cÜK dû%éœRºöYc»%_Í€coB% 0šÜ+ CÓHÚÛÞÂ7àT9p\ú bŒ;Û>LJ¥.dòU `{+¨R®àaËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(TIDATxœíOŒÕÇ¿¿™‰÷OQþlVr½ölw¥•°B*¡ªÿN½T=t)ª¸$iz Žœœ@‚ N@¢ Ž[µ‡&m«l«H›Úq,£eÕÂÉz™ùqÀ¼Ézíñ¼çyã÷û£ß|7¿ßó¼™y ‚ ‚ ‚ ‚ ‚0ùPÚà.,,<æyÞÃQÍÑ¡qžœ™o;޳†áz½^_ŽóüªÈ¤+++‡ÛíöÓDt$í,]6§¦¦.\½zõ›´ƒÄÅI;À¸†5æwvvV¸i‰KæXXXx̰æï2_*•ަ".™ÀuÝJÚúar¶~dNf~0í ýˆ¢è¡´3Ä%sQ.í ý09[?2'€ ÀrDË,G°ÀrDË,G°ÀrDË,G°ÀrDË,G°ÀrDË,G°ÀrÆ*€ïûÓsssùqž3K¬¬¬ö}zœçôtŸ`qqñQfþ3ÿŒ™ÌÎÎÂ÷ý3_&¢ µZí¬;‡¡P¹\þ5€U"z¢Ýnç \.AD!¢ªÕê¿´ÐU¸R©änÞ¼ù23¯8ÏEÏóž¿víÚÃÔõ}ÿ5 õP«Õ^æç–––Ž„aø3?yÀ1€?çóù—×××;jîEËP(f[­Öyf~ƒ%;ÁËËËs:²˜ÈÒÒÒ‘ >Ð|à»ÿ»gZ­ÖùB¡0«#‹r …Âl.—; àxŒÃÊA¼¦:‹¡P¯XˆqÌñ\.wV‡JØm>3‹{,3ÿÔ÷ý_¨Ìc"årù—žŠ{3Ó!2’4fþ½ª<¦BDÏŒz¬ ”P,g:ôV’æwù 2ºmÍ3Ç™ï¡+Áùùùù¨”X€b±8ãºîÛø®yI¹onnNÉ/f"¾ïßàpÒ:ÌüøÌÌÌ9$ P(Ìzžwjš/Ä +Á;I§ƒ‘P1çïÃW[[[-…õŒ¢V«}àkUõT|'IMÍýMe=Cù»ÊbI%ˆ-€®æ`f~WqM㈢è=Õ5“HKÍ]¸~ýúgªëšÆ7.ÑGªëŽ*ÁÐèl>€Kžç½¤¡®‘xž÷"€KªëŽ"ÁP(¼Î¿"ú´ÝnŸÞØØØQ]ÛT666vÂ0<àªkÇ]'(€âëü=ѧÛÛÛ§677oª®m:Fc; ÃÓÐ#ÁÐ뮺élþ¨ÑÛig8f>v†]ˆè³ííí“}ÀúŽ&6_ˆÇ0#Á¾Hó'‡AÜ#€4ò8H‚=Hó'—~Ü@š?ùì'Hómân i¾}ôJ oÙ €£sEJ0“ÞXл,)˜ÅÝËïw¦‘`òÙïÞËžï"ÁäÒïÆÛ=_E‚Éã »®û^ˆ“à[î}/E‚ì3ÌóßÂÑü@ÈÀûÕw3)¯‡fQ­•RçRÊD4̼g± ‚`_)u†áKÛ¶wŸDQ´€Œ™w~0ä‘“5€q3óX?âyÞ•1æÉ®$¢]­õ‘-FD§³f µf¯iš{)å3Œ=žÑ­c׈xÃ̇#”UUµ!€²,/ CÄW"ê¿sdæß kÜ›˜$IjŒImŒˆò¢(ò)÷ÿÉy ]×= !`Sß÷Å\3g¼ck. åüIEND®B`‚olive-continuous/app/ui/style/olive-light/png/slide.32.png000066400000000000000000000012651370472574300240150ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÓIDATX…í—¿jQÆçlÒ'E,çÎB°H•§dí}« [ˆ5Æ"ŠE´|»Á€ïaauï¼€A»Àžc‘É:ÌîÎÎ "îS\æÌ÷ýæÏ¹s/üï’.ÅY–mªêí†ëÜ̾Eñ£­çZU½l,©Ù>¶öì°,¼Ôfî׮À `n‡Ã;fv¬ÏSJ_ú˜gYvOD^î~PÅ×zÍÌ!ŒÜý=°ÅeÛ½êH¾ÜRÕ!„Q#@a$"Çî>¨¸XO/Ëû@DŽëS€áàEODäYé±BÊð»"ò®¾ÀðS›`w°Äg<‰1ž¬µ ¿N•Oâmžç¨ˆøòKnNc<WßÕM«ú  Æxæîã:„ˆLTu/¥´RÚnpU¯ª{ó<Ý}c0³#ú͘jf¯ë]åîã”Òé´¨F>QÖtZ9ýÉ“Æð€+yœ?Edèó}LÜ}øœ›ÙÃz84ß™”€Óð<ÏŸ¶IŽ1¾© €Q™«jZ:ýî¼®F¿þ;^üsmv<­wEÐqgdfŸU]ŸwÞÝ/Dä[Ï•~•eËe©tg™IEND®B`‚olive-continuous/app/ui/style/olive-light/png/slide.64.png000066400000000000000000000022511370472574300240160ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÇIDATxœí›_oÓVÆŸ÷uÄ„¶tÖ®ãÔö*¤‰¢"4íÒ´>Á6vm_1MÜÚ¾ÂÄŠ&m|‹qhS«Qmmí&í%RÔrÃTŸ— ’’'9vŽs`9?©7ö›Çïóı{‡Ãá˜c¨Bm/ ÃψhYDÞ)# "O‰èqš¦÷d†ûxUˆ@†ŸøÀ±²Dt @Ã÷}¯Ó餦z뇫"Z6¨uÊ”Ö0•Pö´¡õ¶)­a* àMÁ`»Û¸l7`€ílã°Ý€m\%?WåSdYJõT+RÁûžç]‘ñâ)ïO¥Ôívûq™ƒOKǧ²,ûÀÿу,Ë~j·Û[ºÚg@E+Ì|ODΨx ÀYfþ}qqñƒÂÝOI³Ù<™eÙo>íöR‘sÌ|/Š¢]­¢(ZQJ­XÈÙ}œˆ®éÐÌ|Àñœ] J©UÝ&Ðg¾>ªFD>Âl¯ ^÷g8ŠºncÐ1ßEº³BaràZ!Œ  €yÑýI5†hÔM !7€"æì{žwK£Î(žçݰ¯Q:6„W‚`Y)uzæ˜ùÊÖÖV[£Ö(ÛÛÛ-¹ £Q^WJ­†axzxÇÀï(‚ef¾ àÝi$¢Ÿ§ÕèGD¾5 s@DWÒ4]ëm8:Lš©‹È/ýgsc¾Ç@ @¤”šÙ„ˆˆèk¢y@cFH3„µ4Mgv÷ØÛÛ{àï1%ZæÍ9Á¾òž¿ŸÑuÃüàYÎö}]ó@Yá$IÖ³,»@Dðrè¼ÆÌ_¤iú¯®Ž)vvvþð€žQðP)u^×aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(„IDATxœíÍoTU‡çÎeœ—€&…d¹·N#!“¨QÄÄ¿Vn P4npÿ¢+MtãÂÊG44°`éR£ ù €ÅiËdH%Øj¦Rî×38…–Ι{Î=wzÞgÕ4÷¼yÓßÓsîǹ3Ã0 Ã0 Ã0 Ã0 Ã0ËÑþ¡\.ggffÞn6›[<ÑúõÇqNäóù£/^œ3Ó"Ó Ýæ) T*­ Ãp?€‹Ô»äºî®«W¯þ¥¿u&.2yŠr¹œ­×ëÇpðÝAžçmå™ ÝÈæ™ñ<ï]"ÚÖEíÁ0 oNMMWÐ'£ Ù<ÖÑ2Ç2fÍÓÁÿ'Ý s,c©<dŽeÌ •§£­ ¦/`,‡°ÀrXËa,‡°ÀrXËa,‡°ÀrXËa,‡°ÀrXËa,§¯‚ 788è™îc16lذ*‚œé>dpM7°CCCOÑ;Dô­Íçó‚ ND§…ÇFGG@†Ú¾ï¿`›âÙÙÙY|ßÿKñ£âH¥RùÍPo]!|ß‘0666¬«™NÊårvzzú£Öwñ€COº®ûAÒo-•J¥µQ}NDÏ=à0ð½çy%õBlž©\ …B¾^¯"¢7ñàð`s†G†‡‡“è ¸ûêÕwK„Üé}{½^?T(òIô&Kê( ùl6{Àf‰a~†ŸêêéD†ŸxLbÌæl6{ ¤J€vøD´Iv,½Á+Úš‡ïû¯xAvmJ£© Nømˆè-•=-„b{¯cÓ(A*(‹+V¬ø*Nø-žÇÒç qD$³4ÝGK‚CëÖ­[©ª©8 X,d2™¯q'¼¸¬Ôö‡ ‚`5€UqëÑ3Ó Q …BÞu݃P~_Ñ’`¿éåÀ˜*Öü˜ºqãF]a½yŒŽŽNøGU½4œ@SøBü¬²Þ"ü¢²˜i @Wøˆˆ¾Q\ó>šÍæ·ªkš” Q4†!ı±±±³ªëÞ˵k×N !Ž«®kJ‚ÄÐ>€S®ë~¨¡î‚¸®»À)ÕuMHˆ ¯óïCqfvvv÷ÈÈÈ-ÕµcddäVE;üªºvÒ÷ ´  ø:Bˆ3FcçÄÄÄ´êÚKQ­VQí† »O U€å~›å 6–{ømú]-Ø~›~–@¹¶…ߦ_%Pº'Pgø@DÏær¹ó¾ïë(Ÿj:$xOå?€²@wøŒž™@‰~r¨– ¶~ò¨” –¾9TIг¾yTHГ~zˆ+´~úˆ#ñM¡Œ2zz?RZw¼˜Þˆs‡´§€%Hqo÷¼°æQñl$Ö9K`UÆbŸ²É£ò©¨’«– 9T?WvÈèGÇ~¥ûªÕj£X,îÖ¸!äl£ÑPú<\%ý¸Fù ~Ý—~ Ðt'Ð6 ú5|@ã­`[$èçðÍÏ–»ý>Ààå*ÁrHèi`µZmܾ}û}!ÄiÕµ‰è™\.÷U¹\Ϊ®½ÃÃÃe2™Ðþé¹¹¹Ä®t{\«ÕfææævêÀæz½þ±†º †á'–úHiZáï¬Õj3ªk/F¢ûjµÚL†ïAÏÍ¢-A¼¬¡î<|߈ÞP]·5íïJ2|ÀÀ†Ë€½jÞËÕ“žö;1²#HãrðTk×¼K±X|Dñ¤Êš&¦ýNŒm Ó±QÆq™Ïð•ÂuÝõD¤ìofjÚïÄèž@ËAEÚ¾Aem“Ó~'Æ7…ª^¢(SQg!²Ù츊:¦§ýNŒ ¨[„ªÕêߊں֗R\ŠS# Ó~'©P³4›ÍÃ*{ZÇqzþœÀ´Lû¤F örpn||\ùç÷ÝK¥R9à¼ì¸4Mû¤Jà œ”vÝuÝ=ššÚê$rg€ëcN¦1| …w$ðd¬à5•R_´Ö­{ÐZ·ˆ¨/"•ˆÂ»„ÏÝ@¤BDý²ÙøÀÛ\ ½ž­C$h­Ï3ð çÜ÷Ü͵v*„1æY2´Öú×bà½à×1|оÀ f.í‚}ÁâIôŒ1)–Êò‘¬UîYKœs#¬Ìá®OA|~­9çFƘ6}Ê,ÂÁjM¬Ô4nªMîçÜHD:««@ÏZÛÌÁ­µÍ\D:¹àÙ>སB0óÇLbæ«Ü{?Ìq6vÂTˆPC ;Ñ_ÁK,BÑ+37DÔZ¤sé¸0cæ—ep ш6yCà²RÀˆÞ «Ê6¢Éplé)tô$§ À4O7w¬‚YUJ½XüM:ýÌW’Í­>%øŠIEND®B`‚olive-continuous/app/ui/style/olive-light/png/slip.64.png000066400000000000000000000022461370472574300236710ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÄIDATxœíšAkGÇÿóVq‚œPtÔJÚ(„¸¸‰KK{ÎhHr ±ÉgHJCoq.îwp É!~‡ö’´lZÓlïj…ñÅØ[ï¼*Ñ”ÎZ3Ú‘ÆK÷3ó˜}ÿ?+í{o ””””üsssgööö¸Ñ_{Y«Õ–VWWÿr™˜m²tzSSSßXðAÿsµ×ëßßßÿÉU²ã K'øJ¯Z+:Jà¢bCµVt”:iâiœ2J\'àšÒ× ¸¦4Àu®) Ó¹¢ g¢bó0ß÷/yžwŸ™?0`UJ¹Ôívå¼0 ?NÓô€kþB¼NÓô»n·»e+gkw@³Dô‚™¯¨8 àK"zÞl6/›ž×h4®¤iú Àý³ªÌ|ˆ^A0k+o+A0+¥\0­Ø>'„øÚôL"ºàœbkZJ¹b˄ܼ'¾šÃÌŸÁì;ìõ¿FYTm™Ëñ}¸ÿÑEb¸aVLÙñB˜WÀq¹MÉñ<Ï{lz Ïóh„æ2ÁØß÷g¤”ËÐHD [[[]Óëloo'Ì|À[ðª”r¥Õj}bz#|ߟ!¢§.h„Ñ|Eë¦I H’dƒ™ïBÓf~bj‚¶“?`Ü&ˆf³¹©Úèt:íÁ߆âO‡Bˆ…8Ž× Y:‡ÞÜ 'PPñ´LÈ4 àâ 5!Ó!„iõvjékQ’i€á¯ïieèÓèÄ߀‚› õ(ú(¨ ÚuˆÖD(I’F£qWñzï ÿóÎÃ8‹0íJpe©ŠqW F½À¤M˜DùmÜ &I²AD÷j„W™y¹^¯·‡‡þ›0 ?"¢ï1æÞc¤y@EëD4=¦+•Ê#ÓkH)¡ßrÜx<21™? ÃP»¢¬×ë2ó5ÐÜ]g®™  BJ©=efX+-wî©°¦ kqk×;;;oüzBˆµyƒ•÷ï™ šá !¾á؇Žë¶Äß EQ´ž¦ém!Ä/ø§‰Z#¢qÿaz^§ÓùÀM¡ àg)å-[â͉)ív{úøø˜Lnû“hµZ+•ŠÜÜÜÔ™+ÉÒiõåè€<‰ª°e¤Šòÿ\'àšÒ× ¸¦4Àu®) p€kêéN‘ º(u€ªµ¢£ÔéµÛíW½^ï<€w_ÏkµÚÒîl~ã%K§ã´JJJJÜò…ãÕv>-5 IEND®B`‚olive-continuous/app/ui/style/olive-light/png/transition-tool.128.png000066400000000000000000000023431370472574300261460ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÚ½jcG†ñg&Ä!ØÒ8 æÜKR†í·Þ;ÈMl|.Òì½Ä6ì„Ým0qN)4)âMâøK:g¾þ3ﯓãçE’AŽ[Ã0Œãø*„ð ðø©ÉÀ{ïý»ÅbqzvvögŒCÀz½~±ÝnO€ã‡JrÞû×›Íæã܃ü0 ŠoÎñv»=†á`îA~ÇW(¾EÇ777ßÍ=Äß~æ‹Aιoçžás_ǸŒäçœ{9÷ BXĸŒä£q±KèœÐ9  s@ç4€Š„Þæþ›@%Bo¯®®4€•Š@q%ãƒPTéø SC|Њ¨%>hÙÕ4€¬j‹@65Æ ‹Zãƒ\ÍñAHªöø $c!>hIX‰@t–⃕µø Dc1>hQXÀl–ãƒ0‹õø LÖB|Ð&i%>h{k)>h{i->h;k1>h;i5>hÏj9>hOj=>hê!>hê%>h÷ô4€;z‹À?zŒÐo|кŽ ÷øÐñÿo]@ñÿÕÝÿ®® ø÷u3ÅXPüÇ5?ÅZÓPüç5;ÅßM“PüÝ57ÅßOSPüý53ÅŸ¦‰(þtæ øó˜€âÏgvЇÉ(~<æ øq™€âÇgfŠŸ†‰(~:Õ@ñÓªzŠŸ^µPü<ª€âçSÝ?¯ª øùU3Å/£Š(~9Å øe€â—WlŠ_‡"Püzd€â×%ë¿>Ù øuÊ2ůWò(~Ý’@ñë—lŠoC’(¾Ñ ø¶D€âÛmŠoS”(¾]³ ø¶Í€âÛ¶Z­ÞL€âÛ¶Z­Þ„¦ @ñmû&|8çß°ÿÆp‡‡‡?—¼Ìsyyy´ëkÿ*øU°äñP|кðX|К÷T|Кö\|КµK|ïœû=Ç…$>çÜo=¿k|Bø÷Z’KáÞ¿ðûÄðÞûwq¯%¹„î´Û7>€_,§ÀEÔ›IËåòôÓƒ)ñÀz½~±ÝnO€ãˆ”t.¼÷¯7›ÍG˜à3€ëëëñèèèÇqqÎ}åœûø<â…e¦Û/ë?…~X.—ߟŸŸÿ óâÃí;€Ø47>hfň€I±âƒ`NÌø ˜;>hf¤ˆ€ ©âƒP½”ñA¨Zêø T+G|Ъ”+>hÕÉ4€ªäŽ@5JÄ   ¥âƒP\Éø#›4„3ÖÂIEND®B`‚olive-continuous/app/ui/style/olive-light/png/transition-tool.16.png000066400000000000000000000006031370472574300260570ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¡IDAT8Ó» Â0Fás­ r : –`:“aà ae„t4ü4 ï$×qe[úŽ]ØæîgI*†™]J)€fÀW âFÒv\7Ãf/i·„%µfð ¤èµ%µ]×µßû¡Àæðb` Ï"x2Å5ø'P‹?k0 /QÒ=¥ts÷cÀìlj»g[û™€“¤lu~,)TÞ1Àz©mŽÂº3ìIEND®B`‚olive-continuous/app/ui/style/olive-light/png/transition-tool.32.png000066400000000000000000000007141370472574300260600ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(êIDATX…Å×;‚0FáKXA(\€+¢§r6Ô,Í&,CŠk¡Ì "òȽþeR|'eœ÷þ Àݵ@B¸ô#œ§Q¼&Fx·ÝP€êD¤»W ‘ªišÿLÁÕ¦â*sðèsñ¨KðhKñ(kðÕkñU1ðűðE1ñÙ±ñYøä-|R€&þ3@ °À¿XზøG€sÎÏó¼tÞû«B8t¸ˆ” ‹Õn}`“¦é8e¼ê,ËNà”Ñ—õ_n0„›|ÃMÆp€;Ìâ»í]ýFJIEND®B`‚olive-continuous/app/ui/style/olive-light/png/transition-tool.64.png000066400000000000000000000013151370472574300260630ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ëIDATxœíÛ=NBA†á÷B€‚öj)ì¢nÂÆ7¢¬Áž]Øv`$4·± Bb?÷gæÌ™ƒ_EÈ%9Ï‹!Çõzý윻®±±0Ëóüu>Ÿÿœz°Ýív_€G /ršÌúÀmQÍfóqêÁp/sS”=œ{ …?ûC»:÷@Kâ ÍûûsÎMë~6ùιér¹¼ÌMñpxH4€/<$À' à ‡D„ÂCBâAy€ÐxP@JHáAaI<( EbàAI€XxP &"ˆ‡ˆ4à!R-xˆ@„hÃ`x  4ã!píx < H ž¤†Ră§©âÁC€”ñÐ0@êxhÀj°‚‡,á¡bkx¨À"J°Š‡,ãáLëøáp89 Ë2óxçÜ$ _± ¹Åb1Úo‡ÿ”Þ_<\X€}aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ('IDATxœíÜÏjSA€ñs"uÕ?“Å]H…d_”Hž¡¶ô%| [Ýö5„¾…µ»Òm6º²í¢K„(äBwbÆ…]fnrïSã|¿íLáÀš¹|"ò¢Ël‡kÓét¯Óéìzï_¨ê¶÷þIªáPMU{ïoUõË|>?+Šât4ýZøïÝØï÷÷½÷ïDäY­Iae¢ªÇ777ټȧ·ÓëõÞ‹È‘ˆl4 6DäÀ9·U–å…ˆøØæÊpÿðß´4ì œs›eYžÇ6E@¿ßß—¿Ÿ|¬¦A·Û½œÍfס ÐÂp8\‘·IÆ‚¥Ã§¡Åà˜N§{Þûçif‚ïýöÝÝÝnh=xTõuš‘ðöB ±ð2Í,°{–Áà½/ÒŒk±g<Rñÿ#VÊ<´û ø‘fXSÕŸ¡µØWÀç4ãÀZìYÆÀ§4ãàœ†‚ (ŠSUý–fXQÕÛõõõ³Ðzð§àÉd2wÎ}‘ƒ$“Á„ª]]]} ­Gïf³ÙµsnKD­O 'ãñøClCåm`Y–ιMᬚ“ñx|,M¯ƒEÄ—eyÞív/Eä•ðNÀ¿n¢ª‡÷ŸüÊßrx%lÅ5}% üß–º ²ÆåS5³>€5zµµÞ°F ™vûÖè´¦yÀ=‚ÖÕïX£GL½>€5ziÔîX£GÔò}kôÒ©Õ°F º}kôÒY¾`A:µúÖè¤S«`ARË÷¬Ñ#H£vÀ=‚4õ¬Ñ#h]ó>€5z­i­`A3éúÖx%¬}ÃeЊ£€‡èdŽ>D„>„>„>@Þè@„>@ÞèdŽ>èäŒ>@æè€>@®èdŽ>@ÞèdŒ>@¦èä„>ˆá2hÅÑÀCô2G"BBB oô B oô2GôrF sô@ Wô2G oô2F SôrBÀrþôre—gyÒIEND®B`‚olive-continuous/app/ui/style/olive-light/png/treeview.16.png000066400000000000000000000005311370472574300245440ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(wIDAT8í± 1gy$hÁuÖw@tñÅн ]ä>;^ØÂÉKLzÚÓîÀÌRDÌt éáîUf–€;pîy¬ÀõÐún¿M8¸{êë6åœ/’NÍ ¶”Rn±4d:ø iÂÛÁø{tðÄß6ø‹è?+IEND®B`‚olive-continuous/app/ui/style/olive-light/png/treeview.32.png000066400000000000000000000006141370472574300245440ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ªIDATX…íÔ!Ã0DÑã‚à†ì} zÖßgIŠÊ·Ä©ZÕuˆíìG‘ÆŠ¬·ƒˆLfI^zšÙ“dRÕõ}™ÜÍlî9¾ErpSÕ5ä[ÅQãyo6³aÔè¿Lù· ‰äB2…GàÚyÿñù=îÒÖˆ¢{ãhlĵzq>jõ0¢è@­ÆF¸_¹î€;à¹î€;px/L§¸%Eé!]IEND®B`‚olive-continuous/app/ui/style/olive-light/png/treeview.64.png000066400000000000000000000011211370472574300245430ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(oIDATxœíØ1NÃ0ÆñïQua²˜}ƒn½GéÆÌ º3wëÈ1X™X {å#xéÈcÉ1 VxéS¿ßf7JŸÓH•þÑE“S›1Æ;Y©êµñL“‘£ª¾ا”ž|^oÄÜ[ 7ƒ]Jé±ÜX”‹¯_~k:’­u¡Ë9¾7®ª 6ÆÍ¡wÆÞ‘•í,öê3Öo€Î2—rÑ{ªún;‹=UíÊuýì g™Kœó!„°°6ÉÎ.¥ôTn,ê+rÎ/!„À­ˆÜXZM÷DäàÀ¶><]º“= Õ9v„?÷€VN:Âï= •£Ž0ÚZyêÃ= •§Ž0ÖZyêÃ= •§Ž0ÖZyêÃ= •£Ž0ÞZkG` "¢aìS}{{€ìåš=`Š;²°°°‘CìS}{{€ìåš=`Š;²°°°ùô CgÙíbšjIEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-down.128.png000066400000000000000000000030351370472574300245430ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(;IDATxœíœK‹U†ŸS“(b3à°¦Ó‰`@W‚‚ ‚Y¹6·êBÄŸüêJÌh²vçB·B@P¦;’,$‚f˜sÜtCOwuO_êr.ï³8ÕÕõQïÓß©®>5 „B!„B!„B!„B!„B!„B!‚Ä,³S§ÓéXk/dY¶`­}”eÙÝ^¯×+µ:QH™çnΟ?ÎZ{xxnÊË€ï²,ÛÞÛÛ{°h1b:UÿyXÛÚÚúøxb®já_àË~¿ÿ9p<ç>¢˜JÏÿL.^¼øôÑÑÑÀ+sxœ_Z­Ö‡»»»-¹ÒÔqþ§ °¹¹ùäÙ³go9ç®,yð!;ι÷ïÝ»÷çŠï“yž¯cn—WycÌ‡×ö÷÷ÿ)ÚžMÛ±ÕjÝ(!|€ËƘ›yž¯—ð^IPVøÎ¹+­VëÆ´í…t:·€««|I0'e†?ÂÕA¦ `œsŸ”xð!—1Û’`:Ýn·eÙW”þO)È{b Ïó×€*(à’:A1yž¯SÒ´;sîBžç¯ŽO‘eoVQÀšƨ¨íOP”mÑðr•E Ðt0 â¶çÜKãc8瞯ºÉOU·ý¢CŽL`ŒyªžZ€„§ƒºÚþ(EÙu€Â’ÜtPgÛÅ9÷÷øXÑ5À~ µŒ“ÌtÐ@Ûå`| h ø­žZ&ˆ~:h¢íR”í„ÖÚë)§h§ƒ¦Úþ(ÖÚÆÇ&èv»?cš˜†\ŠM‚n·Û¶Ö~ÝPÛò`ccãçñÁµñ^¯gÛíö!ðF-eóŒ1æõv»ýýãÇÿk°Ž•Éó|Ý9· ¼Øp)Ÿíììü:>XøcP¿ß¿mŒ¹S}M3 þš é9ˆ1æN¿ß¿]´mÚÏÁvmmíc ®k&X | 8di‹6Î\Ôét:ι[À³UT¶A-*ñ(ü‡Æ˜k³‹žº&p Á·À¹2+[‚?œs×}—À“ >€GÖÚ÷îß¿wÖ‹æZ, æ#´ðaeá’`6!† >" Š 5|XâÉ Ip’Ç “á‡K ’ †ða ] b VÒ“ ¦ð¡  b Jâ— Æð¡D ^ b Jâ“ æð¡  b*— …ð¡B \ R *“ ¥ð¡  R jü— Åð¡FÀ_ R jü“àÌ™36Õð¡À¯Õƃ¿Þ¯Þ­ŠF¯:AÓ4òÉÒ˜ h8|hXHZ‚ÆÃ€$%ð"|ðDHJo€$$ð*|ðLˆZï€(%ð2|˜ñï⛤×ëõŒ1ï›®¥cÞñ1|ð´ ‰ xûÉâµ´Þ‡AJDøˆ”Á„ AHTø˜àµÁ… ^Jdøàé}€Óðì>×ßóO#È0ăNì'HÐ@£>D 4"AáC$@­D>D$Ô"ATáCd@¥D>D(T"A”áC¤@©D>D,”"AÔáCäÀJD>$ ,%AáC"ÀB$>$$Ì%ARáCbÀL ’  %H2|HT8!A–jøÉÓÐtB!„B!„B!„B!„B!„B!„B,Ìÿ =ÄB»C‡IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-down.16.png000066400000000000000000000007751370472574300244670ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8Õ±JÃP†¿ÓÜÜ5Ádºn öE¤tsÖ—ppsèà®Ѿ€ˆàæ 8tVÛt©‹2…RŽK"ÓŠc¸Ëåÿ¾{σäy«ê Àf³¯V«Ï}€s. Ãp "×8†ÖÚsî|—Ä9—Zk§ªÚ¯¯^zª:‘-€ªö­µSç\ú,"[UUU}Äqüœ=àÈs’$ÉSY–_Y–%aN€ã‘«¢(ž¥y!Ïó¡ªÞ¦.̓ ¸X¯×[cÌ´áÅbq ´â½‰È­ªuù½­õíËårùØ0A[PUÕkEsù§>ð/ÁÉN¸SÐHšÅŠˆÖ {èêî÷~ä½ý<¬|–õ|¼8’¢;IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-down.32.png000066400000000000000000000012101370472574300244460ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¦IDATX…í”1nÔ@†¿÷6¹À¬½eÐ^…!%'@ér L½A´Ôá¹ A7²¬T(Òe~4žÕb¼¶c¯RÀ~•å7ó¾ž<†;þw$>¤iº/"‡fv™çù×mŠ6õ—ªøxìUëªêKïýå6ä³Ùì°,ËÅzà4Ïó "¯ÖŠ{fvžeÙÑXy–eGfv^ï_9Q3sõf6cBT{U¯z· |nj0&D›|Ý©ªz„m…è!•“ Àr¹¼I’䣈<4lPy’$Éuá[›çÜÜ97¿wñŽÿ¿B©þ´SÁºIEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-down.64.png000066400000000000000000000017451370472574300244700ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí˜?oÓ@‡Ÿ÷¬@UT”HLHv-ÑŠª ̾E °—ÏÁ¢ù¥_ K‘@ÌÒ$bBÂÊÐQûš'UþØ>Ÿ#qÏŸ»÷÷äîl‡Ãáp8ÇÿˆL;±±±q3I’@)Õ999ùm¯¬â,Zÿ5¾ïßUJ½ž+ƒæ à(I’·Ýn÷GYE› kýcÂ0ÜÔZ·§ôßO’äu·Û=6]¸ Ö××™Q¿ˆ4Ûíö·aÃH@ ¥Ô¡ÖúάADä,ŽãË&Á÷ýmÏóöµÖ«³®‘ŸI’ìt:_*u¢9/<€ÖzÕó¼}ß÷·‹—m†EÃh­ïˆHsxœðdÑ—IB–ðCÒYG´ÖA–—ABžð0žU¥Ú/²P¥„¼áŒ²¦—À÷<…T!¡`ø±¬éð)oA6% ?`”Õ~ˆ¢è¤^¯ßîåì´¦”z¶¶¶ö¥ßï—ò°d(üÑééé»áAz "{@+oÏeÎCá[µZm/Ýॢ(ºl4‡"òÈtWHQ‘çFãkE½¼•¦ ‚`kþVnŽã8Þm·Ûc›½7yUE—õzýsQ ÀŽ Al)¥ „oöz½óÉ×ÀòH(;Dä ®¡óö´DäÕäÞÂ5ØÔL(Bî_~H¦=`C{B^ ‡‡‚ 2 FƒðO° ø&úœAKD^v:\k~#ÀØ«ô<Žã8Þ5 €Ò—ƒ±iŸÆ¨(MB)á¡`|O0ºæ')EÛŒ¯ùIJ…—CiÓ>M© ·+áÁ‚È,ÁZx°$–`5aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(DIDATxœí±ŽW†ÿ“ !¥q„²`O…Ò@•~EJJ¤ Ý‚6¼@)4t %yD(H  ÛØŒ¼l±4Eò"kNŠ]+Þ½ÛsϽ3÷ÿêÝ{®ô:g|g<!„#â{m$˲$Ïó[2U½à €‹>‹È>€·eY¾‡¯”>÷Jêe«ÛíÞpÀ7þþƒˆ<Èóü…ã}-„ÔDš¦—TõUý~>><<ü§ö-Ô@š¦]U}¢ªÛ,óNDîåy^Ô¶± |eY¬ôz½^Y–¿o>\WÕ‡Y–%µl¬"[–ÅÚF¯×ë©ê¯.Õ´ävQ_F£Ñ›šÖ[ GÀšœ„ÿª]ì­ÂQ’$7ûýþ§š× GÀ8 .L&“]ëÎ…¬ÈLÛwþ”Û0êÎ`ÌüE\NÓôªã(@efÚ¾ëð§\³(B*`ÔöO¡ª‹:` †mÿ"¢uLš†ã«ýe˜œ²,ÀGÛŸEDö,êP€9øjûSDäã`0Ø·¨ÅpÏm ªÏ˜\°ÌBø8> ~jUŒœà{æÏðÈê>@x9äYÄë4M[Œþn` mÞ‹ÈŽõ!Q àûj†÷ªº;ÿ².­ ÿ˜(`øÿ ÿ4Q ÀðÿO40üùD!Ã_Lë`øçÓjþrZ+ïF+`øÕi 5Z%Ã_ÖÀð×£0üõi¼ 3-ÃßœÆ Àðë¡‘0üúhœ ¿^%ïŸÆÀðÝо;‚€á»%h¾{‚€áÛ¤ ߎà`ø¶%÷'¾‚ ¤¯hÇ>À "z3Gtáž;Û¾¼ ÀðÃÀ‹ ?Ì`øaa*Ã3~˜˜ÀÏùáby`òîÛ%qð1Ž€=UÝa8&Ö‹@JpBÌ)x½< Ž\Þ :&Z ¼,¢~ñ.Àƒ"Ÿ!ÀNà‹`(‚ Ö'@ , R€X¬%° hJàšà(K!@ \ÑJà‚F P‚ºiœ%¨“F P‚ºh¬%¨ƒF P‚Mi¼%Ø„VP‚ui%X‡V P‚Ui%X…V P‚ª´V€T¡Õ”`­ ç…%XD4”`Q P‚³D'@ f‰R€L‰V€‘ „õÕtÙÉó¼°,êý÷|“çy."?øäy+ß©êÃ,ËË¢[–ÅB¥(Š¢Óéü à_{ÜÊvQ_F£Ñ«‚Ñ€YGI’Üì÷û&)ú0K ãàÂd2Ùµ*FÎ0#Á¡Çm܆Qw¦s8‘à.üIp9MÓ«…(Àf$ð5®Y¡çàs¨jÇ¢X‚¯q "&¿¯@*ài˜œR€ŠXÙ³¨CVÀjˆÈÇÁ`°ï²Æ °"ã@UŸÁè7–(À8>1ª=SðADäyþÂñ¾BeY’çù-™ªÞpÀEŸEdÀÛ²,_‡ÃWJŸ{%„BHœü ônýuÛm4ˆIEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-left.16.png000066400000000000000000000007621370472574300244460ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8•“=NÄ0…ßà4IgÓ"97@H(Ú+7 áÜíM¨VpÖ«¤I+‚" –Œ×Iv§œ™÷Í=„=M)uJD'žË²l­?ÚS¼$¢'fÎÜÛØÑâ›øb"ÒÃ0<º9£#Eq Ào…wu]¸y4!^yâ[­õ»Ÿ»ÓRjéUÖ}ßßø•ƒ„fžÞ‰è‡™ÙuÅq<¹èOÓ¶íFJ¹%¢«?xÆÌçI’¼t]÷5 cÌ›”rÀBQ]æyþÚ4Íç,Àv’e™ ɘù" g`ÇIÓÔ…,„ÇÆ˜µÍ™½…ªªÖÌü@Dß¡xð'†lìœ׌Aÿ¿¿IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-left.32.png000066400000000000000000000011211370472574300244320ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(oIDATX…Å—=NÄ0F¿É6Tq¤44I ´G€†ŽÀ-ÑQs Ø .¢¢¤€ä(¢Yš8}24„*ŽÇ^¦uÆïyü£ ðÏA¾',Šb¿mÛ+":dæO×eY>lE ˲eE7Ä€¨p&¥|ʉB€™Nuy^tp›˜-`‚ÿnÁ}KøJ·ÿÀŒC˜çùÝHFàRÊ»±yœ|Á|Â' ø†O·,®a–eK"Zà+8`¨@È•÷¡­@蕈¨ÀcÉÌ<û)_è”RßBˆ'":°3ðIDDGBˆ/¥”ö©uè%â8~6I$IRÕuýî]š¦ÙXTâØµF ìvX „”°%1I „ÄdßN½„+:»/°ü/ ×TUõÚuÝ954¾•¾À$1Þ:#„©/p>„CÑ4Í&MÓGfÞ#¢].˲|ñÉñ?;PåcØû¼8IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-left.64.png000066400000000000000000000016761370472574300244560ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÜIDATxœí›½n1FÏÝ%Ê4!Y¤” )¦jx€ÁÐC=Ï=4¼zô¤˜ì ÐDbv ò3¦ÉŠU ¾öŒí$_»ëkgm¯w.œëlKBà¤Êó|¸kŒ¹ d"RcÖŒ1χÃámÜèE1»··÷X:îsÙ–eùE?jyžgƘgÀÿ|uÜ4ͪª6mûèé†Ö¾,Ì\ìõz4ýD ÀÒüDKEQÌÚö€<Ï3à)v沦i®Øö€‰ycÌMMûÝÝ]cÛæ‚¦£6¤œöÓÚɲ¬²mÅ ð``m}}ý—m£à<™7MóXÓ0(æEä'p_s€€vûim«Ÿ´‚œ]wûCm‹ÈJY–ï\ÆÒ9€˜ÌCÇb3ˆÑ-cŒôûý¾K _²D]×û ¯Dä`ýOÌ¡f€[ƒÁàs]×ß”1¼Hõ+œ&êixZ 8­Ã à:pYfFD–çææ>ŽÇcÕݾ‹œ7¢º®÷ƒÁK×™ "·CÌ/;qÊËÁÛ£(U^ŸÅ)Bð~I B+§±” ´vMB«çñ ´žÄ¡“Œ,f¥¤±Bè4'Bç—±Ar+„`×R>Séùùù÷£Ñè»&@ðz/Jªê‚_LNîp› ³"ri4½¶müUY€²,wDdxë&íz y£ ‘~½@Y–;À-M½@Tàì—CºõG¥ÜÒ¬ø›,!¨ë‚?ÿ¥º®÷_4MSÅqß‘-Y‡_5}?Tm•Ξë¬ë7ñ*©¦âmIEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-right.128.png000066400000000000000000000032561370472574300247160ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÌIDATxœí=oW†ß³ K X2f¹k'HQ" :w.(%EMºHüˆü74(1QzZÄ–HTHiÍ®wSÄDY ¤Ù9)pجíÝõ̹wæ¾O½¾çHïã{fçc „BHŒˆï4Z­ÖZ£Ñ¸ à’ªžpÀ[}y ãœ{Òét2¯Ö¯8箨ê=í)>¾ `£×ë=0*·³xð"À™3gŽ...~àê¬+"ÏEäë4M/¡µè0À9×TÕ.λ†ˆ DäNš¦½[‹’†e±õõõDU7pˆð@U—ó<ÿÑ9çŠé,^,‹©ê]× Z\=vìXçõë×´ft˜€ÕÕÕ¥,Ëž8RðÒÛ"r£Ûív ^7 ÌF@–e·Q|ø°¤ª?ṗ•""×J\ ÀOËËËŸ”X£–˜àœ;¯ªgˬ¡ª§“$ùž̆‰"rÁ¢Žªž^XXØä8˜Tõ”E]8fÀê@ê¼/Æq05V#`hQçC8¦ÃjxiTgŽƒ0 MÓžˆ ,jÃq°?f'‚Tõ±U­ µ9öÀL€$I6¼³ª7ž1œ€ÙÅ ápø¦Ùl €5«šà¤1L/·ÛíûžYÖ‡ãàc|ÝòÀgÖµÇàUDïÐívwnŠÈÏÖµÇàWDx¼)teeåDžçß©ê¾zù#˲›ƒÁàŸ}øÂë]Á”À?ÞŸ  ~ñ.@ |„%ðE0”ÀA Pk‚ –)@ ¬V€X´%(›à(A™TB€”Ee(ATJ€Må(A‘TR€Ee(ATZ€–Ê P‚ÃP J0/µ óP+J0+µ ³PKJ0-µ ÓPkJpµ û…%Ø‹h€V«uRD6ÁGÓÿÅüñpŸlmm ùhúÇDµüÇÁ=ø*ìJ°[ßGÑP ‘ P‚èâ–€ì«àbj!ßŸÊ ÀðG¥`ø‡§²0üb¨¤ ¿8*'Ã/–J Àð‹§20ür¨„ ¿<‚€á—KÐ0üò V†oC0|;‚€áÛ” ßž``ø~B†ïï0|¿x€áûÇ› ? ¼ÀðÃ!±.èœkŽF£‡ä·øúý~×s^1ýÀõõõDU7Hø!¼°Á7¦¿ ªw\·¬9 žÏ÷Ù1ÀêêêR–eO±ª9þça6²,» †V""×TÕ¨Üÿx•çù­Øø&a²8çΫêY‹Zˆþ«Þ~˜ ",êL`[D¾dø{c2Tõ”E1¸íOÕA õðç¶?%V#`hQgnû3`õ-à¥Qnû3b²¤iÚ‘AÉe¸íÏÙ‰ U}\âòÜöçÄL€$I6¼+aižá;fƒ†Ãá›f³)Ö \–v‰éåàv»}À³‚–ã¶_æw9皪úÀÅyבˆÜIÓ´W`kQbþ¾€¿'IrÀ§³þ½ˆ<‘¯Ò4ý­„ö¢Ãë]Áι+ªz@{ŠoØèõz„ðvÏZàý¹V«µÖh4.¸¤ªçð@_D^è8çžt:Ìk§„B!5áoUf²³Ýë­&IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-right.16.png000066400000000000000000000010011370472574300246140ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8‘1JÄ@†ÿ7™¤Èf0VI‘€x [ko`agá¡^ÀB×+ˆ –"Ë ­ôÙl$ÉNÈ®¯›a¾ÿŸ 3eYc̡֚œsXa‚îAk}àˆˆ´Öoι×)ð]2s@DEQ쯕@)õ ¥Ü°@ÑÞT’ž išO¥Ôb@ÚJŒ1ïu]¿L ’¯$IæÉlL²$h%J©ûA™¯ŽWÐÖ‰ãx>õ'Þ-´CDÌÌ?Ý;!„콃³,ÛŒ¢èš™·²of>¶ÖÞö„>8Ïó4 ÃË.LD'CØ› ÏóTJy`» WUuã­ùŸØ£Â0<[^üÅZ€þJˆN<2ó³µöi €_‰_…±©DIEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-right.32.png000066400000000000000000000011341370472574300246210ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(zIDATX…Í×±JÄ@àvÎê6\l°Rð%õ@A´·µ¶¶ð|}±ÐBPD…G*Å"I­76žèqÙM–YuÊlàÿ2aÙà‹\‹ÖÚU‡D´ÈÌ×Zë£,˦é€3fÖß—“Éd7Ïó[)€r¬mÏ„€QJƒ•ßÔ•(Â8'¢÷؈ÙUQ¯I’äD´†ùÐ"ÚìõzUU½ˆ>ƘŒˆÖˆa¿ß¿,ŠâYeY>y]fÞ Ex±1±­1­S„g‹v™y£É r[4Èt"ä,øQÌüæy…:Ní‡:ï¾²Ö‰èdΩ9­J)µ7nÄišî8v„7º;ýkíÐ^)¥ö›\\Zw@¢íÁéðV€á±Âb†{R[-P3ˆ†íçÑp ®D§£¶søhæœ Œ1w–‰(p¥µ>Ç÷Ráÿ¢>z$$“5¨~IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-right.64.png000066400000000000000000000016401370472574300246300ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¾IDATxœíÛ±nÓ@ÇñïÿŒÕj$¦T‘èÀF%ÈÒ¨Ä[´ìðìtåŠú¨`à "•U©3P‰ØÇ]*¥•ïìóÿÔþfŸ/¿Oì‹ëà67;â3x8öEd[D¶¬µ9p."ß“Éäs3±Ý8ŒF£ `×ZûpÉ!"òz2™œ»Î"NyžŒ1Ÿ€ìšCEä¥fã4Ș7\_`ÓZûn4Ýw™'Dj¬¯¯ß¶j QP ªªG@Ý2›ÖÚ½Á`ð î|mÇå°ŽsÓ4}¯ ¡6€1æຨÓ4ÝÕt;$uœžž–«««'ŽsæÀF¿ßߟÍf Çs4§_ªªÞ…ǼjÆÚW@Qó,˾c^©ãÜ*®'€¢(N²,ûòá®ãir`Üëõöçóù×Ïâg€³³³ŸY–y"¬%Iò¼+/ˆÁâFhâEh âDhâChâBhâAh â@hô#´º‚€^„` !(üCXYYùêù(½–$ÉÓ&¥ƒ€®GéN@ÏíÐè@èº_œþm:"Ráþ¾á"éb±¨ý®Óëõx‡ÏŒ1¬µ=Ó•e¹3Nר)@×å¡C å¡£5 Ïó±1fϳü¡ˆlû”‡®-ßüE‚h+4–‡@ZËCÍå¡eíå¡E€ÊCK±”‡b* ÄVˆ±<4kyh æòà¿_ êòàñ8¬é‘Ö'mï¸**ö´½_`YT”‡0û.GMy€;u8î¸ÈQY–¯¦Ó©Šòv¿@§«ý²„Ú/Ðùj¿,!ö ¨ºç/§íýªËƒ#Àñññ‰ˆìˆÈ¯+;Ð^n·ÎÞæÆç/N¿>ËáÁìTIEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-up.128.png000066400000000000000000000027511370472574300242240ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœíÝÍk\Uð÷½3³P„Ä@SZCf’q#è*K‚ºw+ipUôèŸ!âB\jPܺJ¡{…îÔJÚdr#ja¸`ª2É9.œÓûÑÜù¸÷|=¿Mà¤m^æyrÏ›Jà›Þ”í9lJl`K¯×ëc¾$¢¯766^¶=-l{.…ˆˆ™ŸŸŸß>==ýÅòh‹®ÙðE¬%ˆªeá‹KM® _ÄV‚( P5|S ‚/À¬á‹XJtæ _ÄP‚` °hø"ôY€e…/B.ApXvø"ÔU€ºÂ!– ˜Ô¾­A ©ðEH%ð¾M‡/B)×°¾¡Þ`þWD´ny”ß™yo8-Ï1/„\úη>Ñ3x{¨Ä»+€íË~_·¯ àjøÂÇxS×þ•À‹ø¾ð©ÎÀ·ð…/%pº¾†/|(³pè}þ¢œ~NàäsÇÞç/ÊéçÎ]|¿ì—qu;pª¡†/\,3=|áZ œ(@,á —J`½±…/\)Õľp¡Ö {øÂv ¬À¡‡<‡Ó¯XÂââÆ9ôçÐ3hµZ·™ù¡åY¬=,jô àÐeÿÐ3PJ‰ˆ¶··W´ÖŸc^µ9”í ±¸¾ˆµÀõðEŒ%¨½¾„/b+A­ð-|S j+€¯á‹XJPK|_ÄP‚¥ ”ðEè%XjB _„\‚¥ ÔðE¨%XJB_„X‚… Kø"´,T€ØÂ!•`îľ¥s öðE%˜¹ÿi¾—`¦ üb>— rþ³ùZ‚J@øÕøX‚+ €ðgã[ žY—Nïú¾ØÜÜ|‘™¿ N—ž î÷ûëÆ˜}Bø3SJ1úÿع-ëÆ˜ý~¿_šaY’‹‹‹OˆèF=sUæ]øÂ¡ܘfY˜u«h±ÛíîÑ^SUàmø"MÓ¿WVVî1óDtÍâ(7WWW§iúcö¹Vìîî¶™ùN3s•ò>|¡”;òË'îììt²‹¹+3¿mŒy·™™ ¾Çÿ¬­­Ñëdïžê…³³³ŸÒ4=º¼˜»cÞln¦œàÂGGG©Öú}²xO$É[¹µì‚1æµfÆÉ 6|aûư(Û\˜ù¥fÆyJðá Ë÷7³ Eo žk`Ë¢ _ØÚ˜ùùìZÑðg3ãQ„á ÛAQ¶EWÕÀ,D‡/,l'Ù…¢{€ï$úðE“Û3ÿ]Ë@k}¿æ9~FSÛAQ¶¹(¥¾%¢Ÿkšá—¨{;`æGJ©ï²ëE÷†™?®a„…š·ƒˆHg B4ïÑÁ¿8¯¨¦íà`šiNéy€ÉdrwI—#„?£e–€™N&“»eŸ/-Àh4zÒn·Dô`¯ÿ ÓéÜBø³SJ;Î-Zðõo·ÛƒÑhô¤ìT9Úêv»Ñªþ”ð/"úìäääS"º¨øw X­¯åcá[[[×µÖïÑ;T~RèW"ú&I’ýãããߪþÛpµº^ÿ¹5LkÝO’ä‘Öú$I¹úÿℯ?п‚BVô/Œ+8IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-up.16.png000066400000000000000000000007471370472574300241430ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDAT8ÝAJÃ@†ÿ² ê*ˆ/à ^ÀM‘’Hõ ^Åvã ÄèUĦBR0a@a‚Œ›Œ„Ò´nõß¾ÿûxïÿ;"RˆH±«£‡yžOHÎHNŒ1¯u]?ýZ "É™÷^P$Çiš®š¦yÞ+èàÛQ$/¶Iô.˜dIòÀÁäGnîÁ+­õµsîQ)uà0Hú?Ñ0߀¯Ê²|³Ö~&I²ØŒƒ„"rFò¡¿¶snZUÕº^–eGQÝ{ïO»Þ—÷þR‘탠ªªµsnJ²ï½&9ÒÆ˜'–mÛÞlƒC¬µq/´ÖÇ–$(ß¾E€Žž€IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-up.32.png000066400000000000000000000011231370472574300241260ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(qIDATX…í•¿NƒP…Ϲœ „ýÒ0 ©/aŒqð|‡ÖÕÕ—0ÆÆ]}7W'tr0¡qm¹.P‘” —Û&œ¸÷û~‡@Ÿ>},"¥ ¥”¡Í¢ëBß÷„·Bˆi‡]÷aW8É;n~è[qEÑëÖÖÀ‹t’0ºRÊät v³,»1}&Z7 ™¼£&Z5Ð0y5FM46`0y5­šÐ6Ð49É%ÉeÍòVMÔ ï9§àR)u¡‘pš¾ƒ:¸®öÇñÃ|>wçƒäqÍ@;J©SÏó^Ò4ýl0Çl$þtÛJ¬là6‚`À}|Çñc¼,áºîŒä‘FâÄó¼ç4M¿dYvýÓÞ ^$¿v¢{;ræÊp´)¸Äh%@r¶Ix‰‚)@)u `Q:¿ 9¶—%HŽ«ûçÌßÁp8Ü'y– =%Iòf /gÛû÷éóóßÝÃ^¦±IEND®B`‚olive-continuous/app/ui/style/olive-light/png/tri-up.64.png000066400000000000000000000016631370472574300241440ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÑIDATxœíš½nÓPÇÿÇæ#¢Š%#uIºCfX`)/€xÆ¢ Ô¥¯Ò†ò:ðˆÀ*[¢ Up‘‚‚}Yr"'¦¾ŸEº¿-Žîñùÿr®ue@ Ç!ZBˆ–Ï"_7ž.¥|Ùétnøê#öqÓZø¶â8¾·±±q4§®{q.`)<ãM‚S+Â3^$8°&<ã\‚ Ï8•`]@ÃðŒ3 V(†gœH°&@Ñ’R¾ žÙŠãønš¦GEQü6Õ[+ø—‡^xæ€û¶&Á¸Í±_…µí`T€¥ðŒ ÆÚóë0þL0"Àðž_‡Ñg‚¶Ëc¿ cÛAK€§ðŒ ÊLìy"šÑÀUÅÚÏ¥"µ=¿­²~Æ€gUU=!¢u¶u^ª4žCcFDOß ‡Ã“$IzQ=pM±žòvh$Àtx¾àSÂ…Ø Ïø’p!¶Ã3>$¬à*<ãZ¹\‡g\JX)ÀWxÆ•„ ðžq!á/—%Ã3ªêYë[àmƒÞÃ3*êYë‰ètÝâËži"ˆN¥”‡üy. ˲ïöŒÎY?ºlá™<Ï{RʬéÀÞ,+€¥“`Qß’$yED7Wf_ý𺪪ý<Ï?íÜ ³có¹ýgYö¥¾†Vëv»×«ªº Qeý~ÿ—¥¾­ð¿÷@ ìò¶¹GL²ø„·IEND®B`‚olive-continuous/app/ui/style/olive-light/png/underline.128.png000066400000000000000000000031231370472574300247630ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYsì8ì8q+Ê8tEXtSoftwarewww.inkscape.org›î<ÐIDATxœíÛß‹TuÇñÏ3Û8Ú¬ž9HîÅ®3sf'2'(%‰¢",¢D¢n¢è‡¡Ð?TFØE—ÑeA” Ad !DF %uSV¸f‹lž³º»b£îYv[vvÎ9ß.VCÌüq¾ß9ßYŸçu?Ï÷Yç½ãì93MÕjUéÎÐÙ<_÷ç·½ÎæáÂ> €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9̘‘Z£ÑXbëìz½^ÐÑ2²ˆ„f¤Ön·WØ:[)åh>~ÚÔ.i-ú¢(òlÇqMçñDtCpÊÀŒÔ”Rë,—æãÏÙBƒ‰Ž˜‘šRj£Å³Ö|üˆ©]ÒÒ€ˆ›XDÃæF£Ñ›õ¡}}}EéÌÈår‹?¥Ô!‹h(ÎÌÌlÉúÐeË–½HDZá)¥þ0µOZdbHµZ=`‰Y). ·ŽŒŒdò¦ª^¯¢(PÑ“DQtËØØØ9S{¥aäB}ibކ¾V«õJV‡EQôôž|²ýäæ®~ahŽŽíµZíþNâyÞƒÞ40j¿ÚŒàûþß™˜¥aI’${Ëå²ÖßæWây^E)µ@^w}f`%m&ï¼cpVZ+s¹ÜWžçé¾<ÿG¥Rñ”RßXe`Üïû¿˜£ÍXA|«”úÕÔ< k•R¿xž÷€©ç_ö¸ÝÄ<"ÚibŽ =&‡¹®{ÀVúëBCÀsŽã¨Ÿ›ÍfœfH½^/8Žó†Rê#"Znh·Óóóó/MOO· ÍÓb4€0 ÇÇYMDëMÎM©‡ˆ6¶ÛíçK¥Ò\ÿH³Ùœ¿–6Þb±¸-I’Ýž‚Ù§·Ož‚àUÛK\IÂ0<èºî)¸)«s-ú<‚m”íE®$ó+vår¹AD»‰èެÏÎЮ ^Ù^äj2ÿbȉ'†{{{ï==¼«;RPD´#‚­XO>`ùš}­VÛ$É{6ØÜÃ¥Ô[FGG÷ÙÞåzdöàr&'''Â0Üåºn —aMÝpÉÚþ|>¿É÷ýßl/r½lßµûW£ÑX2;;ûŒRj€AÛû\£SDôºïûŸØ^$­® à‚ó!<©”ÚàtçXÿðn±X|¿›nì¤Ñu\¬V«•ã8~ˆžp7ìÇ0DD;[­Ödz–w1¢«¸Øàààª8ŽÇÂíÚ nCçƒH 8Ëå>=~üøÑŸ—¹EÀ¥êõúŠ(ŠÖ+¥ÖQ Ó®`á3{7X«¿Ñ0ƒ…/¹ž%¢?“$9FDÃívûÇñññ³ü1„B!„B!„B!„B!Œ£jµz£}6Ÿ• ´>Ôcû3vÂ2 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €9 €¹iæsHY"}IEND®B`‚olive-continuous/app/ui/style/olive-light/png/underline.16.png000066400000000000000000000004471370472574300247050ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<¤IDAT8í“1 Â@E_ÜØ+–1°09ƒ^ų¥´µ´¯b P+!YÆ&+Ë‚"¤Iá«þÌg>SÌ$ Xk•€º®“°ö~ÜŸ1’ÀÔî¡QÅÚkÉÙ~ 8„Fß÷¥ˆä"’;çJU=Ç﫲Ö.€°ù°íͳ­ªê6MÓ<³,Ûw]wVÀ˜U=¦iº‹‡§Aá¯ø¯}/sƒ2Òx¨ ¹IEND®B`‚olive-continuous/app/ui/style/olive-light/png/underline.32.png000066400000000000000000000007051370472574300247000ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs;;̶¡ƒtEXtSoftwarewww.inkscape.org›î<BIDATX…í—±NÃ0†ÿsÄ@%,¦´’•d«x€ €×èÂ#dì02ðPÄÀ db )º ¬ ¶Ô6K+µ¦qÒ !$üo¾»ÿîó`Ù&8RJY7¶(f&_Þõ·Õ _ò7@ €Uï>C–e;M¹$IzNèc€Ÿ¡®ë£¦œµöØYWkXk¯}"Êã8–n¼ßïïcò¥æBLÚ¾=—’$éc <¾W"EQt ZëcLNDÙÂF¦D´ÏÌÏk€RêÀ €­¶x4fæQ[ÑÊSÀÌBˆ3o¿“R^t)l<†eYÞÑ•µvÚ¥Ù¬n,¥<-Š¢îâñ>™çJÓt µ>p``Àölè'BLŒ1—UU=ué4µýZî_ñOÞ†ÿ à -e šë¶œIEND®B`‚olive-continuous/app/ui/style/olive-light/png/underline.64.png000066400000000000000000000015011370472574300247000ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsvv§ÂxêtEXtSoftwarewww.inkscape.org›î<¾IDATxœí›MkQ†ß3I‡@›BÄñ†Db ⪠nÄ…õë'(nª+ñˆ‚ˆ?Âuë®*(ŠŠºtc)¥dÆl¤ 2±µM5½ÇE›™Þ{ሞg}>Þy27$CÈÁÃy5ƒHÓ”|úóöûÎ|šÿT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiT€tiŠX÷YÐjµª®½Ífs4§Ä+PLÀ'Ÿkkk5×^fÎëíºÎÞ$W3¿óZES®½ÖÚã9%m×Ù›ä ¢—ž;Î(9ô•™y:§æ­ÃÜ_ÈEÑ]ÏƘ Ûm2Æ\°oP =vNµ9£`˜§{ìùFD§’$yT¤¸^¯O1ó,€¡­j˜y¥×ëíZZZúâ‘«Øc™¯ú,0ÄÌ÷Œ1—”Ô•1—ó.ˆhÆ÷â‚wÔëõ;Ì|Úw!€9f¾U.—V*•z½žé÷ûLjhÀxëDÔJ’ä½o˜ÂšÍæh¿ß `¯ïÒ\KÓôJˆA…O‚‹‹‹Ÿ766Nøb±+Ìübxxøz¨yÛþ—e­V›ˆ¢èçŽiÇ“ C ÜöwN§3ÇÌ< ¢ 3Ÿ yñ€ÛÝnw%˲™±±±ef>DDqÈPàyÇGÛív'ô`'?à,Ë^U«ÕÛ¥R©`??â\Xgæ###çççç—Ïàð°Fc§µö,3ŸpÀg3¯Ñ Ý ñ¨D0?Óh4v[kXk'£(·Öî!¢Fñû]÷@ ð†ˆž¬®®ÞqÈQEQEù¾ø·“÷^¡þ2$@ @ @šÿ^Àwr/ѹ\Ï~}IEND®B`‚olive-continuous/app/ui/style/olive-light/png/undo.128.png000066400000000000000000000037131370472574300237500ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(éIDATxœíÝÏogðï3·‘’]ïLCjPXïF9´MZ.H¿‘… ¨!.Z¤r€öÂ?q @Ъ¥ !Ez¨h«¨PPUE¡‰Ü”ÊñîØ©Mj¿3"‰g÷áPs ²÷×¼ïÎ;Ã÷s™g^åùf~íø€ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÊGŠÀ¤Ž=‡ax—ˆQÕë"²ÜétôŠ[™”. ·ø®ˆ|DUgÞ±xCD~†ácKKKo1¾²)UÚíöWUõû{4þˆÈ«"òÍN§syZc+«Ò Õj=¨ªŽº¾ˆ,]»ví‹—/_¾âr\e7ð’/Æmþ®xvv¶nŒ9íbLUáý`Âæÿ× >ÆSÁþ‚¢0HÎæ@¨ªŸ¶6  ò6šPÕ»lŒ§ª¼ €­æïŠ,Õ©$ï`¹ùÀ»€¼ €ƒæCU_·Y¯j¼ €‹æ@†ÏØ®Y%^ÀUóEäÙååe(<®šàMùƒº•Rh6ßx€€†+,›ŸAp’$Ô®œB;nþ×:Î9µ+iê`óý2Õ°ùþ™ZØ|?M%l¾¿œ€Í÷›Ó°ùþs6¿œ€Í/ë`óËÅjØüò±6¿œ¬€Í/¯Ü`óË-W6¿²DäŠªîØ°."‰ˆ\è÷ûç“$y €Nu<“nÈæÛ'"›ªúO>|øÏgΜÙq¾ÏI6bó§b ÀoÂ0|òâÅ‹oºÚÉØ`ó§nÀW¯^ýÉÆÆÆ¿m믃ÙüB„Þ?;;{o£Ñ0iš¾f³øÈG6ß"ò\///§6êt`ó½r Àg£(:kŒÉýÖóаù^ª«ê¢(Z4Æ$y òZ8'[òÓͪúÓf³ù‰Uý€[míCD^îv»_i];dr NxÀ{mTÕÏòïfe®àÝ CÀþéà€ˆÜ377÷bš¦–kûDÓ4]šŸŸª×ëÐÌ[PD®§iú°õ¬MÍä·¹¹yýСCÏÌÌÌ|À»r–{Oš¦cÈÅ ÕÙ‚ü²,»Q¯×ÏAðeä;E¬×ë/fY¶6h%ëÓÅ;|Np@D>Çñßlü ê³4M7ææææœÌS'‚5cÌK×ɳƒýt»ÝŸ‰È#J×ûýþcÍfó„ƒÚ^ ÃðÇÆz¬ûNªúaë8›%¬Ûí>""?tPº!"O¶ÛíJϾû"èXu÷pCŽòN¿âðaÑͪzªê×Q]ð¹%fkµÚÓY–ýk¿œÏÈ#Áä<øWä|!'‚ÖÀåyŠj÷šÀEêý~ÿñª†`qqñºˆœÏYæÝƒNm¦P^N¦ßᅳg{™´|ªSÅîž\„ !"OT1"2ð>~„íãA˧>W0C0UýgÎ{\ÈdѼ0ˆì{?¢ÍA ›-Üõ5Áî7†K¯ßïws–ø¶p¡ß py:ðh«ÕxT«««k&ú{@é‹ÈéAëþŇ!8¢ª?rPwêDäç“l§ª¿öÑ /¾ìðWÄ£qŸ5ƬX®;UƘׯÚcl¶†áw¶¶¶~6Ï‹NC°cŒyÎrÍ©«ÕjÏApF AÒëõ¾‘$Éê°½ à,³išþÚb½BdYv#MÓ?67D䀽îïˆ<º½½ý½õõõ‘~2÷òëá6ß1‘µn·ûQµ|Òl68`ND®è&Ir@oœ:^Z­Ö·Tõ! ¥Î&Iò% u*©ð»€ýX|Nðw 5*ËÛVnUUgm@äÕEà^r^þaeeåW–‡T)Þ˜øEÓUUývš¦Û®ÆU¥ðöëeqÆðS×?z½Þ×WWWM°X¥ c^i4/‹ÈíØû'®øE¯×{èÒ¥KyEû¿àímàA»Ý¾SU?¨ª1ÞžMóÂÎÎÎéµµµ«EŽˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÈ­ÿþ5MÂíöülIEND®B`‚olive-continuous/app/ui/style/olive-light/png/undo.16.png000066400000000000000000000006771370472574300236720ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÝIDAT8Ý¡nÂpÆ¿–àZÑ>ÀÝY ‡Ÿ›ÁL-¼ ðo±…˜˜˜[IÍ?©§©"”õfiKK«ûÉ»û~¹ïú)"z!¢e—[«:‘@U'Çq&ažì:³eY¿Ömæ b^cÞ;G(¼Ý¦ @`kŒù¸‹ÐAC#™•6"0s$"f~n ˜ùõÿn‹P„\{PÕ·†lfþàfY67I’|yžUxr]w—¦é¥Pß÷yžÿÄqüYû'Í™yÑ£oú„V-‡[ü<IEND®B`‚olive-continuous/app/ui/style/olive-light/png/undo.32.png000066400000000000000000000012661370472574300236630ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÔIDATX…í–?oÓ@‡¯ AÈ— Q¤:¶7:¡|¤î]ÊÂÖ¥JÙøˆ@6_€ªb K*EªÄ-iªÏAé$ü²éTr`S§ ~¦Ó{gÿ^^  à‡²n6›÷Ô+•Ê^·Ûýž‡@)Cø€M4™L:ÖðUœ4‡|ßoxŠ_7ÆÌÂ0\¼jx*ß÷[ÌÜ2kDtì8Îhî³Â|#¢õ^¯w‘‡€µ máŽã< _ò· \WøLë ÿMÀþï?': ™y·T*½ë÷ûGV¼Ãgpà™RêƒYLõäÄ-/=Ï[5‹ Ó…Öú³ëº°u]÷?‡³ÚÙ&B–e¥”Zè”°ÁR–\×€Yîn“°ˆèP.—»U«Õ¾´/v4øÑ À`˜°Õ¶m(¥ž´/脞¯®®ž.—Ëõ$»ŒC¡PØ622’‚`/bæ}=ööo>Ÿ?\*•ÖuA×h³ ¶mÿ6::z·Z­nh7T«Õº”ò¥ÔÌäääm)å»CNÙR¯×ß+¥>´{ô¯ M„A.—{hÛöq[CR-¥ÔÝÖ@$€þ7¡V«}q]7p$$m\)u½5kB\%¢«Qr™ù×ááá…Ba4ŽF‚ ¸CDAHÊvÏóv¶bBýl€¹°"ÚÑzœhìg˜¹ãÀÓ$‚|ëqâQ¸Mýš™Uëqªg&\N£‘!kŸÇÆÆÞ´"ߺóî°ÛuÝGRÊ̾PJ Çq¶X7Qݲ¬ó³³³ë~#RÄ3™g”R¯uèvC)ußqœgDTP&¢{CCCæææÞ¶çjý@"ÊØLD¿ !îéÔMƒ–hÒ«ˆ¨Üh4..//7tê¦A«À7Çi8ˆõ¦‚ 8·¸¸z›Úl²üHꀓD´À[f¾æûþ§¬ô ƒÁ`0 ƒÁƒ¯pCųƵêIEND®B`‚olive-continuous/app/ui/style/olive-light/png/videosource.128.png000066400000000000000000000030131370472574300253230ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ()IDATxœíÝAheðÿûÆ›b+î^Ìîf²ÛÕR"x¨‚ZzTêÑ´Q/*X<*æ¤X¨AÑ›ˆ=hÕÚ´9jñÚšZÐ=J¡¦k&»I<¬¡Å¬kÙýæy0-ÅÔ6î~3³éüÇ0óÞ#óg†ì ³m$òï”J¥íaŽx@À¦Ø§Ú˜Úf<Ï›®Õj“¢\.?Ôív÷cv©j^Dº~SÕkíT£Ñ˜½ñøë»»Õj½ `BUM܃ßIDĘÊf³‡ªÕj'Žžë¹~"8vã\ríä•••Ï<ǰ)òC.—{%êT*•-Ýn÷°ª>ºÎSÎår¹W«ÕjÇ€¡¡¡ž‰nÄÔ*¶Ûí­—/_>Uƒááု<ò?N+¶Z­-W®\9#¥Ri»ª~ÇÛ~4DÄcöÔjµ_\×. yÏóŽ(õ8×s& Ãq^ü訪g­w]·X,nó<ï8z¸øÀõ¹ž7"²Ëñl´–ÓßñÈÈȘçySè³ÔSÀ°ƒ™èD$ïªV±X|LDŽªêýýÖ‘a£ªC.£ÿ¦ª›]Ôñ}·1æ ÷º¨§ª›ùìß FFFöøÀ=.ë2€ïû/c>p—ëÚÎ ’[£££ûUõ-U]ó±½ Àà’ÑÑÑIU}-Ê& À`ò|ß?¨ª{£nÄ ˜;wfšÍæGž£0@ …¦f³ù €§ãêÙw‚ ¨¸dÐù¾?{û£z×ÃFÏ Þ@>ŸÏv:#vÄÝ›HX±X6Æ|‰—:ýâA *‹ÛŒ1'ÐÅ€Ä8Üèõ…H@¹\v¶Ñë3ß÷w[kmôúÅÄ(ª^?€˜D¹ÑëÇ@ s‡;¨ªIϰï)Ǥr @Ê1)Ǥr @Ê1)Ǥr @Ê1)Ǥr @Ê1)Ǥr @Ê1)ÇÄçÝÕ·u &A ÃðMݤg¹£ùùù“^ðWÒ³\ÃÄ,‚Sžç½ à¤g€DÔjµUõ%YNz !óóó?[k',%9 z½~) ý~Mj aõz}±Ûíîp!‰þ ÀXXXø=“ɼ("?ÅÝ[¢~ÿýc=ïS, ›<Ï‹õE‘¼ F£ÑÎårû|WO`ÀT«ÕNo8G?`0Ù Þ‘ÃQ7b—ÎÍÍ} "ˆìÝ2 À€›››û À¨6‰ Àå&‘Ø ¢Ú$i¹,Hk‰ÈŠ‹:Aœ ÃÐå&±mð2" TuÑU­z½îl“("‹FUϺŒniÆe1‡›ÄóÆó¼i±.£µDÄZk¨S¯×/Yk÷¡ÇM¢ˆ„ªzÜÔjµ‹¦ÜŽGרêÑF£ɾ¥Ñh,t: ô°ITÕé .Èf³‡œs=`Ú‰ÈL©Tz?Ê‹‹‹Í6‰ç3™Ì{àÀÒÒRX©TN¶Ûí­"ò0øça_V©_—J¥ÉÓ§OGþ_ÀËËËWóùü·Nç¾ÕëwÓ¯™‘PD¾Éd2“³³³Wq³ËåòƒÖÚq»D¤À¯—_ùSUÎZk§£ºíߎïû;Lx@@ àœçy'VùDDDDDDDDDDDDDDDDDDDDDDDDDDD´Aý Ký0üŸIEND®B`‚olive-continuous/app/ui/style/olive-light/png/videosource.16.png000066400000000000000000000006651370472574300252510ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÓIDAT8Õ’;NQ Ea4ì!=uhh£(={˜ AVÀ »†ú½†¤ÊG™K3‰Fƒ@/ÜÒ÷cË6ü{˜»/Ììº@»N)½@Ó4³®ë.ÍÝ?€º¨›Ù}Jé-"ZIÀ¾˜Ÿ1ÞIšWî¾”ÔöT]E9çÕOî~L$=Ó!wQ2úÓqáÜ€o87à}\8í "Ú1yD¿@ÌìIÒ 8i+`Ô’–lsΫˆX÷gÜXDÌ%ݘ?sÎ/ôs3;øþ:¾éäE¬G0¢IEND®B`‚olive-continuous/app/ui/style/olive-light/png/videosource.32.png000066400000000000000000000010531370472574300252370ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IIDATX…í”/OAGß\‹ é%uP5+úð(_®® ¤ŽRAPT q°‚âc…ØMHø§N‘ÒäCHs--i—œ¸™¹}¿ÜnJJJ–Œ¨ê&p¬å´æ¸¯ÕjƒÁà3ÛtÎm™YHE¤[©×ë—ÀzNr€ ЇOI’¿{ïÏE¤'"éXù5‘ÜCŒ€»8Žo² ïýÐÞ7 ›£·¤¤d1¾Ð{]º7W¶PIEND®B`‚olive-continuous/app/ui/style/olive-light/png/videosource.64.png000066400000000000000000000016071370472574300252510ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(¥IDATxœíÚ¿kaðï÷½¤­˜B …Ûô âV\”¢»,NZ7‘â" ."¤89Ø.ûÔââP ‚³PsohÕ¡¡¦õWi¼Ç¡Óæ’\z½ôùÌÏóä¹/ïex@)¥”RJ)¥ÔéCp]7àÉ19óNÿ!ùÀj…R©ô©Ñþ|>Îqœû®è‘Ukm‘¿ íÚmQ0n­ý¶!ŸÏ_6ÆÌè­1릓ÍfŸ¸á’íÔ W©T^…)ö<ï:ÉyµNu€Cr,Ê Û-ì¾ÃÃÃã"òûzج«æ$¾óG‘L½Ïó&Œ1ϤêÍ:² ‰<Ï›‘|Á×ÓIÐuÝ™j¤©Sp\×} àV£u°Ö^hj¥¸®û1líèèhº\.ÏŠÈf>+Ñ'`hhèÌæææsךa"ÜçXŒŒô¦R©´ðð@BOÀàà`ßîî\luV"H§Ó‹"r>ŠY‰|¢zx ¡DIˆ{¸iq/7 î⦼@ÜɆ¯Æ“Èööö&H~ˆbV"ØØØ(wwwß&ù¾ÕY‰ ÖÖÖvªÕê$€7­ÌIl°¾¾þ«¿¿šär³3ØÈýÛIQãž²éKÑDŸ€ü±Ö>0×hc§b­-,°MÀ÷ý9’HaêÍÁoïI²S¯À÷ýÅ î¨Ö)Ý2V#Yëø¼ ST*•^’œðûˆ²w&‚öÿ,ßH> [ìûþJ“¨}j¶HÎ:•Je+›Í.È‘ÌèŠjÛ¨üà5É;¾ïm¤w{{ûs&“Y6Æ ì#ùÀŠã8w‹Å¢mÏÆJ)¥”RJ)¥N¶¿½ÅwrIEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomin.128.png000066400000000000000000000113361370472574300243160ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(üIDATxœí{p\Õ}Ç¿ß{w¥•ðCÂ/°×{ïÊbL:I°« …`%qi( 40„†Öšvx´<ÊÐÇ$4 xRJ „NS˜!à@y§ ˜PLí˜ LåÝ{×’[?d¼k%K÷þú‡®UI^içÜÝ•¼ŸlíÞó;¿»çwÞ¿ó;@:uŽ]Xmª…eY'ŠHI[D–L˜   Àqfhïð €Cr²\)ii×uÿ§Òï ƒcÅL˲>àt§‘\&"Í…•É>ïØ`³ã8¿àéÌ# ¦­´··Ï:[DV’ªD~f%2QÄ´m{ É`U[™ °HDVµ´´ ›Í¾ƒ[ƒšn-Z4'Þ+"+ª­K•؉Dn sX³-€mÛ§†ñ€ÏT[—*‘ fÍšõa6›Í„‘AM€mÛ«üÀŒjëR4†qÞ¬Y³²Ùì¯u ¯5 mÛ·‰ÈŸ¢Æ»§ c\1{öì–l6û4Ž jÆ:::¢÷ˆÈeÕÖ¥V!yJKKKbùòå¯9Žãk‘©Cˆ*ñx¼)‰

eoÛö—|'hBCD~Éd~\NÚª@"‘8Ã0ŒŸˆˆ†|’o{ž·vçÎo‡!¿T’Éä©"rSX†@Ò‘«]×Ý\rÚ0šŒ… ÎF£Ï˜‚øªì¨I¨;™$÷™¦y~©ËÆ¡ÔÀI0£ÑèBá“|2~Õqœ'P{…âºî3†aœàiíÂEæzž÷C”X¦]²m{ €oè”Iòa·:޳nÿþý:e‡ÁÇ<Íf7´¶¶fH®Õ(>ÑÒÒâe³Ù·ŠMP±. ™L.‘çED§Ñ}àz×uÓeVŒÅ‹/1Msˆ,Ñ(vÈ4ÍóR©Ôóp¥ºú¾—æÂßFòŠ0 ß¶í–yóæ…¶!µsçΆa\ÌVtñ}ÿoQdå®H H$.!y·F‘¯yž÷g:–BÇcÛö—EäR’+Žœ%|üß‘'2™Ì&ÝyÆãñ&Ó4ïð]2IÞä8ÎsŸÓ•áDضÝà9^“È×\×ý4ŸºiooŸ588x/ É_466Þ¬û Gggg$N?P(ÿb!¹/‰œÕÕÕõÉdÏ…ÞˆÈ]…Oò’7@sáÏ›7oÆàààã(âÇ‘¯õ÷÷?¾`Á­'6nÜ8äyÞ >^¦ŒˆÌº¾Ðs¡ÀÂ… çbØu[†ñ'Žãôk’7BssóÝ––ä䦦¦ïêÖ£»»;GòZ’;tÈ‘+âñø¤•/Thhh¸üöIöù¾¿& ¿y˲–8»Ôt"rN2™Žã‘Õ$i×dšæÕ“=š}ÿjwçÎ;µÔŠñˆÈ%e&¥ïûZ×4ŽàºnÚ÷ý;tÈ"yU[[Û쉾Í|ß¿Jlj\’O3šUÿ; ÉOצÈ82™Ì‹Ð°b("3<Ï»r¢ïÃ2“äåªB‚‘¬Îéc>T–¥OЦELÓü.ÉýªrH~¬ú†b–e} À< ¢þ¾Ð4F*Þ<¡z¥R©¬ïû?T•#"s“Éäù¾ «¸PUÉ·Ãlú§ ™Læ)’Êîà"’·L´ÀÒ¥KgøªªÏóÖ¢6wõ*X«,Däwƒ²ƒv8êS¿wkÅ™£pg É­Šbb¹\îëã?Ôn"²RUÉûuè2‘‡Te†qTÙè6“äTL9Žóº.…¦ ®ëþGE†ˆœŠq³­`YÖ)æþÏ Þ÷çCDDuP<3™L~vôº[€ÓÓËààà Z4™†xž§\9DdÌâU­À;===ÝZ4™†ôôôtk˜Ž)#@’Ëe¼¡E“iŒˆ¨þFË0ÊD›X–u‚†ð«%ûµkø¾ÿ+•ô"2cÉ’%#«´Ú @õɾd2ù]úLWæÏŸÿ†CË•çy#eQÖèÿIª$‘måœtµm{™ˆ\Œá¾m*|Rײ¬®“äì°Å0Œ'Óéô¶Roݺuв¬÷”½‹x!oô€j *åù ‹Åî‘ßWÉ· 4°ؾï_fÛöÏs¹Üí»wï.Å$ò ± âí«P´,]ºtf,[`ªþQˆÈ9±Xl}¾uú‰(µ²äa$ÜžÎYÀ„^'ÅPÊKõ÷÷ß àd•üjŒ“JÙöU: Ar$®²NPšÜ]Ìs‰Db4ì6Ö"²2x·bø_żF»èì”NÐ>|¸¨>ä*ùÔ2$‹ 588ø©b>ú @u ‰ky=[¦ÁaÑ‚˜¦©ä1<º¬tvJ0gΜ‚/ÕÖÖ6»ÒW¿T™ÑÞÞ^ðÞƒ™3gªºŒë7’¡Ÿ22 cÚYÑwÔYhJ'vz{{ Öì®®®O4˜¨UsæðàÁƒª­àÈoX3044TÔK‰ˆöÓ¹5DQïæyž’Œ®D: @i}º¡¡¡Xx\%ŸZFDž(æ¹h4ª4ã‘‘Y„ÎYÀÇŠéó\&“ÙDò*yÕ"$7d2™7‹|\é@ Iý@Ruq¢è0)7øP%¿ãÃC‡ÝRÂóªo#‡mtvJ€^jûöíûûûW‘|Q1Ïj#$_èïï_µwïÞ¢w4D uüGçn`ÅZvÏþ<™LþÄ÷ý#ÛÁ' vn ˆ†«-†aøàƒÃÜËEDÚ‚›6êŒÂ²¬¯`”7o9| ã‚l†±‡ÿ’ª€àâÈ:£ ¹ZU†ïû¯ŽÿL»D£ÑW”´˜“‡eÉdòTúL‰Ä"òÛŠbú›šš^ÿ¡v¢z)ïÙ‹ÈM¨€ákcoÔ ç•|Î&¡¸q‰ÈÏ4Èè°,ë"úLelÛ¾€rHZÃ0žÉû¹ªà|d2™×Höhu[r6LÊžµìÓ©Èx‚w¿Iƒ¨=étú?ó}–#§'"ë5Èi‘Û5È™Œ¢¤äCDÊN[¤ü;5…Ú „ØÍ“whhh=×.²mû r&BeÚZ<ƒD"q1†o Uå`,{t¢/C3€žžž^’?Õ!KDþnñâÅ:/VÁ0Œ'ËL*†aü›VeÚÚÚN"Yöu°£!ùÈdžÆ¡úò>|øaèišLÓ\Æx No#ùóRÓ‘|±LgŽII$­žç­ƒÇ–àž…G&{&Tصk×>’é%"KDäáx<®Ýã'—ËÝŽÒv2?Ìår¥[x<ÞDòŸ¡èó7ŠÇ2™Ì¤Îº¡Ÿæillü'’û4‰[nšæ}:]Ù°{÷îC±Xìr’G­”‡ä«}}}—•С Ó4)_ÀžÆÆÆu…š’ׯ‘|3—Ë]§»€áãç$/ ®›ä÷©ˆl‘ÇKpÝ.šàÚ¸ЩK¦a7¦Óéç =W©•6ò¬ ™Bï’¼ÖqœeŽáÈAÍ0ï,H$­A³¯óþ¡-®ë^‰"‚JVÄlÛ^-"7ë–Kr‡çy×…uŸPØ´µµ øtõù0èûþ¹Åþ&¡Â*|`x`hƳ–e)_PQi‰ÄÅžç= ½…’÷•R!BmÂ,ü<€$ÓW»Û4ÍCžç<¹¬··÷8Ó4g Í 9?8ÉœÄp|äÏ£:'’7&“ÉÕ娲LáŸÊlô9ZU¯ùµA¾eÞ×+o½æ×ù  `” ê5¿¶8Ê\×}yô¥Bš©×ü#_ à‰ÈtgT¯ùµIÞi_6›íjii™೚òY{d?¿Nm1á^ÿܹsÿŠ—?`øÌÚÝõš_»r 5‰Ä$¯*Cö€ˆÜšÉd^(G±:•¡ÐÊŸd³Ù_¶¶¶~Dòd­EÊ}™äõ®ë–° Ne)ådiYÖYV’L½ï:uêÔ©S§Îÿ‹Ü̼Ò_‹IEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomin.16.png000066400000000000000000000012671370472574300242340ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(ÕIDAT8…‘¿kAÅ?ßÙõj“"EÀÛÍU„€`¯gH æoˆˆµˆXè_ú˜” “ÆD°ÙÛ›eÑ"!¢m¼ÙgánØ»$ø`˜¼÷æÍã,,,Ü«ªê!ÔGEE»yž´y6-ì÷ûsãñx¸÷§8ŽŸ ‡Ã“Ký~.„ðAÒ¼™Û’ŽÌl X—4kf?¢(Z‡'®m07%ÍŸsïýkI‘$óÞo3;4Bx5‘ ~ó¶™9çyžÿH’ä ¢(Ò4½ ìJš­ªjí"A]Àv#®qè4ïý/`À97ˆ[Ä@ÒQ·Û}`foj1u’ 8—ôDÒ—FÓî༞ P=.ÁÌ&ÎÛ |MX*Šb XlÝLQ·[ižÖÜÑEçÜÇz¹^ÕàO+]Sâc€ÂÞ…Áh4ú ”’f·‰¤ `£%~ÌHÚ/Ëò°ùF—¦éKI«­·þvZ…ÝÖ€3ûÇñJ–e§v•([W•(i¿Óé<ϲì N’dyêæ÷Þû½^ïNáÿ¾·cf£Â^Y–‡mÃX’3³ 1Påy~ _•bQ·Û]M’dpÿeOá/V4Úè2½D¤IEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomin.32.png000066400000000000000000000023521370472574300242260ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYsbb8z™ÛtEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATX…µWMo[E=wì8¨ø…@!¥"}o™"ª!!‘¤@ÕˆøŠÔJ ¡D Ô_‹6,X±£|¬¨‹Š$E‰¨‚ˆ\6!Î{‰ŠZŒ›¤Â=‡Ež£çñ³c·á¬æ~Ìœã™;×ówˆl6Û].—“Éäa’@Dþ®T*׺»»—–——Ëí¬#{žw À˜ˆ “<»¨È-’³"òÍêêê̾Èd2ƒ$'H>Ý™d\I$gWVV–₉6ÉÇ1çéðrOOO©T*ýÖ±ÏóÞ"ùv“Ü53æ,†ö÷YyJDF{{{S¥Ri>hyZëWH¾o¹ àÓ¾ïÿÞDôcN8as(¥& …Â…=d2™AcÌɈ»Dòt?µYã9çz"îm’/AÕl2É ›Ü3n“»®{\k}Eký³ëº/Dc…BárµZp3âî‘Éš+Àó¼cVµ“äéµµµ?ì\y—ä$ŠÈ{v|}}}Y)u;GWÃ3Z둦ŒY$ß·Øö¾ÈøP\B¡P˜p1ê#9+ ›Ív‹È°•üYò¶Aò|Ô‘‘\.—jP.—­4«öNÁUYºwccãɤ("[®_k×u_ ϹMàyÞrļAr*‚K¡½ ??ܰ"rȲoÔÆJ©Z‘Ç /œ³+ÈæŠ`w¼Žÿ°šdÝZ"bâücMz¨66ÆL¸Þçu’»w^DêvÏóWC T*•‚RuºŽÖáY^Š­3‡ïûÙ‚ž²ì?v ‘H,ØŽ¸Ž„½ý®àºîã$w PD6ÇYj°ººú¯ˆÌYîSw+@DÞ°\3ù|þvl'$ù¥å:‘Éd†ãrQ_Ù±õ¡µpÜô-Фû¾ÿ#"÷€c>éïïo8_’S"R‘"€);>00ð(ÉP›ÂöÅr¹\jssósÏZ¡›J©3µÉ{Ak=JòcNĽMr,‚«±Bòi#MÖ%€‹$Ï×±áºnND^Ç΃¤~29ÁW5»N@äu{û"Ébh?àh´Ú-Lû¾ÿaݵÁÐÐPW±X<àùvÈ;Ä6Éw¢¿¼N@›¿|;N»™ì…’g›W¶¶¶Þ܃|6N¿–Ïç·=Ï‘q’£ºâ’Ed“äœRêë½ Vˆçy¿ ñ)m“ߎ:µÖ÷T«Õ'D$ W)U1Æ\sgÉÎo)@k½H2mI^N¥R'Ûýλ¨~›uçÕÿ“¿vÇYPJÝnç-ù"NOµ»û‰}{|´‹ÿݺ’ÀÒu¨IEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomin.64.png000066400000000000000000000045621370472574300242400ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœí[oŒ\Uÿwg»Ýþa·Ôvûæ½×Ù)¥õƒÖEjý´”&@ƒ¥Ä´ý@ÀXk•@Õ!ÖD S’&ý`«i ¥‰¦‚X%üK*˜ˆt—íÌ»of+b§î¸li2óîñü]§ÓÙ÷î{;ÓRð—l²sï¹çžó{ïÝ{Ï9ïqÐ¥˜ÓqœDt­Rj9€ €%ºÌ dÎ(8 ÏÌ#Bˆ×òùün©1­T6O&“¹F)µÀuÌ|e"%D%¥Ô˜ùéB¡p- £­ tœ9sæËJ©­œ«Ï3ó“½½½Ï?~¼’TIÛ°,ëf"ú€O´k ¢SÌü)åooµAK—.5S©Ô.Ÿoµî0Ñ‹•Jåþ±±±bœq¢•FX–õE!Ä^Ë[©Wwz!ÄÆîîn¯\.¿­;¨UmÛwуæ¶Hg̰nÑ¢EÆøøø«:ZA€°mûGîh®V€¬éééé-—ËBÄN1Û5€lÛÞ à+±½ àeoQžˆÞ±,k<Ï›¯”Z‚ÚαÀZf^•À¾_I)jG¥Ó°mûnÛc ™pÀ!)e>Î\–ee ÃØ`33/ÐGDO¸®»{Æþ8FÔÃqœuÌü3Mñ €½sçÎÝ3<<<‘tNÈf³WT«ÕmÌ|'€”Æfæoxž÷|³ÎDô÷÷§«ÕêWhˆ !îÊårÚ+³2™ÌU¾ïï†ÞŽSö}}±Xkì0’L^­V =çÑ­ºÎ¦ ¹0çr¹ß÷7ø†x·a;›uľ‚ÞO£ä˜ù çy÷P:?ID÷ÑgkCù5»¤”oi˜$ÇÙÉÌ·iÈ~SJy´¾!§OŸþ#¢·G¥”߆†óË–-³•R¿ÐužaDg‰è¶|>?¬aš°mûq7„ QÑqœë‡††ªSm±R©´Ñοíûþw¡á<(¥îCƒóÀÌó”R÷hšæû¾¿ƒˆFĘÙÌår·Ô·Å!€˜ùk2!Ä·ŠÅâû1ô®qB¢5ºJ‚9ïP “3 c+êî|m2™Ì5ˆi÷&Xí/¸úS`æùq¹®{‚ˆö…É0sƲ¬ÏLýÖ& HfÌ"z¯££ãI]}íBggçÏQ;pÍ"š~ t ×… 0óþÑÑÑÿhêk†‡‡'ˆè×b×#x ´pgET‹™ŸÒ3±ýð}ÿP„H¯išý€&DtmDÿ›žçå4ík; …ÂI'Âd Ãø I€Rꪑ—ôL»¨x9¬Ó0Œå€^0Ë"úÿڬѶí•î°!«}lÛžioÀ+Dô¨ëºÍ®öëÉQ0sЖFô_ÚZ–µ ÀAƒHè|º|ÀAÇqœ&ýQá¶ h3ó?Ûˆè^´Çñƹçx Iû;CúÛ`èdñâÅ“õ¿SA`s±° QäÂ… 'gÂ|@Ÿ?Q—t (‡u–J¥óî¡¡¡jÒ^(¥^BÃEš˜˜ˆ:FOúü;¬“ˆ>Þ¤yÕÔŸD4)„x I{TÔúТ;€™/Ø&¥”oIÌcí ‚ˆ&3 cc>Ÿ—MD¢¶î" y ¢Qf M?&©©\.7`k˜î} ¥ÌêØØ«Ã:‰(è߯Gô_Ô: &Bmbæ@Ÿ€7"”­J§ÓýšºÚŽÀ–a2J©WM\וDt:LFq«¶…m†"*Aún¡Pˆõ03GÕß7g³YTy[á8N€Ma2Dô{5CíŒPT¼ÏÌ ªÕê6]}í3oJ¥1ó‘©ÿµ ð<ï±™ùÎL&:Ÿ‡°-2Øê´aÛöJ"º=b¾“RÊéE=VZœ™÷Eˆ¤|ßßmš¦vÄÌ3ÖñÃúašf=ÆÌ¡•%fÞƒº’y,<Ï; *ë»\ñ04K\†a<Òì.Nxkš&„2sèNDDE)å‘ú¶¸µA€ŽQëÇÙ ‚ÊÏz"z‘ˆ|"ò™ùÏD´^3Å.‚¹¾¤!ûb†ØµÁt:ÝgÆsÐ{æYß÷wÄ(”L¦}öõõÍëèèxzο ¥üjcc¬; p~?ôߺ!•JvçjMyšÎÛ¶½rΜ9‡¡çü¸Rªé›"Úw@óiÝ1u¨Ñ>Ã0~‘ËåB«(8ŽÓÃÌÛ‰èö¨/øº”òX³N-féüÿ&«mk|ß?¤®µašf6•Jm°)fÉì1)åŒo²DÐ*ç›àj©ë¿p‰èS©µR©4Ÿ™— Ò®F-° =Û7íw]÷‡¡2amt¾íœeú ¸Œgf~Üó¼'t„›&DlÛ^à—¸üœŸ ¢ïK)uÞÐdL§Ó}¨½ËgÍÂs³›/(¥nt]WÛy á®üÌîÊ”R[ øÀwÐæ§‰¨à!×uŸM4~êÓ4»„OˆÍ5  ”ÚR(N¿…mÛ· V£Ó= iˆN2óžàlŸ¸n1M€ã8Û˜yÇ,ljtþ™q繩Ši„:߈ ˜ù)«ƒn€žàO V´(#¢<3ø¾ÿj±X Í '@6›í¬T*C‚àˆˆÆ*•Ê–¸_j|P`À¹sç |‚p5ªœÜˆ‚ïû›.gçºsÅùê*Ö3ÿAÆ4Õjuj«l>4Îu‹Å3Á«°a$œ°ùÃâ<г+—Ëÿêîî~Ú0 Ú÷¼ Ú¡ƒˆöÑ}RÊñKaè%iš]Ùl¶óRÛñ´ÿ¹ëC'¶Ì5–IEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomout.128.png000066400000000000000000000107621370472574300245210ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs‡‡åñetEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(IDATxœípåyÇ¿ßÝ»“dlq®ù¡ÓîžlÆ¥“`»šP( %B ¤š0N©™L€–”ah;“¤IÀCjC褅:1¤ü¤ÌPèØ0))¦ÒÝîIvkcÙ> [‘¥Ý§h­JòɺÓûîÝž|ŸlvŸ÷9=ÏûûyŸhРÁñ k­@­°mûTé$éˆÈ2’€´8@+€áã‡pÀ0€"@@@Þó¼ÿ©öwÐÁñâ¦mÛg8ÀÙ$W‰È‚Ù^ª’‡¼` €Í®ëþ €¯³Œ(˜·°|ùòÖ±±±‹Eä’g‰È Õ,ŸäAù…a/¥R©ç·oß>TÍòËe¾9€iYÖÙ$¯ðYŒ7çqà0€×<•Íf7õôôŒÕZ¡#Ì p'Áõ†a|QD–ÔZŸYø@Dþ%‘H<šË劵V¦® “Éœ”H$¾$"7`|ÐV7<$"O$‰‡úúúv×LZ¬‚ã8iY à͵ÖG‘a?2MóZ´õæ´mûr’wˆÈâZ+£™ý$ïq]w#©V¡uã–eu’ük¯µ.QBò Ã0îÎårïW£<³…(b:޳–äß°k­Lh‘kÒé4ŠÅ⛈¸5ˆu ÐÞÞ¾8™LÞ+"çÕZ—±%‘H|#ÊAbl[ÇqÎ6 ãgÔZ—’‘Ë[[[ß+‹…( ˆ¥8޳À÷,¬µ.1`a—¶¶¶Ž‹Å_ê7 ã8ß‘?GÌ»§*c<ïÄOL‹ÅW¡q\èêêJ655Ý#"Tk]â É•étÚZ½zõË®ëZdê¢J&“iI$ŽãÁ^¥¼âûþÍê‚jî]]]ÉÁÁÁ‡kaüp9vÉ€ÉÉ]###‡ššš†,Ë:…Bá„‘‘‘EMMM Däé ÿ]…Úl:½’ÍfoRÝXªµŽãÜ+"—V£0’ˆlð*€-žçmƒâž}www"—Ë­$y6ÉóE¤ Õû»>ãyÞmPÔÔlÛ¾À—£.'¬áφñt.—‹d:uÇqNð‡>¶‘Bò1×uïžóû:•©ÇqÖˆÈmQ–AòM\×ýy”åÌT¼ã8Ÿðµ°Uˆ ù^¡PøÁ\Þ­‰X–u®aÿ$"FòI¾áûþºþþþ7¢_)Ùlö,¹5*G é‹È žçm®øÝ(:§vÚ’d2ùK#_“µ2‰t'“äÓ4/«tÙ8’x Ìd2y"0>É'’Éä§]×ýâg|Ïóž2 ãBOj.²Ä÷ýï£B›Vu!Èqœµ>¯S&Ƀ†aÜáºîú½{÷Žè”ûöí)‹›ÚÚÚ $ÏÔ(ÞJ§Ó~±X|½ÜªÖd³Ù"òÑétï¸Ùó¼¼F™U£££c™išëEd™F±c¦i^šËåþ»œ‡«Õ0‚»5É/Ö«ñ ¿¿¿Ï0Œ«ÃÙŠ.Aü-ʬÜUé,ËúÉ?Ñ(òeß÷o* j”YöíÛ7²pំq€¬&±ímmmÞþýû·Ïö`ä]€ã8i/ŠÈIšD¾ìyÞ×P§n*¡»»;‘Ïç7ø”y$÷$‰ {{{ë¹È»Y«Ëø$ß$y æ™ñ §§gÌ÷ý[0~¼LY266vólÏEÚ„sþè Ý~ß4Íkãp˜"JÂs£¦á°ïûŸØ;Ó‘¶©TêFh0>ÉCA¬ïÆ×u÷‹È’5ˆk1Mó†c=™„žüÇšÄÝÕßßß§IVìñ C—ù„ˆ<¤*Ã0Œ£l£ÛL’S@2çºî+ºš/xž÷ï\"r¦Í´:€mÛ+5ÌýŸB£ï/…ˆˆê xQ6›ýÈät·g+¾/£££ÏjÑdâû¾rå‘s&ÿ7xsÇŽZ4™‡ìرc@ÔpŠt:I®R”ñªMæ1"¢ú7Z…I»ÀÚÀ¶íS4¤_­8®ýx#‚_¨¼/" —-[6±J«ÍTA‘<”Íf¥KŸùÊÒ¥K߯xj¹9ãûþ„­Êý?Jñl"²m'] ˲>Gò"’gŠHâ“v&†Iî‘wüÌó¼ç”}ÖëÖ­£¶m¿à÷æª@l²Ðëª-@®’ç;::–†qÂB"u3sl‘ví.¶m{ €[*ŒnÎAÁ8Gþ£­ óí«P¶„Æßˆù‘@ê ’;::Ê«´²”`"ÝžÎYÀŒQ'åPî—êîîN†q?€´JyqBDN [³rÃô•ÎBœÈ«¬Ó”f$w•ó\>Ÿ¿ À •²bÊŽã\Ræ³ÿ«RˆLd_ÓÙ(¥t;|øp¹Aʱ1¦¬ï6::ªt f²­tN•ö‰D9`ø]•râL¹éeLÓTŠžl+]€’,^¼xÖ/•ÉdÒšTʉ9-ŽãÌ:–Z´h‘jȸ~ ù)£D"¡%7^œ1 £ªóYFûÊ˃ƒƒ³¶ ®ëP-'æ çr¹Yƒ`‡††T·Ü'ZØ8ÀØØX9_*Ð[D¤¬ôð¾ï+9ÀäSG:@i}:•J•û¥´§W‰ÿZÎCÉdRiÆ%"³³€}ŠïŸ\ÎsŽãüÀ©”GHþºP(<_æã§(–¥ßHª.N”µÚÓÓ3Á×uœ˜‰ $ƒ ø:Ê?ö®ºñ61ÎÐÙ(9*øRýýý}"r Éwˬ9$ÿ“äÕ…B¡ìõ} H½#ÿѹX•àáîÙ¶m–äEV†ù÷êa;xÀÛ~æºî‹¨`;8D5wÀÄ^‚6‚ —TÊ7±²««+¹uëÖÑJŠ ÷ÓËí;ëž®®®äž={>ª"ƒäÄQ{m]@ï)ŠhQýbÇ»wïVNOošæD  ÍvP=É{ÎìßTм&ùáät²:@© y¾&]æ-$?¡(âíÉ?h]¿'¹Eå}éjooÏèÒg¾þmTCï§D^ÇÊ0‘H\¦E™yˆišWB1³Éè`Á‚Ê!Ë$/Gí¯²‰#$©Z9äóù)k'ZàÝwß=Œ0Üx®ˆHgxÓFƒIضý)LŠæ $_Ç´ÕÆ(öð•çäáÅ‘ &ArªŒ ^šþ™vH&“/¨d1§«²ÙìY:ô™X–u®ˆ¨†Âý¦¥¥å…éjw€0«×kªrDäV4ÆÀøµ±ßÐ çÅíÛ·%\ƒà£‘Ç5Èè²mûJúÔ3Žã|ÀJU9†aÜ××7cÖµHcù>ü0ô´-¦i®ûÄyeYm¾ï¯‡†À–ðž…GŽõL¤°sçÎ=$Ó!KD–‰ÈÙL&î?s&“É´üGè»<ê±B¡pÌV3òÓ½Æ ‚àn”™Q4rpgˆÜ…lYfÆÓ¶m×]Ò˲®ò}ÿIèðHÞ_É[‘vQ¿O’üvÜ»ÇqÒ"rô,òLäk®ëÞˆ ÎD6´mû+þ"*ù%8ÀÕmmm‡÷ïßÿâ—qœ¶m_Aòï¾ô ¿`ëË{÷î­(yD$-@•k~)Þ"y¯ëºª1ŠZ°mûãn…Þ¾~’>Éëòùüë¿«[™2oXïy^ªß"0 ãú3¨GòÎÆ·=Ïûá\^Ôêa³‡N™: ¹CDž3 ãñ|>ïÍþÆÜ±mûT’—‰ÈUÐ<À+ɇ]×ýîœß×¥HÌjþLÉ_Aðšˆl^ºté¶ Ï"EWWWr÷îÝ«Hžl™’Ž=bžö<ïv(´nZ­ã—bÀ;úHæ1ž®v—iš}ß:’¹lppðÓ4-$¹4<ÉœÅx~ä3Q›É=ÙlvÍlOAÙêØøõLïûk”wZ•‚lÛþJÃøUç™l6»F‡ñ… ®¾yÎ#žç} •'”˜‘99@£Ù¯.$}ùî\§zÇ¢â}õF³_]ÂR· å³¥¨h Ðhö«ÎæD"qITÆ*èÍ~U%y¿ëºAc_вZ€?ÒU¼˜°%‚K\×Ý€ˆ”á1êó×yžw€Û|Pke"à·{žw]%ûùªs;ضí?ðÍ*é2#$ïñŸÿ”Ÿ:rŽr€ÎÎΆ÷Ô׌9 Ë—/oý €‹1ž€²Ú;vH¾Á¦‘‘‘çwíÚ¥zÏO$åŽãü¥ˆ|µÊzŒ?i{öÃøàQé¢Ëé„9øß°™äæ0WljúL”r€5¤#Ÿ›2&2™L»iš+HžÁɆaœ^ZÑFrˆ$H.ãwì øä¡0ß¾ O2gšfnrúÕzbº˜ŽãüZD"?2V‚Gû ¢cʯ££ãä†ñ/¦8@*•ªºñÃEž†ñkĬrùëªÕç7(Íعsç!U9ZÕ¨ùñ Ô2ïŒùd4Ò¨ù1¡”•OV'š/ŽrÏó^˜|©f5?f”j|¹OwAšOJNûŠÅbo:^ à#šÊYwd?¿A¼˜q¯É’%ÅË0~fí;š_f 5-˺“äõs=""w …gç¢Xƒê0ÛÊŸ‹ÅŸ·µµ½Oò·´•)÷’7{žWq‚Õ¥’“A¦mÛ¸€äù“³X“ô¸"ò’ˆü[¡P¨ûKæ|60“É´ˆÈâT*5šÏç÷ ö¾4hРAƒü4BgXŒÔëIEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomout.16.png000066400000000000000000000012221370472574300244240ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs±±õƒíItEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ(°IDAT8…‘±kA‡¿7;\m®H!x³w[‰°P°Œu ˜ÊVKkKÁÊØ —Bÿ“2b¡iÌYîî,Z$D´Õ›}ΛÍ-þ`™Ùyï÷½yo„ ‡Ã›u]ß\<úš$É~Y–ŸšyÒ6fY¶:›Íž·:جµ‹¢8¹È²l5„ðVU/‹È0VÕ €ˆ¬;ªÚ‘ïI’lEqràœ{+L’äAY–¿šñ4M/»ªzCDÞ{ïï/±ç±ˆœcÖÛæd_Uûu]o›y  `ÜeðÞÿöŒ1ë¶ PÕcçÜmà%`[þ?ÀCUý<÷˜Fðw\Ðø]ˆÔÍÿfÖ¼÷/€«]m8çÅÜéâƘwq»µT1v „p°L§Ó/@¥ª}`w$ž½VTõ°ªª£ù3š4MŸ©êV£×À^c`×m`ED¾Yk7ó¡µ¾àTLrx À+Ùl¶^¯×‹-À¶í·I¾Ó#v À€E˾} ÀFœ‘±þþþT½^_ vìû Çy•äG†›~0íºîï=D?à€³&‡RêR¥R™9P@>ŸÒZÏHÜu’ç=Ïûi?áÏk­? ¸wI¾ìy^T¯Á$'Mr­õDTr¨T*×[­Ö€¿î>¹Ô6Bض}ÆØí$y~mmí¨äm¬¯¯¯(¥.`ïÕµñœã8£="2gæ&*•Ê€kAÉñP…B!-"#Fðç‡%临Ed´X,¦º4!£Ây½v{xžwCDÖ‚îßÜÜ|:iŠÈ£†ë×v#—˽¤”z—äñ(¤"R#ù¡ëºßû®e“]+ "' {ãnSÞJ~ì¸{Ü7‚ý"r"L€Yñb°Lþ’¹DD‡ ø«c4ùp Ñe·coøcÚ¹ vj­owíf³YQªC×évÃuÝY³1˜xưou­@"‘(Ø ¸NùµýHÈårO’üoŠÈ–eY¥.ÕjõY0ÜçŽ*@DÞ2\sårùNh%$ù¥á:›ÏçGÂb£Àqœ1/‚¾z”b×uDàü­õ§…¸äƒƒƒ“ü§iÉ/ÏáŠÅb€ÃM$3qVÂqœ±V«5ƒîÏñTÛè:ãÅb1µµµ5 `´G^¸Fòªçy7Âr¹\QDÞÄÞ…¤s09éyÞW¡"wÀ¯íË$k¾}Àéàn70íºîÇ9Úááá¾Z­vÀ QÈcb—äåàÌ;Dœù"ö.œf19K$§z½®$loo_<€|>“ɼQ.—wmÛ‘ ’cú‚Ed‹ä‚Rêëönï ¶mÿ‚î«´I~'ètç¾V«õ”ˆäô+¥šZ뀛–e•Ìø}8޳L2cv’¼žJ¥^úŸw¨=~Ò7oYÖkÿ'9àÿíX–µ¤”zÐ_Îù"“ɼuï%Žzùˆó Ÿ_y£ÊØIEND®B`‚olive-continuous/app/ui/style/olive-light/png/zoomout.64.png000066400000000000000000000044021370472574300244320ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î<tEXtAuthorMartin Ruskov·ËÌ™3tEXtSourcehttp://commons.wikimedia.org/wiki/Tango_icon^Ÿ( IDATxœí[olGÿ½sœ4l,gïvs¾4m@Ðà’P>E*"ñG%M…’PUT¢„|@Q•¶B¡Š@…µ¡ ”J‘‚ )BiÓ|¨ÚBA*B¤…µE¶ã¬w÷Ρ.øâ†Xº›y|¸µq/—ÙónÒ´ü¤“îæ½yóÞïfgæÍÌïrÐÕhÓuÝ5D´^)µ@À =®‹tþ à,€qfBüi|||§êLšÆâÚ)‹·(¥6¸™ßÓ‘¢ªRê·ÌüT¹\>‰ÈÈ”€¡¡¡®sçÎ}^)u/7eóãÌüxÿÓ'Ož¬wj$3 …Âg‰èA×gÕÑYfþ^ÏtT?m‡V®\içr¹ïøXÚ¶ã@D¨×ë{&&&*Iê‰4( ŸB°:M»¦Í !¶ôôô„µZí´i¥´ Çqî#¢‡,LÉf'X`S__Ÿ599y¤BÇq¾ àK)ØJ`Cooo­Vû=43Å|Çrg/€/$®Hô€ã^&¢q"z½P(\€0 +¥V 9s¬p+3¯íÀ¿'‚ øf¬…ã8÷Ø™ Ê€ÃŽA0ž¤­B¡P´,k €m̼Ĵ=æûþ¾ËÊ“81®ënbæª×X¸páþ‘‘‘©NÛ€R©´¬Ñhì`æ{ä ª035 ÃÚ ;"`pp0ßh4ŽXf >"„ØåyžñÈl‚b±xƒ”rÌfœš”òs•Je¢U`uÒx£ÑøÌ‚–ˆîH;xð099Ùñ2U‡óçÏ7jµÚó}}}×xœ.9½½½§kµÚØÜòD=`hh¨+ZÞêðl†{¨$ö;„ô}€çuŠDôàÆß2n$" Z­n†~mZJù®Lð3RÊÝD4§Ä̶çy·Ï-KB1³®ë×…_«T*ØMQ›»4âô,˺scŠÅâ-Ч´²ðLáûþ0ŒÓaæb¡PøðÌoc¢ÍŒË‚ˆÞìêêzÜÔ^Vèîîþ š ®Ë‚ˆfSÀmq Ì|hll켡½Ì0222ED¿Ô¨}Ñc`D€ëºktÛXÌü¤™‹ÙCJyD£ÒoÛö `H­×È_ ÃÐ3ô/s”Ëå3†ãt,Ëú(`H€RêÊÍ\»¢8'´,k5`–LÀ*ü¯í ]×ÝÀÌ»|À"öLqÀ+BˆG<Ïûsù)ÄìQ0s0Vjä—¤¶ŽãÜÊÌ?ð¤<"›ë¥”?_µjÕÛÈué¶  Ë¿™ù­eD´ æ=l>È)¥îoãÓëšzKóipqœpùòåZŠ,fŽMNRÆÍh‰eéÒ¥­>µb1Z+Å@vàÔ5SjqÂjµÚÚC½Ú™KáZ’¯©©©Ø^ à`NÀ¿ã„Dô¾6Å@“˜¤„ºâû­…D¤ËZßRêÌ|É4éûþ !Ä]^BsÊJWJÝåyÞ+m亩»ŽÒD4ÆÌbTnF›­©h~þ¢I`]œˆ<À¼œÒȯè9 !b}bæQÀœ€—5ÆÖæóùAC[™#òeMœŽRê%Àß÷"úWœŽâc3†âNÊår9Ñ#À̬;ßV*•L¶Ê3…뺽¶ÆéÑoïéò}f^Òh4v˜ÚË Ì¼“™c×Ì|læ»1aþ š›™ï)‹ºÔ938ŽsݧCDg‚ ˜Ôm‹3óAJNJ¹Ï¶í,²¿Xض½ˆˆeæØÃfÞ9Gæ‰Ãð(Ý®ïêhe–êí „â‡Ì;Q%‚csË’ž J—,;Û`“ëº{qeHQ[Ÿ4Ð}-‰]â|])5lYÖ44Wa˜ùNÇq–I)wguP200p]WWטÙ$ø}ß¿äø,QÈçó–e‚ù= Oår¹£®ëÞ˜¤8ŽsÓ‚ ŽÂ쟟TJµ½)b|?`NðyÓ:sÐ ¢ƒ–eýÔó¼ØÄJ×u{™y'Ý­ð"0€¯Að»vB#æüÿ#ºà°”òH´um Û¶K¹\n €­ºy¾ApÙ›,ZÒ ¾ †Ñܺþ Ÿˆþ>³µV­V3ó 4SÚuh&6±kûv ¢C¾ï+V'N˜að™# þ!hŽé/KÀ5<3óÂ0|ÌD¹í4è8Î ¿Àµü}=“{CÚLƒù|~Í»|…y82=ºâE¥Ô§}ß7hy¢þ0æ÷Ï—•RÛ-˺ÀýÈøâ4U<Ün‘cTæ‹mÛ‹„O˜O6WVJm/—Ëg£ßÂqœÛÑ<£Ku1DDg˜y´¶ïøÜb–×uw0óîyøÔü[P(ÖÑf"ú 3¿·Ã6Þð€§£”6½Wf\×ýõ̉iˆ ¾®ëº>`]”Áõè>ÍC‹€ "gæQ)å‰J¥{ ¬”J¥îz½þ*,g MÔëõíIßÔx»À€ééi ïÂàˆ€(]Õ'·¢,¥Üz-ÌYQ’·®=óogÌÐh4ö£9ÊêðŽ ˜C@¥R9]…#aÀ¶wJð@Ëž]­VûgOOÏS–e 4ßç] 4Dt€ˆ¾ÁäÕpôªÀ¶íE¥R©ûjûñdˆÿnY#1[Ä:IEND®B`‚olive-continuous/app/ui/style/olive-light/style.css000066400000000000000000000020131370472574300230420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ /* Hack that forces checked QPushButtons to use dark color */ /* Node styling */ NodeViewItemWidget { qproperty-titlebarColor: #a0a0ff; qproperty-borderColor: #000000; } /* Timeline playhead styling */ TimelinePlayhead { qproperty-playheadColor: #ff0000; qproperty-playheadHighlightColor: rgba(0, 0, 0, 0.25); } olive-continuous/app/ui/style/olive-light/svg/000077500000000000000000000000001370472574300217735ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-light/svg/add-button.svg000066400000000000000000000645551370472574300245740ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/add-effect.svg000066400000000000000000000711521370472574300245040ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/add-transition.svg000066400000000000000000000676171370472574300254550ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/align-center.svg000066400000000000000000000002721370472574300250650ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/align-left.svg000066400000000000000000000002711370472574300245360ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/align-right.svg000066400000000000000000000002721370472574300247220ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/arrow.svg000066400000000000000000000003041370472574300236430ustar00rootroot00000000000000olive-continuous/app/ui/style/olive-light/svg/audiosource.svg000066400000000000000000000642061370472574300250460ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/beam.svg000066400000000000000000000013741370472574300234250ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/box.svg000066400000000000000000000150151370472574300233060ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/clock.svg000066400000000000000000000622611370472574300236160ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/convert-to-dark.sh000077500000000000000000000021761370472574300253570ustar00rootroot00000000000000#!/bin/sh # Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . # convert-to-dark.sh # # A simple script that uses sed/regex to convert any use of white to dark grey. # Allows for easy conversion of white icons for a dark theme to dark icons for # a light theme. if [ $# -ne 2 ] then echo Usage: $0 source-path destination-path echo echo Example: $0 ../../olive-dark/svg . exit 1 fi for f in $1/*.svg do FNBASE=$(basename -s .svg $f) sed -e "s/#ffffff/#202020/g" $f > $FNBASE.svg done olive-continuous/app/ui/style/olive-light/svg/diamond.svg000066400000000000000000000641701370472574300241370ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/dirup.svg000066400000000000000000013136101370472574300236440ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/error.svg000066400000000000000000013117371370472574300236620ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/ff.svg000066400000000000000000000672001370472574300231140ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/folder.svg000066400000000000000000013133701370472574300237770ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/hand.svg000066400000000000000000000662021370472574300234340ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/iconview.svg000066400000000000000000000636051370472574300243510ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/imagesource.svg000066400000000000000000013145701370472574300250320ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/italic.svg000066400000000000000000000003161370472574300237610ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/justify-center.svg000066400000000000000000000002711370472574300254670ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/listview.svg000066400000000000000000000622721370472574300243730ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/magnet.svg000066400000000000000000013152431370472574300240000ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/new.svg000066400000000000000000013165361370472574300233240ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/next.svg000066400000000000000000000646551370472574300235120ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/open.svg000066400000000000000000013230321370472574300234610ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/pause.svg000066400000000000000000000623561370472574300236450ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/play.svg000066400000000000000000000640671370472574300234760ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/prev.svg000066400000000000000000000646561370472574300235110ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/razor.svg000066400000000000000000000626161370472574300236640ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/record.svg000066400000000000000000000614701370472574300240020ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/redo.svg000066400000000000000000000130151370472574300234450ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/rew.svg000066400000000000000000000671731370472574300233270ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/ripple.svg000066400000000000000000013172341370472574300240220ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/rolling.svg000066400000000000000000013253771370472574300242040ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/save.svg000066400000000000000000000167511370472574300234640ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/sequence.svg000066400000000000000000013122471370472574300243360ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/slide.svg000066400000000000000000013241771370472574300236330ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/slip.svg000066400000000000000000013177021370472574300234760ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/transition-tool.svg000066400000000000000000000652571370472574300257000ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/treeview.svg000066400000000000000000000633431370472574300243570ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/tri-down.svg000066400000000000000000000616101370472574300242630ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/tri-left.svg000066400000000000000000000615761370472574300242610ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/tri-right.svg000066400000000000000000000616001370472574300244300ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/tri-up.svg000066400000000000000000000615671370472574300237530ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/underline.svg000066400000000000000000000003421370472574300245000ustar00rootroot00000000000000 olive-continuous/app/ui/style/olive-light/svg/undo.svg000066400000000000000000000127711370472574300234710ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/videosource.svg000066400000000000000000000644351370472574300250570ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/zoomin.svg000066400000000000000000000672161370472574300240430ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/olive-light/svg/zoomout.svg000066400000000000000000000671421370472574300242420ustar00rootroot00000000000000 image/svg+xml Martin Ruskov http://commons.wikimedia.org/wiki/Tango_icon olive-continuous/app/ui/style/style.cpp000066400000000000000000000141431370472574300206200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "style.h" #include #include #include #include #include #include #include #include "config/config.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER QString StyleManager::current_style_; QList StyleManager::ListInternal() { QList style_list; style_list.append(StyleDescriptor(tr("Olive Dark"), ":/style/olive-dark")); style_list.append(StyleDescriptor(tr("Olive Light"), ":/style/olive-light")); return style_list; } void StyleManager::UseOSNativeStyling(QWidget *widget) { #if defined(Q_OS_WINDOWS) QStyle* s = QStyleFactory::create(QStringLiteral("windowsvista")); widget->setStyle(s); widget->setPalette(s->standardPalette()); #elif defined(Q_OS_MAC) QStyle* s = QStyleFactory::create(QStringLiteral("macintosh")); widget->setStyle(s); widget->setPalette(s->standardPalette()); #endif } QPalette StyleManager::ParsePalette(const QString& ini_path) { QSettings ini(ini_path, QSettings::IniFormat); QPalette palette; ParsePaletteGroup(&ini, &palette, QPalette::All); ParsePaletteGroup(&ini, &palette, QPalette::Active); ParsePaletteGroup(&ini, &palette, QPalette::Inactive); ParsePaletteGroup(&ini, &palette, QPalette::Disabled); return palette; } void StyleManager::ParsePaletteGroup(QSettings *ini, QPalette *palette, QPalette::ColorGroup group) { QString group_name; switch (group) { case QPalette::All: group_name = "All"; break; case QPalette::Active: group_name = "Active"; break; case QPalette::Inactive: group_name = "Inactive"; break; case QPalette::Disabled: group_name = "Disabled"; break; default: return; } ini->beginGroup(group_name); QStringList keys = ini->childKeys(); foreach (QString k, keys) { ParsePaletteColor(ini, palette, group, k); } ini->endGroup(); } void StyleManager::ParsePaletteColor(QSettings *ini, QPalette *palette, QPalette::ColorGroup group, const QString &role_name) { QPalette::ColorRole role; if (!QString::compare(role_name, "Window", Qt::CaseInsensitive)) { role = QPalette::Window; } else if (!QString::compare(role_name, "WindowText", Qt::CaseInsensitive)) { role = QPalette::WindowText; } else if (!QString::compare(role_name, "Base", Qt::CaseInsensitive)) { role = QPalette::Base; } else if (!QString::compare(role_name, "AlternateBase", Qt::CaseInsensitive)) { role = QPalette::AlternateBase; } else if (!QString::compare(role_name, "ToolTipBase", Qt::CaseInsensitive)) { role = QPalette::ToolTipBase; } else if (!QString::compare(role_name, "ToolTipText", Qt::CaseInsensitive)) { role = QPalette::ToolTipText; #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) } else if (!QString::compare(role_name, "PlaceholderText", Qt::CaseInsensitive)) { role = QPalette::PlaceholderText; #endif } else if (!QString::compare(role_name, "Text", Qt::CaseInsensitive)) { role = QPalette::Text; } else if (!QString::compare(role_name, "Button", Qt::CaseInsensitive)) { role = QPalette::Button; } else if (!QString::compare(role_name, "ButtonText", Qt::CaseInsensitive)) { role = QPalette::ButtonText; } else if (!QString::compare(role_name, "BrightText", Qt::CaseInsensitive)) { role = QPalette::BrightText; } else if (!QString::compare(role_name, "Highlight", Qt::CaseInsensitive)) { role = QPalette::Highlight; } else if (!QString::compare(role_name, "HighlightedText", Qt::CaseInsensitive)) { role = QPalette::HighlightedText; } else if (!QString::compare(role_name, "Link", Qt::CaseInsensitive)) { role = QPalette::Link; } else if (!QString::compare(role_name, "LinkVisited", Qt::CaseInsensitive)) { role = QPalette::LinkVisited; } else { return; } palette->setColor(group, role, QColor(ini->value(role_name).toString())); } StyleDescriptor StyleManager::DefaultStyle() { return ListInternal().first(); } const QString &StyleManager::GetStyle() { return current_style_; } void StyleManager::SetStyleFromConfig() { QString config_style = Config::Current()["Style"].toString(); if (config_style.isEmpty()) { SetStyle(DefaultStyle()); } else { SetStyle(config_style); } } void StyleManager::SetStyle(const StyleDescriptor &style) { SetStyle(style.path()); } void StyleManager::SetStyle(const QString &style_path) { current_style_ = style_path; // Load all icons for this style (icons must be loaded first because the style change below triggers the icon change) icon::LoadAll(style_path); // Set palette for this QString palette_file = QStringLiteral("%1/palette.ini").arg(style_path); if (QFileInfo::exists(palette_file)) { qApp->setPalette(ParsePalette(palette_file)); } else { qApp->setPalette(qApp->style()->standardPalette()); } // Set CSS style for this QFile css_file(QStringLiteral("%1/style.css").arg(style_path)); if (css_file.exists() && css_file.open(QFile::ReadOnly | QFile::Text)) { // Read in entire CSS from file and set as the application stylesheet QTextStream css_ts(&css_file); qApp->setStyleSheet(css_ts.readAll()); css_file.close(); } else { qApp->setStyleSheet(QString()); } } StyleDescriptor::StyleDescriptor(const QString &name, const QString &path) : name_(name), path_(path) { } const QString &StyleDescriptor::name() const { return name_; } const QString &StyleDescriptor::path() const { return path_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/ui/style/style.h000066400000000000000000000034051370472574300202640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef STYLEMANAGER_H #define STYLEMANAGER_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class StyleDescriptor { public: StyleDescriptor(const QString& name, const QString& path); const QString& name() const; const QString& path() const; private: QString name_; QString path_; }; class StyleManager : public QObject { public: static StyleDescriptor DefaultStyle(); static const QString& GetStyle(); static void SetStyleFromConfig(); static void SetStyle(const StyleDescriptor& style); static void SetStyle(const QString& style_path); static QList ListInternal(); static void UseOSNativeStyling(QWidget* widget); private: static QPalette ParsePalette(const QString& ini_path); static void ParsePaletteGroup(QSettings* ini, QPalette* palette, QPalette::ColorGroup group); static void ParsePaletteColor(QSettings* ini, QPalette* palette, QPalette::ColorGroup group, const QString& role_name); static QString current_style_; }; OLIVE_NAMESPACE_EXIT #endif // STYLEMANAGER_H olive-continuous/app/undo/000077500000000000000000000000001370472574300161415ustar00rootroot00000000000000olive-continuous/app/undo/CMakeLists.txt000066400000000000000000000015111370472574300206770ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} undo/undocommand.h undo/undocommand.cpp undo/undostack.h undo/undostack.cpp PARENT_SCOPE ) olive-continuous/app/undo/undocommand.cpp000066400000000000000000000023401370472574300211500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "undocommand.h" #include "core.h" OLIVE_NAMESPACE_ENTER UndoCommand::UndoCommand(QUndoCommand *parent) : QUndoCommand(parent) { } void UndoCommand::redo() { redo_internal(); modified_ = GetRelevantProject()->is_modified(); GetRelevantProject()->set_modified(true); } void UndoCommand::undo() { undo_internal(); GetRelevantProject()->set_modified(modified_); } void UndoCommand::redo_internal() { QUndoCommand::redo(); } void UndoCommand::undo_internal() { QUndoCommand::undo(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/undo/undocommand.h000066400000000000000000000023171370472574300206210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef UNDOCOMMAND_H #define UNDOCOMMAND_H #include #include "common/define.h" #include "project/project.h" OLIVE_NAMESPACE_ENTER class UndoCommand : public QUndoCommand { public: UndoCommand(QUndoCommand* parent = nullptr); virtual void redo() override; virtual void undo() override; virtual Project* GetRelevantProject() const = 0; protected: virtual void redo_internal(); virtual void undo_internal(); private: bool modified_; }; OLIVE_NAMESPACE_EXIT #endif // UNDOCOMMAND_H olive-continuous/app/undo/undostack.cpp000066400000000000000000000016431370472574300206440ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "undostack.h" OLIVE_NAMESPACE_ENTER void UndoStack::pushIfHasChildren(QUndoCommand *command) { if (command->childCount() > 0) { push(command); } else { delete command; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/undo/undostack.h000066400000000000000000000022601370472574300203050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef UNDOSTACK_H #define UNDOSTACK_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class UndoStack : public QUndoStack { public: /** * @brief A wrapper for push() that either pushes if the command has children or deletes if not * * This function takes ownership of `command`, and may delete it so it should never be accessed after this call. */ void pushIfHasChildren(QUndoCommand* command); }; OLIVE_NAMESPACE_EXIT #endif // UNDOSTACK_H olive-continuous/app/widget/000077500000000000000000000000001370472574300164575ustar00rootroot00000000000000olive-continuous/app/widget/CMakeLists.txt000066400000000000000000000033401370472574300212170ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(audiomonitor) add_subdirectory(clickablelabel) add_subdirectory(collapsebutton) add_subdirectory(colorbutton) add_subdirectory(colorwheel) add_subdirectory(columnedgridlayout) add_subdirectory(curvewidget) add_subdirectory(flowlayout) add_subdirectory(focusablelineedit) add_subdirectory(footagecombobox) add_subdirectory(keyframeview) add_subdirectory(manageddisplay) add_subdirectory(menu) add_subdirectory(nodecombobox) add_subdirectory(nodecopypaste) add_subdirectory(nodeview) add_subdirectory(nodeparamview) add_subdirectory(nodetableview) add_subdirectory(panel) add_subdirectory(pixelsampler) add_subdirectory(playbackcontrols) add_subdirectory(projectexplorer) add_subdirectory(projecttoolbar) add_subdirectory(resizablescrollbar) add_subdirectory(scope) add_subdirectory(slider) add_subdirectory(taskview) add_subdirectory(timebased) add_subdirectory(timelinewidget) add_subdirectory(timeruler) add_subdirectory(timetarget) add_subdirectory(toolbar) add_subdirectory(viewer) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/widget/audiomonitor/000077500000000000000000000000001370472574300211705ustar00rootroot00000000000000olive-continuous/app/widget/audiomonitor/CMakeLists.txt000066400000000000000000000015011370472574300237250ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/audiomonitor/audiomonitor.h widget/audiomonitor/audiomonitor.cpp PARENT_SCOPE ) olive-continuous/app/widget/audiomonitor/audiomonitor.cpp000066400000000000000000000217501370472574300244120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiomonitor.h" #include #include #include #include "audio/audiomanager.h" #include "common/qtutils.h" OLIVE_NAMESPACE_ENTER const int kDecibelStep = 6; const int kDecibelMinimum = -200; const int kMaximumSmoothness = 8; AudioMonitor::AudioMonitor(QWidget *parent) : QOpenGLWidget(parent), cached_channels_(0) { values_.resize(kMaximumSmoothness); connect(AudioManager::instance(), &AudioManager::OutputDeviceStarted, this, &AudioMonitor::OutputDeviceSet); connect(AudioManager::instance(), &AudioManager::OutputPushed, this, &AudioMonitor::OutputPushed); connect(AudioManager::instance(), &AudioManager::AudioParamsChanged, this, &AudioMonitor::SetParams); connect(AudioManager::instance(), &AudioManager::Stopped, this, &AudioMonitor::Stop); } AudioMonitor::~AudioMonitor() { Stop(); } void AudioMonitor::SetParams(const AudioParams ¶ms) { params_ = params; for (int i=0;i v(params_.channel_count(), 0); BytesToSampleSummary(d, v); PushValue(v); SetUpdateLoop(true); } void AudioMonitor::SetUpdateLoop(bool e) { if (e) { connect(this, &AudioMonitor::frameSwapped, this, static_cast(&AudioMonitor::update)); update(); } else { disconnect(this, &AudioMonitor::frameSwapped, this, static_cast(&AudioMonitor::update)); } } void AudioMonitor::paintGL() { QPainter p(this); p.fillRect(rect(), palette().window().color()); if (!params_.channel_count()) { return; } QFontMetrics fm = p.fontMetrics(); int peaks_y = 0; int font_height = fm.height(); // Create rect where decibel markings will go on the side QRect db_labels_rect = rect(); db_labels_rect.setWidth(QFontMetricsWidth(p.fontMetrics(), "-00")); db_labels_rect.adjust(0, font_height, 0, 0); // Determine rect where the main meter will go QRect full_meter_rect = rect(); full_meter_rect.adjust(db_labels_rect.width(), font_height, 0, 0); // Width of each channel in the meter int channel_width = full_meter_rect.width() / params_.channel_count(); if (cached_background_.size() != size() || cached_channels_ != params_.channel_count()) { cached_channels_ = params_.channel_count(); // Generate new background cached_background_ = QPixmap(size()); cached_background_.fill(Qt::transparent); QPainter cached_painter(&cached_background_); { // Draw decibel markings QRect last_db_marking_rect; cached_painter.setPen(palette().text().color()); for (int i=0;i>=kDecibelMinimum;i-=kDecibelStep) { QString db_label; if (i <= kDecibelMinimum) { db_label = "-∞"; } else { db_label = QStringLiteral("%1").arg(i); } qreal log_val = QAudio::convertVolume(i, QAudio::DecibelVolumeScale, QAudio::LogarithmicVolumeScale); QRect db_marking_rect = db_labels_rect; db_marking_rect.adjust(0, db_labels_rect.height() - qRound(log_val * db_labels_rect.height()), 0, 0); db_marking_rect.setHeight(fm.height()); // Prevent any dB markings overlapping if (i == 0 || !db_marking_rect.intersects(last_db_marking_rect)) { cached_painter.drawText(db_marking_rect, Qt::AlignRight, db_label); cached_painter.drawLine(db_marking_rect.topLeft(), db_marking_rect.topRight()); last_db_marking_rect = db_marking_rect; } } } { // Draw bars QLinearGradient g(full_meter_rect.topLeft(), full_meter_rect.bottomLeft()); g.setStops({ QGradientStop(0.0, Qt::red), QGradientStop(0.25, Qt::yellow), QGradientStop(1.0, Qt::green) }); cached_painter.setPen(Qt::black); for (int i=0;i v(params_.channel_count(), 0); if (file_.isOpen()) { UpdateValuesFromFile(v); } PushValue(v); QVector vals = GetAverages(); p.setBrush(QColor(0, 0, 0, 128)); p.setPen(Qt::NoPen); bool all_zeroes = true; for (int i=0;i 1.0) { peaked_[i] = true; } if (all_zeroes && !qIsNull(vol)) { all_zeroes = false; } // Convert val to logarithmic scale vol = QAudio::convertVolume(vol, QAudio::LinearVolumeScale, QAudio::LogarithmicVolumeScale); meter_rect.adjust(0, 0, 0, -qRound(meter_rect.height() * vol)); p.drawRect(meter_rect); if (!peaked_.at(i)) { p.drawRect(peaks_rect); } } if (all_zeroes && !file_.isOpen()) { // Optimize by disabling the update loop SetUpdateLoop(false); } } void AudioMonitor::mousePressEvent(QMouseEvent *) { peaked_.fill(false); update(); } void AudioMonitor::UpdateValuesFromFile(QVector& v) { // Determines how many milliseconds have passed since last update qint64 current_time = QDateTime::currentMSecsSinceEpoch(); qint64 time_passed = current_time - last_time_; // Convert ms to float seconds and determine how many bytes that is qint64 bytes_to_read = params_.time_to_bytes(static_cast(time_passed) * 0.001); if (playback_speed_ < 0) { bytes_to_read = qMin(bytes_to_read, file_.pos()); file_.seek(file_.pos() - bytes_to_read); } QByteArray b = file_.read(bytes_to_read); if (playback_speed_ < 0) { file_.seek(file_.pos() - bytes_to_read); } int abs_speed = qAbs(playback_speed_); if (abs_speed != 1) { int sample_sz = params_.samples_to_bytes(1); int in_nb_samples = params_.bytes_to_samples(b.size()); int out_nb_samples = in_nb_samples / abs_speed; QByteArray speed_adjusted(out_nb_samples * sample_sz, Qt::Uninitialized); for (int i=0;i &v) { values_.removeFirst(); values_.append(v); } void AudioMonitor::BytesToSampleSummary(const QByteArray &b, QVector &v) { const float* samples = reinterpret_cast(b.constData()); int nb_samples = b.size() / sizeof(float); for (int i=0;i v.at(channel)) { v.replace(channel, abs_sample); } } } QVector AudioMonitor::GetAverages() const { QVector v(params_.channel_count(), 0); for (int i=0;i(values_.size()); } return v; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/audiomonitor/audiomonitor.h000066400000000000000000000036251370472574300240600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOMONITORWIDGET_H #define AUDIOMONITORWIDGET_H #include #include #include #include "common/define.h" #include "render/audioparams.h" OLIVE_NAMESPACE_ENTER class AudioMonitor : public QOpenGLWidget { Q_OBJECT public: AudioMonitor(QWidget* parent = nullptr); virtual ~AudioMonitor() override; public slots: void SetParams(const AudioParams& params); void OutputDeviceSet(const QString& filename, qint64 offset, int playback_speed); void Stop(); void OutputPushed(const QByteArray& d); protected: //virtual void paintEvent(QPaintEvent* event) override; virtual void paintGL() override; virtual void mousePressEvent(QMouseEvent* event) override; private: void SetUpdateLoop(bool e); void UpdateValuesFromFile(QVector &v); void PushValue(const QVector& v); void BytesToSampleSummary(const QByteArray& bytes, QVector& v); QVector GetAverages() const; AudioParams params_; QFile file_; qint64 last_time_; int playback_speed_; QVector< QVector > values_; QVector peaked_; QPixmap cached_background_; int cached_channels_; }; OLIVE_NAMESPACE_EXIT #endif // AUDIOMONITORWIDGET_H olive-continuous/app/widget/clickablelabel/000077500000000000000000000000001370472574300213705ustar00rootroot00000000000000olive-continuous/app/widget/clickablelabel/CMakeLists.txt000066400000000000000000000015111370472574300241260ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/clickablelabel/clickablelabel.h widget/clickablelabel/clickablelabel.cpp PARENT_SCOPE ) olive-continuous/app/widget/clickablelabel/clickablelabel.cpp000066400000000000000000000023761370472574300250150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "clickablelabel.h" #include OLIVE_NAMESPACE_ENTER ClickableLabel::ClickableLabel(const QString &text, QWidget *parent) : QLabel(text, parent) { } ClickableLabel::ClickableLabel(QWidget *parent) : QLabel(parent) { } void ClickableLabel::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && underMouse()) { emit MouseClicked(); } } void ClickableLabel::mouseDoubleClickEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { emit MouseDoubleClicked(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/clickablelabel/clickablelabel.h000066400000000000000000000023541370472574300244560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CLICKABLELABEL_H #define CLICKABLELABEL_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ClickableLabel : public QLabel { Q_OBJECT public: ClickableLabel(const QString& text, QWidget* parent = nullptr); ClickableLabel(QWidget* parent = nullptr); protected: virtual void mouseReleaseEvent(QMouseEvent* event) override; virtual void mouseDoubleClickEvent(QMouseEvent* event) override; signals: void MouseClicked(); void MouseDoubleClicked(); }; OLIVE_NAMESPACE_EXIT #endif // CLICKABLELABEL_H olive-continuous/app/widget/collapsebutton/000077500000000000000000000000001370472574300215155ustar00rootroot00000000000000olive-continuous/app/widget/collapsebutton/CMakeLists.txt000066400000000000000000000015111370472574300242530ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/collapsebutton/collapsebutton.h widget/collapsebutton/collapsebutton.cpp PARENT_SCOPE ) olive-continuous/app/widget/collapsebutton/collapsebutton.cpp000066400000000000000000000025131370472574300252600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "collapsebutton.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER CollapseButton::CollapseButton(QWidget *parent) : QPushButton(parent) { setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); setStyleSheet("border: none; background: none;"); setCheckable(true); setChecked(true); setIconSize(QSize(fontMetrics().height()/2, fontMetrics().height()/2)); connect(this, &CollapseButton::toggled, this, &CollapseButton::UpdateIcon); UpdateIcon(isChecked()); } void CollapseButton::UpdateIcon(bool e) { if (e) { setIcon(icon::TriDown); } else { setIcon(icon::TriRight); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/collapsebutton/collapsebutton.h000066400000000000000000000020231370472574300247210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLLAPSEBUTTON_H #define COLLAPSEBUTTON_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class CollapseButton : public QPushButton { Q_OBJECT public: CollapseButton(QWidget* parent = nullptr); private slots: void UpdateIcon(bool e); }; OLIVE_NAMESPACE_EXIT #endif // COLLAPSEBUTTON_H olive-continuous/app/widget/colorbutton/000077500000000000000000000000001370472574300210315ustar00rootroot00000000000000olive-continuous/app/widget/colorbutton/CMakeLists.txt000066400000000000000000000014751370472574300236000ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/colorbutton/colorbutton.h widget/colorbutton/colorbutton.cpp PARENT_SCOPE ) olive-continuous/app/widget/colorbutton/colorbutton.cpp000066400000000000000000000041061370472574300241100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorbutton.h" #include "dialog/color/colordialog.h" OLIVE_NAMESPACE_ENTER ColorButton::ColorButton(ColorManager* color_manager, QWidget *parent) : QPushButton(parent), color_manager_(color_manager), color_processor_(nullptr) { setAutoFillBackground(true); connect(this, &ColorButton::clicked, this, &ColorButton::ShowColorDialog); SetColor(Color(1.0f, 1.0f, 1.0f)); } const ManagedColor &ColorButton::GetColor() const { return color_; } void ColorButton::SetColor(const ManagedColor &c) { color_ = c; color_.set_color_input(color_manager_->GetCompliantColorSpace(color_.color_input())); color_.set_color_output(color_manager_->GetCompliantColorSpace(color_.color_output())); UpdateColor(); } void ColorButton::ShowColorDialog() { ColorDialog cd(color_manager_, color_, this); if (cd.exec() == QDialog::Accepted) { color_ = cd.GetSelectedColor(); UpdateColor(); emit ColorChanged(color_); } } void ColorButton::UpdateColor() { color_processor_ = ColorProcessor::Create(color_manager_, color_.color_input(), color_.color_output()); QColor managed = color_processor_->ConvertColor(color_).toQColor(); setStyleSheet(QStringLiteral("%1--ColorButton {background: %2;}").arg(MACRO_VAL_AS_STR(OLIVE_NAMESPACE), managed.name())); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorbutton/colorbutton.h000066400000000000000000000025351370472574300235610ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORBUTTON_H #define COLORBUTTON_H #include #include "render/colormanager.h" #include "render/managedcolor.h" OLIVE_NAMESPACE_ENTER class ColorButton : public QPushButton { Q_OBJECT public: ColorButton(ColorManager* color_manager, QWidget* parent = nullptr); const ManagedColor& GetColor() const; public slots: void SetColor(const ManagedColor& c); signals: void ColorChanged(const ManagedColor& c); private slots: void ShowColorDialog(); private: void UpdateColor(); ColorManager* color_manager_; ManagedColor color_; ColorProcessorPtr color_processor_; }; OLIVE_NAMESPACE_EXIT #endif // COLORBUTTON_H olive-continuous/app/widget/colorwheel/000077500000000000000000000000001370472574300206225ustar00rootroot00000000000000olive-continuous/app/widget/colorwheel/CMakeLists.txt000066400000000000000000000023371370472574300233670ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/colorwheel/colorgradientwidget.h widget/colorwheel/colorgradientwidget.cpp widget/colorwheel/colorpreviewbox.h widget/colorwheel/colorpreviewbox.cpp widget/colorwheel/colorspacechooser.h widget/colorwheel/colorspacechooser.cpp widget/colorwheel/colorswatchwidget.h widget/colorwheel/colorswatchwidget.cpp widget/colorwheel/colorvalueswidget.h widget/colorwheel/colorvalueswidget.cpp widget/colorwheel/colorwheelwidget.h widget/colorwheel/colorwheelwidget.cpp PARENT_SCOPE ) olive-continuous/app/widget/colorwheel/colorgradientwidget.cpp000066400000000000000000000054131370472574300253710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorgradientwidget.h" #include #include "common/clamp.h" #include "common/lerp.h" #include "node/node.h" OLIVE_NAMESPACE_ENTER ColorGradientWidget::ColorGradientWidget(Qt::Orientation orientation, QWidget *parent) : ColorSwatchWidget(parent), orientation_(orientation), val_(1.0) { } Color ColorGradientWidget::GetColorFromScreenPos(const QPoint &p) const { if (orientation_ == Qt::Horizontal) { return LerpColor(start_, end_, p.x(), width()); } else { return LerpColor(start_, end_, p.y(), height()); } } void ColorGradientWidget::paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); QPainter p(this); int min; int max; if (orientation_ == Qt::Horizontal) { min = height(); max = width(); } else { min = width(); max = height(); } for (int i=0;i(i) / static_cast(max), 0.0f, 1.0f); return Color(lerp(a.red(), b.red(), t), lerp(a.green(), b.green(), t), lerp(a.blue(), b.blue(), t)); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorwheel/colorgradientwidget.h000066400000000000000000000027141370472574300250370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORGRADIENTGLWIDGET_H #define COLORGRADIENTGLWIDGET_H #include "colorswatchwidget.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER class ColorGradientWidget : public ColorSwatchWidget { Q_OBJECT public: ColorGradientWidget(Qt::Orientation orientation, QWidget* parent = nullptr); protected: virtual Color GetColorFromScreenPos(const QPoint& p) const override; virtual void paintEvent(QPaintEvent* e) override; virtual void SelectedColorChangedEvent(const Color& c, bool external) override; private: static Color LerpColor(const Color& a, const Color& b, int i, int max); QPixmap cached_gradient_; Qt::Orientation orientation_; Color start_; Color end_; float val_; }; OLIVE_NAMESPACE_EXIT #endif // COLORGRADIENTGLWIDGET_H olive-continuous/app/widget/colorwheel/colorpreviewbox.cpp000066400000000000000000000031251370472574300245600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorpreviewbox.h" #include OLIVE_NAMESPACE_ENTER ColorPreviewBox::ColorPreviewBox(QWidget *parent) : QWidget(parent), to_ref_processor_(nullptr), to_display_processor_(nullptr) { } void ColorPreviewBox::SetColorProcessor(ColorProcessorPtr to_ref, ColorProcessorPtr to_display) { to_ref_processor_ = to_ref; to_display_processor_ = to_display; update(); } void ColorPreviewBox::SetColor(const Color &c) { color_ = c; update(); } void ColorPreviewBox::paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); QColor c; // Color management if (to_ref_processor_ && to_display_processor_) { c = to_display_processor_->ConvertColor(to_ref_processor_->ConvertColor(color_)).toQColor(); } else { c = color_.toQColor(); } QPainter p(this); p.setPen(Qt::black); p.setBrush(c); p.drawRect(rect().adjusted(0, 0, -1, -1)); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorwheel/colorpreviewbox.h000066400000000000000000000024701370472574300242270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORPREVIEWBOX_H #define COLORPREVIEWBOX_H #include #include "render/color.h" #include "render/colorprocessor.h" OLIVE_NAMESPACE_ENTER class ColorPreviewBox : public QWidget { Q_OBJECT public: ColorPreviewBox(QWidget* parent = nullptr); void SetColorProcessor(ColorProcessorPtr to_ref, ColorProcessorPtr to_display); public slots: void SetColor(const Color& c); protected: virtual void paintEvent(QPaintEvent* e) override; private: Color color_; ColorProcessorPtr to_ref_processor_; ColorProcessorPtr to_display_processor_; }; OLIVE_NAMESPACE_EXIT #endif // COLORPREVIEWBOX_H olive-continuous/app/widget/colorwheel/colorspacechooser.cpp000066400000000000000000000125641370472574300250530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorspacechooser.h" #include #include OLIVE_NAMESPACE_ENTER ColorSpaceChooser::ColorSpaceChooser(ColorManager* color_manager, bool enable_input_field, bool enable_display_fields, QWidget *parent): QGroupBox(parent), color_manager_(color_manager) { QGridLayout* layout = new QGridLayout(this); setTitle(tr("Color Management")); int row = 0; if (enable_input_field) { QString field_text; if (enable_display_fields) { // If the display fields are visible, identify this as the input field_text = tr("Input:"); } else { // Otherwise, this widget will essentially just serve as a list of standard color spaces field_text = tr("Color Space:"); } layout->addWidget(new QLabel(field_text), row, 0); input_combobox_ = new QComboBox(); layout->addWidget(input_combobox_, row, 1); QStringList input_spaces = color_manager->ListAvailableColorspaces(); foreach (const QString& s, input_spaces) { input_combobox_->addItem(s); } if (!color_manager_->GetDefaultInputColorSpace().isEmpty()) { input_combobox_->setCurrentText(color_manager_->GetDefaultInputColorSpace()); } connect(input_combobox_, &QComboBox::currentTextChanged, this, &ColorSpaceChooser::ComboBoxChanged); row++; } else { input_combobox_ = nullptr; } if (enable_display_fields) { { layout->addWidget(new QLabel(tr("Display:")), row, 0); display_combobox_ = new QComboBox(); layout->addWidget(display_combobox_, row, 1); QStringList display_spaces = color_manager->ListAvailableDisplays(); foreach (const QString& s, display_spaces) { display_combobox_->addItem(s); } display_combobox_->setCurrentText(color_manager_->GetDefaultDisplay()); connect(display_combobox_, &QComboBox::currentTextChanged, this, &ColorSpaceChooser::ComboBoxChanged); } row++; { layout->addWidget(new QLabel(tr("View:")), row, 0); view_combobox_ = new QComboBox(); layout->addWidget(view_combobox_, row, 1); UpdateViews(display_combobox_->currentText()); connect(view_combobox_, &QComboBox::currentTextChanged, this, &ColorSpaceChooser::ComboBoxChanged); } row++; { layout->addWidget(new QLabel(tr("Look:")), row, 0); look_combobox_ = new QComboBox(); layout->addWidget(look_combobox_, row, 1); QStringList looks = color_manager->ListAvailableLooks(); look_combobox_->addItem(tr("(None)"), QString()); foreach (const QString& s, looks) { look_combobox_->addItem(s, s); } connect(look_combobox_, &QComboBox::currentTextChanged, this, &ColorSpaceChooser::ComboBoxChanged); } } else { display_combobox_ = nullptr; view_combobox_ = nullptr; look_combobox_ = nullptr; } } QString ColorSpaceChooser::input() const { if (input_combobox_) { return input_combobox_->currentText(); } else { return QString(); } } ColorTransform ColorSpaceChooser::output() const { return ColorTransform(display_combobox_->currentText(), view_combobox_->currentText(), look_combobox_->currentIndex() == 0 ? QString() : look_combobox_->currentText()); } void ColorSpaceChooser::set_input(const QString &s) { input_combobox_->setCurrentText(color_manager_->GetCompliantColorSpace(s)); } void ColorSpaceChooser::set_output(const ColorTransform &out) { ColorTransform compliant = color_manager_->GetCompliantColorSpace(out); display_combobox_->setCurrentText(compliant.display()); view_combobox_->setCurrentText(compliant.view()); if (compliant.look().isEmpty()) { look_combobox_->setCurrentIndex(0); } else { look_combobox_->setCurrentText(compliant.look()); } } void ColorSpaceChooser::UpdateViews(const QString& display) { QString v = view_combobox_->currentText(); view_combobox_->clear(); QStringList views = color_manager_->ListAvailableViews(display); foreach (const QString& s, views) { view_combobox_->addItem(s); } if (views.contains(v)) { // If we have the view we had before, set it again view_combobox_->setCurrentText(v); } else { // Otherwise reset to default view for this display view_combobox_->setCurrentText(color_manager_->GetDefaultView(display)); } } void ColorSpaceChooser::ComboBoxChanged() { if (sender() == display_combobox_) { UpdateViews(display_combobox_->currentText()); } if (input_combobox_) { emit InputColorSpaceChanged(input()); } if (display_combobox_) { emit OutputColorSpaceChanged(output()); } if (input_combobox_ && display_combobox_) { emit ColorSpaceChanged(input(), output()); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorwheel/colorspacechooser.h000066400000000000000000000033171370472574300245140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORSPACECHOOSER_H #define COLORSPACECHOOSER_H #include #include #include "render/colormanager.h" OLIVE_NAMESPACE_ENTER class ColorSpaceChooser : public QGroupBox { Q_OBJECT public: ColorSpaceChooser(ColorManager* color_manager, bool enable_input_field = true, bool enable_display_fields = true, QWidget* parent = nullptr); QString input() const; ColorTransform output() const; void set_input(const QString& s); void set_output(const ColorTransform& out); signals: void InputColorSpaceChanged(const QString& input); void OutputColorSpaceChanged(const ColorTransform& out); void ColorSpaceChanged(const QString& input, const ColorTransform& out); private slots: void UpdateViews(const QString &display); private: ColorManager* color_manager_; QComboBox* input_combobox_; QComboBox* display_combobox_; QComboBox* view_combobox_; QComboBox* look_combobox_; private slots: void ComboBoxChanged(); }; OLIVE_NAMESPACE_EXIT #endif // COLORSPACECHOOSER_H olive-continuous/app/widget/colorwheel/colorswatchwidget.cpp000066400000000000000000000050451370472574300250660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorswatchwidget.h" #include #include "render/backend/opengl/openglrenderfunctions.h" OLIVE_NAMESPACE_ENTER ColorSwatchWidget::ColorSwatchWidget(QWidget *parent) : QWidget(parent), to_linear_processor_(nullptr), to_display_processor_(nullptr) { } const Color &ColorSwatchWidget::GetSelectedColor() const { return selected_color_; } void ColorSwatchWidget::SetColorProcessor(ColorProcessorPtr to_linear, ColorProcessorPtr to_display) { to_linear_processor_ = to_linear; to_display_processor_ = to_display; // Force full update SelectedColorChangedEvent(GetSelectedColor(), true); update(); } void ColorSwatchWidget::SetSelectedColor(const Color &c) { SetSelectedColorInternal(c, true); } void ColorSwatchWidget::mousePressEvent(QMouseEvent *e) { QWidget::mousePressEvent(e); SetSelectedColorInternal(GetColorFromScreenPos(e->pos()), false); emit SelectedColorChanged(GetSelectedColor()); } void ColorSwatchWidget::mouseMoveEvent(QMouseEvent *e) { QWidget::mouseMoveEvent(e); if (e->buttons() & Qt::LeftButton) { SetSelectedColorInternal(GetColorFromScreenPos(e->pos()), false); emit SelectedColorChanged(GetSelectedColor()); } } void ColorSwatchWidget::SelectedColorChangedEvent(const Color &, bool) { } Qt::GlobalColor ColorSwatchWidget::GetUISelectorColor() const { if (GetSelectedColor().GetRoughLuminance() > 0.66) { return Qt::black; } else { return Qt::white; } } Color ColorSwatchWidget::GetManagedColor(const Color &input) const { if (to_linear_processor_ && to_display_processor_) { return to_display_processor_->ConvertColor(to_linear_processor_->ConvertColor(input)); } return input; } void ColorSwatchWidget::SetSelectedColorInternal(const Color &c, bool external) { selected_color_ = c; SelectedColorChangedEvent(c, external); update(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorwheel/colorswatchwidget.h000066400000000000000000000035371370472574300245370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORSWATCHWIDGET_H #define COLORSWATCHWIDGET_H #include #include "render/backend/opengl/openglshader.h" #include "render/color.h" #include "render/colorprocessor.h" OLIVE_NAMESPACE_ENTER class ColorSwatchWidget : public QWidget { Q_OBJECT public: ColorSwatchWidget(QWidget* parent = nullptr); const Color& GetSelectedColor() const; void SetColorProcessor(ColorProcessorPtr to_linear, ColorProcessorPtr to_display); public slots: void SetSelectedColor(const Color& c); signals: void SelectedColorChanged(const Color& c); protected: virtual void mousePressEvent(QMouseEvent* e) override; virtual void mouseMoveEvent(QMouseEvent* e) override; virtual Color GetColorFromScreenPos(const QPoint& p) const = 0; virtual void SelectedColorChangedEvent(const Color& c, bool external); Qt::GlobalColor GetUISelectorColor() const; Color GetManagedColor(const Color& input) const; private: void SetSelectedColorInternal(const Color& c, bool external); Color selected_color_; ColorProcessorPtr to_linear_processor_; ColorProcessorPtr to_display_processor_; }; OLIVE_NAMESPACE_EXIT #endif // COLORSWATCHWIDGET_H olive-continuous/app/widget/colorwheel/colorvalueswidget.cpp000066400000000000000000000131051370472574300250700ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorvalueswidget.h" #include #include OLIVE_NAMESPACE_ENTER ColorValuesWidget::ColorValuesWidget(ColorManager *manager, QWidget *parent) : QWidget(parent), manager_(manager), input_to_ref_(nullptr), ref_to_display_(nullptr), display_to_ref_(nullptr), ref_to_input_(nullptr) { QVBoxLayout* layout = new QVBoxLayout(this); // Create preview box { QHBoxLayout* preview_layout = new QHBoxLayout(); preview_layout->setMargin(0); preview_layout->addWidget(new QLabel(tr("Preview"))); preview_ = new ColorPreviewBox(); preview_->setFixedHeight(fontMetrics().height() * 3 / 2); preview_layout->addWidget(preview_); layout->addLayout(preview_layout); } // Create value tabs { QTabWidget* tabs = new QTabWidget(); input_tab_ = new ColorValuesTab(); tabs->addTab(input_tab_, tr("Input")); connect(input_tab_, &ColorValuesTab::ColorChanged, this, &ColorValuesWidget::UpdateValuesFromInput); connect(input_tab_, &ColorValuesTab::ColorChanged, this, &ColorValuesWidget::ColorChanged); connect(input_tab_, &ColorValuesTab::ColorChanged, preview_, &ColorPreviewBox::SetColor); reference_tab_ = new ColorValuesTab(); tabs->addTab(reference_tab_, tr("Reference")); connect(reference_tab_, &ColorValuesTab::ColorChanged, this, &ColorValuesWidget::UpdateValuesFromRef); display_tab_ = new ColorValuesTab(); tabs->addTab(display_tab_, tr("Display")); connect(display_tab_, &ColorValuesTab::ColorChanged, this, &ColorValuesWidget::UpdateValuesFromDisplay); // FIXME: Display -> Ref temporarily disabled due to OCIO crash (see ColorDialog::ColorSpaceChanged for more info) display_tab_->setEnabled(false); layout->addWidget(tabs); } } Color ColorValuesWidget::GetColor() const { return reference_tab_->GetColor(); } void ColorValuesWidget::SetColorProcessor(ColorProcessorPtr input_to_ref, ColorProcessorPtr ref_to_display, ColorProcessorPtr display_to_ref, ColorProcessorPtr ref_to_input) { input_to_ref_ = input_to_ref; ref_to_display_ = ref_to_display; display_to_ref_ = display_to_ref; ref_to_input_ = ref_to_input; UpdateValuesFromInput(); preview_->SetColorProcessor(input_to_ref_, ref_to_display_); } void ColorValuesWidget::SetColor(const Color &c) { input_tab_->SetColor(c); preview_->SetColor(c); UpdateValuesFromInput(); } void ColorValuesWidget::UpdateValuesFromInput() { UpdateRefFromInput(); UpdateDisplayFromRef(); } void ColorValuesWidget::UpdateValuesFromRef() { UpdateInputFromRef(); UpdateDisplayFromRef(); } void ColorValuesWidget::UpdateValuesFromDisplay() { UpdateRefFromDisplay(); UpdateInputFromRef(); } void ColorValuesWidget::UpdateInputFromRef() { if (ref_to_input_) { input_tab_->SetColor(ref_to_input_->ConvertColor(reference_tab_->GetColor())); } else { input_tab_->SetColor(reference_tab_->GetColor()); } preview_->SetColor(input_tab_->GetColor()); emit ColorChanged(input_tab_->GetColor()); } void ColorValuesWidget::UpdateDisplayFromRef() { if (ref_to_display_) { display_tab_->SetColor(ref_to_display_->ConvertColor(reference_tab_->GetColor())); } else { display_tab_->SetColor(reference_tab_->GetColor()); } } void ColorValuesWidget::UpdateRefFromInput() { if (input_to_ref_) { reference_tab_->SetColor(input_to_ref_->ConvertColor(input_tab_->GetColor())); } else { reference_tab_->SetColor(input_tab_->GetColor()); } } void ColorValuesWidget::UpdateRefFromDisplay() { if (display_to_ref_) { reference_tab_->SetColor(display_to_ref_->ConvertColor(display_tab_->GetColor())); } else { reference_tab_->SetColor(display_tab_->GetColor()); } } ColorValuesTab::ColorValuesTab(QWidget *parent) : QWidget(parent) { QGridLayout* layout = new QGridLayout(this); int row = 0; layout->addWidget(new QLabel(tr("Red")), row, 0); red_slider_ = CreateColorSlider(); layout->addWidget(red_slider_, row, 1); row++; layout->addWidget(new QLabel(tr("Green")), row, 0); green_slider_ = CreateColorSlider(); layout->addWidget(green_slider_, row, 1); row++; layout->addWidget(new QLabel(tr("Blue")), row, 0); blue_slider_ = CreateColorSlider(); layout->addWidget(blue_slider_, row, 1); } Color ColorValuesTab::GetColor() const { return Color(red_slider_->GetValue(), green_slider_->GetValue(), blue_slider_->GetValue()); } void ColorValuesTab::SetColor(const Color &c) { red_slider_->SetValue(c.red()); green_slider_->SetValue(c.green()); blue_slider_->SetValue(c.blue()); } FloatSlider *ColorValuesTab::CreateColorSlider() { FloatSlider* fs = new FloatSlider(); fs->SetDragMultiplier(0.01); fs->SetDecimalPlaces(5); fs->SetLadderElementCount(1); connect(fs, &FloatSlider::ValueChanged, this, &ColorValuesTab::SliderChanged); return fs; } void ColorValuesTab::SliderChanged() { emit ColorChanged(GetColor()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorwheel/colorvalueswidget.h000066400000000000000000000045741370472574300245470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORVALUESWIDGET_H #define COLORVALUESWIDGET_H #include #include "colorpreviewbox.h" #include "render/color.h" #include "render/colormanager.h" #include "widget/slider/floatslider.h" OLIVE_NAMESPACE_ENTER class ColorValuesTab : public QWidget { Q_OBJECT public: ColorValuesTab(QWidget* parent = nullptr); Color GetColor() const; void SetColor(const Color& c); signals: void ColorChanged(const Color& c); private: FloatSlider* CreateColorSlider(); FloatSlider* red_slider_; FloatSlider* green_slider_; FloatSlider* blue_slider_; private slots: void SliderChanged(); }; class ColorValuesWidget : public QWidget { Q_OBJECT public: ColorValuesWidget(ColorManager* manager, QWidget* parent = nullptr); Color GetColor() const; void SetColorProcessor(ColorProcessorPtr input_to_ref, ColorProcessorPtr ref_to_display, ColorProcessorPtr display_to_ref, ColorProcessorPtr ref_to_input); public slots: void SetColor(const Color& c); signals: void ColorChanged(const Color& c); private: void UpdateInputFromRef(); void UpdateDisplayFromRef(); void UpdateRefFromInput(); void UpdateRefFromDisplay(); ColorManager* manager_; ColorPreviewBox* preview_; ColorValuesTab* input_tab_; ColorValuesTab* reference_tab_; ColorValuesTab* display_tab_; ColorProcessorPtr input_to_ref_; ColorProcessorPtr ref_to_display_; ColorProcessorPtr display_to_ref_; ColorProcessorPtr ref_to_input_; private slots: void UpdateValuesFromInput(); void UpdateValuesFromRef(); void UpdateValuesFromDisplay(); }; OLIVE_NAMESPACE_EXIT #endif // COLORVALUESWIDGET_H olive-continuous/app/widget/colorwheel/colorwheelwidget.cpp000066400000000000000000000105751370472574300247050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "colorwheelwidget.h" #include #include #include "common/clamp.h" #include "node/node.h" OLIVE_NAMESPACE_ENTER #define M_180_OVER_PI 57.295791433133264917914229473464 #define M_RADIAN_TO_0_1 0.15915497620314795810531730409296 ColorWheelWidget::ColorWheelWidget(QWidget *parent) : ColorSwatchWidget(parent), val_(1.0f), force_redraw_(false) { } Color ColorWheelWidget::GetColorFromScreenPos(const QPoint &p) const { return GetColorFromTriangle(GetTriangleFromCoords(rect().center(), p)); } void ColorWheelWidget::resizeEvent(QResizeEvent *e) { ColorSwatchWidget::resizeEvent(e); emit DiameterChanged(GetDiameter()); } void ColorWheelWidget::paintEvent(QPaintEvent *e) { ColorSwatchWidget::paintEvent(e); int diameter = GetDiameter(); // Half diameter int radius = diameter / 2; if (cached_wheel_.width() != diameter || force_redraw_) { cached_wheel_ = QPixmap(QSize(diameter, diameter)); cached_wheel_.fill(Qt::transparent); force_redraw_ = false; QPainter p(&cached_wheel_); QPoint center(radius, radius); for (int i=0;i height()) { x = (width() - height()) / 2; y = 0; } else { x = 0; y = (height() - width()) / 2; } p.drawPixmap(x, y, cached_wheel_); // Draw selection // Really rough algorithm for determining whether the selector UI should be white or black int selector_radius = qMax(1, radius / 32); p.setPen(QPen(GetUISelectorColor(), qMax(1, selector_radius / 4))); p.setBrush(Qt::NoBrush); p.drawEllipse(GetCoordsFromColor(GetSelectedColor()), selector_radius, selector_radius); } void ColorWheelWidget::SelectedColorChangedEvent(const Color &c, bool external) { if (external) { force_redraw_ = true; val_ = clamp(c.value(), 0.0f, 1.0f); } } int ColorWheelWidget::GetDiameter() const { return qMin(width(), height()); } qreal ColorWheelWidget::GetRadius() const { return GetDiameter() * 0.5; } ColorWheelWidget::Triangle ColorWheelWidget::GetTriangleFromCoords(const QPoint ¢er, const QPoint &p) const { return GetTriangleFromCoords(center, p.y(), p.x()); } ColorWheelWidget::Triangle ColorWheelWidget::GetTriangleFromCoords(const QPoint ¢er, qreal y, qreal x) const { qreal opposite = y - center.y(); qreal adjacent = x - center.x(); qreal hypotenuse = qSqrt(qPow(adjacent, 2) + qPow(opposite, 2)); return {opposite, adjacent, hypotenuse}; } Color ColorWheelWidget::GetColorFromTriangle(const ColorWheelWidget::Triangle &tri) const { qreal hue = qAtan2(tri.opposite, tri.adjacent) * M_180_OVER_PI + 180.0; qreal sat = qMin(1.0, (tri.hypotenuse / GetRadius())); return Color::fromHsv(hue, sat, val_); } QPoint ColorWheelWidget::GetCoordsFromColor(const Color &c) const { float hue, sat, val; c.toHsv(&hue, &sat, &val); qreal hypotenuse = sat * GetRadius(); qreal radian_angle = (hue - 180.0) / M_180_OVER_PI; qreal opposite = qSin(radian_angle) * hypotenuse; qreal adjacent = qCos(radian_angle) * hypotenuse; QPoint pos(qRound(adjacent), qRound(opposite)); pos += rect().center(); return pos; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/colorwheel/colorwheelwidget.h000066400000000000000000000035561370472574300243530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLORWHEELWIDGET_H #define COLORWHEELWIDGET_H #include #include "colorswatchwidget.h" #include "render/backend/opengl/openglshader.h" #include "render/color.h" OLIVE_NAMESPACE_ENTER class ColorWheelWidget : public ColorSwatchWidget { Q_OBJECT public: ColorWheelWidget(QWidget* parent = nullptr); signals: void DiameterChanged(int radius); protected: virtual Color GetColorFromScreenPos(const QPoint& p) const override; virtual void resizeEvent(QResizeEvent* e) override; virtual void paintEvent(QPaintEvent* e) override; virtual void SelectedColorChangedEvent(const Color& c, bool external) override; private: int GetDiameter() const; qreal GetRadius() const; struct Triangle { qreal opposite; qreal adjacent; qreal hypotenuse; }; Triangle GetTriangleFromCoords(const QPoint ¢er, const QPoint& p) const; Triangle GetTriangleFromCoords(const QPoint ¢er, qreal y, qreal x) const; Color GetColorFromTriangle(const Triangle& tri) const; QPoint GetCoordsFromColor(const Color& c) const; QPixmap cached_wheel_; float val_; bool force_redraw_; }; OLIVE_NAMESPACE_EXIT #endif // COLORWHEELWIDGET_H olive-continuous/app/widget/columnedgridlayout/000077500000000000000000000000001370472574300223715ustar00rootroot00000000000000olive-continuous/app/widget/columnedgridlayout/CMakeLists.txt000066400000000000000000000015311370472574300251310ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/columnedgridlayout/columnedgridlayout.h widget/columnedgridlayout/columnedgridlayout.cpp PARENT_SCOPE ) olive-continuous/app/widget/columnedgridlayout/columnedgridlayout.cpp000066400000000000000000000025751370472574300270200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "columnedgridlayout.h" OLIVE_NAMESPACE_ENTER ColumnedGridLayout::ColumnedGridLayout(QWidget* parent, int maximum_columns) : QGridLayout (parent), maximum_columns_(maximum_columns) { } void ColumnedGridLayout::Add(QWidget *widget) { if (maximum_columns_ > 0) { int row = count() / maximum_columns_; int column = count() % maximum_columns_; addWidget(widget, row, column); } else { addWidget(widget); } } int ColumnedGridLayout::MaximumColumns() const { return maximum_columns_; } void ColumnedGridLayout::SetMaximumColumns(int maximum_columns) { maximum_columns_ = maximum_columns; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/columnedgridlayout/columnedgridlayout.h000066400000000000000000000025501370472574300264560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef COLUMNEDGRIDLAYOUT_H #define COLUMNEDGRIDLAYOUT_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief The ColumnedGridLayout class * * A simple derivative of QGridLayout that provides a automatic row/column layout based on a specified maximum * column count. */ class ColumnedGridLayout : public QGridLayout { Q_OBJECT public: ColumnedGridLayout(QWidget* parent = nullptr, int maximum_columns = 0); void Add(QWidget* widget); int MaximumColumns() const; void SetMaximumColumns(int maximum_columns); private: int maximum_columns_; }; OLIVE_NAMESPACE_EXIT #endif // COLUMNEDGRIDLAYOUT_H olive-continuous/app/widget/curvewidget/000077500000000000000000000000001370472574300210075ustar00rootroot00000000000000olive-continuous/app/widget/curvewidget/CMakeLists.txt000066400000000000000000000017371370472574300235570ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/curvewidget/beziercontrolpointitem.h widget/curvewidget/beziercontrolpointitem.cpp widget/curvewidget/curveview.h widget/curvewidget/curveview.cpp widget/curvewidget/curvewidget.h widget/curvewidget/curvewidget.cpp PARENT_SCOPE ) olive-continuous/app/widget/curvewidget/beziercontrolpointitem.cpp000066400000000000000000000054711370472574300263340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "beziercontrolpointitem.h" #include #include #include #include #include "common/qtutils.h" OLIVE_NAMESPACE_ENTER BezierControlPointItem::BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem *parent) : QGraphicsRectItem(parent), key_(key), mode_(mode), x_scale_(1.0), y_scale_(1.0) { setFlag(QGraphicsItem::ItemIsMovable); connect(key.get(), &NodeKeyframe::TimeChanged, this, &BezierControlPointItem::UpdatePos); if (mode_ == NodeKeyframe::kInHandle) { connect(key.get(), &NodeKeyframe::BezierControlInChanged, this, &BezierControlPointItem::UpdatePos); } else { connect(key.get(), &NodeKeyframe::BezierControlOutChanged, this, &BezierControlPointItem::UpdatePos); } int control_point_size = QFontMetricsWidth(qApp->fontMetrics(), "o"); int half_sz = control_point_size / 2; setRect(-half_sz, -half_sz, control_point_size, control_point_size); } void BezierControlPointItem::SetXScale(double scale) { x_scale_ = scale; UpdatePos(); } void BezierControlPointItem::SetYScale(double scale) { y_scale_ = scale; UpdatePos(); } NodeKeyframePtr BezierControlPointItem::key() const { return key_; } const NodeKeyframe::BezierType &BezierControlPointItem::mode() const { return mode_; } QPointF BezierControlPointItem::GetCorrespondingKeyframeHandle() const { return key_->bezier_control(mode_); } void BezierControlPointItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { if (option->state & QStyle::State_Selected) { painter->setPen(widget->palette().highlight().color()); } else { painter->setPen(widget->palette().text().color()); } painter->drawEllipse(rect()); } void BezierControlPointItem::UpdatePos() { QPointF handle_offset = GetCorrespondingKeyframeHandle(); // Scale handle offset handle_offset.setX(handle_offset.x() * x_scale_); // Flip the Y coordinate because bezier curves are drawn bottom to top handle_offset.setY(-handle_offset.y() * y_scale_); setPos(handle_offset - rect().center()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/curvewidget/beziercontrolpointitem.h000066400000000000000000000032541370472574300257760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef BEZIERCONTROLPOINTITEM_H #define BEZIERCONTROLPOINTITEM_H #include #include "node/keyframe.h" OLIVE_NAMESPACE_ENTER class BezierControlPointItem : public QObject, public QGraphicsRectItem { public: BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem* parent = nullptr); void SetXScale(double scale); void SetYScale(double scale); NodeKeyframePtr key() const; const NodeKeyframe::BezierType& mode() const; QPointF GetCorrespondingKeyframeHandle() const; void SetCorrespondingKeyframeHandle(const QPointF& handle); void SetOpposingKeyframeHandle(const QPointF& handle); protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; private: NodeKeyframePtr key_; NodeKeyframe::BezierType mode_; double x_scale_; double y_scale_; private slots: void UpdatePos(); }; OLIVE_NAMESPACE_EXIT #endif // BEZIERCONTROLPOINTITEM_H olive-continuous/app/widget/curvewidget/curveview.cpp000066400000000000000000000327511370472574300235420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "curveview.h" #include #include #include #include #include "common/qtutils.h" OLIVE_NAMESPACE_ENTER CurveView::CurveView(QWidget *parent) : KeyframeViewBase(parent) { setAlignment(Qt::AlignLeft | Qt::AlignVCenter); setDragMode(RubberBandDrag); setViewportUpdateMode(FullViewportUpdate); SetYAxisEnabled(true); text_padding_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("i")); minimum_grid_space_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("00000")); connect(scene(), &QGraphicsScene::selectionChanged, this, &CurveView::SelectionChanged); } CurveView::~CurveView() { // Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after other members have been destroyed Clear(); } void CurveView::Clear() { KeyframeViewBase::Clear(); foreach (QGraphicsLineItem* line, lines_) { delete line; } lines_.clear(); } void CurveView::SetTrackCount(int count) { track_count_ = count; track_visible_.resize(track_count_); track_visible_.fill(true); } void CurveView::SetTrackVisible(int track, bool visible) { track_visible_[track] = visible; SetKeyframeTrackVisible(track, visible); } void CurveView::drawBackground(QPainter *painter, const QRectF &rect) { if (timebase().isNull()) { return; } painter->setRenderHint(QPainter::Antialiasing); QVector lines; double x_interval = timebase().flipped().toDouble(); double y_interval = 100.0; int x_grid_interval, y_grid_interval; painter->setPen(QPen(palette().window().color(), 1)); do { x_grid_interval = qRound(x_interval * GetScale() * timebase_dbl()); x_interval *= 2.0; } while (x_grid_interval < minimum_grid_space_); do { y_grid_interval = qRound(y_interval * GetYScale()); y_interval *= 2.0; } while (y_grid_interval < minimum_grid_space_); int x_start = qCeil(rect.left() / x_grid_interval) * x_grid_interval; int y_start = qCeil(rect.top() / y_grid_interval) * y_grid_interval; QPointF scene_bottom_left = mapToScene(QPoint(0, qRound(rect.height()))); QPointF scene_top_right = mapToScene(QPoint(qRound(rect.width()), 0)); // Add vertical lines for (int i=x_start;i(i) / GetScale() / timebase_dbl()); painter->drawText(i + text_padding_, qRound(scene_bottom_left.y()) - text_padding_, QString::number(value)); lines.append(QLine(i, qRound(rect.top()), i, qRound(rect.bottom()))); } // Add horizontal lines for (int i=y_start;i(i) / GetYScale()); painter->drawText(qRound(scene_bottom_left.x()) + text_padding_, i - text_padding_, QString::number(-value)); lines.append(QLine(qRound(rect.left()), i, qRound(rect.right()), i)); } // Draw grid painter->drawLines(lines); // Draw keyframe lines for (int j=0;jsetPen(QPen(GetKeyframeColor(j), qMax(1, fontMetrics().height() / 4))); QList keys = GetKeyframesSortedByTime(j); if (!keys.isEmpty()) { QVector keyframe_lines; // Draw straight line leading to first keyframe QPointF first_key_pos = item_map().value(keys.first())->pos(); keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos)); // Draw lines between each keyframe for (int i=1;itype() == NodeKeyframe::kHold) { // Draw a hold keyframe (basically a right angle) keyframe_lines.append(QLineF(before_item->pos().x(), before_item->pos().y(), after_item->pos().x(), before_item->pos().y())); keyframe_lines.append(QLineF(after_item->pos().x(), before_item->pos().y(), after_item->pos().x(), after_item->pos().y())); } else if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) { // Draw a cubic bezier // Cubic beziers have two control points, so we can just use both QPointF before_control_point = before_item->pos() + ScalePoint(before->bezier_control_out()); QPointF after_control_point = after_item->pos() + ScalePoint(after->bezier_control_in()); QPainterPath path; path.moveTo(before_item->pos()); path.cubicTo(before_control_point, after_control_point, after_item->pos()); painter->drawPath(path); } else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) { // Draw a quadratic bezier // Quadratic beziers have a single control point, we just have to determine which it is QPointF key_anchor; QPointF control_point; if (before->type() == NodeKeyframe::kBezier) { key_anchor = before_item->pos(); control_point = before->bezier_control_out(); } else { key_anchor = after_item->pos(); control_point = after->bezier_control_in(); } // Scale control point control_point = key_anchor + ScalePoint(control_point); // Create the path from both keyframes QPainterPath path; path.moveTo(before_item->pos()); path.quadTo(control_point, after_item->pos()); painter->drawPath(path); } else { // Linear to linear keyframe_lines.append(QLineF(before_item->pos(), after_item->pos())); } } // Draw straight line leading from end keyframe QPointF last_key_pos = item_map().value(keys.last())->pos(); keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y()))); painter->drawLines(keyframe_lines); } } // Draw bezier control point lines if (!bezier_control_points_.isEmpty()) { painter->setPen(QPen(palette().text().color(), 1)); QVector bezier_lines; foreach (BezierControlPointItem* item, bezier_control_points_) { // All BezierControlPointItems should be children of a KeyframeViewItem KeyframeViewItem* par = static_cast(item->parentItem()); bezier_lines.append(QLineF(par->pos(), par->pos() + item->pos())); } painter->drawLines(bezier_lines); } } void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key) { disconnect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged); disconnect(key, &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged); } void CurveView::ScaleChangedEvent(const double& scale) { KeyframeViewBase::ScaleChangedEvent(scale); foreach (BezierControlPointItem* item, bezier_control_points_) { item->SetXScale(scale); } } void CurveView::VerticalScaleChangedEvent(double scale) { Q_UNUSED(scale) QMap::const_iterator iterator; for (iterator=item_map().begin();iterator!=item_map().end();iterator++) { SetItemYFromKeyframeValue(iterator.value()->key().get(), iterator.value()); } } void CurveView::wheelEvent(QWheelEvent *event) { if (!HandleZoomFromScroll(event)) { KeyframeViewBase::wheelEvent(event); } } void CurveView::ContextMenuEvent(Menu &m) { m.addSeparator(); // View settings QAction* zoom_fit_action = m.addAction(tr("Zoom to Fit")); connect(zoom_fit_action, &QAction::triggered, this, &CurveView::ZoomToFit); //QAction* reset_zoom_action = m.addAction(tr("Reset Zoom")); } QList CurveView::GetKeyframesSortedByTime(int track) { QList sorted; QMap::const_iterator iterator; for (iterator=item_map().begin();iterator!=item_map().end();iterator++) { NodeKeyframe* key = iterator.key(); if (key->track() != track) { continue; } bool inserted = false; for (int i=0;itime() > key->time()) { sorted.insert(i, key); inserted = true; break; } } if (!inserted) { sorted.append(key); } } return sorted; } qreal CurveView::GetItemYFromKeyframeValue(NodeKeyframe *key) { return GetItemYFromKeyframeValue(key->value().toDouble()); } qreal CurveView::GetItemYFromKeyframeValue(double value) { return -value * GetYScale(); } void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *item) { item->SetOverrideY(GetItemYFromKeyframeValue(key)); } QPointF CurveView::ScalePoint(const QPointF &point) { // Flips Y coordinate because curves are drawn bottom to top return QPointF(point.x() * GetScale(), - point.y() * GetYScale()); } void CurveView::CreateBezierControlPoints(KeyframeViewItem* item) { BezierControlPointItem* bezier_in_pt = new BezierControlPointItem(item->key(), NodeKeyframe::kInHandle, item); bezier_in_pt->SetXScale(GetScale()); bezier_control_points_.append(bezier_in_pt); connect(bezier_in_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection); BezierControlPointItem* bezier_out_pt = new BezierControlPointItem(item->key(), NodeKeyframe::kOutHandle, item); bezier_out_pt->SetXScale(GetScale()); bezier_control_points_.append(bezier_out_pt); connect(bezier_out_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection); } QColor CurveView::GetKeyframeColor(int track) const { if (track_count_) { QColor c; c.setHsvF(static_cast(track) / static_cast(track_count_), 0.5, 1.0); return c; } return palette().text().color(); } void CurveView::KeyframeValueChanged() { NodeKeyframe* key = static_cast(sender()); KeyframeViewItem* item = item_map().value(key); SetItemYFromKeyframeValue(key, item); } void CurveView::KeyframeTypeChanged() { NodeKeyframe* key = static_cast(sender()); KeyframeViewItem* item = item_map().value(key); if (item->isSelected()) { item->setSelected(false); item->setSelected(true); } } void CurveView::SelectionChanged() { // Clear current bezier handles foreach (BezierControlPointItem* item, bezier_control_points_) { delete item; } bezier_control_points_.clear(); QList selected = scene()->selectedItems(); foreach (QGraphicsItem* item, selected) { KeyframeViewItem* this_item = static_cast(item); if (this_item->key()->type() == NodeKeyframe::kBezier) { CreateBezierControlPoints(this_item); } } } void CurveView::BezierControlPointDestroyed() { BezierControlPointItem* item = static_cast(sender()); bezier_control_points_.removeOne(item); } void CurveView::ZoomToFit() { if (item_map().isEmpty()) { // Prevent scaling to DBL_MIN/DBL_MAX return; } QMap::const_iterator i; rational min_time = RATIONAL_MAX; rational max_time = RATIONAL_MIN; double min_val = DBL_MAX; double max_val = DBL_MIN; for (i=item_map().constBegin(); i!=item_map().constEnd(); i++) { rational transformed_time = GetAdjustedTime(i.key()->parent()->parentNode(), GetTimeTarget(), i.key()->time(), NodeParam::kOutput); min_time = qMin(transformed_time, min_time); max_time = qMax(transformed_time, max_time); min_val = qMin(i.key()->value().toDouble(), min_val); max_val = qMax(i.key()->value().toDouble(), max_val); } double time_range = max_time.toDouble() - min_time.toDouble(); double new_x_scale = CalculateScaleFromDimensions(this->width(), time_range); double new_y_scale = CalculateScaleFromDimensions(this->height(), max_val - min_val); emit ScaleChanged(new_x_scale); SetYScale(new_y_scale); horizontalScrollBar()->setValue(TimeToScene(min_time) - CalculatePaddingFromDimensionScale(this->width())); verticalScrollBar()->setValue(GetItemYFromKeyframeValue(max_val) - CalculatePaddingFromDimensionScale(this->height())); } void CurveView::AddKeyframe(NodeKeyframePtr key) { KeyframeViewItem* item = AddKeyframeInternal(key); SetItemYFromKeyframeValue(key.get(), item); item->SetOverrideBrush(GetKeyframeColor(key->track())); connect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged); connect(key.get(), &NodeKeyframe::TypeChanged, this, &CurveView::KeyframeTypeChanged); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/curvewidget/curveview.h000066400000000000000000000046661370472574300232130ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CURVEVIEW_H #define CURVEVIEW_H #include "beziercontrolpointitem.h" #include "node/keyframe.h" #include "widget/keyframeview/keyframeview.h" #include "widget/keyframeview/keyframeviewitem.h" OLIVE_NAMESPACE_ENTER class CurveView : public KeyframeViewBase { Q_OBJECT public: CurveView(QWidget* parent = nullptr); virtual ~CurveView() override; virtual void Clear() override; void SetTrackCount(int count); void SetTrackVisible(int track, bool visible); public slots: void AddKeyframe(NodeKeyframePtr key); void ZoomToFit(); protected: virtual void drawBackground(QPainter* painter, const QRectF& rect) override; virtual void KeyframeAboutToBeRemoved(NodeKeyframe *key) override; virtual void ScaleChangedEvent(const double &scale) override; virtual void VerticalScaleChangedEvent(double scale) override; virtual void wheelEvent(QWheelEvent* event) override; virtual void ContextMenuEvent(Menu &m) override; private: QList GetKeyframesSortedByTime(int track); qreal GetItemYFromKeyframeValue(NodeKeyframe* key); qreal GetItemYFromKeyframeValue(double value); void SetItemYFromKeyframeValue(NodeKeyframe* key, KeyframeViewItem* item); QPointF ScalePoint(const QPointF& point); void AdjustLines(); void CreateBezierControlPoints(KeyframeViewItem *item); QColor GetKeyframeColor(int track) const; int text_padding_; int minimum_grid_space_; QList lines_; QList bezier_control_points_; QVector track_visible_; int track_count_; private slots: void KeyframeValueChanged(); void KeyframeTypeChanged(); void SelectionChanged(); void BezierControlPointDestroyed(); }; OLIVE_NAMESPACE_EXIT #endif // CURVEVIEW_H olive-continuous/app/widget/curvewidget/curvewidget.cpp000066400000000000000000000232061370472574300240460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "curvewidget.h" #include #include #include #include #include "core.h" #include "common/qtutils.h" #include "common/timecodefunctions.h" #include "node/node.h" #include "widget/keyframeview/keyframeviewundo.h" OLIVE_NAMESPACE_ENTER CurveWidget::CurveWidget(QWidget *parent) : TimeBasedWidget(parent), input_(nullptr), bridge_(nullptr) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); QHBoxLayout* top_controls = new QHBoxLayout(); key_control_ = new NodeParamViewKeyframeControl(false); connect(key_control_, &NodeParamViewKeyframeControl::RequestSetTime, this, &CurveWidget::KeyControlRequestedTimeChanged); top_controls->addWidget(key_control_); top_controls->addStretch(); linear_button_ = new QPushButton(tr("Linear")); linear_button_->setCheckable(true); linear_button_->setEnabled(false); top_controls->addWidget(linear_button_); connect(linear_button_, &QPushButton::clicked, this, &CurveWidget::KeyframeTypeButtonTriggered); bezier_button_ = new QPushButton(tr("Bezier")); bezier_button_->setCheckable(true); bezier_button_->setEnabled(false); top_controls->addWidget(bezier_button_); connect(bezier_button_, &QPushButton::clicked, this, &CurveWidget::KeyframeTypeButtonTriggered); hold_button_ = new QPushButton(tr("Hold")); hold_button_->setCheckable(true); hold_button_->setEnabled(false); top_controls->addWidget(hold_button_); connect(hold_button_, &QPushButton::clicked, this, &CurveWidget::KeyframeTypeButtonTriggered); layout->addLayout(top_controls); // We use a separate layout for the ruler+view combination so that there's no spacing between them QVBoxLayout* ruler_view_layout = new QVBoxLayout(); ruler_view_layout->setMargin(0); ruler_view_layout->setSpacing(0); ruler_view_layout->addWidget(ruler()); view_ = new CurveView(); connect(view_, &CurveView::RequestCenterScrollOnPlayhead, this, &CurveWidget::CenterScrollOnPlayhead); ConnectTimelineView(view_); ruler_view_layout->addWidget(view_); layout->addLayout(ruler_view_layout); // Connect ruler and view together connect(view_, &CurveView::TimeChanged, this, &CurveWidget::SetTimeAndSignal); connect(view_->scene(), &QGraphicsScene::selectionChanged, this, &CurveWidget::SelectionChanged); connect(view_, &CurveView::ScaleChanged, this, &CurveWidget::SetScale); // TimeBasedWidget's scrollbar has extra functionality that we can take advantage of view_->setHorizontalScrollBar(scrollbar()); connect(view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); widget_bridge_layout_ = new QHBoxLayout(); widget_bridge_layout_->addStretch(); input_label_ = new QLabel(); widget_bridge_layout_->addWidget(input_label_); widget_bridge_layout_->addStretch(); layout->addLayout(widget_bridge_layout_); SetScale(120.0); } CurveWidget::~CurveWidget() { // Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after other members have been destroyed view_->Clear(); } NodeInput *CurveWidget::GetInput() const { return input_; } void CurveWidget::SetInput(NodeInput *input) { if (bridge_) { foreach (QWidget* bridge_widget, bridge_->widgets()) { bridge_widget->deleteLater(); } bridge_->deleteLater(); bridge_ = nullptr; } foreach (QCheckBox* box, checkboxes_) { box->deleteLater(); } checkboxes_.clear(); if (input_) { disconnect(input_, &NodeInput::KeyframeAdded, view_, &CurveView::AddKeyframe); disconnect(input_, &NodeInput::KeyframeRemoved, view_, &CurveView::RemoveKeyframe); } view_->Clear(); input_ = input; key_control_->SetInput(input_); if (input_) { view_->SetTrackCount(input_->get_number_of_keyframe_tracks()); bridge_ = new NodeParamViewWidgetBridge(input_, this); bridge_->SetTimeTarget(GetTimeTarget()); for (int i=0;iwidgets().size();i++) { // Insert between two stretches to center the widget QCheckBox* checkbox = new QCheckBox(); checkbox->setChecked(true); widget_bridge_layout_->insertWidget(2 + i*2, checkbox); checkboxes_.append(checkbox); connect(checkbox, &QCheckBox::clicked, this, [this](bool e){ view_->SetTrackVisible(checkboxes_.indexOf(static_cast(sender())), e); }); widget_bridge_layout_->insertWidget(2 + i*2 + 1, bridge_->widgets().at(i)); } connect(input_, &NodeInput::KeyframeAdded, view_, &CurveView::AddKeyframe); connect(input_, &NodeInput::KeyframeRemoved, view_, &CurveView::RemoveKeyframe); foreach (const NodeInput::KeyframeTrack& track, input_->keyframe_tracks()) { foreach (NodeKeyframePtr key, track) { view_->AddKeyframe(key); } } } UpdateInputLabel(); QMetaObject::invokeMethod(view_, "ZoomToFit", Qt::QueuedConnection); } const double &CurveWidget::GetVerticalScale() { return view_->GetYScale(); } void CurveWidget::SetVerticalScale(const double &vscale) { view_->SetYScale(vscale); } void CurveWidget::DeleteSelected() { view_->DeleteSelected(); } void CurveWidget::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { UpdateInputLabel(); } QWidget::changeEvent(e); } void CurveWidget::TimeChangedEvent(const int64_t ×tamp) { TimeBasedWidget::TimeChangedEvent(timestamp); view_->SetTime(timestamp); UpdateBridgeTime(timestamp); } void CurveWidget::TimebaseChangedEvent(const rational &timebase) { TimeBasedWidget::TimebaseChangedEvent(timebase); view_->SetTimebase(timebase); } void CurveWidget::ScaleChangedEvent(const double &scale) { TimeBasedWidget::ScaleChangedEvent(scale); view_->SetScale(scale); } void CurveWidget::TimeTargetChangedEvent(Node *target) { key_control_->SetTimeTarget(target); view_->SetTimeTarget(target); if (bridge_) { bridge_->SetTimeTarget(target); } } void CurveWidget::ConnectedNodeChanged(ViewerOutput *n) { SetTimeTarget(n); } void CurveWidget::UpdateInputLabel() { if (input_) { input_label_->setText(QStringLiteral("%1 :: %2:").arg(input_->parentNode()->Name(), input_->name())); } else { input_label_->clear(); } } void CurveWidget::SetKeyframeButtonEnabled(bool enable) { linear_button_->setEnabled(enable); bezier_button_->setEnabled(enable); hold_button_->setEnabled(enable); } void CurveWidget::SetKeyframeButtonChecked(bool checked) { linear_button_->setChecked(checked); bezier_button_->setChecked(checked); hold_button_->setChecked(checked); } void CurveWidget::SetKeyframeButtonCheckedFromType(NodeKeyframe::Type type) { linear_button_->setChecked(type == NodeKeyframe::kLinear); bezier_button_->setChecked(type == NodeKeyframe::kBezier); hold_button_->setChecked(type == NodeKeyframe::kHold); } void CurveWidget::UpdateBridgeTime(const int64_t ×tamp) { if (!input_) { return; } rational time = Timecode::timestamp_to_time(timestamp, view_->timebase()); bridge_->SetTime(time); key_control_->SetTime(time); } void CurveWidget::SelectionChanged() { QList selected = view_->scene()->selectedItems(); SetKeyframeButtonChecked(false); SetKeyframeButtonEnabled(!selected.isEmpty()); if (!selected.isEmpty()) { bool all_same_type = true; NodeKeyframe::Type type = static_cast(selected.first())->key()->type(); for (int i=1;i(selected.at(i-1)); KeyframeViewItem* this_item = static_cast(selected.at(i)); if (prev_item->key()->type() != this_item->key()->type()) { all_same_type = false; break; } } if (all_same_type) { SetKeyframeButtonCheckedFromType(type); } } } void CurveWidget::KeyframeTypeButtonTriggered(bool checked) { QPushButton* key_btn = static_cast(sender()); if (!checked) { // Keyframe buttons cannot be checked off, we undo this action here key_btn->setChecked(true); return; } // Get selected items and do nothing if there are none QList selected = view_->scene()->selectedItems(); if (selected.isEmpty()) { return; } // Set all selected keyframes to this type NodeKeyframe::Type new_type; // Determine which type to set if (key_btn == bezier_button_) { new_type = NodeKeyframe::kBezier; } else if (key_btn == hold_button_) { new_type = NodeKeyframe::kHold; } else { new_type = NodeKeyframe::kLinear; } // Ensure only the appropriate button is checked SetKeyframeButtonCheckedFromType(new_type); QUndoCommand* command = new QUndoCommand(); foreach (QGraphicsItem* item, selected) { KeyframeViewItem* key_item = static_cast(item); new KeyframeSetTypeCommand(key_item->key(), new_type, command); } Core::instance()->undo_stack()->push(command); } void CurveWidget::KeyControlRequestedTimeChanged(const rational &time) { SetTimeAndSignal(Timecode::time_to_timestamp(time, view_->timebase())); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/curvewidget/curvewidget.h000066400000000000000000000050121370472574300235060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef CURVEWIDGET_H #define CURVEWIDGET_H #include #include #include #include #include "curveview.h" #include "node/input.h" #include "widget/nodeparamview/nodeparamviewkeyframecontrol.h" #include "widget/nodeparamview/nodeparamviewwidgetbridge.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER class CurveWidget : public TimeBasedWidget, public TimeTargetObject { Q_OBJECT public: CurveWidget(QWidget* parent = nullptr); virtual ~CurveWidget() override; NodeInput* GetInput() const; void SetInput(NodeInput* input); const double& GetVerticalScale(); void SetVerticalScale(const double& vscale); void DeleteSelected(); protected: virtual void changeEvent(QEvent *) override; virtual void TimeChangedEvent(const int64_t &) override; virtual void TimebaseChangedEvent(const rational &) override; virtual void ScaleChangedEvent(const double &) override; virtual void TimeTargetChangedEvent(Node* target) override; virtual void ConnectedNodeChanged(ViewerOutput* n) override; private: void UpdateInputLabel(); void SetKeyframeButtonEnabled(bool enable); void SetKeyframeButtonChecked(bool checked); void SetKeyframeButtonCheckedFromType(NodeKeyframe::Type type); void UpdateBridgeTime(const int64_t& timestamp); QPushButton* linear_button_; QPushButton* bezier_button_; QPushButton* hold_button_; CurveView* view_; NodeInput* input_; QLabel* input_label_; QHBoxLayout* widget_bridge_layout_; NodeParamViewWidgetBridge* bridge_; NodeParamViewKeyframeControl* key_control_; QList checkboxes_; private slots: void SelectionChanged(); void KeyframeTypeButtonTriggered(bool checked); void KeyControlRequestedTimeChanged(const rational& time); }; OLIVE_NAMESPACE_EXIT #endif // CURVEWIDGET_H olive-continuous/app/widget/flowlayout/000077500000000000000000000000001370472574300206645ustar00rootroot00000000000000olive-continuous/app/widget/flowlayout/CMakeLists.txt000066400000000000000000000014711370472574300234270ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/flowlayout/flowlayout.h widget/flowlayout/flowlayout.cpp PARENT_SCOPE ) olive-continuous/app/widget/flowlayout/flowlayout.cpp000066400000000000000000000137641370472574300236100ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "flowlayout.h" FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) { setContentsMargins(margin, margin, margin, margin); } FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing) : m_hSpace(hSpacing), m_vSpace(vSpacing) { setContentsMargins(margin, margin, margin, margin); } FlowLayout::~FlowLayout() { QLayoutItem *item; while ((item = takeAt(0))) delete item; } void FlowLayout::addItem(QLayoutItem *item) { itemList.append(item); } int FlowLayout::horizontalSpacing() const { if (m_hSpace >= 0) { return m_hSpace; } else { return smartSpacing(QStyle::PM_LayoutHorizontalSpacing); } } int FlowLayout::verticalSpacing() const { if (m_vSpace >= 0) { return m_vSpace; } else { return smartSpacing(QStyle::PM_LayoutVerticalSpacing); } } int FlowLayout::count() const { return itemList.size(); } QLayoutItem *FlowLayout::itemAt(int index) const { return itemList.value(index); } QLayoutItem *FlowLayout::takeAt(int index) { if (index >= 0 && index < itemList.size()) return itemList.takeAt(index); else return 0; } Qt::Orientations FlowLayout::expandingDirections() const { return Qt::Horizontal | Qt::Vertical; } bool FlowLayout::hasHeightForWidth() const { return true; } int FlowLayout::heightForWidth(int width) const { int height = doLayout(QRect(0, 0, width, 0), true); return height; } void FlowLayout::setGeometry(const QRect &rect) { QLayout::setGeometry(rect); doLayout(rect, false); } QSize FlowLayout::sizeHint() const { return minimumSize(); } QSize FlowLayout::minimumSize() const { QSize size; QLayoutItem *item; foreach (item, itemList) size = size.expandedTo(item->minimumSize()); size += QSize(2*margin(), 2*margin()); return size; } int FlowLayout::doLayout(const QRect &rect, bool testOnly) const { int left, top, right, bottom; getContentsMargins(&left, &top, &right, &bottom); QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); int x = effectiveRect.x(); int y = effectiveRect.y(); int lineHeight = 0; QLayoutItem *item; foreach (item, itemList) { QWidget *wid = item->widget(); int spaceX = horizontalSpacing(); if (spaceX == -1) spaceX = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal); int spaceY = verticalSpacing(); if (spaceY == -1) spaceY = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); int nextX = x + item->sizeHint().width() + spaceX; if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { x = effectiveRect.x(); y = y + lineHeight + spaceY; nextX = x + item->sizeHint().width() + spaceX; lineHeight = 0; } if (!testOnly) item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); x = nextX; lineHeight = qMax(lineHeight, item->sizeHint().height()); } return y + lineHeight - rect.y() + bottom; } int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const { QObject *parent = this->parent(); if (!parent) { return -1; } else if (parent->isWidgetType()) { QWidget *pw = static_cast(parent); return pw->style()->pixelMetric(pm, 0, pw); } else { return static_cast(parent)->spacing(); } } olive-continuous/app/widget/flowlayout/flowlayout.h000066400000000000000000000067121370472574300232500ustar00rootroot00000000000000/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef FLOWLAYOUT_H #define FLOWLAYOUT_H #include #include #include class FlowLayout : public QLayout { public: explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1); explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); ~FlowLayout(); void addItem(QLayoutItem *item) override; int horizontalSpacing() const; int verticalSpacing() const; Qt::Orientations expandingDirections() const override; bool hasHeightForWidth() const override; int heightForWidth(int) const override; int count() const override; QLayoutItem *itemAt(int index) const override; QSize minimumSize() const override; void setGeometry(const QRect &rect) override; QSize sizeHint() const override; QLayoutItem *takeAt(int index) override; private: int doLayout(const QRect &rect, bool testOnly) const; int smartSpacing(QStyle::PixelMetric pm) const; QList itemList; int m_hSpace; int m_vSpace; }; #endif // FLOWLAYOUT_H olive-continuous/app/widget/focusablelineedit/000077500000000000000000000000001370472574300221405ustar00rootroot00000000000000olive-continuous/app/widget/focusablelineedit/CMakeLists.txt000066400000000000000000000015251370472574300247030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/focusablelineedit/focusablelineedit.h widget/focusablelineedit/focusablelineedit.cpp PARENT_SCOPE ) olive-continuous/app/widget/focusablelineedit/focusablelineedit.cpp000066400000000000000000000023601370472574300263260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "focusablelineedit.h" #include OLIVE_NAMESPACE_ENTER FocusableLineEdit::FocusableLineEdit(QWidget *parent) : QLineEdit(parent) { } void FocusableLineEdit::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Return: case Qt::Key_Enter: emit Confirmed(); break; case Qt::Key_Escape: emit Cancelled(); break; default: QLineEdit::keyPressEvent(e); } } void FocusableLineEdit::focusOutEvent(QFocusEvent *e) { QLineEdit::focusOutEvent(e); emit Confirmed(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/focusablelineedit/focusablelineedit.h000066400000000000000000000022051370472574300257710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SLIDERLINEEDIT_H #define SLIDERLINEEDIT_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class FocusableLineEdit : public QLineEdit { Q_OBJECT public: FocusableLineEdit(QWidget* parent = nullptr); signals: void Confirmed(); void Cancelled(); protected: void keyPressEvent(QKeyEvent *) override; void focusOutEvent(QFocusEvent *) override; }; OLIVE_NAMESPACE_EXIT #endif // SLIDERLINEEDIT_H olive-continuous/app/widget/footagecombobox/000077500000000000000000000000001370472574300216345ustar00rootroot00000000000000olive-continuous/app/widget/footagecombobox/CMakeLists.txt000066400000000000000000000015151370472574300243760ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/footagecombobox/footagecombobox.h widget/footagecombobox/footagecombobox.cpp PARENT_SCOPE ) olive-continuous/app/widget/footagecombobox/footagecombobox.cpp000066400000000000000000000057021370472574300255210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "footagecombobox.h" #include #include #include "ui/icons/icons.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER FootageComboBox::FootageComboBox(QWidget *parent) : QComboBox(parent), root_(nullptr), footage_(nullptr), only_show_ready_footage_(true) { } void FootageComboBox::showPopup() { if (root_ == nullptr || root_->child_count() == 0) { return; } Menu menu; menu.setMinimumWidth(width()); TraverseFolder(root_, &menu); QAction* selected = menu.exec(parentWidget()->mapToGlobal(pos())); if (selected != nullptr) { SetFootage(selected->data().value()); emit FootageChanged(footage_); } } void FootageComboBox::SetRoot(const Folder *p) { root_ = p; clear(); } void FootageComboBox::SetOnlyShowReadyFootage(bool e) { only_show_ready_footage_ = e; } StreamPtr FootageComboBox::SelectedFootage() { return footage_; } void FootageComboBox::SetFootage(StreamPtr f) { // Remove existing single item used to show the footage name footage_ = f; UpdateText(); } void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m) { for (int i=0;ichild_count();i++) { Item* child = f->child(i); if (child->CanHaveChildren()) { Menu* sub = new Menu(child->name(), m); m->addMenu(sub); TraverseFolder(static_cast(child), sub); } else if (child->type() == Item::kFootage) { Footage* footage = static_cast(child); if (!only_show_ready_footage_ || footage->status() == Footage::kReady) { Menu* stream_menu = new Menu(footage->name(), m); m->addMenu(stream_menu); foreach (StreamPtr stream, footage->streams()) { QAction* stream_action = stream_menu->addAction(FootageToString(stream.get())); stream_action->setData(QVariant::fromValue(stream)); stream_action->setIcon(Stream::IconFromType(stream->type())); } } } } } void FootageComboBox::UpdateText() { // Use combobox functions to show the footage name clear(); if (footage_) { // Use combobox functions to show the footage name addItem(FootageToString(footage_.get())); } } QString FootageComboBox::FootageToString(Stream *f) { return f->description(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/footagecombobox/footagecombobox.h000066400000000000000000000027441370472574300251710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOOTAGECOMBOBOX_H #define FOOTAGECOMBOBOX_H #include #include #include "project/item/footage/footage.h" #include "project/project.h" OLIVE_NAMESPACE_ENTER class FootageComboBox : public QComboBox { Q_OBJECT public: FootageComboBox(QWidget* parent = nullptr); virtual void showPopup() override; void SetRoot(const Folder *p); void SetOnlyShowReadyFootage(bool e); StreamPtr SelectedFootage(); public slots: void SetFootage(StreamPtr f); signals: void FootageChanged(StreamPtr f); private: void TraverseFolder(const Folder *f, QMenu* m); void UpdateText(); static QString FootageToString(Stream* f); const Folder* root_; StreamPtr footage_; bool only_show_ready_footage_; }; OLIVE_NAMESPACE_EXIT #endif // FOOTAGECOMBOBOX_H olive-continuous/app/widget/keyframeview/000077500000000000000000000000001370472574300211555ustar00rootroot00000000000000olive-continuous/app/widget/keyframeview/CMakeLists.txt000066400000000000000000000020751370472574300237210ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/keyframeview/keyframeview.h widget/keyframeview/keyframeview.cpp widget/keyframeview/keyframeviewbase.h widget/keyframeview/keyframeviewbase.cpp widget/keyframeview/keyframeviewitem.h widget/keyframeview/keyframeviewitem.cpp widget/keyframeview/keyframeviewundo.h widget/keyframeview/keyframeviewundo.cpp PARENT_SCOPE ) olive-continuous/app/widget/keyframeview/keyframeview.cpp000066400000000000000000000026361370472574300243660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keyframeview.h" OLIVE_NAMESPACE_ENTER KeyframeView::KeyframeView(QWidget *parent) : KeyframeViewBase(parent), max_scroll_(0) { setAlignment(Qt::AlignLeft | Qt::AlignTop); } void KeyframeView::wheelEvent(QWheelEvent *event) { if (!HandleZoomFromScroll(event)) { KeyframeViewBase::wheelEvent(event); } } void KeyframeView::SceneRectUpdateEvent(QRectF &rect) { rect.setY(0); rect.setHeight(max_scroll_); } void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y) { QPoint global_pt(0, y); QPoint local_pt = mapFromGlobal(global_pt); QPointF scene_pt = mapToScene(local_pt); KeyframeViewItem* item = AddKeyframeInternal(key); item->SetOverrideY(scene_pt.y()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/keyframeview/keyframeview.h000066400000000000000000000023441370472574300240270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef KEYFRAMEVIEW_H #define KEYFRAMEVIEW_H #include "keyframeviewbase.h" OLIVE_NAMESPACE_ENTER class KeyframeView : public KeyframeViewBase { Q_OBJECT public: KeyframeView(QWidget* parent = nullptr); void SetMaxScroll(int i) { max_scroll_ = i; } protected: virtual void wheelEvent(QWheelEvent* event) override; virtual void SceneRectUpdateEvent(QRectF& rect) override; public slots: void AddKeyframe(NodeKeyframePtr key, int y); private: int max_scroll_; }; OLIVE_NAMESPACE_EXIT #endif // KEYFRAMEVIEW_H olive-continuous/app/widget/keyframeview/keyframeviewbase.cpp000066400000000000000000000421031370472574300252120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keyframeviewbase.h" #include #include #include "dialog/keyframeproperties/keyframeproperties.h" #include "keyframeviewundo.h" #include "node/node.h" #include "widget/menu/menu.h" #include "widget/menu/menushared.h" #include "widget/nodeparamview/nodeparamviewundo.h" OLIVE_NAMESPACE_ENTER KeyframeViewBase::KeyframeViewBase(QWidget *parent) : TimelineViewBase(parent), dragging_bezier_point_(nullptr), currently_autoselecting_(false) { SetDefaultDragMode(RubberBandDrag); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &KeyframeViewBase::customContextMenuRequested, this, &KeyframeViewBase::ShowContextMenu); connect(scene(), &QGraphicsScene::selectionChanged, this, &KeyframeViewBase::AutoSelectKeyTimeNeighbors); } void KeyframeViewBase::Clear() { QMap::iterator iterator; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { delete iterator.value(); } item_map_.clear(); } void KeyframeViewBase::DeleteSelected() { QUndoCommand* command = new QUndoCommand(); QMap::const_iterator i; for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) { if (i.value()->isSelected()) { NodeInput* input_parent = i.key()->parent(); new NodeParamRemoveKeyframeCommand(input_parent, input_parent->get_keyframe_shared_ptr_from_raw(i.key()), command); } } Core::instance()->undo_stack()->pushIfHasChildren(command); } void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key) { KeyframeAboutToBeRemoved(key.get()); delete item_map_.take(key.get()); } KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key) { KeyframeViewItem* item = item_map_.value(key.get()); if (!item) { item = new KeyframeViewItem(key); item->SetTimeTarget(GetTimeTarget()); item->SetScale(GetScale()); item_map_.insert(key.get(), item); scene()->addItem(item); if (hidden_tracks_.contains(key->track())) { item->setVisible(false); } } return item; } void KeyframeViewBase::mousePressEvent(QMouseEvent *event) { if (HandPress(event) || PlayheadPress(event)) { return; } active_tool_ = Core::instance()->tool(); if (event->button() == Qt::LeftButton) { QGraphicsView::mousePressEvent(event); if (active_tool_ == Tool::kPointer) { QGraphicsItem* item_under_cursor = itemAt(event->pos()); if (item_under_cursor) { drag_start_ = event->pos(); // Determine what type of item is under the cursor dragging_bezier_point_ = dynamic_cast(item_under_cursor); if (dragging_bezier_point_) { dragging_bezier_point_start_ = dragging_bezier_point_->GetCorrespondingKeyframeHandle(); dragging_bezier_point_opposing_start_ = dragging_bezier_point_->key()->bezier_control(NodeKeyframe::get_opposing_bezier_type(dragging_bezier_point_->mode())); } else { QList selected_items = scene()->selectedItems(); selected_keys_.resize(selected_items.size()); for (int i=0;i(selected_items.at(i)); selected_keys_.replace(i, {key, key->x(), GetAdjustedTime(key->key()->parent()->parentNode(), GetTimeTarget(), key->key()->time(), NodeParam::kOutput), key->key()->value().toDouble()}); } } } } } } void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event) { if (HandMove(event) || PlayheadMove(event)) { return; } if (event->buttons() & Qt::LeftButton) { QGraphicsView::mouseMoveEvent(event); if (active_tool_ == Tool::kPointer) { // Calculate cursor difference and scale it QPointF mouse_diff_scaled = GetScaledCursorPos(event->pos() - drag_start_); if (dragging_bezier_point_) { ProcessBezierDrag(mouse_diff_scaled, !(event->modifiers() & Qt::ControlModifier), false); } else if (!selected_keys_.isEmpty()) { foreach (const KeyframeItemAndTime& keypair, selected_keys_) { //NodeInput* input_parent = keypair.key->key()->parent(); //input_parent->blockSignals(true); rational node_time = GetAdjustedTime(GetTimeTarget(), keypair.key->key()->parent()->parentNode(), CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()), NodeParam::kInput); keypair.key->key()->set_time(node_time); if (IsYAxisEnabled()) { keypair.key->key()->set_value(keypair.value - mouse_diff_scaled.y()); } // We emit a custom value changed signal while the keyframe is being dragged so only the currently viewed // frame gets rendered in this time //input_parent->blockSignals(false); //input_parent->parentNode()->InvalidateVisible(input_parent, input_parent); } } } } } void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event) { if (HandRelease(event) || PlayheadRelease(event)) { return; } if (event->button() == Qt::LeftButton) { QGraphicsView::mouseReleaseEvent(event); if (active_tool_ == Tool::kPointer) { QPoint mouse_diff = event->pos() - drag_start_; QPointF mouse_diff_scaled = GetScaledCursorPos(mouse_diff); if (!mouse_diff.isNull()) { if (dragging_bezier_point_) { ProcessBezierDrag(mouse_diff_scaled, !(event->modifiers() & Qt::ControlModifier), true); dragging_bezier_point_ = nullptr; } else if (!selected_keys_.isEmpty()) { QUndoCommand* command = new QUndoCommand(); foreach (const KeyframeItemAndTime& keypair, selected_keys_) { KeyframeViewItem* item = keypair.key; keypair.key->key()->parent()->blockSignals(true); // Calculate the new time for this keyframe rational node_time = GetAdjustedTime(GetTimeTarget(), keypair.key->key()->parent()->parentNode(), CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()), NodeParam::kInput); // Commit movement // Since we overrode the cache signalling while dragging, we simulate here precisely the change that // occurred by first setting the keyframe to its original position, and then letting the input handle // the signalling once the undo command is pushed. item->key()->set_time(keypair.time); new NodeParamSetKeyframeTimeCommand(item->key(), node_time, keypair.time, command); // Commit value if we're setting a value if (IsYAxisEnabled()) { item->key()->set_value(keypair.value); new NodeParamSetKeyframeValueCommand(item->key(), keypair.value - mouse_diff_scaled.y(), keypair.value, command); } keypair.key->key()->parent()->blockSignals(false); } Core::instance()->undo_stack()->push(command); } } selected_keys_.clear(); } } } void KeyframeViewBase::ScaleChangedEvent(const double &scale) { TimelineViewBase::ScaleChangedEvent(scale); QMap::const_iterator iterator; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { iterator.value()->SetScale(scale); } } const QMap &KeyframeViewBase::item_map() const { return item_map_; } void KeyframeViewBase::KeyframeAboutToBeRemoved(NodeKeyframe *) { } void KeyframeViewBase::TimeTargetChangedEvent(Node *target) { QMap::const_iterator i; for (i=item_map_.begin();i!=item_map_.end();i++) { i.value()->SetTimeTarget(target); } } void KeyframeViewBase::SetKeyframeTrackVisible(int track, bool visible) { if (!visible == hidden_tracks_.contains(track)) { return; } QMap::const_iterator i; for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) { if (i.key()->track() == track) { i.value()->setVisible(visible); } } if (visible) { hidden_tracks_.removeOne(track); } else { hidden_tracks_.append(track); } } void KeyframeViewBase::ContextMenuEvent(Menu& m) { Q_UNUSED(m) } rational KeyframeViewBase::CalculateNewTimeFromScreen(const rational &old_time, double cursor_diff) { return rational::fromDouble(old_time.toDouble() + cursor_diff); } QPointF KeyframeViewBase::GenerateBezierControlPosition(const NodeKeyframe::BezierType mode, const QPointF &start_point, const QPointF &scaled_cursor_diff) { QPointF new_bezier_pos = start_point; new_bezier_pos += scaled_cursor_diff; // LIMIT bezier handles from overlapping each other if (mode == NodeKeyframe::kInHandle) { if (new_bezier_pos.x() > 0) { new_bezier_pos.setX(0); } } else { if (new_bezier_pos.x() < 0) { new_bezier_pos.setX(0); } } return new_bezier_pos; } void KeyframeViewBase::ProcessBezierDrag(QPointF mouse_diff_scaled, bool include_opposing, bool undoable) { // Flip the mouse Y because bezier control points are drawn bottom to top, not top to bottom mouse_diff_scaled.setY(-mouse_diff_scaled.y()); QPointF new_bezier_pos = GenerateBezierControlPosition(dragging_bezier_point_->mode(), dragging_bezier_point_start_, mouse_diff_scaled); // If the user is NOT holding control, we set the other handle to the exact negative of this handle QPointF new_opposing_pos; NodeKeyframe::BezierType opposing_type = NodeKeyframe::get_opposing_bezier_type(dragging_bezier_point_->mode()); if (include_opposing) { new_opposing_pos = GenerateBezierControlPosition(opposing_type, dragging_bezier_point_opposing_start_, -mouse_diff_scaled); } else { new_opposing_pos = dragging_bezier_point_opposing_start_; } //NodeInput* input_parent = dragging_bezier_point_->key()->parent(); if (undoable) { QUndoCommand* command = new QUndoCommand(); // Similar to the code in MouseRelease, we manipulated the signalling earlier and need to set the keys back to their // original position to allow the input to signal correctly when the undo command is pushed. //input_parent->blockSignals(true); dragging_bezier_point_->key()->set_bezier_control(dragging_bezier_point_->mode(), dragging_bezier_point_start_); new KeyframeSetBezierControlPoint(dragging_bezier_point_->key(), dragging_bezier_point_->mode(), new_bezier_pos, dragging_bezier_point_start_, command); if (include_opposing) { dragging_bezier_point_->key()->set_bezier_control(opposing_type, dragging_bezier_point_opposing_start_); new KeyframeSetBezierControlPoint(dragging_bezier_point_->key(), opposing_type, new_opposing_pos, dragging_bezier_point_opposing_start_, command); } //input_parent->blockSignals(false); Core::instance()->undo_stack()->push(command); } else { //input_parent->blockSignals(true); dragging_bezier_point_->key()->set_bezier_control(dragging_bezier_point_->mode(), new_bezier_pos); dragging_bezier_point_->key()->set_bezier_control(opposing_type, new_opposing_pos); //input_parent->blockSignals(false); //input_parent->parentNode()->InvalidateVisible(input_parent, input_parent); } } QPointF KeyframeViewBase::GetScaledCursorPos(const QPoint &cursor_pos) { return QPointF(static_cast(cursor_pos.x()) / GetScale(), static_cast(cursor_pos.y()) / GetYScale()); } void KeyframeViewBase::ShowContextMenu() { Menu m; MenuShared::instance()->AddItemsForEditMenu(&m, false); QAction* linear_key_action = nullptr; QAction* bezier_key_action = nullptr; QAction* hold_key_action = nullptr; QList items = scene()->selectedItems(); if (!items.isEmpty()) { bool all_keys_are_same_type = true; NodeKeyframe::Type type = static_cast(items.first())->key()->type(); for (int i=1;i(items.at(i)); KeyframeViewItem* prev_item = static_cast(items.at(i-1)); if (key_item->key()->type() != prev_item->key()->type()) { all_keys_are_same_type = false; break; } } m.addSeparator(); linear_key_action = m.addAction(tr("Linear")); bezier_key_action = m.addAction(tr("Bezier")); hold_key_action = m.addAction(tr("Hold")); if (all_keys_are_same_type) { switch (type) { case NodeKeyframe::kLinear: linear_key_action->setChecked(true); break; case NodeKeyframe::kBezier: bezier_key_action->setChecked(true); break; case NodeKeyframe::kHold: hold_key_action->setChecked(true); break; } } } ContextMenuEvent(m); if (!items.isEmpty()) { m.addSeparator(); QAction* properties_action = m.addAction(tr("P&roperties")); connect(properties_action, &QAction::triggered, this, &KeyframeViewBase::ShowKeyframePropertiesDialog); } QAction* selected = m.exec(QCursor::pos()); // Process keyframe type changes if (!items.isEmpty()) { if (selected == linear_key_action || selected == bezier_key_action || selected == hold_key_action) { NodeKeyframe::Type new_type; if (selected == hold_key_action) { new_type = NodeKeyframe::kHold; } else if (selected == bezier_key_action) { new_type = NodeKeyframe::kBezier; } else { new_type = NodeKeyframe::kLinear; } QUndoCommand* command = new QUndoCommand(); foreach (QGraphicsItem* item, items) { new KeyframeSetTypeCommand(static_cast(item)->key(), new_type, command); } Core::instance()->undo_stack()->pushIfHasChildren(command); } } } void KeyframeViewBase::ShowKeyframePropertiesDialog() { QList items = scene()->selectedItems(); QList keys; foreach (QGraphicsItem* item, items) { keys.append(static_cast(item)->key()); } if (!keys.isEmpty()) { KeyframePropertiesDialog kd(keys, timebase(), this); kd.exec(); } } void KeyframeViewBase::AutoSelectKeyTimeNeighbors() { if (currently_autoselecting_ || IsYAxisEnabled()) { return; } // Prevents infinite loop currently_autoselecting_ = true; QList selected_items = scene()->selectedItems(); foreach (QGraphicsItem* g, selected_items) { KeyframeViewItem* key_item = static_cast(g); rational key_time = key_item->key()->time(); QList keys = key_item->key()->parent()->get_keyframe_at_time(key_time); foreach (NodeKeyframePtr k, keys) { if (k == key_item->key()) { continue; } // Ensure this key is not already selected KeyframeViewItem* item = item_map_.value(k.get()); item->setSelected(true); } } currently_autoselecting_ = false; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/keyframeview/keyframeviewbase.h000066400000000000000000000057371370472574300246730ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef KEYFRAMEVIEWBASE_H #define KEYFRAMEVIEWBASE_H #include "keyframeviewitem.h" #include "node/keyframe.h" #include "widget/curvewidget/beziercontrolpointitem.h" #include "widget/menu/menu.h" #include "widget/timelinewidget/view/timelineviewbase.h" #include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER class KeyframeViewBase : public TimelineViewBase, public TimeTargetObject { Q_OBJECT public: KeyframeViewBase(QWidget* parent = nullptr); virtual void Clear(); void DeleteSelected(); public slots: void RemoveKeyframe(NodeKeyframePtr key); protected: virtual KeyframeViewItem* AddKeyframeInternal(NodeKeyframePtr key); virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; virtual void mouseReleaseEvent(QMouseEvent *event) override; virtual void ScaleChangedEvent(const double& scale) override; const QMap& item_map() const; virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key); virtual void TimeTargetChangedEvent(Node*) override; void SetKeyframeTrackVisible(int track, bool visible); virtual void ContextMenuEvent(Menu &m); private: rational CalculateNewTimeFromScreen(const rational& old_time, double cursor_diff); static QPointF GenerateBezierControlPosition(const NodeKeyframe::BezierType mode, const QPointF& start_point, const QPointF& scaled_cursor_diff); void ProcessBezierDrag(QPointF mouse_diff_scaled, bool include_opposing, bool undoable); QPointF GetScaledCursorPos(const QPoint& cursor_pos); struct KeyframeItemAndTime { KeyframeViewItem* key; qreal item_x; rational time; double value; }; QMap item_map_; Tool::Item active_tool_; QPoint drag_start_; BezierControlPointItem* dragging_bezier_point_; QPointF dragging_bezier_point_start_; QPointF dragging_bezier_point_opposing_start_; QVector selected_keys_; bool currently_autoselecting_; QList hidden_tracks_; private slots: void ShowContextMenu(); void ShowKeyframePropertiesDialog(); void AutoSelectKeyTimeNeighbors(); }; OLIVE_NAMESPACE_EXIT #endif // KEYFRAMEVIEWBASE_H olive-continuous/app/widget/keyframeview/keyframeviewitem.cpp000066400000000000000000000061671370472574300252500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keyframeviewitem.h" #include #include #include #include #include "common/qtutils.h" #include "node/input.h" OLIVE_NAMESPACE_ENTER KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) : QGraphicsRectItem(parent), key_(key), scale_(1.0), vert_center_(0), use_custom_brush_(false) { setFlag(QGraphicsItem::ItemIsSelectable); connect(key.get(), &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos); connect(key.get(), &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw); int keyframe_size = QFontMetricsWidth(qApp->fontMetrics(), "Oi"); int half_sz = keyframe_size/2; setRect(-half_sz, -half_sz, keyframe_size, keyframe_size); UpdatePos(); // Set default brush } void KeyframeViewItem::SetOverrideY(qreal vertical_center) { vert_center_ = vertical_center; UpdatePos(); } void KeyframeViewItem::SetScale(double scale) { scale_ = scale; UpdatePos(); } void KeyframeViewItem::SetOverrideBrush(const QBrush &b) { use_custom_brush_ = true; setBrush(b); } NodeKeyframePtr KeyframeViewItem::key() const { return key_; } void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::black); if (option->state & QStyle::State_Selected) { painter->setBrush(widget->palette().highlight()); } else if (use_custom_brush_) { painter->setBrush(brush()); } else { painter->setBrush(widget->palette().text()); } switch (key_->type()) { case NodeKeyframe::kLinear: { QPointF points[] = { QPointF(rect().center().x(), rect().top()), QPointF(rect().right(), rect().center().y()), QPointF(rect().center().x(), rect().bottom()), QPointF(rect().left(), rect().center().y()) }; painter->drawPolygon(points, 4); break; } case NodeKeyframe::kBezier: painter->drawEllipse(rect()); break; case NodeKeyframe::kHold: painter->drawRect(rect()); break; } } void KeyframeViewItem::TimeTargetChangedEvent(Node *) { UpdatePos(); } void KeyframeViewItem::UpdatePos() { rational adjusted = GetAdjustedTime(key_->parent()->parentNode(), GetTimeTarget(), key_->time(), NodeParam::kOutput); setPos(adjusted.toDouble() * scale_, vert_center_); } void KeyframeViewItem::Redraw() { QGraphicsItem::update(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/keyframeview/keyframeviewitem.h000066400000000000000000000031321370472574300247020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef KEYFRAMEVIEWITEM_H #define KEYFRAMEVIEWITEM_H #include #include "node/keyframe.h" #include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTargetObject { Q_OBJECT public: KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent = nullptr); void SetOverrideY(qreal vertical_center); void SetScale(double scale); void SetOverrideBrush(const QBrush& b); NodeKeyframePtr key() const; protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; virtual void TimeTargetChangedEvent(Node* ) override; private: NodeKeyframePtr key_; double scale_; qreal vert_center_; bool use_custom_brush_; private slots: void UpdatePos(); void Redraw(); }; OLIVE_NAMESPACE_EXIT #endif // KEYFRAMEVIEWITEM_H olive-continuous/app/widget/keyframeview/keyframeviewundo.cpp000066400000000000000000000044231370472574300252500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "keyframeviewundo.h" #include "node/input.h" #include "node/node.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand *parent) : UndoCommand(parent), key_(key), old_type_(key->type()), new_type_(type) { } Project *KeyframeSetTypeCommand::GetRelevantProject() const { return static_cast(key_->parent()->parentNode()->parent())->project(); } void KeyframeSetTypeCommand::redo_internal() { key_->set_type(new_type_); } void KeyframeSetTypeCommand::undo_internal() { key_->set_type(old_type_); } KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand *parent) : UndoCommand(parent), key_(key), mode_(mode), old_point_(key->bezier_control(mode_)), new_point_(point) { } KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF &new_point, const QPointF &old_point, QUndoCommand *parent) : UndoCommand(parent), key_(key), mode_(mode), old_point_(old_point), new_point_(new_point) { } Project *KeyframeSetBezierControlPoint::GetRelevantProject() const { return static_cast(key_->parent()->parentNode()->parent())->project(); } void KeyframeSetBezierControlPoint::redo_internal() { key_->set_bezier_control(mode_, new_point_); } void KeyframeSetBezierControlPoint::undo_internal() { key_->set_bezier_control(mode_, old_point_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/keyframeview/keyframeviewundo.h000066400000000000000000000036551370472574300247230ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef KEYFRAMEVIEWUNDO_H #define KEYFRAMEVIEWUNDO_H #include "node/keyframe.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER class KeyframeSetTypeCommand : public UndoCommand { public: KeyframeSetTypeCommand(NodeKeyframePtr key, NodeKeyframe::Type type, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeKeyframePtr key_; NodeKeyframe::Type old_type_; NodeKeyframe::Type new_type_; }; class KeyframeSetBezierControlPoint : public UndoCommand { public: KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand* parent = nullptr); KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& new_point, const QPointF& old_point, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeKeyframePtr key_; NodeKeyframe::BezierType mode_; QPointF old_point_; QPointF new_point_; }; OLIVE_NAMESPACE_EXIT #endif // KEYFRAMEVIEWUNDO_H olive-continuous/app/widget/manageddisplay/000077500000000000000000000000001370472574300214415ustar00rootroot00000000000000olive-continuous/app/widget/manageddisplay/CMakeLists.txt000066400000000000000000000015111370472574300241770ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/manageddisplay/manageddisplay.h widget/manageddisplay/manageddisplay.cpp PARENT_SCOPE ) olive-continuous/app/widget/manageddisplay/manageddisplay.cpp000066400000000000000000000204511370472574300251310ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "manageddisplay.h" #include OLIVE_NAMESPACE_ENTER ManagedDisplayWidget::ManagedDisplayWidget(QWidget *parent) : QOpenGLWidget(parent), color_manager_(nullptr), color_service_(nullptr) { setContextMenuPolicy(Qt::CustomContextMenu); } ManagedDisplayWidget::~ManagedDisplayWidget() { ContextCleanup(); } void ManagedDisplayWidget::ConnectColorManager(ColorManager *color_manager) { if (color_manager_ == color_manager) { return; } if (color_manager_ != nullptr) { disconnect(color_manager_, &ColorManager::ConfigChanged, this, &ManagedDisplayWidget::ColorConfigChanged); } color_manager_ = color_manager; if (color_manager_ != nullptr) { connect(color_manager_, &ColorManager::ConfigChanged, this, &ManagedDisplayWidget::ColorConfigChanged); } ColorConfigChanged(); emit ColorManagerChanged(color_manager_); } ColorManager *ManagedDisplayWidget::color_manager() const { return color_manager_; } void ManagedDisplayWidget::DisconnectColorManager() { ConnectColorManager(nullptr); } const ColorTransform &ManagedDisplayWidget::GetColorTransform() const { return color_transform_; } Menu *ManagedDisplayWidget::GetColorSpaceMenu(QMenu *parent, bool auto_connect) { QStringList colorspaces = color_manager()->ListAvailableColorspaces(); Menu* ocio_colorspace_menu = new Menu(tr("Color Space"), parent); if (auto_connect) { connect(ocio_colorspace_menu, &Menu::triggered, this, &ManagedDisplayWidget::MenuColorspaceSelect); } foreach (const QString& c, colorspaces) { QAction* action = ocio_colorspace_menu->addAction(c); action->setCheckable(true); action->setChecked(color_transform_.output() == c); action->setData(c); } return ocio_colorspace_menu; } void ManagedDisplayWidget::ColorConfigChanged() { if (!color_manager_) { color_service_ = nullptr; return; } SetColorTransform(color_manager_->GetCompliantColorSpace(color_transform_, true)); } OpenGLColorProcessorPtr ManagedDisplayWidget::color_service() { return color_service_; } void ManagedDisplayWidget::ContextCleanup() { makeCurrent(); color_service_ = nullptr; doneCurrent(); } void ManagedDisplayWidget::ShowDefaultContextMenu() { Menu m(this); if (color_manager_) { m.addMenu(GetColorSpaceMenu(&m)); m.addSeparator(); m.addMenu(GetDisplayMenu(&m)); m.addMenu(GetViewMenu(&m)); m.addMenu(GetLookMenu(&m)); } else { QAction* a = m.addAction(tr("No color manager connected")); a->setEnabled(false); } m.exec(QCursor::pos()); } void ManagedDisplayWidget::MenuDisplaySelect(QAction *action) { const ColorTransform& old_transform = GetColorTransform(); ColorTransform new_transform = color_manager()->GetCompliantColorSpace(ColorTransform(action->data().toString(), old_transform.view(), old_transform.look())); SetColorTransform(new_transform); } void ManagedDisplayWidget::MenuViewSelect(QAction *action) { const ColorTransform& old_transform = GetColorTransform(); ColorTransform new_transform = color_manager()->GetCompliantColorSpace(ColorTransform(old_transform.display(), action->data().toString(), old_transform.look())); SetColorTransform(new_transform); } void ManagedDisplayWidget::MenuLookSelect(QAction *action) { const ColorTransform& old_transform = GetColorTransform(); ColorTransform new_transform = color_manager()->GetCompliantColorSpace(ColorTransform(old_transform.display(), old_transform.view(), action->data().toString())); SetColorTransform(new_transform); } void ManagedDisplayWidget::MenuColorspaceSelect(QAction *action) { SetColorTransform(color_manager()->GetCompliantColorSpace(ColorTransform(action->data().toString()))); } void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform) { makeCurrent(); color_transform_ = transform; SetupColorProcessor(); ColorProcessorChangedEvent(); doneCurrent(); } void ManagedDisplayWidget::initializeGL() { SetupColorProcessor(); connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ManagedDisplayWidget::ContextCleanup, Qt::DirectConnection); } void ManagedDisplayWidget::EnableDefaultContextMenu() { connect(this, &ManagedDisplayWidget::customContextMenuRequested, this, &ManagedDisplayWidget::ShowDefaultContextMenu); } void ManagedDisplayWidget::ColorProcessorChangedEvent() { update(); } Menu* ManagedDisplayWidget::GetDisplayMenu(QMenu* parent, bool auto_connect) { QStringList displays = color_manager()->ListAvailableDisplays(); Menu* ocio_display_menu = new Menu(tr("Display"), parent); if (auto_connect) { connect(ocio_display_menu, &Menu::triggered, this, &ManagedDisplayWidget::MenuDisplaySelect); } foreach (const QString& d, displays) { QAction* action = ocio_display_menu->addAction(d); action->setCheckable(true); action->setChecked(color_transform_.display() == d); action->setData(d); } return ocio_display_menu; } Menu* ManagedDisplayWidget::GetViewMenu(QMenu* parent, bool auto_connect) { QStringList views = color_manager()->ListAvailableViews(color_transform_.display()); Menu* ocio_view_menu = new Menu(tr("View"), parent); if (auto_connect) { connect(ocio_view_menu, &Menu::triggered, this, &ManagedDisplayWidget::MenuViewSelect); } foreach (const QString& v, views) { QAction* action = ocio_view_menu->addAction(v); action->setCheckable(true); action->setChecked(color_transform_.view() == v); action->setData(v); } return ocio_view_menu; } Menu* ManagedDisplayWidget::GetLookMenu(QMenu* parent, bool auto_connect) { QStringList looks = color_manager()->ListAvailableLooks(); Menu* ocio_look_menu = new Menu(tr("Look"), parent); if (auto_connect) { connect(ocio_look_menu, &Menu::triggered, this, &ManagedDisplayWidget::MenuLookSelect); } // Setup "no look" action QAction* no_look_action = ocio_look_menu->addAction(tr("(None)")); no_look_action->setCheckable(true); no_look_action->setChecked(color_transform_.look().isEmpty()); no_look_action->setData(QString()); // Set up the rest of the looks foreach (const QString& l, looks) { QAction* action = ocio_look_menu->addAction(l); action->setCheckable(true); action->setChecked(color_transform_.look() == l); action->setData(l); } return ocio_look_menu; } void ManagedDisplayWidget::SetupColorProcessor() { if (!context()) { return; } color_service_ = nullptr; if (color_manager_) { // (Re)create color processor try { color_service_ = OpenGLColorProcessor::Create(color_manager_, color_manager_->GetReferenceColorSpace(), color_transform_); color_service_->Enable(context(), true); } catch (OCIO::Exception& e) { QMessageBox::critical(this, tr("OpenColorIO Error"), tr("Failed to set color configuration: %1").arg(e.what()), QMessageBox::Ok); } } else { color_service_ = nullptr; } emit ColorProcessorChanged(std::static_pointer_cast(color_service_)); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/manageddisplay/manageddisplay.h000066400000000000000000000111011370472574300245660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MANAGEDDISPLAYOBJECT_H #define MANAGEDDISPLAYOBJECT_H #include #include "render/backend/opengl/openglcolorprocessor.h" #include "render/colormanager.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER class ManagedDisplayWidget : public QOpenGLWidget { Q_OBJECT public: ManagedDisplayWidget(QWidget* parent = nullptr); virtual ~ManagedDisplayWidget() override; /** * @brief Disconnect a ColorManager (equivalent to ConnectColorManager(nullptr)) */ void DisconnectColorManager(); /** * @brief Access currently connected ColorManager (nullptr if none) */ ColorManager* color_manager() const; /** * @brief Get current color transform */ const ColorTransform& GetColorTransform() const; /** * @brief Get menu that can be used to select the colorspace */ Menu* GetColorSpaceMenu(QMenu* parent, bool auto_connect = true); /** * @brief Get menu that can be used to select the display transform */ Menu* GetDisplayMenu(QMenu* parent, bool auto_connect = true); /** * @brief Get menu that can be used to select the view transform */ Menu* GetViewMenu(QMenu* parent, bool auto_connect = true); /** * @brief Get menu that can be used to select the look transform */ Menu* GetLookMenu(QMenu* parent, bool auto_connect = true); public slots: /** * @brief Replaces the color transform with a new one */ void SetColorTransform(const ColorTransform& transform); /** * @brief Connect a ColorManager (ColorManagers usually belong to the Project) */ void ConnectColorManager(ColorManager* color_manager); signals: /** * @brief Emitted when the color processor changes */ void ColorProcessorChanged(ColorProcessorPtr processor); /** * @brief Emitted when a new color manager is connected */ void ColorManagerChanged(ColorManager* color_manager); protected: /** * @brief Provides access to the color processor (nullptr if none is set) */ OpenGLColorProcessorPtr color_service(); /** * @brief Override when setting up OpenGL context */ virtual void initializeGL() override; /** * @brief Enables a context menu that allows simple access to the DVL pipeline */ void EnableDefaultContextMenu(); /** * @brief Function called whenever the processor changes * * Default functionality is just to call update() */ virtual void ColorProcessorChangedEvent(); private: /** * @brief Call this if this user has selected a different display/view/look to recreate the processor */ void SetupColorProcessor(); /** * @brief Cleanup function */ void ClearOCIOLutTexture(); /** * @brief Connected color manager */ ColorManager* color_manager_; /** * @brief Color management service */ OpenGLColorProcessorPtr color_service_; /** * @brief Internal color transform storage */ ColorTransform color_transform_; private slots: /** * @brief Sets all color settings to the defaults pertaining to this configuration */ void ColorConfigChanged(); /** * @brief Cleans up resources if context is about to be destroyed */ void ContextCleanup(); /** * @brief The default context menu shown */ void ShowDefaultContextMenu(); /** * @brief If GetDisplayMenu() is called with `auto_connect` set to true, it will be connected to this */ void MenuDisplaySelect(QAction* action); /** * @brief If GetViewMenu() is called with `auto_connect` set to true, it will be connected to this */ void MenuViewSelect(QAction* action); /** * @brief If GetLookMenu() is called with `auto_connect` set to true, it will be connected to this */ void MenuLookSelect(QAction* action); /** * @brief If GetColorSpaceMenu() is called with `auto_connect` set to true, it will be connected to this */ void MenuColorspaceSelect(QAction* action); }; OLIVE_NAMESPACE_EXIT #endif // MANAGEDDISPLAYOBJECT_H olive-continuous/app/widget/menu/000077500000000000000000000000001370472574300174235ustar00rootroot00000000000000olive-continuous/app/widget/menu/CMakeLists.txt000066400000000000000000000015311370472574300221630ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/menu/menu.h widget/menu/menu.cpp widget/menu/menushared.h widget/menu/menushared.cpp PARENT_SCOPE ) olive-continuous/app/widget/menu/menu.cpp000066400000000000000000000045631370472574300211030ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "menu.h" #include "ui/style/style.h" OLIVE_NAMESPACE_ENTER Menu::Menu(QMenuBar *bar) { bar->addMenu(this); Init(); } Menu::Menu(Menu *menu) { menu->addMenu(this); Init(); } Menu::Menu(QWidget *parent) : QMenu(parent) { Init(); } Menu::Menu(const QString &s, QWidget *parent) : QMenu(s, parent) { Init(); } QAction *Menu::AddActionWithData(const QString &text, const QVariant &d, const QVariant &compare) { QAction* a = addAction(text); a->setData(d); a->setCheckable(true); a->setChecked(d == compare); return a; } QAction* Menu::InsertAlphabetically(const QString &s) { QAction* action = new QAction(s, this); InsertAlphabetically(action); return action; } void Menu::InsertAlphabetically(QAction *entry) { QList actions = this->actions(); foreach (QAction* action, actions) { if (action->text() > entry->text()) { insertAction(action, entry); return; } } addAction(entry); } void Menu::InsertAlphabetically(Menu *menu) { InsertAlphabetically(menu->menuAction()); } void Menu::ConformItem(QAction *a, const QString &id, const QString &key) { a->setProperty("id", id); if (!key.isEmpty()) { a->setShortcut(key); a->setProperty("keydefault", key); // Set to application context so that ViewerWindows still trigger shortcuts a->setShortcutContext(Qt::ApplicationShortcut); } } void Menu::SetBooleanAction(QAction *a, bool* boolean) { // FIXME: Connect to some boolean function a->setCheckable(true); a->setChecked(*boolean); a->setProperty("boolptr", reinterpret_cast(boolean)); } void Menu::Init() { StyleManager::UseOSNativeStyling(this); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/menu/menu.h000066400000000000000000000145151370472574300205460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef WIDGETMENU_H #define WIDGETMENU_H #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief A menu widget for context menus and menu bars * * A QMenu subclass with functions for creating menus and menu items that conform to Olive's menu and keyboard shortcut * system. * * In Olive, menu items in the menu bar are also responsible for keyboard shortcuts throughout the application. To allow * these to be configurable and these configurations saveable, every item needs a unique ID. This ID gets linked to the * keyboard shortcuts in config files. The ID doesn't get translated so it can also persist through language changes. * * The ID gets stored in the QAction's "id" property. If a keyboard shortcut is provided, it gets stored in the * QAction's "keydefault" property. * * It is always recommended to use this over QMenu in any situation. */ class Menu : public QMenu { public: Menu(QMenuBar* bar); template /** * @brief Construct a Menu and add it to a QMenuBar * * This Menu can be connected to a slot that's triggered when the Menu is "about to show". Use `receiver` and * `member` to connect this (same syntax as QObject::connect) or leave as nullptr to not. */ Menu(QMenuBar* bar, const typename QtPrivate::FunctionPointer::Object *receiver, Func member) { bar->addMenu(this); Init(); ConnectAboutToShow(receiver, member); } Menu(Menu* menu); template /** * @brief Construct a Menu and add it as a submenu to another Menu * * This Menu can be connected to a slot that's triggered when the Menu is "about to show". Use `receiver` and * `member` to connect this (same syntax as QObject::connect) or leave as nullptr to not. */ Menu(Menu* menu, const typename QtPrivate::FunctionPointer::Object *receiver, Func member) { menu->addMenu(this); Init(); ConnectAboutToShow(receiver, member); } /** * @brief Construct a popup menu */ Menu(QWidget* parent = nullptr); /** * @brief Construct a popup menu */ Menu(const QString& s, QWidget* parent = nullptr); template /** * @brief Create a menu item and add it to this menu * * @param id * * The action's unique ID * * @param receiver * * The QObject to receive the signal when this item is triggered * * @param member * * The QObject slot to connect this action's triggered signal to * * @param key * * Default keyboard sequence * * @return * * The QAction that was created and added to this Menu */ QAction* AddItem(const QString& id, const typename QtPrivate::FunctionPointer::Object *receiver, Func member, const QString &key = QString()) { QAction* a = CreateItem(this, id, receiver, member, key); addAction(a); return a; } QAction* AddActionWithData(const QString& text, const QVariant& d, const QVariant& compare); QAction *InsertAlphabetically(const QString& s); void InsertAlphabetically(QAction* entry); void InsertAlphabetically(Menu* menu); template /** * @brief Create a menu item * * @param parent * * The QAction's parent * * @param id * * The action's unique ID * * @param receiver * * The QObject to receive the signal when this item is triggered * * @param member * * The QObject slot to connect this action's triggered signal to * * @param key * * Default keyboard sequence * * @return * * The QAction that was created and added to this Menu */ static QAction* CreateItem(QObject* parent, const QString& id, const typename QtPrivate::FunctionPointer::Object *receiver, Func member, const QString& key = QString()) { QAction* a = new QAction(parent); ConformItem(a, id, receiver, member, key); return a; } template /** * @brief Conform a QAction to Olive's ID/keydefault system * * If a QAction was created elsewhere (e.g. through QUndoStack::createUndoAction()), this function will give it * properties conforming it to Olive's menu item system * * @param a * * The QAction's to conform * * @param id * * The action's unique ID * * @param receiver * * The QObject to receive the signal when this item is triggered * * @param member * * The QObject slot to connect this action's triggered signal to * * @param key * * Default keyboard sequence */ static void ConformItem(QAction *a, const QString& id, const typename QtPrivate::FunctionPointer::Object *receiver, Func member, const QString& key = QString()) { ConformItem(a, id, key); connect(a, &QAction::triggered, receiver, member); } static void ConformItem(QAction *a, const QString& id, const QString& key = QString()); static void SetBooleanAction(QAction* a, bool *boolean); private: void Init(); template void ConnectAboutToShow(const typename QtPrivate::FunctionPointer::Object *receiver, Func member) { connect(this, &Menu::aboutToShow, receiver, member); } }; OLIVE_NAMESPACE_EXIT #endif // WIDGETMENU_H olive-continuous/app/widget/menu/menushared.cpp000066400000000000000000000167611370472574300222750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "menushared.h" #include "core.h" #include "panel/panelmanager.h" #include "panel/timeline/timeline.h" OLIVE_NAMESPACE_ENTER MenuShared* MenuShared::instance_ = nullptr; MenuShared::MenuShared() { // "New" menu shared items new_project_item_ = Menu::CreateItem(this, "newproj", Core::instance(), &Core::CreateNewProject, "Ctrl+N"); new_sequence_item_ = Menu::CreateItem(this, "newseq", Core::instance(), &Core::CreateNewSequence, "Ctrl+Shift+N"); new_folder_item_ = Menu::CreateItem(this, "newfolder", Core::instance(), &Core::CreateNewFolder); // "Edit" menu shared items edit_cut_item_ = Menu::CreateItem(this, "cut", this, &MenuShared::CutTriggered, "Ctrl+X"); edit_copy_item_ = Menu::CreateItem(this, "copy", this, &MenuShared::CopyTriggered, "Ctrl+C"); edit_paste_item_ = Menu::CreateItem(this, "paste", this, &MenuShared::PasteTriggered, "Ctrl+V"); edit_paste_insert_item_ = Menu::CreateItem(this, "pasteinsert", this, &MenuShared::PasteInsertTriggered, "Ctrl+Shift+V"); edit_duplicate_item_ = Menu::CreateItem(this, "duplicate", this, &MenuShared::DuplicateTriggered, "Ctrl+D"); edit_delete_item_ = Menu::CreateItem(this, "delete", this, &MenuShared::DeleteSelectedTriggered, "Del"); edit_ripple_delete_item_ = Menu::CreateItem(this, "rippledelete", this, &MenuShared::RippleDeleteTriggered, "Shift+Del"); edit_split_item_ = Menu::CreateItem(this, "split", this, &MenuShared::SplitAtPlayheadTriggered, "Ctrl+K"); // "In/Out" menu shared items inout_set_in_item_ = Menu::CreateItem(this, "setinpoint", this, &MenuShared::SetInTriggered, "I"); inout_set_out_item_ = Menu::CreateItem(this, "setoutpoint", this, &MenuShared::SetOutTriggered, "O"); inout_reset_in_item_ = Menu::CreateItem(this, "resetin", this, &MenuShared::ResetInTriggered); inout_reset_out_item_ = Menu::CreateItem(this, "resetout", this, &MenuShared::ResetOutTriggered); inout_clear_inout_item_ = Menu::CreateItem(this, "clearinout", this, &MenuShared::ClearInOutTriggered, "G"); // "Clip Edit" menu shared items clip_add_default_transition_item_ = Menu::CreateItem(this, "deftransition", this, &MenuShared::DefaultTransitionTriggered, "Ctrl+Shift+D"); clip_link_unlink_item_ = Menu::CreateItem(this, "linkunlink", this, &MenuShared::ToggleLinksTriggered, "Ctrl+L"); clip_enable_disable_item_ = Menu::CreateItem(this, "enabledisable", this, &MenuShared::EnableDisableTriggered, "Shift+E"); clip_nest_item_ = Menu::CreateItem(this, "nest", this, &MenuShared::NestTriggered); Retranslate(); } void MenuShared::CreateInstance() { instance_ = new MenuShared(); } void MenuShared::DestroyInstance() { delete instance_; } void MenuShared::AddItemsForNewMenu(Menu *m) { m->addAction(new_project_item_); m->addSeparator(); m->addAction(new_sequence_item_); m->addAction(new_folder_item_); } void MenuShared::AddItemsForEditMenu(Menu *m, bool for_clips) { m->addAction(Core::instance()->undo_stack()->createUndoAction(m)); m->addAction(Core::instance()->undo_stack()->createRedoAction(m)); m->addSeparator(); m->addAction(edit_cut_item_); m->addAction(edit_copy_item_); m->addAction(edit_paste_item_); m->addAction(edit_paste_insert_item_); m->addAction(edit_duplicate_item_); m->addAction(edit_delete_item_); if (for_clips) { m->addAction(edit_ripple_delete_item_); m->addAction(edit_split_item_); } } void MenuShared::AddItemsForInOutMenu(Menu *m) { m->addAction(inout_set_in_item_); m->addAction(inout_set_out_item_); m->addSeparator(); m->addAction(inout_reset_in_item_); m->addAction(inout_reset_out_item_); m->addAction(inout_clear_inout_item_); } void MenuShared::AddItemsForClipEditMenu(Menu *m) { m->addAction(clip_add_default_transition_item_); m->addAction(clip_link_unlink_item_); m->addAction(clip_enable_disable_item_); m->addAction(clip_nest_item_); } MenuShared *MenuShared::instance() { return instance_; } void MenuShared::SplitAtPlayheadTriggered() { TimelinePanel* timeline = PanelManager::instance()->MostRecentlyFocused(); if (timeline != nullptr) { timeline->SplitAtPlayhead(); } } void MenuShared::DeleteSelectedTriggered() { PanelManager::instance()->CurrentlyFocused()->DeleteSelected(); } void MenuShared::RippleDeleteTriggered() { PanelManager::instance()->CurrentlyFocused()->RippleDelete(); } void MenuShared::SetInTriggered() { PanelManager::instance()->CurrentlyFocused()->SetIn(); } void MenuShared::SetOutTriggered() { PanelManager::instance()->CurrentlyFocused()->SetOut(); } void MenuShared::ResetInTriggered() { PanelManager::instance()->CurrentlyFocused()->ResetIn(); } void MenuShared::ResetOutTriggered() { PanelManager::instance()->CurrentlyFocused()->ResetOut(); } void MenuShared::ClearInOutTriggered() { PanelManager::instance()->CurrentlyFocused()->ClearInOut(); } void MenuShared::ToggleLinksTriggered() { PanelManager::instance()->CurrentlyFocused()->ToggleLinks(); } void MenuShared::CutTriggered() { PanelManager::instance()->CurrentlyFocused()->CutSelected(); } void MenuShared::CopyTriggered() { PanelManager::instance()->CurrentlyFocused()->CopySelected(); } void MenuShared::PasteTriggered() { PanelManager::instance()->CurrentlyFocused()->Paste(); } void MenuShared::PasteInsertTriggered() { PanelManager::instance()->CurrentlyFocused()->PasteInsert(); } void MenuShared::DuplicateTriggered() { PanelManager::instance()->CurrentlyFocused()->Duplicate(); } void MenuShared::EnableDisableTriggered() { PanelManager::instance()->CurrentlyFocused()->ToggleSelectedEnabled(); } void MenuShared::NestTriggered() { qDebug() << "FIXME: Stub"; } void MenuShared::DefaultTransitionTriggered() { qDebug() << "FIXME: Stub"; } void MenuShared::Retranslate() { // "New" menu shared items new_project_item_->setText(tr("&Project")); new_sequence_item_->setText(tr("&Sequence")); new_folder_item_->setText(tr("&Folder")); // "Edit" menu shared items edit_cut_item_->setText(tr("Cu&t")); edit_copy_item_->setText(tr("Cop&y")); edit_paste_item_->setText(tr("&Paste")); edit_paste_insert_item_->setText(tr("Paste Insert")); edit_duplicate_item_->setText(tr("Duplicate")); edit_delete_item_->setText(tr("Delete")); edit_ripple_delete_item_->setText(tr("Ripple Delete")); edit_split_item_->setText(tr("Split")); // "In/Out" menu shared items inout_set_in_item_->setText(tr("Set In Point")); inout_set_out_item_->setText(tr("Set Out Point")); inout_reset_in_item_->setText(tr("Reset In Point")); inout_reset_out_item_->setText(tr("Reset Out Point")); inout_clear_inout_item_->setText(tr("Clear In/Out Point")); // "Clip Edit" menu shared items clip_add_default_transition_item_->setText(tr("Add Default Transition")); clip_link_unlink_item_->setText(tr("Link/Unlink")); clip_enable_disable_item_->setText(tr("Enable/Disable")); clip_nest_item_->setText(tr("Nest")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/menu/menushared.h000066400000000000000000000051651370472574300217360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MENUSHARED_H #define MENUSHARED_H #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER /** * @brief A static object that provides various "stock" menus for use throughout the application */ class MenuShared : public QObject { Q_OBJECT public: MenuShared(); static void CreateInstance(); static void DestroyInstance(); void Retranslate(); void AddItemsForNewMenu(Menu* m); void AddItemsForEditMenu(Menu* m, bool for_clips); void AddItemsForInOutMenu(Menu* m); void AddItemsForClipEditMenu(Menu* m); static MenuShared* instance(); private: // "New" menu shared items QAction* new_project_item_; QAction* new_sequence_item_; QAction* new_folder_item_; // "Edit" menu shared items QAction* edit_cut_item_; QAction* edit_copy_item_; QAction* edit_paste_item_; QAction* edit_paste_insert_item_; QAction* edit_duplicate_item_; QAction* edit_delete_item_; QAction* edit_ripple_delete_item_; QAction* edit_split_item_; // "In/Out" menu shared items QAction* inout_set_in_item_; QAction* inout_set_out_item_; QAction* inout_reset_in_item_; QAction* inout_reset_out_item_; QAction* inout_clear_inout_item_; // "Clip Edit" menu shared items QAction* clip_add_default_transition_item_; QAction* clip_link_unlink_item_; QAction* clip_enable_disable_item_; QAction* clip_nest_item_; static MenuShared* instance_; private slots: void SplitAtPlayheadTriggered(); void DeleteSelectedTriggered(); void RippleDeleteTriggered(); void SetInTriggered(); void SetOutTriggered(); void ResetInTriggered(); void ResetOutTriggered(); void ClearInOutTriggered(); void ToggleLinksTriggered(); void CutTriggered(); void CopyTriggered(); void PasteTriggered(); void PasteInsertTriggered(); void DuplicateTriggered(); void EnableDisableTriggered(); void NestTriggered(); void DefaultTransitionTriggered(); }; OLIVE_NAMESPACE_EXIT #endif // MENUSHARED_H olive-continuous/app/widget/nodecombobox/000077500000000000000000000000001370472574300211355ustar00rootroot00000000000000olive-continuous/app/widget/nodecombobox/CMakeLists.txt000066400000000000000000000015011370472574300236720ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/nodecombobox/nodecombobox.h widget/nodecombobox/nodecombobox.cpp PARENT_SCOPE ) olive-continuous/app/widget/nodecombobox/nodecombobox.cpp000066400000000000000000000036151370472574300243240ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodecombobox.h" #include #include #include "node/factory.h" #include "ui/icons/icons.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER NodeComboBox::NodeComboBox(QWidget *parent) : QComboBox(parent) { } void NodeComboBox::showPopup() { Menu* m = NodeFactory::CreateMenu(this, true); QAction* selected = m->exec(parentWidget()->mapToGlobal(pos())); if (selected) { QString new_id = NodeFactory::GetIDFromMenuAction(selected); SetNodeInternal(new_id, true); } delete m; } const QString &NodeComboBox::GetSelectedNode() const { return selected_id_; } void NodeComboBox::SetNode(const QString &id) { SetNodeInternal(id, false); } void NodeComboBox::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { UpdateText(); } QComboBox::changeEvent(e); } void NodeComboBox::UpdateText() { clear(); if (!selected_id_.isEmpty()) { addItem(NodeFactory::GetNameFromID(selected_id_)); } } void NodeComboBox::SetNodeInternal(const QString &id, bool emit_signal) { if (selected_id_ != id) { selected_id_ = id; UpdateText(); if (emit_signal) { emit NodeChanged(selected_id_); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodecombobox/nodecombobox.h000066400000000000000000000024771370472574300237760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODECOMBOBOX_H #define NODECOMBOBOX_H #include #include "node/node.h" OLIVE_NAMESPACE_ENTER class NodeComboBox : public QComboBox { Q_OBJECT public: NodeComboBox(QWidget* parent = nullptr); virtual void showPopup() override; const QString& GetSelectedNode() const; public slots: void SetNode(const QString& id); protected: virtual void changeEvent(QEvent *e) override; signals: void NodeChanged(const QString& id); private: void UpdateText(); void SetNodeInternal(const QString& id, bool emit_signal); QString selected_id_; }; OLIVE_NAMESPACE_EXIT #endif // FOOTAGECOMBOBOX_H olive-continuous/app/widget/nodecopypaste/000077500000000000000000000000001370472574300213345ustar00rootroot00000000000000olive-continuous/app/widget/nodecopypaste/CMakeLists.txt000066400000000000000000000015051370472574300240750ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/nodecopypaste/nodecopypaste.h widget/nodecopypaste/nodecopypaste.cpp PARENT_SCOPE ) olive-continuous/app/widget/nodecopypaste/nodecopypaste.cpp000066400000000000000000000111301370472574300247110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodecopypaste.h" #include #include "core.h" #include "widget/nodeview/nodeviewundo.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER void NodeCopyPasteWidget::CopyNodesToClipboard(const QList &nodes, void *userdata) { QString copy_str; QXmlStreamWriter writer(©_str); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement(QStringLiteral("olive")); foreach (Node* n, nodes) { n->Save(&writer); } CopyNodesToClipboardInternal(&writer, userdata); writer.writeEndElement(); // olive writer.writeEndDocument(); Core::CopyStringToClipboard(copy_str); } QList NodeCopyPasteWidget::PasteNodesFromClipboard(Sequence *graph, QUndoCommand* command, void *userdata) { QString clipboard = Core::PasteStringFromClipboard(); if (clipboard.isEmpty()) { return QList(); } QXmlStreamReader reader(clipboard); QList pasted_nodes; XMLNodeData xml_node_data; while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("olive")) { while (XMLReadNextStartElement(&reader)) { if (reader.name() == QStringLiteral("node")) { Node* node = XMLLoadNode(&reader); if (node) { node->Load(&reader, xml_node_data, nullptr); pasted_nodes.append(node); } } else { PasteNodesFromClipboardInternal(&reader, userdata); } } } else { reader.skipCurrentElement(); } } if (pasted_nodes.isEmpty()) { // If we passed through the whole string and there were no nodes, it must not be data for us after all return QList(); } // If we have some nodes AND the XML data was malformed, the user should probably know if (reader.hasError()) { // Delete all nodes so this is a no-op foreach (Node* n, pasted_nodes) { delete n; } // If this was NOT an internal error, we assume it's an XML error that the user needs to know about QMessageBox::critical(Core::instance()->main_window(), QCoreApplication::translate("NodeCopyPasteWidget", "Error pasting nodes"), QCoreApplication::translate("NodeCopyPasteWidget", "Failed to paste nodes: %1").arg(reader.errorString()), QMessageBox::Ok); return QList(); } // Add all nodes to graph foreach (Node* n, pasted_nodes) { new NodeAddCommand(graph, n, command); } // Make connections if (!xml_node_data.desired_connections.isEmpty()) { XMLConnectNodes(xml_node_data, command); } // Link blocks XMLLinkBlocks(xml_node_data); // Connect footage to existing footage if it exists if (!xml_node_data.footage_connections.isEmpty()) { // Get list of all footage from project QList footage = graph->project()->get_items_of_type(Item::kFootage); if (!footage.isEmpty()) { foreach (const XMLNodeData::FootageConnection& con, xml_node_data.footage_connections) { if (con.footage) { // Assume this is a pointer to a Stream* Stream* loaded_stream = reinterpret_cast(con.footage); bool found = false; foreach (ItemPtr item, footage) { const QList& streams = std::static_pointer_cast(item)->streams(); foreach (StreamPtr s, streams) { if (s.get() == loaded_stream) { con.input->set_standard_value(QVariant::fromValue(s)); found = true; break; } } if (found) { break; } } } } } } return pasted_nodes; } void NodeCopyPasteWidget::CopyNodesToClipboardInternal(QXmlStreamWriter*, void*) { } void NodeCopyPasteWidget::PasteNodesFromClipboardInternal(QXmlStreamReader* reader, void*) { reader->skipCurrentElement(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodecopypaste/nodecopypaste.h000066400000000000000000000026121370472574300243630ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODECOPYPASTEWIDGET_H #define NODECOPYPASTEWIDGET_H #include #include #include "node/node.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER class NodeCopyPasteWidget { public: NodeCopyPasteWidget() = default; protected: void CopyNodesToClipboard(const QList& nodes, void* userdata = nullptr); QList PasteNodesFromClipboard(Sequence *graph, QUndoCommand *command, void* userdata = nullptr); virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata); virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, void* userdata); }; OLIVE_NAMESPACE_EXIT #endif // NODECOPYPASTEWIDGET_H olive-continuous/app/widget/nodeparamview/000077500000000000000000000000001370472574300213205ustar00rootroot00000000000000olive-continuous/app/widget/nodeparamview/CMakeLists.txt000066400000000000000000000027751370472574300240730ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/nodeparamview/nodeparamview.h widget/nodeparamview/nodeparamview.cpp widget/nodeparamview/nodeparamviewarraywidget.h widget/nodeparamview/nodeparamviewarraywidget.cpp widget/nodeparamview/nodeparamviewconnectedlabel.h widget/nodeparamview/nodeparamviewconnectedlabel.cpp widget/nodeparamview/nodeparamviewitem.h widget/nodeparamview/nodeparamviewitem.cpp widget/nodeparamview/nodeparamviewkeyframecontrol.h widget/nodeparamview/nodeparamviewkeyframecontrol.cpp widget/nodeparamview/nodeparamviewrichtext.h widget/nodeparamview/nodeparamviewrichtext.cpp widget/nodeparamview/nodeparamviewundo.h widget/nodeparamview/nodeparamviewundo.cpp widget/nodeparamview/nodeparamviewwidgetbridge.h widget/nodeparamview/nodeparamviewwidgetbridge.cpp PARENT_SCOPE ) olive-continuous/app/widget/nodeparamview/nodeparamview.cpp000066400000000000000000000202431370472574300246660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamview.h" #include #include #include #include "common/timecodefunctions.h" #include "node/output/viewer/viewer.h" OLIVE_NAMESPACE_ENTER NodeParamView::NodeParamView(QWidget *parent) : TimeBasedWidget(true, false, parent), last_scroll_val_(0) { // Create horizontal layout to place scroll area in (and keyframe editing eventually) QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); QSplitter* splitter = new QSplitter(Qt::Horizontal); layout->addWidget(splitter); // Set up scroll area for params QScrollArea* scroll_area = new QScrollArea(); scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scroll_area->setWidgetResizable(true); splitter->addWidget(scroll_area); // Param widget param_widget_area_ = new QWidget(); scroll_area->setWidget(param_widget_area_); // Set up scroll area layout param_layout_ = new QVBoxLayout(param_widget_area_); param_layout_->setSpacing(0); // KeyframeView is offset by a ruler, so to stay synchronized with it, we should be too param_layout_->setContentsMargins(0, ruler()->height(), 0, 0); // Add a stretch to allow empty space at the bottom of the layout param_layout_->addStretch(); // Set up keyframe view QWidget* keyframe_area = new QWidget(); QVBoxLayout* keyframe_area_layout = new QVBoxLayout(keyframe_area); keyframe_area_layout->setSpacing(0); keyframe_area_layout->setMargin(0); // Create ruler object keyframe_area_layout->addWidget(ruler()); // Create keyframe view keyframe_view_ = new KeyframeView(); keyframe_view_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ConnectTimelineView(keyframe_view_); connect(keyframe_view_, &KeyframeView::RequestCenterScrollOnPlayhead, this, &NodeParamView::CenterScrollOnPlayhead); keyframe_area_layout->addWidget(keyframe_view_); // Connect ruler and keyframe view together connect(ruler(), &TimeRuler::TimeChanged, keyframe_view_, &KeyframeView::SetTime); connect(keyframe_view_, &KeyframeView::TimeChanged, ruler(), &TimeRuler::SetTime); connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTimestamp); // Connect keyframe view scaling to this connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale); splitter->addWidget(keyframe_area); // Set both widgets to 50/50 splitter->setSizes({INT_MAX, INT_MAX}); // Disable collapsing param view (but collapsing keyframe view is permitted) splitter->setCollapsible(0, false); // Create global vertical scrollbar on the right vertical_scrollbar_ = new QScrollBar(); vertical_scrollbar_->setMaximum(0); layout->addWidget(vertical_scrollbar_); // Connect scrollbars together connect(scroll_area->verticalScrollBar(), &QScrollBar::rangeChanged, vertical_scrollbar_, &QScrollBar::setRange); connect(scroll_area->verticalScrollBar(), &QScrollBar::rangeChanged, this, &NodeParamView::ForceKeyframeViewToScroll); connect(keyframe_view_->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue); connect(keyframe_view_->verticalScrollBar(), &QScrollBar::valueChanged, scroll_area->verticalScrollBar(), &QScrollBar::setValue); connect(scroll_area->verticalScrollBar(), &QScrollBar::valueChanged, vertical_scrollbar_, &QScrollBar::setValue); connect(scroll_area->verticalScrollBar(), &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue); connect(vertical_scrollbar_, &QScrollBar::valueChanged, scroll_area->verticalScrollBar(), &QScrollBar::setValue); connect(vertical_scrollbar_, &QScrollBar::valueChanged, keyframe_view_->verticalScrollBar(), &QScrollBar::setValue); // TimeBasedWidget's scrollbar has extra functionality that we can take advantage of keyframe_view_->setHorizontalScrollBar(scrollbar()); keyframe_view_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); connect(keyframe_view_->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); // Set a default scale - FIXME: Hardcoded SetScale(120); SetMaximumScale(TimelineViewBase::kMaximumScale); } void NodeParamView::SetNodes(QList nodes) { // If we already have item widgets, delete them all now foreach (NodeParamViewItem* item, items_) { emit ClosedNode(item->GetNode()); emit FoundGizmos(nullptr); item->deleteLater(); } items_.clear(); // Reset keyframe view keyframe_view_->Clear(); // Set the internal list to the one we've received nodes_ = nodes; if (!nodes_.isEmpty()) { // For each node, create a widget bool found_gizmos = false; foreach (Node* node, nodes_) { NodeParamViewItem* item = new NodeParamViewItem(node); // Insert the widget before the stretch param_layout_->insertWidget(param_layout_->count() - 1, item); connect(item, &NodeParamViewItem::KeyframeAdded, keyframe_view_, &KeyframeView::AddKeyframe); connect(item, &NodeParamViewItem::KeyframeRemoved, keyframe_view_, &KeyframeView::RemoveKeyframe); connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged); connect(item, &NodeParamViewItem::InputDoubleClicked, this, &NodeParamView::InputDoubleClicked); connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode); items_.append(item); emit OpenedNode(node); if (!found_gizmos && node->HasGizmos()) { emit FoundGizmos(node); found_gizmos = true; } } UpdateItemTime(GetTimestamp()); QMetaObject::invokeMethod(this, "PlaceKeyframesOnView", Qt::QueuedConnection); } } void NodeParamView::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); vertical_scrollbar_->setPageStep(vertical_scrollbar_->height()); } void NodeParamView::ScaleChangedEvent(const double &scale) { TimeBasedWidget::ScaleChangedEvent(scale); keyframe_view_->SetScale(scale); } void NodeParamView::TimebaseChangedEvent(const rational &timebase) { TimeBasedWidget::TimebaseChangedEvent(timebase); keyframe_view_->SetTimebase(timebase); UpdateItemTime(GetTimestamp()); } void NodeParamView::TimeChangedEvent(const int64_t ×tamp) { TimeBasedWidget::TimeChangedEvent(timestamp); keyframe_view_->SetTime(timestamp); UpdateItemTime(timestamp); } void NodeParamView::ConnectedNodeChanged(ViewerOutput *n) { // Set viewer as a time target keyframe_view_->SetTimeTarget(n); foreach (NodeParamViewItem* item, items_) { item->SetTimeTarget(n); } } const QList &NodeParamView::nodes() { return nodes_; } Node *NodeParamView::GetTimeTarget() const { return keyframe_view_->GetTimeTarget(); } void NodeParamView::DeleteSelected() { keyframe_view_->DeleteSelected(); } void NodeParamView::UpdateItemTime(const int64_t ×tamp) { rational time = Timecode::timestamp_to_time(timestamp, timebase()); foreach (NodeParamViewItem* item, items_) { item->SetTime(time); } } void NodeParamView::ItemRequestedTimeChanged(const rational &time) { SetTimeAndSignal(Timecode::time_to_timestamp(time, keyframe_view_->timebase())); } void NodeParamView::ForceKeyframeViewToScroll() { keyframe_view_->SetMaxScroll(param_widget_area_->height() - ruler()->height()); } void NodeParamView::PlaceKeyframesOnView() { foreach (NodeParamViewItem* item, items_) { QMetaObject::invokeMethod(item, "SignalAllKeyframes", Qt::QueuedConnection); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamview.h000066400000000000000000000042151370472574300243340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEW_H #define NODEPARAMVIEW_H #include #include #include "node/node.h" #include "nodeparamviewitem.h" #include "widget/keyframeview/keyframeview.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER class NodeParamView : public TimeBasedWidget { Q_OBJECT public: NodeParamView(QWidget* parent = nullptr); void SetNodes(QList nodes); const QList& nodes(); Node* GetTimeTarget() const; void DeleteSelected(); signals: void InputDoubleClicked(NodeInput* input); void RequestSelectNode(const QList& target); void OpenedNode(Node* n); void ClosedNode(Node* n); void FoundGizmos(Node* n); protected: virtual void resizeEvent(QResizeEvent *event) override; virtual void ScaleChangedEvent(const double &) override; virtual void TimebaseChangedEvent(const rational&) override; virtual void TimeChangedEvent(const int64_t &) override; virtual void ConnectedNodeChanged(ViewerOutput* n) override; private: void UpdateItemTime(const int64_t ×tamp); QVBoxLayout* param_layout_; KeyframeView* keyframe_view_; QList nodes_; QList items_; QScrollBar* vertical_scrollbar_; int last_scroll_val_; QWidget* param_widget_area_; private slots: void ItemRequestedTimeChanged(const rational& time); void ForceKeyframeViewToScroll(); void PlaceKeyframesOnView(); }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEW_H olive-continuous/app/widget/nodeparamview/nodeparamviewarraywidget.cpp000066400000000000000000000031161370472574300271310ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewarraywidget.h" #include OLIVE_NAMESPACE_ENTER NodeParamViewArrayWidget::NodeParamViewArrayWidget(NodeInputArray* array, QWidget* parent) : QWidget(parent), array_(array) { QHBoxLayout* layout = new QHBoxLayout(this); count_lbl_ = new QLabel(); layout->addWidget(count_lbl_); layout->addStretch(); plus_btn_ = new QPushButton(tr("+")); plus_btn_->setFixedWidth(plus_btn_->sizeHint().height()); layout->addWidget(plus_btn_); connect(plus_btn_, &QPushButton::clicked, this, &NodeParamViewArrayWidget::AddElement); connect(array_, &NodeInputArray::SizeChanged, this, &NodeParamViewArrayWidget::UpdateCounter); UpdateCounter(); } void NodeParamViewArrayWidget::UpdateCounter() { count_lbl_->setText(tr("%1 elements").arg(array_->GetSize())); } void NodeParamViewArrayWidget::AddElement() { array_->Append(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewarraywidget.h000066400000000000000000000023501370472574300265750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWARRAYWIDGET_H #define NODEPARAMVIEWARRAYWIDGET_H #include #include #include #include "node/inputarray.h" OLIVE_NAMESPACE_ENTER class NodeParamViewArrayWidget : public QWidget { Q_OBJECT public: NodeParamViewArrayWidget(NodeInputArray* array, QWidget* parent = nullptr); private: NodeInputArray* array_; QLabel* count_lbl_; QPushButton* plus_btn_; private slots: void UpdateCounter(); void AddElement(); }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWARRAYWIDGET_H olive-continuous/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp000066400000000000000000000054031370472574300275520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewconnectedlabel.h" #include #include "common/qtutils.h" #include "core.h" #include "node/node.h" #include "widget/menu/menu.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER NodeParamViewConnectedLabel::NodeParamViewConnectedLabel(NodeInput *input, QWidget *parent) : QWidget(parent), input_(input) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(QFontMetricsWidth(fontMetrics(), QStringLiteral(" "))); layout->setMargin(0); layout->addWidget(new QLabel(tr("Connected to"))); connected_to_lbl_ = new ClickableLabel(); connected_to_lbl_->setCursor(Qt::PointingHandCursor); connected_to_lbl_->setContextMenuPolicy(Qt::CustomContextMenu); connect(connected_to_lbl_, &ClickableLabel::MouseClicked, this, &NodeParamViewConnectedLabel::ConnectionClicked); connect(connected_to_lbl_, &ClickableLabel::customContextMenuRequested, this, &NodeParamViewConnectedLabel::ShowLabelContextMenu); layout->addWidget(connected_to_lbl_); layout->addStretch(); // Set up "link" font QFont link_font = connected_to_lbl_->font(); link_font.setUnderline(true); connected_to_lbl_->setForegroundRole(QPalette::Link); connected_to_lbl_->setFont(link_font); UpdateConnected(); connect(input_, &NodeInput::EdgeAdded, this, &NodeParamViewConnectedLabel::UpdateConnected); connect(input_, &NodeInput::EdgeRemoved, this, &NodeParamViewConnectedLabel::UpdateConnected); } void NodeParamViewConnectedLabel::UpdateConnected() { QString connection_str; if (input_->is_connected()) { connection_str = input_->get_connected_node()->Name(); } else { connection_str = tr("Nothing"); } connected_to_lbl_->setText(connection_str); } void NodeParamViewConnectedLabel::ShowLabelContextMenu() { Menu m(this); QAction* disconnect_action = m.addAction(tr("Disconnect")); connect(disconnect_action, &QAction::triggered, this, [this](){ Core::instance()->undo_stack()->push(new NodeEdgeRemoveCommand(input_->get_connected_output(), input_)); }); m.exec(QCursor::pos()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewconnectedlabel.h000066400000000000000000000024031370472574300272140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWCONNECTEDLABEL_H #define NODEPARAMVIEWCONNECTEDLABEL_H #include "node/input.h" #include "widget/clickablelabel/clickablelabel.h" OLIVE_NAMESPACE_ENTER class NodeParamViewConnectedLabel : public QWidget { Q_OBJECT public: NodeParamViewConnectedLabel(NodeInput* input, QWidget* parent = nullptr); signals: void ConnectionClicked(); private slots: void UpdateConnected(); void ShowLabelContextMenu(); private: ClickableLabel* connected_to_lbl_; NodeInput* input_; }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWCONNECTEDLABEL_H olive-continuous/app/widget/nodeparamview/nodeparamviewitem.cpp000066400000000000000000000271371370472574300255560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewitem.h" #include #include #include #include #include "core.h" #include "nodeparamviewundo.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER NodeParamViewItem::NodeParamViewItem(Node *node, QWidget *parent) : QWidget(parent), node_(node) { QVBoxLayout* main_layout = new QVBoxLayout(this); main_layout->setSpacing(0); main_layout->setMargin(0); // Create title bar widget title_bar_ = new NodeParamViewItemTitleBar(this); title_bar_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); QHBoxLayout* title_bar_layout = new QHBoxLayout(title_bar_); title_bar_collapse_btn_ = new CollapseButton(); title_bar_layout->addWidget(title_bar_collapse_btn_); title_bar_lbl_ = new QLabel(title_bar_); title_bar_layout->addWidget(title_bar_lbl_); // Add title bar to widget main_layout->addWidget(title_bar_); // Create and add contents widget QVector inputs; // Filter out inputs foreach (NodeParam* p, node->parameters()) { if (p->type() == NodeParam::kInput) { inputs.append(static_cast(p)); } } body_ = new NodeParamViewItemBody(inputs); connect(body_, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItem::InputDoubleClicked); connect(body_, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItem::RequestSelectNode); connect(body_, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItem::RequestSetTime); connect(body_, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItem::KeyframeAdded); connect(body_, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItem::KeyframeRemoved); connect(title_bar_collapse_btn_, &QPushButton::toggled, body_, &NodeParamViewItemBody::setVisible); main_layout->addWidget(body_); connect(node_, &Node::LabelChanged, this, &NodeParamViewItem::Retranslate); Retranslate(); } void NodeParamViewItem::SetTimeTarget(Node *target) { body_->SetTimeTarget(target); } void NodeParamViewItem::SetTime(const rational &time) { time_ = time; body_->SetTime(time_); } Node *NodeParamViewItem::GetNode() const { return node_; } void NodeParamViewItem::SignalAllKeyframes() { body_->SignalAllKeyframes(); } void NodeParamViewItem::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); } QWidget::changeEvent(e); } void NodeParamViewItem::Retranslate() { node_->Retranslate(); if (node_->GetLabel().isEmpty()) { title_bar_lbl_->setText(node_->Name()); } else { title_bar_lbl_->setText(tr("%1 (%2)").arg(node_->GetLabel(), node_->Name())); } body_->Retranslate(); } NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) : QWidget(parent) { } void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QPainter p(this); // Draw bottom border using text color int bottom = height() - 1; p.setPen(palette().text().color()); p.drawLine(0, bottom, width(), bottom); } NodeParamViewItemBody::NodeParamViewItemBody(const QVector &inputs, QWidget *parent) : QWidget(parent) { int row_count = 0; const int max_col = 10; QGridLayout* content_layout = new QGridLayout(this); foreach (NodeInput* input, inputs) { InputUI ui_objects; // Add descriptor label ui_objects.main_label = new ClickableLabel(); connect(ui_objects.main_label, &ClickableLabel::MouseDoubleClicked, this, &NodeParamViewItemBody::LabelDoubleClicked); if (input->IsArray()) { QHBoxLayout* array_label_layout = new QHBoxLayout(); array_label_layout->setMargin(0); CollapseButton* array_collapse_btn = new CollapseButton(); array_label_layout->addWidget(array_collapse_btn); array_label_layout->addWidget(ui_objects.main_label); content_layout->addLayout(array_label_layout, row_count, 0); NodeParamViewItemBody* sub_body = new NodeParamViewItemBody(static_cast(input)->sub_params()); sub_bodies_.append(sub_body); sub_body->layout()->setMargin(0); content_layout->addWidget(sub_body, row_count + 1, 0, 1, max_col + 1); connect(array_collapse_btn, &CollapseButton::toggled, sub_body, &NodeParamViewItemBody::setVisible); connect(sub_body, &NodeParamViewItemBody::KeyframeAdded, this, &NodeParamViewItemBody::KeyframeAdded); connect(sub_body, &NodeParamViewItemBody::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved); connect(sub_body, &NodeParamViewItemBody::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime); connect(sub_body, &NodeParamViewItemBody::InputDoubleClicked, this, &NodeParamViewItemBody::InputDoubleClicked); connect(sub_body, &NodeParamViewItemBody::RequestSelectNode, this, &NodeParamViewItemBody::RequestSelectNode); } else { content_layout->addWidget(ui_objects.main_label, row_count, 0); } // Create a widget/input bridge for this input ui_objects.widget_bridge = new NodeParamViewWidgetBridge(input, this); // Add widgets for this parameter to the layout { int column = 1; foreach (QWidget* w, ui_objects.widget_bridge->widgets()) { content_layout->addWidget(w, row_count, column); column++; } } if (input->is_connectable()) { // Create clickable label used when an input is connected ui_objects.connected_label = new NodeParamViewConnectedLabel(input); connect(ui_objects.connected_label, &NodeParamViewConnectedLabel::ConnectionClicked, this, &NodeParamViewItemBody::ConnectionClicked); content_layout->addWidget(ui_objects.connected_label, row_count, 1); connect(input, &NodeInput::EdgeAdded, this, &NodeParamViewItemBody::EdgeChanged); connect(input, &NodeInput::EdgeRemoved, this, &NodeParamViewItemBody::EdgeChanged); } // Add keyframe control to this layout if parameter is keyframable if (input->is_keyframable()) { // Hacky but effective way to make sure this widget is always as far right as possible int control_column = max_col; ui_objects.key_control = new NodeParamViewKeyframeControl(); ui_objects.key_control->SetInput(input); content_layout->addWidget(ui_objects.key_control, row_count, control_column); connect(ui_objects.key_control, &NodeParamViewKeyframeControl::RequestSetTime, this, &NodeParamViewItemBody::RequestSetTime); connect(input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItemBody::InputKeyframeEnableChanged); connect(input, &NodeInput::KeyframeAdded, this, &NodeParamViewItemBody::InputAddedKeyframe); connect(input, &NodeInput::KeyframeRemoved, this, &NodeParamViewItemBody::KeyframeRemoved); } input_ui_map_.insert(input, ui_objects); // Update "connected" label if (input->is_connectable()) { UpdateUIForEdgeConnection(input); } row_count++; // If the row count is an array, we put an extra body widget in the next row so we skip over it here if (input->IsArray()) { row_count++; } } } void NodeParamViewItemBody::SetTimeTarget(Node *target) { foreach (const InputUI& ui_obj, input_ui_map_) { // Only keyframable inputs have a key control widget if (ui_obj.key_control) { ui_obj.key_control->SetTimeTarget(target); } ui_obj.widget_bridge->SetTimeTarget(target); } foreach (NodeParamViewItemBody* sb, sub_bodies_) { sb->SetTimeTarget(target); } } void NodeParamViewItemBody::SetTime(const rational &time) { foreach (const InputUI& ui_obj, input_ui_map_) { // Only keyframable inputs have a key control widget if (ui_obj.key_control) { ui_obj.key_control->SetTime(time); } ui_obj.widget_bridge->SetTime(time); } foreach (NodeParamViewItemBody* sb, sub_bodies_) { sb->SetTime(time); } } void NodeParamViewItemBody::Retranslate() { QMap::const_iterator i; for (i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) { i.value().main_label->setText(tr("%1:").arg(i.key()->name())); } foreach (NodeParamViewItemBody* sb, sub_bodies_) { sb->Retranslate(); } } void NodeParamViewItemBody::SignalAllKeyframes() { QMap::const_iterator i; for (i=input_ui_map_.begin(); i!=input_ui_map_.end(); i++) { NodeInput* input = i.key(); foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) { foreach (NodeKeyframePtr key, track) { InputAddedKeyframeInternal(input, key); } } } foreach (NodeParamViewItemBody* sb, sub_bodies_) { sb->SignalAllKeyframes(); } } void NodeParamViewItemBody::EdgeChanged() { UpdateUIForEdgeConnection(static_cast(sender())); } void NodeParamViewItemBody::UpdateUIForEdgeConnection(NodeInput *input) { // Show/hide bridge widgets const InputUI& ui_objects = input_ui_map_[input]; foreach (QWidget* w, ui_objects.widget_bridge->widgets()) { w->setVisible(!input->is_connected()); } // Show/hide connection label ui_objects.connected_label->setVisible(input->is_connected()); } void NodeParamViewItemBody::InputKeyframeEnableChanged(bool e) { NodeInput* input = static_cast(sender()); foreach (const NodeInput::KeyframeTrack& track, input->keyframe_tracks()) { foreach (NodeKeyframePtr key, track) { if (e) { // Add a keyframe item for each keyframe InputAddedKeyframeInternal(input, key); } else { // Remove each keyframe item emit KeyframeRemoved(key); } } } } void NodeParamViewItemBody::InputAddedKeyframe(NodeKeyframePtr key) { // Get NodeInput that emitted this signal NodeInput* input = static_cast(sender()); InputAddedKeyframeInternal(input, key); } void NodeParamViewItemBody::LabelDoubleClicked() { QMap::const_iterator iterator; for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) { if (iterator.value().main_label == sender()) { emit InputDoubleClicked(iterator.key()); return; } } } void NodeParamViewItemBody::ConnectionClicked() { QMap::const_iterator iterator; for (iterator=input_ui_map_.begin(); iterator!=input_ui_map_.end(); iterator++) { if (iterator.value().connected_label == sender()) { Node* connected = iterator.key()->get_connected_node(); if (connected) { emit RequestSelectNode({connected}); } return; } } } void NodeParamViewItemBody::InputAddedKeyframeInternal(NodeInput *input, NodeKeyframePtr keyframe) { // Find its row in the parameters QLabel* lbl = input_ui_map_.value(input).main_label; // Find label's Y position QPoint lbl_center = lbl->rect().center(); // Find global position lbl_center = lbl->mapToGlobal(lbl_center); emit KeyframeAdded(keyframe, lbl_center.y()); } NodeParamViewItemBody::InputUI::InputUI() : main_label(nullptr), widget_bridge(nullptr), connected_label(nullptr), key_control(nullptr) { } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewitem.h000066400000000000000000000064561370472574300252240ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWITEM_H #define NODEPARAMVIEWITEM_H #include #include #include #include #include #include "node/node.h" #include "nodeparamviewconnectedlabel.h" #include "nodeparamviewkeyframecontrol.h" #include "nodeparamviewwidgetbridge.h" #include "widget/clickablelabel/clickablelabel.h" #include "widget/collapsebutton/collapsebutton.h" OLIVE_NAMESPACE_ENTER class NodeParamViewItemTitleBar : public QWidget { public: NodeParamViewItemTitleBar(QWidget* parent = nullptr); protected: virtual void paintEvent(QPaintEvent *event) override; }; class NodeParamViewItemBody : public QWidget { Q_OBJECT public: NodeParamViewItemBody(const QVector& inputs, QWidget* parent = nullptr); void SetTimeTarget(Node* target); void SetTime(const rational& time); void Retranslate(); void SignalAllKeyframes(); signals: void KeyframeAdded(NodeKeyframePtr key, int y); void KeyframeRemoved(NodeKeyframePtr key); void RequestSetTime(const rational& time); void InputDoubleClicked(NodeInput* input); void RequestSelectNode(const QList& node); private: void UpdateUIForEdgeConnection(NodeInput* input); void InputAddedKeyframeInternal(NodeInput* input, NodeKeyframePtr keyframe); struct InputUI { InputUI(); ClickableLabel* main_label; NodeParamViewWidgetBridge* widget_bridge; NodeParamViewConnectedLabel* connected_label; NodeParamViewKeyframeControl* key_control; }; QMap input_ui_map_; QVector sub_bodies_; private slots: void EdgeChanged(); void InputKeyframeEnableChanged(bool e); void InputAddedKeyframe(NodeKeyframePtr key); void LabelDoubleClicked(); void ConnectionClicked(); }; class NodeParamViewItem : public QWidget { Q_OBJECT public: NodeParamViewItem(Node* node, QWidget* parent = nullptr); void SetTimeTarget(Node* target); void SetTime(const rational& time); Node* GetNode() const; public slots: void SignalAllKeyframes(); signals: void KeyframeAdded(NodeKeyframePtr key, int y); void KeyframeRemoved(NodeKeyframePtr key); void RequestSetTime(const rational& time); void InputDoubleClicked(NodeInput* input); void RequestSelectNode(const QList& node); protected: virtual void changeEvent(QEvent *e) override; private: NodeParamViewItemTitleBar* title_bar_; QLabel* title_bar_lbl_; CollapseButton* title_bar_collapse_btn_; NodeParamViewItemBody* body_; Node* node_; rational time_; private slots: void Retranslate(); }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWITEM_H olive-continuous/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp000066400000000000000000000221161370472574300300140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewkeyframecontrol.h" #include #include #include "core.h" #include "nodeparamviewundo.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(bool right_align, QWidget *parent) : QWidget(parent), input_(nullptr) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); if (right_align) { // Automatically right aligns all buttons layout->addStretch(); } prev_key_btn_ = CreateNewToolButton(icon::TriLeft); prev_key_btn_->setIconSize(prev_key_btn_->iconSize() / 2); layout->addWidget(prev_key_btn_); toggle_key_btn_ = CreateNewToolButton(icon::Diamond); toggle_key_btn_->setCheckable(true); toggle_key_btn_->setIconSize(toggle_key_btn_->iconSize() / 2); layout->addWidget(toggle_key_btn_); next_key_btn_ = CreateNewToolButton(icon::TriRight); next_key_btn_->setIconSize(next_key_btn_->iconSize() / 2); layout->addWidget(next_key_btn_); enable_key_btn_ = CreateNewToolButton(icon::Clock); enable_key_btn_->setCheckable(true); enable_key_btn_->setIconSize(enable_key_btn_->iconSize() / 4 * 3); layout->addWidget(enable_key_btn_); connect(prev_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::GoToPreviousKey); connect(next_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::GoToNextKey); connect(toggle_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::ToggleKeyframe); connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable); connect(enable_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::KeyframeEnableChanged); // Set defaults SetInput(nullptr); ShowButtonsFromKeyframeEnable(false); } NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const { return input_; } void NodeParamViewKeyframeControl::SetInput(NodeInput *input) { if (input_ != nullptr) { disconnect(input_, &NodeInput::KeyframeEnableChanged, enable_key_btn_, &QPushButton::setChecked); disconnect(input_, &NodeInput::KeyframeAdded, this, &NodeParamViewKeyframeControl::UpdateState); disconnect(input_, &NodeInput::KeyframeRemoved, this, &NodeParamViewKeyframeControl::UpdateState); } input_ = input; SetButtonsEnabled(input_); // Pick up keyframing value enable_key_btn_->setChecked(input_ && input_->is_keyframing()); // Update buttons UpdateState(); if (input_ != nullptr) { connect(input_, &NodeInput::KeyframeEnableChanged, enable_key_btn_, &QPushButton::setChecked); connect(input_, &NodeInput::KeyframeAdded, this, &NodeParamViewKeyframeControl::UpdateState); connect(input_, &NodeInput::KeyframeRemoved, this, &NodeParamViewKeyframeControl::UpdateState); } } void NodeParamViewKeyframeControl::SetTime(const rational &time) { time_ = time; UpdateState(); } QPushButton *NodeParamViewKeyframeControl::CreateNewToolButton(const QIcon& icon) const { QPushButton* btn = new QPushButton(); btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); btn->setIcon(icon); return btn; } void NodeParamViewKeyframeControl::SetButtonsEnabled(bool e) { prev_key_btn_->setEnabled(e); toggle_key_btn_->setEnabled(e); next_key_btn_->setEnabled(e); enable_key_btn_->setEnabled(e); } rational NodeParamViewKeyframeControl::GetCurrentTimeAsNodeTime() const { return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput); } rational NodeParamViewKeyframeControl::ConvertToViewerTime(const rational &r) const { return GetAdjustedTime(input_->parentNode(), GetTimeTarget(), r, NodeParam::kOutput); } void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e) { prev_key_btn_->setVisible(e); toggle_key_btn_->setVisible(e); next_key_btn_->setVisible(e); } void NodeParamViewKeyframeControl::ToggleKeyframe(bool e) { rational node_time = GetCurrentTimeAsNodeTime(); QList keys = input_->get_keyframe_at_time(node_time); QUndoCommand* command = new QUndoCommand(); if (e && keys.isEmpty()) { // Add a keyframe here (one for each track) for (int i=0;iget_number_of_keyframe_tracks();i++) { NodeKeyframePtr key = NodeKeyframe::Create(node_time, input_->get_value_at_time_for_track(node_time, i), input_->get_best_keyframe_type_for_time(node_time, i), i); new NodeParamInsertKeyframeCommand(input_, key, command); } } else if (!e && !keys.isEmpty()) { // Remove all keyframes at this time foreach (NodeKeyframePtr key, keys) { new NodeParamRemoveKeyframeCommand(input_, key, command); if (input_->keyframe_tracks().at(key->track()).size() == 1) { // If this was the last keyframe on this track, set the standard value to the value at this time too new NodeParamSetStandardValueCommand(input_, key->track(), input_->get_value_at_time_for_track(node_time, key->track()), command); } } } Core::instance()->undo_stack()->pushIfHasChildren(command); } void NodeParamViewKeyframeControl::UpdateState() { if (!input_) { return; } NodeKeyframePtr earliest_key = input_->get_earliest_keyframe(); NodeKeyframePtr latest_key = input_->get_latest_keyframe(); rational node_time = GetCurrentTimeAsNodeTime(); prev_key_btn_->setEnabled(earliest_key && node_time > earliest_key->time()); next_key_btn_->setEnabled(latest_key && node_time < latest_key->time()); toggle_key_btn_->setChecked(input_->has_keyframe_at_time(node_time)); } void NodeParamViewKeyframeControl::GoToPreviousKey() { rational node_time = GetCurrentTimeAsNodeTime(); NodeKeyframePtr previous_key = input_->get_closest_keyframe_before_time(node_time); if (previous_key) { rational key_time = ConvertToViewerTime(previous_key->time()); emit RequestSetTime(key_time); } } void NodeParamViewKeyframeControl::GoToNextKey() { rational node_time = GetCurrentTimeAsNodeTime(); NodeKeyframePtr next_key = input_->get_closest_keyframe_after_time(node_time); if (next_key) { rational key_time = ConvertToViewerTime(next_key->time()); emit RequestSetTime(key_time); } } void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e) { if (e == input_->is_keyframing()) { // No-op return; } QUndoCommand* command = new QUndoCommand(); if (e) { // Enable keyframing new NodeParamSetKeyframingCommand(input_, true, command); // Create one keyframe across all tracks here QVector key_vals = input_->get_split_standard_value(); for (int i=0;i stored_vals = input_->get_split_values_at_time(GetCurrentTimeAsNodeTime()); // Delete all keyframes foreach (const NodeInput::KeyframeTrack& track, input_->keyframe_tracks()) { for (int i=track.size()-1;i>=0;i--) { new NodeParamRemoveKeyframeCommand(input_, track.at(i), command); } } // Update standard value for (int i=0;isetChecked(true); } } Core::instance()->undo_stack()->pushIfHasChildren(command); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h000066400000000000000000000036071370472574300274650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWKEYFRAMECONTROL_H #define NODEPARAMVIEWKEYFRAMECONTROL_H #include #include #include "node/input.h" #include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER class NodeParamViewKeyframeControl : public QWidget, public TimeTargetObject { Q_OBJECT public: NodeParamViewKeyframeControl(bool right_align = true, QWidget* parent = nullptr); NodeInput* GetConnectedInput() const; void SetInput(NodeInput* input); void SetTime(const rational& time); signals: void RequestSetTime(const rational& time); private: QPushButton* CreateNewToolButton(const QIcon &icon) const; void SetButtonsEnabled(bool e); rational GetCurrentTimeAsNodeTime() const; rational ConvertToViewerTime(const rational& r) const; QPushButton* prev_key_btn_; QPushButton* toggle_key_btn_; QPushButton* next_key_btn_; QPushButton* enable_key_btn_; NodeInput* input_; rational time_; private slots: void ShowButtonsFromKeyframeEnable(bool e); void ToggleKeyframe(bool e); void UpdateState(); void GoToPreviousKey(); void GoToNextKey(); void KeyframeEnableChanged(bool e); }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWKEYFRAMECONTROL_H olive-continuous/app/widget/nodeparamview/nodeparamviewrichtext.cpp000066400000000000000000000031611370472574300264410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewrichtext.h" #include #include #include "dialog/richtext/richtext.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER NodeParamViewRichText::NodeParamViewRichText(QWidget *parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); line_edit_ = new QLineEdit(); connect(line_edit_, &QLineEdit::textEdited, this, &NodeParamViewRichText::textEdited); layout->addWidget(line_edit_); QPushButton* edit_btn = new QPushButton(); edit_btn->setIcon(icon::ToolEdit); layout->addWidget(edit_btn); connect(edit_btn, &QPushButton::clicked, this, &NodeParamViewRichText::ShowRichTextDialog); } void NodeParamViewRichText::ShowRichTextDialog() { RichTextDialog d(line_edit_->text(), this); if (d.exec() == QDialog::Accepted) { QString s = d.text(); line_edit_->setText(s); emit textEdited(s); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewrichtext.h000066400000000000000000000027411370472574300261110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWRICHTEXT_H #define NODEPARAMVIEWRICHTEXT_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class NodeParamViewRichText : public QWidget { Q_OBJECT public: NodeParamViewRichText(QWidget* parent = nullptr); QString text() const { return line_edit_->text(); } public slots: void setText(const QString &s) { line_edit_->setText(s); } void setTextPreservingCursor(const QString &s) { int cursor_pos = line_edit_->cursorPosition(); line_edit_->setText(s); line_edit_->setCursorPosition(cursor_pos); } signals: void textEdited(const QString &); private: QLineEdit* line_edit_; private slots: void ShowRichTextDialog(); }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWRICHTEXT_H olive-continuous/app/widget/nodeparamview/nodeparamviewundo.cpp000066400000000000000000000123431370472574300255560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewundo.h" #include "node/node.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER NodeParamSetKeyframingCommand::NodeParamSetKeyframingCommand(NodeInput *input, bool setting, QUndoCommand *parent) : UndoCommand(parent), input_(input), setting_(setting) { Q_ASSERT(setting != input_->is_keyframing()); } Project *NodeParamSetKeyframingCommand::GetRelevantProject() const { return static_cast(input_->parentNode()->parent())->project(); } void NodeParamSetKeyframingCommand::redo_internal() { input_->set_is_keyframing(setting_); } void NodeParamSetKeyframingCommand::undo_internal() { input_->set_is_keyframing(!setting_); } NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& value, QUndoCommand* parent) : UndoCommand(parent), key_(key), old_value_(key_->value()), new_value_(value) { } NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant &new_value, const QVariant &old_value, QUndoCommand *parent) : UndoCommand(parent), key_(key), old_value_(old_value), new_value_(new_value) { } Project *NodeParamSetKeyframeValueCommand::GetRelevantProject() const { return static_cast(key_->parent()->parentNode()->parent())->project(); } void NodeParamSetKeyframeValueCommand::redo_internal() { key_->set_value(new_value_); } void NodeParamSetKeyframeValueCommand::undo_internal() { key_->set_value(old_value_); } NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, QUndoCommand* parent) : UndoCommand(parent), input_(input), keyframe_(keyframe), done_(false) { } NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, bool already_done, QUndoCommand *parent) : UndoCommand(parent), input_(input), keyframe_(keyframe), done_(already_done) { } Project *NodeParamInsertKeyframeCommand::GetRelevantProject() const { return static_cast(input_->parentNode()->parent())->project(); } void NodeParamInsertKeyframeCommand::redo_internal() { if (!done_) { input_->insert_keyframe(keyframe_); } } void NodeParamInsertKeyframeCommand::undo_internal() { input_->remove_keyframe(keyframe_); done_ = false; } NodeParamRemoveKeyframeCommand::NodeParamRemoveKeyframeCommand(NodeInput *input, NodeKeyframePtr keyframe, QUndoCommand *parent) : UndoCommand(parent), input_(input), keyframe_(keyframe) { } Project *NodeParamRemoveKeyframeCommand::GetRelevantProject() const { return static_cast(input_->parentNode()->parent())->project(); } void NodeParamRemoveKeyframeCommand::redo_internal() { input_->remove_keyframe(keyframe_); } void NodeParamRemoveKeyframeCommand::undo_internal() { input_->insert_keyframe(keyframe_); } NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational &time, QUndoCommand *parent) : UndoCommand(parent), key_(key), old_time_(key->time()), new_time_(time) { } NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational &new_time, const rational &old_time, QUndoCommand *parent) : UndoCommand(parent), key_(key), old_time_(old_time), new_time_(new_time) { } Project *NodeParamSetKeyframeTimeCommand::GetRelevantProject() const { return static_cast(key_->parent()->parentNode()->parent())->project(); } void NodeParamSetKeyframeTimeCommand::redo_internal() { key_->set_time(new_time_); } void NodeParamSetKeyframeTimeCommand::undo_internal() { key_->set_time(old_time_); } NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *input, int track, const QVariant &value, QUndoCommand *parent) : UndoCommand(parent), input_(input), track_(track), old_value_(input_->get_standard_value()), new_value_(value) { } NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(NodeInput *input, int track, const QVariant &new_value, const QVariant &old_value, QUndoCommand *parent) : UndoCommand(parent), input_(input), track_(track), old_value_(old_value), new_value_(new_value) { } Project *NodeParamSetStandardValueCommand::GetRelevantProject() const { return static_cast(input_->parentNode()->parent())->project(); } void NodeParamSetStandardValueCommand::redo_internal() { input_->set_standard_value(new_value_, track_); } void NodeParamSetStandardValueCommand::undo_internal() { input_->set_standard_value(old_value_, track_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewundo.h000066400000000000000000000075011370472574300252230ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWUNDO_H #define NODEPARAMVIEWUNDO_H #include "node/input.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER class NodeParamSetKeyframingCommand : public UndoCommand { public: NodeParamSetKeyframingCommand(NodeInput* input, bool setting, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeInput* input_; bool setting_; }; class NodeParamInsertKeyframeCommand : public UndoCommand { public: NodeParamInsertKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, QUndoCommand *parent = nullptr); NodeParamInsertKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, bool already_done, QUndoCommand *parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeInput* input_; NodeKeyframePtr keyframe_; bool done_; }; class NodeParamRemoveKeyframeCommand : public UndoCommand { public: NodeParamRemoveKeyframeCommand(NodeInput* input, NodeKeyframePtr keyframe, QUndoCommand *parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeInput* input_; NodeKeyframePtr keyframe_; }; class NodeParamSetKeyframeTimeCommand : public UndoCommand { public: NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational& time, QUndoCommand* parent = nullptr); NodeParamSetKeyframeTimeCommand(NodeKeyframePtr key, const rational& new_time, const rational& old_time, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeKeyframePtr key_; rational old_time_; rational new_time_; }; class NodeParamSetKeyframeValueCommand : public UndoCommand { public: NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& value, QUndoCommand* parent = nullptr); NodeParamSetKeyframeValueCommand(NodeKeyframePtr key, const QVariant& new_value, const QVariant& old_value, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeKeyframePtr key_; QVariant old_value_; QVariant new_value_; }; class NodeParamSetStandardValueCommand : public UndoCommand { public: NodeParamSetStandardValueCommand(NodeInput* input, int track, const QVariant& value, QUndoCommand* parent = nullptr); NodeParamSetStandardValueCommand(NodeInput* input, int track, const QVariant& new_value, const QVariant& old_value, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeInput* input_; int track_; QVariant old_value_; QVariant new_value_; }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWUNDO_H olive-continuous/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp000066400000000000000000000515061370472574300272550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeparamviewwidgetbridge.h" #include #include #include #include #include #include "core.h" #include "node/node.h" #include "nodeparamviewarraywidget.h" #include "nodeparamviewrichtext.h" #include "nodeparamviewundo.h" #include "project/item/sequence/sequence.h" #include "undo/undostack.h" #include "widget/colorbutton/colorbutton.h" #include "widget/footagecombobox/footagecombobox.h" #include "widget/slider/floatslider.h" #include "widget/slider/integerslider.h" OLIVE_NAMESPACE_ENTER NodeParamViewWidgetBridge::NodeParamViewWidgetBridge(NodeInput *input, QObject *parent) : QObject(parent), input_(input) { CreateWidgets(); connect(input_, &NodeInput::ValueChanged, this, &NodeParamViewWidgetBridge::InputValueChanged); connect(input_, &NodeInput::PropertyChanged, this, &NodeParamViewWidgetBridge::PropertyChanged); } void NodeParamViewWidgetBridge::SetTime(const rational &time) { time_ = time; if (input_) { UpdateWidgetValues(); } } const QList &NodeParamViewWidgetBridge::widgets() const { return widgets_; } void NodeParamViewWidgetBridge::CreateWidgets() { if (input_->IsArray()) { NodeParamViewArrayWidget* w = new NodeParamViewArrayWidget(static_cast(input_)); widgets_.append(w); } else { // We assume the first data type is the "primary" type switch (input_->data_type()) { // None of these inputs have applicable UI widgets case NodeParam::kNone: case NodeParam::kAny: case NodeParam::kTexture: case NodeParam::kMatrix: case NodeParam::kRational: case NodeParam::kSamples: case NodeParam::kDecimal: case NodeParam::kNumber: case NodeParam::kString: case NodeParam::kBuffer: case NodeParam::kVector: case NodeParam::kShaderJob: case NodeParam::kSampleJob: case NodeParam::kGenerateJob: break; case NodeParam::kInt: { IntegerSlider* slider = new IntegerSlider(); slider->SetDefaultValue(input_->GetDefaultValue()); slider->SetLadderElementCount(2); widgets_.append(slider); connect(slider, &IntegerSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } case NodeParam::kFloat: { CreateSliders(1); break; } case NodeParam::kVec2: { CreateSliders(2); break; } case NodeParam::kVec3: { CreateSliders(3); break; } case NodeParam::kVec4: { CreateSliders(4); break; } case NodeParam::kCombo: { QComboBox* combobox = new QComboBox(); QStringList items = input_->get_combobox_strings(); foreach (const QString& s, items) { combobox->addItem(s); } widgets_.append(combobox); connect(combobox, static_cast(&QComboBox::currentIndexChanged), this, &NodeParamViewWidgetBridge::WidgetCallback); break; } case NodeParam::kFile: // FIXME: File selector break; case NodeParam::kColor: { // NOTE: Very convoluted way to get back to the project's color manager ColorButton* color_button = new ColorButton(static_cast(input_->parentNode()->parent())->project()->color_manager()); widgets_.append(color_button); connect(color_button, &ColorButton::ColorChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } case NodeParam::kText: { NodeParamViewRichText* line_edit = new NodeParamViewRichText(); widgets_.append(line_edit); connect(line_edit, &NodeParamViewRichText::textEdited, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } case NodeParam::kBoolean: { QCheckBox* check_box = new QCheckBox(); widgets_.append(check_box); connect(check_box, &QCheckBox::clicked, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } case NodeParam::kFont: { QFontComboBox* font_combobox = new QFontComboBox(); widgets_.append(font_combobox); connect(font_combobox, &QFontComboBox::currentFontChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } case NodeParam::kFootage: { FootageComboBox* footage_combobox = new FootageComboBox(); footage_combobox->SetRoot(static_cast(input_->parentNode()->parent())->project()->root()); connect(footage_combobox, &FootageComboBox::FootageChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); widgets_.append(footage_combobox); break; } } // Check all properties QHash::const_iterator iterator; for (iterator=input_->properties().begin();iterator!=input_->properties().end();iterator++) { PropertyChanged(iterator.key(), iterator.value()); } UpdateWidgetValues(); } } void NodeParamViewWidgetBridge::SetInputValue(const QVariant &value, int track) { QUndoCommand* command = new QUndoCommand(); SetInputValueInternal(value, track, command); Core::instance()->undo_stack()->pushIfHasChildren(command); } void NodeParamViewWidgetBridge::SetInputValueInternal(const QVariant &value, int track, QUndoCommand *command) { rational node_time = GetCurrentTimeAsNodeTime(); if (input_->is_keyframing()) { NodeKeyframePtr existing_key = input_->get_keyframe_at_time_on_track(node_time, track); if (existing_key) { new NodeParamSetKeyframeValueCommand(existing_key, value, command); } else { // No existing key, create a new one NodeKeyframePtr new_key = NodeKeyframe::Create(node_time, value, input_->get_best_keyframe_type_for_time(node_time, track), track); new NodeParamInsertKeyframeCommand(input_, new_key, command); } } else { new NodeParamSetStandardValueCommand(input_, track, value, command); } } void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant &value) { rational node_time = GetCurrentTimeAsNodeTime(); int slider_track = widgets_.indexOf(slider); if (slider->IsDragging()) { // While we're dragging, we block the input's normal signalling and create our own if (!dragger_.IsStarted()) { dragger_.Start(input_, node_time, slider_track); } dragger_.Drag(value); //input_->parentNode()->InvalidateVisible(input_, input_); } else if (dragger_.IsStarted()) { // We were dragging and just stopped dragger_.Drag(value); dragger_.End(); } else { // No drag was involved, we can just push the value SetInputValue(value, slider_track); } } void NodeParamViewWidgetBridge::WidgetCallback() { switch (input_->data_type()) { // None of these inputs have applicable UI widgets case NodeParam::kNone: case NodeParam::kAny: case NodeParam::kTexture: case NodeParam::kMatrix: case NodeParam::kSamples: case NodeParam::kRational: case NodeParam::kDecimal: case NodeParam::kNumber: case NodeParam::kString: case NodeParam::kVector: case NodeParam::kBuffer: case NodeParam::kShaderJob: case NodeParam::kSampleJob: case NodeParam::kGenerateJob: break; case NodeParam::kInt: { // Widget is a IntegerSlider IntegerSlider* slider = static_cast(sender()); ProcessSlider(slider, QVariant::fromValue(slider->GetValue())); break; } case NodeParam::kFloat: { // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); ProcessSlider(slider, slider->GetValue()); break; } case NodeParam::kVec2: { // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); ProcessSlider(slider, slider->GetValue()); break; } case NodeParam::kVec3: { // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); ProcessSlider(slider, slider->GetValue()); break; } case NodeParam::kVec4: { // Widget is a FloatSlider FloatSlider* slider = static_cast(sender()); ProcessSlider(slider, slider->GetValue()); break; } case NodeParam::kFile: // FIXME: File selector break; case NodeParam::kColor: { // Sender is a ColorButton ManagedColor c = static_cast(sender())->GetColor(); QUndoCommand* command = new QUndoCommand(); SetInputValueInternal(c.red(), 0, command); SetInputValueInternal(c.green(), 1, command); SetInputValueInternal(c.blue(), 2, command); SetInputValueInternal(c.alpha(), 3, command); input_->blockSignals(true); input_->set_property(QStringLiteral("col_input"), c.color_input()); input_->set_property(QStringLiteral("col_display"), c.color_output().display()); input_->set_property(QStringLiteral("col_view"), c.color_output().view()); input_->set_property(QStringLiteral("col_look"), c.color_output().look()); input_->blockSignals(false); Core::instance()->undo_stack()->pushIfHasChildren(command); break; } case NodeParam::kText: { // Sender is a NodeParamViewRichText SetInputValue(static_cast(sender())->text(), 0); break; } case NodeParam::kBoolean: { // Widget is a QCheckBox SetInputValue(static_cast(sender())->isChecked(), 0); break; } case NodeParam::kFont: { // Widget is a QFontComboBox SetInputValue(static_cast(sender())->currentFont().family(), 0); break; } case NodeParam::kFootage: { // Widget is a FootageComboBox SetInputValue(QVariant::fromValue(static_cast(sender())->SelectedFootage()), 0); break; } case NodeParam::kCombo: { // Widget is a QComboBox QComboBox* cb = static_cast(widgets_.first()); int index = cb->currentIndex(); // Subtract any splitters up until this point for (int i=index-1; i>=0; i--) { if (cb->itemData(i, Qt::AccessibleDescriptionRole).toString() == QStringLiteral("separator")) { index--; } } SetInputValue(index, 0); break; } } } void NodeParamViewWidgetBridge::CreateSliders(int count) { for (int i=0;iSetDefaultValue(input_->GetDefaultValueForTrack(i)); fs->SetLadderElementCount(2); widgets_.append(fs); connect(fs, &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); } } void NodeParamViewWidgetBridge::UpdateWidgetValues() { if (input_->IsArray()) { return; } rational node_time = GetCurrentTimeAsNodeTime(); // We assume the first data type is the "primary" type switch (input_->data_type()) { // None of these inputs have applicable UI widgets case NodeParam::kNone: case NodeParam::kAny: case NodeParam::kTexture: case NodeParam::kMatrix: case NodeParam::kRational: case NodeParam::kSamples: case NodeParam::kDecimal: case NodeParam::kNumber: case NodeParam::kString: case NodeParam::kBuffer: case NodeParam::kShaderJob: case NodeParam::kSampleJob: case NodeParam::kGenerateJob: case NodeParam::kVector: break; case NodeParam::kInt: static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toLongLong()); break; case NodeParam::kFloat: static_cast(widgets_.first())->SetValue(input_->get_value_at_time(node_time).toDouble()); break; case NodeParam::kVec2: { QVector2D vec2 = input_->get_value_at_time(node_time).value(); static_cast(widgets_.at(0))->SetValue(static_cast(vec2.x())); static_cast(widgets_.at(1))->SetValue(static_cast(vec2.y())); break; } case NodeParam::kVec3: { QVector3D vec3 = input_->get_value_at_time(node_time).value(); static_cast(widgets_.at(0))->SetValue(static_cast(vec3.x())); static_cast(widgets_.at(1))->SetValue(static_cast(vec3.y())); static_cast(widgets_.at(2))->SetValue(static_cast(vec3.z())); break; } case NodeParam::kVec4: { QVector4D vec4 = input_->get_value_at_time(node_time).value(); static_cast(widgets_.at(0))->SetValue(static_cast(vec4.x())); static_cast(widgets_.at(1))->SetValue(static_cast(vec4.y())); static_cast(widgets_.at(2))->SetValue(static_cast(vec4.z())); static_cast(widgets_.at(3))->SetValue(static_cast(vec4.w())); break; } case NodeParam::kFile: // FIXME: File selector break; case NodeParam::kColor: { ManagedColor mc = input_->get_value_at_time(node_time).value(); mc.set_color_input(input_->get_property(QStringLiteral("col_input")).toString()); QString d = input_->get_property(QStringLiteral("col_display")).toString(); QString v = input_->get_property(QStringLiteral("col_view")).toString(); QString l = input_->get_property(QStringLiteral("col_look")).toString(); mc.set_color_output(ColorTransform(d, v, l)); static_cast(widgets_.first())->SetColor(mc); break; } case NodeParam::kText: { NodeParamViewRichText* e = static_cast(widgets_.first()); e->setTextPreservingCursor(input_->get_value_at_time(node_time).toString()); break; } case NodeParam::kBoolean: static_cast(widgets_.first())->setChecked(input_->get_value_at_time(node_time).toBool()); break; case NodeParam::kFont: { QFontComboBox* fc = static_cast(widgets_.first()); fc->blockSignals(true); fc->setCurrentFont(input_->get_value_at_time(node_time).toString()); fc->blockSignals(false); break; } case NodeParam::kCombo: { QComboBox* cb = static_cast(widgets_.first()); cb->blockSignals(true); cb->setCurrentIndex(input_->get_value_at_time(node_time).toInt()); cb->blockSignals(false); break; } case NodeParam::kFootage: static_cast(widgets_.first())->SetFootage(input_->get_value_at_time(node_time).value()); break; } } rational NodeParamViewWidgetBridge::GetCurrentTimeAsNodeTime() const { return GetAdjustedTime(GetTimeTarget(), input_->parentNode(), time_, NodeParam::kInput); } void NodeParamViewWidgetBridge::InputValueChanged(const TimeRange &range) { if (!dragger_.IsStarted() && range.in() <= time_ && range.out() >= time_) { // We'll need to update the widgets because the values have changed on our current time UpdateWidgetValues(); } } void NodeParamViewWidgetBridge::PropertyChanged(const QString &key, const QVariant &value) { // Parameters for vectors only if (input_->data_type() & NodeParam::kVector) { if (key == QStringLiteral("disablex")) { static_cast(widgets_.at(0))->setEnabled(!value.toBool()); } else if (key == QStringLiteral("disabley")) { static_cast(widgets_.at(1))->setEnabled(!value.toBool()); } else if (widgets_.size() > 2 && key == QStringLiteral("disablez")) { static_cast(widgets_.at(2))->setEnabled(!value.toBool()); } else if (widgets_.size() > 3 && key == QStringLiteral("disablew")) { static_cast(widgets_.at(3))->setEnabled(!value.toBool()); } } // Parameters for integers, floats, and vectors if (input_->data_type() & NodeParam::kNumber || input_->data_type() & NodeParam::kVector) { if (key == QStringLiteral("min")) { switch (input_->data_type()) { case NodeParam::kInt: static_cast(widgets_.first())->SetMinimum(value.value()); break; case NodeParam::kFloat: static_cast(widgets_.first())->SetMinimum(value.toDouble()); break; case NodeParam::kRational: // FIXME: Rational doesn't have a UI implementation yet break; case NodeParam::kVec2: { QVector2D min = value.value(); static_cast(widgets_.at(0))->SetMinimum(min.x()); static_cast(widgets_.at(1))->SetMinimum(min.y()); break; } case NodeParam::kVec3: { QVector3D min = value.value(); static_cast(widgets_.at(0))->SetMinimum(min.x()); static_cast(widgets_.at(1))->SetMinimum(min.y()); static_cast(widgets_.at(2))->SetMinimum(min.z()); break; } case NodeParam::kVec4: { QVector4D min = value.value(); static_cast(widgets_.at(0))->SetMinimum(min.x()); static_cast(widgets_.at(1))->SetMinimum(min.y()); static_cast(widgets_.at(2))->SetMinimum(min.z()); static_cast(widgets_.at(3))->SetMinimum(min.w()); break; } default: break; } } else if (key == QStringLiteral("max")) { switch (input_->data_type()) { case NodeParam::kInt: static_cast(widgets_.first())->SetMaximum(value.value()); break; case NodeParam::kFloat: static_cast(widgets_.first())->SetMaximum(value.toDouble()); break; case NodeParam::kRational: // FIXME: Rational doesn't have a UI implementation yet break; case NodeParam::kVec2: { QVector2D max = value.value(); static_cast(widgets_.at(0))->SetMaximum(max.x()); static_cast(widgets_.at(1))->SetMaximum(max.y()); break; } case NodeParam::kVec3: { QVector3D max = value.value(); static_cast(widgets_.at(0))->SetMaximum(max.x()); static_cast(widgets_.at(1))->SetMaximum(max.y()); static_cast(widgets_.at(2))->SetMaximum(max.z()); break; } case NodeParam::kVec4: { QVector4D max = value.value(); static_cast(widgets_.at(0))->SetMaximum(max.x()); static_cast(widgets_.at(1))->SetMaximum(max.y()); static_cast(widgets_.at(2))->SetMaximum(max.z()); static_cast(widgets_.at(3))->SetMaximum(max.w()); break; } default: break; } } } // ComboBox strings changing if (input_->data_type() & NodeParam::kCombo) { QComboBox* cb = static_cast(widgets_.first()); int old_index = cb->currentIndex(); // Block the combobox changed signals since we anticipate the index will be the same and not require a re-render cb->blockSignals(true); cb->clear(); QStringList items = input_->get_combobox_strings(); foreach (const QString& s, items) { if (s.isEmpty()) { cb->insertSeparator(cb->count()); } else { cb->addItem(s); } } cb->setCurrentIndex(old_index); cb->blockSignals(false); // In case the amount of items is LESS and the previous index cannot be set, NOW we trigger a re-cache since the // value has changed if (cb->currentIndex() != old_index) { WidgetCallback(); } } // Parameters for floats and vectors only if (input_->data_type() & NodeParam::kFloat || input_->data_type() & NodeParam::kVector) { if (key == QStringLiteral("view")) { FloatSlider::DisplayType display_type; if (value == QStringLiteral("percent")) { display_type = FloatSlider::kPercentage; } else if (value == QStringLiteral("db")) { display_type = FloatSlider::kDecibel; } else { // Avoid undefined behavior return; } foreach (QWidget* w, widgets_) { static_cast(w)->SetDisplayType(display_type); } } else if (key == QStringLiteral("decimalplaces")) { int dec_places = value.toInt(); foreach (QWidget* w, widgets_) { static_cast(w)->SetDecimalPlaces(dec_places); } } else if (key == QStringLiteral("autotrim")) { bool autotrim = value.toBool(); foreach (QWidget* w, widgets_) { static_cast(w)->SetAutoTrimDecimalPlaces(autotrim); } } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeparamview/nodeparamviewwidgetbridge.h000066400000000000000000000035351370472574300267210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEPARAMVIEWWIDGETBRIDGE_H #define NODEPARAMVIEWWIDGETBRIDGE_H #include #include "node/input.h" #include "node/inputdragger.h" #include "widget/slider/sliderbase.h" #include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER class NodeParamViewWidgetBridge : public QObject, public TimeTargetObject { Q_OBJECT public: NodeParamViewWidgetBridge(NodeInput* input, QObject* parent); void SetTime(const rational& time); const QList& widgets() const; private: void CreateWidgets(); void SetInputValue(const QVariant& value, int track); void SetInputValueInternal(const QVariant& value, int track, QUndoCommand* command); void ProcessSlider(SliderBase* slider, const QVariant& value); void CreateSliders(int count); void UpdateWidgetValues(); rational GetCurrentTimeAsNodeTime() const; NodeInput* input_; QList widgets_; rational time_; NodeInputDragger dragger_; private slots: void WidgetCallback(); void InputValueChanged(const TimeRange& range); void PropertyChanged(const QString& key, const QVariant& value); }; OLIVE_NAMESPACE_EXIT #endif // NODEPARAMVIEWWIDGETBRIDGE_H olive-continuous/app/widget/nodetableview/000077500000000000000000000000001370472574300213075ustar00rootroot00000000000000olive-continuous/app/widget/nodetableview/CMakeLists.txt000066400000000000000000000017631370472574300240560ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/nodetableview/nodetabletraverser.h widget/nodetableview/nodetabletraverser.cpp widget/nodetableview/nodetableview.h widget/nodetableview/nodetableview.cpp widget/nodetableview/nodetablewidget.h widget/nodetableview/nodetablewidget.cpp PARENT_SCOPE ) olive-continuous/app/widget/nodetableview/nodetabletraverser.cpp000066400000000000000000000031361370472574300257110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodetabletraverser.h" OLIVE_NAMESPACE_ENTER QVariant NodeTableTraverser::ProcessVideoFootage(StreamPtr stream, const rational &input_time) { ImageStreamPtr video_stream = std::static_pointer_cast(stream); return QVariant::fromValue(VideoParams(video_stream->width(), video_stream->height(), video_stream->timebase(), video_stream->format())); } QVariant NodeTableTraverser::ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time) { AudioStreamPtr audio_stream = std::static_pointer_cast(stream); return QVariant::fromValue(AudioParams(audio_stream->sample_rate(), audio_stream->channel_layout(), SampleFormat::kInternalFormat)); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodetableview/nodetabletraverser.h000066400000000000000000000022071370472574300253540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODETABLETRAVERSER_H #define NODETABLETRAVERSER_H #include "node/traverser.h" OLIVE_NAMESPACE_ENTER class NodeTableTraverser : public NodeTraverser { public: NodeTableTraverser() = default; protected: virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time); virtual QVariant ProcessAudioFootage(StreamPtr stream, const TimeRange &input_time); }; OLIVE_NAMESPACE_EXIT #endif // NODETABLETRAVERSER_H olive-continuous/app/widget/nodetableview/nodetableview.cpp000066400000000000000000000103031370472574300246400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodetableview.h" #include #include #include "node/param.h" #include "nodetabletraverser.h" OLIVE_NAMESPACE_ENTER NodeTableView::NodeTableView(QWidget* parent) : QTreeWidget(parent), last_set_node_(nullptr) { setColumnCount(3); setHeaderLabels({tr("Type"), tr("Source"), tr("R/X"), tr("G/Y"), tr("B/Z"), tr("A/W")}); } void NodeTableView::SetNode(Node *n, const rational &time) { if (last_set_node_ != n) { // Clear everything if the node has changed clear(); } last_set_node_ = n; NodeTableTraverser traverser; NodeValueDatabase db = traverser.GenerateDatabase(n, TimeRange(time, time)); // Remove top items if necessary for (int i=0;itopLevelItemCount();i++) { if (!db.contains(this->topLevelItem(i)->data(0, Qt::UserRole).toString())) { delete this->takeTopLevelItem(i); i--; } } NodeValueDatabase::const_iterator i; for (i=db.begin(); i!=db.end(); i++) { const NodeValueTable& table = i.value(); NodeInput* input = n->GetInputWithID(i.key()); if (!input) { // Filters out table entries that aren't inputs (like "global") continue; } QTreeWidgetItem* top_item = nullptr; for (int j=0;jtopLevelItemCount();j++) { QTreeWidgetItem* compare = this->topLevelItem(j); if (compare->data(0, Qt::UserRole).toString() == input->id()) { top_item = compare; break; } } if (!top_item) { top_item = new QTreeWidgetItem(); top_item->setText(0, input->name()); top_item->setData(0, Qt::UserRole, input->id()); top_item->setFirstColumnSpanned(true); this->addTopLevelItem(top_item); } // Create children if necessary while (top_item->childCount() < table.Count()) { top_item->addChild(new QTreeWidgetItem()); } // Remove children if necessary while (top_item->childCount() > table.Count()) { delete top_item->takeChild(top_item->childCount() - 1); } for (int j=0;jchild(j); // Set data type name sub_item->setText(0, NodeParam::GetPrettyDataTypeName(value.type())); // Determine source QString source_name; if (value.source()) { source_name = value.source()->Name(); } else { source_name = tr("(unknown)"); } sub_item->setText(1, source_name); switch (value.type()) { case NodeParam::kTexture: { // NodeTableTraverser puts video params in here VideoParams p = value.data().value(); int channel_count = PixelFormat::ChannelCount(p.format()); for (int k=0;ksetItemWidget(sub_item, 2 + k, new QCheckBox()); } break; } default: { QVector split_values = input->split_normal_value_into_track_values(value.data()); for (int k=0;ksetText(2 + k, NodeInput::ValueToString(value.type(), split_values.at(k))); } } } } } } void NodeTableView::SetMultipleNodeMessage() { this->clear(); QTreeWidgetItem* item = new QTreeWidgetItem(); item->setText(0, tr("Multiple nodes selected")); item->setFirstColumnSpanned(true); this->addTopLevelItem(item); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodetableview/nodetableview.h000066400000000000000000000021101370472574300243020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODETABLEVIEW_H #define NODETABLEVIEW_H #include #include "node/node.h" OLIVE_NAMESPACE_ENTER class NodeTableView : public QTreeWidget { public: NodeTableView(QWidget* parent = nullptr); void SetNode(Node* n, const rational& time); void SetMultipleNodeMessage(); private: Node* last_set_node_; }; OLIVE_NAMESPACE_EXIT #endif // NODETABLEVIEW_H olive-continuous/app/widget/nodetableview/nodetablewidget.cpp000066400000000000000000000032241370472574300251550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodetablewidget.h" #include OLIVE_NAMESPACE_ENTER NodeTableWidget::NodeTableWidget(QWidget* parent) : TimeBasedWidget(parent), node_(nullptr) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); view_ = new NodeTableView(); layout->addWidget(view_); } void NodeTableWidget::SetNodes(const QList &nodes) { node_ = nullptr; if (nodes.isEmpty()) { view_->clear(); } else if (nodes.size() == 1) { node_ = nodes.first(); ViewerOutput* viewer = node_->FindOutputNode(); if (viewer) { qDebug() << "Found timebase"; SetTimebase(viewer->video_params().time_base()); } UpdateView(); } else { view_->SetMultipleNodeMessage(); } } void NodeTableWidget::TimeChangedEvent(const int64_t &) { UpdateView(); } void NodeTableWidget::UpdateView() { if (node_) { view_->SetNode(node_, GetTime()); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodetableview/nodetablewidget.h000066400000000000000000000022641370472574300246250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODETABLEWIDGET_H #define NODETABLEWIDGET_H #include "nodetableview.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER class NodeTableWidget : public TimeBasedWidget { public: NodeTableWidget(QWidget* parent = nullptr); void SetNodes(const QList& nodes); protected: virtual void TimeChangedEvent(const int64_t& ts) override; private: void UpdateView(); NodeTableView* view_; Node* node_; }; OLIVE_NAMESPACE_EXIT #endif // NODETABLEWIDGET_H olive-continuous/app/widget/nodeview/000077500000000000000000000000001370472574300202775ustar00rootroot00000000000000olive-continuous/app/widget/nodeview/CMakeLists.txt000066400000000000000000000023001370472574300230320ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/nodeview/nodeview.h widget/nodeview/nodeview.cpp widget/nodeview/nodeviewcommon.h widget/nodeview/nodeviewedge.h widget/nodeview/nodeviewedge.cpp widget/nodeview/nodeviewitem.h widget/nodeview/nodeviewitem.cpp widget/nodeview/nodeviewitemwidgetproxy.h widget/nodeview/nodeviewitemwidgetproxy.cpp widget/nodeview/nodeviewscene.h widget/nodeview/nodeviewscene.cpp widget/nodeview/nodeviewundo.h widget/nodeview/nodeviewundo.cpp PARENT_SCOPE ) olive-continuous/app/widget/nodeview/nodeview.cpp000066400000000000000000000620761370472574300226360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeview.h" #include #include #include "core.h" #include "nodeviewundo.h" #include "node/factory.h" #include "widget/menu/menushared.h" #define super HandMovableView OLIVE_NAMESPACE_ENTER NodeView::NodeView(QWidget *parent) : HandMovableView(parent), graph_(nullptr), drop_edge_(nullptr), filter_mode_(kFilterShowSelectedBlocks), scale_(1.0) { setScene(&scene_); SetDefaultDragMode(RubberBandDrag); setContextMenuPolicy(Qt::CustomContextMenu); setMouseTracking(true); setRenderHint(QPainter::Antialiasing); setViewportUpdateMode(FullViewportUpdate); connect(&scene_, &QGraphicsScene::changed, this, &NodeView::ItemsChanged); connect(this, &NodeView::customContextMenuRequested, this, &NodeView::ShowContextMenu); ConnectSelectionChangedSignal(); SetFlowDirection(NodeViewCommon::kTopToBottom); // Set massive scene rect and hide the scrollbars to create an "infinite space" effect scene_.setSceneRect(-1000000, -1000000, 2000000, 2000000); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } NodeView::~NodeView() { // Unset the current graph SetGraph(nullptr); } void NodeView::SetGraph(NodeGraph *graph) { if (graph_ == graph) { return; } if (graph_ != nullptr) { disconnect(graph_, &NodeGraph::NodeAdded, &scene_, &NodeViewScene::AddNode); disconnect(graph_, &NodeGraph::NodeRemoved, &scene_, &NodeViewScene::RemoveNode); disconnect(graph_, &NodeGraph::EdgeAdded, this, &NodeView::GraphEdgeAdded); disconnect(graph_, &NodeGraph::EdgeRemoved, this, &NodeView::GraphEdgeRemoved); } // Clear the scene of all UI objects scene_.clear(); // Set reference to the graph graph_ = graph; scene_.SetGraph(graph_); // If the graph is valid, add UI objects for each of its Nodes if (graph_ != nullptr) { connect(graph_, &NodeGraph::NodeAdded, &scene_, &NodeViewScene::AddNode); connect(graph_, &NodeGraph::NodeRemoved, &scene_, &NodeViewScene::RemoveNode); connect(graph_, &NodeGraph::EdgeAdded, this, &NodeView::GraphEdgeAdded); connect(graph_, &NodeGraph::EdgeRemoved, this, &NodeView::GraphEdgeRemoved); foreach (Node* n, graph_->nodes()) { scene_.AddNode(n); } ValidateFilter(); } } void NodeView::DeleteSelected() { if (!graph_) { return; } QUndoCommand* command = new QUndoCommand(); { QList selected_edges = scene_.GetSelectedEdges(); foreach (NodeEdge* edge, selected_edges) { new NodeEdgeRemoveCommand(edge->output(), edge->input(), command); } } { QList selected_nodes = scene_.GetSelectedNodes(); // Ensure no nodes are "undeletable" for (int i=0;iCanBeDeleted()) { selected_nodes.removeAt(i); i--; } } if (!selected_nodes.isEmpty()) { new NodeRemoveCommand(graph_, selected_nodes, command); } } Core::instance()->undo_stack()->pushIfHasChildren(command); } void NodeView::SelectAll() { // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. DisconnectSelectionChangedSignal(); scene_.SelectAll(); ReconnectSelectionChangedSignal(); } void NodeView::DeselectAll() { // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. DisconnectSelectionChangedSignal(); scene_.DeselectAll(); ReconnectSelectionChangedSignal(); } void NodeView::Select(const QList &nodes) { if (!graph_) { return; } // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. DisconnectSelectionChangedSignal(); scene_.DeselectAll(); foreach (Node* n, nodes) { NodeViewItem* item = scene_.NodeToUIObject(n); item->setSelected(true); } ReconnectSelectionChangedSignal(); } void NodeView::SelectWithDependencies(QList nodes) { if (!graph_) { return; } int original_length = nodes.size(); for (int i=0;iGetDependencies()); } Select(nodes); } void NodeView::SelectBlocks(const QList &blocks) { if (selected_blocks_ == blocks) { return; } // Remove temporary associations foreach (Block* b, selected_blocks_) { if (!blocks.contains(b)) { temporary_association_map_.remove(b); } } selected_blocks_ = blocks; // Block scene signals while our selection is changing a lot scene_.blockSignals(true); if (filter_mode_ == kFilterShowSelectedBlocks) { UpdateBlockFilter(); } QList nodes; nodes.reserve(blocks.size()); foreach (Block* b, blocks) { nodes.append(b); nodes.append(b->GetDependencies()); } SelectWithDependencies(nodes); // Stop blocking signals and send a change signal now that all of our processing is done scene_.blockSignals(false); SceneSelectionChangedSlot(); if (!blocks.isEmpty()) { NodeViewItem* item = scene_.NodeToUIObject(blocks.first()); if (item) { centerOn(item); } } } void NodeView::CopySelected(bool cut) { if (!graph_) { return; } QList selected = scene_.GetSelectedNodes(); if (selected.isEmpty()) { return; } CopyNodesToClipboard(selected); if (cut) { DeleteSelected(); } } void NodeView::Paste() { if (!graph_) { return; } QUndoCommand* command = new QUndoCommand(); QList pasted_nodes = PasteNodesFromClipboard(static_cast(graph_), command); Core::instance()->undo_stack()->pushIfHasChildren(command); if (!pasted_nodes.isEmpty()) { foreach (Node* n, pasted_nodes) { AssociateNodeWithSelectedBlocks(n); } AttachNodesToCursor(pasted_nodes); } } void NodeView::Duplicate() { if (!graph_) { return; } QList selected = scene_.GetSelectedNodes(); if (selected.isEmpty()) { return; } QUndoCommand* command = new QUndoCommand(); QList duplicated_nodes; foreach (Node* n, selected) { Node* copy = n->copy(); Node::CopyInputs(n, copy, false); duplicated_nodes.append(copy); new NodeAddCommand(graph_, copy, command); } for (int i=0;ioutput()->edges()) { if (edge->input()->parentNode() == dst) { new NodeEdgeAddCommand(duplicated_nodes.at(i)->output(), duplicated_nodes.at(j)->GetInputWithID(edge->input()->id()), command); } } } } Core::instance()->undo_stack()->pushIfHasChildren(command); if (!duplicated_nodes.isEmpty()) { AttachNodesToCursor(duplicated_nodes); } } void NodeView::ItemsChanged() { QHash::const_iterator i; for (i=scene_.edge_map().constBegin(); i!=scene_.edge_map().constEnd(); i++) { i.value()->Adjust(); } } void NodeView::keyPressEvent(QKeyEvent *event) { super::keyPressEvent(event); if (event->key() == Qt::Key_Escape && !attached_items_.isEmpty()) { DetachItemsFromCursor(); // We undo the last action which SHOULD be adding the node // FIXME: Possible danger of this not being the case? Core::instance()->undo_stack()->undo(); } } void NodeView::mousePressEvent(QMouseEvent *event) { if (HandPress(event)) return; super::mousePressEvent(event); } void NodeView::mouseMoveEvent(QMouseEvent *event) { if (HandMove(event)) return; super::mouseMoveEvent(event); if (!attached_items_.isEmpty()) { MoveAttachedNodesToCursor(event->pos()); // See if the user clicked on an edge (only when dropping single nodes) if (attached_items_.size() == 1) { Node* attached_node = attached_items_.first().item->GetNode(); QRect edge_detect_rect(event->pos(), event->pos()); // FIXME: Hardcoded numbers edge_detect_rect.adjust(-20, -20, 20, 20); QList items = this->items(edge_detect_rect); NodeViewEdge* new_drop_edge = nullptr; // See if there is an edge here foreach (QGraphicsItem* item, items) { new_drop_edge = dynamic_cast(item); if (new_drop_edge) { drop_input_ = nullptr; foreach (NodeParam* param, attached_node->parameters()) { if (param->type() == NodeParam::kInput) { NodeInput* input = static_cast(param); if (input->is_connectable()) { if (input->data_type() & new_drop_edge->edge()->input()->data_type()) { drop_input_ = input; break; } else if (!drop_input_) { drop_input_ = input; } } } } if (drop_input_) { break; } else { new_drop_edge = nullptr; } } } if (drop_edge_ != new_drop_edge) { if (drop_edge_) { drop_edge_->SetHighlighted(false); } drop_edge_ = new_drop_edge; if (drop_edge_) { drop_edge_->SetHighlighted(true); } } } } } void NodeView::mouseReleaseEvent(QMouseEvent *event) { if (HandRelease(event)) return; if (!attached_items_.isEmpty()) { if (attached_items_.size() == 1) { Node* dropping_node = attached_items_.first().item->GetNode(); if (drop_edge_) { NodeEdgePtr old_edge = drop_edge_->edge(); // We have everything we need to place the node in between QUndoCommand* command = new QUndoCommand(); // Remove old edge new NodeEdgeRemoveCommand(old_edge, command); // Place new edges new NodeEdgeAddCommand(old_edge->output(), drop_input_, command); new NodeEdgeAddCommand(dropping_node->output(), old_edge->input(), command); Core::instance()->undo_stack()->push(command); } drop_edge_ = nullptr; } DetachItemsFromCursor(); } super::mouseReleaseEvent(event); } void NodeView::wheelEvent(QWheelEvent *event) { if (event->modifiers() & Qt::ControlModifier) { // FIXME: Hardcoded divider (0.001) qreal multiplier = 1.0 + (static_cast(event->angleDelta().x() + event->angleDelta().y()) * 0.001); double test_scale = scale_ * multiplier; if (test_scale > 0.1) { scale(multiplier, multiplier); scale_ = test_scale; } } else { QWidget::wheelEvent(event); } } void NodeView::SceneSelectionChangedSlot() { emit SelectionChanged(scene_.GetSelectedNodes()); } void NodeView::ShowContextMenu(const QPoint &pos) { if (!graph_) { return; } Menu m; MenuShared::instance()->AddItemsForEditMenu(&m, false); m.addSeparator(); QList selected = scene_.GetSelectedItems(); if (itemAt(pos) && !selected.isEmpty()) { // Label node action QAction* label_action = m.addAction(tr("Label")); connect(label_action, &QAction::triggered, this, [this](){ Core::instance()->LabelNodes(scene_.GetSelectedNodes()); }); m.addSeparator(); // Auto-position action QAction* autopos = m.addAction(tr("Auto-Position")); connect(autopos, &QAction::triggered, this, &NodeView::AutoPositionDescendents); } else { QAction* curved_action = m.addAction(tr("Smooth Edges")); curved_action->setCheckable(true); curved_action->setChecked(scene_.GetEdgesAreCurved()); connect(curved_action, &QAction::triggered, &scene_, &NodeViewScene::SetEdgesAreCurved); m.addSeparator(); Menu* filter_menu = new Menu(tr("Filter"), &m); m.addMenu(filter_menu); filter_menu->AddActionWithData(tr("Show All"), kFilterShowAll, filter_mode_); filter_menu->AddActionWithData(tr("Show Selected Blocks Only"), kFilterShowSelectedBlocks, filter_mode_); connect(filter_menu, &Menu::triggered, this, &NodeView::ContextMenuFilterChanged); Menu* direction_menu = new Menu(tr("Direction"), &m); m.addMenu(direction_menu); direction_menu->AddActionWithData(tr("Top to Bottom"), NodeViewCommon::kTopToBottom, scene_.GetFlowDirection()); direction_menu->AddActionWithData(tr("Bottom to Top"), NodeViewCommon::kBottomToTop, scene_.GetFlowDirection()); direction_menu->AddActionWithData(tr("Left to Right"), NodeViewCommon::kLeftToRight, scene_.GetFlowDirection()); direction_menu->AddActionWithData(tr("Right to Left"), NodeViewCommon::kRightToLeft, scene_.GetFlowDirection()); connect(direction_menu, &Menu::triggered, this, &NodeView::ContextMenuSetDirection); m.addSeparator(); Menu* add_menu = NodeFactory::CreateMenu(&m); add_menu->setTitle(tr("Add")); connect(add_menu, &Menu::triggered, this, &NodeView::CreateNodeSlot); m.addMenu(add_menu); } m.exec(mapToGlobal(pos)); } void NodeView::CreateNodeSlot(QAction *action) { Node* new_node = NodeFactory::CreateFromMenuAction(action); if (new_node) { // Associate this new node with these blocks (allows it to be visible with them even while it // isn't connected to anything) AssociateNodeWithSelectedBlocks(new_node); Core::instance()->undo_stack()->push(new NodeAddCommand(graph_, new_node)); NodeViewItem* item = scene_.NodeToUIObject(new_node); AttachItemsToCursor({item}); } } void NodeView::ContextMenuSetDirection(QAction *action) { SetFlowDirection(static_cast(action->data().toInt())); } void NodeView::AutoPositionDescendents() { QList selected = scene_.GetSelectedNodes(); foreach (Node* n, selected) { scene_.ReorganizeFrom(n); } } void NodeView::ContextMenuFilterChanged(QAction *action) { FilterMode filter = static_cast(action->data().toInt()); if (filter_mode_ != filter) { filter_mode_ = filter; if (filter == kFilterShowAll) { // Un-hide all blocks foreach (NodeViewItem* item, scene_.item_map()) { item->setVisible(true); } foreach (NodeViewEdge* edge, scene_.edge_map()) { edge->setVisible(true); } } ValidateFilter(); } } void NodeView::PlaceNode(NodeViewItem *n, const QPointF &pos) { QRectF destination_rect = n->rect(); destination_rect.translate(n->pos()); double x_movement = destination_rect.width() * 1.5; double y_movement = destination_rect.height() * 1.5; QList items = scene()->items(destination_rect); n->setPos(pos); foreach (QGraphicsItem* item, items) { if (item == n) { continue; } NodeViewItem* node_item = dynamic_cast(item); if (!node_item) { continue; } qDebug() << "Moving" << node_item->GetNode() << "for" << n->GetNode(); QPointF new_pos; if (item->pos() == pos) { qDebug() << "Same pos, need more info"; // Item positions are exact, we'll need more information to determine where this item should go Node* ours = n->GetNode(); Node* theirs = node_item->GetNode(); bool moved = false; new_pos = item->pos(); // Heuristic to determine whether to move the other item above or below foreach (NodeEdgePtr our_edge, ours->output()->edges()) { foreach (NodeEdgePtr their_edge, theirs->output()->edges()) { if (our_edge->output()->parentNode() == their_edge->output()->parentNode()) { qDebug() << " They share a node that they output to"; if (our_edge->input()->index() > their_edge->input()->index()) { // Their edge should go above ours qDebug() << " Our edge goes BELOW theirs"; new_pos.setY(new_pos.y() - y_movement); } else { // Our edge should go below ours qDebug() << " Our edge goes ABOVE theirs"; new_pos.setY(new_pos.y() + y_movement); } moved = true; break; } } } // If we find anything, just move at random if (!moved) { new_pos.setY(new_pos.y() - y_movement); } } else if (item->pos().x() == pos.x()) { qDebug() << "Same X, moving vertically"; // Move strictly up or down new_pos = item->pos(); if (item->pos().y() < pos.y()) { // Move further up new_pos.setY(pos.y() - y_movement); } else { // Move further down new_pos.setY(pos.y() + y_movement); } } else if (item->pos().y() == pos.y()) { qDebug() << "Same Y, moving horizontally"; // Move strictly left or right new_pos = item->pos(); if (item->pos().x() < pos.x()) { // Move further up new_pos.setX(pos.x() - x_movement); } else { // Move further down new_pos.setX(pos.x() + x_movement); } } else { qDebug() << "Diff pos, pushing in angle"; // The item does not have equal X or Y, attempt to push it away from `pos` in the direction it's in double x_diff = item->pos().x() - pos.x(); double y_diff = item->pos().y() - pos.y(); double slope = y_diff / x_diff; double y_int = item->pos().y() - slope * item->pos().x(); if (qAbs(slope) > 1.0) { // Vertical difference is greater than horizontal difference, prioritize vertical movement double desired_y = pos.y(); if (item->pos().y() > pos.y()) { desired_y += y_movement; } else { desired_y -= y_movement; } double x = (desired_y - y_int) / slope; new_pos = QPointF(x, desired_y); } else { // Horizontal difference is greater than vertical difference, prioritize horizontal movement double desired_x = pos.x(); if (item->pos().x() > pos.x()) { desired_x += x_movement; } else { desired_x -= x_movement; } double y = slope * desired_x + y_int; new_pos = QPointF(desired_x, y); } } PlaceNode(node_item, new_pos); } } void NodeView::AttachNodesToCursor(const QList &nodes) { QList items; foreach (Node* p, nodes) { items.append(scene_.NodeToUIObject(p)); } AttachItemsToCursor(items); } void NodeView::AttachItemsToCursor(const QList& items) { DetachItemsFromCursor(); if (!items.isEmpty()) { foreach (NodeViewItem* i, items) { attached_items_.append({i, i->pos() - items.first()->pos()}); } setMouseTracking(true); MoveAttachedNodesToCursor(mapFromGlobal(QCursor::pos())); } } void NodeView::DetachItemsFromCursor() { attached_items_.clear(); setMouseTracking(false); } void NodeView::SetFlowDirection(NodeViewCommon::FlowDirection dir) { scene_.SetFlowDirection(dir); } void NodeView::MoveAttachedNodesToCursor(const QPoint& p) { QPointF item_pos = mapToScene(p); foreach (const AttachedItem& i, attached_items_) { i.item->setPos(item_pos + i.original_pos); } } void NodeView::ConnectSelectionChangedSignal() { connect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot); } void NodeView::ReconnectSelectionChangedSignal() { ConnectSelectionChangedSignal(); SceneSelectionChangedSlot(); } void NodeView::DisconnectSelectionChangedSignal() { disconnect(&scene_, &QGraphicsScene::selectionChanged, this, &NodeView::SceneSelectionChangedSlot); } void NodeView::UpdateBlockFilter() { // Hide all nodes foreach (NodeViewItem* item, scene_.item_map()) { item->setVisible(false); } bool first = true; QRectF last_rect; QList currently_visible; foreach (Block* b, selected_blocks_) { // Auto-position this node's dependencies scene_.ReorganizeFrom(b); // Start calculating the bounding rect of this node's deps QPointF node_pos = b->GetPosition(); QRectF anchor(node_pos, node_pos); QList deps = b->GetDependencies(); foreach (Node* d, deps) { QPointF dep_pos = d->GetPosition(); anchor.setLeft(qMin(anchor.left(), dep_pos.x())); anchor.setRight(qMax(anchor.right(), dep_pos.x())); anchor.setTop(qMin(anchor.top(), dep_pos.y())); anchor.setBottom(qMax(anchor.bottom(), dep_pos.y())); NodeViewItem* item = scene_.NodeToUIObject(d); if (item) { item->setVisible(true); } } // Shift the bounding rect in relation to the other bounding rects if (first) { first = false; } else { QPointF desired_anchor_pos = last_rect.bottomRight() + QPointF(0, 2); QPointF necessary_movement = anchor.topRight() - desired_anchor_pos; b->SetPosition(b->GetPosition() - necessary_movement); foreach (Node* d, deps) { d->SetPosition(d->GetPosition() - necessary_movement); } } // Now that we're done calculating the bounding rect, add this block... deps.append(b); // ...then add its associations deps.append(temporary_association_map_[b]); QHash >::const_iterator i; for (i=association_map_.begin(); i!=association_map_.end(); i++) { if (i.value().contains(b)) { deps.append(i.key()); } } // And make sure all nodes are shown foreach (Node* n, deps) { NodeViewItem* item = scene_.NodeToUIObject(n); if (item) { item->setVisible(true); } } // And lastly, add them all to our currently visible list currently_visible.append(deps); // Cache this rect so we can calculate other rects last_rect = anchor; } // Show only edges between those dependencies foreach (NodeViewEdge* edge, scene_.edge_map()) { edge->setVisible((currently_visible.contains(edge->edge()->input()->parentNode()) && currently_visible.contains(edge->edge()->output()->parentNode()))); } } void NodeView::AssociateNodeWithSelectedBlocks(Node *n) { association_map_.insert(n, selected_blocks_); connect(n, &Node::destroyed, this, &NodeView::AssociatedNodeDestroyed, Qt::DirectConnection); } void NodeView::DisassociateNode(Node *n, bool remove_from_map) { if (remove_from_map) { association_map_.remove(n); } disconnect(n, &Node::destroyed, this, &NodeView::AssociatedNodeDestroyed); } void NodeView::ValidateFilter() { // Force auto-positioning switch (filter_mode_) { case kFilterShowAll: // NOTE: Assumes Sequence scene_.ReorganizeFrom(static_cast(graph_)->viewer_output()); break; case kFilterShowSelectedBlocks: UpdateBlockFilter(); break; } } void NodeView::AssociatedNodeDestroyed() { DisassociateNode(static_cast(sender()), true); } void NodeView::GraphEdgeAdded(NodeEdgePtr edge) { Node* input_node = edge->input()->parentNode(); if (input_node->OutputsTo(static_cast(graph_)->viewer_output(), true)) { QHash >::const_iterator i = association_map_.begin(); while (i != association_map_.end()) { if (input_node->InputsFrom(i.key(), true)) { i = association_map_.erase(i); } else { i++; } } } scene_.AddEdge(edge); ValidateFilter(); } void NodeView::GraphEdgeRemoved(NodeEdgePtr edge) { scene_.RemoveEdge(edge); Node* output_node = edge->output()->parentNode(); // Check if this disconnected node still connects to a selected block, in which case do nothing foreach (Block* b, selected_blocks_) { if (output_node->OutputsTo(b, true)) { return; } } QList disconnected_nodes; disconnected_nodes.append(output_node); disconnected_nodes.append(output_node->GetDependencies()); if (output_node->OutputsTo(static_cast(graph_)->viewer_output(), true)) { // Check if this disconnected node still has a path to the viewer somewhere else foreach (Block* b, selected_blocks_) { QList& temp_assocs = temporary_association_map_[b]; temp_assocs.append(disconnected_nodes); } } else { // Otherwise, we must associate these nodes foreach (Node* n, disconnected_nodes) { AssociateNodeWithSelectedBlocks(n); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeview/nodeview.h000066400000000000000000000106541370472574300222760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEVIEW_H #define NODEVIEW_H #include #include #include "node/graph.h" #include "nodeviewscene.h" #include "widget/timelinewidget/view/handmovableview.h" #include "widget/nodecopypaste/nodecopypaste.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget for viewing and editing node graphs * * This widget takes a NodeGraph object and constructs a QGraphicsScene representing its data, viewing and allowing * the user to make modifications to it. */ class NodeView : public HandMovableView, public NodeCopyPasteWidget { Q_OBJECT public: NodeView(QWidget* parent); virtual ~NodeView() override; /** * @brief Sets the graph to view */ void SetGraph(NodeGraph* graph); /** * @brief Delete selected nodes from graph (user-friendly/undoable) */ void DeleteSelected(); void SelectAll(); void DeselectAll(); void Select(const QList& nodes); void SelectWithDependencies(QList nodes); void SelectBlocks(const QList& blocks); void CopySelected(bool cut); void Paste(); void Duplicate(); signals: /** * @brief Signal emitted when the selected nodes have changed */ void SelectionChanged(QList selected_nodes); protected: virtual void keyPressEvent(QKeyEvent *event) override; virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; virtual void mouseReleaseEvent(QMouseEvent* event) override; virtual void wheelEvent(QWheelEvent* event) override; private: void PlaceNode(NodeViewItem* n, const QPointF& pos); void AttachNodesToCursor(const QList& nodes); void AttachItemsToCursor(const QList& items); void DetachItemsFromCursor(); void SetFlowDirection(NodeViewCommon::FlowDirection dir); void MoveAttachedNodesToCursor(const QPoint &p); void ConnectSelectionChangedSignal(); void ReconnectSelectionChangedSignal(); void DisconnectSelectionChangedSignal(); void UpdateBlockFilter(); void AssociateNodeWithSelectedBlocks(Node* n); void DisassociateNode(Node* n, bool remove_from_map); NodeGraph* graph_; struct AttachedItem { NodeViewItem* item; QPointF original_pos; }; QList attached_items_; NodeViewEdge* drop_edge_; NodeInput* drop_input_; NodeViewScene scene_; QList selected_blocks_; QHash > association_map_; QHash > temporary_association_map_; enum FilterMode { kFilterShowAll, kFilterShowSelectedBlocks }; FilterMode filter_mode_; double scale_; private slots: void ValidateFilter(); void AssociatedNodeDestroyed(); void GraphEdgeAdded(NodeEdgePtr edge); void GraphEdgeRemoved(NodeEdgePtr edge); /** * @brief Internal function triggered when any change is signalled from the QGraphicsScene * * Current primary function is to inform all NodeViewEdges to re-adjust in case any Nodes have moved */ void ItemsChanged(); /** * @brief Receiver for when the scene's selected items change */ void SceneSelectionChangedSlot(); /** * @brief Receiver for when the user right clicks (or otherwise requests a context menu) */ void ShowContextMenu(const QPoint &pos); /** * @brief Receiver for when the user requests a new node from the add menu */ void CreateNodeSlot(QAction* action); /** * @brief Receiver for setting the direction from the context menu */ void ContextMenuSetDirection(QAction* action); /** * @brief Receiver for auto-position descendents menu action */ void AutoPositionDescendents(); /** * @brief Receiver for the user changing the filter */ void ContextMenuFilterChanged(QAction* action); }; OLIVE_NAMESPACE_EXIT #endif // NODEVIEW_H olive-continuous/app/widget/nodeview/nodeviewcommon.h000066400000000000000000000031561370472574300235060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEVIEWCOMMON_H #define NODEVIEWCOMMON_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class NodeViewCommon { public: enum FlowDirection { kTopToBottom, kBottomToTop, kLeftToRight, kRightToLeft }; static Qt::Orientation GetFlowOrientation(FlowDirection dir) { if (dir == kTopToBottom || dir == kBottomToTop) { return Qt::Vertical; } else { return Qt::Horizontal; } } static bool DirectionsAreOpposing(FlowDirection a, FlowDirection b) { return ((a == NodeViewCommon::kLeftToRight && b == NodeViewCommon::kRightToLeft) || (a == NodeViewCommon::kRightToLeft && b == NodeViewCommon::kLeftToRight) || (a == NodeViewCommon::kTopToBottom && b == NodeViewCommon::kBottomToTop) || (a == NodeViewCommon::kBottomToTop && b == NodeViewCommon::kTopToBottom)); } }; OLIVE_NAMESPACE_EXIT #endif // NODEVIEWCOMMON_H olive-continuous/app/widget/nodeview/nodeviewedge.cpp000066400000000000000000000075041370472574300234560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeviewedge.h" #include #include #include #include #include "common/clamp.h" #include "common/lerp.h" #include "nodeview.h" #include "nodeviewscene.h" OLIVE_NAMESPACE_ENTER NodeViewEdge::NodeViewEdge(QGraphicsItem *parent) : QGraphicsPathItem(parent), edge_(nullptr), connected_(false), highlighted_(false), flow_dir_(NodeViewCommon::kLeftToRight), curved_(true) { setFlag(QGraphicsItem::ItemIsSelectable); // Ensures this UI object is drawn behind other objects setZValue(-1); // Use font metrics to set edge width for basic high DPI support edge_width_ = QFontMetrics(QFont()).height() / 12; } void NodeViewEdge::SetEdge(NodeEdgePtr edge) { SetConnected(true); // Set the new edge pointer edge_ = edge; // Re-adjust the line positioning for this new edge Adjust(); } NodeEdgePtr NodeViewEdge::edge() { return edge_; } void NodeViewEdge::Adjust() { if (!edge_ || !scene()) { return; } // Get the UI objects of both nodes that this edge connects NodeViewItem* output = static_cast(scene())->NodeToUIObject(edge_->output()->parentNode()); NodeViewItem* input = static_cast(scene())->NodeToUIObject(edge_->input()->parentNode()); if (!output || !input) { return; } // Draw a line between the two SetPoints(output->GetParamPoint(edge_->output(), output->pos()), input->GetParamPoint(edge_->input(), output->pos()), input->IsExpanded()); } void NodeViewEdge::SetConnected(bool c) { connected_ = c; update(); } void NodeViewEdge::SetHighlighted(bool e) { highlighted_ = e; update(); } void NodeViewEdge::SetPoints(const QPointF &start, const QPointF &end, bool input_is_expanded) { QPainterPath path; path.moveTo(start); if (curved_) { double half_x = lerp(start.x(), end.x(), 0.5); double half_y = lerp(start.y(), end.y(), 0.5); QPointF cp1, cp2; if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) { cp1 = QPointF(half_x, start.y()); } else { cp1 = QPointF(start.x(), half_y); } if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal || input_is_expanded) { cp2 = QPointF(half_x, end.y()); } else { cp2 = QPointF(end.x(), half_y); } path.cubicTo(cp1, cp2, end); } else { path.lineTo(end); } setPath(path); } void NodeViewEdge::SetFlowDirection(NodeViewCommon::FlowDirection dir) { flow_dir_ = dir; Adjust(); } void NodeViewEdge::SetCurved(bool e) { curved_ = e; update(); } void NodeViewEdge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { QPalette::ColorGroup group; QPalette::ColorRole role; if (connected_) { group = QPalette::Active; } else { group = QPalette::Disabled; } if (highlighted_ != bool(option->state & QStyle::State_Selected)) { role = QPalette::Highlight; } else { role = QPalette::Text; } painter->setPen(QPen(qApp->palette().color(group, role), edge_width_)); painter->setBrush(Qt::NoBrush); painter->drawPath(path()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeview/nodeviewedge.h000066400000000000000000000065561370472574300231310ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEEDGEITEM_H #define NODEEDGEITEM_H #include #include #include "node/edge.h" #include "nodeviewcommon.h" OLIVE_NAMESPACE_ENTER /** * @brief A graphical representation of a NodeEdge to be used in NodeView * * A fairly simple line widget use to visualize a connection between two node parameters (a NodeEdge). */ class NodeViewEdge : public QGraphicsPathItem { public: NodeViewEdge(QGraphicsItem* parent = nullptr); /** * @brief Set the edge that this item corresponds to * * This can be changed at any time (but under most circumstances won't be). Calling this will automatically call * Adjust() to move this item into the correct position. */ void SetEdge(NodeEdgePtr edge); NodeEdgePtr edge(); /** * @brief Moves/updates this line to visually connect between the two corresponding NodeViewItems * * Using the attached edge (see SetEdge()), this function retrieves the NodeViewItems representing the two nodes * that this edge connects. It uses their positions to determine where the line should visually connect and sets * it accordingly. * * This should be set any time the NodeEdge changes (see SetEdge()), and any time the nodes move in the NodeGraph * (see NodeView::ItemsChanged()). This will keep the nodes visually connected at all times. */ void Adjust(); /** * @brief Set the connected state of this line * * When the edge is not connected, it visually depicts this by coloring the line grey. When an edge is connected or * a potential connection is valid, the line is colored white. This function sets whether the line should be grey * (false) or white (true). * * Using SetEdge() automatically sets this to true. Under most circumstances this should be left alone, and only * be set when an edge is being created/dragged. */ void SetConnected(bool c); /** * @brief Set highlighted state * * Changes color of edge. */ void SetHighlighted(bool e); /** * @brief Set points to create curve from */ void SetPoints(const QPointF& start, const QPointF& end, bool input_is_expanded); /** * @brief Sets the direction nodes are flowing */ void SetFlowDirection(NodeViewCommon::FlowDirection dir); /** * @brief Set whether edges should be drawn as curved or as straight lines */ void SetCurved(bool e); protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; private: NodeEdgePtr edge_; int edge_width_; bool connected_; bool highlighted_; NodeViewCommon::FlowDirection flow_dir_; bool curved_; }; OLIVE_NAMESPACE_EXIT #endif // NODEEDGEITEM_H olive-continuous/app/widget/nodeview/nodeviewitem.cpp000066400000000000000000000442511370472574300235100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeviewitem.h" #include #include #include #include #include #include "common/flipmodifiers.h" #include "common/qtutils.h" #include "config/config.h" #include "core.h" #include "nodeview.h" #include "nodeviewscene.h" #include "nodeviewundo.h" #include "ui/icons/icons.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER NodeViewItem::NodeViewItem(QGraphicsItem *parent) : QGraphicsRectItem(parent), node_(nullptr), dragging_edge_(nullptr), cached_drop_item_(nullptr), cached_drop_item_expanded_(false), expanded_(false), hide_titlebar_(false), standard_click_(false), highlighted_index_(-1), node_edge_change_command_(nullptr), flow_dir_(NodeViewCommon::kLeftToRight) { // Set flags for this widget setFlag(QGraphicsItem::ItemIsMovable); setFlag(QGraphicsItem::ItemIsSelectable); setFlag(QGraphicsItem::ItemSendsGeometryChanges); // // We use font metrics to set all the UI measurements for DPI-awareness // // Set border width node_border_width_ = DefaultItemBorder(); int widget_width = DefaultItemWidth(); int widget_height = DefaultItemHeight(); title_bar_rect_ = QRectF(-widget_width/2, -widget_height/2, widget_width, widget_height); setRect(title_bar_rect_); } QPointF NodeViewItem::GetNodePosition() const { QPointF node_pos; qreal adjusted_x = pos().x() / DefaultItemHorizontalPadding(); qreal adjusted_y = pos().y() / DefaultItemVerticalPadding(); switch (flow_dir_) { case NodeViewCommon::kLeftToRight: node_pos.setX(adjusted_x); node_pos.setY(adjusted_y); break; case NodeViewCommon::kRightToLeft: node_pos.setX(-adjusted_x); node_pos.setY(adjusted_y); break; case NodeViewCommon::kTopToBottom: node_pos.setX(adjusted_y); node_pos.setY(adjusted_x); break; case NodeViewCommon::kBottomToTop: node_pos.setX(-adjusted_y); node_pos.setY(adjusted_x); break; } return node_pos; } void NodeViewItem::SetNodePosition(const QPointF &pos) { switch (flow_dir_) { case NodeViewCommon::kLeftToRight: setPos(pos.x() * DefaultItemHorizontalPadding(), pos.y() * DefaultItemVerticalPadding()); break; case NodeViewCommon::kRightToLeft: setPos(-pos.x() * DefaultItemHorizontalPadding(), pos.y() * DefaultItemVerticalPadding()); break; case NodeViewCommon::kTopToBottom: setPos(pos.y() * DefaultItemHorizontalPadding(), pos.x() * DefaultItemVerticalPadding()); break; case NodeViewCommon::kBottomToTop: setPos(pos.y() * DefaultItemHorizontalPadding(), -pos.x() * DefaultItemVerticalPadding()); break; } } int NodeViewItem::DefaultTextPadding() { return QFontMetrics(QFont()).height() / 4; } int NodeViewItem::DefaultItemHeight() { return QFontMetrics(QFont()).height() + DefaultTextPadding() * 2; } int NodeViewItem::DefaultItemWidth() { return QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHHHH");; } int NodeViewItem::DefaultMaximumTextWidth() { return QFontMetricsWidth(QFontMetrics(QFont()), "HHHHHHHH");; } int NodeViewItem::DefaultItemBorder() { return QFontMetrics(QFont()).height() / 12; } qreal NodeViewItem::DefaultItemHorizontalPadding() const { if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) { return DefaultItemWidth() * 1.5; } else { return DefaultItemWidth() * 1.25; } } qreal NodeViewItem::DefaultItemVerticalPadding() const { if (NodeViewCommon::GetFlowOrientation(flow_dir_) == Qt::Horizontal) { return DefaultItemHeight() * 1.5; } else { return DefaultItemHeight() * 2.0; } } void NodeViewItem::SetNode(Node *n) { node_ = n; node_inputs_.clear(); if (node_) { node_->Retranslate(); foreach (NodeParam* p, node_->parameters()) { if (p->type() == NodeParam::kInput) { NodeInput* input = static_cast(p); if (input->is_connectable()) { node_inputs_.append(input); } } } SetNodePosition(node_->GetPosition()); } update(); } Node *NodeViewItem::GetNode() const { return node_; } bool NodeViewItem::IsExpanded() const { return expanded_; } void NodeViewItem::SetExpanded(bool e, bool hide_titlebar) { if (node_inputs_.isEmpty() || (expanded_ == e && hide_titlebar_ == hide_titlebar)) { return; } expanded_ = e; hide_titlebar_ = hide_titlebar; if (expanded_ && !node_inputs_.isEmpty()) { // Create new rect QRectF new_rect = title_bar_rect_; if (hide_titlebar_) { new_rect.setHeight(new_rect.height() * node_inputs_.size()); } else { new_rect.setHeight(new_rect.height() * (node_inputs_.size() + 1)); } setRect(new_rect); } else { setRect(title_bar_rect_); } update(); } void NodeViewItem::ToggleExpanded() { SetExpanded(!IsExpanded()); } void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { // HACK for getting the main QWidget palette color (the `widget`'s palette uses the NodeView color instead which we // don't want here) QPalette app_pal = Core::instance()->main_window()->palette(); // Draw background rect if expanded if (IsExpanded()) { painter->setPen(Qt::NoPen); painter->setBrush(app_pal.color(QPalette::Window)); painter->drawRect(rect()); painter->setPen(app_pal.color(QPalette::Text)); for (int i=0;ifillRect(input_rect, highlight_col); } painter->drawText(input_rect, Qt::AlignCenter, node_inputs_.at(i)->name()); } } // Draw the titlebar if (!hide_titlebar_ && node_) { Color node_color = Config::Current()[QStringLiteral("NodeCatColor%1") .arg(node_->Category().first())].value(); painter->setPen(Qt::black); painter->setBrush(node_color.toQColor()); painter->drawRect(title_bar_rect_); painter->setPen(app_pal.color(QPalette::Text)); QString node_label; if (node_->GetLabel().isEmpty()) { node_label = node_->ShortName(); } else { node_label = node_->GetLabel(); } { QFont f; QFontMetrics fm(f); int max_text_width = DefaultMaximumTextWidth(); if (QFontMetricsWidth(fm, node_label) > max_text_width) { QString concatenated; do { node_label.chop(1); concatenated = QCoreApplication::translate("NodeViewItem", "%1...").arg(node_label); } while (QFontMetricsWidth(fm, concatenated) > max_text_width); node_label = concatenated; } } if (node_color.GetRoughLuminance() > 0.66) { painter->setPen(Qt::black); } else { painter->setPen(Qt::white); } // Draw the text in a rect (the rect is sized around text already in the constructor) painter->drawText(title_bar_rect_, Qt::AlignCenter, node_label); } // Draw final border QPen border_pen; border_pen.setWidth(node_border_width_); if (option->state & QStyle::State_Selected) { border_pen.setColor(app_pal.color(QPalette::Highlight)); } else { border_pen.setColor(Qt::black); } painter->setPen(border_pen); painter->setBrush(Qt::NoBrush); painter->drawRect(rect()); } void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { // We override standard mouse behavior in some cases. In these cases, we don't want the standard "move" and "release" // events to trigger if we haven't already triggered the "press" event. We use this variable to determine whether // base class behavior is valid here. standard_click_ = false; // If CTRL is held, we start a new edge if (node_ && event->modifiers() & Qt::ControlModifier) { NodeParam* param = node_->output(); // Create draggable object dragging_edge_ = new NodeViewEdge(); dragging_edge_->SetFlowDirection(flow_dir_); // Set up a QUndoCommand to make this action undoable node_edge_change_command_ = new QUndoCommand(); if (param->type() == NodeParam::kOutput || param->edges().isEmpty()) { // For an output param (or an input param with no connections), we default to creating a new edge drag_source_ = this; drag_src_param_ = param; // Set the starting position to the current param's connector dragging_edge_start_ = GetParamPoint(param, QPointF()); } else if (param->type() == NodeParam::kInput) { // For an input param, we default to moving an existing edge // (here we use the last one, which will usually also be the first) NodeEdgePtr edge = param->edges().last(); // The starting position will be the OPPOSING parameter's rectangle // Get the opposing parameter drag_src_param_ = edge->output(); // Get its Node UI object drag_source_ = static_cast(scene())->NodeToUIObject(drag_src_param_->parentNode()); // Get the opposing parameter's rect center using the line's current coordinates // (we use the current coordinates because a complex formula is used for the line's coords if // the opposing node is collapsed, therefore it's easier to just retrieve it from line itself) NodeViewEdge* existing_edge_ui = static_cast(scene())->EdgeToUIObject(edge); QPainterPath existing_edge_line = existing_edge_ui->path(); QPointF edge_start = existing_edge_line.pointAtPercent(0); QPointF edge_end = existing_edge_line.pointAtPercent(1); if (existing_edge_ui->contains(edge_start)) { dragging_edge_start_ = edge_start; } else { dragging_edge_start_ = edge_end; } // Remove old edge NodeEdgeRemoveCommand* remove_command = new NodeEdgeRemoveCommand(edge->output(), edge->input(), node_edge_change_command_); remove_command->redo(); } // Add it to the scene scene()->addItem(dragging_edge_); // Trigger initial line setting mouseMoveEvent(event); return; } else { // We aren't using any override behaviors, switch back to standard click behavior standard_click_ = true; event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); QGraphicsRectItem::mousePressEvent(event); } } void NodeViewItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { // Check if an edge drag was initiated if (dragging_edge_ != nullptr) { QPointF end_point = event->scenePos(); drag_dest_param_ = nullptr; if (!cached_drop_item_ || !cached_drop_item_->contains(cached_drop_item_->mapFromScene(event->scenePos()))) { // Cursor has left last entered item, we need to find a new one if (cached_drop_item_) { // If we expanded an item below but are no longer dragging over it, re-collapse it if (cached_drop_item_expanded_) { cached_drop_item_->SetExpanded(false); } cached_drop_item_->SetHighlightedIndex(-1); cached_drop_item_->setZValue(0); cached_drop_item_ = nullptr; } NodeViewItem* cursor_item = dynamic_cast(scene()->itemAt(event->scenePos(), sceneTransform())); if (cursor_item && cursor_item != drag_source_ && !cursor_item->node_inputs_.isEmpty()) { cached_drop_item_ = cursor_item; // If the item we're dragging over is collapsed, expand it cached_drop_item_expanded_ = !cached_drop_item_->IsExpanded(); if (cached_drop_item_expanded_) { cached_drop_item_->SetExpanded(true, true); } cached_drop_item_->setZValue(1); } else { cached_drop_item_ = nullptr; } } if (cached_drop_item_) { int highlight_their_index = -1; // See if the mouse is currently inside a connector rect for (int i=0;inode_inputs_.size();i++) { // Get the parameter we're dragging into NodeParam* comp_param = cached_drop_item_->node_inputs_.at(i); // See if cursor is inside its UI if (cached_drop_item_->GetInputRect(i).contains(cached_drop_item_->mapFromScene(event->scenePos()))) { // See if we're dragging inside the hitbox // Attempt to prevent circular dependency - ensure the receiving node doesn't output to the outputting node if (!cached_drop_item_->GetNode()->OutputsTo(node_, true)) { drag_dest_param_ = comp_param; highlight_their_index = i; QPointF end_point_local = cached_drop_item_->GetInputPoint(i, pos()); end_point = cached_drop_item_->mapToScene(end_point_local); } break; } } cached_drop_item_->SetHighlightedIndex(highlight_their_index); } dragging_edge_->SetConnected(drag_dest_param_); dragging_edge_->SetPoints(dragging_edge_start_, end_point, cached_drop_item_ ? cached_drop_item_->IsExpanded() : false); return; } if (standard_click_) { event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); QGraphicsRectItem::mouseMoveEvent(event); } } void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { // Check if an edge drag was initiated if (dragging_edge_ != nullptr) { // Remove the drag object scene()->removeItem(dragging_edge_); // If we expanded an item in the drag, re-collapse it now if (cached_drop_item_) { if (cached_drop_item_expanded_) { cached_drop_item_->SetExpanded(false); } cached_drop_item_->SetHighlightedIndex(-1); cached_drop_item_->setZValue(0); cached_drop_item_ = nullptr; } if (drag_dest_param_ != nullptr) { // We dragged to somewhere, so we'll make a new connection NodeEdgePtr new_edge; NodeOutput* output; NodeInput* input; // Connecting will automatically add an edge UI object through the signal/slot system if (drag_dest_param_->type() == NodeParam::kOutput) { output = static_cast(drag_dest_param_); input = static_cast(drag_src_param_); } else { output = static_cast(drag_src_param_); input = static_cast(drag_dest_param_); } // Use a command to make Node connecting undoable new NodeEdgeAddCommand(output, input, node_edge_change_command_); } dragging_edge_ = nullptr; Core::instance()->undo_stack()->pushIfHasChildren(node_edge_change_command_); node_edge_change_command_ = nullptr; return; } if (standard_click_) { event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); QGraphicsRectItem::mouseReleaseEvent(event); } } void NodeViewItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { QGraphicsRectItem::mouseDoubleClickEvent(event); if (!(event->modifiers() & Qt::ControlModifier)) { SetExpanded(!IsExpanded()); } } QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if (change == ItemPositionHasChanged && node_) { node_->blockSignals(true); node_->SetPosition(GetNodePosition()); node_->blockSignals(false); } return QGraphicsItem::itemChange(change, value); } void NodeViewItem::SetHighlightedIndex(int index) { if (highlighted_index_ == index) { return; } highlighted_index_ = index; update(); } QRectF NodeViewItem::GetInputRect(int index) const { QRectF r = title_bar_rect_; if (!hide_titlebar_) { index++; } if (IsExpanded()) { r.translate(0, r.height() * index); } return r; } QPointF NodeViewItem::GetParamPoint(NodeParam *param, const QPointF& source_pos) const { if (param->type() == NodeParam::kOutput) { switch (flow_dir_) { case NodeViewCommon::kLeftToRight: default: return pos() + QPointF(rect().right(), rect().center().y()); case NodeViewCommon::kRightToLeft: return pos() + QPointF(rect().left(), rect().center().y()); case NodeViewCommon::kTopToBottom: return pos() + QPointF(rect().center().x(), rect().bottom()); case NodeViewCommon::kBottomToTop: return pos() + QPointF(rect().center().x(), rect().top()); } } else { NodeInput* input = static_cast(param); // Resolve NodeInputArray elements while (input->parentNode() != input->parent()) { input = static_cast(input->parent()); } return pos() + GetInputPoint(node_inputs_.indexOf(input), source_pos); } } void NodeViewItem::SetFlowDirection(NodeViewCommon::FlowDirection dir) { flow_dir_ = dir; } QPointF NodeViewItem::GetInputPoint(int index, const QPointF& source_pos) const { QRectF input_rect = GetInputRect(index); Qt::Orientation flow_orientation = NodeViewCommon::GetFlowOrientation(flow_dir_); if (flow_orientation == Qt::Horizontal || IsExpanded()) { if (flow_dir_ == NodeViewCommon::kLeftToRight || (flow_orientation == Qt::Vertical && source_pos.x() < pos().x())) { return QPointF(input_rect.left(), input_rect.center().y()); } else { return QPointF(input_rect.right(), input_rect.center().y()); } } else { if (flow_dir_ == NodeViewCommon::kTopToBottom) { return QPointF(input_rect.center().x(), input_rect.top()); } else { return QPointF(input_rect.center().x(), input_rect.bottom()); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeview/nodeviewitem.h000066400000000000000000000106431370472574300231530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEVIEWITEM_H #define NODEVIEWITEM_H #include #include #include #include #include #include "node/node.h" #include "nodeviewcommon.h" #include "nodeviewedge.h" #include "nodeviewitemwidgetproxy.h" OLIVE_NAMESPACE_ENTER /** * @brief A visual widget representation of a Node object to be used in a NodeView * * This widget can be collapsed or expanded to show/hide the node's various parameters. * * To retrieve the NodeViewItem for a certain Node, use NodeView::NodeToUIObject(). */ class NodeViewItem : public QGraphicsRectItem { public: NodeViewItem(QGraphicsItem* parent = nullptr); QPointF GetNodePosition() const; void SetNodePosition(const QPointF& pos); /** * @brief Set the Node to correspond to this widget */ void SetNode(Node* n); /** * @brief Get currently attached node */ Node* GetNode() const; /** * @brief Get expanded state */ bool IsExpanded() const; /** * @brief Set expanded state */ void SetExpanded(bool e, bool hide_titlebar = false); void ToggleExpanded(); /** * @brief Returns GLOBAL point that edges should connect to for any NodeParam member of this object */ QPointF GetParamPoint(NodeParam* param, const QPointF &source_pos) const; /** * @brief Sets the direction nodes are flowing */ void SetFlowDirection(NodeViewCommon::FlowDirection dir); static int DefaultTextPadding(); static int DefaultItemHeight(); static int DefaultItemWidth(); static int DefaultMaximumTextWidth(); static int DefaultItemBorder(); qreal DefaultItemHorizontalPadding() const; qreal DefaultItemVerticalPadding() const; protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; private: /** * @brief Highlight an input (for instance when the user is dragging over it) */ void SetHighlightedIndex(int index); /** * @brief Returns local rect of a NodeInput in array node_inputs_[index] */ QRectF GetInputRect(int index) const; /** * @brief Returns local point that edges should connect to for a NodeInput in array node_inputs_[index] */ QPointF GetInputPoint(int index, const QPointF &source_pos) const; /** * @brief Reference to attached Node */ Node* node_; /** * @brief Cached list of node inputs */ QList node_inputs_; /** * @brief Rectangle of the Node's title bar (equal to rect() when collapsed) */ QRectF title_bar_rect_; /// Edge dragging variables NodeViewEdge* dragging_edge_; QPointF dragging_edge_start_; NodeParam* drag_src_param_; NodeParam* drag_dest_param_; NodeViewItem* drag_source_; NodeViewItem* cached_drop_item_; bool cached_drop_item_expanded_; /// Sizing variables to use when drawing int node_border_width_; /** * @brief Expanded state */ bool expanded_; bool hide_titlebar_; /** * @brief Current click mode * * \see mousePressEvent() */ bool standard_click_; int highlighted_index_; /** * @brief QUndoCommand for creating and deleting edges by dragging * * \see mousePressEvent() * \see mouseReleaseEvent() */ QUndoCommand* node_edge_change_command_; NodeViewCommon::FlowDirection flow_dir_; }; OLIVE_NAMESPACE_EXIT #endif // NODEVIEWITEM_H olive-continuous/app/widget/nodeview/nodeviewitemwidgetproxy.cpp000066400000000000000000000020531370472574300260100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeviewitemwidgetproxy.h" QColor NodeViewItemWidget::TitleBarColor() { return title_bar_color_; } void NodeViewItemWidget::SetTitleBarColor(QColor color) { title_bar_color_ = color; } QColor NodeViewItemWidget::BorderColor() { return border_color_; } void NodeViewItemWidget::SetBorderColor(QColor color) { border_color_ = color; } olive-continuous/app/widget/nodeview/nodeviewitemwidgetproxy.h000066400000000000000000000030351370472574300254560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEVIEWITEMWIDGETPROXY_H #define NODEVIEWITEMWIDGETPROXY_H #include /** * @brief A proxy object to allow NodeViewItem access to CSS functions * * QGraphicsItems can't take Q_PROPERTYs for CSS stylesheet input, but QWidgets can. This is a hack to allow CSS * properties to be set from CSS and then read by NodeViewItem. */ class NodeViewItemWidget : public QWidget { Q_OBJECT Q_PROPERTY(QColor titlebarColor READ TitleBarColor WRITE SetTitleBarColor DESIGNABLE true) Q_PROPERTY(QColor borderColor READ BorderColor WRITE SetBorderColor DESIGNABLE true) public: NodeViewItemWidget() = default; QColor TitleBarColor(); void SetTitleBarColor(QColor color); QColor BorderColor(); void SetBorderColor(QColor color); private: QColor title_bar_color_; QColor border_color_; }; #endif // NODEVIEWITEMWIDGETPROXY_H olive-continuous/app/widget/nodeview/nodeviewscene.cpp000066400000000000000000000167011370472574300236460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeviewscene.h" #include "common/functiontimer.h" #include "nodeviewedge.h" #include "nodeviewitem.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER NodeViewScene::NodeViewScene(QObject *parent) : QGraphicsScene(parent), graph_(nullptr), direction_(NodeViewCommon::kLeftToRight), curved_edges_(true) { } void NodeViewScene::SetFlowDirection(NodeViewCommon::FlowDirection direction) { direction_ = direction; { // Iterate over node items setting direction QHash::const_iterator i; for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) { i.value()->SetFlowDirection(direction_); // Update position too i.value()->SetNodePosition(i.key()->GetPosition()); } } { // Iterate over edge items setting direction QHash::const_iterator i; for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) { i.value()->SetFlowDirection(direction_); } } } void NodeViewScene::clear() { // Deselect everything (prevents signals that a selection has changed after deleting an object) DeselectAll(); // HACK: QGraphicsScene contains some sort of internal caching of the selected items which doesn't update unless // we call a function like this. That means even though we deselect all items above, QGraphicsScene will // continue to incorrectly signal selectionChanged() when items that were selected (but are now not) get // deleted. Calling this function appears to update the internal cache and prevent this. selectedItems(); { QHash::const_iterator i; for (i=item_map_.begin();i!=item_map_.end();i++) { delete i.value(); } item_map_.clear(); } { QHash::const_iterator i; for (i=edge_map_.begin();i!=edge_map_.end();i++) { delete i.value(); } edge_map_.clear(); } } void NodeViewScene::SelectAll() { QList all_items = this->items(); foreach (QGraphicsItem* i, all_items) { i->setSelected(true); } } void NodeViewScene::DeselectAll() { QList selected_items = this->selectedItems(); foreach (QGraphicsItem* i, selected_items) { i->setSelected(false); } } NodeViewItem *NodeViewScene::NodeToUIObject(Node *n) { return item_map_.value(n); } NodeViewEdge *NodeViewScene::EdgeToUIObject(NodeEdgePtr n) { return edge_map_.value(n.get()); } void NodeViewScene::SetGraph(NodeGraph *graph) { graph_ = graph; } QList NodeViewScene::GetSelectedNodes() const { QHash::const_iterator iterator; QList selected; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { if (iterator.value()->isSelected()) { selected.append(iterator.key()); } } return selected; } QList NodeViewScene::GetSelectedItems() const { QHash::const_iterator iterator; QList selected; for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) { if (iterator.value()->isSelected()) { selected.append(iterator.value()); } } return selected; } QList NodeViewScene::GetSelectedEdges() const { QList edges; QHash::const_iterator i; for (i=edge_map_.constBegin(); i!=edge_map_.constEnd(); i++) { if (i.value()->isSelected()) { edges.append(i.key()); } } return edges; } const QHash &NodeViewScene::item_map() const { return item_map_; } const QHash &NodeViewScene::edge_map() const { return edge_map_; } void NodeViewScene::AddNode(Node* node) { NodeViewItem* item = new NodeViewItem(); item->SetFlowDirection(direction_); item->SetNode(node); addItem(item); item_map_.insert(node, item); // Add a NodeViewEdge for each connection foreach (NodeParam* param, node->parameters()) { // We only bother working with outputs since eventually this will cover all inputs too // (covering both would lead to duplicates since every edge connects to one input and one output) if (param->type() == NodeParam::kOutput) { const QVector& edges = param->edges(); foreach(NodeEdgePtr edge, edges) { AddEdge(edge); } } } connect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged); connect(node, &Node::LabelChanged, this, &NodeViewScene::NodeLabelChanged); } void NodeViewScene::RemoveNode(Node *node) { disconnect(node, &Node::LabelChanged, this, &NodeViewScene::NodeLabelChanged); disconnect(node, &Node::PositionChanged, this, &NodeViewScene::NodePositionChanged); delete item_map_.take(node); } void NodeViewScene::AddEdge(NodeEdgePtr edge) { NodeViewEdge* edge_ui = new NodeViewEdge(); edge_ui->SetEdge(edge); edge_ui->SetFlowDirection(direction_); edge_ui->SetCurved(curved_edges_); addItem(edge_ui); edge_map_.insert(edge.get(), edge_ui); } void NodeViewScene::RemoveEdge(NodeEdgePtr edge) { delete edge_map_.take(edge.get()); } int NodeViewScene::DetermineWeight(Node *n) { QList inputs = n->GetImmediateDependencies(); int weight = 0; foreach (Node* i, inputs) { if (i->GetRoutesTo(n) == 1) { weight += DetermineWeight(i); } } return qMax(1, weight); } Qt::Orientation NodeViewScene::GetFlowOrientation() const { return NodeViewCommon::GetFlowOrientation(direction_); } NodeViewCommon::FlowDirection NodeViewScene::GetFlowDirection() const { return direction_; } void NodeViewScene::ReorganizeFrom(Node* n) { QList immediates = n->GetImmediateDependencies(); if (immediates.isEmpty()) { // Nothing to do return; } QPointF parent_pos = n->GetPosition(); int weight_count = DetermineWeight(n); qreal child_x = parent_pos.x() - 1.0; qreal children_height = weight_count-1; qreal children_y = parent_pos.y() - children_height * 0.5; int weight_counter = 0; foreach (Node* i, immediates) { if (i->GetRoutesTo(n) == 1) { int weight = DetermineWeight(i); i->SetPosition(QPointF(child_x, children_y + weight_counter + (weight - 1) * 0.5)); weight_counter += weight; ReorganizeFrom(i); } } } bool NodeViewScene::GetEdgesAreCurved() const { return curved_edges_; } void NodeViewScene::SetEdgesAreCurved(bool curved) { if (curved_edges_ != curved) { curved_edges_ = curved; foreach (NodeViewEdge* e, edge_map_) { e->SetCurved(curved_edges_); } } } void NodeViewScene::NodePositionChanged(const QPointF &pos) { item_map_.value(static_cast(sender()))->SetNodePosition(pos); } void NodeViewScene::NodeLabelChanged() { item_map_.value(static_cast(sender()))->update(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeview/nodeviewscene.h000066400000000000000000000104641370472574300233130ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEVIEWSCENE_H #define NODEVIEWSCENE_H #include #include #include "node/graph.h" #include "nodeviewedge.h" #include "nodeviewitem.h" OLIVE_NAMESPACE_ENTER class NodeViewScene : public QGraphicsScene { Q_OBJECT public: NodeViewScene(QObject *parent = nullptr); void clear(); void SelectAll(); void DeselectAll(); /** * @brief Retrieve the graphical widget corresponding to a specific Node * * In situations where you know what Node you're working with but need the UI object (e.g. for positioning), this * static function will retrieve the NodeViewItem (Node UI representation) connected to this Node in a certain * QGraphicsScene. This can be called from any other UI object, since it'll have a reference to the QGraphicsScene * through QGraphicsItem::scene(). * * If the scene does not contain a widget for this node (usually meaning the node's graph is not the active graph * in this view/scene), this function returns nullptr. */ NodeViewItem* NodeToUIObject(Node* n); /** * @brief Retrieve the graphical widget corresponding to a specific NodeEdge * * Same as NodeToUIObject() but returns a NodeViewEdge corresponding to a NodeEdgePtr instead. */ NodeViewEdge* EdgeToUIObject(NodeEdgePtr n); void SetGraph(NodeGraph* graph); QList GetSelectedNodes() const; QList GetSelectedItems() const; QList GetSelectedEdges() const; const QHash& item_map() const; const QHash& edge_map() const; Qt::Orientation GetFlowOrientation() const; NodeViewCommon::FlowDirection GetFlowDirection() const; void SetFlowDirection(NodeViewCommon::FlowDirection direction); /** * @brief Automatically reposition the nodes based on their connections */ void ReorganizeFrom(Node* n); bool GetEdgesAreCurved() const; public slots: /** * @brief Slot when a Node is added to a graph (SetGraph() connects this) * * This should NEVER be called directly, only connected to a NodeGraph. To add a Node to the NodeGraph * use NodeGraph::AddNode(). */ void AddNode(Node* node); /** * @brief Slot when a Node is removed from a graph (SetGraph() connects this) * * This should NEVER be called directly, only connected to a NodeGraph. To remove a Node from the NodeGraph * use NodeGraph::RemoveNode(). */ void RemoveNode(Node* node); /** * @brief Slot when an edge is added to a graph (SetGraph() connects this) * * This should NEVER be called directly, only connected to a NodeGraph. To add an edge (i.e. connect two node * parameters together), use NodeParam::ConnectEdge(). */ void AddEdge(NodeEdgePtr edge); /** * @brief Slot when an edge is removed from a graph (SetGraph() connects this) * * This should NEVER be called directly, only connected to a NodeGraph. To remove an edge (i.e. disconnect two node * parameters), use NodeParam::DisconnectEdge(). */ void RemoveEdge(NodeEdgePtr edge); /** * @brief Set whether edges in this scene should be curved or not */ void SetEdgesAreCurved(bool curved); private: static int DetermineWeight(Node* n); QHash item_map_; QHash edge_map_; NodeGraph* graph_; NodeViewCommon::FlowDirection direction_; bool curved_edges_; private slots: /** * @brief Receiver for whenever a node position changes */ void NodePositionChanged(const QPointF& pos); /** * @brief Receiver for when a node's label has changed */ void NodeLabelChanged(); }; OLIVE_NAMESPACE_EXIT #endif // NODEVIEWSCENE_H olive-continuous/app/widget/nodeview/nodeviewundo.cpp000066400000000000000000000116361370472574300235200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "nodeviewundo.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER NodeEdgeAddCommand::NodeEdgeAddCommand(NodeOutput *output, NodeInput *input, QUndoCommand *parent) : UndoCommand(parent), output_(output), input_(input), old_edge_(nullptr), done_(false) { } void NodeEdgeAddCommand::redo_internal() { if (done_) { return; } old_edge_ = NodeParam::DisconnectForNewOutput(input_); NodeParam::ConnectEdge(output_, input_); done_ = true; } void NodeEdgeAddCommand::undo_internal() { if (!done_) { return; } NodeParam::DisconnectEdge(output_, input_); if (old_edge_ != nullptr) { NodeParam::ConnectEdge(old_edge_->output(), old_edge_->input()); } done_ = false; } Project *NodeEdgeAddCommand::GetRelevantProject() const { return static_cast(output_->parentNode()->parent())->project(); } NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(NodeOutput *output, NodeInput *input, QUndoCommand *parent) : UndoCommand(parent), output_(output), input_(input), done_(false) { } NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(NodeEdgePtr edge, QUndoCommand *parent) : UndoCommand(parent), output_(edge->output()), input_(edge->input()), done_(false) { } void NodeEdgeRemoveCommand::redo_internal() { if (done_) { return; } NodeParam::DisconnectEdge(output_, input_); done_ = true; } void NodeEdgeRemoveCommand::undo_internal() { if (!done_) { return; } NodeParam::ConnectEdge(output_, input_); done_ = false; } Project *NodeEdgeRemoveCommand::GetRelevantProject() const { return static_cast(output_->parentNode()->parent())->project(); } NodeAddCommand::NodeAddCommand(NodeGraph *graph, Node *node, QUndoCommand *parent) : UndoCommand(parent), graph_(graph), node_(node) { // Ensures that when this command is destroyed, if redo() is never called again, the node will be destroyed too node_->setParent(&memory_manager_); } void NodeAddCommand::redo_internal() { graph_->AddNode(node_); } void NodeAddCommand::undo_internal() { graph_->TakeNode(node_, &memory_manager_); } Project *NodeAddCommand::GetRelevantProject() const { return static_cast(graph_)->project(); } NodeRemoveCommand::NodeRemoveCommand(NodeGraph *graph, const QList &nodes, QUndoCommand *parent) : UndoCommand(parent), graph_(graph), nodes_(nodes) { } void NodeRemoveCommand::redo_internal() { // Cache edges for undoing foreach (Node* n, nodes_) { foreach (NodeParam* param, n->parameters()) { foreach (NodeEdgePtr edge, param->edges()) { // Ensures the same edge isn't added twice (prevents double connecting when undoing) if (!edges_.contains(edge)) { edges_.append(edge); } } } } // Take nodes from graph (TakeNode() will automatically disconnect edges) foreach (Node* n, nodes_) { graph_->TakeNode(n, &memory_manager_); } } void NodeRemoveCommand::undo_internal() { // Re-add nodes to graph foreach (Node* n, nodes_) { graph_->AddNode(n); } // Re-connect edges foreach (NodeEdgePtr edge, edges_) { NodeParam::ConnectEdge(edge->output(), edge->input()); } edges_.clear(); } Project *NodeRemoveCommand::GetRelevantProject() const { return static_cast(graph_)->project(); } NodeRemoveWithExclusiveDeps::NodeRemoveWithExclusiveDeps(NodeGraph *graph, Node *node, QUndoCommand *parent) : UndoCommand(parent) { QList node_and_its_deps; node_and_its_deps.append(node); node_and_its_deps.append(node->GetExclusiveDependencies()); remove_command_ = new NodeRemoveCommand(graph, node_and_its_deps, this); } Project *NodeRemoveWithExclusiveDeps::GetRelevantProject() const { return remove_command_->GetRelevantProject(); } NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, bool include_connections, QUndoCommand *parent) : QUndoCommand(parent), src_(src), dest_(dest), include_connections_(include_connections) { } NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, QUndoCommand *parent) : QUndoCommand(parent), src_(src), dest_(dest), include_connections_(true) { } void NodeCopyInputsCommand::redo() { Node::CopyInputs(src_, dest_, include_connections_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/nodeview/nodeviewundo.h000066400000000000000000000072511370472574300231630ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef NODEVIEWUNDO_H #define NODEVIEWUNDO_H #include #include "node/graph.h" #include "node/node.h" #include "nodeviewitem.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER /** * @brief An undoable command for connecting two NodeParams together * * Can be considered a QUndoCommand wrapper for NodeParam::ConnectEdge()/ */ class NodeEdgeAddCommand : public UndoCommand { public: NodeEdgeAddCommand(NodeOutput* output, NodeInput* input, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeOutput* output_; NodeInput* input_; NodeEdgePtr old_edge_; bool done_; }; /** * @brief An undoable command for disconnecting two NodeParams * * Can be considered a QUndoCommand wrapper for NodeParam::DisonnectEdge()/ */ class NodeEdgeRemoveCommand : public UndoCommand { public: NodeEdgeRemoveCommand(NodeOutput* output, NodeInput* input, QUndoCommand* parent = nullptr); NodeEdgeRemoveCommand(NodeEdgePtr edge, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: NodeOutput* output_; NodeInput* input_; bool done_; }; class NodeAddCommand : public UndoCommand { public: NodeAddCommand(NodeGraph* graph, Node* node, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: QObject memory_manager_; NodeGraph* graph_; Node* node_; }; class NodeRemoveCommand : public UndoCommand { public: NodeRemoveCommand(NodeGraph* graph, const QList& nodes, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: QObject memory_manager_; NodeGraph* graph_; QList nodes_; QList edges_; }; class NodeRemoveWithExclusiveDeps : public UndoCommand { public: NodeRemoveWithExclusiveDeps(NodeGraph* graph, Node* node, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; private: NodeRemoveCommand* remove_command_; }; class NodeCopyInputsCommand : public QUndoCommand { public: NodeCopyInputsCommand(Node* src, Node* dest, bool include_connections = true, QUndoCommand* parent = nullptr); NodeCopyInputsCommand(Node* src, Node* dest, QUndoCommand* parent = nullptr); protected: virtual void redo() override; private: Node* src_; Node* dest_; bool include_connections_; }; OLIVE_NAMESPACE_EXIT #endif // NODEVIEWUNDO_H olive-continuous/app/widget/panel/000077500000000000000000000000001370472574300175565ustar00rootroot00000000000000olive-continuous/app/widget/panel/CMakeLists.txt000066400000000000000000000014451370472574300223220ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/panel/panel.h widget/panel/panel.cpp PARENT_SCOPE ) olive-continuous/app/widget/panel/panel.cpp000066400000000000000000000072411370472574300213650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "panel.h" #include #include #include #include #include #include #include OLIVE_NAMESPACE_ENTER PanelWidget::PanelWidget(const QString &object_name, QWidget *parent) : QDockWidget(parent), border_visible_(false), signal_instead_of_close_(false) { setObjectName(object_name); setFocusPolicy(Qt::ClickFocus); connect(this, &PanelWidget::visibilityChanged, this, &PanelWidget::PanelVisibilityChanged); } void PanelWidget::SetMovementLocked(bool locked) { if (locked) { // Disable moving on QDockWidget setFeatures(features() & ~QDockWidget::DockWidgetMovable); // Hide the title bar (only real way to do this is to replace it with an empty QWidget) setTitleBarWidget(new QWidget(this)); } else { // Re-enable moving on QDockWidget setFeatures(features() | QDockWidget::DockWidgetMovable); // Set the "custom" titlebar to null so the default gets restored setTitleBarWidget(nullptr); } } void PanelWidget::SetBorderVisible(bool enabled) { border_visible_ = enabled; update(); } void PanelWidget::SetTitle(const QString &t) { title_ = t; UpdateTitle(); } void PanelWidget::SetSubtitle(const QString &t) { subtitle_ = t; UpdateTitle(); } void PanelWidget::paintEvent(QPaintEvent *event) { // Perform default behavior QDockWidget::paintEvent(event); // Check if this panel (or a child of it) has focus using PanelFocusManager if (border_visible_) { // Draw a highlight border if so QPainter p(this); // We need to adjust the rect by 1 pixel since the bottom and right are "offscreen" QRect highlight_border = rect(); highlight_border.adjust(0, 0, -1, -1); // Set the color to the palette's highlight color p.setPen(palette().highlight().color()); // Draw the highlight border p.drawRect(highlight_border); } } void PanelWidget::UpdateTitle() { // If there's no subtitle, just use the title. Otherwise, we set a formatted combination of the two that can // differ based on translation if (subtitle_.isEmpty()) { setWindowTitle(title_); } else { setWindowTitle(tr("%1: %2").arg(title_, subtitle_)); } } void PanelWidget::PanelVisibilityChanged(bool e) { if (e) { setFocus(); } } void PanelWidget::SetSignalInsteadOfClose(bool e) { signal_instead_of_close_ = e; } void PanelWidget::closeEvent(QCloseEvent *event) { if (signal_instead_of_close_) { event->ignore(); emit CloseRequested(); } else { QDockWidget::closeEvent(event); } } void PanelWidget::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); } QDockWidget::changeEvent(e); } void PanelWidget::Retranslate() { } void PanelWidget::SetWidgetWithPadding(QWidget *widget) { QWidget* wrapper = new QWidget(); QHBoxLayout* layout = new QHBoxLayout(wrapper); layout->setMargin(layout->margin() / 2); layout->addWidget(widget); setWidget(wrapper); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/panel/panel.h000066400000000000000000000125061370472574300210320ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PANEL_WIDGET_H #define PANEL_WIDGET_H #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget that is always dockable within the MainWindow. */ class PanelWidget : public QDockWidget { Q_OBJECT public: /** * @brief PanelWidget Constructor * * @param parent * * The PanelWidget's parent, enforced to help with memory handling. Most of the time this will be an instance of * MainWindow. */ PanelWidget(const QString& object_name, QWidget* parent); /** * @brief Set whether panel movement is locked or not */ void SetMovementLocked(bool locked); /** * @brief Set visibility of panel's highlighted border, mostly used for showing panel focus * * @param enabled */ void SetBorderVisible(bool enabled); /** * @brief If enabled, sends signal CloseRequested() when the user closes instead of closing * * Defaults to FALSE. Use this to override default panel closing functionality. */ void SetSignalInsteadOfClose(bool e); /** * @brief Called whenever this panel is focused and user uses "Zoom In" (either in menus or as a keyboard shortcut) * * This function is up to the Panel's interpretation of what the user intends to zoom into. Default behavior is a * no-op. */ virtual void ZoomIn(){} /** * @brief Called whenever this panel is focused and user uses "Zoom Out" (either in menus or as a keyboard shortcut) * * This function is up to the Panel's interpretation of what the user intends to zoom out of. Default behavior is a * no-op. */ virtual void ZoomOut(){} virtual void GoToStart(){} virtual void PrevFrame(){} /** * @brief Called whenever this panel is focused and user uses "Play/Pause" (either in menus or as a keyboard shortcut) * * This function is up to the Panel's interpretation of what the user intends to zoom out of. Default behavior is a * no-op. */ virtual void PlayPause(){} virtual void PlayInToOut(){} virtual void NextFrame(){} virtual void GoToEnd(){} virtual void SelectAll(){} virtual void DeselectAll(){} virtual void RippleToIn(){} virtual void RippleToOut(){} virtual void EditToIn(){} virtual void EditToOut(){} virtual void ShuttleLeft(){} virtual void ShuttleStop(){} virtual void ShuttleRight(){} virtual void GoToPrevCut(){} virtual void GoToNextCut(){} virtual void DeleteSelected(){} virtual void RippleDelete(){} virtual void Insert(){} virtual void Overwrite(){} virtual void IncreaseTrackHeight(){} virtual void DecreaseTrackHeight(){} virtual void SetIn(){} virtual void SetOut(){} virtual void ResetIn(){} virtual void ResetOut(){} virtual void ClearInOut(){} virtual void SetMarker(){} virtual void ToggleLinks(){} virtual void CutSelected(){} virtual void CopySelected(){} virtual void Paste(){} virtual void PasteInsert(){} virtual void ToggleShowAll(){} virtual void GoToIn(){} virtual void GoToOut(){} virtual void DeleteInToOut(){} virtual void RippleDeleteInToOut(){} virtual void ToggleSelectedEnabled(){} virtual void Duplicate(){} signals: void CloseRequested(); protected: /** * @brief paintEvent * @param event */ void paintEvent(QPaintEvent *event) override; virtual void changeEvent(QEvent* e) override; virtual void closeEvent(QCloseEvent* event) override; virtual void Retranslate(); void SetWidgetWithPadding(QWidget* widget); protected slots: /** * @brief Set panel's title * * Use this function to set the title of the panel. * * A PanelWidget has the default format of "Title: Subtitle" (can differ depending on translation). If no Subtitle * is set, the title will just be formatted "Title". * * @param t * * String to set the title to */ void SetTitle(const QString& t); /** * @brief Set panel's subtitle * * Use this function to set the subtitle of the panel. * * A PanelWidget has the default format of "Title: Subtitle" (can differ depending on translation). If no Subtitle * is set, the title will just be formatted "Title". * * @param t * * String to set the subtitle to */ void SetSubtitle(const QString& t); private: /** * @brief Internal function that sets the QDockWidget's window title whenever the title/subtitle change. * * Should be called any time a change is made to title_ or subtitle_ */ void UpdateTitle(); QString title_; QString subtitle_; bool border_visible_; bool signal_instead_of_close_; private slots: void PanelVisibilityChanged(bool e); }; OLIVE_NAMESPACE_EXIT #endif // PANEL_WIDGET_H olive-continuous/app/widget/pixelsampler/000077500000000000000000000000001370472574300211645ustar00rootroot00000000000000olive-continuous/app/widget/pixelsampler/CMakeLists.txt000066400000000000000000000015011370472574300237210ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/pixelsampler/pixelsampler.h widget/pixelsampler/pixelsampler.cpp PARENT_SCOPE ) olive-continuous/app/widget/pixelsampler/pixelsampler.cpp000066400000000000000000000044061370472574300244010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "pixelsampler.h" #include OLIVE_NAMESPACE_ENTER PixelSamplerWidget::PixelSamplerWidget(QWidget *parent) : QGroupBox(parent) { QVBoxLayout* layout = new QVBoxLayout(this); label_ = new QLabel(); layout->addWidget(label_); setTitle(tr("Color")); UpdateLabelInternal(); } void PixelSamplerWidget::SetValues(const Color &color) { color_ = color; UpdateLabelInternal(); } void PixelSamplerWidget::UpdateLabelInternal() { label_->setText(tr("" "R: %1
" "G: %2
" "B: %3
" "A: %4" "").arg(QString::number(color_.red()), QString::number(color_.green()), QString::number(color_.blue()), QString::number(color_.alpha()))); } ManagedPixelSamplerWidget::ManagedPixelSamplerWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); display_view_ = new PixelSamplerWidget(); display_view_->setTitle(tr("Display")); layout->addWidget(display_view_); reference_view_ = new PixelSamplerWidget(); reference_view_->setTitle(tr("Reference")); layout->addWidget(reference_view_); } void ManagedPixelSamplerWidget::SetValues(const Color &reference, const Color &display) { reference_view_->SetValues(reference); display_view_->SetValues(display); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/pixelsampler/pixelsampler.h000066400000000000000000000027061370472574300240470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PIXELSAMPLERWIDGET_H #define PIXELSAMPLERWIDGET_H #include #include #include #include "render/color.h" OLIVE_NAMESPACE_ENTER class PixelSamplerWidget : public QGroupBox { Q_OBJECT public: PixelSamplerWidget(QWidget* parent = nullptr); public slots: void SetValues(const Color& color); private: void UpdateLabelInternal(); Color color_; QLabel* label_; }; class ManagedPixelSamplerWidget : public QWidget { Q_OBJECT public: ManagedPixelSamplerWidget(QWidget* parent = nullptr); public slots: void SetValues(const Color& reference, const Color& display); private: PixelSamplerWidget* reference_view_; PixelSamplerWidget* display_view_; }; OLIVE_NAMESPACE_EXIT #endif // PIXELSAMPLERWIDGET_H olive-continuous/app/widget/playbackcontrols/000077500000000000000000000000001370472574300220315ustar00rootroot00000000000000olive-continuous/app/widget/playbackcontrols/CMakeLists.txt000066400000000000000000000016411370472574300245730ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/playbackcontrols/dragbutton.h widget/playbackcontrols/dragbutton.cpp widget/playbackcontrols/playbackcontrols.h widget/playbackcontrols/playbackcontrols.cpp PARENT_SCOPE ) olive-continuous/app/widget/playbackcontrols/dragbutton.cpp000066400000000000000000000017131370472574300247100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "dragbutton.h" OLIVE_NAMESPACE_ENTER DragButton::DragButton(QWidget *parent) : QPushButton(parent) { } void DragButton::mousePressEvent(QMouseEvent *event) { QPushButton::mousePressEvent(event); emit MousePressed(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/playbackcontrols/dragbutton.h000066400000000000000000000020761370472574300243600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef DRAGBUTTON_H #define DRAGBUTTON_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class DragButton : public QPushButton { Q_OBJECT public: DragButton(QWidget* parent = nullptr); signals: void MousePressed(); protected: virtual void mousePressEvent(QMouseEvent* event) override; }; OLIVE_NAMESPACE_EXIT #endif // DRAGBUTTON_H olive-continuous/app/widget/playbackcontrols/playbackcontrols.cpp000066400000000000000000000162041370472574300261120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "playbackcontrols.h" #include #include #include #include "core.h" #include "config/config.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER PlaybackControls::PlaybackControls(QWidget *parent) : QWidget(parent), time_base_(0) { // Create lower controls QHBoxLayout* lower_control_layout = new QHBoxLayout(this); lower_control_layout->setSpacing(0); lower_control_layout->setMargin(0); QSizePolicy lower_container_size_policy(QSizePolicy::Minimum, QSizePolicy::Expanding); lower_container_size_policy.setHorizontalStretch(1); // In the lower-left, we create a current timecode label wrapped in a QWidget for fixed sizing lower_left_container_ = new QWidget(); lower_left_container_->setVisible(false); lower_left_container_->setSizePolicy(lower_container_size_policy); lower_control_layout->addWidget(lower_left_container_); QHBoxLayout* lower_left_layout = new QHBoxLayout(lower_left_container_); lower_left_layout->setSpacing(0); lower_left_layout->setMargin(0); cur_tc_lbl_ = new TimeSlider(); connect(cur_tc_lbl_, &TimeSlider::ValueChanged, this, &PlaybackControls::TimeChanged); lower_left_layout->addWidget(cur_tc_lbl_); lower_left_layout->addStretch(); // This is only here QWidget* blank_widget = new QWidget(); //new QHBoxLayout(blank_widget); blank_widget->setSizePolicy(lower_container_size_policy); lower_control_layout->addWidget(blank_widget); // In the lower-middle, we create playback control buttons QWidget* lower_middle_container = new QWidget(); lower_middle_container->setSizePolicy(lower_container_size_policy); lower_control_layout->addWidget(lower_middle_container); QHBoxLayout* lower_middle_layout = new QHBoxLayout(lower_middle_container); lower_middle_layout->setSpacing(0); lower_middle_layout->setMargin(0); // Go To Start Button go_to_start_btn_ = new QPushButton(); lower_middle_layout->addWidget(go_to_start_btn_); connect(go_to_start_btn_, &QPushButton::clicked, this, &PlaybackControls::BeginClicked); // Prev Frame Button prev_frame_btn_ = new QPushButton(); lower_middle_layout->addWidget(prev_frame_btn_); connect(prev_frame_btn_, &QPushButton::clicked, this, &PlaybackControls::PrevFrameClicked); // Play/Pause Button playpause_stack_ = new QStackedWidget(); lower_middle_layout->addWidget(playpause_stack_); play_btn_ = new QPushButton(); playpause_stack_->addWidget(play_btn_); connect(play_btn_, &QPushButton::clicked, this, &PlaybackControls::PlayClicked); pause_btn_ = new QPushButton(); playpause_stack_->addWidget(pause_btn_); connect(pause_btn_, &QPushButton::clicked, this, &PlaybackControls::PauseClicked); // Default to showing play button playpause_stack_->setCurrentWidget(play_btn_); playpause_stack_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); // Next Frame Button next_frame_btn_ = new QPushButton(); lower_middle_layout->addWidget(next_frame_btn_); connect(next_frame_btn_, &QPushButton::clicked, this, &PlaybackControls::NextFrameClicked); // Go To End Button go_to_end_btn_ = new QPushButton(); lower_middle_layout->addWidget(go_to_end_btn_); connect(go_to_end_btn_, &QPushButton::clicked, this, &PlaybackControls::EndClicked); QWidget* av_btn_widget = new QWidget(); av_btn_widget->setSizePolicy(lower_container_size_policy); QHBoxLayout* av_btn_layout = new QHBoxLayout(av_btn_widget); av_btn_layout->setSpacing(0); av_btn_layout->setMargin(0); video_drag_btn_ = new DragButton(); connect(video_drag_btn_, &QPushButton::clicked, this, &PlaybackControls::VideoClicked); connect(video_drag_btn_, &DragButton::MousePressed, this, &PlaybackControls::VideoPressed); av_btn_layout->addWidget(video_drag_btn_); audio_drag_btn_ = new DragButton(); connect(audio_drag_btn_, &QPushButton::clicked, this, &PlaybackControls::AudioClicked); connect(audio_drag_btn_, &DragButton::MousePressed, this, &PlaybackControls::AudioPressed); av_btn_layout->addWidget(audio_drag_btn_); lower_control_layout->addWidget(av_btn_widget); // The lower-right, we create another timecode label, this time to show the end timecode lower_right_container_ = new QWidget(); lower_right_container_->setVisible(false); lower_right_container_->setSizePolicy(lower_container_size_policy); lower_control_layout->addWidget(lower_right_container_); QHBoxLayout* lower_right_layout = new QHBoxLayout(lower_right_container_); lower_right_layout->setSpacing(0); lower_right_layout->setMargin(0); lower_right_layout->addStretch(); end_tc_lbl_ = new QLabel(); lower_right_layout->addWidget(end_tc_lbl_); UpdateIcons(); SetTimebase(0); SetAudioVideoDragButtonsVisible(false); connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &PlaybackControls::TimecodeChanged); } void PlaybackControls::SetTimecodeEnabled(bool enabled) { lower_left_container_->setVisible(enabled); lower_right_container_->setVisible(enabled); } void PlaybackControls::SetTimebase(const rational &r) { time_base_ = r; cur_tc_lbl_->SetTimebase(r); cur_tc_lbl_->setEnabled(!r.isNull()); } void PlaybackControls::SetAudioVideoDragButtonsVisible(bool e) { video_drag_btn_->setVisible(e); audio_drag_btn_->setVisible(e); } void PlaybackControls::SetTime(const int64_t &r) { cur_tc_lbl_->SetValue(r); } void PlaybackControls::SetEndTime(const int64_t &r) { if (time_base_.isNull()) { return; } end_time_ = r; end_tc_lbl_->setText(Timecode::timestamp_to_timecode(end_time_, time_base_, Core::instance()->GetTimecodeDisplay())); } void PlaybackControls::ShowPauseButton() { // Play was clicked, toggle to pause playpause_stack_->setCurrentWidget(pause_btn_); } void PlaybackControls::ShowPlayButton() { playpause_stack_->setCurrentWidget(play_btn_); } void PlaybackControls::changeEvent(QEvent *e) { QWidget::changeEvent(e); if (e->type() == QEvent::StyleChange) { UpdateIcons(); } } void PlaybackControls::UpdateIcons() { go_to_start_btn_->setIcon(icon::GoToStart); prev_frame_btn_->setIcon(icon::PrevFrame); play_btn_->setIcon(icon::Play); pause_btn_->setIcon(icon::Pause); next_frame_btn_->setIcon(icon::NextFrame); go_to_end_btn_->setIcon(icon::GoToEnd); video_drag_btn_->setIcon(icon::Video); audio_drag_btn_->setIcon(icon::Audio); } void PlaybackControls::TimecodeChanged() { // Update end time SetEndTime(end_time_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/playbackcontrols/playbackcontrols.h000066400000000000000000000055671370472574300255710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PLAYBACKCONTROLS_H #define PLAYBACKCONTROLS_H #include #include #include #include #include "common/rational.h" #include "dragbutton.h" #include "widget/slider/timeslider.h" OLIVE_NAMESPACE_ENTER /** * @brief A playback controls widget providing buttons for navigating media * * This widget optionally features timecode displays for the current timecode and end timecode. */ class PlaybackControls : public QWidget { Q_OBJECT public: PlaybackControls(QWidget* parent = nullptr); /** * @brief Set whether the timecodes should be shown or not */ void SetTimecodeEnabled(bool enabled); void SetTimebase(const rational& r); void SetAudioVideoDragButtonsVisible(bool e); public slots: void SetTime(const int64_t &r); void SetEndTime(const int64_t &r); void ShowPauseButton(); void ShowPlayButton(); signals: /** * @brief Signal emitted when "Go to Start" is clicked */ void BeginClicked(); /** * @brief Signal emitted when "Previous Frame" is clicked */ void PrevFrameClicked(); /** * @brief Signal emitted when "Play" is clicked */ void PlayClicked(); /** * @brief Signal emitted when "Pause" is clicked */ void PauseClicked(); /** * @brief Signal emitted when "Next Frame" is clicked */ void NextFrameClicked(); /** * @brief Signal emitted when "Go to End" is clicked */ void EndClicked(); void AudioClicked(); void VideoClicked(); void AudioPressed(); void VideoPressed(); void TimeChanged(const int64_t& t); protected: virtual void changeEvent(QEvent *) override; private: void UpdateIcons(); QWidget* lower_left_container_; QWidget* lower_right_container_; TimeSlider* cur_tc_lbl_; QLabel* end_tc_lbl_; int64_t end_time_; rational time_base_; QPushButton* go_to_start_btn_; QPushButton* prev_frame_btn_; QPushButton* play_btn_; QPushButton* pause_btn_; QPushButton* next_frame_btn_; QPushButton* go_to_end_btn_; DragButton* video_drag_btn_; DragButton* audio_drag_btn_; QStackedWidget* playpause_stack_; private slots: void TimecodeChanged(); }; OLIVE_NAMESPACE_EXIT #endif // PLAYBACKCONTROLS_H olive-continuous/app/widget/projectexplorer/000077500000000000000000000000001370472574300217065ustar00rootroot00000000000000olive-continuous/app/widget/projectexplorer/CMakeLists.txt000066400000000000000000000031411370472574300244450ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/projectexplorer/projectexplorer.h widget/projectexplorer/projectexplorer.cpp widget/projectexplorer/projectexplorertreeview.h widget/projectexplorer/projectexplorertreeview.cpp widget/projectexplorer/projectexplorerlistview.h widget/projectexplorer/projectexplorerlistview.cpp widget/projectexplorer/projectexplorerlistviewbase.h widget/projectexplorer/projectexplorerlistviewbase.cpp widget/projectexplorer/projectexplorerlistviewitemdelegate.h widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp widget/projectexplorer/projectexplorericonview.h widget/projectexplorer/projectexplorericonview.cpp widget/projectexplorer/projectexplorericonviewitemdelegate.h widget/projectexplorer/projectexplorericonviewitemdelegate.cpp widget/projectexplorer/projectexplorernavigation.h widget/projectexplorer/projectexplorernavigation.cpp PARENT_SCOPE ) olive-continuous/app/widget/projectexplorer/projectexplorer.cpp000066400000000000000000000370321370472574300256460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorer.h" #include #include #include #include #include #include #include "common/define.h" #include "core.h" #include "dialog/footageproperties/footageproperties.h" #include "dialog/sequence/sequence.h" #include "task/cache/footagecache.h" #include "task/taskmanager.h" #include "widget/menu/menu.h" #include "widget/menu/menushared.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER ProjectExplorer::ProjectExplorer(QWidget *parent) : QWidget(parent), model_(this) { // Create layout QVBoxLayout* layout = new QVBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); // Set up navigation bar nav_bar_ = new ProjectExplorerNavigation(this); connect(nav_bar_, &ProjectExplorerNavigation::SizeChanged, this, &ProjectExplorer::SizeChangedSlot); connect(nav_bar_, &ProjectExplorerNavigation::DirectoryUpClicked, this, &ProjectExplorer::DirUpSlot); layout->addWidget(nav_bar_); // Set up stacked widget stacked_widget_ = new QStackedWidget(this); layout->addWidget(stacked_widget_); // Add tree view to stacked widget tree_view_ = new ProjectExplorerTreeView(stacked_widget_); tree_view_->setContextMenuPolicy(Qt::CustomContextMenu); AddView(tree_view_); // Add list view to stacked widget list_view_ = new ProjectExplorerListView(stacked_widget_); list_view_->setContextMenuPolicy(Qt::CustomContextMenu); AddView(list_view_); // Add icon view to stacked widget icon_view_ = new ProjectExplorerIconView(stacked_widget_); icon_view_->setContextMenuPolicy(Qt::CustomContextMenu); AddView(icon_view_); // Set default view to tree view set_view_type(ProjectToolbar::TreeView); // Set default icon size SizeChangedSlot(kProjectIconSizeDefault); // Set rename timer timeout rename_timer_.setInterval(500); connect(&rename_timer_, &QTimer::timeout, this, &ProjectExplorer::RenameTimerSlot); connect(tree_view_, &ProjectExplorerTreeView::customContextMenuRequested, this, &ProjectExplorer::ShowContextMenu); connect(list_view_, &ProjectExplorerListView::customContextMenuRequested, this, &ProjectExplorer::ShowContextMenu); connect(icon_view_, &ProjectExplorerIconView::customContextMenuRequested, this, &ProjectExplorer::ShowContextMenu); } const ProjectToolbar::ViewType &ProjectExplorer::view_type() const { return view_type_; } void ProjectExplorer::set_view_type(ProjectToolbar::ViewType type) { view_type_ = type; // Set widget based on view type switch (view_type_) { case ProjectToolbar::TreeView: stacked_widget_->setCurrentWidget(tree_view_); nav_bar_->setVisible(false); break; case ProjectToolbar::ListView: stacked_widget_->setCurrentWidget(list_view_); nav_bar_->setVisible(true); break; case ProjectToolbar::IconView: stacked_widget_->setCurrentWidget(icon_view_); nav_bar_->setVisible(true); break; } } void ProjectExplorer::Edit(Item *item) { CurrentView()->edit(model_.CreateIndexFromItem(item)); } void ProjectExplorer::AddView(QAbstractItemView *view) { view->setModel(&model_); view->setEditTriggers(QAbstractItemView::NoEditTriggers); connect(view, &QAbstractItemView::clicked, this, &ProjectExplorer::ItemClickedSlot); connect(view, &QAbstractItemView::doubleClicked, this, &ProjectExplorer::ItemDoubleClickedSlot); connect(view, SIGNAL(DoubleClickedEmptyArea()), this, SLOT(ViewEmptyAreaDoubleClickedSlot())); stacked_widget_->addWidget(view); } void ProjectExplorer::BrowseToFolder(const QModelIndex &index) { // Make sure any rename timers are stopped rename_timer_.stop(); // Set appropriate views to this index icon_view_->setRootIndex(index); list_view_->setRootIndex(index); // Set navbar text to folder's name if (index.isValid()) { Folder* f = static_cast(index.internalPointer()); nav_bar_->set_text(f->name()); } else { // Or set it to an empty string if the index is valid (which means we're browsing to the root directory) nav_bar_->set_text(QString()); } // Set directory up enabled button based on whether we're in root or not nav_bar_->set_dir_up_enabled(index.isValid()); } QAbstractItemView *ProjectExplorer::CurrentView() const { return static_cast(stacked_widget_->currentWidget()); } void ProjectExplorer::ItemClickedSlot(const QModelIndex &index) { if (index.isValid()) { if (clicked_index_ == index) { // The item has been clicked more than once, start a timer for renaming rename_timer_.start(); } else { // Cache this index for the next click clicked_index_ = index; // If the rename timer had started, stop it now rename_timer_.stop(); } } else { // Stop the rename timer rename_timer_.stop(); } } void ProjectExplorer::ViewEmptyAreaDoubleClickedSlot() { // Ensure no attempts to rename are made clicked_index_ = QModelIndex(); rename_timer_.stop(); emit DoubleClickedItem(nullptr); } void ProjectExplorer::ItemDoubleClickedSlot(const QModelIndex &index) { // Ensure no attempts to rename are made clicked_index_ = QModelIndex(); rename_timer_.stop(); // Retrieve source item from index Item* i = static_cast(index.internalPointer()); // If the item is a folder, browse to it if (i->CanHaveChildren() && (view_type() == ProjectToolbar::ListView || view_type() == ProjectToolbar::IconView)) { BrowseToFolder(index); } // Emit a signal emit DoubleClickedItem(i); } void ProjectExplorer::SizeChangedSlot(int s) { icon_view_->setGridSize(QSize(s, s)); list_view_->setIconSize(QSize(s, s)); } void ProjectExplorer::DirUpSlot() { QModelIndex current_root = icon_view_->rootIndex(); if (current_root.isValid()) { QModelIndex parent = current_root.parent(); BrowseToFolder(parent); } } void ProjectExplorer::RenameTimerSlot() { // Start editing this index CurrentView()->edit(clicked_index_); // Reset clicked index state clicked_index_ = QModelIndex(); // Stop rename timer rename_timer_.stop(); } void ProjectExplorer::ShowContextMenu() { Menu menu; Menu new_menu; context_menu_items_ = SelectedItems(); if (context_menu_items_.isEmpty()) { // Items to show if no items are selected // "New" menu new_menu.setTitle(tr("&New")); MenuShared::instance()->AddItemsForNewMenu(&new_menu); menu.addMenu(&new_menu); // "Import" action QAction* import_action = menu.addAction(tr("&Import...")); connect(import_action, &QAction::triggered, Core::instance(), &Core::DialogImportShow); menu.addSeparator(); // Project properties action QAction* project_properties = menu.addAction(tr("&Project Properties...")); connect(project_properties, &QAction::triggered, Core::instance(), &Core::DialogProjectPropertiesShow); } else { // Actions to add when only one item is selected if (context_menu_items_.size() == 1) { Item* context_menu_item = context_menu_items_.first(); switch (context_menu_item->type()) { case Item::kFolder: { QAction* open_in_new_tab = menu.addAction(tr("Open in New Tab")); connect(open_in_new_tab, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewTab); QAction* open_in_new_window = menu.addAction(tr("Open in New Window")); connect(open_in_new_window, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewWindow); break; } case Item::kFootage: { QString reveal_text; #if defined(Q_OS_WINDOWS) reveal_text = tr("Reveal in Explorer"); #elif defined(Q_OS_MAC) reveal_text = tr("Reveal in Finder"); #else reveal_text = tr("Reveal in File Manager"); #endif QAction* reveal_action = menu.addAction(reveal_text); connect(reveal_action, &QAction::triggered, this, &ProjectExplorer::RevealSelectedFootage); break; } case Item::kSequence: break; } menu.addSeparator(); } bool all_items_are_footage = true; bool all_items_have_video_streams = true; bool all_items_are_footage_or_sequence = true; foreach (Item* i, context_menu_items_) { if (i->type() == Item::kFootage && !static_cast(i)->HasStreamsOfType(Stream::kVideo)) { all_items_have_video_streams = false; } if (i->type() != Item::kFootage) { all_items_are_footage = false; } if (i->type() != Item::kFootage && i->type() != Item::kSequence) { all_items_are_footage_or_sequence = false; } } if (all_items_are_footage && all_items_have_video_streams) { Menu* proxy_menu = new Menu(tr("Pre-Cache"), &menu); menu.addMenu(proxy_menu); QList sequences = project()->get_items_of_type(Item::kSequence); if (sequences.isEmpty()) { QAction* a = proxy_menu->addAction(tr("No sequences exist in project")); a->setEnabled(false); } else { foreach (ItemPtr i, sequences) { QAction* a = proxy_menu->addAction(tr("For \"%1\"").arg(i->name())); a->setData(Node::PtrToValue(i.get())); } connect(proxy_menu, &Menu::triggered, this, &ProjectExplorer::ContextMenuStartProxy); } } Q_UNUSED(all_items_are_footage_or_sequence) if (context_menu_items_.size() == 1) { menu.addSeparator(); QAction* properties_action = menu.addAction(tr("P&roperties")); connect(properties_action, &QAction::triggered, this, &ProjectExplorer::ShowItemPropertiesDialog); } } menu.exec(QCursor::pos()); } void ProjectExplorer::ShowItemPropertiesDialog() { Item* sel = context_menu_items_.first(); switch (sel->type()) { case Item::kFootage: { // FIXME: Support for multiple items FootagePropertiesDialog fpd(this, static_cast(sel)); fpd.exec(); break; } case Item::kFolder: { // FIXME: Rename dialog probably break; } case Item::kSequence: { // FIXME: Support for multiple items SequenceDialog sd(static_cast(sel), SequenceDialog::kExisting, this); sd.exec(); break; } } } void ProjectExplorer::RevealSelectedFootage() { Footage* footage = static_cast(context_menu_items_.first()); #if defined(Q_OS_WINDOWS) // Explorer QStringList args; args << "/select," << QDir::toNativeSeparators(footage->filename()); QProcess::startDetached("explorer", args); #elif defined(Q_OS_MAC) QStringList args; args << "-e"; args << "tell application \"Finder\""; args << "-e"; args << "activate"; args << "-e"; args << "select POSIX file \""+footage->filename()+"\""; args << "-e"; args << "end tell"; QProcess::startDetached("osascript", args); #else QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(footage->filename()).dir().absolutePath())); #endif } void ProjectExplorer::OpenContextMenuItemInNewTab() { Core::instance()->main_window()->FolderOpen(project(), context_menu_items_.first(), false); } void ProjectExplorer::OpenContextMenuItemInNewWindow() { Core::instance()->main_window()->FolderOpen(project(), context_menu_items_.first(), true); } void ProjectExplorer::ContextMenuStartProxy(QAction *a) { QList video_streams; // To get here, the `context_menu_items_` must be all kFootage foreach (Item* i, context_menu_items_) { VideoStreamPtr s = std::static_pointer_cast(static_cast(i)->get_first_stream_of_type(Stream::kVideo)); if (s) { video_streams.append(s); } } Sequence* sequence = Node::ValueToPtr(a->data()); // Start a background task for proxying foreach (VideoStreamPtr video_stream, video_streams) { FootageCacheTask* proxy_task = new FootageCacheTask(video_stream, sequence); TaskManager::instance()->AddTask(proxy_task); } } Project *ProjectExplorer::project() const { return model_.project(); } void ProjectExplorer::set_project(Project *p) { model_.set_project(p); } QModelIndex ProjectExplorer::get_root_index() const { return tree_view_->rootIndex(); } void ProjectExplorer::set_root(Item *item) { QModelIndex index = model_.CreateIndexFromItem(item); BrowseToFolder(index); tree_view_->setRootIndex(index); } QList ProjectExplorer::SelectedItems() const { // Determine which view is active and get its selected indexes QModelIndexList index_list = CurrentView()->selectionModel()->selectedRows(); // Convert indexes to item objects QList selected_items; for (int i=0;i(index.internalPointer()); selected_items.append(item); } return selected_items; } Folder *ProjectExplorer::GetSelectedFolder() const { if (project() == nullptr) { return nullptr; } Folder* folder = nullptr; // Get the selected items from the panel QList selected_items = SelectedItems(); // Heuristic for finding the selected folder: // // - If `folder` is nullptr, we set the first folder we find. Either the item itself if it's a folder, or the // item's parent. // - Otherwise, if all folders found are the same, we'll use that to import into. // - If more than one folder is found, we play it safe and import into the root folder for (int i=0;iCanHaveChildren()) { sel_item = sel_item->parent(); Q_ASSERT(sel_item->CanHaveChildren()); } if (folder == nullptr) { // If the folder is nullptr, cache it as this folder folder = static_cast(sel_item); } else if (folder != sel_item) { // If not, we've already cached a folder so we check if it's the same // If it isn't, we "play it safe" and use the root folder folder = nullptr; break; } } // If we didn't pick up a folder from the heuristic above for whatever reason, use root if (folder == nullptr) { folder = project()->root(); } return folder; } ProjectViewModel *ProjectExplorer::model() { return &model_; } void ProjectExplorer::SelectAll() { CurrentView()->selectAll(); } void ProjectExplorer::DeselectAll() { CurrentView()->selectionModel()->clearSelection(); } void ProjectExplorer::DeleteSelected() { QList selected = SelectedItems(); if (selected.isEmpty()) { return; } QUndoCommand* command = new QUndoCommand(); foreach (Item* item, selected) { ItemPtr item_ptr = item->get_shared_ptr(); // If this is a sequence, close it if (item_ptr->type() == Item::kSequence) { Sequence* s = static_cast(item_ptr.get()); if (Core::instance()->main_window()->IsSequenceOpen(s)) { Core::instance()->main_window()->CloseSequence(s); } } new ProjectViewModel::RemoveItemCommand(&model_, item_ptr, command); } Core::instance()->undo_stack()->pushIfHasChildren(command); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorer.h000066400000000000000000000107101370472574300253050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORER_H #define PROJECTEXPLORER_H #include #include #include #include "project/project.h" #include "project/projectviewmodel.h" #include "widget/projectexplorer/projectexplorericonview.h" #include "widget/projectexplorer/projectexplorerlistview.h" #include "widget/projectexplorer/projectexplorertreeview.h" #include "widget/projectexplorer/projectexplorernavigation.h" #include "widget/projecttoolbar/projecttoolbar.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget for browsing through a Project structure. * * ProjectExplorer automatically handles the view<->model system using a ProjectViewModel. Therefore, all that needs to * be provided is the Project structure itself. * * This widget contains three views, tree view, list view, and icon view. These can be switched at any time. */ class ProjectExplorer : public QWidget { Q_OBJECT public: ProjectExplorer(QWidget* parent); const ProjectToolbar::ViewType& view_type() const; Project* project() const; void set_project(Project* p); QModelIndex get_root_index() const; void set_root(Item* item); QList SelectedItems() const; /** * @brief Use a heuristic to determine which (if any) folder is selected * * Generally for some import/adding processes, we assume that if a folder is selected, the user probably wants to * create the new object in it rather than in the root. If, however, more than one folder is selected, we can't * truly determine any folder from this and just return the root instead. * * @return * * A folder that's heuristically been determined as "selected", or the root directory if none, or nullptr if no * project is open. */ Folder* GetSelectedFolder() const; /** * @brief Access the ViewModel model of the project */ ProjectViewModel* model(); void SelectAll(); void DeselectAll(); void DeleteSelected(); public slots: void set_view_type(ProjectToolbar::ViewType type); void Edit(Item* item); signals: /** * @brief Emitted when an Item is double clicked * * @param item * * The Item that was double clicked, or nullptr if empty area was double clicked */ void DoubleClickedItem(Item* item); private: /** * @brief Simple convenience function for adding a view to this stacked widget * * Mainly for use in the constructor. Adds the view, connects its signals/slots, and sets the model. * * @param view * * View to add to the stack */ void AddView(QAbstractItemView* view); /** * @brief Browse to a specific folder index in the model * * Only affects list_view_ and icon_view_. * * @param index * * Either an invalid index to return to the project root, or an index to a valid Folder object. */ void BrowseToFolder(const QModelIndex& index); /** * @brief Get the currently active QAbstractItemView */ QAbstractItemView* CurrentView() const; QStackedWidget* stacked_widget_; ProjectExplorerNavigation* nav_bar_; ProjectExplorerIconView* icon_view_; ProjectExplorerListView* list_view_; ProjectExplorerTreeView* tree_view_; ProjectToolbar::ViewType view_type_; ProjectViewModel model_; QModelIndex clicked_index_; QTimer rename_timer_; QList context_menu_items_; private slots: void ItemClickedSlot(const QModelIndex& index); void ViewEmptyAreaDoubleClickedSlot(); void ItemDoubleClickedSlot(const QModelIndex& index); void SizeChangedSlot(int s); void DirUpSlot(); void RenameTimerSlot(); void ShowContextMenu(); void ShowItemPropertiesDialog(); void RevealSelectedFootage(); void OpenContextMenuItemInNewTab(); void OpenContextMenuItemInNewWindow(); void ContextMenuStartProxy(QAction* a); }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORER_H olive-continuous/app/widget/projectexplorer/projectexplorericonview.cpp000066400000000000000000000017151370472574300274110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorericonview.h" OLIVE_NAMESPACE_ENTER ProjectExplorerIconView::ProjectExplorerIconView(QWidget *parent) : ProjectExplorerListViewBase(parent) { setViewMode(QListView::IconMode); setItemDelegate(&delegate_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorericonview.h000066400000000000000000000023101370472574300270460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERICONVIEW_H #define PROJECTEXPLORERICONVIEW_H #include "projectexplorerlistviewbase.h" #include "projectexplorericonviewitemdelegate.h" OLIVE_NAMESPACE_ENTER /** * @brief The view widget used when ProjectExplorer is in Icon View */ class ProjectExplorerIconView : public ProjectExplorerListViewBase { Q_OBJECT public: ProjectExplorerIconView(QWidget* parent); private: ProjectExplorerIconViewItemDelegate delegate_; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERICONVIEW_H olive-continuous/app/widget/projectexplorer/projectexplorericonviewitemdelegate.cpp000066400000000000000000000063601370472574300317640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorericonviewitemdelegate.h" #include #include "common/qtutils.h" OLIVE_NAMESPACE_ENTER ProjectExplorerIconViewItemDelegate::ProjectExplorerIconViewItemDelegate(QObject *parent) : QStyledItemDelegate (parent) { } QSize ProjectExplorerIconViewItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { Q_UNUSED(option) return QSize(256, 256); } void ProjectExplorerIconViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QFontMetrics fm = painter->fontMetrics(); QRect img_rect = option.rect; // Draw Text if (fm.height() < option.rect.height() / 2) { img_rect.setHeight(img_rect.height()-fm.height()); QRect text_rect = option.rect; text_rect.setTop(text_rect.top() + option.rect.height() - fm.height()); QColor text_bgcolor; QColor text_fgcolor; if (option.state & QStyle::State_Selected) { text_bgcolor = option.palette.highlight().color(); text_fgcolor = option.palette.highlightedText().color(); } else { text_bgcolor = Qt::white; text_fgcolor = Qt::black; } painter->fillRect(text_rect, text_bgcolor); painter->setPen(text_fgcolor); QString duration_str = index.data(Qt::UserRole).toString(); int timecode_width = QFontMetricsWidth(fm, duration_str); int max_name_width = option.rect.width(); if (timecode_width < option.rect.width() / 2) { painter->drawText(text_rect, static_cast(Qt::AlignBottom | Qt::AlignRight), index.data(Qt::UserRole).toString()); max_name_width -= timecode_width; } painter->drawText(text_rect, static_cast(Qt::AlignBottom | Qt::AlignLeft), fm.elidedText(index.data(Qt::DisplayRole).toString(), Qt::ElideRight, max_name_width)); } // Draw image QIcon ico = index.data(Qt::DecorationRole).value(); QSize icon_size = ico.actualSize(img_rect.size()); img_rect = QRect(img_rect.x() + (img_rect.width() / 2 - icon_size.width() / 2), img_rect.y() + (img_rect.height() / 2 - icon_size.height() / 2), icon_size.width(), icon_size.height()); painter->drawPixmap(img_rect, ico.pixmap(icon_size)); if (option.state & QStyle::State_Selected) { QColor highlight_color = option.palette.highlight().color(); highlight_color.setAlphaF(0.5); painter->setCompositionMode(QPainter::CompositionMode_SourceAtop); painter->fillRect(img_rect, highlight_color); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorericonviewitemdelegate.h000066400000000000000000000026211370472574300314250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERICONVIEWITEMDELEGATE_H #define PROJECTEXPLORERICONVIEWITEMDELEGATE_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief The delegate that's used to draw items when ProjectExplorer is in Icon view */ class ProjectExplorerIconViewItemDelegate : public QStyledItemDelegate { public: ProjectExplorerIconViewItemDelegate(QObject *parent = nullptr); virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERICONVIEWITEMDELEGATE_H olive-continuous/app/widget/projectexplorer/projectexplorerlistview.cpp000066400000000000000000000017151370472574300274340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorerlistview.h" OLIVE_NAMESPACE_ENTER ProjectExplorerListView::ProjectExplorerListView(QWidget *parent) : ProjectExplorerListViewBase(parent) { setViewMode(QListView::ListMode); setItemDelegate(&delegate_); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorerlistview.h000066400000000000000000000023101370472574300270710ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERLISTVIEW_H #define PROJECTEXPLORERLISTVIEW_H #include "projectexplorerlistviewbase.h" #include "projectexplorerlistviewitemdelegate.h" OLIVE_NAMESPACE_ENTER /** * @brief The view widget used when ProjectExplorer is in List View */ class ProjectExplorerListView : public ProjectExplorerListViewBase { Q_OBJECT public: ProjectExplorerListView(QWidget* parent); private: ProjectExplorerListViewItemDelegate delegate_; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERLISTVIEW_H olive-continuous/app/widget/projectexplorer/projectexplorerlistviewbase.cpp000066400000000000000000000031271370472574300302660ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorerlistviewbase.h" #include OLIVE_NAMESPACE_ENTER ProjectExplorerListViewBase::ProjectExplorerListViewBase(QWidget *parent) : QListView(parent) { // FIXME Is this necessary? setMovement(QListView::Free); // Set selection mode (allows multiple item selection) setSelectionMode(QAbstractItemView::ExtendedSelection); // Set resize mode setResizeMode(QListView::Adjust); // Set widget to emit a signal on right click setContextMenuPolicy(Qt::CustomContextMenu); } void ProjectExplorerListViewBase::mouseDoubleClickEvent(QMouseEvent *event) { // Perform default double click functions QListView::mouseDoubleClickEvent(event); // QAbstractItemView already has a doubleClicked() signal, but we emit another here for double clicking empty space if (!indexAt(event->pos()).isValid()) { emit DoubleClickedEmptyArea(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorerlistviewbase.h000066400000000000000000000032531370472574300277330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERLISTVIEWBASE_H #define PROJECTEXPLORERLISTVIEWBASE_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief A QListView derivative that contains functionality used by both List view and Icon view (which are both based * on QListView) */ class ProjectExplorerListViewBase : public QListView { Q_OBJECT public: ProjectExplorerListViewBase(QWidget* parent); protected: /** * @brief Double click event override * * Function that signals DoubleClickedView(). * * FIXME: This code is the same as the code in ProjectExplorerTreeView. Is there a way to merge these two through * subclassing? */ virtual void mouseDoubleClickEvent(QMouseEvent *event) override; signals: /** * @brief Unconditional double click signal * * Emits a signal when the view is double clicked but not on any particular item */ void DoubleClickedEmptyArea(); }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERLISTVIEWBASE_H olive-continuous/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.cpp000066400000000000000000000054021370472574300320030ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorerlistviewitemdelegate.h" #include OLIVE_NAMESPACE_ENTER ProjectExplorerListViewItemDelegate::ProjectExplorerListViewItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QSize ProjectExplorerListViewItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { return QSize(option.decorationSize.height(), option.decorationSize.height()); } void ProjectExplorerListViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QFontMetrics fm = painter->fontMetrics(); QRect img_rect = option.rect; if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } img_rect.setWidth(qMin(img_rect.width(), img_rect.height())); QIcon ico = index.data(Qt::DecorationRole).value(); QSize icon_size = ico.actualSize(img_rect.size()); img_rect = QRect(img_rect.x() + (img_rect.width() / 2 - icon_size.width() / 2), img_rect.y() + (img_rect.height() / 2 - icon_size.height() / 2), icon_size.width(), icon_size.height()); painter->drawPixmap(img_rect, ico.pixmap(icon_size)); QRect text_rect = option.rect; text_rect.setLeft(text_rect.left() + option.rect.height()); int maximum_line_count = qMax(1, option.rect.height() / fm.height() - 1); QString text; if (maximum_line_count == 1) { text = index.data(Qt::DisplayRole).toString(); } else { text = index.data(Qt::ToolTipRole).toString(); if (text.isEmpty()) { text = index.data(Qt::DisplayRole).toString(); } else { QStringList strings = text.split("\n"); while (strings.size() > maximum_line_count) { strings.removeLast(); } text = strings.join("\n"); } } painter->setPen(option.state & QStyle::State_Selected ? option.palette.highlightedText().color() : option.palette.text().color()); painter->drawText(text_rect, static_cast(Qt::AlignLeft | Qt::AlignVCenter), text); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorerlistviewitemdelegate.h000066400000000000000000000026211370472574300314500ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERLISTVIEWITEMDELEGATE_H #define PROJECTEXPLORERLISTVIEWITEMDELEGATE_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief The delegate that's used to draw items when ProjectExplorer is in List view */ class ProjectExplorerListViewItemDelegate : public QStyledItemDelegate { public: ProjectExplorerListViewItemDelegate(QObject *parent = nullptr); virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERLISTVIEWITEMDELEGATE_H olive-continuous/app/widget/projectexplorer/projectexplorernavigation.cpp000066400000000000000000000052631370472574300277270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorernavigation.h" #include #include #include "common/define.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER ProjectExplorerNavigation::ProjectExplorerNavigation(QWidget *parent) : QWidget(parent) { // Create widget layout QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); // Create "directory up" button dir_up_btn_ = new QPushButton(this); dir_up_btn_->setEnabled(false); dir_up_btn_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); layout->addWidget(dir_up_btn_); connect(dir_up_btn_, SIGNAL(clicked(bool)), this, SIGNAL(DirectoryUpClicked())); // Create directory tree label dir_lbl_ = new QLabel(this); dir_lbl_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); layout->addWidget(dir_lbl_); // Create size slider size_slider_ = new QSlider(this); size_slider_->setOrientation(Qt::Horizontal); size_slider_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); layout->addWidget(size_slider_); connect(size_slider_, SIGNAL(valueChanged(int)), this, SIGNAL(SizeChanged(int))); Retranslate(); UpdateIcons(); } void ProjectExplorerNavigation::set_text(const QString &s) { dir_lbl_->setText(s); } void ProjectExplorerNavigation::set_dir_up_enabled(bool e) { dir_up_btn_->setEnabled(e); } void ProjectExplorerNavigation::set_size_value(int s) { size_slider_->setValue(s); } void ProjectExplorerNavigation::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); } else if (e->type() == QEvent::StyleChange) { UpdateIcons(); } QWidget::changeEvent(e); } void ProjectExplorerNavigation::Retranslate() { dir_up_btn_->setToolTip(tr("Go to parent folder")); } void ProjectExplorerNavigation::UpdateIcons() { dir_up_btn_->setIcon(icon::DirUp); size_slider_->setMinimum(kProjectIconSizeMinimum); size_slider_->setMaximum(kProjectIconSizeMaximum); size_slider_->setValue(kProjectIconSizeDefault); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorernavigation.h000066400000000000000000000061221370472574300273670ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERLISTVIEWTOOLBAR_H #define PROJECTEXPLORERLISTVIEWTOOLBAR_H #include #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief A navigation bar widget for ProjectExplorer's Icon and List views * * Unlike the Tree view, Icon and List don't follow a hierarchical view of information. This means there is no direct * way of navigating in and out of folders in those view types. We solve this in two ways: * * * Double clicking a Folder in those views will enter that folder * * This navigation bar offers a "directory up" button for leaving a folder * * This navbar also provides an icon size slider for those views (between kProjectIconSizeMinimum and * kProjectIconSizeMaximum) as well as text that's intended to be set to the current Folder's name (or * empty for the root folder). * * This widget does not actually communicate to Project or ProjectExplorer classes. It is simply UI widgets that are * intended to be connected in ways that do. This is the primarily responsibility of ProjectExplorer. * * By default, the directory up button is disabled (assuming root folder), the text is empty, and the icon size slider * is set to kProjectIconSizeDefault. */ class ProjectExplorerNavigation : public QWidget { Q_OBJECT public: ProjectExplorerNavigation(QWidget* parent); /** * @brief Sets the text string * * This text is intended to be set to the current Folder's name * * @param s */ void set_text(const QString& s); /** * @brief Set whether the "directory up" button is enabled or not * * @param e */ void set_dir_up_enabled(bool e); /** * @brief Set the current value of the size slider * * NOTE: Does NOT emit SizeChanged(). * * @param s * * New size value to set to */ void set_size_value(int s); signals: /** * @brief Signal emitted when the directory up button is clicked */ void DirectoryUpClicked(); /** * @brief Signal emitted when the icon size slider changes value * * @param size * * New size set in the slider */ void SizeChanged(int size); protected: virtual void changeEvent(QEvent *) override; private: void Retranslate(); void UpdateIcons(); QPushButton* dir_up_btn_; QLabel* dir_lbl_; QSlider* size_slider_; }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERLISTVIEWTOOLBAR_H olive-continuous/app/widget/projectexplorer/projectexplorertreeview.cpp000066400000000000000000000032101370472574300274100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projectexplorertreeview.h" #include OLIVE_NAMESPACE_ENTER ProjectExplorerTreeView::ProjectExplorerTreeView(QWidget *parent) : QTreeView(parent) { // Set selection mode (allows multiple item selection) setSelectionMode(QAbstractItemView::ExtendedSelection); // Allow dragging and dropping setDragDropMode(QAbstractItemView::DragDrop); // Enable dragging setDragEnabled(true); // Allow dropping from external sources setAcceptDrops(true); // Set context menu to emit a signal setContextMenuPolicy(Qt::CustomContextMenu); } void ProjectExplorerTreeView::mouseDoubleClickEvent(QMouseEvent *event) { // Perform default double click functions QTreeView::mouseDoubleClickEvent(event); // QAbstractItemView already has a doubleClicked() signal, but we emit another here for double clicking empty space if (!indexAt(event->pos()).isValid()) { emit DoubleClickedEmptyArea(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projectexplorer/projectexplorertreeview.h000066400000000000000000000034331370472574300270640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTEXPLORERTREEVIEW_H #define PROJECTEXPLORERTREEVIEW_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief The view widget used when ProjectExplorer is in Tree View * * A fairly simple subclass of QTreeView that provides a double clicked signal whether the index is valid or not * (QAbstractItemView has a doubleClicked() signal but it's only emitted with a valid index). */ class ProjectExplorerTreeView : public QTreeView { Q_OBJECT public: ProjectExplorerTreeView(QWidget* parent); protected: /** * @brief Double click event override * * Function that signals DoubleClickedView(). * * FIXME: This code is the same as the code in ProjectExplorerListViewBase. Is there a way to merge these two through * */ virtual void mouseDoubleClickEvent(QMouseEvent *event) override; signals: /** * @brief Unconditional double click signal * * Emits a signal when the view is double clicked but not on any particular item */ void DoubleClickedEmptyArea(); }; OLIVE_NAMESPACE_EXIT #endif // PROJECTEXPLORERTREEVIEW_H olive-continuous/app/widget/projecttoolbar/000077500000000000000000000000001370472574300215105ustar00rootroot00000000000000olive-continuous/app/widget/projecttoolbar/CMakeLists.txt000066400000000000000000000015111370472574300242460ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/projecttoolbar/projecttoolbar.h widget/projecttoolbar/projecttoolbar.cpp PARENT_SCOPE ) olive-continuous/app/widget/projecttoolbar/projecttoolbar.cpp000066400000000000000000000111721370472574300252470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "projecttoolbar.h" #include #include #include #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER ProjectToolbar::ProjectToolbar(QWidget *parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); new_button_ = new QPushButton(); connect(new_button_, SIGNAL(clicked(bool)), this, SIGNAL(NewClicked())); layout->addWidget(new_button_); open_button_ = new QPushButton(); connect(open_button_, SIGNAL(clicked(bool)), this, SIGNAL(OpenClicked())); layout->addWidget(open_button_); save_button_ = new QPushButton(); connect(save_button_, SIGNAL(clicked(bool)), this, SIGNAL(SaveClicked())); layout->addWidget(save_button_); undo_button_ = new QPushButton(); connect(undo_button_, SIGNAL(clicked(bool)), this, SIGNAL(UndoClicked())); layout->addWidget(undo_button_); redo_button_ = new QPushButton(); connect(redo_button_, SIGNAL(clicked(bool)), this, SIGNAL(RedoClicked())); layout->addWidget(redo_button_); search_field_ = new QLineEdit(); search_field_->setClearButtonEnabled(true); connect(search_field_, SIGNAL(textChanged(const QString &)), this, SIGNAL(SearchChanged(const QString&))); layout->addWidget(search_field_); tree_button_ = new QPushButton(); tree_button_->setCheckable(true); connect(tree_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); layout->addWidget(tree_button_); list_button_ = new QPushButton(); list_button_->setCheckable(true); connect(list_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); layout->addWidget(list_button_); icon_button_ = new QPushButton(); icon_button_->setCheckable(true); connect(icon_button_, SIGNAL(clicked(bool)), this, SLOT(ViewButtonClicked())); layout->addWidget(icon_button_); // Group Tree/List/Icon view buttons into a button group for easy exclusive-buttons QButtonGroup* view_button_group = new QButtonGroup(this); view_button_group->setExclusive(true); view_button_group->addButton(tree_button_); view_button_group->addButton(list_button_); view_button_group->addButton(icon_button_); Retranslate(); UpdateIcons(); } void ProjectToolbar::SetView(ViewType type) { switch (type) { case TreeView: tree_button_->setChecked(true); break; case IconView: icon_button_->setChecked(true); break; case ListView: list_button_->setChecked(true); break; } } void ProjectToolbar::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); } else if (e->type() == QEvent::StyleChange) { UpdateIcons(); } QWidget::changeEvent(e); } void ProjectToolbar::Retranslate() { new_button_->setToolTip(tr("New...")); open_button_->setToolTip(tr("Open Project")); save_button_->setToolTip(tr("Save Project")); undo_button_->setToolTip(tr("Undo")); redo_button_->setToolTip(tr("Redo")); search_field_->setPlaceholderText(tr("Search media, markers, etc.")); tree_button_->setToolTip(tr("Switch to Tree View")); list_button_->setToolTip(tr("Switch to List View")); icon_button_->setToolTip(tr("Switch to Icon View")); } void ProjectToolbar::UpdateIcons() { new_button_->setIcon(icon::New); open_button_->setIcon(icon::Open); save_button_->setIcon(icon::Save); undo_button_->setIcon(icon::Undo); redo_button_->setIcon(icon::Redo); tree_button_->setIcon(icon::TreeView); list_button_->setIcon(icon::ListView); icon_button_->setIcon(icon::IconView); } void ProjectToolbar::ViewButtonClicked() { // Determine which view button triggered this slot and emit a signal accordingly if (sender() == tree_button_) { emit ViewChanged(ProjectToolbar::TreeView); } else if (sender() == icon_button_) { emit ViewChanged(ProjectToolbar::IconView); } else if (sender() == list_button_) { emit ViewChanged(ProjectToolbar::ListView); } else { // Assert that it was one of the above buttons abort(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/projecttoolbar/projecttoolbar.h000066400000000000000000000040101370472574300247050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef PROJECTTOOLBAR_H #define PROJECTTOOLBAR_H #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief The ProjectToolbar class * * A toolbar consisting of project functions (new/open/save), edit functions (undo/redo), a search field, and a * project view selector (tree/icon/list). * * This object's signals can be connected to various functions in the application for better user experience. */ class ProjectToolbar : public QWidget { Q_OBJECT public: ProjectToolbar(QWidget* parent); enum ViewType { TreeView, ListView, IconView }; public slots: void SetView(ViewType type); protected: void changeEvent(QEvent *) override; signals: void NewClicked(); void OpenClicked(); void SaveClicked(); void UndoClicked(); void RedoClicked(); void SearchChanged(const QString&); void ViewChanged(ViewType type); private: void Retranslate(); void UpdateIcons(); QPushButton* new_button_; QPushButton* open_button_; QPushButton* save_button_; QPushButton* undo_button_; QPushButton* redo_button_; QLineEdit* search_field_; QPushButton* tree_button_; QPushButton* list_button_; QPushButton* icon_button_; private slots: void ViewButtonClicked(); }; OLIVE_NAMESPACE_EXIT #endif // PROJECTTOOLBAR_H olive-continuous/app/widget/resizablescrollbar/000077500000000000000000000000001370472574300223435ustar00rootroot00000000000000olive-continuous/app/widget/resizablescrollbar/CMakeLists.txt000066400000000000000000000015311370472574300251030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/resizablescrollbar/resizablescrollbar.h widget/resizablescrollbar/resizablescrollbar.cpp PARENT_SCOPE ) olive-continuous/app/widget/resizablescrollbar/resizablescrollbar.cpp000066400000000000000000000103661370472574300267410ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "resizablescrollbar.h" #include #include #include #include #include "common/range.h" OLIVE_NAMESPACE_ENTER const int ResizableScrollBar::kHandleWidth = 10; ResizableScrollBar::ResizableScrollBar(QWidget *parent) : QScrollBar(parent) { Init(); } ResizableScrollBar::ResizableScrollBar(Qt::Orientation orientation, QWidget *parent): QScrollBar(orientation, parent) { Init(); } void ResizableScrollBar::mousePressEvent(QMouseEvent *event) { if (mouse_handle_state_ == kNotInHandle) { QScrollBar::mousePressEvent(event); } else { mouse_dragging_ = true; mouse_drag_start_ = GetActiveMousePos(event); } } void ResizableScrollBar::mouseMoveEvent(QMouseEvent *event) { QStyleOptionSlider opt; initStyleOption(&opt); QRect sr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, this); if (mouse_dragging_) { int new_drag_pos = GetActiveMousePos(event); int mouse_movement = new_drag_pos - mouse_drag_start_; mouse_drag_start_ = new_drag_pos; if (mouse_handle_state_ == kInTopHandle) { mouse_movement = -mouse_movement; } double width_adjustment = static_cast(sr.width() + mouse_movement); // Prevent dividing by zero or emitting a negative scale if (width_adjustment > 0) { double scale_multiplier = static_cast(sr.width()) / width_adjustment; emit RequestScale(scale_multiplier); if (mouse_handle_state_ == kInTopHandle) { QRect gr = style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, this); int slider_min = gr.x(); int slider_max = gr.right() - (sr.width() + mouse_movement); int val = QStyle::sliderValueFromPosition(minimum(), maximum(), event->pos().x() - slider_min, slider_max - slider_min, opt.upsideDown); setValue(val); } else { setValue(qRound(static_cast(value()) * scale_multiplier)); } } } else { int mouse_pos, top, bottom; Qt::CursorShape target_cursor; mouse_pos = GetActiveMousePos(event); if (orientation() == Qt::Horizontal) { top = sr.left(); bottom = sr.right(); target_cursor = Qt::SizeHorCursor; } else { top = sr.top(); bottom = sr.bottom(); target_cursor = Qt::SizeVerCursor; } if (InRange(mouse_pos, top, kHandleWidth)) { mouse_handle_state_ = kInTopHandle; } else if (InRange(mouse_pos, bottom, kHandleWidth)) { mouse_handle_state_ = kInBottomHandle; } else { mouse_handle_state_ = kNotInHandle; } if (mouse_handle_state_ == kNotInHandle) { unsetCursor(); } else { setCursor(target_cursor); } QScrollBar::mouseMoveEvent(event); } } void ResizableScrollBar::mouseReleaseEvent(QMouseEvent *event) { if (mouse_dragging_) { mouse_dragging_ = false; } else { QScrollBar::mouseReleaseEvent(event); } } void ResizableScrollBar::Init() { setSingleStep(20); setMaximum(0); setMouseTracking(true); mouse_handle_state_= kNotInHandle; mouse_dragging_ = false; } int ResizableScrollBar::GetActiveMousePos(QMouseEvent *event) { if (orientation() == Qt::Horizontal) { return event->pos().x(); } else { return event->pos().y(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/resizablescrollbar/resizablescrollbar.h000066400000000000000000000031441370472574300264020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef RESIZABLESCROLLBAR_H #define RESIZABLESCROLLBAR_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ResizableScrollBar : public QScrollBar { Q_OBJECT public: ResizableScrollBar(QWidget* parent = nullptr); ResizableScrollBar(Qt::Orientation orientation, QWidget* parent = nullptr); signals: void RequestScale(const double& multiplier); protected: virtual void mousePressEvent(QMouseEvent* event) override; virtual void mouseMoveEvent(QMouseEvent* event) override; virtual void mouseReleaseEvent(QMouseEvent* event) override; private: static const int kHandleWidth; enum MouseHandleState { kNotInHandle, kInTopHandle, kInBottomHandle }; void Init(); int GetActiveMousePos(QMouseEvent* event); MouseHandleState mouse_handle_state_; bool mouse_dragging_; int mouse_drag_start_; }; OLIVE_NAMESPACE_EXIT #endif // RESIZABLESCROLLBAR_H olive-continuous/app/widget/scope/000077500000000000000000000000001370472574300175705ustar00rootroot00000000000000olive-continuous/app/widget/scope/CMakeLists.txt000066400000000000000000000015111370472574300223260ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(histogram) add_subdirectory(scopebase) add_subdirectory(waveform) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/widget/scope/histogram/000077500000000000000000000000001370472574300215655ustar00rootroot00000000000000olive-continuous/app/widget/scope/histogram/CMakeLists.txt000066400000000000000000000015011370472574300243220ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/scope/histogram/histogram.h widget/scope/histogram/histogram.cpp PARENT_SCOPE ) olive-continuous/app/widget/scope/histogram/histogram.cpp000066400000000000000000000016731370472574300242750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "histogram.h" #include #include #include "common/clamp.h" #include "common/functiontimer.h" OLIVE_NAMESPACE_ENTER HistogramScope::HistogramScope(QWidget* parent) : ScopeBase(parent) { } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/scope/histogram/histogram.h000066400000000000000000000021121370472574300237270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef HISTOGRAMSCOPE_H #define HISTOGRAMSCOPE_H #include "widget/scope/scopebase/scopebase.h" OLIVE_NAMESPACE_ENTER class HistogramScope : public ScopeBase { Q_OBJECT public: HistogramScope(QWidget* parent = nullptr); protected: //virtual OpenGLShaderPtr CreateShader() override; //virtual void DrawScope() override; }; OLIVE_NAMESPACE_EXIT #endif // HISTOGRAMSCOPE_H olive-continuous/app/widget/scope/scopebase/000077500000000000000000000000001370472574300215345ustar00rootroot00000000000000olive-continuous/app/widget/scope/scopebase/CMakeLists.txt000066400000000000000000000015011370472574300242710ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/scope/scopebase/scopebase.h widget/scope/scopebase/scopebase.cpp PARENT_SCOPE ) olive-continuous/app/widget/scope/scopebase/scopebase.cpp000066400000000000000000000062771370472574300242200ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "scopebase.h" #include "render/backend/opengl/openglrenderfunctions.h" OLIVE_NAMESPACE_ENTER ScopeBase::ScopeBase(QWidget* parent) : ManagedDisplayWidget(parent), buffer_(nullptr) { EnableDefaultContextMenu(); } ScopeBase::~ScopeBase() { CleanUp(); if (context()) { disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp); } } void ScopeBase::SetBuffer(Frame *frame) { buffer_ = frame; UploadTextureFromBuffer(); } void ScopeBase::showEvent(QShowEvent* e) { ManagedDisplayWidget::showEvent(e); UploadTextureFromBuffer(); } OpenGLShaderPtr ScopeBase::CreateShader() { return OpenGLShader::CreateDefault(); } void ScopeBase::DrawScope() { managed_tex().Bind(); OpenGLRenderFunctions::Blit(pipeline()); managed_tex().Release(); } OpenGLShaderPtr ScopeBase::pipeline() { return pipeline_; } OpenGLTexture &ScopeBase::managed_tex() { return managed_tex_; } void ScopeBase::UploadTextureFromBuffer() { if (!isVisible()) { return; } if (buffer_) { makeCurrent(); if (!texture_.IsCreated() || texture_.width() != buffer_->width() || texture_.height() != buffer_->height() || texture_.format() != buffer_->format()) { texture_.Destroy(); managed_tex_.Destroy(); texture_.Create(context(), buffer_); managed_tex_.Create(context(), buffer_->video_params()); } else { texture_.Upload(buffer_); } doneCurrent(); } update(); } void ScopeBase::CleanUp() { makeCurrent(); pipeline_ = nullptr; texture_.Destroy(); managed_tex_.Destroy(); framebuffer_.Destroy(); doneCurrent(); } void ScopeBase::initializeGL() { ManagedDisplayWidget::initializeGL(); pipeline_ = CreateShader(); framebuffer_.Create(context()); connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ScopeBase::CleanUp, Qt::DirectConnection); UploadTextureFromBuffer(); } void ScopeBase::paintGL() { QOpenGLFunctions* f = context()->functions(); f->glClearColor(0, 0, 0, 0); f->glClear(GL_COLOR_BUFFER_BIT); if (buffer_ && pipeline() && texture_.IsCreated()) { // Convert reference frame to display space framebuffer_.Attach(&managed_tex_); framebuffer_.Bind(); texture_.Bind(); f->glViewport(0, 0, texture_.width(), texture_.height()); color_service()->ProcessOpenGL(); texture_.Release(); framebuffer_.Release(); framebuffer_.Detach(); f->glViewport(0, 0, width(), height()); DrawScope(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/scope/scopebase/scopebase.h000066400000000000000000000033631370472574300236560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SCOPEBASE_H #define SCOPEBASE_H #include "codec/frame.h" #include "render/backend/opengl/openglcolorprocessor.h" #include "render/backend/opengl/openglframebuffer.h" #include "render/backend/opengl/openglshader.h" #include "render/backend/opengl/opengltexture.h" #include "widget/manageddisplay/manageddisplay.h" OLIVE_NAMESPACE_ENTER class ScopeBase : public ManagedDisplayWidget { public: ScopeBase(QWidget* parent = nullptr); virtual ~ScopeBase() override; public slots: void SetBuffer(Frame* frame); protected: virtual void initializeGL() override; virtual void paintGL() override; virtual void showEvent(QShowEvent* e) override; virtual OpenGLShaderPtr CreateShader(); virtual void DrawScope(); OpenGLShaderPtr pipeline(); OpenGLTexture& managed_tex(); private: void UploadTextureFromBuffer(); OpenGLShaderPtr pipeline_; OpenGLTexture texture_; OpenGLTexture managed_tex_; OpenGLFramebuffer framebuffer_; Frame* buffer_; private slots: void CleanUp(); }; OLIVE_NAMESPACE_EXIT #endif // SCOPEBASE_H olive-continuous/app/widget/scope/waveform/000077500000000000000000000000001370472574300214165ustar00rootroot00000000000000olive-continuous/app/widget/scope/waveform/CMakeLists.txt000066400000000000000000000014751370472574300241650ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/scope/waveform/waveform.h widget/scope/waveform/waveform.cpp PARENT_SCOPE ) olive-continuous/app/widget/scope/waveform/waveform.cpp000066400000000000000000000077741370472574300237670ustar00rootroot00000000000000 /*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "waveform.h" #include #include #include #include "common/qtutils.h" #include "node/node.h" #include "render/backend/opengl/openglrenderfunctions.h" OLIVE_NAMESPACE_ENTER WaveformScope::WaveformScope(QWidget* parent) : ScopeBase(parent) { } OpenGLShaderPtr WaveformScope::CreateShader() { OpenGLShaderPtr pipeline = OpenGLShader::Create(); pipeline->create(); pipeline->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex()); pipeline->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); pipeline->link(); return pipeline; } void WaveformScope::DrawScope() { float waveform_scale = 0.80f; float waveform_dim_x = width() * waveform_scale; float waveform_dim_y = height() * waveform_scale; float waveform_start_dim_x = (width() - waveform_dim_x) / 2.0f; float waveform_start_dim_y = (height() - waveform_dim_y) / 2.0f; float waveform_end_dim_x = width() - waveform_start_dim_x; float waveform_end_dim_y = height() - waveform_start_dim_y; // Draw waveform through shader pipeline()->bind(); pipeline()->setUniformValue("ove_resolution", managed_tex().width(), managed_tex().height()); pipeline()->setUniformValue("ove_viewport", width(), height()); GLfloat luma[3] = {0.0, 0.0, 0.0}; color_manager()->GetDefaultLumaCoefs(luma); pipeline()->setUniformValue("luma_coeffs", luma[0], luma[1], luma[2]); // Scale of the waveform relative to the viewport surface. pipeline()->setUniformValue("waveform_scale", waveform_scale); pipeline()->setUniformValue( "waveform_dims", waveform_dim_x, waveform_dim_y); pipeline()->setUniformValue( "waveform_region", waveform_start_dim_x, waveform_start_dim_y, waveform_end_dim_x, waveform_end_dim_y); float waveform_start_uv_x = waveform_start_dim_x / width(); float waveform_start_uv_y = waveform_start_dim_y / height(); float waveform_end_uv_x = waveform_end_dim_x / width(); float waveform_end_uv_y = waveform_end_dim_y / height(); pipeline()->setUniformValue( "waveform_uv", waveform_start_uv_x, waveform_start_uv_y, waveform_end_uv_x, waveform_end_uv_y); pipeline()->release(); managed_tex().Bind(); OpenGLRenderFunctions::Blit(pipeline()); managed_tex().Release(); // Draw line overlays QPainter p(this); QFontMetrics font_metrics = QFontMetrics(QFont()); QString label; float ire_increment = 0.1f; int ire_steps = qRound(1.0 / ire_increment); QVector ire_lines(ire_steps + 1); int font_x_offset = 0; int font_y_offset = font_metrics.capHeight() / 2.0f; p.setCompositionMode(QPainter::CompositionMode_Plus); p.setPen(QColor(0.0, 0.6 * 255.0, 0.0)); p.setFont(QFont()); for (int i=0; i <= ire_steps; i++) { ire_lines[i].setLine( waveform_start_dim_x, (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y, waveform_end_dim_x, (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y); label = QString::number(1.0 - (i * ire_increment), 'f', 1); font_x_offset = QFontMetricsWidth(font_metrics, label) + 4; p.drawText( waveform_start_dim_x - font_x_offset, (waveform_dim_y * (i * ire_increment)) + waveform_start_dim_y + font_y_offset, label); } p.drawLines(ire_lines); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/scope/waveform/waveform.h000066400000000000000000000021011370472574300234070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef WAVEFORMSCOPE_H #define WAVEFORMSCOPE_H #include "widget/scope/scopebase/scopebase.h" OLIVE_NAMESPACE_ENTER class WaveformScope : public ScopeBase { Q_OBJECT public: WaveformScope(QWidget* parent = nullptr); protected: virtual OpenGLShaderPtr CreateShader() override; virtual void DrawScope() override; }; OLIVE_NAMESPACE_EXIT #endif // WAVEFORMSCOPE_H olive-continuous/app/widget/slider/000077500000000000000000000000001370472574300177415ustar00rootroot00000000000000olive-continuous/app/widget/slider/CMakeLists.txt000066400000000000000000000022531370472574300225030ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/slider/floatslider.h widget/slider/floatslider.cpp widget/slider/integerslider.h widget/slider/integerslider.cpp widget/slider/sliderbase.h widget/slider/sliderbase.cpp widget/slider/sliderlabel.h widget/slider/sliderlabel.cpp widget/slider/sliderladder.h widget/slider/sliderladder.cpp widget/slider/stringslider.h widget/slider/stringslider.cpp widget/slider/timeslider.h widget/slider/timeslider.cpp PARENT_SCOPE ) olive-continuous/app/widget/slider/floatslider.cpp000066400000000000000000000100571370472574300227600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "floatslider.h" #include OLIVE_NAMESPACE_ENTER FloatSlider::FloatSlider(QWidget *parent) : SliderBase(kFloat, parent), display_type_(kNormal), decimal_places_(1), autotrim_decimal_places_(false) { connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant))); } double FloatSlider::GetValue() { return Value().toDouble(); } void FloatSlider::SetValue(const double &d) { SliderBase::SetValue(d); } void FloatSlider::SetMinimum(const double &d) { SetMinimumInternal(d); } void FloatSlider::SetMaximum(const double &d) { SetMaximumInternal(d); } void FloatSlider::SetDecimalPlaces(int i) { decimal_places_ = i; ForceLabelUpdate(); } void FloatSlider::SetDisplayType(const FloatSlider::DisplayType &type) { display_type_ = type; switch (display_type_) { case kNormal: ClearFormat(); break; case kDecibel: SetFormat(tr("%1 dB")); break; case kPercentage: SetFormat(tr("%1%")); break; } } void FloatSlider::SetAutoTrimDecimalPlaces(bool e) { autotrim_decimal_places_ = e; ForceLabelUpdate(); } QString FloatSlider::ValueToString(const QVariant &v) { double val = v.toDouble(); switch (display_type_) { case kNormal: // Do nothing, skip to the return string at the end break; case kDecibel: // Convert to decibels and return dB formatted string val = QAudio::convertVolume(val, QAudio::LinearVolumeScale, QAudio::DecibelVolumeScale); break; case kPercentage: // Multiply value by 100 for user-friendly percentage val *= 100.0; break; } QString s = QString::number(val, 'f', decimal_places_); if (autotrim_decimal_places_) { while (s.endsWith('0') && s.at(s.size() - 2).isDigit()) { s = s.left(s.size() - 1); } } return s; } QVariant FloatSlider::StringToValue(const QString &s, bool *ok) { switch (display_type_) { case kNormal: // Do nothing, skip to the return string at the end break; case kDecibel: { bool valid; // See if we can get a decimal number out of this qreal decibels = s.toDouble(&valid); if (ok) *ok = valid; if (valid) { // Convert from decibel scale to linear decimal return QAudio::convertVolume(decibels, QAudio::DecibelVolumeScale, QAudio::LinearVolumeScale); } break; } case kPercentage: { bool valid; // Try to get double value double val = s.toDouble(&valid); if (ok) *ok = valid; // If we could get it, convert back to a 0.0 - 1.0 value and return if (valid) { return val * 0.01; } break; } } // Just try to convert the string to a double return s.toDouble(ok); } double FloatSlider::AdjustDragDistanceInternal(const double &start, const double &drag) { switch (display_type_) { case kNormal: // No change here break; case kDecibel: { qreal current_db = QAudio::convertVolume(start, QAudio::LinearVolumeScale, QAudio::DecibelVolumeScale); current_db += drag; qreal adjusted_linear = QAudio::convertVolume(current_db, QAudio::DecibelVolumeScale, QAudio::LinearVolumeScale); return adjusted_linear; } case kPercentage: return SliderBase::AdjustDragDistanceInternal(start, drag * 0.01); } return SliderBase::AdjustDragDistanceInternal(start, drag); } void FloatSlider::ConvertValue(QVariant v) { emit ValueChanged(v.toDouble()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/floatslider.h000066400000000000000000000032541370472574300224260ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FLOATSLIDER_H #define FLOATSLIDER_H #include "sliderbase.h" OLIVE_NAMESPACE_ENTER class FloatSlider : public SliderBase { Q_OBJECT public: FloatSlider(QWidget* parent = nullptr); enum DisplayType { kNormal, kDecibel, kPercentage }; double GetValue(); void SetValue(const double& d); void SetMinimum(const double& d); void SetMaximum(const double& d); void SetDecimalPlaces(int i); void SetDisplayType(const DisplayType& type); void SetAutoTrimDecimalPlaces(bool e); protected: virtual QString ValueToString(const QVariant& v) override; virtual QVariant StringToValue(const QString& s, bool* ok) override; virtual double AdjustDragDistanceInternal(const double& start, const double& drag) override; signals: void ValueChanged(double); private slots: void ConvertValue(QVariant v); private: DisplayType display_type_; int decimal_places_; bool autotrim_decimal_places_; }; OLIVE_NAMESPACE_EXIT #endif // FLOATSLIDER_H olive-continuous/app/widget/slider/integerslider.cpp000066400000000000000000000033061370472574300233070ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "integerslider.h" OLIVE_NAMESPACE_ENTER IntegerSlider::IntegerSlider(QWidget* parent) : SliderBase(kInteger, parent) { connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant))); } int64_t IntegerSlider::GetValue() { return Value().toLongLong(); } void IntegerSlider::SetValue(const int64_t &v) { SliderBase::SetValue(QVariant::fromValue(v)); } void IntegerSlider::SetMinimum(const int64_t &d) { SetMinimumInternal(QVariant::fromValue(d)); } void IntegerSlider::SetMaximum(const int64_t &d) { SetMaximumInternal(QVariant::fromValue(d)); } QVariant IntegerSlider::StringToValue(const QString &s, bool *ok) { bool valid; // Allow both floats and integers for either modes double decimal_val = s.toDouble(&valid); if (ok) { *ok = valid; } if (valid) { // But for an integer, we round it return qRound(decimal_val); } return QVariant(); } void IntegerSlider::ConvertValue(QVariant v) { emit ValueChanged(v.toInt()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/integerslider.h000066400000000000000000000023711370472574300227550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef INTEGERSLIDER_H #define INTEGERSLIDER_H #include "sliderbase.h" OLIVE_NAMESPACE_ENTER class IntegerSlider : public SliderBase { Q_OBJECT public: IntegerSlider(QWidget* parent = nullptr); int64_t GetValue(); void SetValue(const int64_t& v); void SetMinimum(const int64_t& d); void SetMaximum(const int64_t& d); protected: virtual QVariant StringToValue(const QString& s, bool* ok) override; signals: void ValueChanged(int64_t); private slots: void ConvertValue(QVariant v); }; OLIVE_NAMESPACE_EXIT #endif // INTEGERSLIDER_H olive-continuous/app/widget/slider/sliderbase.cpp000066400000000000000000000205651370472574300225720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sliderbase.h" #include #include #include #include "common/qtutils.h" #include "core.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER SliderBase::SliderBase(Mode mode, QWidget *parent) : QStackedWidget(parent), drag_multiplier_(1.0), has_min_(false), has_max_(false), mode_(mode), dragged_diff_(0), require_valid_input_(true), tristate_(false), drag_ladder_(nullptr), ladder_element_count_(0), dragged_(false) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); label_ = new SliderLabel(this); addWidget(label_); editor_ = new FocusableLineEdit(this); addWidget(editor_); connect(label_, &SliderLabel::LabelPressed, this, &SliderBase::LabelPressed); connect(label_, &SliderLabel::focused, this, &SliderBase::ShowEditor); connect(label_, &SliderLabel::RequestReset, this, &SliderBase::ResetValue); connect(editor_, &FocusableLineEdit::Confirmed, this, &SliderBase::LineEditConfirmed); connect(editor_, &FocusableLineEdit::Cancelled, this, &SliderBase::LineEditCancelled); // Set valid cursor based on mode switch (mode_) { case kString: setCursor(Qt::PointingHandCursor); SetValue(""); break; case kInteger: case kFloat: setCursor(Qt::SizeHorCursor); SetValue(0); break; } } void SliderBase::SetDragMultiplier(const double &d) { drag_multiplier_ = d; } void SliderBase::SetRequireValidInput(bool e) { require_valid_input_ = e; } void SliderBase::SetAlignment(Qt::Alignment alignment) { label_->setAlignment(alignment); } bool SliderBase::IsTristate() const { return tristate_; } void SliderBase::SetTristate() { tristate_ = true; UpdateLabel(0); } bool SliderBase::IsDragging() const { return drag_ladder_; } void SliderBase::SetFormat(const QString &s) { custom_format_ = s; ForceLabelUpdate(); } void SliderBase::ClearFormat() { custom_format_.clear(); ForceLabelUpdate(); } void SliderBase::ForceLabelUpdate() { UpdateLabel(Value()); } const QVariant &SliderBase::Value() const { if (IsDragging()) { return temp_dragged_value_; } return value_; } void SliderBase::SetValue(const QVariant &v) { if (IsDragging()) { return; } value_ = ClampValue(v); // Disable tristate tristate_ = false; UpdateLabel(value_); } void SliderBase::SetDefaultValue(const QVariant &v) { default_value_ = v; } void SliderBase::SetMinimumInternal(const QVariant &v) { min_value_ = v; has_min_ = true; // Limit value by this new minimum value if (value_.toDouble() < min_value_.toDouble()) { SetValue(min_value_); } } void SliderBase::SetMaximumInternal(const QVariant &v) { max_value_ = v; has_max_ = true; // Limit value by this new maximum value if (value_.toDouble() > max_value_.toDouble()) { SetValue(max_value_); } } void SliderBase::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { UpdateLabel(value_); } QStackedWidget::changeEvent(e); } const QVariant &SliderBase::ClampValue(const QVariant &v) { if (has_min_ && v.toDouble() < min_value_.toDouble()) { return min_value_; } if (has_max_ && v.toDouble() > max_value_.toDouble()) { return max_value_; } return v; } QString SliderBase::GetFormat() const { if (custom_format_.isEmpty()) { return QStringLiteral("%1"); } else { return custom_format_; } } void SliderBase::RepositionLadder() { QPoint label_global_pos = label_->mapToGlobal(label_->pos()); int text_width = QFontMetricsWidth(label_->fontMetrics(), label_->text()); QPoint ladder_pos(label_global_pos.x(), label_global_pos.y() + label_->height() / 2 - drag_ladder_->height() / 2); if (ladder_element_count_ > 0) { ladder_pos.setX(ladder_pos.x() + text_width + QFontMetricsWidth(label_->fontMetrics(), QStringLiteral("H"))); } else { ladder_pos.setX(ladder_pos.x() + text_width / 2 - drag_ladder_->width() / 2); } drag_ladder_->move(ladder_pos); } void SliderBase::UpdateLabel(const QVariant &v) { if (tristate_) { label_->setText("---"); } else { label_->setText(GetFormat().arg(ValueToString(v))); } } double SliderBase::AdjustDragDistanceInternal(const double &start, const double &drag) { return start + drag; } QString SliderBase::ValueToString(const QVariant &v) { return v.toString(); } QVariant SliderBase::StringToValue(const QString &s, bool *ok) { *ok = true; return s; } void SliderBase::ShowEditor() { // This was a simple click // Load label's text into editor editor_->setText(ValueToString(value_)); // Show editor setCurrentWidget(editor_); // Select all text in the editor editor_->setFocus(); editor_->selectAll(); } void SliderBase::LabelPressed() { switch (mode_) { case kString: // No dragging supported for strings break; case kInteger: case kFloat: { drag_ladder_ = new SliderLadder(drag_multiplier_, ladder_element_count_); drag_ladder_->SetValue(ValueToString(value_)); drag_ladder_->show(); RepositionLadder(); connect(drag_ladder_, &SliderLadder::DraggedByValue, this, &SliderBase::LadderDragged); connect(drag_ladder_, &SliderLadder::Released, this, &SliderBase::LadderReleased); break; } } } void SliderBase::LadderDragged(int value, double multiplier) { dragged_ = true; switch (mode_) { case kString: // No dragging supported for strings break; case kInteger: case kFloat: { dragged_diff_ += value * drag_multiplier_ * multiplier; double drag_val = AdjustDragDistanceInternal(value_.toDouble(), dragged_diff_); // Update temporary value if (mode_ == kInteger) { temp_dragged_value_ = qRound(drag_val); } else { temp_dragged_value_ = drag_val; } QVariant clamped = ClampValue(temp_dragged_value_); if (clamped != temp_dragged_value_) { temp_dragged_value_ = clamped; dragged_diff_ = temp_dragged_value_.toDouble() - value_.toDouble(); } UpdateLabel(temp_dragged_value_); drag_ladder_->SetValue(ValueToString(temp_dragged_value_)); RepositionLadder(); emit ValueChanged(temp_dragged_value_); break; } } } void SliderBase::LadderReleased() { drag_ladder_->deleteLater(); drag_ladder_ = nullptr; dragged_diff_ = 0; if (dragged_) { // This was a drag switch (mode_) { case kString: // No-op break; case kInteger: SetValue(temp_dragged_value_.toInt()); break; case kFloat: SetValue(temp_dragged_value_.toDouble()); break; } emit ValueChanged(value_); dragged_ = false; } else { ShowEditor(); } } void SliderBase::LineEditConfirmed() { bool is_valid = true; QVariant test_val = StringToValue(editor_->text(), &is_valid); // Ensure editor doesn't signal that the focus is lost editor_->blockSignals(true); label_->blockSignals(true); if (is_valid) { SetValue(test_val); setCurrentWidget(label_); emit ValueChanged(value_); } else if (require_valid_input_ && !IsTristate()) { QMessageBox::critical(this, tr("Invalid Value"), tr("The entered value is not valid for this field."), QMessageBox::Ok); // Refocus editor editor_->setFocus(); } editor_->blockSignals(false); label_->blockSignals(false); } void SliderBase::LineEditCancelled() { // Ensure editor doesn't signal that the focus is lost editor_->blockSignals(true); label_->blockSignals(true); // Set widget back to label setCurrentWidget(label_); editor_->blockSignals(false); label_->blockSignals(false); } void SliderBase::ResetValue() { if (!default_value_.isNull()) { SetValue(default_value_); emit ValueChanged(value_); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/sliderbase.h000066400000000000000000000054231370472574300222330ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SLIDERBASE_H #define SLIDERBASE_H #include #include "sliderlabel.h" #include "sliderladder.h" #include "widget/focusablelineedit/focusablelineedit.h" OLIVE_NAMESPACE_ENTER class SliderBase : public QStackedWidget { Q_OBJECT public: enum Mode { kString, kInteger, kFloat }; SliderBase(Mode mode, QWidget* parent = nullptr); void SetDragMultiplier(const double& d); void SetRequireValidInput(bool e); void SetAlignment(Qt::Alignment alignment); void SetDefaultValue(const QVariant& v); bool IsTristate() const; void SetTristate(); bool IsDragging() const; void SetFormat(const QString& s); void ClearFormat(); void SetLadderElementCount(int b) { ladder_element_count_ = b; } signals: void ValueChanged(QVariant v); protected: const QVariant& Value() const; void SetValue(const QVariant& v); void SetMinimumInternal(const QVariant& v); void SetMaximumInternal(const QVariant& v); void UpdateLabel(const QVariant& v); virtual double AdjustDragDistanceInternal(const double& start, const double& drag); virtual QString ValueToString(const QVariant &v); virtual QVariant StringToValue(const QString& s, bool* ok); virtual void changeEvent(QEvent* e) override; void ForceLabelUpdate(); double drag_multiplier_; private: const QVariant& ClampValue(const QVariant& v); QString GetFormat() const; void RepositionLadder(); SliderLabel* label_; FocusableLineEdit* editor_; QVariant value_; QVariant default_value_; bool has_min_; QVariant min_value_; bool has_max_; QVariant max_value_; Mode mode_; double dragged_diff_; QVariant temp_dragged_value_; bool require_valid_input_; bool tristate_; QString custom_format_; SliderLadder* drag_ladder_; int ladder_element_count_; bool dragged_; private slots: void ShowEditor(); void LabelPressed(); void LadderDragged(int value, double multiplier); void LadderReleased(); void LineEditConfirmed(); void LineEditCancelled(); void ResetValue(); }; OLIVE_NAMESPACE_EXIT #endif // SLIDERBASE_H olive-continuous/app/widget/slider/sliderlabel.cpp000066400000000000000000000031511370472574300227270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sliderlabel.h" #include #include #include OLIVE_NAMESPACE_ENTER SliderLabel::SliderLabel(QWidget *parent) : QLabel(parent) { QPalette p = palette(); p.setColor(QPalette::Disabled, QPalette::Highlight, p.color(QPalette::Disabled, QPalette::ButtonText)); setPalette(p); // Use highlight color as font color setForegroundRole(QPalette::Link); // Set underlined QFont f = font(); f.setUnderline(true); setFont(f); // Allow users to tab to this widget setFocusPolicy(Qt::TabFocus); } void SliderLabel::mousePressEvent(QMouseEvent *e) { if (e->modifiers() & Qt::AltModifier) { emit RequestReset(); } else { emit LabelPressed(); } } void SliderLabel::focusInEvent(QFocusEvent *event) { QWidget::focusInEvent(event); if (event->reason() == Qt::TabFocusReason) { emit focused(); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/sliderlabel.h000066400000000000000000000022221370472574300223720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SLIDERLABEL_H #define SLIDERLABEL_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class SliderLabel : public QLabel { Q_OBJECT public: SliderLabel(QWidget* parent); protected: virtual void mousePressEvent(QMouseEvent *ev) override; virtual void focusInEvent(QFocusEvent *event) override; signals: void LabelPressed(); void focused(); void RequestReset(); }; OLIVE_NAMESPACE_EXIT #endif // SLIDERLABEL_H olive-continuous/app/widget/slider/sliderladder.cpp000066400000000000000000000126261370472574300231120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "sliderladder.h" #include #include #include #include #include #ifdef Q_OS_MAC #include #endif #include "common/clamp.h" #include "common/lerp.h" OLIVE_NAMESPACE_ENTER SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QWidget* parent) : QFrame(parent, Qt::Popup), y_mobility_(0) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); setFrameShape(QFrame::Box); setLineWidth(1); for (int i=nb_outer_values-1;i>=0;i--) { elements_.append(new SliderLadderElement(qPow(10, i + 1) * drag_multiplier)); } // Create center entry SliderLadderElement* start_element = new SliderLadderElement(drag_multiplier); active_element_ = elements_.size(); start_element->SetHighlighted(true); elements_.append(start_element); for (int i=0;iaddWidget(e); } if (elements_.size() == 1) { elements_.first()->SetMultiplierVisible(false); } drag_timer_.setInterval(10); connect(&drag_timer_, &QTimer::timeout, this, &SliderLadder::TimerUpdate); #if defined(Q_OS_MAC) CGAssociateMouseAndMouseCursorPosition(false); CGDisplayHideCursor(kCGDirectMainDisplay); CGGetLastMouseDelta(nullptr, nullptr); #else drag_start_ = QCursor::pos(); static_cast(QApplication::instance())->setOverrideCursor(Qt::BlankCursor); #endif } SliderLadder::~SliderLadder() { #if defined(Q_OS_MAC) CGAssociateMouseAndMouseCursorPosition(true); CGDisplayShowCursor(kCGDirectMainDisplay); #else static_cast(QApplication::instance())->restoreOverrideCursor(); #endif } void SliderLadder::SetValue(const QString &s) { foreach (SliderLadderElement* e, elements_) { e->SetValue(s); } } void SliderLadder::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event) drag_timer_.stop(); emit Released(); } void SliderLadder::showEvent(QShowEvent *event) { QWidget::showEvent(event); drag_timer_.start(); } void SliderLadder::TimerUpdate() { int32_t x_mvmt, y_mvmt; // Keep cursor in the same position #if defined(Q_OS_MAC) CGGetLastMouseDelta(&x_mvmt, &y_mvmt); #else QPoint current_pos = QCursor::pos(); x_mvmt = current_pos.x() - drag_start_.x(); y_mvmt = current_pos.y() - drag_start_.y(); QCursor::setPos(drag_start_); #endif if (!x_mvmt && !y_mvmt) { return; } if (qApp->keyboardModifiers() & Qt::ControlModifier) { // Movement is vertical y_mobility_ += y_mvmt; if (qAbs(y_mobility_) > fontMetrics().height()) { int new_active_element; if (y_mvmt < 0) { // Movement is UP new_active_element = active_element_ - 1; } else { // Movement is DOWN new_active_element = active_element_ + 1; } // Check if the proposed element is valid if (new_active_element >= 0 && new_active_element < elements_.size()) { elements_.at(active_element_)->SetHighlighted(false); active_element_ = new_active_element; elements_.at(active_element_)->SetHighlighted(true); } y_mobility_ = 0; } } else { y_mobility_ = 0; emit DraggedByValue(x_mvmt + y_mvmt, elements_.at(active_element_)->GetMultiplier()); } } SliderLadderElement::SliderLadderElement(const double &multiplier, QWidget *parent) : QWidget(parent), multiplier_(multiplier), highlighted_(false), multiplier_visible_(true) { QVBoxLayout* layout = new QVBoxLayout(this); label_ = new QLabel(); label_->setAlignment(Qt::AlignCenter); layout->addWidget(label_); QPalette p = palette(); QColor highlight_color = palette().text().color(); highlight_color.setAlpha(64); p.setColor(QPalette::Highlight, highlight_color); setPalette(p); setAutoFillBackground(true); UpdateLabel(); } void SliderLadderElement::SetHighlighted(bool e) { highlighted_ = e; if (highlighted_) { setBackgroundRole(QPalette::Highlight); } else { setBackgroundRole(QPalette::Window); } UpdateLabel(); } void SliderLadderElement::SetValue(const QString &value) { value_ = value; UpdateLabel(); } void SliderLadderElement::SetMultiplierVisible(bool e) { multiplier_visible_ = e; UpdateLabel(); } void SliderLadderElement::UpdateLabel() { if (multiplier_visible_) { QString val_text; if (highlighted_) { val_text = value_; } label_->setText(QStringLiteral("%1\n%2").arg(QString::number(multiplier_), val_text)); } else { label_->setText(value_); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/sliderladder.h000066400000000000000000000037051370472574300225550ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SLIDERLADDER_H #define SLIDERLADDER_H #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class SliderLadderElement : public QWidget { Q_OBJECT public: SliderLadderElement(const double& multiplier, QWidget* parent = nullptr); void SetHighlighted(bool e); void SetValue(const QString& value); void SetMultiplierVisible(bool e); double GetMultiplier() const { return multiplier_; } private: void UpdateLabel(); QLabel* label_; double multiplier_; QString value_; bool highlighted_; bool multiplier_visible_; }; class SliderLadder : public QFrame { Q_OBJECT public: SliderLadder(double drag_multiplier, int nb_outer_values, QWidget* parent = nullptr); virtual ~SliderLadder() override; void SetValue(const QString& s); protected: virtual void mouseReleaseEvent(QMouseEvent *event) override; virtual void showEvent(QShowEvent *event) override; signals: void DraggedByValue(int value, double multiplier); void Released(); private: QPoint drag_start_; QList elements_; int active_element_; QTimer drag_timer_; int y_mobility_; private slots: void TimerUpdate(); }; OLIVE_NAMESPACE_EXIT #endif // SLIDERLADDER_H olive-continuous/app/widget/slider/stringslider.cpp000066400000000000000000000024461370472574300231640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "stringslider.h" OLIVE_NAMESPACE_ENTER StringSlider::StringSlider(QWidget* parent) : SliderBase(kString, parent) { connect(this, SIGNAL(ValueChanged(QVariant)), this, SLOT(ConvertValue(QVariant))); } QString StringSlider::GetValue() { return Value().toString(); } void StringSlider::SetValue(const QString &v) { SliderBase::SetValue(v); } QString StringSlider::ValueToString(const QVariant &v) { QString vstr = v.toString(); return (vstr.isEmpty()) ? tr("(none)") : vstr; } void StringSlider::ConvertValue(QVariant v) { emit ValueChanged(v.toString()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/stringslider.h000066400000000000000000000023271370472574300226270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef STRINGSLIDER_H #define STRINGSLIDER_H #include "sliderbase.h" OLIVE_NAMESPACE_ENTER class StringSlider : public SliderBase { Q_OBJECT public: StringSlider(QWidget* parent = nullptr); void SetDragMultiplier(const double& d) = delete; QString GetValue(); void SetValue(const QString& v); protected: virtual QString ValueToString(const QVariant& value) override; signals: void ValueChanged(QString); private slots: void ConvertValue(QVariant v); }; OLIVE_NAMESPACE_EXIT #endif // STRINGSLIDER_H olive-continuous/app/widget/slider/timeslider.cpp000066400000000000000000000035361370472574300226150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timeslider.h" #include "common/timecodefunctions.h" #include "core.h" OLIVE_NAMESPACE_ENTER TimeSlider::TimeSlider(QWidget *parent) : IntegerSlider(parent) { SetMinimum(0); connect(Core::instance(), &Core::TimecodeDisplayChanged, this, &TimeSlider::TimecodeDisplayChanged); } void TimeSlider::SetTimebase(const rational &timebase) { timebase_ = timebase; // Refresh label since we have a new timebase to generate a timecode with UpdateLabel(Value()); } QString TimeSlider::ValueToString(const QVariant &v) { if (timebase_.isNull()) { // We can't generate a timecode without a timebase, so we just return the number return IntegerSlider::ValueToString(v); } return Timecode::timestamp_to_timecode(v.toLongLong(), timebase_, Core::instance()->GetTimecodeDisplay()); } QVariant TimeSlider::StringToValue(const QString &s, bool *ok) { return QVariant::fromValue(Timecode::timecode_to_timestamp(s, timebase_, Core::instance()->GetTimecodeDisplay(), ok)); } void TimeSlider::TimecodeDisplayChanged() { UpdateLabel(Value()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/slider/timeslider.h000066400000000000000000000023541370472574300222570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMESLIDER_H #define TIMESLIDER_H #include "common/rational.h" #include "integerslider.h" OLIVE_NAMESPACE_ENTER class TimeSlider : public IntegerSlider { Q_OBJECT public: TimeSlider(QWidget* parent = nullptr); void SetTimebase(const rational& timebase); protected: virtual QString ValueToString(const QVariant& v) override; virtual QVariant StringToValue(const QString& s, bool* ok) override; private: rational timebase_; private slots: void TimecodeDisplayChanged(); }; OLIVE_NAMESPACE_EXIT #endif // TIMESLIDER_H olive-continuous/app/widget/taskview/000077500000000000000000000000001370472574300203145ustar00rootroot00000000000000olive-continuous/app/widget/taskview/CMakeLists.txt000066400000000000000000000017111370472574300230540ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/taskview/elapsedcounterwidget.h widget/taskview/elapsedcounterwidget.cpp widget/taskview/taskview.h widget/taskview/taskview.cpp widget/taskview/taskviewitem.h widget/taskview/taskviewitem.cpp PARENT_SCOPE ) olive-continuous/app/widget/taskview/elapsedcounterwidget.cpp000066400000000000000000000044041370472574300252430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "elapsedcounterwidget.h" #include #include #include "common/timecodefunctions.h" OLIVE_NAMESPACE_ENTER ElapsedCounterWidget::ElapsedCounterWidget(QWidget* parent) : QWidget(parent), last_progress_(0), start_time_(0) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(layout->spacing() * 8); layout->setMargin(0); elapsed_lbl_ = new QLabel(); layout->addWidget(elapsed_lbl_); remaining_lbl_ = new QLabel(); layout->addWidget(remaining_lbl_); elapsed_timer_.setInterval(500); connect(&elapsed_timer_, &QTimer::timeout, this, &ElapsedCounterWidget::UpdateTimers); UpdateTimers(); } void ElapsedCounterWidget::SetProgress(double d) { last_progress_ = d; UpdateTimers(); } void ElapsedCounterWidget::Start() { Start(QDateTime::currentMSecsSinceEpoch()); } void ElapsedCounterWidget::Start(qint64 start_time) { start_time_ = start_time; elapsed_timer_.start(); UpdateTimers(); } void ElapsedCounterWidget::UpdateTimers() { int64_t elapsed_ms, remaining_ms; if (last_progress_ > 0) { elapsed_ms = QDateTime::currentMSecsSinceEpoch() - start_time_; double ms_per_progress_unit = elapsed_ms / last_progress_; double remaining_progress = 1.0 - last_progress_; remaining_ms = qRound64(ms_per_progress_unit * remaining_progress); } else { elapsed_ms = 0; remaining_ms = 0; } elapsed_lbl_->setText(tr("Elapsed: %1").arg(Timecode::TimeToString(elapsed_ms))); remaining_lbl_->setText(tr("Remaining: %1").arg(Timecode::TimeToString(remaining_ms))); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/taskview/elapsedcounterwidget.h000066400000000000000000000024421370472574300247100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef ELAPSEDCOUNTERWIDGET_H #define ELAPSEDCOUNTERWIDGET_H #include #include #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ElapsedCounterWidget : public QWidget { Q_OBJECT public: ElapsedCounterWidget(QWidget* parent = nullptr); void SetProgress(double d); void Start(); void Start(qint64 start_time); private: QLabel* elapsed_lbl_; QLabel* remaining_lbl_; double last_progress_; QTimer elapsed_timer_; qint64 start_time_; private slots: void UpdateTimers(); }; OLIVE_NAMESPACE_EXIT #endif // ELAPSEDCOUNTERWIDGET_H olive-continuous/app/widget/taskview/taskview.cpp000066400000000000000000000033411370472574300226560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "taskview.h" #include OLIVE_NAMESPACE_ENTER TaskView::TaskView(QWidget* parent) : QScrollArea(parent) { // Allow scroll area to resize widget to fit setWidgetResizable(true); // Create central widget central_widget_ = new QWidget(this); setWidget(central_widget_); // Create layout for central widget layout_ = new QVBoxLayout(central_widget_); layout_->setSpacing(0); layout_->setMargin(0); // Add a "stretch" so that TaskViewItems don't try to expand all the way to the bottom layout_->addStretch(); } void TaskView::AddTask(Task *t) { // Create TaskViewItem (UI representation of a Task) and connect it TaskViewItem* item = new TaskViewItem(t); connect(item, &TaskViewItem::TaskCancelled, this, &TaskView::TaskCancelled); items_.insert(t, item); layout_->insertWidget(layout_->count()-1, item); } void TaskView::TaskFailed(Task *t) { items_.value(t)->Failed(); } void TaskView::RemoveTask(Task *t) { items_.value(t)->deleteLater(); items_.remove(t); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/taskview/taskview.h000066400000000000000000000034321370472574300223240ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TASKVIEW_H #define TASKVIEW_H #include #include #include "widget/taskview/taskviewitem.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget that shows a list of Tasks * * TaskView is a fairly simple widget for showing TaskViewItem widgets that each represent a Task object. The main * entry point is the slot AddTask() which should be connected to a TaskManager's TaskAdded() signal. No more connecting * is necessary since TaskViewItem will automatically delete itself (thus removing itself from the TaskView) when the * Task finishes. */ class TaskView : public QScrollArea { Q_OBJECT public: TaskView(QWidget* parent); signals: void TaskCancelled(Task* t); public slots: /** * @brief Creates a TaskViewItem, connects it to a Task, and adds it to this widget * * Connect this to TaskManager::TaskAdded(). */ void AddTask(Task* t); void TaskFailed(Task* t); void RemoveTask(Task* t); private: QWidget* central_widget_; QVBoxLayout* layout_; QHash items_; }; OLIVE_NAMESPACE_EXIT #endif // TASKVIEW_H olive-continuous/app/widget/taskview/taskviewitem.cpp000066400000000000000000000054261370472574300235430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "taskviewitem.h" #include #include #include "common/timecodefunctions.h" #include "ui/icons/icons.h" OLIVE_NAMESPACE_ENTER TaskViewItem::TaskViewItem(Task* task, QWidget *parent) : QFrame(parent), task_(task) { // Draw border around this item setFrameShape(QFrame::StyledPanel); // Create layout QVBoxLayout* layout = new QVBoxLayout(this); // Create header label task_name_lbl_ = new QLabel(this); task_name_lbl_->setText(task_->GetTitle()); layout->addWidget(task_name_lbl_); // Create center layout (combines progress bar and a cancel button) QHBoxLayout* middle_layout = new QHBoxLayout(); layout->addLayout(middle_layout); // Create progress bar progress_bar_ = new QProgressBar(this); progress_bar_->setRange(0, 100); middle_layout->addWidget(progress_bar_); // Create cancel button cancel_btn_ = new QPushButton(this); cancel_btn_->setIcon(icon::Error); middle_layout->addWidget(cancel_btn_); // Create stack with error label and elapsed/remaining time status_stack_ = new QStackedWidget(); status_stack_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); layout->addWidget(status_stack_); // Create elapsed timer elapsed_timer_lbl_ = new ElapsedCounterWidget(); status_stack_->addWidget(elapsed_timer_lbl_); // Create error label task_error_lbl_ = new QLabel(this); status_stack_->addWidget(task_error_lbl_); // Set up elapsed timer status_stack_->setCurrentWidget(elapsed_timer_lbl_); elapsed_timer_lbl_->Start(task_->GetStartTime()); // Connect to the task connect(task_, &Task::ProgressChanged, this, &TaskViewItem::UpdateProgress); connect(cancel_btn_, &QPushButton::clicked, this, [this] { emit TaskCancelled(task_); }); } void TaskViewItem::Failed() { status_stack_->setCurrentWidget(task_error_lbl_); task_error_lbl_->setStyleSheet("color: red"); task_error_lbl_->setText(tr("Error: %1").arg(task_->GetError())); } void TaskViewItem::UpdateProgress(double d) { progress_bar_->setValue(qRound(100.0 * d)); elapsed_timer_lbl_->SetProgress(d); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/taskview/taskviewitem.h000066400000000000000000000035641370472574300232110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TASKVIEWITEM_H #define TASKVIEWITEM_H #include #include #include #include #include #include "elapsedcounterwidget.h" #include "task/task.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget that visually represents the status of a Task * * The TaskViewItem widget shows a description of the Task (Task::text(), a progress bar (updated by * Task::ProgressChanged), the Task's status (text generated from Task::status() or Task::error()), and provides * a cancel button (triggering Task::Cancel()) for cancelling a Task before it finishes. * * The main entry point is SetTask() after a Task and TaskViewItem objects are created. */ class TaskViewItem : public QFrame { Q_OBJECT public: TaskViewItem(Task *task, QWidget* parent = nullptr); void Failed(); signals: void TaskCancelled(Task* t); private: QLabel* task_name_lbl_; QProgressBar* progress_bar_; QPushButton* cancel_btn_; QStackedWidget* status_stack_; ElapsedCounterWidget* elapsed_timer_lbl_; QLabel* task_error_lbl_; Task* task_; private slots: void UpdateProgress(double d); }; OLIVE_NAMESPACE_EXIT #endif // TASKVIEWITEM_H olive-continuous/app/widget/timebased/000077500000000000000000000000001370472574300204145ustar00rootroot00000000000000olive-continuous/app/widget/timebased/CMakeLists.txt000066400000000000000000000014651370472574300231620ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timebased/timebased.h widget/timebased/timebased.cpp PARENT_SCOPE ) olive-continuous/app/widget/timebased/timebased.cpp000066400000000000000000000302371370472574300230620ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timebased.h" #include #include #include "common/timecodefunctions.h" #include "config/config.h" #include "core.h" #include "project/item/sequence/sequence.h" #include "widget/timelinewidget/undo/undo.h" OLIVE_NAMESPACE_ENTER TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_status_visible, QWidget *parent) : TimelineScaledWidget(parent), viewer_node_(nullptr), auto_max_scrollbar_(false), points_(nullptr), toggle_show_all_(false), auto_set_timebase_(true) { ruler_ = new TimeRuler(ruler_text_visible, ruler_cache_status_visible, this); connect(ruler_, &TimeRuler::TimeChanged, this, &TimeBasedWidget::SetTimeAndSignal); scrollbar_ = new ResizableScrollBar(Qt::Horizontal, this); connect(scrollbar_, &ResizableScrollBar::RequestScale, this, &TimeBasedWidget::ScrollBarResized); } void TimeBasedWidget::SetScaleAndCenterOnPlayhead(const double &scale) { SetScale(scale); // Zoom towards the playhead // (using a hacky singleShot so the scroll occurs after the scene and its scrollbars have updated) QTimer::singleShot(0, this, &TimeBasedWidget::CenterScrollOnPlayhead); } rational TimeBasedWidget::GetTime() const { return Timecode::timestamp_to_time(ruler()->GetTime(), timebase()); } const int64_t &TimeBasedWidget::GetTimestamp() const { return ruler_->GetTime(); } ViewerOutput *TimeBasedWidget::GetConnectedNode() const { return viewer_node_; } void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node) { if (viewer_node_ == node) { return; } if (viewer_node_) { DisconnectNodeInternal(viewer_node_); disconnect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll); disconnect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &TimeBasedWidget::SetTimebase); if (auto_set_timebase_) { SetTimebase(rational()); } points_ = nullptr; ruler()->ConnectTimelinePoints(nullptr); } viewer_node_ = node; ConnectedNodeChanged(viewer_node_); if (viewer_node_) { connect(viewer_node_, &ViewerOutput::LengthChanged, this, &TimeBasedWidget::UpdateMaximumScroll); if ((points_ = ConnectTimelinePoints())) { ruler()->ConnectTimelinePoints(points_); } if (auto_set_timebase_) { if (!viewer_node_->video_params().time_base().isNull()) { SetTimebase(viewer_node_->video_params().time_base()); } else if (viewer_node_->audio_params().sample_rate() > 0) { SetTimebase(viewer_node_->audio_params().time_base()); } else { SetTimebase(rational()); } connect(viewer_node_, &ViewerOutput::TimebaseChanged, this, &TimeBasedWidget::SetTimebase); } ConnectNodeInternal(viewer_node_); } UpdateMaximumScroll(); } void TimeBasedWidget::UpdateMaximumScroll() { rational length = (viewer_node_) ? viewer_node_->GetLength() : rational(); if (auto_max_scrollbar_) { scrollbar_->setMaximum(qMax(0, qCeil(TimeToScene(length)) - width())); } foreach (TimelineViewBase* base, timeline_views_) { base->SetEndTime(length); } } void TimeBasedWidget::ScrollBarResized(const double &multiplier) { QScrollBar* bar = static_cast(sender()); // Our extension area (represented by a TimelineViewEndItem) is NOT scaled, but the ResizableScrollBar doesn't know // this. Here we re-calculate the requested scale knowing that the end item is not affected by scale. int current_max = bar->maximum(); double proposed_max = static_cast(current_max) * multiplier; proposed_max = proposed_max - (bar->width() * 0.5 / multiplier) + (bar->width() * 0.5); double corrected_scale; if (current_max == 0) { corrected_scale = multiplier; } else { corrected_scale = (proposed_max / static_cast(current_max)); } SetScale(GetScale() * corrected_scale); } TimeRuler *TimeBasedWidget::ruler() const { return ruler_; } ResizableScrollBar *TimeBasedWidget::scrollbar() const { return scrollbar_; } void TimeBasedWidget::TimebaseChangedEvent(const rational &timebase) { TimelineScaledWidget::TimebaseChangedEvent(timebase); ruler_->SetTimebase(timebase); emit TimebaseChanged(timebase); } void TimeBasedWidget::ScaleChangedEvent(const double &scale) { TimelineScaledWidget::ScaleChangedEvent(scale); ruler_->SetScale(scale); UpdateMaximumScroll(); toggle_show_all_ = false; } void TimeBasedWidget::SetAutoMaxScrollBar(bool e) { auto_max_scrollbar_ = e; } void TimeBasedWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); // Update horizontal scrollbar's page step to the width of the panel scrollbar()->setPageStep(scrollbar()->width()); UpdateMaximumScroll(); } TimelinePoints *TimeBasedWidget::ConnectTimelinePoints() { return static_cast(viewer_node_->parent()); } Project *TimeBasedWidget::GetTimelinePointsProject() { return static_cast(viewer_node_->parent())->project(); } TimelinePoints *TimeBasedWidget::GetConnectedTimelinePoints() const { return points_; } void TimeBasedWidget::ConnectTimelineView(TimelineViewBase *base) { timeline_views_.append(base); } void TimeBasedWidget::SetTimestamp(int64_t timestamp) { ruler_->SetTime(timestamp); TimeChangedEvent(timestamp); } void TimeBasedWidget::SetTimebase(const rational &timebase) { TimelineScaledWidget::SetTimebase(timebase); } void TimeBasedWidget::SetScale(const double &scale) { // Simple QObject slot wrapper around TimelineScaledWidget::SetScale() TimelineScaledWidget::SetScale(scale); } void TimeBasedWidget::ZoomIn() { SetScaleAndCenterOnPlayhead(GetScale() * 2); } void TimeBasedWidget::ZoomOut() { SetScaleAndCenterOnPlayhead(GetScale() * 0.5); } void TimeBasedWidget::GoToPrevCut() { if (!GetConnectedNode()) { return; } if (GetTimestamp() == 0) { return; } int64_t closest_cut = 0; foreach (TrackOutput* track, viewer_node_->GetTracks()) { int64_t this_track_closest_cut = 0; foreach (Block* block, track->Blocks()) { int64_t block_out_ts = Timecode::time_to_timestamp(block->out(), timebase()); if (block_out_ts < GetTimestamp()) { this_track_closest_cut = block_out_ts; } else { break; } } closest_cut = qMax(closest_cut, this_track_closest_cut); } SetTimeAndSignal(closest_cut); } void TimeBasedWidget::GoToNextCut() { if (!GetConnectedNode()) { return; } int64_t closest_cut = INT64_MAX; foreach (TrackOutput* track, GetConnectedNode()->GetTracks()) { int64_t this_track_closest_cut = Timecode::time_to_timestamp(track->track_length(), timebase()); if (this_track_closest_cut <= GetTimestamp()) { this_track_closest_cut = INT64_MAX; } foreach (Block* block, track->Blocks()) { int64_t block_in_ts = Timecode::time_to_timestamp(block->in(), timebase()); if (block_in_ts > GetTimestamp()) { this_track_closest_cut = block_in_ts; break; } } closest_cut = qMin(closest_cut, this_track_closest_cut); } if (closest_cut < INT64_MAX) { SetTimeAndSignal(closest_cut); } } void TimeBasedWidget::GoToStart() { if (viewer_node_) { SetTimeAndSignal(0); } } void TimeBasedWidget::PrevFrame() { if (viewer_node_) { SetTimeAndSignal(qMax(static_cast(0), ruler()->GetTime() - 1)); } } void TimeBasedWidget::NextFrame() { if (viewer_node_) { SetTimeAndSignal(ruler()->GetTime() + 1); } } void TimeBasedWidget::GoToEnd() { if (viewer_node_) { SetTimeAndSignal(Timecode::time_to_timestamp(viewer_node_->GetLength(), timebase())); } } void TimeBasedWidget::SetTimeAndSignal(const int64_t &t) { SetTimestamp(t); emit TimeChanged(t); } void TimeBasedWidget::CenterScrollOnPlayhead() { scrollbar_->setValue(qRound(TimeToScene(Timecode::timestamp_to_time(ruler_->GetTime(), timebase()))) - scrollbar_->width()/2); } void TimeBasedWidget::SetAutoSetTimebase(bool e) { auto_set_timebase_ = e; } void TimeBasedWidget::SetPoint(Timeline::MovementMode m, const rational& time) { if (!points_) { return; } QUndoCommand* command = new QUndoCommand(); // Enable workarea if it isn't already enabled if (!points_->workarea()->enabled()) { new WorkareaSetEnabledCommand(GetTimelinePointsProject(), points_, true, command); } // Determine our new range rational in_point, out_point; if (m == Timeline::kTrimIn) { in_point = time; if (!points_->workarea()->enabled() || points_->workarea()->out() < in_point) { out_point = TimelineWorkArea::kResetOut; } else { out_point = points_->workarea()->out(); } } else { out_point = time; if (!points_->workarea()->enabled() || points_->workarea()->in() > out_point) { in_point = TimelineWorkArea::kResetIn; } else { in_point = points_->workarea()->in(); } } // Set workarea new WorkareaSetRangeCommand(GetTimelinePointsProject(), points_, TimeRange(in_point, out_point), command); Core::instance()->undo_stack()->push(command); } void TimeBasedWidget::ResetPoint(Timeline::MovementMode m) { if (!points_ || !points_->workarea()->enabled()) { return; } TimeRange r = points_->workarea()->range(); if (m == Timeline::kTrimIn) { r.set_in(TimelineWorkArea::kResetIn); } else { r.set_out(TimelineWorkArea::kResetOut); } Core::instance()->undo_stack()->push(new WorkareaSetRangeCommand(GetTimelinePointsProject(), points_, r)); } void TimeBasedWidget::SetInAtPlayhead() { SetPoint(Timeline::kTrimIn, GetTime()); } void TimeBasedWidget::SetOutAtPlayhead() { SetPoint(Timeline::kTrimOut, GetTime()); } void TimeBasedWidget::ResetIn() { ResetPoint(Timeline::kTrimIn); } void TimeBasedWidget::ResetOut() { ResetPoint(Timeline::kTrimOut); } void TimeBasedWidget::ClearInOutPoints() { if (!points_) { return; } Core::instance()->undo_stack()->push(new WorkareaSetEnabledCommand(GetTimelinePointsProject(), points_, false)); } void TimeBasedWidget::SetMarker() { if (!points_) { return; } bool ok; QString marker_name; if (Config::Current()["SetNameWithMarker"].toBool()) { marker_name = QInputDialog::getText(this, tr("Set Marker"), tr("Marker name:"), QLineEdit::Normal, QString(), &ok); } else { ok = true; } if (ok) { points_->markers()->AddMarker(TimeRange(GetTime(), GetTime()), marker_name); } } void TimeBasedWidget::ToggleShowAll() { if (!GetConnectedNode()) { return; } if (toggle_show_all_) { SetScale(toggle_show_all_old_scale_); scrollbar_->setValue(toggle_show_all_old_scroll_); // Don't have to set toggle_show_all_ because SetScale() will automatically set it to false } else { int w; if (timeline_views_.isEmpty()) { w = width(); } else { w = timeline_views_.first()->width(); } toggle_show_all_old_scale_ = GetScale(); toggle_show_all_old_scroll_ = scrollbar_->value(); SetScaleFromDimensions(w, GetConnectedNode()->GetLength().toDouble()); scrollbar_->setValue(0); // Must explicitly do this because SetScale() will automatically set this to false toggle_show_all_ = true; } } void TimeBasedWidget::GoToIn() { if (viewer_node_) { if (points_ && points_->workarea()->enabled()) { SetTimeAndSignal(Timecode::time_to_timestamp(points_->workarea()->in(), timebase())); } else { GoToStart(); } } } void TimeBasedWidget::GoToOut() { if (viewer_node_) { if (points_ && points_->workarea()->enabled()) { SetTimeAndSignal(Timecode::time_to_timestamp(points_->workarea()->out(), timebase())); } else { GoToEnd(); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timebased/timebased.h000066400000000000000000000102431370472574300225220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMEBASEDWIDGET_H #define TIMEBASEDWIDGET_H #include #include "node/output/viewer/viewer.h" #include "timeline/timelinecommon.h" #include "widget/resizablescrollbar/resizablescrollbar.h" #include "widget/timelinewidget/timelinescaledobject.h" #include "widget/timelinewidget/view/timelineview.h" #include "widget/timeruler/timeruler.h" OLIVE_NAMESPACE_ENTER class TimeBasedWidget : public TimelineScaledWidget { Q_OBJECT public: TimeBasedWidget(bool ruler_text_visible = true, bool ruler_cache_status_visible = false, QWidget* parent = nullptr); rational GetTime() const; const int64_t& GetTimestamp() const; void ZoomIn(); void ZoomOut(); ViewerOutput* GetConnectedNode() const; void ConnectViewerNode(ViewerOutput *node); void SetScaleAndCenterOnPlayhead(const double& scale); TimeRuler* ruler() const; public slots: void SetTimestamp(int64_t timestamp); void SetTimebase(const rational& timebase); void SetScale(const double& scale); void GoToStart(); void PrevFrame(); void NextFrame(); void GoToEnd(); void GoToPrevCut(); void GoToNextCut(); void SetInAtPlayhead(); void SetOutAtPlayhead(); void ResetIn(); void ResetOut(); void ClearInOutPoints(); void SetMarker(); void ToggleShowAll(); void GoToIn(); void GoToOut(); protected slots: void SetTimeAndSignal(const int64_t& t); protected: ResizableScrollBar* scrollbar() const; virtual void TimebaseChangedEvent(const rational&) override; virtual void TimeChangedEvent(const int64_t&){} virtual void ScaleChangedEvent(const double &) override; virtual void ConnectedNodeChanged(ViewerOutput*){} virtual void ConnectNodeInternal(ViewerOutput*){} virtual void DisconnectNodeInternal(ViewerOutput*){} void SetAutoMaxScrollBar(bool e); virtual void resizeEvent(QResizeEvent *event) override; virtual TimelinePoints* ConnectTimelinePoints(); virtual Project* GetTimelinePointsProject(); TimelinePoints* GetConnectedTimelinePoints() const; void ConnectTimelineView(TimelineViewBase* base); protected slots: /** * @brief Slot to center the horizontal scroll bar on the playhead's current position */ void CenterScrollOnPlayhead(); /** * @brief By default, TimeBasedWidget will set the timebase to the viewer node's video timebase. * Set this to false if you want to set your own timebase. */ void SetAutoSetTimebase(bool e); signals: void TimeChanged(const int64_t&); void TimebaseChanged(const rational&); private: /** * @brief Set either in or out point to the current playhead * * @param m * * Set to kTrimIn or kTrimOut for setting the in point or out point respectively. */ void SetPoint(Timeline::MovementMode m, const rational &time); /** * @brief Reset either the in or out point * * Sets either the in point to 0 or the out point to `RATIONAL_MAX`. * * @param m * * Set to kTrimIn or kTrimOut for setting the in point or out point respectively. */ void ResetPoint(Timeline::MovementMode m); ViewerOutput* viewer_node_; TimeRuler* ruler_; ResizableScrollBar* scrollbar_; bool auto_max_scrollbar_; TimelinePoints* points_; QList timeline_views_; bool toggle_show_all_; double toggle_show_all_old_scale_; int toggle_show_all_old_scroll_; bool auto_set_timebase_; private slots: void UpdateMaximumScroll(); void ScrollBarResized(const double& multiplier); }; OLIVE_NAMESPACE_EXIT #endif // TIMEBASEDWIDGET_H olive-continuous/app/widget/timelinewidget/000077500000000000000000000000001370472574300214715ustar00rootroot00000000000000olive-continuous/app/widget/timelinewidget/CMakeLists.txt000066400000000000000000000022711370472574300242330ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(trackview) add_subdirectory(tool) add_subdirectory(undo) add_subdirectory(view) set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timelinewidget/snapservice.h widget/timelinewidget/snapservice.cpp widget/timelinewidget/timelineandtrackview.h widget/timelinewidget/timelineandtrackview.cpp widget/timelinewidget/timelinescaledobject.h widget/timelinewidget/timelinescaledobject.cpp widget/timelinewidget/timelinewidget.h widget/timelinewidget/timelinewidget.cpp PARENT_SCOPE ) olive-continuous/app/widget/timelinewidget/snapservice.cpp000066400000000000000000000000311370472574300245110ustar00rootroot00000000000000#include "snapservice.h" olive-continuous/app/widget/timelinewidget/snapservice.h000066400000000000000000000010771370472574300241710ustar00rootroot00000000000000#ifndef SNAPSERVICE_H #define SNAPSERVICE_H #include "common/rational.h" OLIVE_NAMESPACE_ENTER class SnapService { public: SnapService() = default; enum SnapPoints { kSnapToClips = 0x1, kSnapToPlayhead = 0x2, kSnapToMarkers = 0x4, kSnapAll = 0xFF }; /** * @brief Snaps point `start_point` that is moving by `movement` to currently existing clips */ virtual bool SnapPoint(QList start_times, rational *movement, int snap_points = kSnapAll) = 0; virtual void HideSnaps() = 0; }; OLIVE_NAMESPACE_EXIT #endif // SNAPSERVICE_H olive-continuous/app/widget/timelinewidget/timelineandtrackview.cpp000066400000000000000000000041161370472574300264100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineandtrackview.h" #include #include OLIVE_NAMESPACE_ENTER TimelineAndTrackView::TimelineAndTrackView(Qt::Alignment vertical_alignment, QWidget *parent) : QWidget(parent) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); splitter_ = new QSplitter(Qt::Horizontal); splitter_->setChildrenCollapsible(false); layout->addWidget(splitter_); track_view_ = new TrackView(vertical_alignment); splitter_->addWidget(track_view_); view_ = new TimelineView(vertical_alignment); splitter_->addWidget(view_); connect(view_->verticalScrollBar(), &QScrollBar::valueChanged, this, &TimelineAndTrackView::ViewValueChanged); connect(track_view_->verticalScrollBar(), &QScrollBar::valueChanged, this, &TimelineAndTrackView::TracksValueChanged); splitter_->setSizes({1, width()}); } QSplitter *TimelineAndTrackView::splitter() const { return splitter_; } TimelineView *TimelineAndTrackView::view() const { return view_; } TrackView *TimelineAndTrackView::track_view() const { return track_view_; } void TimelineAndTrackView::ViewValueChanged(int v) { track_view_->verticalScrollBar()->setValue(v - view_->verticalScrollBar()->minimum()); } void TimelineAndTrackView::TracksValueChanged(int v) { view_->verticalScrollBar()->setValue(view_->verticalScrollBar()->minimum() + v); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/timelineandtrackview.h000066400000000000000000000025761370472574300260650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEANDTRACKVIEW_H #define TIMELINEANDTRACKVIEW_H #include #include #include "view/timelineview.h" #include "trackview/trackview.h" OLIVE_NAMESPACE_ENTER class TimelineAndTrackView : public QWidget { public: TimelineAndTrackView(Qt::Alignment vertical_alignment = Qt::AlignTop, QWidget* parent = nullptr); QSplitter* splitter() const; TimelineView* view() const; TrackView* track_view() const; private: QSplitter* splitter_; TimelineView* view_; TrackView* track_view_; private slots: void ViewValueChanged(int v); void TracksValueChanged(int v); }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEANDTRACKVIEW_H olive-continuous/app/widget/timelinewidget/timelinescaledobject.cpp000066400000000000000000000063251370472574300263540ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelinescaledobject.h" #include #include #include "common/clamp.h" OLIVE_NAMESPACE_ENTER const int TimelineScaledObject::kCalculateDimensionsPadding = 10; TimelineScaledObject::TimelineScaledObject() : scale_(1.0), min_scale_(0), max_scale_(DBL_MAX) { } void TimelineScaledObject::SetTimebase(const rational &timebase) { timebase_ = timebase; timebase_dbl_ = timebase_.toDouble(); TimebaseChangedEvent(timebase); } const rational &TimelineScaledObject::timebase() const { return timebase_; } const double &TimelineScaledObject::timebase_dbl() const { return timebase_dbl_; } rational TimelineScaledObject::SceneToTime(const double &x, const double &x_scale, const rational &timebase, bool round) { double unscaled_time = x / x_scale / timebase.toDouble(); // Adjust screen point by scale and timebase qint64 rounded_x_mvmt; if (round) { rounded_x_mvmt = qRound64(unscaled_time); } else { rounded_x_mvmt = qFloor(unscaled_time); } // Return a time in the timebase return rational(rounded_x_mvmt * timebase.numerator(), timebase.denominator()); } double TimelineScaledObject::TimeToScene(const rational &time) { return time.toDouble() * scale_; } rational TimelineScaledObject::SceneToTime(const double &x, bool round) { return SceneToTime(x, scale_, timebase_, round); } void TimelineScaledObject::SetMaximumScale(const double &max) { max_scale_ = max; if (GetScale() > max_scale_) { SetScale(max_scale_); } } void TimelineScaledObject::SetMinimumScale(const double &min) { min_scale_ = min; if (GetScale() < min_scale_) { SetScale(min_scale_); } } const double& TimelineScaledObject::GetScale() const { return scale_; } void TimelineScaledObject::SetScale(const double& scale) { Q_ASSERT(scale > 0); scale_ = clamp(scale, min_scale_, max_scale_); ScaleChangedEvent(scale_); } void TimelineScaledObject::SetScaleFromDimensions(double viewport_width, double content_width) { SetScale(CalculateScaleFromDimensions(viewport_width, content_width)); } double TimelineScaledObject::CalculateScaleFromDimensions(double viewport_sz, double content_sz) { return static_cast(viewport_sz / kCalculateDimensionsPadding * (kCalculateDimensionsPadding-1)) / static_cast(content_sz); } double TimelineScaledObject::CalculatePaddingFromDimensionScale(double viewport_sz) { return (viewport_sz / (kCalculateDimensionsPadding * 2)); } TimelineScaledWidget::TimelineScaledWidget(QWidget *parent) : QWidget(parent) { } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/timelinescaledobject.h000066400000000000000000000042211370472574300260120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINESCALEDOBJECT_H #define TIMELINESCALEDOBJECT_H #include #include "common/rational.h" OLIVE_NAMESPACE_ENTER class TimelineScaledObject { public: TimelineScaledObject(); virtual ~TimelineScaledObject() = default; void SetTimebase(const rational &timebase); const rational& timebase() const; const double& timebase_dbl() const; static rational SceneToTime(const double &x, const double& x_scale, const rational& timebase, bool round = false); const double& GetScale() const; void SetScale(const double& scale); void SetScaleFromDimensions(double viewport_width, double content_width); static double CalculateScaleFromDimensions(double viewport_sz, double content_sz); static double CalculatePaddingFromDimensionScale(double viewport_sz); protected: double TimeToScene(const rational& time); rational SceneToTime(const double &x, bool round = false); virtual void TimebaseChangedEvent(const rational&){} virtual void ScaleChangedEvent(const double&){} void SetMaximumScale(const double& max); void SetMinimumScale(const double& min); private: rational timebase_; double timebase_dbl_; double scale_; double min_scale_; double max_scale_; static const int kCalculateDimensionsPadding; }; class TimelineScaledWidget : public QWidget, public TimelineScaledObject { Q_OBJECT public: TimelineScaledWidget(QWidget* parent = nullptr); }; OLIVE_NAMESPACE_EXIT #endif // TIMELINESCALEDOBJECT_H olive-continuous/app/widget/timelinewidget/timelinewidget.cpp000066400000000000000000001350251370472574300252150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelinewidget.h" #include #include #include #include #include "core.h" #include "common/range.h" #include "common/timecodefunctions.h" #include "dialog/sequence/sequence.h" #include "dialog/speedduration/speedduration.h" #include "node/block/transition/transition.h" #include "tool/tool.h" #include "trackview/trackview.h" #include "widget/menu/menu.h" #include "widget/menu/menushared.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::TimelineWidget(QWidget *parent) : TimeBasedWidget(true, true, parent), rubberband_(QRubberBand::Rectangle, this), active_tool_(nullptr), use_audio_time_units_(false) { QVBoxLayout* vert_layout = new QVBoxLayout(this); vert_layout->setSpacing(0); vert_layout->setMargin(0); QHBoxLayout* ruler_and_time_layout = new QHBoxLayout(); vert_layout->addLayout(ruler_and_time_layout); timecode_label_ = new TimeSlider(); timecode_label_->SetAlignment(Qt::AlignCenter); timecode_label_->setVisible(false); connect(timecode_label_, &TimeSlider::ValueChanged, this, &TimelineWidget::SetTimeAndSignal); ruler_and_time_layout->addWidget(timecode_label_); ruler_and_time_layout->addWidget(ruler()); ruler()->SetSnapService(this); // Create list of TimelineViews - these MUST correspond to the ViewType enum view_splitter_ = new QSplitter(Qt::Vertical); view_splitter_->setChildrenCollapsible(false); vert_layout->addWidget(view_splitter_); // Video view views_.append(new TimelineAndTrackView(Qt::AlignBottom)); // Audio view views_.append(new TimelineAndTrackView(Qt::AlignTop)); // Create tools tools_.resize(OLIVE_NAMESPACE::Tool::kCount); tools_.fill(nullptr); tools_.replace(OLIVE_NAMESPACE::Tool::kPointer, new PointerTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kEdit, new EditTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kRipple, new RippleTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kRolling, new RollingTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kRazor, new RazorTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kSlip, new SlipTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kSlide, new SlideTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kZoom, new ZoomTool(this)); tools_.replace(OLIVE_NAMESPACE::Tool::kTransition, new TransitionTool(this)); //tools_.replace(OLIVE_NAMESPACE::Tool::kRecord, new PointerTool(this)); FIXME: Implement tools_.replace(OLIVE_NAMESPACE::Tool::kAdd, new AddTool(this)); import_tool_ = new ImportTool(this); // We add this to the list to make deleting all tools easier, it should never get accessed through the list under // normal circumstances (but *technically* its index would be Tool::kCount) tools_.append(import_tool_); // Global scrollbar connect(scrollbar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); connect(views_.first()->view()->horizontalScrollBar(), &QScrollBar::rangeChanged, scrollbar(), &QScrollBar::setRange); vert_layout->addWidget(scrollbar()); connect(ruler(), &TimeRuler::TimeChanged, this, &TimelineWidget::SetViewTimestamp); foreach (TimelineAndTrackView* tview, views_) { TimelineView* view = tview->view(); view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); view->SetSnapService(this); view_splitter_->addWidget(tview); ConnectTimelineView(view); connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); connect(view, &TimelineView::ScaleChanged, this, &TimelineWidget::SetScale); connect(view, &TimelineView::TimeChanged, this, &TimelineWidget::ViewTimestampChanged); connect(view, &TimelineView::customContextMenuRequested, this, &TimelineWidget::ShowContextMenu); connect(scrollbar(), &QScrollBar::valueChanged, view->horizontalScrollBar(), &QScrollBar::setValue); connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, scrollbar(), &QScrollBar::setValue); connect(view, &TimelineView::RequestCenterScrollOnPlayhead, this, &TimelineWidget::CenterScrollOnPlayhead); connect(view, &TimelineView::MousePressed, this, &TimelineWidget::ViewMousePressed); connect(view, &TimelineView::MouseMoved, this, &TimelineWidget::ViewMouseMoved); connect(view, &TimelineView::MouseReleased, this, &TimelineWidget::ViewMouseReleased); connect(view, &TimelineView::MouseDoubleClicked, this, &TimelineWidget::ViewMouseDoubleClicked); connect(view, &TimelineView::DragEntered, this, &TimelineWidget::ViewDragEntered); connect(view, &TimelineView::DragMoved, this, &TimelineWidget::ViewDragMoved); connect(view, &TimelineView::DragLeft, this, &TimelineWidget::ViewDragLeft); connect(view, &TimelineView::DragDropped, this, &TimelineWidget::ViewDragDropped); ConnectViewSelectionSignal(view); connect(tview->splitter(), &QSplitter::splitterMoved, this, &TimelineWidget::UpdateHorizontalSplitters); // Connect each view's scroll to each other foreach (TimelineAndTrackView* other_tview, views_) { TimelineView* other_view = other_tview->view(); if (view != other_view) { connect(view->horizontalScrollBar(), &QScrollBar::valueChanged, other_view->horizontalScrollBar(), &QScrollBar::setValue); } } } // Split viewer 50/50 view_splitter_->setSizes({INT_MAX, INT_MAX}); // FIXME: Magic number SetScale(90.0); SetMaximumScale(TimelineViewBase::kMaximumScale); SetAutoSetTimebase(false); } TimelineWidget::~TimelineWidget() { // Ensure no blocks are selected before any child widgets are destroyed (prevents corrupt ViewSelectionChanged() signal) Clear(); qDeleteAll(tools_); } void TimelineWidget::Clear() { foreach (TimelineAndTrackView* tview, views_) { DisconnectViewSelectionSignal(tview->view()); } QMap::const_iterator iterator; for (iterator=block_items_.begin(); iterator!=block_items_.end(); iterator++) { delete iterator.value(); } block_items_.clear(); foreach (TimelineAndTrackView* tview, views_) { ConnectViewSelectionSignal(tview->view()); } emit SelectionChanged(QList()); SetTimebase(0); } void TimelineWidget::TimebaseChangedEvent(const rational &timebase) { TimeBasedWidget::TimebaseChangedEvent(timebase); timecode_label_->SetTimebase(timebase); timecode_label_->setVisible(!timebase.isNull()); QMap::const_iterator iterator; for (iterator=block_items_.begin();iterator!=block_items_.end();iterator++) { if (iterator.value()) { iterator.value()->SetTimebase(timebase); } } UpdateViewTimebases(); } void TimelineWidget::resizeEvent(QResizeEvent *event) { TimeBasedWidget::resizeEvent(event); // Update timecode label size UpdateTimecodeWidthFromSplitters(views_.first()->splitter()); } void TimelineWidget::TimeChangedEvent(const int64_t& timestamp) { SetViewTimestamp(timestamp); timecode_label_->SetValue(timestamp); } void TimelineWidget::ScaleChangedEvent(const double &scale) { TimeBasedWidget::ScaleChangedEvent(scale); QMap::const_iterator iterator; for (iterator=block_items_.begin();iterator!=block_items_.end();iterator++) { if (iterator.value()) { iterator.value()->SetScale(scale); } } foreach (TimelineViewGhostItem* ghost, ghost_items_) { ghost->SetScale(scale); } foreach (TimelineAndTrackView* view, views_) { view->view()->SetScale(scale); } } void TimelineWidget::ConnectNodeInternal(ViewerOutput *n) { connect(n, &ViewerOutput::BlockAdded, this, &TimelineWidget::AddBlock); connect(n, &ViewerOutput::BlockRemoved, this, &TimelineWidget::RemoveBlock); connect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); connect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); connect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); connect(n, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); ruler()->SetPlaybackCache(n->video_frame_cache()); SetTimebase(n->video_params().time_base()); for (int i=0;i(i); TimelineView* view = views_.at(i)->view(); TrackList* track_list = n->track_list(track_type); TrackView* track_view = views_.at(i)->track_view(); track_view->ConnectTrackList(track_list); view->ConnectTrackList(track_list); // Defer to the track to make all the block UI items necessary foreach (TrackOutput* track, n->track_list(track_type)->GetTracks()) { AddTrack(track, track_type); } } } void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n) { disconnect(n, &ViewerOutput::BlockAdded, this, &TimelineWidget::AddBlock); disconnect(n, &ViewerOutput::BlockRemoved, this, &TimelineWidget::RemoveBlock); disconnect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack); disconnect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack); disconnect(n, &ViewerOutput::TimebaseChanged, this, &TimelineWidget::SetTimebase); disconnect(n, &ViewerOutput::TrackHeightChanged, this, &TimelineWidget::TrackHeightChanged); ruler()->SetPlaybackCache(nullptr); SetTimebase(0); Clear(); foreach (TimelineAndTrackView* tview, views_) { tview->track_view()->DisconnectTrackList(); tview->view()->ConnectTrackList(nullptr); } } void TimelineWidget::CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata) { writer->writeStartElement(QStringLiteral("timeline")); // Cache the earliest in point so all copied clips have a "relative" in point that can be pasted anywhere QList& selected = *static_cast*>(userdata); rational earliest_in = RATIONAL_MAX; foreach (TimelineViewBlockItem* item, selected) { Block* block = item->block(); earliest_in = qMin(earliest_in, block->in()); } foreach (TimelineViewBlockItem* item, selected) { Block* block = item->block(); writer->writeStartElement(QStringLiteral("block")); writer->writeAttribute(QStringLiteral("ptr"), QString::number(reinterpret_cast(block))); writer->writeAttribute(QStringLiteral("in"), (block->in() - earliest_in).toString()); TrackOutput* track = TrackOutput::TrackFromBlock(block); if (track) { writer->writeAttribute(QStringLiteral("tracktype"), QString::number(track->track_type())); writer->writeAttribute(QStringLiteral("trackindex"), QString::number(track->Index())); } writer->writeEndElement(); } writer->writeEndElement(); // timeline } void TimelineWidget::PasteNodesFromClipboardInternal(QXmlStreamReader *reader, void *userdata) { if (reader->name() == QStringLiteral("timeline")) { QList& paste_data = *static_cast*>(userdata); while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("block")) { BlockPasteData bpd; foreach (QXmlStreamAttribute attr, reader->attributes()) { if (attr.name() == QStringLiteral("ptr")) { bpd.ptr = attr.value().toULongLong(); } else if (attr.name() == QStringLiteral("in")) { bpd.in = rational::fromString(attr.value().toString()); } else if (attr.name() == QStringLiteral("tracktype")) { bpd.track_type = static_cast(attr.value().toInt()); } else if (attr.name() == QStringLiteral("trackindex")) { bpd.track_index = attr.value().toInt(); } } paste_data.append(bpd); reader->skipCurrentElement(); } } } else { NodeCopyPasteWidget::PasteNodesFromClipboardInternal(reader, userdata); } } TimelineWidget::DraggedFootage TimelineWidget::FootageToDraggedFootage(Footage *f) { return DraggedFootage(f, f->get_enabled_stream_flags()); } QList TimelineWidget::FootageToDraggedFootage(QList footage) { QList df; foreach (Footage* f, footage) { df.append(FootageToDraggedFootage(f)); } return df; } rational TimelineWidget::GetToolTipTimebase() const { if (GetConnectedNode() && use_audio_time_units_) { return GetConnectedNode()->audio_params().time_base(); } return timebase(); } void TimelineWidget::SelectAll() { foreach (TimelineAndTrackView* view, views_) { DisconnectViewSelectionSignal(view->view()); view->view()->SelectAll(); ConnectViewSelectionSignal(view->view()); } ViewSelectionChanged(); } void TimelineWidget::DeselectAll() { foreach (TimelineAndTrackView* view, views_) { DisconnectViewSelectionSignal(view->view()); view->view()->DeselectAll(); ConnectViewSelectionSignal(view->view()); } emit SelectionChanged(QList()); } void TimelineWidget::RippleToIn() { RippleTo(Timeline::kTrimIn); } void TimelineWidget::RippleToOut() { RippleTo(Timeline::kTrimOut); } void TimelineWidget::EditToIn() { EditTo(Timeline::kTrimIn); } void TimelineWidget::EditToOut() { EditTo(Timeline::kTrimOut); } void TimelineWidget::SplitAtPlayhead() { if (!GetConnectedNode()) { return; } rational playhead_time = Timecode::timestamp_to_time(GetTimestamp(), timebase()); QList selected_blocks = GetSelectedBlocks(); // Prioritize blocks that are selected and overlap the playhead QVector blocks_to_split; QVector block_is_selected; bool some_blocks_are_selected = false; // Get all blocks at the playhead foreach (TrackOutput* track, GetConnectedNode()->GetTracks()) { Block* b = track->BlockContainingTime(playhead_time); if (b && b->type() == Block::kClip) { bool selected = false; // See if this block is selected foreach (TimelineViewBlockItem* item, selected_blocks) { if (item->block() == b) { some_blocks_are_selected = true; selected = true; break; } } blocks_to_split.append(b); block_is_selected.append(selected); } } // If some blocks are selected, we prioritize those and don't split the blocks that aren't if (some_blocks_are_selected) { for (int i=0;iundo_stack()->push(new BlockSplitPreservingLinksCommand(blocks_to_split, {playhead_time})); } } void TimelineWidget::DeleteSelectedInternal(const QList &blocks, bool transition_aware, bool remove_from_graph, QUndoCommand *command) { foreach (Block* b, blocks) { TrackOutput* original_track = TrackOutput::TrackFromBlock(b); /*if (transition_aware && b->type() == Block::kTransition) { // Deleting transitions restores their in/out offsets to their attached blocks TransitionBlock* transition = static_cast(b); // Ripple remove transition new TrackRippleRemoveBlockCommand(original_track, transition, command); // Resize attached blocks to make up length if (transition->connected_in_block()) { new BlockResizeWithMediaInCommand(transition->connected_in_block(), transition->connected_in_block()->length() + transition->in_offset(), command); } if (transition->connected_out_block()) { new BlockResizeCommand(transition->connected_out_block(), transition->connected_out_block()->length() + transition->out_offset(), command); } } else */ /* if (b->next()) { new TrackRippleRemoveBlockCommand(original_track, b, command); if (b->previous() && b->previous()->type() == Block::kGap && b->next() && b->next()->type() == Block::kGap) { // Both previous AND next are blocks. We'll want to merge them together. new TrackRippleRemoveBlockCommand(original_track, b->next(), command); } else { // Make new gap and replace old Block with it for now GapBlock* gap = new GapBlock(); gap->set_length_and_media_out(b->length()); new NodeAddCommand(static_cast(b->parent()), gap, command); new TrackReplaceBlockCommand(original_track, b, gap, command); } } */ new TrackReplaceBlockWithGapCommand(original_track, b, command); if (remove_from_graph) { new BlockUnlinkAllCommand(b, command); new NodeRemoveWithExclusiveDeps(static_cast(b->parent()), b, command); } } } void TimelineWidget::DeleteSelected(bool ripple) { QList selected_list = GetSelectedBlocks(); QList blocks_to_delete; QList tracks_affected; foreach (TimelineViewBlockItem* item, selected_list) { Block* b = item->block(); blocks_to_delete.append(b); if (!tracks_affected.contains(item->Track())) { tracks_affected.append(item->Track()); } } // No-op if nothing is selected if (blocks_to_delete.isEmpty()) { return; } QUndoCommand* command = new QUndoCommand(); // Replace blocks with gaps (effectively deleting them) DeleteSelectedInternal(blocks_to_delete, true, true, command); /* // Clean each track foreach (const TrackReference& track, tracks_affected) { new TrackCleanGapsCommand(GetConnectedNode()->track_list(track.type()), track.index(), command); } */ // Insert ripple command now that it's all cleaned up gaps if (ripple) { TimeRangeList range_list; foreach (Block* b, blocks_to_delete) { range_list.InsertTimeRange(TimeRange(b->in(), b->out())); } new TimelineRippleDeleteGapsAtRegionsCommand(GetConnectedNode(), range_list, command); } Core::instance()->undo_stack()->pushIfHasChildren(command); } void TimelineWidget::IncreaseTrackHeight() { if (!GetConnectedNode()) { return; } QVector all_tracks = GetConnectedNode()->GetTracks(); // Increase the height of each track by one "unit" foreach (TrackOutput* t, all_tracks) { t->SetTrackHeight(t->GetTrackHeight() + t->GetTrackHeightIncrement()); } } void TimelineWidget::DecreaseTrackHeight() { if (!GetConnectedNode()) { return; } QVector all_tracks = GetConnectedNode()->GetTracks(); // Decrease the height of each track by one "unit" foreach (TrackOutput* t, all_tracks) { t->SetTrackHeight(qMax(t->GetTrackHeight() - t->GetTrackHeightIncrement(), t->GetTrackHeightMinimum())); } } void TimelineWidget::InsertFootageAtPlayhead(const QList& footage) { import_tool_->PlaceAt(footage, GetTime(), true); } void TimelineWidget::OverwriteFootageAtPlayhead(const QList &footage) { import_tool_->PlaceAt(footage, GetTime(), false); } void TimelineWidget::ToggleLinksOnSelected() { QList sel = GetSelectedBlocks(); // Prioritize unlinking QList blocks; bool link = true; foreach (TimelineViewBlockItem* item, sel) { if (link && item->block()->HasLinks()) { link = false; } blocks.append(item->block()); } if (link) { Core::instance()->undo_stack()->push(new BlockLinkManyCommand(blocks, true)); } else { Core::instance()->undo_stack()->push(new BlockLinkManyCommand(blocks, false)); } } void TimelineWidget::CopySelected(bool cut) { if (!GetConnectedNode()) { return; } QList selected = GetSelectedBlocks(); if (selected.isEmpty()) { return; } QList selected_nodes; foreach (TimelineViewBlockItem* item, selected) { Node* block = item->block(); selected_nodes.append(block); QList deps = block->GetDependencies(); foreach (Node* d, deps) { if (!selected_nodes.contains(d)) { selected_nodes.append(d); } } } CopyNodesToClipboard(selected_nodes, &selected); if (cut) { DeleteSelected(); } } void TimelineWidget::Paste(bool insert) { if (!GetConnectedNode()) { return; } QUndoCommand* command = new QUndoCommand(); QList paste_data; QList pasted = PasteNodesFromClipboard(static_cast(GetConnectedNode()->parent()), command, &paste_data); rational paste_start = GetTime(); if (insert) { rational paste_end = GetTime(); foreach (const BlockPasteData& bpd, paste_data) { foreach (Node* n, pasted) { if (n->property("xml_ptr") == bpd.ptr) { paste_end = qMax(paste_end, paste_start + bpd.in + static_cast(n)->length()); break; } } } if (paste_end != paste_start) { InsertGapsAt(paste_start, paste_end - paste_start, command); } } foreach (const BlockPasteData& bpd, paste_data) { foreach (Node* n, pasted) { if (n->property("xml_ptr") == bpd.ptr) { qDebug() << "Placing" << n; new TrackPlaceBlockCommand(GetConnectedNode()->track_list(bpd.track_type), bpd.track_index, static_cast(n), paste_start + bpd.in, command); break; } } } Core::instance()->undo_stack()->pushIfHasChildren(command); } void TimelineWidget::DeleteInToOut(bool ripple) { if (!GetConnectedNode() || !GetConnectedTimelinePoints() || !GetConnectedTimelinePoints()->workarea()->enabled()) { return; } QUndoCommand* command = new QUndoCommand(); if (ripple) { new TimelineRippleRemoveAreaCommand(GetConnectedNode(), GetConnectedTimelinePoints()->workarea()->in(), GetConnectedTimelinePoints()->workarea()->out(), command); } else { QVector unlocked_tracks = GetConnectedNode()->GetUnlockedTracks(); foreach (TrackOutput* track, unlocked_tracks) { GapBlock* gap = new GapBlock(); gap->set_length_and_media_out(GetConnectedTimelinePoints()->workarea()->length()); new NodeAddCommand(static_cast(track->parent()), gap, command); new TrackPlaceBlockCommand(GetConnectedNode()->track_list(track->track_type()), track->Index(), gap, GetConnectedTimelinePoints()->workarea()->in(), command); } } // Clear workarea after this new WorkareaSetEnabledCommand(GetTimelinePointsProject(), GetConnectedTimelinePoints(), false, command); if (ripple) { SetTimeAndSignal(Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->in(), timebase())); } Core::instance()->undo_stack()->push(command); } void TimelineWidget::ToggleSelectedEnabled() { QList items = GetSelectedBlocks(); if (items.isEmpty()) { return; } QUndoCommand* command = new QUndoCommand(); foreach (TimelineViewBlockItem* i, items) { new BlockEnableDisableCommand(i->block(), !i->block()->is_enabled(), command); } Core::instance()->undo_stack()->pushIfHasChildren(command); } QList TimelineWidget::GetSelectedBlocks() { QList list; QMapIterator iterator(block_items_); while (iterator.hasNext()) { iterator.next(); TimelineViewBlockItem* item = iterator.value(); if (item && item->isSelected()) { list.append(item); } } return list; } void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, QUndoCommand *command) { for (int i=0;itrack_list(static_cast(i)), earliest_point, insert_length, command); } } TrackOutput *TimelineWidget::GetTrackFromReference(const TrackReference &ref) { return GetConnectedNode()->track_list(ref.type())->GetTrackAt(ref.index()); } void TimelineWidget::ConnectViewSelectionSignal(TimelineView *view) { connect(view, &TimelineView::SelectionChanged, this, &TimelineWidget::ViewSelectionChanged); } void TimelineWidget::DisconnectViewSelectionSignal(TimelineView *view) { disconnect(view, &TimelineView::SelectionChanged, this, &TimelineWidget::ViewSelectionChanged); } int TimelineWidget::GetTrackY(const TrackReference &ref) { return views_.at(ref.type())->view()->GetTrackY(ref.index()); } int TimelineWidget::GetTrackHeight(const TrackReference &ref) { return views_.at(ref.type())->view()->GetTrackHeight(ref.index()); } void TimelineWidget::CenterOn(qreal scene_pos) { scrollbar()->setValue(qRound(scene_pos - scrollbar()->width()/2)); } void TimelineWidget::ClearGhosts() { if (!ghost_items_.isEmpty()) { foreach (TimelineViewGhostItem* ghost, ghost_items_) { delete ghost; } ghost_items_.clear(); } HideSnaps(); } bool TimelineWidget::HasGhosts() { return !ghost_items_.isEmpty(); } TimelineWidget::Tool *TimelineWidget::GetActiveTool() { return tools_.at(Core::instance()->tool()); } void TimelineWidget::ViewMousePressed(TimelineViewMouseEvent *event) { active_tool_ = GetActiveTool(); if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MousePress(event); } if (event->GetButton() != Qt::LeftButton) { // Suspend tool immediately if the cursor isn't the primary button active_tool_->MouseRelease(event); active_tool_ = nullptr; } } void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event) { if (GetConnectedNode()) { if (active_tool_) { active_tool_->MouseMove(event); } else { // Mouse is not down, attempt a hover event Tool* hover_tool = GetActiveTool(); if (hover_tool) { hover_tool->HoverMove(event); } } } } void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event) { if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MouseRelease(event); active_tool_ = nullptr; } } void TimelineWidget::ViewMouseDoubleClicked(TimelineViewMouseEvent *event) { if (GetConnectedNode() && active_tool_ != nullptr) { active_tool_->MouseDoubleClick(event); active_tool_ = nullptr; } } void TimelineWidget::ViewDragEntered(TimelineViewMouseEvent *event) { import_tool_->DragEnter(event); } void TimelineWidget::ViewDragMoved(TimelineViewMouseEvent *event) { import_tool_->DragMove(event); } void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event) { import_tool_->DragLeave(event); } void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event) { import_tool_->DragDrop(event); } void TimelineWidget::AddBlock(Block *block, TrackReference track) { // Set up clip with view parameters (clip item will automatically size its rect accordingly) TimelineViewBlockItem* item = new TimelineViewBlockItem(block); item->SetYCoords(GetTrackY(track), GetTrackHeight(track)); item->SetScale(GetScale()); item->SetTrack(track); item->SetTimebase(timebase()); // Add to list of clip items that can be iterated through block_items_.insert(block, item); // Add item to graphics scene views_.at(track.type())->view()->scene()->addItem(item); connect(block, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed); connect(block, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated); connect(block, &Block::LabelChanged, this, &TimelineWidget::BlockUpdated); connect(block, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated); } void TimelineWidget::RemoveBlock(Block *block) { disconnect(block, &Block::Refreshed, this, &TimelineWidget::BlockRefreshed); disconnect(block, &Block::LinksChanged, this, &TimelineWidget::BlockUpdated); disconnect(block, &Block::LabelChanged, this, &TimelineWidget::BlockUpdated); disconnect(block, &Block::EnabledChanged, this, &TimelineWidget::BlockUpdated); delete block_items_.take(block); } void TimelineWidget::AddTrack(TrackOutput *track, Timeline::TrackType type) { foreach (Block* b, track->Blocks()) { AddBlock(b, TrackReference(type, track->Index())); } connect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged); connect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated); } void TimelineWidget::RemoveTrack(TrackOutput *track) { disconnect(track, &TrackOutput::IndexChanged, this, &TimelineWidget::TrackIndexChanged); disconnect(track, &TrackOutput::PreviewChanged, this, &TimelineWidget::TrackPreviewUpdated); foreach (Block* b, track->Blocks()) { RemoveBlock(b); } } void TimelineWidget::TrackIndexChanged() { TrackOutput* track = static_cast(sender()); TrackReference ref(track->track_type(), track->Index()); foreach (Block* b, track->Blocks()) { TimelineViewBlockItem* item = block_items_.value(b); item->SetYCoords(GetTrackY(ref), GetTrackHeight(ref)); item->SetTrack(ref); } } void TimelineWidget::ViewSelectionChanged() { if (rubberband_.isVisible()) { return; } QList selected_items = GetSelectedBlocks(); QList selected_blocks; foreach (TimelineViewBlockItem* item, selected_items) { selected_blocks.append(item->block()); } emit SelectionChanged(selected_blocks); } void TimelineWidget::BlockRefreshed() { TimelineViewRect* rect = block_items_.value(static_cast(sender())); if (rect) { rect->UpdateRect(); } } void TimelineWidget::BlockUpdated() { TimelineViewRect* rect = block_items_.value(static_cast(sender())); if (rect) { rect->update(); } } void TimelineWidget::TrackPreviewUpdated() { QMap::const_iterator i; TrackOutput* track = static_cast(sender()); TrackReference track_ref(track->track_type(), track->Index()); for (i=block_items_.constBegin(); i!=block_items_.constEnd(); i++) { if (i.value()->Track() == track_ref) { i.value()->update(); } } } void TimelineWidget::UpdateHorizontalSplitters() { QSplitter* sender_splitter = static_cast(sender()); foreach (TimelineAndTrackView* tview, views_) { QSplitter* recv_splitter = tview->splitter(); if (recv_splitter != sender_splitter) { recv_splitter->blockSignals(true); recv_splitter->setSizes(sender_splitter->sizes()); recv_splitter->blockSignals(false); } } UpdateTimecodeWidthFromSplitters(sender_splitter); } void TimelineWidget::UpdateTimecodeWidthFromSplitters(QSplitter* s) { timecode_label_->setFixedWidth(s->sizes().first() + s->handleWidth()); } void TimelineWidget::TrackHeightChanged(Timeline::TrackType type, int index, int height) { Q_UNUSED(index) Q_UNUSED(height) QMap::const_iterator iterator; TimelineView* view = views_.at(type)->view(); for (iterator=block_items_.begin();iterator!=block_items_.end();iterator++) { TimelineViewBlockItem* block_item = iterator.value(); if (block_item->Track().type() == type) { block_item->SetYCoords(view->GetTrackY(block_item->Track().index()), view->GetTrackHeight(block_item->Track().index())); } } } void TimelineWidget::ShowContextMenu() { Menu menu(this); QList selected = GetSelectedBlocks(); if (!selected.isEmpty()) { MenuShared::instance()->AddItemsForEditMenu(&menu, true); menu.addSeparator(); QAction* speed_duration_action = menu.addAction(tr("Speed/Duration")); connect(speed_duration_action, &QAction::triggered, this, &TimelineWidget::ShowSpeedDurationDialog); menu.addSeparator(); QAction* properties_action = menu.addAction(tr("Properties")); connect(properties_action, &QAction::triggered, this, [this](){ QList block_items = GetSelectedBlocks(); QList nodes; foreach (TimelineViewBlockItem* i, block_items) { nodes.append(i->block()); } Core::instance()->LabelNodes(nodes); }); } if (selected.isEmpty()) { QAction* toggle_audio_units = menu.addAction(tr("Use Audio Time Units")); toggle_audio_units->setCheckable(true); toggle_audio_units->setChecked(use_audio_time_units_); connect(toggle_audio_units, &QAction::triggered, this, &TimelineWidget::SetUseAudioTimeUnits); menu.addSeparator(); QAction* properties_action = menu.addAction(tr("Properties")); connect(properties_action, &QAction::triggered, this, &TimelineWidget::ShowSequenceDialog); } menu.exec(QCursor::pos()); } void TimelineWidget::ShowSpeedDurationDialog() { QList selected = GetSelectedBlocks(); QList selected_clips; foreach (TimelineViewBlockItem* item, selected) { if (item->block()->type() == Block::kClip) { selected_clips.append(static_cast(item->block())); } } if (selected_clips.isEmpty()) { // SpeedDurationDialog expects at least one clip return; } SpeedDurationDialog speed_diag(timebase(), selected_clips, this); speed_diag.exec(); } void TimelineWidget::DeferredScrollAction() { scrollbar()->setValue(deferred_scroll_value_); } void TimelineWidget::ShowSequenceDialog() { if (!GetConnectedNode()) { return; } SequenceDialog sd(static_cast(GetConnectedNode()->parent()), SequenceDialog::kExisting, this); sd.exec(); } void TimelineWidget::SetUseAudioTimeUnits(bool use) { use_audio_time_units_ = use; // Update timebases UpdateViewTimebases(); // Force update of the viewer timestamps SetViewTimestamp(GetTimestamp()); } void TimelineWidget::SetViewTimestamp(const int64_t &ts) { for (int i=0;iview()->SetTime(Timecode::rescale_timestamp(ts, timebase(), GetConnectedNode()->audio_params().time_base())); } else { view->view()->SetTime(ts); } } } void TimelineWidget::ViewTimestampChanged(int64_t ts) { if (use_audio_time_units_ && sender() == views_.at(Timeline::kTrackTypeAudio)) { ts = Timecode::rescale_timestamp(ts, GetConnectedNode()->audio_params().time_base(), timebase()); } // Update all other views SetViewTimestamp(ts); ruler()->SetTime(ts); emit TimeChanged(ts); } void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost) { ghost->SetScale(GetScale()); ghost_items_.append(ghost); views_.at(ghost->Track().type())->view()->scene()->addItem(ghost); } void TimelineWidget::UpdateViewTimebases() { for (int i=0;iview()->SetTimebase(GetConnectedNode()->audio_params().time_base()); } else { view->view()->SetTimebase(timebase()); } } } void TimelineWidget::SetViewBeamCursor(const TimelineCoordinate &coord) { foreach (TimelineAndTrackView* tview, views_) { tview->view()->SetBeamCursor(coord); } } void TimelineWidget::SetBlockLinksSelected(Block* block, bool selected) { TimelineViewBlockItem* link_item; foreach (Block* link, block->linked_clips()) { if ((link_item = block_items_[link]) != nullptr) { link_item->setSelected(selected); } } } QVector TimelineWidget::GetEditToInfo(const rational& playhead_time, Timeline::MovementMode mode) { // Get list of unlocked tracks QVector tracks = GetConnectedNode()->GetUnlockedTracks(); // Create list to cache nearest times and the blocks at this point QVector info_list(tracks.size()); for (int i=0;iNearestBlockBeforeOrAt(playhead_time); } else { b = track->NearestBlockBefore(playhead_time); } // If we have a block here, cache how close it is to the track if (b) { rational this_track_closest_point; if (mode == Timeline::kTrimIn) { this_track_closest_point = b->in(); } else { this_track_closest_point = b->out(); } info.nearest_time = this_track_closest_point; } info.nearest_block = b; info_list[i] = info; } return info_list; } void TimelineWidget::RippleTo(Timeline::MovementMode mode) { rational playhead_time = GetTime(); QVector tracks = GetEditToInfo(playhead_time, mode); if (tracks.isEmpty()) { return; } // Find each track's nearest point and determine the overall timeline's nearest point rational closest_point_to_playhead = (mode == Timeline::kTrimIn) ? rational() : RATIONAL_MAX; foreach (const Timeline::EditToInfo& info, tracks) { if (info.nearest_block) { if (mode == Timeline::kTrimIn) { closest_point_to_playhead = qMax(info.nearest_time, closest_point_to_playhead); } else { closest_point_to_playhead = qMin(info.nearest_time, closest_point_to_playhead); } } } // If we're not inserting gaps and the edit point is right on the nearest in point, we enter a // single-frame mode where we remove one frame only if (closest_point_to_playhead == playhead_time) { if (mode == Timeline::kTrimIn) { playhead_time += timebase(); } else { playhead_time -= timebase(); } } // For standard rippling, we can cache here the region that will be rippled out rational in_ripple = qMin(closest_point_to_playhead, playhead_time); rational out_ripple = qMax(closest_point_to_playhead, playhead_time); TimelineRippleRemoveAreaCommand* c = new TimelineRippleRemoveAreaCommand(GetConnectedNode(), in_ripple, out_ripple); Core::instance()->undo_stack()->push(c); // If we rippled, ump to where new cut is if applicable if (mode == Timeline::kTrimIn) { SetTimeAndSignal(Timecode::time_to_timestamp(closest_point_to_playhead, timebase())); } else if (mode == Timeline::kTrimOut && closest_point_to_playhead == GetTime()) { SetTimeAndSignal(Timecode::time_to_timestamp(playhead_time, timebase())); } } void TimelineWidget::EditTo(Timeline::MovementMode mode) { const rational playhead_time = GetTime(); // Get list of unlocked tracks QVector tracks = GetEditToInfo(playhead_time, mode); if (tracks.isEmpty()) { return; } QUndoCommand* command = new QUndoCommand(); foreach (const Timeline::EditToInfo& info, tracks) { if (info.nearest_block && info.nearest_block->type() != Block::kGap && info.nearest_time != playhead_time) { rational new_len; if (mode == Timeline::kTrimIn) { new_len = playhead_time - info.nearest_time; } else { new_len = info.nearest_time - playhead_time; } new_len = info.nearest_block->length() - new_len; new BlockTrimCommand(info.track, info.nearest_block, new_len, mode, command); } } Core::instance()->undo_stack()->pushIfHasChildren(command); } void TimelineWidget::ShowSnap(const QList ×) { foreach (TimelineAndTrackView* tview, views_) { tview->view()->EnableSnap(times); } } void TimelineWidget::HideSnaps() { foreach (TimelineAndTrackView* tview, views_) { tview->view()->DisableSnap(); } } QByteArray TimelineWidget::SaveSplitterState() const { return view_splitter_->saveState(); } void TimelineWidget::RestoreSplitterState(const QByteArray &state) { view_splitter_->restoreState(state); } void TimelineWidget::StartRubberBandSelect(bool enable_selecting, bool select_links) { drag_origin_ = QCursor::pos(); rubberband_.show(); MoveRubberBandSelect(enable_selecting, select_links); } void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_links) { QPoint rubberband_now = QCursor::pos(); rubberband_.setGeometry(QRect(mapFromGlobal(drag_origin_), mapFromGlobal(rubberband_now)).normalized()); if (!enable_selecting) { return; } QList new_selected_list; foreach (TimelineAndTrackView* tview, views_) { // Map global mouse coordinates to viewport TimelineView* view = tview->view(); QRect mapped_rect(view->viewport()->mapFromGlobal(drag_origin_), view->viewport()->mapFromGlobal(rubberband_now)); // Normalize and get items in rect QList rubberband_items = view->items(mapped_rect.normalized()); new_selected_list.append(rubberband_items); } foreach (QGraphicsItem* item, rubberband_now_selected_) { item->setSelected(false); } foreach (QGraphicsItem* item, new_selected_list) { TimelineViewBlockItem* block_item = dynamic_cast(item); if (!block_item || block_item->block()->type() == Block::kGap) { continue; } TrackOutput* t = GetTrackFromReference(block_item->Track()); if (t && t->IsLocked()) { continue; } block_item->setSelected(true); if (select_links) { // Select the block's links Block* b = block_item->block(); SetBlockLinksSelected(b, true); // Add its links to the list TimelineViewBlockItem* link_item; foreach (Block* link, b->linked_clips()) { if ((link_item = block_items_[link]) != nullptr) { if (!new_selected_list.contains(link_item)) { new_selected_list.append(link_item); } } } } } rubberband_now_selected_ = new_selected_list; } void TimelineWidget::EndRubberBandSelect(bool enable_selecting, bool select_links) { MoveRubberBandSelect(enable_selecting, select_links); rubberband_.hide(); rubberband_now_selected_.clear(); ViewSelectionChanged(); } struct SnapData { rational time; rational movement; }; QList AttemptSnap(const QList& screen_pt, double compare_pt, const QList& start_times, const rational& compare_time) { const qreal kSnapRange = 10; // FIXME: Hardcoded number QList snap_data; for (int i=0;i start_times, rational* movement, int snap_points) { QList screen_pt; foreach (const rational& s, start_times) { screen_pt.append(TimeToScene(s + *movement)); } QList potential_snaps; if (snap_points & kSnapToPlayhead) { rational playhead_abs_time = GetTime(); qreal playhead_pos = TimeToScene(playhead_abs_time); potential_snaps.append(AttemptSnap(screen_pt, playhead_pos, start_times, playhead_abs_time)); } if (snap_points & kSnapToClips) { QMap::const_iterator i; for (i=block_items_.constBegin(); i!=block_items_.constEnd(); i++) { TimelineViewBlockItem* item = i.value(); if (item) { qreal rect_left = item->x(); qreal rect_right = rect_left + item->rect().width(); // Attempt snapping to clip in point potential_snaps.append(AttemptSnap(screen_pt, rect_left, start_times, item->block()->in())); // Attempt snapping to clip out point potential_snaps.append(AttemptSnap(screen_pt, rect_right, start_times, item->block()->out())); } } } if ((snap_points & kSnapToMarkers) && GetConnectedTimelinePoints()) { foreach (TimelineMarker* m, GetConnectedTimelinePoints()->markers()->list()) { qreal marker_pos = TimeToScene(m->time().in()); potential_snaps.append(AttemptSnap(screen_pt, marker_pos, start_times, m->time().in())); if (m->time().in() != m->time().out()) { marker_pos = TimeToScene(m->time().out()); potential_snaps.append(AttemptSnap(screen_pt, marker_pos, start_times, m->time().out())); } } } if (potential_snaps.isEmpty()) { HideSnaps(); return false; } int closest_snap = 0; rational closest_diff = qAbs(potential_snaps.at(0).movement - *movement); // Determine which snap point was the closest for (int i=1; i snap_times; foreach (const SnapData& d, potential_snaps) { if (d.movement == *movement) { snap_times.append(d.time); } } ShowSnap(snap_times); return true; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/timelinewidget.h000066400000000000000000000373631370472574300246700ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEWIDGET_H #define TIMELINEWIDGET_H #include #include #include #include "core.h" #include "node/output/viewer/viewer.h" #include "snapservice.h" #include "timeline/timelinecommon.h" #include "timelineandtrackview.h" #include "widget/nodecopypaste/nodecopypaste.h" #include "widget/slider/timeslider.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER /** * @brief Full widget for working with TimelineOutput nodes * * Encapsulates TimelineViews, TimeRulers, and scrollbars for a complete widget to manipulate Timelines */ class TimelineWidget : public TimeBasedWidget, public NodeCopyPasteWidget, public SnapService { Q_OBJECT public: enum DropWithoutSequenceBehavior { kDWSAsk, kDWSAuto, kDWSManual, kDWSDisable }; TimelineWidget(QWidget* parent = nullptr); virtual ~TimelineWidget() override; void Clear(); void SelectAll(); void DeselectAll(); void RippleToIn(); void RippleToOut(); void EditToIn(); void EditToOut(); void SplitAtPlayhead(); void DeleteSelected(bool ripple = false); void IncreaseTrackHeight(); void DecreaseTrackHeight(); void InsertFootageAtPlayhead(const QList &footage); void OverwriteFootageAtPlayhead(const QList &footage); void ToggleLinksOnSelected(); void CopySelected(bool cut); void Paste(bool insert); void DeleteInToOut(bool ripple); void ToggleSelectedEnabled(); QList GetSelectedBlocks(); virtual bool SnapPoint(QList start_times, rational *movement, int snap_points = kSnapAll) override; virtual void HideSnaps() override; QByteArray SaveSplitterState() const; void RestoreSplitterState(const QByteArray& state); signals: void SelectionChanged(const QList& selected_blocks); protected: virtual void resizeEvent(QResizeEvent *event) override; virtual void TimebaseChangedEvent(const rational &) override; virtual void TimeChangedEvent(const int64_t &) override; virtual void ScaleChangedEvent(const double &) override; virtual void ConnectNodeInternal(ViewerOutput* n) override; virtual void DisconnectNodeInternal(ViewerOutput* n) override; virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata) override; virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, void* userdata) override; struct BlockPasteData { quintptr ptr; rational in; Timeline::TrackType track_type; int track_index; }; private: class DraggedFootage { public: DraggedFootage(Footage* f, quint64 streams) : footage_(f), streams_(streams) { } Footage* footage() const { return footage_; } const quint64& streams() const { return streams_; } private: Footage* footage_; quint64 streams_; }; static DraggedFootage FootageToDraggedFootage(Footage* f); static QList FootageToDraggedFootage(QList footage); class Tool { public: Tool(TimelineWidget* parent); virtual ~Tool(); virtual void MousePress(TimelineViewMouseEvent *){} virtual void MouseMove(TimelineViewMouseEvent *){} virtual void MouseRelease(TimelineViewMouseEvent *){} virtual void MouseDoubleClick(TimelineViewMouseEvent *){} virtual void HoverMove(TimelineViewMouseEvent *){} virtual void DragEnter(TimelineViewMouseEvent *){} virtual void DragMove(TimelineViewMouseEvent *){} virtual void DragLeave(QDragLeaveEvent *){} virtual void DragDrop(TimelineViewMouseEvent *){} TimelineWidget* parent(); static Timeline::MovementMode FlipTrimMode(const Timeline::MovementMode& trim_mode); protected: /** * @brief Retrieve the QGraphicsItem at a particular scene position * * Requires a float-based scene position. If you have a screen position, use GetScenePos() first to convert it to a * scene position */ TimelineViewBlockItem* GetItemAtScenePos(const TimelineCoordinate &coord); /** * @brief Validates Ghosts that are moving horizontally (time-based) * * Validation is the process of ensuring that whatever movements the user is making are "valid" and "legal". This * function's validation ensures that no Ghost's in point ends up in a negative timecode. */ rational ValidateTimeMovement(rational movement, const QVector ghosts); /** * @brief Validates Ghosts that are moving vertically (track-based) * * This function's validation ensures that no Ghost's track ends up in a negative (non-existent) track. */ int ValidateTrackMovement(int movement, const QVector ghosts); void GetGhostData(const QVector& ghosts, rational *earliest_point, rational *latest_point); void InsertGapsAtGhostDestination(const QVector& ghosts, QUndoCommand* command); QList snap_points_; bool dragging_; TimelineCoordinate drag_start_; private: TimelineWidget* parent_; }; class BeamTool : public Tool { public: BeamTool(TimelineWidget *parent); virtual void HoverMove(TimelineViewMouseEvent *event) override; protected: TimelineCoordinate ValidatedCoordinate(TimelineCoordinate coord); }; class PointerTool : public Tool { public: PointerTool(TimelineWidget* parent); virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; virtual void HoverMove(TimelineViewMouseEvent *event) override; protected: virtual void FinishDrag(TimelineViewMouseEvent *event); virtual void InitiateDrag(TimelineViewBlockItem* clicked_item, Timeline::MovementMode trim_mode); TimelineViewGhostItem* AddGhostFromBlock(Block *block, const TrackReference& track, Timeline::MovementMode mode); TimelineViewGhostItem* AddGhostFromNull(const rational& in, const rational& out, const TrackReference& track, Timeline::MovementMode mode); /** * @brief Validates Ghosts that are getting their in points trimmed * * Assumes ghost->data() is a Block. Ensures no Ghost's in point becomes a negative timecode. Also ensures no * Ghost's length becomes 0 or negative. */ rational ValidateInTrimming(rational movement, const QVector ghosts, bool prevent_overwriting); /** * @brief Validates Ghosts that are getting their out points trimmed * * Assumes ghost->data() is a Block. Ensures no Ghost's in point becomes a negative timecode. Also ensures no * Ghost's length becomes 0 or negative. */ rational ValidateOutTrimming(rational movement, const QVector ghosts, bool prevent_overwriting); virtual void ProcessDrag(const TimelineCoordinate &mouse_pos); const Timeline::MovementMode& drag_movement_mode() const { return drag_movement_mode_; } void SetMovementAllowed(bool e) { movement_allowed_ = e; } void SetTrimmingAllowed(bool e) { trimming_allowed_ = e; } void SetTrackMovementAllowed(bool e) { track_movement_allowed_ = e; } void SetTrimOverwriteAllowed(bool e) { trim_overwrite_allowed_ = e; } void SetGapTrimmingAllowed(bool e) { gap_trimming_allowed_ = e; } private: Timeline::MovementMode IsCursorInTrimHandle(TimelineViewBlockItem* block, qreal cursor_x); void AddGhostInternal(TimelineViewGhostItem* ghost, Timeline::MovementMode mode); bool IsClipTrimmable(TimelineViewBlockItem* clip, const QList& items, const Timeline::MovementMode& mode); bool movement_allowed_; bool trimming_allowed_; bool track_movement_allowed_; bool trim_overwrite_allowed_; bool gap_trimming_allowed_; bool rubberband_selecting_; Timeline::TrackType drag_track_type_; Timeline::MovementMode drag_movement_mode_; TimelineViewBlockItem* clicked_item_; }; class ImportTool : public Tool { public: ImportTool(TimelineWidget* parent); virtual void DragEnter(TimelineViewMouseEvent *event) override; virtual void DragMove(TimelineViewMouseEvent *event) override; virtual void DragLeave(QDragLeaveEvent *event) override; virtual void DragDrop(TimelineViewMouseEvent *event) override; void PlaceAt(const QList &footage, const rational& start, bool insert); void PlaceAt(const QList &footage, const rational& start, bool insert); private: void FootageToGhosts(rational ghost_start, const QList& footage, const rational &dest_tb, const int &track_start); void PrepGhosts(const rational &frame, const int &track_index); void DropGhosts(bool insert); QList dragged_footage_; int import_pre_buffer_; }; class EditTool : public BeamTool { public: EditTool(TimelineWidget* parent); virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; }; class RazorTool : public BeamTool { public: RazorTool(TimelineWidget* parent); virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; private: QVector split_tracks_; }; class RippleTool : public PointerTool { public: RippleTool(TimelineWidget* parent); protected: virtual void FinishDrag(TimelineViewMouseEvent *event) override; virtual void InitiateDrag(TimelineViewBlockItem* clicked_item, Timeline::MovementMode trim_mode) override; }; class RollingTool : public PointerTool { public: RollingTool(TimelineWidget* parent); protected: virtual void FinishDrag(TimelineViewMouseEvent *event) override; virtual void InitiateDrag(TimelineViewBlockItem* clicked_item, Timeline::MovementMode trim_mode) override; }; class SlideTool : public PointerTool { public: SlideTool(TimelineWidget* parent); protected: virtual void FinishDrag(TimelineViewMouseEvent *event) override; virtual void InitiateDrag(TimelineViewBlockItem* clicked_item, Timeline::MovementMode trim_mode) override; }; class SlipTool : public PointerTool { public: SlipTool(TimelineWidget* parent); protected: virtual void ProcessDrag(const TimelineCoordinate &mouse_pos) override; virtual void FinishDrag(TimelineViewMouseEvent *event) override; }; class ZoomTool : public Tool { public: ZoomTool(TimelineWidget* parent); virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; }; class AddTool : public BeamTool { public: AddTool(TimelineWidget* parent); virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; protected: void MouseMoveInternal(const rational& cursor_frame, bool outwards); TimelineViewGhostItem* ghost_; rational drag_start_point_; }; class TransitionTool : public AddTool { public: TransitionTool(TimelineWidget* parent); virtual void MousePress(TimelineViewMouseEvent *event) override; virtual void MouseMove(TimelineViewMouseEvent *event) override; virtual void MouseRelease(TimelineViewMouseEvent *event) override; private: bool dual_transition_; }; rational GetToolTipTimebase() const; void InsertGapsAt(const rational& time, const rational& length, QUndoCommand* command); void DeleteSelectedInternal(const QList& blocks, bool transition_aware, bool remove_from_graph, QUndoCommand* command); void SetBlockLinksSelected(Block *block, bool selected); QVector GetEditToInfo(const rational &playhead_time, Timeline::MovementMode mode); void RippleTo(Timeline::MovementMode mode); void EditTo(Timeline::MovementMode mode); void ShowSnap(const QList& times); QPoint drag_origin_; void StartRubberBandSelect(bool enable_selecting, bool select_links); void MoveRubberBandSelect(bool enable_selecting, bool select_links); void EndRubberBandSelect(bool enable_selecting, bool select_links); QRubberBand rubberband_; QList rubberband_now_selected_; Tool* GetActiveTool(); QVector tools_; ImportTool* import_tool_; Tool* active_tool_; void ClearGhosts(); bool HasGhosts(); QVector ghost_items_; QMap block_items_; TrackOutput* GetTrackFromReference(const TrackReference& ref); void ConnectViewSelectionSignal(TimelineView* view); void DisconnectViewSelectionSignal(TimelineView* view); QList views_; TimeSlider* timecode_label_; int deferred_scroll_value_; bool use_audio_time_units_; QSplitter* view_splitter_; int GetTrackY(const TrackReference& ref); int GetTrackHeight(const TrackReference& ref); void CenterOn(qreal scene_pos); void AddGhost(TimelineViewGhostItem* ghost); void UpdateViewTimebases(); void SetViewBeamCursor(const TimelineCoordinate& coord); private slots: void ViewMousePressed(TimelineViewMouseEvent* event); void ViewMouseMoved(TimelineViewMouseEvent* event); void ViewMouseReleased(TimelineViewMouseEvent* event); void ViewMouseDoubleClicked(TimelineViewMouseEvent* event); void ViewDragEntered(TimelineViewMouseEvent* event); void ViewDragMoved(TimelineViewMouseEvent* event); void ViewDragLeft(QDragLeaveEvent* event); void ViewDragDropped(TimelineViewMouseEvent* event); void AddBlock(Block* block, TrackReference track); void RemoveBlock(Block* block); void AddTrack(TrackOutput* track, Timeline::TrackType type); void RemoveTrack(TrackOutput* track); void TrackIndexChanged(); void ViewSelectionChanged(); /** * @brief Slot for when a Block node changes its parameters and the graphics need to update * * This slot does a static_cast on sender() to Block*, meaning all objects triggering this slot must be Blocks or * derivatives. */ void BlockRefreshed(); void BlockUpdated(); void TrackPreviewUpdated(); void UpdateHorizontalSplitters(); void UpdateTimecodeWidthFromSplitters(QSplitter *s); void TrackHeightChanged(Timeline::TrackType type, int index, int height); void ShowContextMenu(); void ShowSpeedDurationDialog(); void DeferredScrollAction(); void ShowSequenceDialog(); void SetUseAudioTimeUnits(bool use); void SetViewTimestamp(const int64_t& ts); void ViewTimestampChanged(int64_t ts); }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEWIDGET_H olive-continuous/app/widget/timelinewidget/tool/000077500000000000000000000000001370472574300224465ustar00rootroot00000000000000olive-continuous/app/widget/timelinewidget/tool/CMakeLists.txt000066400000000000000000000023641370472574300252130ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timelinewidget/tool/add.cpp widget/timelinewidget/tool/beam.cpp widget/timelinewidget/tool/edit.cpp widget/timelinewidget/tool/import.cpp widget/timelinewidget/tool/pointer.cpp widget/timelinewidget/tool/razor.cpp widget/timelinewidget/tool/ripple.cpp widget/timelinewidget/tool/rolling.cpp widget/timelinewidget/tool/slide.cpp widget/timelinewidget/tool/slip.cpp widget/timelinewidget/tool/transition.cpp widget/timelinewidget/tool/tool.cpp widget/timelinewidget/tool/zoom.cpp PARENT_SCOPE ) olive-continuous/app/widget/timelinewidget/tool/add.cpp000066400000000000000000000134751370472574300237140ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include "core.h" #include "node/factory.h" #include "node/generator/solid/solid.h" #include "node/generator/text/text.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::AddTool::AddTool(TimelineWidget *parent) : BeamTool(parent), ghost_(nullptr) { } void TimelineWidget::AddTool::MousePress(TimelineViewMouseEvent *event) { const TrackReference& track = event->GetTrack(); // Check if track is locked TrackOutput* t = parent()->GetTrackFromReference(track); if (t && t->IsLocked()) { return; } Timeline::TrackType add_type = Timeline::kTrackTypeNone; switch (Core::instance()->GetSelectedAddableObject()) { case OLIVE_NAMESPACE::Tool::kAddableBars: case OLIVE_NAMESPACE::Tool::kAddableSolid: case OLIVE_NAMESPACE::Tool::kAddableTitle: add_type = Timeline::kTrackTypeVideo; break; case OLIVE_NAMESPACE::Tool::kAddableTone: add_type = Timeline::kTrackTypeAudio; break; case OLIVE_NAMESPACE::Tool::kAddableEmpty: // Leave as "none", which means this block can be placed on any track break; case OLIVE_NAMESPACE::Tool::kAddableCount: // Return so we do nothing return; } if (add_type == Timeline::kTrackTypeNone || add_type == track.type()) { drag_start_point_ = ValidatedCoordinate(event->GetCoordinates(true)).GetFrame(); ghost_ = new TimelineViewGhostItem(); ghost_->SetIn(drag_start_point_); ghost_->SetOut(drag_start_point_); ghost_->SetTrack(track); ghost_->SetYCoords(parent()->GetTrackY(track), parent()->GetTrackHeight(track)); parent()->AddGhost(ghost_); snap_points_.append(drag_start_point_); } } void TimelineWidget::AddTool::MouseMove(TimelineViewMouseEvent *event) { if (!ghost_) { return; } MouseMoveInternal(event->GetFrame(), event->GetModifiers() & Qt::AltModifier); } void TimelineWidget::AddTool::MouseRelease(TimelineViewMouseEvent *event) { MouseMove(event); const TrackReference& track = ghost_->Track(); if (ghost_) { if (!ghost_->AdjustedLength().isNull()) { QUndoCommand* command = new QUndoCommand(); ClipBlock* clip = new ClipBlock(); clip->set_length_and_media_out(ghost_->AdjustedLength()); clip->SetLabel(OLIVE_NAMESPACE::Tool::GetAddableObjectName(Core::instance()->GetSelectedAddableObject())); NodeGraph* graph = static_cast(parent()->GetConnectedNode()->parent()); new NodeAddCommand(graph, clip, command); new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track.type()), track.index(), clip, ghost_->GetAdjustedIn(), command); switch (Core::instance()->GetSelectedAddableObject()) { case OLIVE_NAMESPACE::Tool::kAddableEmpty: // Empty, nothing to be done break; case OLIVE_NAMESPACE::Tool::kAddableSolid: { Node* solid = new SolidGenerator(); new NodeAddCommand(graph, solid, command); new NodeEdgeAddCommand(solid->output(), clip->texture_input(), command); break; } case OLIVE_NAMESPACE::Tool::kAddableTitle: { Node* text = new TextGenerator(); new NodeAddCommand(graph, text, command); new NodeEdgeAddCommand(text->output(), clip->texture_input(), command); break; } case OLIVE_NAMESPACE::Tool::kAddableBars: case OLIVE_NAMESPACE::Tool::kAddableTone: // Not implemented yet qWarning() << "Unimplemented add object:" << Core::instance()->GetSelectedAddableObject(); break; case OLIVE_NAMESPACE::Tool::kAddableCount: // Invalid value, do nothing break; } Core::instance()->undo_stack()->push(command); } parent()->ClearGhosts(); snap_points_.clear(); ghost_ = nullptr; } } void TimelineWidget::AddTool::MouseMoveInternal(const rational &cursor_frame, bool outwards) { // Calculate movement rational movement = cursor_frame - drag_start_point_; // Validation: Ensure in point never goes below 0 if (movement < -ghost_->In() || (outwards && -movement < -ghost_->In())) { movement = -ghost_->In(); } // Snap movement bool snapped = parent()->SnapPoint(snap_points_, &movement); // If alt is held, our movement goes both ways (outwards) if (!snapped && outwards) { // Snap backwards too movement = -movement; parent()->SnapPoint(snap_points_, &movement); // We don't need to un-neg here because outwards means all future processing will be done both pos and neg } // Make adjustment if (!movement) { ghost_->SetInAdjustment(0); ghost_->SetOutAdjustment(0); } else if (movement > 0) { ghost_->SetInAdjustment(outwards ? -movement : 0); ghost_->SetOutAdjustment(movement); } else if (movement < 0) { ghost_->SetInAdjustment(movement); ghost_->SetOutAdjustment(outwards ? -movement : 0); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/beam.cpp000066400000000000000000000025271370472574300240640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" OLIVE_NAMESPACE_ENTER TimelineWidget::BeamTool::BeamTool(TimelineWidget *parent) : Tool(parent) { } void TimelineWidget::BeamTool::HoverMove(TimelineViewMouseEvent *event) { parent()->SetViewBeamCursor(ValidatedCoordinate(event->GetCoordinates(true))); } TimelineCoordinate TimelineWidget::BeamTool::ValidatedCoordinate(TimelineCoordinate coord) { if (Core::instance()->snapping()) { rational movement; parent()->SnapPoint({coord.GetFrame()}, &movement); if (!movement.isNull()) { coord.SetFrame(coord.GetFrame() + movement); } } return coord; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/edit.cpp000066400000000000000000000022351370472574300241010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" OLIVE_NAMESPACE_ENTER TimelineWidget::EditTool::EditTool(TimelineWidget* parent) : BeamTool(parent) { } void TimelineWidget::EditTool::MousePress(TimelineViewMouseEvent *event) { Q_UNUSED(event) } void TimelineWidget::EditTool::MouseMove(TimelineViewMouseEvent *event) { Q_UNUSED(event) } void TimelineWidget::EditTool::MouseRelease(TimelineViewMouseEvent *event) { Q_UNUSED(event) } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/import.cpp000066400000000000000000000373431370472574300244760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include #include #include #include #include "config/config.h" #include "common/qtutils.h" #include "core.h" #include "dialog/sequence/sequence.h" #include "node/audio/volume/volume.h" #include "node/generator/matrix/matrix.h" #include "node/input/media/audio/audio.h" #include "node/input/media/video/video.h" #include "node/math/math/math.h" #include "project/item/sequence/sequence.h" #include "widget/nodeview/nodeviewundo.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER Timeline::TrackType TrackTypeFromStreamType(Stream::Type stream_type) { switch (stream_type) { case Stream::kVideo: case Stream::kImage: return Timeline::kTrackTypeVideo; case Stream::kAudio: return Timeline::kTrackTypeAudio; case Stream::kSubtitle: // Temporarily disabled until we figure out a better thing to do with this //return Timeline::kTrackTypeSubtitle; case Stream::kUnknown: case Stream::kData: case Stream::kAttachment: break; } return Timeline::kTrackTypeNone; } TimelineWidget::ImportTool::ImportTool(TimelineWidget *parent) : Tool(parent) { // Calculate width used for importing to give ghosts a slight lead-in so the ghosts aren't right on the cursor import_pre_buffer_ = QFontMetricsWidth(parent->fontMetrics(), "HHHHHHHH"); } void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event) { QStringList mime_formats = event->GetMimeData()->formats(); // Listen for MIME data from a ProjectViewModel if (mime_formats.contains("application/x-oliveprojectitemdata")) { // Data is drag/drop data from a ProjectViewModel QByteArray model_data = event->GetMimeData()->data("application/x-oliveprojectitemdata"); // Use QDataStream to deserialize the data QDataStream stream(&model_data, QIODevice::ReadOnly); // Variables to deserialize into quintptr item_ptr; int r; quint64 enabled_streams; // Set drag start position drag_start_ = event->GetCoordinates(); snap_points_.clear(); while (!stream.atEnd()) { stream >> enabled_streams >> r >> item_ptr; // Get Item object Item* item = reinterpret_cast(item_ptr); // Check if Item is Footage if (item->type() == Item::kFootage) { // If the Item is Footage, we can create a Ghost from it dragged_footage_.append(DraggedFootage(static_cast(item), enabled_streams)); } } PrepGhosts(drag_start_.GetFrame() - parent()->SceneToTime(import_pre_buffer_), drag_start_.GetTrack().index()); event->accept(); } else { // FIXME: Implement dropping from file event->ignore(); } } void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event) { if (!dragged_footage_.isEmpty()) { if (parent()->HasGhosts()) { rational time_movement = event->GetFrame() - drag_start_.GetFrame(); int track_movement = event->GetTrack().index() - drag_start_.GetTrack().index(); time_movement = ValidateTimeMovement(time_movement, parent()->ghost_items_); track_movement = ValidateTrackMovement(track_movement, parent()->ghost_items_); // If snapping is enabled, check for snap points if (Core::instance()->snapping()) { parent()->SnapPoint(snap_points_, &time_movement); time_movement = ValidateTimeMovement(time_movement, parent()->ghost_items_); track_movement = ValidateTrackMovement(track_movement, parent()->ghost_items_); } rational earliest_ghost = RATIONAL_MAX; // Move ghosts to the mouse cursor foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { ghost->SetInAdjustment(time_movement); ghost->SetOutAdjustment(time_movement); ghost->SetTrackAdjustment(track_movement); TrackReference adjusted_track = ghost->GetAdjustedTrack(); ghost->SetYCoords(parent()->GetTrackY(adjusted_track), parent()->GetTrackHeight(adjusted_track)); earliest_ghost = qMin(earliest_ghost, ghost->GetAdjustedIn()); } // Generate tooltip (showing earliest in point of imported clip) int64_t earliest_timestamp = Timecode::time_to_timestamp(earliest_ghost, parent()->GetToolTipTimebase()); QString tooltip_text = Timecode::timestamp_to_timecode(earliest_timestamp, parent()->GetToolTipTimebase(), Core::instance()->GetTimecodeDisplay()); // Force tooltip to update (otherwise the tooltip won't move as written in the documentation, and could get in the way // of the cursor) QToolTip::hideText(); QToolTip::showText(QCursor::pos(), tooltip_text, parent()); } event->accept(); } else { event->ignore(); } } void TimelineWidget::ImportTool::DragLeave(QDragLeaveEvent* event) { if (!dragged_footage_.isEmpty()) { parent()->ClearGhosts(); dragged_footage_.clear(); event->accept(); } else { event->ignore(); } } void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event) { if (!dragged_footage_.isEmpty()) { DropGhosts(event->GetModifiers() & Qt::ControlModifier); event->accept(); } else { event->ignore(); } } void TimelineWidget::ImportTool::PlaceAt(const QList &footage, const rational &start, bool insert) { PlaceAt(FootageToDraggedFootage(footage), start, insert); } void TimelineWidget::ImportTool::PlaceAt(const QList &footage, const rational &start, bool insert) { dragged_footage_ = footage; if (dragged_footage_.isEmpty()) { return; } PrepGhosts(start, 0); DropGhosts(insert); } void TimelineWidget::ImportTool::FootageToGhosts(rational ghost_start, const QList &footage_list, const rational& dest_tb, const int& track_start) { foreach (const DraggedFootage& footage, footage_list) { // Each stream is offset by one track per track "type", we keep track of them in this vector QVector track_offsets(Timeline::kTrackTypeCount); track_offsets.fill(track_start); QVector footage_ghosts; rational footage_duration; bool contains_image_stream = false; quint64 enabled_streams = footage.streams(); // Loop through all streams in footage foreach (StreamPtr stream, footage.footage()->streams()) { Timeline::TrackType track_type = TrackTypeFromStreamType(stream->type()); quint64 cached_enabled_streams = enabled_streams; enabled_streams >>= 1; // Check if this stream has a compatible TrackList if (track_type == Timeline::kTrackTypeNone || !(cached_enabled_streams & 0x1)) { continue; } TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); if (stream->type() == Stream::kImage) { // Stream is essentially length-less - we may use the default still image length in config, // or we may use another stream's length depending on the circumstance contains_image_stream = true; } else { // Rescale stream duration to timeline timebase // Convert to rational time if (footage.footage()->workarea()->enabled()) { footage_duration = qMax(footage_duration, footage.footage()->workarea()->range().length()); ghost->SetMediaIn(footage.footage()->workarea()->in()); } else { int64_t stream_duration = Timecode::rescale_timestamp_ceil(stream->duration(), stream->timebase(), dest_tb); footage_duration = qMax(footage_duration, Timecode::timestamp_to_time(stream_duration, dest_tb)); } } ghost->SetTrack(TrackReference(track_type, track_offsets.at(track_type))); // Increment track count for this track type track_offsets[track_type]++; snap_points_.append(ghost->In()); snap_points_.append(ghost->Out()); ghost->setData(TimelineViewGhostItem::kAttachedFootage, QVariant::fromValue(stream)); ghost->SetMode(Timeline::kMove); footage_ghosts.append(ghost); } if (contains_image_stream && footage_duration.isNull()) { // Footage must ONLY be image streams so no duration value was found, use default in config footage_duration = Config::Current()["DefaultStillLength"].value(); } foreach (TimelineViewGhostItem* ghost, footage_ghosts) { ghost->SetIn(ghost_start); ghost->SetOut(ghost_start + footage_duration); parent()->AddGhost(ghost); } // Stack each ghost one after the other ghost_start += footage_duration; } } void TimelineWidget::ImportTool::PrepGhosts(const rational& frame, const int& track_index) { if (parent()->GetConnectedNode()) { FootageToGhosts(frame, dragged_footage_, parent()->timebase(), track_index); } } void TimelineWidget::ImportTool::DropGhosts(bool insert) { QUndoCommand* command = new QUndoCommand(); NodeGraph* dst_graph = nullptr; ViewerOutput* viewer_node = nullptr; Sequence* open_sequence = nullptr; if (parent()->GetConnectedNode()) { viewer_node = parent()->GetConnectedNode(); dst_graph = static_cast(parent()->GetConnectedNode()->parent()); } else { // There's no active timeline here, ask the user what to do DropWithoutSequenceBehavior behavior = static_cast(Config::Current()["DropWithoutSequenceBehavior"].toInt()); if (behavior == kDWSAsk) { QCheckBox* dont_ask_again_box = new QCheckBox(tr("Don't ask me again")); QMessageBox mbox(parent()); mbox.setIcon(QMessageBox::Question); mbox.setWindowTitle(tr("No Active Sequence")); mbox.setText(tr("No sequence is currently open. Would you like to create one?")); mbox.setCheckBox(dont_ask_again_box); QPushButton* auto_params_btn = mbox.addButton(tr("Automatically Detect Parameters From Footage"), QMessageBox::YesRole); QPushButton* manual_params_btn = mbox.addButton(tr("Set Parameters Manually"), QMessageBox::NoRole); mbox.addButton(QMessageBox::Cancel); mbox.exec(); if (mbox.clickedButton() == auto_params_btn) { behavior = kDWSAuto; } else if (mbox.clickedButton() == manual_params_btn) { behavior = kDWSManual; } else { behavior = kDWSDisable; } if (behavior != kDWSDisable && dont_ask_again_box->isChecked()) { Config::Current()["DropWithoutSequenceBehavior"] = behavior; } } if (behavior != kDWSDisable) { ProjectPtr active_project = Core::instance()->GetActiveProject(); if (active_project) { SequencePtr new_sequence = Core::instance()->CreateNewSequenceForProject(active_project.get()); new_sequence->set_default_parameters(); bool sequence_is_valid = true; if (behavior == kDWSAuto) { QList footage_only; foreach (const DraggedFootage& df, dragged_footage_) { footage_only.append(df.footage()); } new_sequence->set_parameters_from_footage(footage_only); } else { SequenceDialog sd(new_sequence.get(), SequenceDialog::kNew, parent()); sd.SetUndoable(false); if (sd.exec() != QDialog::Accepted) { sequence_is_valid = false; } } if (sequence_is_valid) { new_sequence->add_default_nodes(); new ProjectViewModel::AddItemCommand(Core::instance()->GetActiveProjectModel(), Core::instance()->GetSelectedFolderInActiveProject(), new_sequence, command); FootageToGhosts(0, dragged_footage_, new_sequence->video_params().time_base(), 0); dst_graph = new_sequence.get(); viewer_node = new_sequence->viewer_output(); // Set this as the sequence to open open_sequence = new_sequence.get(); } } } } if (dst_graph) { QVector block_items(parent()->ghost_items_.size()); // Check if we're inserting if (insert) { InsertGapsAtGhostDestination(parent()->ghost_items_, command); } for (int i=0;ighost_items_.size();i++) { TimelineViewGhostItem* ghost = parent()->ghost_items_.at(i); StreamPtr footage_stream = ghost->data(TimelineViewGhostItem::kAttachedFootage).value(); ClipBlock* clip = new ClipBlock(); clip->set_media_in(ghost->MediaIn()); clip->set_length_and_media_out(ghost->Length()); clip->SetLabel(footage_stream->footage()->name()); new NodeAddCommand(dst_graph, clip, command); switch (footage_stream->type()) { case Stream::kVideo: case Stream::kImage: { VideoInput* video_input = new VideoInput(); video_input->SetFootage(footage_stream); new NodeAddCommand(dst_graph, video_input, command); new NodeEdgeAddCommand(video_input->output(), clip->texture_input(), command); /* MatrixGenerator* matrix = new MatrixGenerator(); new NodeAddCommand(dst_graph, matrix, command); MathNode* multiply = new MathNode(); multiply->SetOperation(MathNode::kOpMultiply); new NodeAddCommand(dst_graph, multiply, command); new NodeEdgeAddCommand(video_input->output(), multiply->param_a_in(), command); new NodeEdgeAddCommand(matrix->output(), multiply->param_b_in(), command); new NodeEdgeAddCommand(multiply->output(), clip->texture_input(), command); */ break; } case Stream::kAudio: { AudioInput* audio_input = new AudioInput(); audio_input->SetFootage(footage_stream); new NodeAddCommand(dst_graph, audio_input, command); VolumeNode* volume_node = new VolumeNode(); new NodeAddCommand(dst_graph, volume_node, command); new NodeEdgeAddCommand(audio_input->output(), volume_node->samples_input(), command); new NodeEdgeAddCommand(volume_node->output(), clip->texture_input(), command); break; } default: break; } new TrackPlaceBlockCommand(viewer_node->track_list(ghost->GetAdjustedTrack().type()), ghost->GetAdjustedTrack().index(), clip, ghost->GetAdjustedIn(), command); block_items.replace(i, clip); // Link any clips so far that share the same Footage with this one for (int j=0;jghost_items_.at(j)->data(TimelineViewGhostItem::kAttachedFootage).value(); if (footage_compare->footage() == footage_stream->footage()) { Block::Link(block_items.at(j), clip); } } } } Core::instance()->undo_stack()->pushIfHasChildren(command); parent()->ClearGhosts(); dragged_footage_.clear(); if (open_sequence) { Core::instance()->main_window()->OpenSequence(open_sequence); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/pointer.cpp000066400000000000000000000523741370472574300246450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include #include #include "common/clamp.h" #include "common/flipmodifiers.h" #include "common/qtutils.h" #include "common/range.h" #include "common/timecodefunctions.h" #include "config/config.h" #include "core.h" #include "node/block/gap/gap.h" #include "node/block/transition/transition.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::PointerTool::PointerTool(TimelineWidget *parent) : Tool(parent), movement_allowed_(true), trimming_allowed_(true), track_movement_allowed_(true), trim_overwrite_allowed_(false), gap_trimming_allowed_(false), rubberband_selecting_(false) { } void TimelineWidget::PointerTool::MousePress(TimelineViewMouseEvent *event) { // Determine if item clicked on is selectable clicked_item_ = GetItemAtScenePos(event->GetCoordinates()); bool selectable_item = (clicked_item_ && clicked_item_->flags() & QGraphicsItem::ItemIsSelectable && !parent()->GetTrackFromReference(clicked_item_->Track())->IsLocked()); if (selectable_item) { // Cache the clip's type for use later drag_track_type_ = clicked_item_->Track().type(); // If we haven't started dragging yet, we'll initiate a drag here // Record where the drag started in timeline coordinates drag_start_ = event->GetCoordinates(); // Determine whether we're trimming or moving based on the position of the cursor drag_movement_mode_ = IsCursorInTrimHandle(clicked_item_, event->GetSceneX()); // If we're not in a trim mode, we must be in a move mode (provided the tool allows movement and // the block is not a gap) if (drag_movement_mode_ == Timeline::kNone && movement_allowed_ && clicked_item_->block()->type() != Block::kGap) { drag_movement_mode_ = Timeline::kMove; } // If this item is already selected, no further selection needs to be made if (clicked_item_->isSelected()) { // If shift is held, deselect it if (event->GetModifiers() & Qt::ShiftModifier) { clicked_item_->setSelected(false); // If not holding alt, deselect all links as well if (!(event->GetModifiers() & Qt::AltModifier)) { parent()->SetBlockLinksSelected(clicked_item_->block(), false); } } return; } } // If not holding shift, deselect all clips if (!(event->GetModifiers() & Qt::ShiftModifier)) { parent()->DeselectAll(); } if (selectable_item) { // Select this item clicked_item_->setSelected(true); // If not holding alt, select all links as well if (!(event->GetModifiers() & Qt::AltModifier)) { parent()->SetBlockLinksSelected(clicked_item_->block(), true); } } else if (event->GetButton() == Qt::LeftButton) { // Start rubberband drag parent()->StartRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier)); rubberband_selecting_ = true; } } void TimelineWidget::PointerTool::MouseMove(TimelineViewMouseEvent *event) { if (rubberband_selecting_) { // Process rubberband select parent()->MoveRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier)); return; } if (!dragging_) { // Now that the cursor has moved, we will assume the intention is to drag // Clear snap points snap_points_.clear(); // If we're performing an action, we can initiate ghosts if (drag_movement_mode_ != Timeline::kNone) { InitiateDrag(clicked_item_, drag_movement_mode_); } // Set dragging to true here so no matter what, the drag isn't re-initiated until it's completed dragging_ = true; } if (dragging_ && !parent()->ghost_items_.isEmpty()) { // We're already dragging AND we have ghosts to work with ProcessDrag(event->GetCoordinates()); } } void TimelineWidget::PointerTool::MouseRelease(TimelineViewMouseEvent *event) { if (rubberband_selecting_) { // Finish rubberband select parent()->EndRubberBandSelect(true, !(event->GetModifiers() & Qt::AltModifier)); rubberband_selecting_ = false; return; } if (dragging_) { if (!parent()->ghost_items_.isEmpty()) { FinishDrag(event); } parent()->ClearGhosts(); snap_points_.clear(); dragging_ = false; } } void TimelineWidget::PointerTool::HoverMove(TimelineViewMouseEvent *event) { if (trimming_allowed_) { // No dragging, but we still want to process cursors TimelineViewBlockItem* block_at_cursor = GetItemAtScenePos(event->GetCoordinates()); if (block_at_cursor) { switch (IsCursorInTrimHandle(block_at_cursor, event->GetSceneX())) { case Timeline::kTrimIn: parent()->setCursor(Qt::SizeHorCursor); break; case Timeline::kTrimOut: parent()->setCursor(Qt::SizeHorCursor); break; default: parent()->unsetCursor(); } } else { parent()->unsetCursor(); } } else { parent()->unsetCursor(); } } void TimelineWidget::PointerTool::FinishDrag(TimelineViewMouseEvent *event) { QList ghosts_moving; QList blocks_moving; QList ghosts_trimming; QList blocks_trimming; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { if (!ghost->HasBeenAdjusted()) { continue; } Block* b = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); if (ghost->mode() == Timeline::kMove) { ghosts_moving.append(ghost); blocks_moving.append(b); } else if (Timeline::IsATrimMode(ghost->mode())) { ghosts_trimming.append(ghost); blocks_trimming.append(b); } } if (blocks_moving.isEmpty() && blocks_trimming.isEmpty()) { // Likely means no block was adjusted, so we can skip the rest of the processing return; } // See if we're duplicated because ALT is held (only moved blocks can duplicate) bool duplicate_clips = (!blocks_moving.isEmpty() && event->GetModifiers() & Qt::AltModifier); bool inserting = (!blocks_moving.isEmpty() && event->GetModifiers() & Qt::ControlModifier); QUndoCommand* command = new QUndoCommand(); for (int i=0;iGetTrackFromReference(ghost->GetAdjustedTrack()), blocks_trimming.at(i), ghost->AdjustedLength(), ghost->mode(), command); } if (!blocks_moving.isEmpty()) { // If we're not duplicating, "remove" the clips and replace them with gaps if (!duplicate_clips) { parent()->DeleteSelectedInternal(blocks_moving, false, false, command); } if (inserting) { // If we're inserting, ripple everything at the destination with gaps InsertGapsAtGhostDestination(parent()->ghost_items_, command); } // Now we can re-add each clip for (int i=0;icopy(); new NodeAddCommand(static_cast(block->parent()), copy, command); new NodeCopyInputsCommand(block, copy, true, command); // Place the copy instead of the original block block = static_cast(copy); } const TrackReference& track_ref = ghost->GetAdjustedTrack(); new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track_ref.type()), track_ref.index(), block, ghost->GetAdjustedIn(), command); } // FIXME: Heavy optimization since MOST of the timeline does NOT change in this time } Core::instance()->undo_stack()->pushIfHasChildren(command); } void TimelineWidget::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) { // Calculate track movement int track_movement = track_movement_allowed_ ? mouse_pos.GetTrack().index() - drag_start_.GetTrack().index() : 0; // Determine frame movement rational time_movement = mouse_pos.GetFrame() - drag_start_.GetFrame(); // Validate movement (enforce all ghosts moving in legal ways) time_movement = ValidateTimeMovement(time_movement, parent()->ghost_items_); time_movement = ValidateInTrimming(time_movement, parent()->ghost_items_, !trim_overwrite_allowed_); time_movement = ValidateOutTrimming(time_movement, parent()->ghost_items_, !trim_overwrite_allowed_); // Perform snapping if enabled (adjusts time_movement if it's close to any potential snap points) if (Core::instance()->snapping()) { parent()->SnapPoint(snap_points_, &time_movement); time_movement = ValidateTimeMovement(time_movement, parent()->ghost_items_); time_movement = ValidateInTrimming(time_movement, parent()->ghost_items_, !trim_overwrite_allowed_); time_movement = ValidateOutTrimming(time_movement, parent()->ghost_items_, !trim_overwrite_allowed_); } // Validate ghosts that are being moved (clips from other track types do NOT get moved) { QVector validate_track_ghosts = parent()->ghost_items_; for (int i=0;iTrack().type() != drag_track_type_) { validate_track_ghosts.removeAt(i); i--; } } track_movement = ValidateTrackMovement(track_movement, validate_track_ghosts); } // Perform movement foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { switch (ghost->mode()) { case Timeline::kNone: break; case Timeline::kTrimIn: ghost->SetInAdjustment(time_movement); break; case Timeline::kTrimOut: ghost->SetOutAdjustment(time_movement); break; case Timeline::kMove: { ghost->SetInAdjustment(time_movement); ghost->SetOutAdjustment(time_movement); // Track movement is only legal for moving, not for trimming // Also, we only move the clips on the same track type that the drag started from if (ghost->Track().type() == drag_track_type_) { ghost->SetTrackAdjustment(track_movement); const TrackReference& track = ghost->GetAdjustedTrack(); ghost->SetYCoords(parent()->GetTrackY(track), parent()->GetTrackHeight(track)); } break; } } } // Regenerate tooltip and force it to update (otherwise the tooltip won't move as written in the // documentation, and could get in the way of the cursor) QToolTip::hideText(); QToolTip::showText(QCursor::pos(), Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, parent()->GetToolTipTimebase()), parent()->GetToolTipTimebase(), Core::instance()->GetTimecodeDisplay(), true), parent()); } Timeline::MovementMode TimelineWidget::PointerTool::IsCursorInTrimHandle(TimelineViewBlockItem *block, qreal cursor_x) { double kTrimHandle = QFontMetricsWidth(parent()->fontMetrics(), "H"); // Block is too narrow, no trimming allowed if (block->rect().width() <= kTrimHandle * 2) { return Timeline::kNone; } if (trimming_allowed_ && cursor_x <= block->x() + kTrimHandle) { return Timeline::kTrimIn; } else if (trimming_allowed_ && cursor_x >= block->x() + block->rect().right() - kTrimHandle) { return Timeline::kTrimOut; } else { return Timeline::kNone; } } void TimelineWidget::PointerTool::InitiateDrag(TimelineViewBlockItem* clicked_item, Timeline::MovementMode trim_mode) { // Get list of selected blocks QList clips = parent()->GetSelectedBlocks(); if (trim_mode == Timeline::kMove) { // Create ghosts for moving foreach (TimelineViewBlockItem* clip_item, clips) { // Gaps are not allowed to move, so we ignore those here if (clip_item->block()->type() == Block::kGap) { continue; } AddGhostFromBlock(clip_item->block(), clip_item->Track(), trim_mode); } } else { // "Multi-trim" is trimming a clip on more than one track. Only the earliest (for in trimming) // or latest (for out trimming) clip on each track can be trimmed. Therefore, it's only enabled // if the clicked item is the earliest/latest on its track. bool multitrim_enabled = IsClipTrimmable(clicked_item, clips, trim_mode); // Create ghosts for trimming foreach (TimelineViewBlockItem* clip_item, clips) { if (clip_item != clicked_item && (!multitrim_enabled || !IsClipTrimmable(clip_item, clips, trim_mode))) { // Either multitrim is disabled or this clip is NOT the earliest/latest in its track. We // won't include it. continue; } Block* block = clip_item->block(); Timeline::MovementMode block_mode = trim_mode; // Some tools interpret "gap trimming" as equivalent to resizing the adjacent block. In that // scenario, we include the adjacent block instead. if (block->type() == Block::kGap && !gap_trimming_allowed_) { block = (trim_mode == Timeline::kTrimIn) ? block->previous() : block->next(); block_mode = FlipTrimMode(trim_mode); // If there's no adjacent block, do nothing here if (!block) { continue; } } // Create ghost for this block AddGhostFromBlock(block, clip_item->Track(), block_mode); } } } TimelineViewGhostItem* TimelineWidget::PointerTool::AddGhostFromBlock(Block* block, const TrackReference& track, Timeline::MovementMode mode) { TimelineViewGhostItem* ghost = TimelineViewGhostItem::FromBlock(block, track, parent()->GetTrackY(track), parent()->GetTrackHeight(track)); AddGhostInternal(ghost, mode); return ghost; } TimelineViewGhostItem* TimelineWidget::PointerTool::AddGhostFromNull(const rational &in, const rational &out, const TrackReference& track, Timeline::MovementMode mode) { TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); ghost->SetIn(in); ghost->SetOut(out); ghost->SetTrack(track); ghost->SetYCoords(parent()->GetTrackY(track), parent()->GetTrackHeight(track)); AddGhostInternal(ghost, mode); return ghost; } void TimelineWidget::PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost, Timeline::MovementMode mode) { ghost->SetMode(mode); // Prepare snap points (optimizes snapping for later) switch (mode) { case Timeline::kMove: snap_points_.append(ghost->In()); snap_points_.append(ghost->Out()); break; case Timeline::kTrimIn: snap_points_.append(ghost->In()); break; case Timeline::kTrimOut: snap_points_.append(ghost->Out()); break; default: break; } parent()->AddGhost(ghost); } bool TimelineWidget::PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip, const QList& items, const Timeline::MovementMode& mode) { foreach (TimelineViewBlockItem* compare, items) { if (clip->Track() == compare->Track() && clip != compare && ((compare->block()->in() < clip->block()->in() && mode == Timeline::kTrimIn) || (compare->block()->out() > clip->block()->out() && mode == Timeline::kTrimOut))) { return false; } } return true; } rational TimelineWidget::PointerTool::ValidateInTrimming(rational movement, const QVector ghosts, bool prevent_overwriting) { foreach (TimelineViewGhostItem* ghost, ghosts) { if (ghost->mode() != Timeline::kTrimIn) { continue; } Block* block = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); rational earliest_in = RATIONAL_MIN; rational latest_in = ghost->Out(); if (!ghost->CanHaveZeroLength()) { latest_in -= parent()->timebase(); } if (block) { /* FIXME: Rewrite transition logic if (block->type() == Block::kTransition) { // For transitions, validate with the attached block TransitionBlock* transition = static_cast(block); if (transition->connected_in_block() && transition->connected_out_block()) { // Here, we try to get the latest earliest point for both the in and out blocks, we do in here and out will // be calculated later earliest_in = GetEarliestPointForClip(transition->connected_in_block()); // We set the block to the out block since that will be before the in block and will be the one we use to // prevent overwriting since we're trimming the in side of this transition block = transition->connected_out_block(); latest_in = transition->in() + transition->out_offset(); } else { // Use whatever block is attached block = transition->connected_in_block() ? transition->connected_in_block() : transition->connected_out_block(); } } */ if (prevent_overwriting) { // Look for a Block in the way Block* prev = block->previous(); while (prev != nullptr) { if (prev->type() == Block::kClip) { earliest_in = qMax(earliest_in, prev->out()); break; } prev = prev->previous(); } // Limit in point at 0 on the timeline earliest_in = qMax(rational(), earliest_in); } } // Clamp adjusted value between the earliest and latest values rational adjusted = ghost->In() + movement; rational clamped = clamp(adjusted, earliest_in, latest_in); if (clamped != adjusted) { movement = clamped - ghost->In(); } } return movement; } rational TimelineWidget::PointerTool::ValidateOutTrimming(rational movement, const QVector ghosts, bool prevent_overwriting) { foreach (TimelineViewGhostItem* ghost, ghosts) { if (ghost->mode() != Timeline::kTrimOut) { continue; } Block* block = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); // Determine earliest and latest out points rational earliest_out = ghost->In(); if (!ghost->CanHaveZeroLength()) { earliest_out += parent()->timebase(); } rational latest_out = RATIONAL_MAX; // Ripple tool creates block-less ghosts and creates gaps with them later if (block) { /* FIXME: Rewrite transition logic if (block->type() == Block::kTransition) { // For transitions, validate with the attached block TransitionBlock* transition = static_cast(block); if (transition->connected_in_block() && transition->connected_out_block()) { // We set the block to the out block since that will be before the in block and will be the one we use to // prevent overwriting since we're trimming the in side of this transition // FIXME: At some point we may add some better logic to `latest_out` akin to the logic in ValidateInTrimming // which is why this hasn't yet been collapsed into the ternary below. block = transition->connected_in_block(); earliest_out = transition->out() - transition->in_offset(); } else { block = transition->connected_in_block() ? transition->connected_in_block() : transition->connected_out_block(); } } */ if (prevent_overwriting) { // Determine if there's a block in the way Block* next = block->next(); while (next != nullptr) { if (next->type() == Block::kClip) { latest_out = qMin(latest_out, next->in()); break; } next = next->next(); } } } // Clamp adjusted value between the earliest and latest values rational adjusted = ghost->Out() + movement; rational clamped = clamp(adjusted, earliest_out, latest_out); if (clamped != adjusted) { movement = clamped - ghost->Out(); } } return movement; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/razor.cpp000066400000000000000000000050251370472574300243110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" OLIVE_NAMESPACE_ENTER TimelineWidget::RazorTool::RazorTool(TimelineWidget* parent) : BeamTool(parent) { } void TimelineWidget::RazorTool::MousePress(TimelineViewMouseEvent *event) { split_tracks_.clear(); MouseMove(event); } void TimelineWidget::RazorTool::MouseMove(TimelineViewMouseEvent *event) { if (!dragging_) { drag_start_ = ValidatedCoordinate(event->GetCoordinates(true)); dragging_ = true; } // Split at the current cursor track TrackReference split_track = event->GetTrack(); if (!split_tracks_.contains(split_track)) { split_tracks_.append(split_track); } } void TimelineWidget::RazorTool::MouseRelease(TimelineViewMouseEvent *event) { Q_UNUSED(event) // Always split at the same time rational split_time = drag_start_.GetFrame(); QVector blocks_to_split; foreach (const TrackReference& track_ref, split_tracks_) { TrackOutput* track = parent()->GetTrackFromReference(track_ref); if (track == nullptr || track->IsLocked()) { continue; } Block* block_at_time = track->NearestBlockBefore(split_time); // Ensure there's a valid block here if (block_at_time && block_at_time->type() == Block::kClip && !blocks_to_split.contains(block_at_time)) { blocks_to_split.append(block_at_time); // Add links if no alt is held if (!(event->GetModifiers() & Qt::AltModifier)) { foreach (Block* link, block_at_time->linked_clips()) { if (!blocks_to_split.contains(link)) { blocks_to_split.append(link); } } } } } split_tracks_.clear(); if (!blocks_to_split.isEmpty()) { Core::instance()->undo_stack()->push(new BlockSplitPreservingLinksCommand(blocks_to_split, {split_time})); } dragging_ = false; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/ripple.cpp000066400000000000000000000115451370472574300244530ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include "node/block/gap/gap.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::RippleTool::RippleTool(TimelineWidget* parent) : PointerTool(parent) { SetMovementAllowed(false); SetTrimOverwriteAllowed(true); SetGapTrimmingAllowed(true); } void TimelineWidget::RippleTool::InitiateDrag(TimelineViewBlockItem *clicked_item, Timeline::MovementMode trim_mode) { PointerTool::InitiateDrag(clicked_item, trim_mode); if (parent()->ghost_items_.isEmpty()) { return; } // Find the earliest ripple rational earliest_ripple = RATIONAL_MAX; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { rational ghost_ripple_point; if (trim_mode == Timeline::kTrimIn) { ghost_ripple_point = ghost->In(); } else { ghost_ripple_point = ghost->Out(); } earliest_ripple = qMin(earliest_ripple, ghost_ripple_point); } // For each track that does NOT have a ghost, we need to make one for Gaps foreach (TrackOutput* track, parent()->GetConnectedNode()->GetTracks()) { if (track->IsLocked()) { continue; } // Determine if we've already created a ghost on this track bool ghost_on_this_track_exists = false; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { if (parent()->GetTrackFromReference(ghost->Track()) == track) { ghost_on_this_track_exists = true; break; } } // If there's no ghost on this track, create one if (!ghost_on_this_track_exists) { // Find the block that starts just before the ripple point, and ends either on or just after it Block* block_before_ripple = track->NearestBlockBefore(earliest_ripple); // If block is null, there will be no blocks after to ripple if (block_before_ripple) { TimelineViewGhostItem* ghost; TrackReference track_ref(track->track_type(), track->Index()); if (block_before_ripple->type() == Block::kGap) { // If this Block is already a Gap, ghost it now ghost = AddGhostFromBlock(block_before_ripple, track_ref, trim_mode); } else if (block_before_ripple->next()) { // Assuming this block is NOT at the end of the track (i.e. next != null) // We're going to create a gap after it. If next is a gap, we can just use that if (block_before_ripple->next()->type() == Block::kGap) { ghost = AddGhostFromBlock(block_before_ripple->next(), track_ref, trim_mode); } else { // If next is NOT a gap, we'll need to create one, for which we'll use a null ghost ghost = AddGhostFromNull(block_before_ripple->out(), block_before_ripple->out(), track_ref, trim_mode); ghost->setData(TimelineViewGhostItem::kReferenceBlock, Node::PtrToValue(block_before_ripple)); } } } } } } void TimelineWidget::RippleTool::FinishDrag(TimelineViewMouseEvent *event) { Q_UNUSED(event) QVector< QList > info_list(Timeline::kTrackTypeCount); foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { TrackOutput* track = parent()->GetTrackFromReference(ghost->Track()); TrackListRippleToolCommand::RippleInfo i = {Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)), Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kReferenceBlock)), track, ghost->AdjustedLength(), ghost->Length()}; info_list[track->track_type()].append(i); } QUndoCommand* command = new QUndoCommand(); for (int i=0;iGetConnectedNode()->track_list(static_cast(i)), info_list.at(i), drag_movement_mode(), command); } Core::instance()->undo_stack()->pushIfHasChildren(command); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/rolling.cpp000066400000000000000000000053151370472574300246240ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include "node/block/gap/gap.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::RollingTool::RollingTool(TimelineWidget* parent) : PointerTool(parent) { SetMovementAllowed(false); SetTrimOverwriteAllowed(true); SetGapTrimmingAllowed(true); } void TimelineWidget::RollingTool::InitiateDrag(TimelineViewBlockItem *clicked_item, Timeline::MovementMode trim_mode) { PointerTool::InitiateDrag(clicked_item, trim_mode); // For each ghost, we make an equivalent Ghost on the next/previous block foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { Block* ghost_block = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); if (ghost->mode() == Timeline::kTrimIn && ghost_block->previous()) { // Add an extra Ghost for the previous block AddGhostFromBlock(ghost_block->previous(), ghost->Track(), Timeline::kTrimOut); } else if (ghost->mode() == Timeline::kTrimOut && ghost_block->next()) { AddGhostFromBlock(ghost_block->next(), ghost->Track(), Timeline::kTrimIn); } } } void TimelineWidget::RollingTool::FinishDrag(TimelineViewMouseEvent *event) { QUndoCommand* command = new QUndoCommand(); // Find earliest point to ripple around foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { if (ghost->mode() == drag_movement_mode()) { Block* b = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); BlockTrimCommand* c = new BlockTrimCommand(parent()->GetTrackFromReference(ghost->Track()), b, ghost->AdjustedLength(), drag_movement_mode(), command); c->SetAllowNonGapTrimming(true); } } Core::instance()->undo_stack()->pushIfHasChildren(command); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/slide.cpp000066400000000000000000000076531370472574300242650ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include "node/block/gap/gap.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::SlideTool::SlideTool(TimelineWidget* parent) : PointerTool(parent) { SetTrimmingAllowed(false); SetTrackMovementAllowed(false); SetTrimOverwriteAllowed(true); SetGapTrimmingAllowed(true); } struct TrackBlockListPair { TrackReference track; QList blocks; }; void TimelineWidget::SlideTool::InitiateDrag(TimelineViewBlockItem *clicked_item, Timeline::MovementMode trim_mode) { PointerTool::InitiateDrag(clicked_item, trim_mode); // Sort blocks into tracks QList blocks_per_track; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { Block* b = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); bool found = false; for (int i=0;iTrack()) { blocks_per_track[i].blocks.append(b); found = true; break; } } if (!found) { blocks_per_track.append({ghost->Track(), {b}}); } } // Make contiguous runs of blocks per each track foreach (const TrackBlockListPair& p, blocks_per_track) { // Blocks must be merged if any are non-adjacent const TrackReference& track = p.track; const QList& blocks = p.blocks; Block* earliest_block = blocks.first(); Block* latest_block = blocks.first(); // Find the earliest and latest selected blocks for (int j=1;jin() < earliest_block->in()) { earliest_block = compare; } if (compare->in() > latest_block->in()) { latest_block = compare; } } // Add any blocks between these blocks that aren't already in the list if (earliest_block != latest_block) { Block* b = earliest_block; while ((b = b->next()) != latest_block) { if (!blocks.contains(b)) { AddGhostFromBlock(b, track, Timeline::kMove); } } } // Add surrounding blocks that will be trimming instead of moving if (earliest_block->previous()) { AddGhostFromBlock(earliest_block->previous(), track, Timeline::kTrimOut); } if (latest_block->next()) { AddGhostFromBlock(latest_block->next(), track, Timeline::kTrimIn); } } } void TimelineWidget::SlideTool::FinishDrag(TimelineViewMouseEvent *event) { Q_UNUSED(event) QVector info; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { if (!ghost->HasBeenAdjusted()) { continue; } Block* b = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); info.append({parent()->GetTrackFromReference(ghost->Track()), b, ghost->mode(), ghost->mode() == Timeline::kMove ? ghost->GetAdjustedIn() : ghost->AdjustedLength(), ghost->mode() == Timeline::kMove ? ghost->In() : ghost->Length()}); } if (!info.isEmpty()) { Core::instance()->undo_stack()->push(new TrackSlideCommand(info)); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/slip.cpp000066400000000000000000000053361370472574300241300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include #include "common/timecodefunctions.h" #include "config/config.h" OLIVE_NAMESPACE_ENTER TimelineWidget::SlipTool::SlipTool(TimelineWidget *parent) : PointerTool(parent) { SetTrimmingAllowed(false); SetTrackMovementAllowed(false); } void TimelineWidget::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) { // Determine frame movement rational time_movement = drag_start_.GetFrame() - mouse_pos.GetFrame(); // Validate slip (enforce all ghosts moving in legal ways) foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { if (ghost->MediaIn() + time_movement < 0) { time_movement = -ghost->MediaIn(); } } // Perform slip foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { ghost->SetMediaInAdjustment(time_movement); } // Generate tooltip and force it to to update (otherwise the tooltip won't move as written in the // documentation, and could get in the way of the cursor) QToolTip::hideText(); QToolTip::showText(QCursor::pos(), Timecode::timestamp_to_timecode(Timecode::time_to_timestamp(time_movement, parent()->GetToolTipTimebase()), parent()->GetToolTipTimebase(), Core::instance()->GetTimecodeDisplay(), true), parent()); } void TimelineWidget::SlipTool::FinishDrag(TimelineViewMouseEvent *event) { Q_UNUSED(event) QUndoCommand* command = new QUndoCommand(); // Find earliest point to ripple around foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { Block* b = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); new BlockSetMediaInCommand(b, ghost->GetAdjustedMediaIn(), command); } Core::instance()->undo_stack()->pushIfHasChildren(command); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/tool.cpp000066400000000000000000000101111370472574300241210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include "node/block/transition/transition.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::Tool::Tool(TimelineWidget *parent) : dragging_(false), parent_(parent) { } TimelineWidget::Tool::~Tool() { } TimelineWidget *TimelineWidget::Tool::parent() { return parent_; } Timeline::MovementMode TimelineWidget::Tool::FlipTrimMode(const Timeline::MovementMode &trim_mode) { if (trim_mode == Timeline::kTrimIn) { return Timeline::kTrimOut; } if (trim_mode == Timeline::kTrimOut) { return Timeline::kTrimIn; } return trim_mode; } TimelineViewBlockItem *TimelineWidget::Tool::GetItemAtScenePos(const TimelineCoordinate& coord) { QMapIterator iterator(parent()->block_items_); while (iterator.hasNext()) { iterator.next(); Block* b = iterator.key(); TimelineViewBlockItem* item = iterator.value(); if (b->in() <= coord.GetFrame() && b->out() > coord.GetFrame() && item->Track() == coord.GetTrack()) { return item; } } return nullptr; } rational TimelineWidget::Tool::ValidateTimeMovement(rational movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { if (ghost->mode() != Timeline::kMove) { continue; } Block* block = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kAttachedBlock)); if (block && block->type() == Block::kTransition) { TransitionBlock* transition = static_cast(block); // Dual transitions are only allowed to move so that neither of their offsets are < 0 if (transition->connected_in_block() && transition->connected_out_block()) { if (movement > transition->out_offset()) { movement = transition->out_offset(); } if (movement < -transition->in_offset()) { movement = -transition->in_offset(); } } } // Prevents any ghosts from going below 0:00:00 time if (ghost->In() + movement < 0) { movement = -ghost->In(); } } return movement; } int TimelineWidget::Tool::ValidateTrackMovement(int movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { if (ghost->mode() != Timeline::kMove) { continue; } if (!ghost->CanMoveTracks()) { movement = 0; } else if (ghost->Track().index() + movement < 0) { // Prevents any ghosts from going to a non-existent negative track movement = -ghost->Track().index(); } } return movement; } void TimelineWidget::Tool::GetGhostData(const QVector &ghosts, rational *earliest_point, rational *latest_point) { rational ep = RATIONAL_MAX; rational lp = RATIONAL_MIN; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { ep = qMin(ep, ghost->GetAdjustedIn()); lp = qMax(lp, ghost->GetAdjustedOut()); } if (earliest_point) { *earliest_point = ep; } if (latest_point) { *latest_point = lp; } } void TimelineWidget::Tool::InsertGapsAtGhostDestination(const QVector &ghosts, QUndoCommand *command) { rational earliest_point, latest_point; GetGhostData(ghosts, &earliest_point, &latest_point); parent()->InsertGapsAt(earliest_point, latest_point - earliest_point, command); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/transition.cpp000066400000000000000000000144561370472574300253560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" #include "node/block/transition/crossdissolve/crossdissolvetransition.h" #include "node/block/transition/transition.h" #include "node/factory.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER TimelineWidget::TransitionTool::TransitionTool(TimelineWidget *parent) : AddTool(parent) { } void TimelineWidget::TransitionTool::MousePress(TimelineViewMouseEvent *event) { const TrackReference& track = event->GetTrack(); TrackOutput* t = parent()->GetTrackFromReference(track); rational cursor_frame = event->GetFrame(); if (!t || t->IsLocked()) { return; } Block* block_at_time = t->BlockAtTime(event->GetFrame()); if (!block_at_time || block_at_time->type() != Block::kClip) { return; } // Determine which side of the clip the transition belongs to rational transition_start_point; Timeline::MovementMode trim_mode; rational halfway_point = block_at_time->in() + block_at_time->length() / 2; rational tenth_point = block_at_time->in() + block_at_time->length() / 10; Block* other_block = nullptr; if (cursor_frame < halfway_point) { transition_start_point = block_at_time->in(); trim_mode = Timeline::kTrimIn; if (cursor_frame < tenth_point && block_at_time->previous() && block_at_time->previous()->type() == Block::kClip) { other_block = block_at_time->previous(); } } else { transition_start_point = block_at_time->out(); trim_mode = Timeline::kTrimOut; dual_transition_ = (cursor_frame > block_at_time->length() - tenth_point); if (cursor_frame > block_at_time->length() - tenth_point && block_at_time->next() && block_at_time->next()->type() == Block::kClip) { other_block = block_at_time->next(); } } // Create ghost ghost_ = new TimelineViewGhostItem(); ghost_->SetTrack(track); ghost_->SetYCoords(parent()->GetTrackY(track), parent()->GetTrackHeight(track)); ghost_->SetIn(transition_start_point); ghost_->SetOut(transition_start_point); ghost_->SetMode(trim_mode); ghost_->setData(TimelineViewGhostItem::kAttachedBlock, Node::PtrToValue(block_at_time)); dual_transition_ = (other_block); if (other_block) ghost_->setData(TimelineViewGhostItem::kReferenceBlock, Node::PtrToValue(other_block)); parent()->AddGhost(ghost_); snap_points_.append(transition_start_point); // Set the drag start point drag_start_point_ = cursor_frame; } void TimelineWidget::TransitionTool::MouseMove(TimelineViewMouseEvent *event) { if (!ghost_) { return; } MouseMoveInternal(event->GetFrame(), dual_transition_); } void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event) { MouseMove(event); const TrackReference& track = ghost_->Track(); if (ghost_) { if (!ghost_->AdjustedLength().isNull()) { TransitionBlock* transition; if (Core::instance()->GetSelectedTransition().isEmpty()) { // Fallback if the user hasn't selected one yet transition = new CrossDissolveTransition(); } else { transition = static_cast(NodeFactory::CreateFromID(Core::instance()->GetSelectedTransition())); } QUndoCommand* command = new QUndoCommand(); // Place transition in place new NodeAddCommand(static_cast(parent()->GetConnectedNode()->parent()), transition, command); new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track.type()), track.index(), transition, ghost_->GetAdjustedIn(), command); if (dual_transition_) { transition->set_length_and_media_out(ghost_->AdjustedLength()); transition->set_media_in(-ghost_->AdjustedLength()/2); // Block mouse is hovering over Block* active_block = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kAttachedBlock)); // Block mouse is next to Block* friend_block = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kReferenceBlock)); // Use ghost mode to determine which block is which Block* out_block = (ghost_->mode() == Timeline::kTrimIn) ? friend_block : active_block; Block* in_block = (ghost_->mode() == Timeline::kTrimIn) ? active_block : friend_block; // Connect block to transition new NodeEdgeAddCommand(out_block->output(), transition->out_block_input(), command); new NodeEdgeAddCommand(in_block->output(), transition->in_block_input(), command); } else { Block* block_to_transition = Node::ValueToPtr(ghost_->data(TimelineViewGhostItem::kAttachedBlock)); NodeInput* transition_input_to_connect; if (ghost_->mode() == Timeline::kTrimIn) { transition->set_length_and_media_out(ghost_->AdjustedLength()); transition_input_to_connect = transition->in_block_input(); } else { transition->set_length_and_media_out(ghost_->AdjustedLength()); transition_input_to_connect = transition->out_block_input(); } // Connect block to transition new NodeEdgeAddCommand(block_to_transition->output(), transition_input_to_connect, command); } Core::instance()->undo_stack()->push(command); } parent()->ClearGhosts(); snap_points_.clear(); ghost_ = nullptr; } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/tool/zoom.cpp000066400000000000000000000057341370472574300241470ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "widget/timelinewidget/timelinewidget.h" OLIVE_NAMESPACE_ENTER TimelineWidget::ZoomTool::ZoomTool(TimelineWidget *parent) : Tool(parent) { } void TimelineWidget::ZoomTool::MousePress(TimelineViewMouseEvent *event) { Q_UNUSED(event) } void TimelineWidget::ZoomTool::MouseMove(TimelineViewMouseEvent *event) { Q_UNUSED(event) if (dragging_) { parent()->MoveRubberBandSelect(false, false); } else { parent()->StartRubberBandSelect(false, false); dragging_ = true; } } void TimelineWidget::ZoomTool::MouseRelease(TimelineViewMouseEvent *event) { if (dragging_) { // Zoom into the rubberband selection QRect screen_coords = parent()->rubberband_.geometry(); parent()->EndRubberBandSelect(false, false); TimelineView* reference_view = parent()->views_.first()->view(); QPointF scene_topleft = reference_view->mapToScene(reference_view->mapFrom(parent(), screen_coords.topLeft())); QPointF scene_bottomright = reference_view->mapToScene(reference_view->mapFrom(parent(), screen_coords.bottomRight())); double scene_left = scene_topleft.x(); double scene_right = scene_bottomright.x(); // Normalize scale to 1.0 scale double scene_width = (scene_right - scene_left) / parent()->GetScale(); double new_scale = qMin(TimelineViewBase::kMaximumScale, static_cast(reference_view->viewport()->width()) / scene_width); parent()->deferred_scroll_value_ = qMax(0, qRound(scene_left / parent()->GetScale() * new_scale)); parent()->SetScale(new_scale); dragging_ = false; } else { // Simple zoom in/out at the cursor position double scale = parent()->GetScale(); if (event->GetModifiers() & Qt::AltModifier) { // Zoom out if the user clicks while holding Alt scale *= 0.5; } else { // Otherwise zoom in scale *= 2.0; } parent()->SetScale(scale); // Adjust scroll location for new scale double frame_x = event->GetFrame().toDouble() * scale; parent()->deferred_scroll_value_ = qMax(0, qRound(frame_x - parent()->views_.first()->view()->viewport()->width()/2)); } // (using a hacky singleShot so the scroll occurs after the scene and its scrollbars have updated) QTimer::singleShot(0, parent(), &TimelineWidget::DeferredScrollAction); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/trackview/000077500000000000000000000000001370472574300234705ustar00rootroot00000000000000olive-continuous/app/widget/timelinewidget/trackview/CMakeLists.txt000066400000000000000000000020471370472574300262330ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timelinewidget/trackview/trackview.h widget/timelinewidget/trackview/trackview.cpp widget/timelinewidget/trackview/trackviewitem.h widget/timelinewidget/trackview/trackviewitem.cpp widget/timelinewidget/trackview/trackviewsplitter.h widget/timelinewidget/trackview/trackviewsplitter.cpp PARENT_SCOPE ) olive-continuous/app/widget/timelinewidget/trackview/trackview.cpp000066400000000000000000000072531370472574300262020ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "trackview.h" #include #include #include #include #include #include "trackviewitem.h" OLIVE_NAMESPACE_ENTER TrackView::TrackView(Qt::Alignment vertical_alignment, QWidget *parent) : QScrollArea(parent), list_(nullptr), alignment_(vertical_alignment) { setAlignment(Qt::AlignLeft | alignment_); QWidget* central = new QWidget(); setWidget(central); setWidgetResizable(true); QVBoxLayout* layout = new QVBoxLayout(central); layout->setMargin(0); layout->setSpacing(0); if (alignment_ == Qt::AlignBottom) { layout->addStretch(); connect(verticalScrollBar(), &QScrollBar::rangeChanged, this, &TrackView::ScrollbarRangeChanged); last_scrollbar_max_ = verticalScrollBar()->maximum(); } splitter_ = new TrackViewSplitter(alignment_); splitter_->setChildrenCollapsible(false); layout->addWidget(splitter_); if (alignment_ == Qt::AlignTop) { layout->addStretch(); } connect(splitter_, &TrackViewSplitter::TrackHeightChanged, this, &TrackView::TrackHeightChanged); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } void TrackView::ConnectTrackList(TrackList *list) { if (list_ != nullptr) { foreach (TrackViewItem* item, items_) { delete item; } items_.clear(); disconnect(list_, &TrackList::TrackHeightChanged, splitter_, &TrackViewSplitter::SetTrackHeight); disconnect(list_, &TrackList::TrackAdded, this, &TrackView::InsertTrack); disconnect(list_, &TrackList::TrackRemoved, this, &TrackView::RemoveTrack); } list_ = list; if (list_ != nullptr) { foreach (TrackOutput* track, list_->GetTracks()) { TrackViewItem* item = new TrackViewItem(track); items_.append(item); splitter_->Insert(track->Index(), track->GetTrackHeight(), item); } connect(list_, &TrackList::TrackHeightChanged, splitter_, &TrackViewSplitter::SetTrackHeight); connect(list_, &TrackList::TrackAdded, this, &TrackView::InsertTrack); connect(list_, &TrackList::TrackRemoved, this, &TrackView::RemoveTrack); } } void TrackView::DisconnectTrackList() { ConnectTrackList(nullptr); } void TrackView::resizeEvent(QResizeEvent *e) { QScrollArea::resizeEvent(e); splitter_->SetSpacerHeight(height()/2); } void TrackView::ScrollbarRangeChanged(int, int max) { if (max != last_scrollbar_max_) { int ba_val = last_scrollbar_max_ - verticalScrollBar()->value(); int new_val = max - ba_val; verticalScrollBar()->setValue(new_val); emit verticalScrollBar()->valueChanged(new_val); last_scrollbar_max_ = max; } } void TrackView::TrackHeightChanged(int index, int height) { list_->GetTrackAt(index)->SetTrackHeight(height); } void TrackView::InsertTrack(TrackOutput *track) { splitter_->Insert(track->Index(), track->GetTrackHeight(), new TrackViewItem(track)); } void TrackView::RemoveTrack(TrackOutput *track) { splitter_->Remove(track->Index()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/trackview/trackview.h000066400000000000000000000031221370472574300256360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRACKVIEW_H #define TRACKVIEW_H #include #include #include "node/output/track/tracklist.h" #include "trackviewitem.h" #include "trackviewsplitter.h" OLIVE_NAMESPACE_ENTER class TrackView : public QScrollArea { Q_OBJECT public: TrackView(Qt::Alignment vertical_alignment = Qt::AlignTop, QWidget* parent = nullptr); void ConnectTrackList(TrackList* list); void DisconnectTrackList(); protected: virtual void resizeEvent(QResizeEvent *e) override; private: QList items_; TrackList* list_; TrackViewSplitter* splitter_; Qt::Alignment alignment_; int last_scrollbar_max_; private slots: void ScrollbarRangeChanged(int min, int max); void TrackHeightChanged(int index, int height); void InsertTrack(TrackOutput* track); void RemoveTrack(TrackOutput* track); }; OLIVE_NAMESPACE_EXIT #endif // TRACKVIEW_H olive-continuous/app/widget/timelinewidget/trackview/trackviewitem.cpp000066400000000000000000000061711370472574300270570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "trackviewitem.h" #include #include #include #include #include OLIVE_NAMESPACE_ENTER TrackViewItem::TrackViewItem(TrackOutput* track, QWidget *parent) : QWidget(parent), track_(track) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); stack_ = new QStackedWidget(); layout->addWidget(stack_); label_ = new ClickableLabel(track_->GetTrackName()); connect(label_, SIGNAL(MouseDoubleClicked()), this, SLOT(LabelClicked())); stack_->addWidget(label_); line_edit_ = new FocusableLineEdit(); connect(line_edit_, SIGNAL(Confirmed()), this, SLOT(LineEditConfirmed())); connect(line_edit_, SIGNAL(Cancelled()), this, SLOT(LineEditCancelled())); stack_->addWidget(line_edit_); mute_button_ = CreateMSLButton(tr("M"), Qt::red); connect(mute_button_, SIGNAL(toggled(bool)), track_, SLOT(SetMuted(bool))); layout->addWidget(mute_button_); /*solo_button_ = CreateMSLButton(tr("S"), Qt::yellow); layout->addWidget(solo_button_);*/ lock_button_ = CreateMSLButton(tr("L"), Qt::gray); connect(lock_button_, SIGNAL(toggled(bool)), track_, SLOT(SetLocked(bool))); layout->addWidget(lock_button_); setMinimumHeight(mute_button_->height()); connect(track, &TrackOutput::MutedChanged, mute_button_, &QPushButton::setChecked); } QPushButton *TrackViewItem::CreateMSLButton(const QString& text, const QColor& checked_color) const { QPushButton* button = new QPushButton(text); button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); button->setCheckable(true); button->setStyleSheet(QStringLiteral("QPushButton::checked { background: %1; }").arg(checked_color.name())); int size = button->sizeHint().height(); size = qRound(size * 0.75); button->setFixedSize(size, size); return button; } void TrackViewItem::LabelClicked() { stack_->setCurrentWidget(line_edit_); line_edit_->setFocus(); line_edit_->selectAll(); } void TrackViewItem::LineEditConfirmed() { line_edit_->blockSignals(true); QString line_edit_str = line_edit_->text(); if (!line_edit_str.isEmpty()) { label_->setText(line_edit_str); track_->SetTrackName(line_edit_str); } stack_->setCurrentWidget(label_); line_edit_->blockSignals(false); } void TrackViewItem::LineEditCancelled() { line_edit_->blockSignals(true); stack_->setCurrentWidget(label_); line_edit_->blockSignals(false); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/trackview/trackviewitem.h000066400000000000000000000030561370472574300265230ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRACKVIEWITEM_H #define TRACKVIEWITEM_H #include #include #include #include "node/output/track/track.h" #include "widget/clickablelabel/clickablelabel.h" #include "widget/focusablelineedit/focusablelineedit.h" OLIVE_NAMESPACE_ENTER class TrackViewItem : public QWidget { Q_OBJECT public: TrackViewItem(TrackOutput* track, QWidget* parent = nullptr); private: QPushButton* CreateMSLButton(const QString &text, const QColor &checked_color) const; QStackedWidget* stack_; ClickableLabel* label_; FocusableLineEdit* line_edit_; QPushButton* mute_button_; QPushButton* solo_button_; QPushButton* lock_button_; TrackOutput* track_; private slots: void LabelClicked(); void LineEditConfirmed(); void LineEditCancelled(); }; OLIVE_NAMESPACE_EXIT #endif // TRACKVIEWITEM_H olive-continuous/app/widget/timelinewidget/trackview/trackviewsplitter.cpp000066400000000000000000000104031370472574300277600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "trackviewsplitter.h" #include #include #include "node/output/track/track.h" OLIVE_NAMESPACE_ENTER TrackViewSplitter::TrackViewSplitter(Qt::Alignment vertical_alignment, QWidget* parent) : QSplitter(Qt::Vertical, parent), alignment_(vertical_alignment), spacer_height_(0) { setHandleWidth(1); int initial_height = 0; // Add empty spacer so we get a splitter handle after the last element QWidget* spacer = new QWidget(); addWidget(spacer); setFixedHeight(initial_height); } void TrackViewSplitter::HandleReceiver(TrackViewSplitterHandle *h, int diff) { int ele_id = -1; for (int i=0;i element_sizes = sizes(); int old_ele_sz = element_sizes.at(ele_id); // Transform element size by diff int new_ele_sz = old_ele_sz + diff; // Limit by track minimum height new_ele_sz = qMax(new_ele_sz, TrackOutput::GetTrackHeightMinimum()); if (alignment_ == Qt::AlignBottom) { ele_id = count() - ele_id - 1; } SetTrackHeight(ele_id, new_ele_sz); emit TrackHeightChanged(ele_id, new_ele_sz); } void TrackViewSplitter::SetTrackHeight(int index, int h) { QList element_sizes = sizes(); if (alignment_ == Qt::AlignBottom) { index = count() - index - 1; } int old_ele_sz = element_sizes.at(index); int diff = h - old_ele_sz; // Set new size on element element_sizes.replace(index, h); setSizes(element_sizes); // Increase height by the difference setFixedHeight(height() + diff); } void TrackViewSplitter::SetHeightWithSizes(QList sizes) { int start_height = 0; // Add spacer height too if (alignment_ == Qt::AlignBottom) { sizes.replace(0, spacer_height_); } else { sizes.replace(count() - 1, spacer_height_); } foreach (int s, sizes) { start_height += s + handleWidth(); } // The spacer doesn't need a handle width start_height -= handleWidth(); setFixedHeight(start_height); setSizes(sizes); } void TrackViewSplitter::Insert(int index, int height, QWidget *item) { QList sz = sizes(); if (alignment_ == Qt::AlignBottom) { index = count() - index; } sz.insert(index, height); insertWidget(index, item); SetHeightWithSizes(sz); } void TrackViewSplitter::Remove(int index) { QList sz = sizes(); if (alignment_ == Qt::AlignBottom) { index = count() - 1 - index; } sz.removeAt(index); delete widget(index); SetHeightWithSizes(sz); } void TrackViewSplitter::SetSpacerHeight(int height) { spacer_height_ = height; SetHeightWithSizes(sizes()); } QSplitterHandle *TrackViewSplitter::createHandle() { return new TrackViewSplitterHandle(orientation(), this); } TrackViewSplitterHandle::TrackViewSplitterHandle(Qt::Orientation orientation, QSplitter *parent) : QSplitterHandle(orientation, parent), dragging_(false) { } void TrackViewSplitterHandle::mousePressEvent(QMouseEvent *) { } void TrackViewSplitterHandle::mouseMoveEvent(QMouseEvent *) { if (dragging_) { static_cast(parent())->HandleReceiver(this, QCursor::pos().y() - drag_y_); } drag_y_ = QCursor::pos().y(); dragging_ = true; } void TrackViewSplitterHandle::mouseReleaseEvent(QMouseEvent *) { dragging_ = false; } void TrackViewSplitterHandle::paintEvent(QPaintEvent *) { QPainter p(this); p.fillRect(rect(), palette().base()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/trackview/trackviewsplitter.h000066400000000000000000000036331370472574300274340ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TRACKVIEWSPLITTER_H #define TRACKVIEWSPLITTER_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class TrackViewSplitterHandle : public QSplitterHandle { Q_OBJECT public: TrackViewSplitterHandle(Qt::Orientation orientation, QSplitter *parent); protected: virtual void mousePressEvent(QMouseEvent *e) override; virtual void mouseMoveEvent(QMouseEvent *e) override; virtual void mouseReleaseEvent(QMouseEvent *e) override; virtual void paintEvent(QPaintEvent *e) override; private: int drag_y_; bool dragging_; }; class TrackViewSplitter : public QSplitter { Q_OBJECT public: TrackViewSplitter(Qt::Alignment vertical_alignment, QWidget* parent = nullptr); void HandleReceiver(TrackViewSplitterHandle* h, int diff); void SetHeightWithSizes(QList sizes); void Insert(int index, int height, QWidget* item); void Remove(int index); void SetSpacerHeight(int height); public slots: void SetTrackHeight(int index, int h); signals: void TrackHeightChanged(int index, int height); protected: virtual QSplitterHandle *createHandle() override; private: Qt::Alignment alignment_; int spacer_height_; }; OLIVE_NAMESPACE_EXIT #endif // TRACKVIEWSPLITTER_H olive-continuous/app/widget/timelinewidget/undo/000077500000000000000000000000001370472574300224365ustar00rootroot00000000000000olive-continuous/app/widget/timelinewidget/undo/CMakeLists.txt000066400000000000000000000014771370472574300252070ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timelinewidget/undo/undo.h widget/timelinewidget/undo/undo.cpp PARENT_SCOPE ) olive-continuous/app/widget/timelinewidget/undo/undo.cpp000066400000000000000000001304571370472574300241210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "undo.h" #include "core.h" #include "node/block/clip/clip.h" #include "node/block/transition/transition.h" #include "node/graph.h" #include "widget/nodeview/nodeviewundo.h" OLIVE_NAMESPACE_ENTER Node* TakeNodeFromParentGraph(Node* n, QObject* new_parent = nullptr) { static_cast(n->parent())->TakeNode(n, new_parent); return n; } BlockResizeCommand::BlockResizeCommand(Block *block, rational new_length, QUndoCommand* parent) : UndoCommand(parent), block_(block), old_length_(block->length()), new_length_(new_length) { } Project *BlockResizeCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockResizeCommand::redo_internal() { block_->set_length_and_media_out(new_length_); } void BlockResizeCommand::undo_internal() { block_->set_length_and_media_out(old_length_); } BlockResizeWithMediaInCommand::BlockResizeWithMediaInCommand(Block *block, rational new_length, QUndoCommand *parent) : UndoCommand(parent), block_(block), old_length_(block->length()), new_length_(new_length) { } Project *BlockResizeWithMediaInCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockResizeWithMediaInCommand::redo_internal() { block_->set_length_and_media_in(new_length_); } void BlockResizeWithMediaInCommand::undo_internal() { block_->set_length_and_media_in(old_length_); } BlockSetMediaInCommand::BlockSetMediaInCommand(Block *block, rational new_media_in, QUndoCommand* parent) : UndoCommand(parent), block_(block), old_media_in_(block->media_in()), new_media_in_(new_media_in) { } Project *BlockSetMediaInCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockSetMediaInCommand::redo_internal() { block_->set_media_in(new_media_in_); } void BlockSetMediaInCommand::undo_internal() { block_->set_media_in(old_media_in_); } TrackRippleRemoveBlockCommand::TrackRippleRemoveBlockCommand(TrackOutput *track, Block *block, QUndoCommand *parent) : UndoCommand(parent), track_(track), block_(block) { } Project *TrackRippleRemoveBlockCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void TrackRippleRemoveBlockCommand::redo_internal() { before_ = block_->previous(); track_->RippleRemoveBlock(block_); } void TrackRippleRemoveBlockCommand::undo_internal() { if (before_) { track_->InsertBlockAfter(block_, before_); } else { track_->PrependBlock(block_); } } TrackInsertBlockAfterCommand::TrackInsertBlockAfterCommand(TrackOutput *track, Block *block, Block *before, QUndoCommand *parent) : UndoCommand(parent), track_(track), block_(block), before_(before) { } Project *TrackInsertBlockAfterCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void TrackInsertBlockAfterCommand::redo_internal() { track_->InsertBlockAfter(block_, before_); } void TrackInsertBlockAfterCommand::undo_internal() { track_->RippleRemoveBlock(block_); } TrackRippleRemoveAreaCommand::TrackRippleRemoveAreaCommand(TrackOutput *track, rational in, rational out, QUndoCommand *parent) : UndoCommand(parent), track_(track), in_(in), out_(out), splice_(false), trim_out_(nullptr), trim_in_(nullptr), insert_(nullptr) { } Project *TrackRippleRemoveAreaCommand::GetRelevantProject() const { return static_cast(track_->parent())->project(); } void TrackRippleRemoveAreaCommand::SetInsert(Block *insert) { insert_ = insert; } void TrackRippleRemoveAreaCommand::redo_internal() { // Iterate through blocks determining which need trimming/removing/splitting foreach (Block* block, track_->Blocks()) { if (block->in() < in_ && block->out() > out_) { // The area entirely within this Block trim_out_ = block; splice_ = true; // We don't need to do anything else here break; } else if (block->in() >= in_ && block->out() <= out_) { // This Block's is entirely within the area removed_blocks_.append(block); } else if (block->in() < in_ && block->out() >= in_) { // This Block's out point exceeds `in` trim_out_ = block; } else if (block->in() <= out_ && block->out() > out_) { // This Block's in point exceeds `out` trim_in_ = block; } } track_->BeginOperation(); // If we picked up a block to splice if (splice_) { // Split the block here trim_in_ = static_cast(trim_out_->copy()); static_cast(track_->parent())->AddNode(trim_in_); Node::CopyInputs(trim_out_, trim_in_); trim_out_old_length_ = trim_out_->length(); trim_out_->set_length_and_media_out(in_ - trim_out_->in()); trim_in_->set_length_and_media_in(trim_out_old_length_ - (out_ - trim_out_->in())); track_->InsertBlockAfter(trim_in_, trim_out_); } else { // If we picked up a block to trim the in point of if (trim_in_) { trim_in_old_length_ = trim_in_->length(); trim_in_new_length_ = trim_in_->out() - out_; } // If we picked up a block to trim the out point of if (trim_out_) { trim_out_old_length_ = trim_out_->length(); trim_out_new_length_ = in_ - trim_out_->in(); } // If we picked up a block to trim the in point of if (trim_in_old_length_ != trim_in_new_length_) { trim_in_->set_length_and_media_in(trim_in_new_length_); } // Remove all blocks that are flagged for removal foreach (Block* remove_block, removed_blocks_) { track_->RippleRemoveBlock(remove_block); BlockUnlinkAllCommand* unlink_command = new BlockUnlinkAllCommand(remove_block); unlink_command->redo(); remove_block_commands_.append(unlink_command); NodeRemoveWithExclusiveDeps* remove_command = new NodeRemoveWithExclusiveDeps(static_cast(remove_block->parent()), remove_block); remove_command->redo(); remove_block_commands_.append(remove_command); } // If we picked up a block to trim the out point of if (trim_out_old_length_ != trim_out_new_length_) { trim_out_->set_length_and_media_out(trim_out_new_length_); } } // If we were given a block to insert, insert it here if (insert_) { if (!trim_out_) { // This is the start of the Sequence track_->PrependBlock(insert_); } else if (!trim_in_) { // This is the end of the Sequence track_->AppendBlock(insert_); } else { // This is somewhere in the middle of the Sequence track_->InsertBlockAfter(insert_, trim_out_); } } track_->EndOperation(); track_->InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), track_->block_input(), track_->block_input()); } void TrackRippleRemoveAreaCommand::undo_internal() { track_->BeginOperation(); // If we were given a block to insert, insert it here if (insert_ != nullptr) { track_->RippleRemoveBlock(insert_); } if (splice_) { // trim_in_ is our copy and trim_out_ is our original track_->RippleRemoveBlock(trim_in_); trim_out_->set_length_and_media_out(trim_out_old_length_); delete TakeNodeFromParentGraph(trim_in_); } else { // If we picked up a block to trim the out point of if (trim_out_old_length_ != trim_out_new_length_) { trim_out_->set_length_and_media_out(trim_out_old_length_); } // Restore blocks that were removed for (int i=remove_block_commands_.size()-1;i>=0;i--) { UndoCommand* command = remove_block_commands_.at(i); command->undo(); delete command; } remove_block_commands_.clear(); for (int i=removed_blocks_.size()-1;i>=0;i--) { Block* remove_block = removed_blocks_.at(i); if (trim_in_) { track_->InsertBlockBefore(remove_block, trim_in_); } else { track_->AppendBlock(remove_block); } } removed_blocks_.clear(); // If we picked up a block to trim the in point of if (trim_in_old_length_ != trim_in_new_length_) { trim_in_->set_length_and_media_in(trim_in_old_length_); } } track_->EndOperation(); track_->InvalidateCache(TimeRange(in_, insert_ ? out_ : RATIONAL_MAX), track_->block_input(), track_->block_input()); } TrackPlaceBlockCommand::TrackPlaceBlockCommand(TrackList *timeline, int track, Block *block, rational in, QUndoCommand *parent) : TrackRippleRemoveAreaCommand(nullptr, in, 0, parent), // Out gets set correctly in redo() timeline_(timeline), track_index_(track), gap_(nullptr) { insert_ = block; } Project *TrackPlaceBlockCommand::GetRelevantProject() const { return static_cast(static_cast(timeline_->parent())->parent())->project(); } void TrackPlaceBlockCommand::redo_internal() { added_track_count_ = 0; // Get track (or make it if necessary) while (track_index_ >= timeline_->GetTracks().size()) { timeline_->AddTrack(); added_track_count_++; } track_ = timeline_->GetTrackAt(track_index_); append_ = (in_ >= track_->track_length()); // Check if the placement location is past the end of the timeline if (append_) { if (in_ > track_->track_length()) { // If so, insert a gap here gap_ = new GapBlock(); gap_->set_length_and_media_out(in_ - track_->track_length()); static_cast(track_->parent())->AddNode(gap_); track_->AppendBlock(gap_); } track_->AppendBlock(insert_); } else { out_ = in_ + insert_->length(); // Place the Block at this point TrackRippleRemoveAreaCommand::redo_internal(); } } void TrackPlaceBlockCommand::undo_internal() { if (append_) { track_->RippleRemoveBlock(insert_); if (gap_ != nullptr) { track_->RippleRemoveBlock(gap_); delete TakeNodeFromParentGraph(gap_); } } else { TrackRippleRemoveAreaCommand::undo_internal(); } for (;added_track_count_>0;added_track_count_--) { timeline_->RemoveTrack(); } } BlockSplitCommand::BlockSplitCommand(TrackOutput* track, Block *block, rational point, QUndoCommand *parent) : UndoCommand(parent), track_(track), block_(block), new_length_(point - block->in()), old_length_(block->length()), point_(point) { Q_ASSERT(point > block_->in() && point < block_->out() && block_->type() == Block::kClip); // Ensures that this block is deleted if this action is undone new_block_ = static_cast(block_->copy()); new_block_->setParent(&memory_manager_); // Determine if the block outputs to an "out" transition foreach (NodeEdgePtr edge, block_->output()->edges()) { if (edge->input()->parentNode()->IsBlock() && static_cast(edge->input()->parentNode())->type() == Block::kTransition && edge->input() == static_cast(edge->input()->parentNode())->out_block_input()) { transitions_to_move_.append(edge->input()); } } } Project *BlockSplitCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockSplitCommand::redo_internal() { track_->BeginOperation(); static_cast(block_->parent())->AddNode(new_block_); Node::CopyInputs(block_, new_block_); rational new_part_length = block_->length() - (point_ - block_->in()); block_->set_length_and_media_out(new_length_); new_block_->set_length_and_media_in(new_part_length); track_->InsertBlockAfter(new_block_, block_); foreach (NodeInput* transition, transitions_to_move_) { NodeParam::DisconnectEdge(block_->output(), transition); NodeParam::ConnectEdge(new_block_->output(), transition); } track_->EndOperation(); } void BlockSplitCommand::undo_internal() { track_->BeginOperation(); block_->set_length_and_media_out(old_length_); track_->RippleRemoveBlock(new_block_); TakeNodeFromParentGraph(new_block_, &memory_manager_); foreach (NodeInput* transition, transitions_to_move_) { NodeParam::DisconnectEdge(new_block_->output(), transition); NodeParam::ConnectEdge(block_->output(), transition); } track_->EndOperation(); } Block *BlockSplitCommand::new_block() { return new_block_; } TrackSplitAtTimeCommand::TrackSplitAtTimeCommand(TrackOutput *track, rational point, QUndoCommand *parent) : UndoCommand(parent), track_(track) { // Find Block that contains this time foreach (Block* b, track->Blocks()) { if (b->out() == point) { // This time is between blocks, no split needs to occur return; } else if (b->in() < point && b->out() > point) { // We found the Block, split it new BlockSplitCommand(track_, b, point, this); return; } } } Project *TrackSplitAtTimeCommand::GetRelevantProject() const { return static_cast(track_->parent())->project(); } TrackReplaceBlockCommand::TrackReplaceBlockCommand(TrackOutput* track, Block *old, Block *replace, QUndoCommand *parent) : UndoCommand(parent), track_(track), old_(old), replace_(replace) { } Project *TrackReplaceBlockCommand::GetRelevantProject() const { return static_cast(track_->parent())->project(); } void TrackReplaceBlockCommand::redo_internal() { track_->ReplaceBlock(old_, replace_); } void TrackReplaceBlockCommand::undo_internal() { track_->ReplaceBlock(replace_, old_); } TrackPrependBlockCommand::TrackPrependBlockCommand(TrackOutput *track, Block *block, QUndoCommand *parent) : UndoCommand(parent), track_(track), block_(block) { } Project *TrackPrependBlockCommand::GetRelevantProject() const { return static_cast(track_->parent())->project(); } void TrackPrependBlockCommand::redo_internal() { track_->PrependBlock(block_); } void TrackPrependBlockCommand::undo_internal() { track_->RippleRemoveBlock(block_); } BlockSplitPreservingLinksCommand::BlockSplitPreservingLinksCommand(const QVector &blocks, const QList ×, QUndoCommand *parent) : UndoCommand(parent), blocks_(blocks), times_(times) { QVector< QVector > split_blocks(times.size()); for (int i=0;i splits(blocks.size()); for (int j=0;jin() < time && b->out() > time) { TrackOutput* track = TrackOutput::TrackFromBlock(b); Q_ASSERT(track); BlockSplitCommand* split_command = new BlockSplitCommand(track, b, time, this); splits.replace(j, split_command->new_block()); } else { splits.replace(j, nullptr); } } split_blocks.replace(i, splits); } // Now that we've determined all the splits, we can relink everything for (int i=0;i& split_list, split_blocks) { Block::Link(split_list.at(i), split_list.at(j)); } } } } } Project *BlockSplitPreservingLinksCommand::GetRelevantProject() const { return static_cast(blocks_.first()->parent())->project(); } BlockSetSpeedCommand::BlockSetSpeedCommand(Block *block, const rational &new_speed, QUndoCommand *parent) : UndoCommand(parent), block_(block), old_speed_(block->speed()), new_speed_(new_speed) { } Project *BlockSetSpeedCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockSetSpeedCommand::redo_internal() { block_->set_speed(new_speed_); } void BlockSetSpeedCommand::undo_internal() { block_->set_speed(old_speed_); } TimelineRippleDeleteGapsAtRegionsCommand::TimelineRippleDeleteGapsAtRegionsCommand(ViewerOutput *vo, const TimeRangeList ®ions, QUndoCommand *parent) : UndoCommand(parent), timeline_(vo), regions_(regions) { } Project *TimelineRippleDeleteGapsAtRegionsCommand::GetRelevantProject() const { return static_cast(timeline_->parent())->project(); } void TimelineRippleDeleteGapsAtRegionsCommand::redo_internal() { foreach (const TimeRange& range, regions_) { rational max_ripple_length = range.length(); QList blocks_around_range; foreach (TrackOutput* track, timeline_->GetTracks()) { // Get the block from every other track that is either at or just before our block's in point Block* block_at_time = track->NearestBlockBeforeOrAt(range.in()); if (block_at_time) { if (block_at_time->type() == Block::kGap) { max_ripple_length = qMin(block_at_time->length(), max_ripple_length); } else { max_ripple_length = 0; break; } blocks_around_range.append(block_at_time); } } if (max_ripple_length > 0) { foreach (Block* resize, blocks_around_range) { if (resize->length() == max_ripple_length) { // Remove block entirely TrackRippleRemoveBlockCommand* remove_command = new TrackRippleRemoveBlockCommand(TrackOutput::TrackFromBlock(resize), resize); remove_command->redo(); commands_.append(remove_command); } else { // Resize block BlockResizeCommand* resize_command = new BlockResizeCommand(resize, resize->length() - max_ripple_length); resize_command->redo(); commands_.append(resize_command); } } } } } void TimelineRippleDeleteGapsAtRegionsCommand::undo_internal() { for (int i=commands_.size()-1;i>=0;i--) { commands_.at(i)->undo(); delete commands_.at(i); } commands_.empty(); } WorkareaSetEnabledCommand::WorkareaSetEnabledCommand(Project* project, TimelinePoints *points, bool enabled, QUndoCommand *parent) : UndoCommand(parent), project_(project), points_(points), old_enabled_(points_->workarea()->enabled()), new_enabled_(enabled) { } Project *WorkareaSetEnabledCommand::GetRelevantProject() const { return project_; } void WorkareaSetEnabledCommand::redo_internal() { points_->workarea()->set_enabled(new_enabled_); } void WorkareaSetEnabledCommand::undo_internal() { points_->workarea()->set_enabled(old_enabled_); } WorkareaSetRangeCommand::WorkareaSetRangeCommand(Project* project, TimelinePoints *points, const TimeRange &range, QUndoCommand *parent) : UndoCommand(parent), project_(project), points_(points), old_range_(points_->workarea()->range()), new_range_(range) { } Project *WorkareaSetRangeCommand::GetRelevantProject() const { return project_; } void WorkareaSetRangeCommand::redo_internal() { points_->workarea()->set_range(new_range_); } void WorkareaSetRangeCommand::undo_internal() { points_->workarea()->set_range(old_range_); } BlockLinkCommand::BlockLinkCommand(Block *a, Block *b, bool link, QUndoCommand *parent) : UndoCommand(parent), a_(a), b_(b), link_(link) { } Project *BlockLinkCommand::GetRelevantProject() const { return static_cast(a_->parent())->project(); } void BlockLinkCommand::redo_internal() { if (link_) { done_ = Block::Link(a_, b_); } else { done_ = Block::Unlink(a_, b_); } } void BlockLinkCommand::undo_internal() { if (done_) { if (link_) { Block::Unlink(a_, b_); } else { Block::Link(a_, b_); } } } BlockUnlinkAllCommand::BlockUnlinkAllCommand(Block *block, QUndoCommand *parent) : UndoCommand(parent), block_(block) { } Project *BlockUnlinkAllCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockUnlinkAllCommand::redo_internal() { unlinked_ = block_->linked_clips(); foreach (Block* link, unlinked_) { Block::Unlink(block_, link); } } void BlockUnlinkAllCommand::undo_internal() { foreach (Block* link, unlinked_) { Block::Link(block_, link); } unlinked_.clear(); } BlockLinkManyCommand::BlockLinkManyCommand(const QList blocks, bool link, QUndoCommand *parent) : UndoCommand(parent), blocks_(blocks) { foreach (Block* a, blocks_) { foreach (Block* b, blocks_) { if (a != b) { new BlockLinkCommand(a, b, link, this); } } } } Project *BlockLinkManyCommand::GetRelevantProject() const { return static_cast(blocks_.first()->parent())->project(); } BlockEnableDisableCommand::BlockEnableDisableCommand(Block *block, bool enabled, QUndoCommand *parent) : UndoCommand(parent), block_(block), old_enabled_(block_->is_enabled()), new_enabled_(enabled) { } Project *BlockEnableDisableCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockEnableDisableCommand::redo_internal() { block_->set_enabled(new_enabled_); } void BlockEnableDisableCommand::undo_internal() { block_->set_enabled(old_enabled_); } BlockTrimCommand::BlockTrimCommand(TrackOutput* track, Block *block, rational new_length, Timeline::MovementMode mode, QUndoCommand *command) : UndoCommand(command), track_(track), block_(block), old_length_(block->length()), new_length_(new_length), mode_(mode), adjacent_(nullptr), we_created_adjacent_(false), we_deleted_adjacent_(false), allow_nongap_trimming_(false) { } Project *BlockTrimCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void BlockTrimCommand::redo_internal() { track_->BeginOperation(); // Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer rational trim_diff = old_length_ - new_length_; TimeRange invalidate_range; if (mode_ == Timeline::kTrimIn) { invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff); block_->set_length_and_media_in(new_length_); adjacent_ = block_->previous(); } else { invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff); block_->set_length_and_media_out(new_length_); adjacent_ = block_->next(); } if (trim_diff > rational()) { // If trimming SHORTER, we'll need to create/modify a gap if (adjacent_ && (adjacent_->type() == Block::kGap || allow_nongap_trimming_)) { // A gap (or equivalent) exists, simply increase the size of it if (mode_ == Timeline::kTrimIn) { adjacent_->set_length_and_media_out(adjacent_->length() + trim_diff); } else { adjacent_->set_length_and_media_in(adjacent_->length() + trim_diff); } } else { // Don't create a gap if the trim was at the end of the sequence (which would be indicated by // the mode being "trim out" and "block_->next()" being null. if (mode_ == Timeline::kTrimIn || block_->next()) { // We must create a gap we_created_adjacent_ = true; adjacent_ = new GapBlock(); adjacent_->set_length_and_media_out(trim_diff); static_cast(track_->parent())->AddNode(adjacent_); if (mode_ == Timeline::kTrimIn) { track_->InsertBlockBefore(adjacent_, block_); } else { track_->InsertBlockAfter(adjacent_, block_); } } } } else { if (adjacent_) { // If trimming LONGER, we'll need to trim the adjacent // (assume if there's no adjacent, we're at the end of the timeline and do nothing) rational adjacent_length = adjacent_->length() + trim_diff; if (adjacent_length.isNull()) { // Ripple remove block track_->RippleRemoveBlock(adjacent_); TakeNodeFromParentGraph(adjacent_, &memory_manager_); we_deleted_adjacent_ = true; } else if (mode_ == Timeline::kTrimIn) { adjacent_->set_length_and_media_out(adjacent_length); } else { adjacent_->set_length_and_media_in(adjacent_length); } } } track_->EndOperation(); track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } void BlockTrimCommand::undo_internal() { track_->BeginOperation(); // Will be POSITIVE if trimming shorter and NEGATIVE if trimming longer rational trim_diff = old_length_ - new_length_; if (trim_diff > rational()) { // If trimmed SHORTER, we need to unadjust the gap if (we_created_adjacent_) { // If we created a gap, just remove it straight up track_->RippleRemoveBlock(adjacent_); delete TakeNodeFromParentGraph(adjacent_); adjacent_ = nullptr; we_created_adjacent_ = false; } else if (adjacent_) { // If we adjusted an existing gap, unadjust here adjacent_->set_length_and_media_out(adjacent_->length() - trim_diff); } } else { if (adjacent_) { // If trimmed LONGER, we adjusted an existing block // (assume if there's no adjacent, we're at the end of the timeline and do nothing) if (we_deleted_adjacent_) { static_cast(track_->parent())->AddNode(adjacent_); if (mode_ == Timeline::kTrimIn) { track_->InsertBlockBefore(adjacent_, block_); } else { track_->InsertBlockAfter(adjacent_, block_); } we_deleted_adjacent_ = false; } else if (mode_ == Timeline::kTrimIn) { adjacent_->set_length_and_media_out(adjacent_->length() - trim_diff); } else { adjacent_->set_length_and_media_in(adjacent_->length() - trim_diff); } } } TimeRange invalidate_range; if (mode_ == Timeline::kTrimIn) { block_->set_length_and_media_in(old_length_); invalidate_range = TimeRange(block_->in(), block_->in() + trim_diff); } else { block_->set_length_and_media_out(old_length_); invalidate_range = TimeRange(block_->out(), block_->out() - trim_diff); } track_->EndOperation(); track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } TrackReplaceBlockWithGapCommand::TrackReplaceBlockWithGapCommand(TrackOutput *track, Block *block, QUndoCommand *command) : UndoCommand(command), track_(track), block_(block), we_created_gap_(false), gap_(nullptr), merged_gap_(nullptr) { } Project *TrackReplaceBlockWithGapCommand::GetRelevantProject() const { return static_cast(block_->parent())->project(); } void TrackReplaceBlockWithGapCommand::redo_internal() { TimeRange invalidate_range; track_->BeginOperation(); // If the block has no next, it's at the end of the track and there's no need to create a gap if (block_->next()) { invalidate_range = TimeRange(block_->in(), block_->out()); rational new_gap_length = block_->length(); bool previous_is_a_gap = (block_->previous() && block_->previous()->type() == Block::kGap); bool next_is_a_gap = (block_->next() && block_->next()->type() == Block::kGap); if (previous_is_a_gap) { // Extend gap before this block gap_ = static_cast(block_->previous()); // If the next is also a gap, we'll merge the two if (next_is_a_gap) { merged_gap_ = static_cast(block_->next()); new_gap_length += merged_gap_->length(); track_->RippleRemoveBlock(merged_gap_); TakeNodeFromParentGraph(merged_gap_, &memory_manager_); } } else if (next_is_a_gap) { // Extend gap after this block gap_ = static_cast(block_->next()); } if (gap_) { // Extend an existing gap new_gap_length += gap_->length(); gap_->set_length_and_media_out(new_gap_length); track_->RippleRemoveBlock(block_); } else { // No gap exists, create one gap_ = new GapBlock(); gap_->set_length_and_media_out(new_gap_length); static_cast(track_->parent())->AddNode(gap_); track_->ReplaceBlock(block_, gap_); we_created_gap_ = true; } } else { rational earliest_change = block_->in(); // Handle the gap being at the end where no gap is necessary track_->RippleRemoveBlock(block_); // If there were also gaps leading up to this block, clean them up here if (!track_->Blocks().isEmpty() && track_->Blocks().last()->type() == Block::kGap) { merged_gap_ = static_cast(track_->Blocks().last()); earliest_change = merged_gap_->in(); track_->RippleRemoveBlock(merged_gap_); TakeNodeFromParentGraph(merged_gap_, &memory_manager_); } invalidate_range = TimeRange(earliest_change, RATIONAL_MAX); } track_->EndOperation(); track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } void TrackReplaceBlockWithGapCommand::undo_internal() { TimeRange invalidate_range; track_->BeginOperation(); if (gap_) { if (we_created_gap_) { // We made this gap, simply swap our gap back track_->ReplaceBlock(gap_, block_); delete TakeNodeFromParentGraph(gap_); gap_ = nullptr; } else { // We must have extended an existing gap rational original_gap_length = gap_->length() - block_->length(); // If we merged two gaps together, restore it now if (merged_gap_) { original_gap_length -= merged_gap_->length(); static_cast(track_->parent())->AddNode(merged_gap_); track_->InsertBlockAfter(merged_gap_, gap_); } // Restore original block track_->InsertBlockAfter(block_, gap_); // Restore gap's original length gap_->set_length_and_media_out(original_gap_length); } invalidate_range = TimeRange(block_->in(), block_->out()); } else { // If there's no `gap_`, we must have removed the block at the end invalidate_range = TimeRange(track_->track_length(), RATIONAL_MAX); if (merged_gap_) { static_cast(track_->parent())->AddNode(merged_gap_); track_->AppendBlock(merged_gap_); } track_->AppendBlock(block_); } merged_gap_ = nullptr; track_->EndOperation(); track_->InvalidateCache(invalidate_range, track_->block_input(), track_->block_input()); } TrackSlideCommand::TrackSlideCommand(const QVector &blocks, QUndoCommand *parent) : UndoCommand(parent), blocks_(blocks) { } Project *TrackSlideCommand::GetRelevantProject() const { return static_cast(blocks_.first().track->parent())->project(); } void TrackSlideCommand::redo_internal() { slide_internal(false); } void TrackSlideCommand::undo_internal() { slide_internal(true); } void TrackSlideCommand::slide_internal(bool undo) { QMap invalidate_ranges; // Make sure all movement blocks' old positions are invalidated foreach (const BlockSlideInfo& info, blocks_) { if (info.mode == Timeline::kMove) { invalidate_ranges[info.track].InsertTimeRange(TimeRange(info.block->in(), info.block->out())); } } // Perform trims foreach (const BlockSlideInfo& info, blocks_) { info.track->BeginOperation(); if (info.mode == Timeline::kTrimIn || info.mode == Timeline::kTrimOut) { rational new_len = undo ? info.old_time : info.new_time; if (info.mode == Timeline::kTrimIn) { info.block->set_length_and_media_in(new_len); } else { info.block->set_length_and_media_out(new_len); } } else if (!undo && info.mode == Timeline::kMove && !info.block->previous()) { // If this is a moving block and there was nothing before it to offset its time correctly, // insert a gap here GapBlock* gap = new GapBlock(); gap->set_length_and_media_out(info.new_time); static_cast(info.block->parent())->AddNode(gap); info.track->PrependBlock(gap); added_gaps_.append(gap); } info.track->EndOperation(); } if (undo) { // If undoing, remove added gaps foreach (GapBlock* gap, added_gaps_) { TrackOutput* track = TrackOutput::TrackFromBlock(gap); track->BeginOperation(); track->RippleRemoveBlock(gap); delete TakeNodeFromParentGraph(gap); track->EndOperation(); } added_gaps_.clear(); } // Make sure all movement blocks' new positions are invalidated foreach (const BlockSlideInfo& info, blocks_) { if (info.mode == Timeline::kMove) { invalidate_ranges[info.track].InsertTimeRange(TimeRange(info.block->in(), info.block->out())); } } QMap::const_iterator i; for (i=invalidate_ranges.constBegin(); i!=invalidate_ranges.constEnd(); i++) { foreach (const TimeRange& r, i.value()) { i.key()->InvalidateCache(r, i.key()->block_input(), i.key()->block_input()); } } } TrackListRippleRemoveAreaCommand::TrackListRippleRemoveAreaCommand(TrackList *list, rational in, rational out, QUndoCommand *parent) : UndoCommand(parent), list_(list), in_(in), out_(out) { all_tracks_unlocked_ = true; foreach (TrackOutput* track, list_->GetTracks()) { if (track->IsLocked()) { all_tracks_unlocked_ = false; continue; } TrackRippleRemoveAreaCommand* c = new TrackRippleRemoveAreaCommand(track, in, out); commands_.append(c); working_tracks_.append(track); } } TrackListRippleRemoveAreaCommand::~TrackListRippleRemoveAreaCommand() { qDeleteAll(commands_); } Project *TrackListRippleRemoveAreaCommand::GetRelevantProject() const { return static_cast(static_cast(list_->parent())->parent())->project(); } void TrackListRippleRemoveAreaCommand::redo_internal() { if (all_tracks_unlocked_) { // We can optimize here by simply shifting the whole cache forward instead of re-caching // everything following this time if (list_->type() == Timeline::kTrackTypeVideo) { static_cast(list_->parent())->ShiftVideoCache(out_, in_); } else if (list_->type() == Timeline::kTrackTypeAudio) { static_cast(list_->parent())->ShiftAudioCache(out_, in_); } foreach (TrackOutput* track, working_tracks_) { track->BeginOperation(); } } foreach (TrackRippleRemoveAreaCommand* c, commands_) { c->redo(); } if (all_tracks_unlocked_) { foreach (TrackOutput* track, working_tracks_) { track->EndOperation(); } } } void TrackListRippleRemoveAreaCommand::undo_internal() { if (all_tracks_unlocked_) { // We can optimize here by simply shifting the whole cache forward instead of re-caching // everything following this time if (list_->type() == Timeline::kTrackTypeVideo) { static_cast(list_->parent())->ShiftVideoCache(in_, out_); } else if (list_->type() == Timeline::kTrackTypeAudio) { static_cast(list_->parent())->ShiftAudioCache(in_, out_); } foreach (TrackOutput* track, working_tracks_) { track->BeginOperation(); } } foreach (TrackRippleRemoveAreaCommand* c, commands_) { c->undo(); } if (all_tracks_unlocked_) { foreach (TrackOutput* track, working_tracks_) { track->EndOperation(); } } } TimelineRippleRemoveAreaCommand::TimelineRippleRemoveAreaCommand(ViewerOutput *timeline, rational in, rational out, QUndoCommand *parent) : UndoCommand(parent), timeline_(timeline) { for (int i=0; itrack_list(static_cast(i)), in, out, this); } } Project *TimelineRippleRemoveAreaCommand::GetRelevantProject() const { return static_cast(timeline_->parent())->project(); } TrackListRippleToolCommand::TrackListRippleToolCommand(TrackList *track_list, const QList &info, const Timeline::MovementMode &movement_mode, QUndoCommand *parent) : UndoCommand(parent), track_list_(track_list), info_(info), movement_mode_(movement_mode) { working_data_.resize(info_.size()); all_tracks_unlocked_ = (info_.size() == track_list_->GetTrackCount()); } Project *TrackListRippleToolCommand::GetRelevantProject() const { return static_cast(static_cast(track_list_->parent())->parent())->project(); } void TrackListRippleToolCommand::redo_internal() { rational old_latest_pt; rational earliest_pt; if (all_tracks_unlocked_) { // We can do some optimization here foreach (const RippleInfo& info, info_) { info.track->BeginOperation(); } old_latest_pt = RATIONAL_MIN; earliest_pt = RATIONAL_MAX; foreach (const RippleInfo& info, info_) { if (info.block) { old_latest_pt = qMax(old_latest_pt, info.block->out()); if (movement_mode_ == Timeline::kTrimIn) { earliest_pt = qMin(earliest_pt, info.block->in()); } else { earliest_pt = qMin(earliest_pt, info.block->out()); } } else { old_latest_pt = qMax(old_latest_pt, info.ref_block->out()); earliest_pt = qMin(earliest_pt, info.ref_block->out()); } } } for (int i=0;i 0) { if (movement_mode_ == Timeline::kTrimIn) { // We'll need to shift the media in point too b->set_length_and_media_in(info.new_length); } else { b->set_length_and_media_out(info.new_length); } } else { // Assume the Block was a Gap and it was reduced to zero length, remove it here working_data_[i].removed_gap_after = b->previous(); info.track->RippleRemoveBlock(b); TakeNodeFromParentGraph(b, &memory_manager_); } } else if (info.new_length > 0) { // This is a gap we are creating GapBlock* gap = new GapBlock(); gap->set_length_and_media_out(info.new_length); static_cast(info.ref_block->parent())->AddNode(gap); working_data_[i].created_gap = gap; info.track->InsertBlockAfter(gap, info.ref_block); } } if (all_tracks_unlocked_) { // We can do some optimization here rational new_latest_pt = RATIONAL_MIN; for (int i=0;i 0) { new_latest_pt = qMax(new_latest_pt, info.block->out()); } else { new_latest_pt = qMax(new_latest_pt, info.block->in()); } } else if (info.new_length > 0) { new_latest_pt = qMax(new_latest_pt, working_data_.at(i).created_gap->out()); } } if (track_list_->type() == Timeline::kTrackTypeVideo) { static_cast(track_list_->parent())->ShiftVideoCache(old_latest_pt, new_latest_pt); } else if (track_list_->type() == Timeline::kTrackTypeAudio) { static_cast(track_list_->parent())->ShiftAudioCache(old_latest_pt, new_latest_pt); } foreach (const RippleInfo& info, info_) { info.track->EndOperation(); // FIXME: Untested, is this desirable behavior? if (earliest_pt < new_latest_pt) { info.track->InvalidateCache(TimeRange(earliest_pt, new_latest_pt), info.track->block_input(), info.track->block_input()); } } } } void TrackListRippleToolCommand::undo_internal() { // FIXME: Add cache shift optimization // Clean created gaps for (int i=info_.size()-1; i>=0; i--) { const RippleInfo& info = info_.at(i); Block* b = info.block; if (b) { // This was a Block that already existed if (info.new_length > 0) { if (movement_mode_ == Timeline::kTrimIn) { // We'll need to shift the media in point too b->set_length_and_media_in(info.old_length); } else { b->set_length_and_media_out(info.old_length); } } else { // Assume the Block was a Gap and it was reduced to zero length, remove it here Block* previous_block = working_data_[i].removed_gap_after; static_cast(info.track->parent())->AddNode(b); if (previous_block) { info.track->InsertBlockAfter(b, previous_block); } else { info.track->PrependBlock(b); } } } else if (info.new_length > 0) { // We created a gap here, remove it GapBlock* gap = working_data_.at(i).created_gap; info.track->RippleRemoveBlock(gap); delete TakeNodeFromParentGraph(gap); } } } TrackListInsertGaps::TrackListInsertGaps(TrackList *track_list, const rational &point, const rational &length, QUndoCommand *parent) : UndoCommand(parent), track_list_(track_list), point_(point), length_(length), split_command_(nullptr) { all_tracks_unlocked_ = true; foreach (TrackOutput* track, track_list_->GetTracks()) { if (track->IsLocked()) { all_tracks_unlocked_ = false; continue; } working_tracks_.append(track); } } Project *TrackListInsertGaps::GetRelevantProject() const { return static_cast(static_cast(track_list_->parent())->parent())->project(); } void TrackListInsertGaps::redo_internal() { if (all_tracks_unlocked_) { // Optimize by shifting over since we have a constant amount of time being inserted if (track_list_->type() == Timeline::kTrackTypeVideo) { static_cast(track_list_->parent())->ShiftVideoCache(point_, point_ + length_); } else if (track_list_->type() == Timeline::kTrackTypeAudio) { static_cast(track_list_->parent())->ShiftAudioCache(point_, point_ + length_); } foreach (TrackOutput* track, working_tracks_) { track->BeginOperation(); } } QVector blocks_to_split; QList blocks_to_append_gap_to; foreach (TrackOutput* track, working_tracks_) { foreach (Block* b, track->Blocks()) { if (b->type() == Block::kGap && b->in() <= point_ && b->out() >= point_) { gaps_to_extend_.append(b); } else if (b->type() == Block::kClip && b->out() >= point_) { if (b->out() > point_) { blocks_to_split.append(b); } blocks_to_append_gap_to.append(b); } } } foreach (Block* gap, gaps_to_extend_) { gap->set_length_and_media_out(gap->length() + length_); } if (!blocks_to_split.isEmpty()) { split_command_ = new BlockSplitPreservingLinksCommand(blocks_to_split, {point_}); split_command_->redo(); } foreach (Block* block, blocks_to_append_gap_to) { GapBlock* gap = new GapBlock(); gap->set_length_and_media_out(length_); static_cast(block->parent())->AddNode(gap); TrackOutput::TrackFromBlock(block)->InsertBlockAfter(gap, block); gaps_added_.append(gap); } if (all_tracks_unlocked_) { foreach (TrackOutput* track, working_tracks_) { track->EndOperation(); } } } void TrackListInsertGaps::undo_internal() { if (all_tracks_unlocked_) { // Optimize by shifting over since we have a constant amount of time being inserted if (track_list_->type() == Timeline::kTrackTypeVideo) { static_cast(track_list_->parent())->ShiftVideoCache(point_ + length_, point_); } else if (track_list_->type() == Timeline::kTrackTypeAudio) { static_cast(track_list_->parent())->ShiftAudioCache(point_ + length_, point_); } foreach (TrackOutput* track, working_tracks_) { track->BeginOperation(); } } // Remove added gaps foreach (GapBlock* gap, gaps_added_) { TrackOutput::TrackFromBlock(gap)->RippleRemoveBlock(gap); delete TakeNodeFromParentGraph(gap); } gaps_added_.clear(); // Un-split blocks if (split_command_) { split_command_->undo(); delete split_command_; split_command_ = nullptr; } // Restore original length of gaps foreach (Block* gap, gaps_to_extend_) { gap->set_length_and_media_out(gap->length() - length_); } gaps_to_extend_.clear(); if (all_tracks_unlocked_) { foreach (TrackOutput* track, working_tracks_) { track->EndOperation(); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/undo/undo.h000066400000000000000000000335371370472574300235670ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEUNDOABLE_H #define TIMELINEUNDOABLE_H #include #include "node/block/block.h" #include "node/block/gap/gap.h" #include "node/output/track/track.h" #include "node/output/track/tracklist.h" #include "timeline/timelinepoints.h" #include "undo/undocommand.h" OLIVE_NAMESPACE_ENTER class BlockResizeCommand : public UndoCommand { public: BlockResizeCommand(Block* block, rational new_length, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; rational old_length_; rational new_length_; }; class BlockResizeWithMediaInCommand : public UndoCommand { public: BlockResizeWithMediaInCommand(Block* block, rational new_length, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; rational old_length_; rational new_length_; }; class BlockTrimCommand : public UndoCommand { public: BlockTrimCommand(TrackOutput *track, Block* block, rational new_length, Timeline::MovementMode mode, QUndoCommand* command = nullptr); virtual Project* GetRelevantProject() const override; void SetAllowNonGapTrimming(bool e) { allow_nongap_trimming_ = e; } protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* block_; rational old_length_; rational new_length_; Timeline::MovementMode mode_; Block* adjacent_; bool we_created_adjacent_; bool we_deleted_adjacent_; bool allow_nongap_trimming_; QObject memory_manager_; }; class BlockSetMediaInCommand : public UndoCommand { public: BlockSetMediaInCommand(Block* block, rational new_media_in, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; rational old_media_in_; rational new_media_in_; }; class BlockSetSpeedCommand : public UndoCommand { public: BlockSetSpeedCommand(Block* block, const rational& new_speed, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; rational old_speed_; rational new_speed_; }; class TrackRippleRemoveBlockCommand : public UndoCommand { public: TrackRippleRemoveBlockCommand(TrackOutput* track, Block* block, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* block_; Block* before_; }; class TrackPrependBlockCommand : public UndoCommand { public: TrackPrependBlockCommand(TrackOutput* track, Block* block, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* block_; }; class TrackInsertBlockAfterCommand : public UndoCommand { public: TrackInsertBlockAfterCommand(TrackOutput* track, Block* block, Block* before, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* block_; Block* before_; }; /** * @brief Clears the area between in and out * * The area between `in` and `out` is guaranteed to be freed. BLocks are trimmed and removed to free this space. * By default, nothing takes this area meaning all subsequent clips are pushed backward, however you can specify * a block to insert at the `in` point. No checking is done to ensure `insert` is the same length as `in` to `out`. */ class TrackRippleRemoveAreaCommand : public UndoCommand { public: TrackRippleRemoveAreaCommand(TrackOutput* track, rational in, rational out, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; void SetInsert(Block* insert); protected: virtual void redo_internal() override; virtual void undo_internal() override; protected: Project* project_; TrackOutput* track_; rational in_; rational out_; bool splice_; Block* trim_out_; Block* trim_in_; QVector removed_blocks_; rational trim_in_old_length_; rational trim_out_old_length_; rational trim_in_new_length_; rational trim_out_new_length_; Block* insert_; QObject memory_manager_; QList remove_block_commands_; }; class TrackListRippleRemoveAreaCommand : public UndoCommand { public: TrackListRippleRemoveAreaCommand(TrackList* list, rational in, rational out, QUndoCommand* parent = nullptr); virtual ~TrackListRippleRemoveAreaCommand() override; virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackList* list_; QList working_tracks_; rational in_; rational out_; bool all_tracks_unlocked_; QVector commands_; }; class TimelineRippleRemoveAreaCommand : public UndoCommand { public: TimelineRippleRemoveAreaCommand(ViewerOutput* timeline, rational in, rational out, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; private: ViewerOutput* timeline_; }; class TrackListRippleToolCommand : public UndoCommand { public: struct RippleInfo { Block* block; Block* ref_block; TrackOutput* track; rational new_length; rational old_length; }; TrackListRippleToolCommand(TrackList* track_list, const QList& info, const Timeline::MovementMode& movement_mode, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackList* track_list_; QList info_; Timeline::MovementMode movement_mode_; struct WorkingData { GapBlock* created_gap; Block* removed_gap_after; }; QVector working_data_; QObject memory_manager_; bool all_tracks_unlocked_; }; /** * @brief Destructively places `block` at the in point `start` * * The Block is guaranteed to be placed at the starting point specified. If there are Blocks in this area, they are * either trimmed or removed to make space for this Block. Additionally, if the Block is placed beyond the end of * the Sequence, a GapBlock is inserted to compensate. */ class TrackPlaceBlockCommand : public TrackRippleRemoveAreaCommand { public: TrackPlaceBlockCommand(TrackList *timeline, int track, Block* block, rational in, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackList* timeline_; int track_index_; bool append_; GapBlock* gap_; int added_track_count_; }; class BlockSplitCommand : public UndoCommand { public: BlockSplitCommand(TrackOutput* track, Block* block, rational point, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; Block* new_block(); protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* block_; rational new_length_; rational old_length_; rational point_; Block* new_block_; QList transitions_to_move_; QObject memory_manager_; }; class TrackSplitAtTimeCommand : public UndoCommand { public: TrackSplitAtTimeCommand(TrackOutput* track, rational point, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; private: TrackOutput* track_; }; class BlockSplitPreservingLinksCommand : public UndoCommand { public: BlockSplitPreservingLinksCommand(const QVector &blocks, const QList& times, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; private: QVector blocks_; QList times_; }; /** * @brief Replaces Block `old` with Block `replace` * * Both blocks must have equal lengths. */ class TrackReplaceBlockCommand : public UndoCommand { public: TrackReplaceBlockCommand(TrackOutput* track, Block* old, Block* replace, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* old_; Block* replace_; }; class TrackReplaceBlockWithGapCommand : public UndoCommand { public: TrackReplaceBlockWithGapCommand(TrackOutput* track, Block* block, QUndoCommand* command = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackOutput* track_; Block* block_; bool we_created_gap_; GapBlock* gap_; GapBlock* merged_gap_; QObject memory_manager_; }; class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand { public: TimelineRippleDeleteGapsAtRegionsCommand(ViewerOutput* vo, const TimeRangeList& regions, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: ViewerOutput* timeline_; TimeRangeList regions_; QList commands_; }; class WorkareaSetEnabledCommand : public UndoCommand { public: WorkareaSetEnabledCommand(Project *project, TimelinePoints* points, bool enabled, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Project* project_; TimelinePoints* points_; bool old_enabled_; bool new_enabled_; }; class WorkareaSetRangeCommand : public UndoCommand { public: WorkareaSetRangeCommand(Project *project, TimelinePoints* points, const TimeRange& range, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Project* project_; TimelinePoints* points_; TimeRange old_range_; TimeRange new_range_; }; class BlockLinkManyCommand : public UndoCommand { public: BlockLinkManyCommand(const QList blocks, bool link, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; private: QList blocks_; }; class BlockLinkCommand : public UndoCommand { public: BlockLinkCommand(Block* a, Block* b, bool link, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* a_; Block* b_; bool link_; bool done_; }; class BlockUnlinkAllCommand : public UndoCommand { public: BlockUnlinkAllCommand(Block* block, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; QVector unlinked_; }; class BlockEnableDisableCommand : public UndoCommand { public: BlockEnableDisableCommand(Block* block, bool enabled, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: Block* block_; bool old_enabled_; bool new_enabled_; }; class TrackSlideCommand : public UndoCommand { public: struct BlockSlideInfo { TrackOutput* track; Block* block; Timeline::MovementMode mode; rational new_time; rational old_time; }; TrackSlideCommand(const QVector& blocks, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: void slide_internal(bool undo); QVector blocks_; QList added_gaps_; }; class TrackListInsertGaps : public UndoCommand { public: TrackListInsertGaps(TrackList* track_list, const rational& point, const rational& length, QUndoCommand* parent = nullptr); virtual Project* GetRelevantProject() const override; protected: virtual void redo_internal() override; virtual void undo_internal() override; private: TrackList* track_list_; rational point_; rational length_; QList working_tracks_; bool all_tracks_unlocked_; QList gaps_to_extend_; QList gaps_added_; BlockSplitPreservingLinksCommand* split_command_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEUNDOABLE_H olive-continuous/app/widget/timelinewidget/view/000077500000000000000000000000001370472574300224435ustar00rootroot00000000000000olive-continuous/app/widget/timelinewidget/view/CMakeLists.txt000066400000000000000000000030331370472574300252020ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timelinewidget/view/handmovableview.h widget/timelinewidget/view/handmovableview.cpp widget/timelinewidget/view/timelineplayhead.h widget/timelinewidget/view/timelineplayhead.cpp widget/timelinewidget/view/timelineview.h widget/timelinewidget/view/timelineview.cpp widget/timelinewidget/view/timelineviewmouseevent.h widget/timelinewidget/view/timelineviewmouseevent.cpp widget/timelinewidget/view/timelineviewrect.h widget/timelinewidget/view/timelineviewrect.cpp widget/timelinewidget/view/timelineviewbase.h widget/timelinewidget/view/timelineviewbase.cpp widget/timelinewidget/view/timelineviewblockitem.h widget/timelinewidget/view/timelineviewblockitem.cpp widget/timelinewidget/view/timelineviewghostitem.h widget/timelinewidget/view/timelineviewghostitem.cpp PARENT_SCOPE ) olive-continuous/app/widget/timelinewidget/view/handmovableview.cpp000066400000000000000000000057741370472574300263370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "handmovableview.h" #include #include "core.h" OLIVE_NAMESPACE_ENTER HandMovableView::HandMovableView(QWidget* parent) : QGraphicsView(parent), dragging_hand_(false) { connect(Core::instance(), &Core::ToolChanged, this, &HandMovableView::ApplicationToolChanged); } void HandMovableView::ApplicationToolChanged(Tool::Item tool) { if (tool == Tool::kHand) { setDragMode(ScrollHandDrag); } else { setDragMode(default_drag_mode_); } ToolChangedEvent(tool); } bool HandMovableView::HandPress(QMouseEvent *event) { if (event->button() == Qt::MiddleButton) { pre_hand_drag_mode_ = dragMode(); dragging_hand_ = true; setDragMode(ScrollHandDrag); // Transform mouse event to act like the left button is pressed QMouseEvent transformed(event->type(), event->localPos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); QGraphicsView::mousePressEvent(&transformed); return true; } return false; } bool HandMovableView::HandMove(QMouseEvent *event) { if (dragging_hand_) { // Transform mouse event to act like the left button is pressed QMouseEvent transformed(event->type(), event->localPos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); QGraphicsView::mouseMoveEvent(&transformed); } return dragging_hand_; } bool HandMovableView::HandRelease(QMouseEvent *event) { if (dragging_hand_) { // Transform mouse event to act like the left button is pressed QMouseEvent transformed(event->type(), event->localPos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); QGraphicsView::mouseReleaseEvent(&transformed); setDragMode(pre_hand_drag_mode_); dragging_hand_ = false; return true; } return false; } void HandMovableView::SetDefaultDragMode(QGraphicsView::DragMode mode) { default_drag_mode_ = mode; setDragMode(default_drag_mode_); } const QGraphicsView::DragMode &HandMovableView::GetDefaultDragMode() const { return default_drag_mode_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/handmovableview.h000066400000000000000000000026501370472574300257720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef HANDMOVABLEVIEW_H #define HANDMOVABLEVIEW_H #include #include "tool/tool.h" OLIVE_NAMESPACE_ENTER class HandMovableView : public QGraphicsView { Q_OBJECT public: HandMovableView(QWidget* parent = nullptr); protected: virtual void ToolChangedEvent(Tool::Item tool){Q_UNUSED(tool)} bool HandPress(QMouseEvent* event); bool HandMove(QMouseEvent* event); bool HandRelease(QMouseEvent* event); void SetDefaultDragMode(DragMode mode); const DragMode& GetDefaultDragMode() const; private: bool dragging_hand_; DragMode pre_hand_drag_mode_; DragMode default_drag_mode_; private slots: void ApplicationToolChanged(Tool::Item tool); }; OLIVE_NAMESPACE_EXIT #endif // HANDMOVABLEVIEW_H olive-continuous/app/widget/timelinewidget/view/timelineplayhead.cpp000066400000000000000000000027241370472574300264720ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineplayhead.h" #include const QColor &TimelinePlayhead::GetPlayheadColor() const { return playhead_color_; } const QColor &TimelinePlayhead::GetPlayheadHighlightColor() const { return playhead_highlight_color_; } void TimelinePlayhead::SetPlayheadColor(QColor c) { playhead_color_ = c; } void TimelinePlayhead::SetPlayheadHighlightColor(QColor c) { playhead_highlight_color_ = c; } void TimelinePlayhead::Draw(QPainter* painter, const QRectF& playhead_rect) const { painter->setPen(Qt::NoPen); painter->setBrush(GetPlayheadHighlightColor()); painter->drawRect(playhead_rect); painter->setPen(GetPlayheadColor()); painter->setBrush(Qt::NoBrush); painter->drawLine(QLineF(playhead_rect.topLeft(), playhead_rect.bottomLeft())); } olive-continuous/app/widget/timelinewidget/view/timelineplayhead.h000066400000000000000000000031751370472574300261400ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEPLAYHEADSTYLE_H #define TIMELINEPLAYHEADSTYLE_H #include /** * @brief A QWidget proxy for TimeRuler and TimelinePlayheadItem to allow them to share CSS values * * To allow Qt CSS customization (which is only available to QWidgets) to be accessed by TimeRuler */ class TimelinePlayhead : public QWidget { Q_OBJECT Q_PROPERTY(QColor playheadColor READ GetPlayheadColor WRITE SetPlayheadColor DESIGNABLE true) Q_PROPERTY(QColor playheadHighlightColor READ GetPlayheadHighlightColor WRITE SetPlayheadHighlightColor DESIGNABLE true) public: TimelinePlayhead() = default; const QColor& GetPlayheadColor() const; const QColor& GetPlayheadHighlightColor() const; void SetPlayheadColor(QColor c); void SetPlayheadHighlightColor(QColor c); void Draw(QPainter *painter, const QRectF &rect) const; private: QColor playhead_color_; QColor playhead_highlight_color_; }; #endif // TIMELINEPLAYHEADSTYLE_H olive-continuous/app/widget/timelinewidget/view/timelineview.cpp000066400000000000000000000262151370472574300256560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineview.h" #include #include #include #include #include #include #include "config/config.h" #include "common/flipmodifiers.h" #include "common/timecodefunctions.h" #include "node/input/media/media.h" #include "project/item/footage/footage.h" OLIVE_NAMESPACE_ENTER TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : TimelineViewBase(parent), show_beam_cursor_(false), connected_track_list_(nullptr) { Q_ASSERT(vertical_alignment == Qt::AlignTop || vertical_alignment == Qt::AlignBottom); setAlignment(Qt::AlignLeft | vertical_alignment); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setBackgroundRole(QPalette::Window); setContextMenuPolicy(Qt::CustomContextMenu); viewport()->setMouseTracking(true); connect(scene(), &QGraphicsScene::selectionChanged, this, &TimelineView::SelectionChanged); } void TimelineView::SelectAll() { QList all_items = items(); foreach (QGraphicsItem* i, all_items) { i->setSelected(true); } } void TimelineView::DeselectAll() { QList all_items = items(); foreach (QGraphicsItem* i, all_items) { i->setSelected(false); } } void TimelineView::mousePressEvent(QMouseEvent *event) { if (HandPress(event) || PlayheadPress(event)) { // Let the parent handle this return; } if (dragMode() != GetDefaultDragMode()) { TimelineViewBase::mousePressEvent(event); return; } TimelineViewMouseEvent timeline_event = CreateMouseEvent(event); emit MousePressed(&timeline_event); } void TimelineView::mouseMoveEvent(QMouseEvent *event) { if (HandMove(event) || PlayheadMove(event)) { // Let the parent handle this return; } if (dragMode() != GetDefaultDragMode()) { TimelineViewBase::mouseMoveEvent(event); return; } TimelineViewMouseEvent timeline_event = CreateMouseEvent(event); emit MouseMoved(&timeline_event); } void TimelineView::mouseReleaseEvent(QMouseEvent *event) { if (HandRelease(event) || PlayheadRelease(event)) { // Let the parent handle this return; } if (dragMode() != GetDefaultDragMode()) { TimelineViewBase::mouseReleaseEvent(event); return; } TimelineViewMouseEvent timeline_event = CreateMouseEvent(event); emit MouseReleased(&timeline_event); } void TimelineView::mouseDoubleClickEvent(QMouseEvent *event) { TimelineViewMouseEvent timeline_event = CreateMouseEvent(event); emit MouseDoubleClicked(&timeline_event); } void TimelineView::wheelEvent(QWheelEvent *event) { if (HandleZoomFromScroll(event)) { return; } else { #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) QPoint angle_delta = event->angleDelta(); if (Config::Current()["InvertTimelineScrollAxes"].toBool()) { angle_delta = QPoint(angle_delta.y(), angle_delta.x()); } QWheelEvent e( #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) event->position(), event->globalPosition(), #else event->pos(), event->globalPos(), #endif event->pixelDelta(), angle_delta, event->buttons(), event->modifiers(), event->phase(), event->inverted(), event->source() ); #else Qt::Orientation orientation = event->orientation(); if (Config::Current()["InvertTimelineScrollAxes"].toBool()) { orientation = (orientation == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal; } QWheelEvent e( event->pos(), event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), orientation, event->buttons(), event->modifiers() ); #endif QGraphicsView::wheelEvent(&e); } } void TimelineView::dragEnterEvent(QDragEnterEvent *event) { TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), Qt::NoButton, event->keyboardModifiers()); timeline_event.SetMimeData(event->mimeData()); timeline_event.SetEvent(event); emit DragEntered(&timeline_event); } void TimelineView::dragMoveEvent(QDragMoveEvent *event) { TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), Qt::NoButton, event->keyboardModifiers()); timeline_event.SetMimeData(event->mimeData()); timeline_event.SetEvent(event); emit DragMoved(&timeline_event); } void TimelineView::dragLeaveEvent(QDragLeaveEvent *event) { emit DragLeft(event); } void TimelineView::dropEvent(QDropEvent *event) { TimelineViewMouseEvent timeline_event = CreateMouseEvent(event->pos(), Qt::NoButton, event->keyboardModifiers()); timeline_event.SetMimeData(event->mimeData()); timeline_event.SetEvent(event); emit DragDropped(&timeline_event); } void TimelineView::drawBackground(QPainter *painter, const QRectF &rect) { if (!connected_track_list_) { return; } painter->setPen(palette().base().color()); int line_y = 0; foreach (TrackOutput* track, connected_track_list_->GetTracks()) { line_y += track->GetTrackHeight(); // One px gap between tracks line_y++; int this_line_y; if (alignment() & Qt::AlignTop) { this_line_y = line_y; } else { this_line_y = -line_y; } painter->drawLine(qRound(rect.left()), this_line_y, qRound(rect.right()), this_line_y); } } void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) { TimelineViewBase::drawForeground(painter, rect); if (show_beam_cursor_ && connected_track_list_ && cursor_coord_.GetTrack().type() == connected_track_list_->type()) { painter->setPen(Qt::gray); double cursor_x = TimeToScene(cursor_coord_.GetFrame()); int track_index = cursor_coord_.GetTrack().index(); int track_y = GetTrackY(track_index); painter->drawLine(cursor_x, track_y, cursor_x, track_y + GetTrackHeight(track_index)); } } void TimelineView::ToolChangedEvent(Tool::Item tool) { switch (tool) { case Tool::kRazor: setCursor(Qt::SplitHCursor); break; case Tool::kEdit: setCursor(Qt::IBeamCursor); break; case Tool::kAdd: case Tool::kTransition: case Tool::kZoom: setCursor(Qt::CrossCursor); break; default: unsetCursor(); } // Hide/show cursor if necessary if (show_beam_cursor_) { show_beam_cursor_ = false; viewport()->update(); } } void TimelineView::SceneRectUpdateEvent(QRectF &rect) { if (alignment() & Qt::AlignTop) { rect.setTop(0); rect.setBottom(GetHeightOfAllTracks() + height() / 2); } else if (alignment() & Qt::AlignBottom) { rect.setBottom(0); rect.setTop(GetHeightOfAllTracks() - height() / 2); } } Timeline::TrackType TimelineView::ConnectedTrackType() { if (connected_track_list_) { return connected_track_list_->type(); } return Timeline::kTrackTypeNone; } Stream::Type TimelineView::TrackTypeToStreamType(Timeline::TrackType track_type) { switch (track_type) { case Timeline::kTrackTypeNone: case Timeline::kTrackTypeCount: break; case Timeline::kTrackTypeVideo: return Stream::kVideo; case Timeline::kTrackTypeAudio: return Stream::kAudio; case Timeline::kTrackTypeSubtitle: return Stream::kSubtitle; } return Stream::kUnknown; } TimelineCoordinate TimelineView::ScreenToCoordinate(const QPoint& pt) { return SceneToCoordinate(mapToScene(pt)); } TimelineCoordinate TimelineView::SceneToCoordinate(const QPointF& pt) { return TimelineCoordinate(SceneToTime(pt.x()), TrackReference(ConnectedTrackType(), SceneToTrack(pt.y()))); } TimelineViewMouseEvent TimelineView::CreateMouseEvent(QMouseEvent *event) { return CreateMouseEvent(event->pos(), event->button(), event->modifiers()); } TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) { QPointF scene_pt = mapToScene(pos); return TimelineViewMouseEvent(scene_pt.x(), GetScale(), timebase(), TrackReference(ConnectedTrackType(), SceneToTrack(scene_pt.y())), button, modifiers); } int TimelineView::GetHeightOfAllTracks() const { if (connected_track_list_) { if (alignment() & Qt::AlignTop) { return GetTrackY(connected_track_list_->GetTrackCount()); } else { return GetTrackY(connected_track_list_->GetTrackCount() - 1); } } else { return 0; } } int TimelineView::GetTrackY(int track_index) const { if (!connected_track_list_ || !connected_track_list_->GetTrackCount()) { return 0; } int y = 0; if (alignment() & Qt::AlignBottom) { track_index++; } for (int i=0;i= connected_track_list_->GetTrackCount()) { return TrackOutput::GetDefaultTrackHeight(); } return connected_track_list_->GetTrackAt(track_index)->GetTrackHeight(); } QPoint TimelineView::GetScrollCoordinates() const { return QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value()); } void TimelineView::SetScrollCoordinates(const QPoint &pt) { horizontalScrollBar()->setValue(pt.x()); verticalScrollBar()->setValue(pt.y()); } void TimelineView::ConnectTrackList(TrackList *list) { if (connected_track_list_) { disconnect(connected_track_list_, SIGNAL(TrackHeightChanged(int, int)), viewport(), SLOT(update())); } connected_track_list_ = list; if (connected_track_list_) { connect(connected_track_list_, SIGNAL(TrackHeightChanged(int, int)), viewport(), SLOT(update())); } } void TimelineView::SetBeamCursor(const TimelineCoordinate &coord) { bool update_required = coord.GetTrack().type() == connected_track_list_->type() || cursor_coord_.GetTrack().type() == connected_track_list_->type(); show_beam_cursor_ = true; cursor_coord_ = coord; if (update_required) { viewport()->update(); } } int TimelineView::SceneToTrack(double y) { int track = -1; int heights = 0; if (alignment() & Qt::AlignBottom) { y = -y; } do { track++; heights += GetTrackHeight(track); } while (y > heights); return track; } void TimelineView::UserSetTime(const int64_t &time) { SetTime(time); emit TimeChanged(time); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/timelineview.h000066400000000000000000000073731370472574300253270ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEVIEW_H #define TIMELINEVIEW_H #include #include #include #include #include #include "node/block/clip/clip.h" #include "timelineviewbase.h" #include "timelineviewblockitem.h" #include "timelineviewmouseevent.h" #include "timelineviewghostitem.h" #include "widget/timelinewidget/undo/undo.h" #include "undo/undostack.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget for viewing and interacting Sequences * * This widget primarily exposes users to viewing and modifying Block nodes, usually through a TimelineOutput node. */ class TimelineView : public TimelineViewBase { Q_OBJECT public: TimelineView(Qt::Alignment vertical_alignment = Qt::AlignTop, QWidget* parent = nullptr); void SelectAll(); void DeselectAll(); int GetTrackY(int track_index) const; int GetTrackHeight(int track_index) const; QPoint GetScrollCoordinates() const; void SetScrollCoordinates(const QPoint& pt); void ConnectTrackList(TrackList* list); void SetBeamCursor(const TimelineCoordinate& coord); signals: void MousePressed(TimelineViewMouseEvent* event); void MouseMoved(TimelineViewMouseEvent* event); void MouseReleased(TimelineViewMouseEvent* event); void MouseDoubleClicked(TimelineViewMouseEvent* event); void DragEntered(TimelineViewMouseEvent* event); void DragMoved(TimelineViewMouseEvent* event); void DragLeft(QDragLeaveEvent* event); void DragDropped(TimelineViewMouseEvent* event); void SelectionChanged(); protected: virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; virtual void mouseReleaseEvent(QMouseEvent *event) override; virtual void mouseDoubleClickEvent(QMouseEvent *event) override; virtual void wheelEvent(QWheelEvent* event) override; virtual void dragEnterEvent(QDragEnterEvent *event) override; virtual void dragMoveEvent(QDragMoveEvent *event) override; virtual void dragLeaveEvent(QDragLeaveEvent *event) override; virtual void dropEvent(QDropEvent *event) override; virtual void drawBackground(QPainter *painter, const QRectF &rect) override; virtual void drawForeground(QPainter *painter, const QRectF &rect) override; virtual void ToolChangedEvent(Tool::Item tool) override; virtual void SceneRectUpdateEvent(QRectF& rect) override; private: Timeline::TrackType ConnectedTrackType(); Stream::Type TrackTypeToStreamType(Timeline::TrackType track_type); TimelineCoordinate ScreenToCoordinate(const QPoint& pt); TimelineCoordinate SceneToCoordinate(const QPointF& pt); TimelineViewMouseEvent CreateMouseEvent(QMouseEvent* event); TimelineViewMouseEvent CreateMouseEvent(const QPoint &pos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers); int GetHeightOfAllTracks() const; int SceneToTrack(double y); void UserSetTime(const int64_t& time); void UpdatePlayheadRect(); bool show_beam_cursor_; TimelineCoordinate cursor_coord_; TrackList* connected_track_list_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEVIEW_H olive-continuous/app/widget/timelinewidget/view/timelineviewbase.cpp000066400000000000000000000207521370472574300265110ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineviewbase.h" #include #include #include #include #include "common/autoscroll.h" #include "common/timecodefunctions.h" #include "config/config.h" OLIVE_NAMESPACE_ENTER const double TimelineViewBase::kMaximumScale = 8192; TimelineViewBase::TimelineViewBase(QWidget *parent) : HandMovableView(parent), playhead_(0), playhead_scene_left_(-1), playhead_scene_right_(-1), dragging_playhead_(false), snapped_(false), snap_service_(nullptr), y_axis_enabled_(false), y_scale_(1.0) { setScene(&scene_); // Set default scale SetScale(1.0); SetDefaultDragMode(NoDrag); connect(&scene_, SIGNAL(changed(const QList&)), this, SLOT(UpdateSceneRect())); SetMaximumScale(kMaximumScale); } void TimelineViewBase::TimebaseChangedEvent(const rational &) { // Timebase influences position/visibility of playhead viewport()->update(); } void TimelineViewBase::EnableSnap(const QList &points) { snapped_ = true; snap_time_ = points; viewport()->update(); } void TimelineViewBase::DisableSnap() { snapped_ = false; viewport()->update(); } void TimelineViewBase::SetSnapService(SnapService *service) { snap_service_ = service; } const double &TimelineViewBase::GetYScale() const { return y_scale_; } void TimelineViewBase::VerticalScaleChangedEvent(double) { } void TimelineViewBase::SetYScale(const double &y_scale) { y_scale_ = y_scale; if (y_axis_enabled_) { VerticalScaleChangedEvent(y_scale_); viewport()->update(); } } void TimelineViewBase::SetTime(const int64_t time) { playhead_ = time; switch (static_cast(Config::Current()["Autoscroll"].toInt())) { case AutoScroll::kNone: // Do nothing break; case AutoScroll::kPage: QMetaObject::invokeMethod(this, "PageScrollToPlayhead", Qt::QueuedConnection); break; case AutoScroll::kSmooth: emit RequestCenterScrollOnPlayhead(); break; } // Force redraw for playhead viewport()->update(); } void TimelineViewBase::drawForeground(QPainter *painter, const QRectF &rect) { QGraphicsView::drawForeground(painter, rect); if (!timebase().isNull()) { double width = TimeToScene(timebase()); playhead_scene_left_ = GetPlayheadX(); playhead_scene_right_ = playhead_scene_left_ + width; playhead_style_.Draw(painter, QRectF(playhead_scene_left_, rect.top(), width, rect.height())); } if (snapped_) { painter->setPen(palette().text().color()); foreach (const rational& r, snap_time_) { double x = TimeToScene(r); painter->drawLine(x, rect.top(), x, rect.height()); } } } rational TimelineViewBase::GetPlayheadTime() const { return Timecode::timestamp_to_time(playhead_, timebase()); } bool TimelineViewBase::PlayheadPress(QMouseEvent *event) { QPointF scene_pos = mapToScene(event->pos()); dragging_playhead_ = (event->button() == Qt::LeftButton && scene_pos.x() >= playhead_scene_left_ && scene_pos.x() < playhead_scene_right_); return dragging_playhead_; } bool TimelineViewBase::PlayheadMove(QMouseEvent *event) { if (!dragging_playhead_) { return false; } QPointF scene_pos = mapToScene(event->pos()); rational mouse_time = SceneToTime(scene_pos.x()); int64_t target_ts = qMax(static_cast(0), Timecode::time_to_timestamp(mouse_time, timebase())); if (Core::instance()->snapping() && snap_service_) { rational target_time = Timecode::timestamp_to_time(target_ts, timebase()); rational movement; snap_service_->SnapPoint({target_time}, &movement, SnapService::kSnapAll & ~SnapService::kSnapToPlayhead); if (!movement.isNull()) { target_ts = Timecode::time_to_timestamp(target_time + movement, timebase()); } } SetTime(target_ts); emit TimeChanged(target_ts); return true; } bool TimelineViewBase::PlayheadRelease(QMouseEvent*) { if (dragging_playhead_) { dragging_playhead_ = false; if (snap_service_) { snap_service_->HideSnaps(); } return true; } return false; } qreal TimelineViewBase::GetPlayheadX() { return TimeToScene(Timecode::timestamp_to_time(playhead_, timebase())); } void TimelineViewBase::SetEndTime(const rational &length) { end_time_ = length; UpdateSceneRect(); } void TimelineViewBase::UpdateSceneRect() { QRectF bounding_rect = scene_.itemsBoundingRect(); // There's no need for a timeline to ever go below 0 on the X scale bounding_rect.setLeft(0); // Ensure the scene is always the full length of the timeline with a gap at the end to work with bounding_rect.setRight(TimeToScene(end_time_) + width() / 2); // Any further rect processing from derivatives can be done here SceneRectUpdateEvent(bounding_rect); // If the scene is already this rect, do nothing if (scene_.sceneRect() != bounding_rect) { scene_.setSceneRect(bounding_rect); } } void TimelineViewBase::PageScrollToPlayhead() { int playhead_pos = qRound(GetPlayheadX()); int viewport_padding = viewport()->width() / 16; if (playhead_pos < horizontalScrollBar()->value()) { // Anchor the playhead to the RIGHT of where we scroll to horizontalScrollBar()->setValue(playhead_pos - viewport()->width() + viewport_padding); } else if (playhead_pos > horizontalScrollBar()->value() + viewport()->width()) { // Anchor the playhead to the LEFT of where we scroll to horizontalScrollBar()->setValue(playhead_pos - viewport_padding); } } void TimelineViewBase::resizeEvent(QResizeEvent *event) { QGraphicsView::resizeEvent(event); UpdateSceneRect(); } void TimelineViewBase::ScaleChangedEvent(const double &scale) { TimelineScaledObject::ScaleChangedEvent(scale); // Update scene rect UpdateSceneRect(); // Force redraw for playhead if the above function didn't do it viewport()->update(); } bool TimelineViewBase::HandleZoomFromScroll(QWheelEvent *event) { if (WheelEventIsAZoomEvent(event)) { // If CTRL is held (or a preference is set to swap CTRL behavior), we zoom instead of scrolling if (!event->angleDelta().isNull()) { bool only_vertical = false; bool only_horizontal = false; // Ctrl+Shift limits to only one axis // Alt switches between horizontal only (alt held) or vertical only (alt not held) if (y_axis_enabled_) { if (event->modifiers() & Qt::ShiftModifier) { if (event->modifiers() & Qt::AltModifier) { only_horizontal = true; } else { only_vertical = true; } } } else { only_horizontal = true; } double scale_multiplier; if (event->angleDelta().x() + event->angleDelta().y() > 0) { scale_multiplier = 1.1; } else { scale_multiplier = 0.9; } QPointF cursor_pos; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) cursor_pos = event->position(); #else cursor_pos = event->posF(); #endif if (!only_vertical) { double new_x_scale = GetScale() * scale_multiplier; int new_x_scroll = qRound(horizontalScrollBar()->value() / GetScale() * new_x_scale + (cursor_pos.x() - cursor_pos.x() / new_x_scale * GetScale())); emit ScaleChanged(new_x_scale); horizontalScrollBar()->setValue(new_x_scroll); } if (!only_horizontal) { double new_y_scale = GetYScale() * scale_multiplier; int new_y_scroll = qRound(verticalScrollBar()->value() / GetYScale() * new_y_scale + (cursor_pos.y() - cursor_pos.y() / new_y_scale * GetYScale())); SetYScale(new_y_scale); verticalScrollBar()->setValue(new_y_scroll); } } return true; } return false; } bool TimelineViewBase::WheelEventIsAZoomEvent(QWheelEvent *event) { return (static_cast(event->modifiers() & Qt::ControlModifier) == !Config::Current()["ScrollZooms"].toBool()); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/timelineviewbase.h000066400000000000000000000062721370472574300261570ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEVIEWBASE_H #define TIMELINEVIEWBASE_H #include #include "core.h" #include "handmovableview.h" #include "timelineplayhead.h" #include "widget/timelinewidget/snapservice.h" #include "widget/timelinewidget/timelinescaledobject.h" OLIVE_NAMESPACE_ENTER class TimelineViewBase : public HandMovableView, public TimelineScaledObject { Q_OBJECT public: TimelineViewBase(QWidget* parent = nullptr); static const double kMaximumScale; void EnableSnap(const QList& points); void DisableSnap(); bool IsSnapped() const { return snapped_; } void SetSnapService(SnapService* service); const double& GetYScale() const; void SetYScale(const double& y_scale); public slots: void SetTime(const int64_t time); void SetEndTime(const rational& length); signals: void TimeChanged(const int64_t& time); void ScaleChanged(double scale); void RequestCenterScrollOnPlayhead(); protected: virtual void drawForeground(QPainter *painter, const QRectF &rect) override; virtual void resizeEvent(QResizeEvent *event) override; virtual void ScaleChangedEvent(const double& scale) override; virtual void SceneRectUpdateEvent(QRectF&){} virtual void VerticalScaleChangedEvent(double scale); bool HandleZoomFromScroll(QWheelEvent* event); bool WheelEventIsAZoomEvent(QWheelEvent* event); rational GetPlayheadTime() const; bool PlayheadPress(QMouseEvent* event); bool PlayheadMove(QMouseEvent* event); bool PlayheadRelease(QMouseEvent* event); virtual void TimebaseChangedEvent(const rational &) override; bool IsYAxisEnabled() const { return y_axis_enabled_; } void SetYAxisEnabled(bool e) { y_axis_enabled_ = e; } private: qreal GetPlayheadX(); int64_t playhead_; TimelinePlayhead playhead_style_; double playhead_scene_left_; double playhead_scene_right_; bool dragging_playhead_; QGraphicsScene scene_; bool snapped_; QList snap_time_; rational end_time_; SnapService* snap_service_; bool y_axis_enabled_; double y_scale_; private slots: /** * @brief Slot called whenever the view resizes or the scene contents change to enforce minimum scene sizes */ void UpdateSceneRect(); /** * @brief Slot to handle page scrolling of the playhead * * If the playhead is outside the current scroll bounds, this function will scroll to where it is. Otherwise it will * do nothing. */ void PageScrollToPlayhead(); }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEVIEWBASE_H olive-continuous/app/widget/timelinewidget/view/timelineviewblockitem.cpp000066400000000000000000000154661370472574300275560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineviewblockitem.h" #include #include #include #include #include #include #include #include #include "common/qtutils.h" #include "config/config.h" #include "core.h" #include "node/block/transition/transition.h" #include "widget/viewer/audiowaveformview.h" OLIVE_NAMESPACE_ENTER TimelineViewBlockItem::TimelineViewBlockItem(Block *block, QGraphicsItem* parent) : TimelineViewRect(parent), block_(block) { setBrush(Qt::white); setCursor(Qt::DragMoveCursor); setFlag(QGraphicsItem::ItemIsSelectable, block_->type() == Block::kClip || block_->type() == Block::kGap || block_->type() == Block::kTransition); UpdateRect(); } Block *TimelineViewBlockItem::block() const { return block_; } void TimelineViewBlockItem::UpdateRect() { double item_left = TimeToScene(block_->in()); double item_width = TimeToScene(block_->length()); // -1 on width and height so we don't overlap any adjacent clips setRect(0, y_, item_width - 1, height_); setPos(item_left, 0.0); setToolTip(QCoreApplication::translate("TimelineViewBlockItem", "%1\n\nIn: %2\nOut: %3\nLength: %4").arg(block_->Name(), Timecode::time_to_timecode(block_->in(), timebase(), Core::instance()->GetTimecodeDisplay()), Timecode::time_to_timecode(block_->out(), timebase(), Core::instance()->GetTimecodeDisplay()), Timecode::time_to_timecode(block_->out() - block_->in(), timebase(), Core::instance()->GetTimecodeDisplay()))); } void TimelineViewBlockItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { switch (block_->type()) { case Block::kClip: { QLinearGradient grad; grad.setStart(0, rect().top()); grad.setFinalStop(0, rect().bottom()); if (block_->is_enabled()) { grad.setColorAt(0.0, QColor(160, 160, 240)); grad.setColorAt(1.0, QColor(128, 128, 192)); } else { grad.setColorAt(0.0, QColor(160, 160, 160)); grad.setColorAt(1.0, QColor(128, 128, 128)); } painter->fillRect(rect(), grad); if (option->state & QStyle::State_Selected) { painter->fillRect(rect(), QColor(0, 0, 0, 64)); } // Draw waveform if one is available painter->setPen(QColor(64, 64, 64)); TrackOutput* track = TrackOutput::TrackFromBlock(block_); if (track) { QMutexLocker locker(track->waveform_lock()); AudioVisualWaveform::DrawWaveform(painter, rect().toRect(), this->GetScale(), track->waveform(), block_->in()); } painter->setPen(Qt::white); painter->drawLine(rect().topLeft(), QPointF(rect().right(), rect().top())); painter->drawLine(rect().topLeft(), QPointF(rect().left(), rect().bottom() - 1)); // Draw text if (block_->is_enabled()) { painter->setPen(Qt::white); } else { painter->setPen(Qt::lightGray); } int text_top = TrackOutput::GetTrackHeightMinimum() / 2 - painter->fontMetrics().height() / 2; QRectF text_rect = rect(); text_rect.adjust(0, text_top, 0, 0); painter->drawText(text_rect, Qt::AlignLeft | Qt::AlignTop, block_->GetLabel()); // Linked clips are underlined if (block_->HasLinks()) { QFontMetrics fm = painter->fontMetrics(); int text_width = qMin(qRound(rect().width()), QFontMetricsWidth(fm, block_->GetLabel())); QPointF underline_start = rect().topLeft() + QPointF(0, text_top + fm.height()); QPointF underline_end = underline_start + QPointF(text_width, 0); painter->drawLine(underline_start, underline_end); } painter->setPen(QColor(64, 64, 64)); painter->drawLine(QPointF(rect().left(), rect().bottom() - 1), QPointF(rect().right(), rect().bottom() - 1)); painter->drawLine(QPointF(rect().right(), rect().bottom() - 1), QPointF(rect().right(), rect().top())); break; } case Block::kGap: if (option->state & QStyle::State_Selected) { // FIXME: Make this palette or CSS painter->fillRect(rect(), QColor(255, 255, 255, 128)); } break; case Block::kTransition: { QLinearGradient grad; grad.setStart(0, rect().top()); grad.setFinalStop(0, rect().bottom()); grad.setColorAt(0.0, QColor(192, 160, 224)); grad.setColorAt(1.0, QColor(160, 128, 192)); painter->setBrush(grad); painter->setPen(QPen(QColor(96, 80, 112), 1)); painter->drawRect(rect()); if (option->state & QStyle::State_Selected) { painter->fillRect(rect(), QColor(0, 0, 0, 64)); } // Draw lines antialiased painter->setRenderHint(QPainter::Antialiasing); TransitionBlock* t = static_cast(block_); if (t->connected_out_block() && t->connected_in_block()) { // Draw line between out offset and in offset qreal crossover_line = rect().left(); crossover_line += TimeToScene(t->out_offset()); painter->drawLine(qRound(crossover_line), qRound(rect().top()), qRound(crossover_line), qRound(rect().bottom())); // Draw lines to mid point QPointF mid_point(crossover_line, rect().center().y()); painter->drawLine(rect().topLeft(), mid_point); painter->drawLine(rect().bottomLeft(), mid_point); painter->drawLine(rect().topRight(), mid_point); painter->drawLine(rect().bottomRight(), mid_point); } else if (t->connected_out_block()) { // Transition fades something out, we'll draw a line painter->drawLine(rect().topLeft(), rect().bottomRight()); } else if (t->connected_in_block()) { // Transition fades something in, we'll draw a line painter->drawLine(rect().bottomLeft(), rect().topRight()); } break; } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/timelineviewblockitem.h000066400000000000000000000024731370472574300272150ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEVIEWCLIPITEM_H #define TIMELINEVIEWCLIPITEM_H #include "timelineviewrect.h" #include "node/block/clip/clip.h" OLIVE_NAMESPACE_ENTER /** * @brief A graphical representation of a ClipBlock */ class TimelineViewBlockItem : public TimelineViewRect { public: TimelineViewBlockItem(Block* block, QGraphicsItem* parent = nullptr); Block* block() const; virtual void UpdateRect() override; protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; private: Block* block_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEVIEWCLIPITEM_H olive-continuous/app/widget/timelinewidget/view/timelineviewghostitem.cpp000066400000000000000000000105531370472574300276000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineviewghostitem.h" #include OLIVE_NAMESPACE_ENTER TimelineViewGhostItem::TimelineViewGhostItem(QGraphicsItem *parent) : TimelineViewRect(parent), track_adj_(0), stream_(nullptr), mode_(Timeline::kNone), can_have_zero_length_(true), can_move_tracks_(true) { SetInvisible(false); } TimelineViewGhostItem *TimelineViewGhostItem::FromBlock(Block *block, const TrackReference& track, int y, int height) { TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); ghost->SetIn(block->in()); ghost->SetOut(block->out()); ghost->SetMediaIn(block->media_in()); ghost->SetTrack(track); ghost->SetYCoords(y, height); ghost->setData(kAttachedBlock, Node::PtrToValue(block)); if (block->type() == Block::kClip) { ghost->can_have_zero_length_ = false; } return ghost; } bool TimelineViewGhostItem::CanHaveZeroLength() const { return can_have_zero_length_; } bool TimelineViewGhostItem::CanMoveTracks() const { return can_move_tracks_; } void TimelineViewGhostItem::SetCanMoveTracks(bool e) { can_move_tracks_ = e; } void TimelineViewGhostItem::SetInvisible(bool invisible) { setBrush(Qt::NoBrush); if (invisible) { setPen(Qt::NoPen); } else { setPen(QPen(Qt::yellow, 2)); // FIXME: Make customizable via CSS } } const rational &TimelineViewGhostItem::In() const { return in_; } const rational &TimelineViewGhostItem::Out() const { return out_; } const rational &TimelineViewGhostItem::MediaIn() const { return media_in_; } rational TimelineViewGhostItem::Length() const { return out_ - in_; } rational TimelineViewGhostItem::AdjustedLength() const { return GetAdjustedOut() - GetAdjustedIn(); } void TimelineViewGhostItem::SetIn(const rational &in) { in_ = in; UpdateRect(); } void TimelineViewGhostItem::SetOut(const rational &out) { out_ = out; UpdateRect(); } void TimelineViewGhostItem::SetMediaIn(const rational &media_in) { media_in_ = media_in; } void TimelineViewGhostItem::SetInAdjustment(const rational &in_adj) { in_adj_ = in_adj; UpdateRect(); } void TimelineViewGhostItem::SetOutAdjustment(const rational &out_adj) { out_adj_ = out_adj; UpdateRect(); } void TimelineViewGhostItem::SetTrackAdjustment(const int &track_adj) { track_adj_ = track_adj; } void TimelineViewGhostItem::SetMediaInAdjustment(const rational &media_in_adj) { media_in_adj_ = media_in_adj; } const rational &TimelineViewGhostItem::InAdjustment() const { return in_adj_; } const rational &TimelineViewGhostItem::OutAdjustment() const { return out_adj_; } const rational &TimelineViewGhostItem::MediaInAdjustment() const { return media_in_adj_; } const int &TimelineViewGhostItem::TrackAdjustment() const { return track_adj_; } rational TimelineViewGhostItem::GetAdjustedIn() const { return in_ + in_adj_; } rational TimelineViewGhostItem::GetAdjustedOut() const { return out_ + out_adj_; } rational TimelineViewGhostItem::GetAdjustedMediaIn() const { return media_in_ + media_in_adj_; } TrackReference TimelineViewGhostItem::GetAdjustedTrack() const { return TrackReference(track_.type(), track_.index() + track_adj_); } const Timeline::MovementMode &TimelineViewGhostItem::mode() const { return mode_; } void TimelineViewGhostItem::SetMode(const Timeline::MovementMode &mode) { mode_ = mode; } bool TimelineViewGhostItem::HasBeenAdjusted() const { return InAdjustment() != 0 || OutAdjustment() != 0 || MediaInAdjustment() != 0 || TrackAdjustment() != 0; } void TimelineViewGhostItem::UpdateRect() { rational length = GetAdjustedOut() - GetAdjustedIn(); setRect(0, y_, TimeToScene(length), height_ - 1); setPos(TimeToScene(GetAdjustedIn()), 0); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/timelineviewghostitem.h000066400000000000000000000054021370472574300272420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEVIEWGHOSTITEM_H #define TIMELINEVIEWGHOSTITEM_H #include #include "project/item/footage/footage.h" #include "timeline/timelinecommon.h" #include "timelineviewblockitem.h" #include "timelineviewrect.h" OLIVE_NAMESPACE_ENTER /** * @brief A graphical representation of changes the user is making before they apply it */ class TimelineViewGhostItem : public TimelineViewRect { public: enum DataType { kAttachedBlock, kReferenceBlock, kAttachedFootage }; TimelineViewGhostItem(QGraphicsItem* parent = nullptr); static TimelineViewGhostItem* FromBlock(Block *block, const TrackReference &track, int y, int height); bool CanHaveZeroLength() const; bool CanMoveTracks() const; void SetCanMoveTracks(bool e); void SetInvisible(bool invisible); const rational& In() const; const rational& Out() const; const rational& MediaIn() const; rational Length() const; rational AdjustedLength() const; void SetIn(const rational& in); void SetOut(const rational& out); void SetMediaIn(const rational& media_in); void SetInAdjustment(const rational& in_adj); void SetOutAdjustment(const rational& out_adj); void SetTrackAdjustment(const int& track_adj); void SetMediaInAdjustment(const rational& media_in_adj); const rational& InAdjustment() const; const rational& OutAdjustment() const; const rational& MediaInAdjustment() const; const int& TrackAdjustment() const; rational GetAdjustedIn() const; rational GetAdjustedOut() const; rational GetAdjustedMediaIn() const; TrackReference GetAdjustedTrack() const; const Timeline::MovementMode& mode() const; void SetMode(const Timeline::MovementMode& mode); bool HasBeenAdjusted() const; virtual void UpdateRect() override; protected: private: rational in_; rational out_; rational media_in_; rational in_adj_; rational out_adj_; rational media_in_adj_; int track_adj_; StreamPtr stream_; Timeline::MovementMode mode_; bool can_have_zero_length_; bool can_move_tracks_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEVIEWGHOSTITEM_H olive-continuous/app/widget/timelinewidget/view/timelineviewmouseevent.cpp000066400000000000000000000050601370472574300277640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineviewmouseevent.h" #include #include "widget/timelinewidget/timelinescaledobject.h" OLIVE_NAMESPACE_ENTER TimelineViewMouseEvent::TimelineViewMouseEvent(const qreal &scene_x, const double &scale_x, const rational &timebase, const TrackReference &track, const Qt::MouseButton &button, const Qt::KeyboardModifiers &modifiers) : scene_x_(scene_x), scale_x_(scale_x), timebase_(timebase), track_(track), button_(button), modifiers_(modifiers), source_event_(nullptr), mime_data_(nullptr) { } TimelineCoordinate TimelineViewMouseEvent::GetCoordinates(bool round_time) const { return TimelineCoordinate(GetFrame(round_time), track_); } const Qt::KeyboardModifiers TimelineViewMouseEvent::GetModifiers() const { return modifiers_; } rational TimelineViewMouseEvent::GetFrame(bool round) const { return TimelineScaledObject::SceneToTime(scene_x_, scale_x_, timebase_, round); } const TrackReference &TimelineViewMouseEvent::GetTrack() const { return track_; } const QMimeData* TimelineViewMouseEvent::GetMimeData() { return mime_data_; } void TimelineViewMouseEvent::SetMimeData(const QMimeData *data) { mime_data_ = data; } void TimelineViewMouseEvent::SetEvent(QEvent *event) { source_event_ = event; } const qreal &TimelineViewMouseEvent::GetSceneX() const { return scene_x_; } const Qt::MouseButton &TimelineViewMouseEvent::GetButton() const { return button_; } void TimelineViewMouseEvent::accept() { if (source_event_ != nullptr) source_event_->accept(); } void TimelineViewMouseEvent::ignore() { if (source_event_ != nullptr) source_event_->ignore(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/timelineviewmouseevent.h000066400000000000000000000045431370472574300274360ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEVIEWMOUSEEVENT_H #define TIMELINEVIEWMOUSEEVENT_H #include #include #include #include "timeline/timelinecoordinate.h" OLIVE_NAMESPACE_ENTER class TimelineViewMouseEvent { public: TimelineViewMouseEvent(const qreal& scene_x, const double& scale_x, const rational& timebase, const TrackReference &track, const Qt::MouseButton &button, const Qt::KeyboardModifiers& modifiers = Qt::NoModifier); TimelineCoordinate GetCoordinates(bool round_time = false) const; const Qt::KeyboardModifiers GetModifiers() const; /** * @brief Gets the time at this cursor point * * @param round * * If set to true, the time will be rounded to the nearest time. If set to false, the time is floored so the time is * always to the left of the cursor. The former behavior is better for clicking between frames (e.g. razor tool) and * the latter is better for clicking directly on frames (e.g. pointer tool). */ rational GetFrame(bool round = false) const; const TrackReference& GetTrack() const; const QMimeData *GetMimeData(); void SetMimeData(const QMimeData *data); void SetEvent(QEvent* event); const qreal& GetSceneX() const; const Qt::MouseButton& GetButton() const; void accept(); void ignore(); private: qreal scene_x_; double scale_x_; rational timebase_; TrackReference track_; Qt::MouseButton button_; Qt::KeyboardModifiers modifiers_; QEvent* source_event_; const QMimeData* mime_data_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEVIEWMOUSEEVENT_H olive-continuous/app/widget/timelinewidget/view/timelineviewrect.cpp000066400000000000000000000026311370472574300265300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timelineviewrect.h" OLIVE_NAMESPACE_ENTER TimelineViewRect::TimelineViewRect(QGraphicsItem* parent) : QGraphicsRectItem(parent), y_(0), height_(0) { } void TimelineViewRect::SetYCoords(int y, int height) { y_ = y; height_ = height; UpdateRect(); } const TrackReference &TimelineViewRect::Track() { return track_; } void TimelineViewRect::SetTrack(const TrackReference &track) { track_ = track; } void TimelineViewRect::ScaleChangedEvent(const double &scale) { TimelineScaledObject::ScaleChangedEvent(scale); UpdateRect(); } void TimelineViewRect::TimebaseChangedEvent(const rational &tb) { TimelineScaledObject::TimebaseChangedEvent(tb); UpdateRect(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timelinewidget/view/timelineviewrect.h000066400000000000000000000027511370472574300262000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMELINEVIEWRECT_H #define TIMELINEVIEWRECT_H #include #include "timeline/timelinecoordinate.h" #include "../timelinescaledobject.h" OLIVE_NAMESPACE_ENTER /** * @brief A base class for graphical representations of Block nodes */ class TimelineViewRect : public QGraphicsRectItem, public TimelineScaledObject { public: TimelineViewRect(QGraphicsItem* parent = nullptr); void SetYCoords(int y, int height); const TrackReference& Track(); void SetTrack(const TrackReference& track); virtual void UpdateRect() = 0; protected: virtual void ScaleChangedEvent(const double &) override; virtual void TimebaseChangedEvent(const rational&) override; int y_; int height_; TrackReference track_; }; OLIVE_NAMESPACE_EXIT #endif // TIMELINEVIEWRECT_H olive-continuous/app/widget/timeruler/000077500000000000000000000000001370472574300204675ustar00rootroot00000000000000olive-continuous/app/widget/timeruler/CMakeLists.txt000066400000000000000000000015771370472574300232410ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timeruler/seekablewidget.h widget/timeruler/seekablewidget.cpp widget/timeruler/timeruler.h widget/timeruler/timeruler.cpp PARENT_SCOPE ) olive-continuous/app/widget/timeruler/seekablewidget.cpp000066400000000000000000000145421370472574300241600ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "seekablewidget.h" #include #include #include #include "common/qtutils.h" #include "core.h" OLIVE_NAMESPACE_ENTER SeekableWidget::SeekableWidget(QWidget* parent) : TimelineScaledWidget(parent), time_(0), timeline_points_(nullptr), scroll_(0), snap_service_(nullptr) { QFontMetrics fm = fontMetrics(); text_height_ = fm.height(); // Set width of playhead marker playhead_width_ = QFontMetricsWidth(fm, "H"); } void SeekableWidget::ConnectTimelinePoints(TimelinePoints *points) { if (timeline_points_) { disconnect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast(&SeekableWidget::update)); disconnect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&SeekableWidget::update)); } timeline_points_ = points; if (timeline_points_) { connect(timeline_points_->workarea(), &TimelineWorkArea::RangeChanged, this, static_cast(&SeekableWidget::update)); connect(timeline_points_->workarea(), &TimelineWorkArea::EnabledChanged, this, static_cast(&SeekableWidget::update)); } update(); } void SeekableWidget::SetSnapService(SnapService *service) { snap_service_ = service; } const int64_t &SeekableWidget::GetTime() const { return time_; } const int &SeekableWidget::GetScroll() const { return scroll_; } void SeekableWidget::mousePressEvent(QMouseEvent *event) { SeekToScreenPoint(event->pos().x()); } void SeekableWidget::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { SeekToScreenPoint(event->pos().x()); } } void SeekableWidget::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event) if (snap_service_) { snap_service_->HideSnaps(); } } void SeekableWidget::ScaleChangedEvent(const double &) { update(); } TimelinePoints *SeekableWidget::timeline_points() const { return timeline_points_; } void SeekableWidget::SetTime(const int64_t &r) { time_ = r; update(); } void SeekableWidget::SetScroll(int s) { scroll_ = s; update(); } double SeekableWidget::ScreenToUnitFloat(int screen) { return (screen + scroll_) / GetScale() / timebase_dbl(); } int64_t SeekableWidget::ScreenToUnit(int screen) { return qFloor(ScreenToUnitFloat(screen)); } int64_t SeekableWidget::ScreenToUnitRounded(int screen) { return qRound64(ScreenToUnitFloat(screen)); } int SeekableWidget::UnitToScreen(int64_t unit) { return qFloor(static_cast(unit) * GetScale() * timebase_dbl()) - scroll_; } int SeekableWidget::TimeToScreen(const rational &time) { return qFloor(time.toDouble() * GetScale()) - scroll_; } void SeekableWidget::SeekToScreenPoint(int screen) { int64_t timestamp = qMax(static_cast(0), ScreenToUnitRounded(screen)); if (Core::instance()->snapping() && snap_service_) { rational playhead_time = Timecode::timestamp_to_time(timestamp, timebase()); rational movement; snap_service_->SnapPoint({playhead_time}, &movement, SnapService::kSnapAll & ~SnapService::kSnapToPlayhead); if (!movement.isNull()) { timestamp = Timecode::time_to_timestamp(playhead_time + movement, timebase()); } } SetTime(timestamp); emit TimeChanged(timestamp); } void SeekableWidget::DrawTimelinePoints(QPainter* p, int marker_bottom) { if (!timeline_points()) { return; } // Draw in/out workarea if (timeline_points()->workarea()->enabled()) { int workarea_left = qMax(0, TimeToScreen(timeline_points()->workarea()->in())); int workarea_right; if (timeline_points()->workarea()->out() == TimelineWorkArea::kResetOut) { workarea_right = width(); } else { workarea_right = qMin(width(), TimeToScreen(timeline_points()->workarea()->out())); } p->fillRect(workarea_left, 0, workarea_right - workarea_left, height(), palette().highlight()); } // Draw markers if (marker_bottom > 0 && !timeline_points()->markers()->list().isEmpty()) { int marker_top = marker_bottom - text_height_; // FIXME: Hardcoded marker colors p->setPen(Qt::black); p->setBrush(Qt::green); foreach (TimelineMarker* marker, timeline_points()->markers()->list()) { int marker_left = TimeToScreen(marker->time().in()); int marker_right = TimeToScreen(marker->time().out()); if (marker_left >= width() || marker_right < 0) { continue; } if (marker->time().length() == 0) { // Single point in time marker DrawPlayhead(p, marker_left, marker_bottom); } else { // Marker range int rect_left = qMax(0, marker_left); int rect_right = qMin(width(), marker_right); QRect marker_rect(rect_left, marker_top, rect_right - rect_left, marker_bottom - marker_top); p->drawRect(marker_rect); if (!marker->name().isEmpty()) { p->drawText(marker_rect, marker->name()); } } } } } void SeekableWidget::DrawPlayhead(QPainter *p, int x, int y) { int half_width = playhead_width_ / 2; if (x + half_width < 0 || x - half_width > width()) { return; } p->setRenderHint(QPainter::Antialiasing); int half_text_height = text_height() / 3; QPoint points[] = { QPoint(x, y), QPoint(x - half_width, y - half_text_height), QPoint(x - half_width, y - text_height()), QPoint(x + 1 + half_width, y - text_height()), QPoint(x + 1 + half_width, y - half_text_height), QPoint(x + 1, y), }; p->drawPolygon(points, 6); p->setRenderHint(QPainter::Antialiasing, false); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timeruler/seekablewidget.h000066400000000000000000000053261370472574300236250ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef SEEKABLEWIDGET_H #define SEEKABLEWIDGET_H #include "common/rational.h" #include "timeline/timelinepoints.h" #include "widget/timelinewidget/snapservice.h" #include "widget/timelinewidget/view/timelineplayhead.h" #include "widget/timelinewidget/timelinescaledobject.h" OLIVE_NAMESPACE_ENTER class SeekableWidget : public TimelineScaledWidget { Q_OBJECT public: SeekableWidget(QWidget *parent = nullptr); const int64_t& GetTime() const; const int& GetScroll() const; void ConnectTimelinePoints(TimelinePoints* points); void SetSnapService(SnapService* service); public slots: void SetTime(const int64_t &r); void SetScroll(int s); protected: void SeekToScreenPoint(int screen); virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; virtual void mouseReleaseEvent(QMouseEvent *event) override; virtual void ScaleChangedEvent(const double&) override; void DrawTimelinePoints(QPainter *p, int marker_bottom = 0); TimelinePoints* timeline_points() const; double ScreenToUnitFloat(int screen); int64_t ScreenToUnit(int screen); int64_t ScreenToUnitRounded(int screen); int UnitToScreen(int64_t unit); int TimeToScreen(const rational& time); void DrawPlayhead(QPainter* p, int x, int y); inline const int& text_height() const { return text_height_; } inline const int& playhead_width() const { return playhead_width_; } inline const QColor& GetPlayheadColor() const { return style_.GetPlayheadColor(); } inline const QColor& GetPlayheadHighlightColor() const { return style_.GetPlayheadHighlightColor(); } signals: /** * @brief Signal emitted whenever the time changes on this ruler, either by user or programmatically */ void TimeChanged(int64_t); private: int64_t time_; TimelinePlayhead style_; TimelinePoints* timeline_points_; int scroll_; int text_height_; int playhead_width_; SnapService* snap_service_; }; OLIVE_NAMESPACE_EXIT #endif // SEEKABLEWIDGET_H olive-continuous/app/widget/timeruler/timeruler.cpp000066400000000000000000000221751370472574300232120ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timeruler.h" #include #include #include "common/timecodefunctions.h" #include "common/qtutils.h" #include "config/config.h" #include "core.h" OLIVE_NAMESPACE_ENTER TimeRuler::TimeRuler(bool text_visible, bool cache_status_visible, QWidget* parent) : SeekableWidget(parent), text_visible_(text_visible), centered_text_(true), show_cache_status_(cache_status_visible), playback_cache_(nullptr) { QFontMetrics fm = fontMetrics(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); // Text height is used to calculate widget height cache_status_height_ = text_height() / 4; // Get the "minimum" space allowed between two line markers on the ruler (in screen pixels) // Mediocre but reliable way of scaling UI objects by font/DPI size minimum_gap_between_lines_ = QFontMetricsWidth(fm, "H"); // Text visibility affects height, so we set that here UpdateHeight(); // Force update if the default timecode display mode changes connect(Core::instance(), &Core::TimecodeDisplayChanged, this, static_cast(&TimeRuler::update)); } void TimeRuler::SetPlaybackCache(PlaybackCache *cache) { if (!show_cache_status_) { return; } if (playback_cache_) { disconnect(playback_cache_, &PlaybackCache::Invalidated, this, static_cast(&TimeRuler::update)); disconnect(playback_cache_, &PlaybackCache::Validated, this, static_cast(&TimeRuler::update)); disconnect(playback_cache_, &PlaybackCache::LengthChanged, this, static_cast(&TimeRuler::update)); } playback_cache_ = cache; if (playback_cache_) { connect(playback_cache_, &PlaybackCache::Invalidated, this, static_cast(&TimeRuler::update)); connect(playback_cache_, &PlaybackCache::Validated, this, static_cast(&TimeRuler::update)); connect(playback_cache_, &PlaybackCache::LengthChanged, this, static_cast(&TimeRuler::update)); } update(); } void TimeRuler::paintEvent(QPaintEvent *) { // Nothing to paint if the timebase is invalid if (timebase().isNull()) { return; } QPainter p(this); // Draw timeline points if connected if (timeline_points()) { int marker_bottom = height() - text_height(); if (show_cache_status_) { marker_bottom -= cache_status_height_; } if (text_visible_) { marker_bottom -= cache_status_height_; } DrawTimelinePoints(&p, marker_bottom); } double width_of_frame = timebase_dbl() * GetScale(); double width_of_second = 0; do { width_of_second += timebase_dbl(); } while (width_of_second < 1.0); width_of_second *= GetScale(); double width_of_minute = width_of_second * 60; double width_of_hour = width_of_minute * 60; double width_of_day = width_of_hour * 24; double long_interval, short_interval; int long_rate = 0; // Used for comparison, even if one unit can technically fit, we have to fit at least two for it to matter int doubled_gap = minimum_gap_between_lines_ * 2; if (width_of_day < doubled_gap) { long_interval = -1; short_interval = width_of_day; } else if (width_of_hour < doubled_gap) { long_interval = width_of_day; long_rate = 24; short_interval = width_of_hour; } else if (width_of_minute < doubled_gap) { long_interval = width_of_hour; long_rate = 60; short_interval = width_of_minute; } else if (width_of_second < doubled_gap) { long_interval = width_of_minute; long_rate = 60; short_interval = width_of_second; } else if (width_of_frame < doubled_gap) { long_interval = width_of_second; long_rate = qRound(timebase_flipped_dbl_); short_interval = width_of_frame; } else { // FIXME: Implement this... long_interval = width_of_second; short_interval = width_of_frame; } if (short_interval < minimum_gap_between_lines_) { if (long_interval <= 0) { do { short_interval *= 2; } while (short_interval < minimum_gap_between_lines_); } else { int div; short_interval = long_interval; for (div=long_rate;div>0;div--) { if (long_rate%div == 0) { // This division produces a whole number double test_frame_width = long_interval / static_cast(div); if (test_frame_width >= minimum_gap_between_lines_) { short_interval = test_frame_width; break; } } } } } // Set line color to main text color p.setBrush(Qt::NoBrush); p.setPen(palette().text().color()); // Calculate line dimensions QFontMetrics fm = p.fontMetrics(); int line_bottom = height(); if (show_cache_status_) { line_bottom -= cache_status_height_; } int long_height = fm.height(); int short_height = long_height/2; int long_y = line_bottom - long_height; int short_y = line_bottom - short_height; // Draw long lines int last_long_unit = -1; int last_short_unit = -1; int last_text_draw = INT_MIN; // FIXME: Hardcoded number const int kAverageTextWidth = 200; for (int i=-kAverageTextWidth;i(i + GetScroll()); if (long_interval > -1) { int this_long_unit = qFloor(screen_pt/long_interval); if (this_long_unit != last_long_unit) { int line_y = long_y; if (text_visible_) { QRect text_rect; Qt::Alignment text_align; QString timecode_str = Timecode::timestamp_to_timecode(ScreenToUnit(i), timebase(), Core::instance()->GetTimecodeDisplay()); int timecode_width = QFontMetricsWidth(fm, timecode_str); int timecode_left; if (centered_text_) { text_rect = QRect(i - kAverageTextWidth/2, 0, kAverageTextWidth, fm.height()); text_align = Qt::AlignCenter; timecode_left = i - timecode_width/2; } else { text_rect = QRect(i, 0, kAverageTextWidth, fm.height()); text_align = Qt::AlignLeft | Qt::AlignVCenter; timecode_left = i; // Add gap to left between line and text timecode_str.prepend(' '); } if (timecode_left > last_text_draw) { p.drawText(text_rect, static_cast(text_align), timecode_str); last_text_draw = timecode_left + timecode_width; if (!centered_text_) { line_y = 0; } } } p.drawLine(i, line_y, i, line_bottom); last_long_unit = this_long_unit; } } if (short_interval > -1) { int this_short_unit = qFloor(screen_pt/short_interval); if (this_short_unit != last_short_unit) { p.drawLine(i, short_y, i, line_bottom); last_short_unit = this_short_unit; } } } // If cache status is enabled if (show_cache_status_ && playback_cache_) { int cache_screen_length = qMin(TimeToScreen(playback_cache_->GetLength()), width()); if (cache_screen_length > 0) { int cache_y = height() - cache_status_height_; p.fillRect(0, cache_y, cache_screen_length , cache_status_height_, Qt::green); foreach (const TimeRange& range, playback_cache_->GetInvalidatedRanges()) { int range_left = TimeToScreen(range.in()); if (range_left >= width()) { continue; } int range_right = TimeToScreen(range.out()); if (range_right < 0) { continue; } int adjusted_left = qMax(0, range_left); p.fillRect(adjusted_left, cache_y, qMin(width(), range_right) - adjusted_left, cache_status_height_, Qt::red); } } } // Draw the playhead if it's on screen at the moment int playhead_pos = UnitToScreen(GetTime()); p.setPen(Qt::NoPen); p.setBrush(GetPlayheadColor()); DrawPlayhead(&p, playhead_pos, line_bottom); } void TimeRuler::TimebaseChangedEvent(const rational &tb) { timebase_flipped_dbl_ = tb.flipped().toDouble(); update(); } int TimeRuler::CacheStatusHeight() const { return fontMetrics().height() / 4; } void TimeRuler::UpdateHeight() { int height = text_height(); // Add text height if (text_visible_) { height += text_height(); } // Add cache status height if (show_cache_status_) { height += cache_status_height_; } // Add marker height height += text_height(); setFixedHeight(height); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timeruler/timeruler.h000066400000000000000000000031041370472574300226460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMERULER_H #define TIMERULER_H #include #include #include "common/timerange.h" #include "seekablewidget.h" #include "render/playbackcache.h" OLIVE_NAMESPACE_ENTER class TimeRuler : public SeekableWidget { Q_OBJECT public: TimeRuler(bool text_visible = true, bool cache_status_visible = false, QWidget* parent = nullptr); void SetCenteredText(bool c); void SetPlaybackCache(PlaybackCache* cache); protected: virtual void paintEvent(QPaintEvent* e) override; virtual void TimebaseChangedEvent(const rational& tb) override; private: void UpdateHeight(); int CacheStatusHeight() const; int cache_status_height_; int minimum_gap_between_lines_; bool text_visible_; bool centered_text_; double timebase_flipped_dbl_; bool show_cache_status_; PlaybackCache* playback_cache_; }; OLIVE_NAMESPACE_EXIT #endif // TIMERULER_H olive-continuous/app/widget/timetarget/000077500000000000000000000000001370472574300206245ustar00rootroot00000000000000olive-continuous/app/widget/timetarget/CMakeLists.txt000066400000000000000000000014711370472574300233670ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/timetarget/timetarget.h widget/timetarget/timetarget.cpp PARENT_SCOPE ) olive-continuous/app/widget/timetarget/timetarget.cpp000066400000000000000000000036401370472574300235000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "timetarget.h" OLIVE_NAMESPACE_ENTER TimeTargetObject::TimeTargetObject() : time_target_(nullptr), path_index_(0) { } Node *TimeTargetObject::GetTimeTarget() const { return time_target_; } void TimeTargetObject::SetTimeTarget(Node *target) { time_target_ = target; TimeTargetChangedEvent(time_target_); } void TimeTargetObject::SetPathIndex(int index) { path_index_ = index; } rational TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const rational &r, NodeParam::Type direction) const { if (!from || !to) { return r; } return GetAdjustedTime(from, to, TimeRange(r, r), direction).in(); } TimeRange TimeTargetObject::GetAdjustedTime(Node* from, Node* to, const TimeRange &r, NodeParam::Type direction) const { if (!from || !to) { return r; } QList adjusted = from->TransformTimeTo(r, to, direction); if (adjusted.isEmpty()) { return r; } return adjusted.at(path_index_); } /*int TimeTargetObject::GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const { if (!time_target_) { return 0; } QList adjusted = from->TransformTimeTo(TimeRange(), time_target_, direction); return adjusted.size(); }*/ OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/timetarget/timetarget.h000066400000000000000000000026231370472574300231450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TIMETARGETOBJECT_H #define TIMETARGETOBJECT_H #include "node/node.h" OLIVE_NAMESPACE_ENTER class TimeTargetObject { public: TimeTargetObject(); Node* GetTimeTarget() const; void SetTimeTarget(Node* target); void SetPathIndex(int index); rational GetAdjustedTime(Node* from, Node* to, const rational& r, NodeParam::Type direction) const; TimeRange GetAdjustedTime(Node* from, Node* to, const TimeRange& r, NodeParam::Type direction) const; //int GetNumberOfPathAdjustments(Node* from, NodeParam::Type direction) const; protected: virtual void TimeTargetChangedEvent(Node* ){} private: Node* time_target_; int path_index_; }; OLIVE_NAMESPACE_EXIT #endif // TIMETARGETOBJECT_H olive-continuous/app/widget/toolbar/000077500000000000000000000000001370472574300201215ustar00rootroot00000000000000olive-continuous/app/widget/toolbar/CMakeLists.txt000066400000000000000000000015611370472574300226640ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/toolbar/toolbar.h widget/toolbar/toolbar.cpp widget/toolbar/toolbarbutton.h widget/toolbar/toolbarbutton.cpp PARENT_SCOPE ) olive-continuous/app/widget/toolbar/toolbar.cpp000066400000000000000000000136701370472574300222760ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "toolbar.h" #include #include #include #include #include "node/factory.h" #include "ui/icons/icons.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER Toolbar::Toolbar(QWidget *parent) : QWidget(parent) { layout_ = new FlowLayout(this); layout_->setMargin(0); // Create standard tool buttons btn_pointer_tool_ = CreateToolButton(Tool::kPointer); btn_edit_tool_ = CreateToolButton(Tool::kEdit); btn_ripple_tool_ = CreateToolButton(Tool::kRipple); btn_rolling_tool_ = CreateToolButton(Tool::kRolling); btn_razor_tool_ = CreateToolButton(Tool::kRazor); btn_slip_tool_ = CreateToolButton(Tool::kSlip); btn_slide_tool_ = CreateToolButton(Tool::kSlide); btn_hand_tool_ = CreateToolButton(Tool::kHand); btn_zoom_tool_ = CreateToolButton(Tool::kZoom); btn_record_ = CreateToolButton(Tool::kRecord); btn_transition_tool_ = CreateToolButton(Tool::kTransition); btn_add_ = CreateToolButton(Tool::kAdd); // Create snapping button, which is not actually a tool, it's a toggle option btn_snapping_toggle_ = CreateNonToolButton(); connect(btn_snapping_toggle_, &QPushButton::clicked, this, &Toolbar::SnappingButtonClicked); // Connect transition button to menu signal connect(btn_transition_tool_, &QPushButton::clicked, this, &Toolbar::TransitionButtonClicked); // Connect add button to menu signal connect(btn_add_, &QPushButton::clicked, this, &Toolbar::AddButtonClicked); Retranslate(); UpdateIcons(); } void Toolbar::SetTool(const Tool::Item& tool) { // For each tool, set the "checked" state to whether the button's tool is the current tool for (int i=0;isetChecked(btn->tool() == tool); } } void Toolbar::SetSnapping(const bool& snapping) { // Set checked state of snapping toggle btn_snapping_toggle_->setChecked(snapping); } void Toolbar::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); } else if (e->type() == QEvent::StyleChange) { UpdateIcons(); } QWidget::changeEvent(e); } void Toolbar::Retranslate() { btn_pointer_tool_->setToolTip(tr("Pointer Tool")); btn_edit_tool_->setToolTip(tr("Edit Tool")); btn_ripple_tool_->setToolTip(tr("Ripple Tool")); btn_rolling_tool_->setToolTip(tr("Rolling Tool")); btn_razor_tool_->setToolTip(tr("Razor Tool")); btn_slip_tool_->setToolTip(tr("Slip Tool")); btn_slide_tool_->setToolTip(tr("Slide Tool")); btn_hand_tool_->setToolTip(tr("Hand Tool")); btn_zoom_tool_->setToolTip(tr("Zoom Tool")); btn_transition_tool_->setToolTip(tr("Transition Tool")); btn_record_->setToolTip(tr("Record Tool")); btn_add_->setToolTip(tr("Add Tool")); btn_snapping_toggle_->setToolTip(tr("Toggle Snapping")); } void Toolbar::UpdateIcons() { btn_pointer_tool_->setIcon(icon::ToolPointer); btn_edit_tool_->setIcon(icon::ToolEdit); btn_ripple_tool_->setIcon(icon::ToolRipple); btn_rolling_tool_->setIcon(icon::ToolRolling); btn_razor_tool_->setIcon(icon::ToolRazor); btn_slip_tool_->setIcon(icon::ToolSlip); btn_slide_tool_->setIcon(icon::ToolSlide); btn_hand_tool_->setIcon(icon::ToolHand); btn_zoom_tool_->setIcon(icon::ZoomIn); btn_record_->setIcon(icon::Record); btn_transition_tool_->setIcon(icon::ToolTransition); btn_add_->setIcon(icon::Add); btn_snapping_toggle_->setIcon(icon::Snapping); } ToolbarButton* Toolbar::CreateToolButton(const Tool::Item& tool) { // Create a ToolbarButton object ToolbarButton* b = new ToolbarButton(this, tool); // Add it to the layout layout_->addWidget(b); // Add it to the list for iterating through later toolbar_btns_.append(b); // Connect it to the tool button click handler connect(b, SIGNAL(clicked(bool)), this, SLOT(ToolButtonClicked())); return b; } ToolbarButton *Toolbar::CreateNonToolButton() { // Create a ToolbarButton object ToolbarButton* b = new ToolbarButton(this, Tool::kNone); // Add it to the layout layout_->addWidget(b); return b; } void Toolbar::ToolButtonClicked() { // Get new tool from ToolbarButton object Tool::Item new_tool = static_cast(sender())->tool(); // Set checked state of all tool buttons // NOTE: Not necessary if this is appropriately connected to Core //SetTool(new_tool); // Emit signal that the tool just changed emit ToolChanged(new_tool); } void Toolbar::SnappingButtonClicked(bool b) { emit SnappingChanged(b); } void Toolbar::AddButtonClicked() { Menu m(this); for (int i=0;i(i))); action->setData(i); } connect(&m, &QMenu::triggered, this, &Toolbar::AddMenuItemTriggered); m.exec(QCursor::pos()); } void Toolbar::TransitionButtonClicked() { Menu* m = NodeFactory::CreateMenu(this, false, Node::kCategoryTransition); connect(m, &QMenu::triggered, this, &Toolbar::TransitionMenuItemTriggered); m->exec(QCursor::pos()); delete m; } void Toolbar::AddMenuItemTriggered(QAction* a) { emit AddableObjectChanged(static_cast(a->data().toInt())); } void Toolbar::TransitionMenuItemTriggered(QAction *a) { emit SelectedTransitionChanged(NodeFactory::GetIDFromMenuAction(a)); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/toolbar/toolbar.h000066400000000000000000000153521370472574300217420ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TOOLBAR_H #define TOOLBAR_H #include #include "widget/flowlayout/flowlayout.h" #include "widget/toolbar/toolbarbutton.h" #include "tool/tool.h" OLIVE_NAMESPACE_ENTER /** * @brief A widget containing buttons for all of Olive's application-wide tools. * * Buttons are displayed in a FlowLayout that * adjusts and wraps (like text) depending on the widget's size. * * By default, this Toolbar is not connected to anything. It's recommended to connect SLOT(SetTool()) and * SIGNAL(ToolChanged()) to Core (corresponding SIGNAL(ToolChanged()) and SLOT(SetTool()) respectively) so that the * Toolbar updates the current tool application-wide, and is also automatically updated when the tool is changed * elsewhere. */ class Toolbar : public QWidget { Q_OBJECT public: /** * @brief Toolbar Constructor * * Creates and connects all the Toolbar buttons * * @param parent * * QWidget parent. */ Toolbar(QWidget* parent); public slots: /** * @brief Set the tool to be displayed as "selected" * * This function does not set the application-wide tool, it only sets which tool show as selected in this widget. * It's recommended to use this function only as a slot connected to Core::ToolChanged() so that it automatically * updates whenever the application-wide tool is changed. * * @param tool * * Tool to show as selected */ void SetTool(const Tool::Item &tool); /** * @brief Set snapping checked value * * Similar to SetTool(), this does not set anything application-wide, it only changes the displayed button appearance. * In this case, whether the snapping button should show as snapping enabled or disabled. * * @param snapping */ void SetSnapping(const bool &snapping); protected: /** * @brief Qt changeEvent * * Overridden to catch language change events (see Retranslate()) * * @param e */ virtual void changeEvent(QEvent* e) override; signals: /** * @brief Emitted whenever a tool is selected using this widget * * @param t * * Tool that was selected */ void ToolChanged(const Tool::Item& t); /** * @brief Emitted whenever the snapping setting is changed * * @param b * * New snapping enabled setting */ void SnappingChanged(const bool& b); /** * @brief Emitted when the addable object is changed from the add tool menu */ void AddableObjectChanged(const Tool::AddableObject& obj); /** * @brief Emitted when the selected transition is changed from the transition tool menu */ void SelectedTransitionChanged(const QString& id); private: /** * @brief Reset all strings based on the currently selected language */ void Retranslate(); /** * @brief Update icons after a style change */ void UpdateIcons(); /** * @brief Internal convenience function for creating tool buttons quickly * * This function will create a ToolbarButton object, set the icon to `icon`, set its tool value to `tool`, add it to * the widget layout, add it to toolbar_btns_ so the buttons can be iterated (done in various functions), and connect * the button to ToolButtonClicked(). * * If you need a non-tool but similarly styled button, use CreateNonToolButton(). * * @return * * The created ToolbarButton. The button parent is automatically set to `this`. */ ToolbarButton* CreateToolButton(const Tool::Item& tool); /** * @brief Internal convenience function for creating buttons quickly * * Similar to CreateToolButton() but doesn't add the button to toolbar_btns_ and doesn't connect the button to * ToolButtonClicked(). This is to create a button that is similarly styled but doesn't actually represent a tool * per se. * * @return * * The created ToolbarButton. The button parent is automatically set to `this`. */ ToolbarButton* CreateNonToolButton(); /** * @brief Internal layout used for buttons */ FlowLayout* layout_; /** * @brief Array/list of toolbar buttons * * This list is automatically appended by CreateToolButton(). It's used to iterate through the toolbar buttons * quickly with for loops, etc. See SetTool() for example usage. */ QList toolbar_btns_; ToolbarButton* btn_pointer_tool_; ToolbarButton* btn_edit_tool_; ToolbarButton* btn_ripple_tool_; ToolbarButton* btn_rolling_tool_; ToolbarButton* btn_razor_tool_; ToolbarButton* btn_slip_tool_; ToolbarButton* btn_slide_tool_; ToolbarButton* btn_hand_tool_; ToolbarButton* btn_transition_tool_; ToolbarButton* btn_zoom_tool_; ToolbarButton* btn_record_; ToolbarButton* btn_add_; ToolbarButton* btn_snapping_toggle_; private slots: /** * @brief Slot for a ToolbarButton being clicked * * ToolbarButtons created from CreateToolButton() are automatically connected to this slot. * This slot will receive the ToolbarButton's tool value * and emit a signal indicating that the tool has changed to the newly selected tool. This function static_casts * the sender to ToolbarButton so you should not connect any other class type to this slot. */ void ToolButtonClicked(); /** * @brief Receiver for the snapping toggle button * * This function's primary purpose is to emit SnappingChanged() and should be connected to the ToolbarButton's * SIGNAL(clicked(bool)). * * @param b * * The new snapping value received from the sender's clicked signal */ void SnappingButtonClicked(bool b); /** * @brief Receiver for the add button * * The add button pops up a list for which object to create. */ void AddButtonClicked(); /** * @brief Receiver for the transition button * * The transition button pops up a list for which transition to create. */ void TransitionButtonClicked(); /** * @brief Receiver for the menu created by AddButtonClicked() */ void AddMenuItemTriggered(QAction* a); /** * @brief Receiver for the menu created by TransitionButtonClicked() */ void TransitionMenuItemTriggered(QAction* a); }; OLIVE_NAMESPACE_EXIT #endif // TOOLBAR_H olive-continuous/app/widget/toolbar/toolbarbutton.cpp000066400000000000000000000017251370472574300235300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "toolbarbutton.h" OLIVE_NAMESPACE_ENTER ToolbarButton::ToolbarButton(QWidget *parent, const Tool::Item &tool) : QPushButton(parent), tool_(tool) { setCheckable(true); } const Tool::Item &ToolbarButton::tool() { return tool_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/toolbar/toolbarbutton.h000066400000000000000000000031471370472574300231750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef TOOLBARBUTTON_H #define TOOLBARBUTTON_H #include #include "tool/tool.h" OLIVE_NAMESPACE_ENTER /** * @brief Simple derived class of QPushButton to contain an Tool ID. Used as the main widget through Toolbar. */ class ToolbarButton : public QPushButton { public: /** * @brief ToolbarButton Constructor * * @param parent * * QWidget parent. Almost always an instance of Toolbar. * * @param tool * * Tool object. Must be a member of enum Tool::Item, including kNone if this button does not represent a tool. */ ToolbarButton(QWidget* parent, const Tool::Item& tool); /** * @brief Retrieve tool ID that this button represents * * Set in the constructor and shouldn't change throughout its lifetime. */ const Tool::Item& tool(); private: /** * @brief Internal tool value */ Tool::Item tool_; }; OLIVE_NAMESPACE_EXIT #endif // TOOLBARBUTTON_H olive-continuous/app/widget/viewer/000077500000000000000000000000001370472574300177605ustar00rootroot00000000000000olive-continuous/app/widget/viewer/CMakeLists.txt000066400000000000000000000025141370472574300225220ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} widget/viewer/audiowaveformview.h widget/viewer/audiowaveformview.cpp widget/viewer/footageviewer.h widget/viewer/footageviewer.cpp widget/viewer/gizmotraverser.h widget/viewer/gizmotraverser.cpp widget/viewer/viewer.h widget/viewer/viewer.cpp widget/viewer/viewerdisplay.h widget/viewer/viewerdisplay.cpp widget/viewer/viewerplaybacktimer.h widget/viewer/viewerplaybacktimer.cpp widget/viewer/viewerqueue.h widget/viewer/viewersafemargininfo.h widget/viewer/viewersizer.h widget/viewer/viewersizer.cpp widget/viewer/viewerwindow.h widget/viewer/viewerwindow.cpp PARENT_SCOPE ) olive-continuous/app/widget/viewer/audiowaveformview.cpp000066400000000000000000000100121370472574300242210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "audiowaveformview.h" #include #include #include #include "common/clamp.h" #include "config/config.h" OLIVE_NAMESPACE_ENTER AudioWaveformView::AudioWaveformView(QWidget *parent) : SeekableWidget(parent), playback_(nullptr) { setAutoFillBackground(true); setBackgroundRole(QPalette::Base); } void AudioWaveformView::SetViewer(AudioPlaybackCache *playback) { if (playback_) { disconnect(playback_, &AudioPlaybackCache::Validated, this, &AudioWaveformView::ForceUpdate); disconnect(playback_, &AudioPlaybackCache::ParametersChanged, this, &AudioWaveformView::BackendParamsChanged); SetTimebase(0); } playback_ = playback; if (playback_) { connect(playback_, &AudioPlaybackCache::Validated, this, &AudioWaveformView::ForceUpdate); connect(playback_, &AudioPlaybackCache::ParametersChanged, this, &AudioWaveformView::BackendParamsChanged); SetTimebase(playback_->GetParameters().time_base()); } ForceUpdate(); } void AudioWaveformView::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); const AudioParams& params = playback_->GetParameters(); if (!playback_ || playback_->GetCacheFilename().isEmpty() || !params.is_valid()) { return; } if (cached_size_ != size() || cached_scale_ != GetScale() || cached_scroll_ != GetScroll()) { cached_waveform_ = QPixmap(size()); cached_waveform_.fill(Qt::transparent); QFile fs(playback_->GetCacheFilename()); if (fs.open(QFile::ReadOnly)) { QPainter wave_painter(&cached_waveform_); // FIXME: Hardcoded color wave_painter.setPen(QColor(64, 255, 160)); int drew = 0; fs.seek(params.samples_to_bytes(ScreenToUnitRounded(0))); for (int x=0; x samples = AudioVisualWaveform::SumSamples(reinterpret_cast(read_buffer.constData()), samples_len, params.channel_count()); for (int i=0;iGetParameters().time_base()); } void AudioWaveformView::ForceUpdate() { cached_size_ = QSize(); update(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/audiowaveformview.h000066400000000000000000000030111370472574300236670ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef AUDIOWAVEFORMVIEW_H #define AUDIOWAVEFORMVIEW_H #include #include "audio/audiovisualwaveform.h" #include "render/audioparams.h" #include "render/audioplaybackcache.h" #include "widget/timeruler/seekablewidget.h" OLIVE_NAMESPACE_ENTER class AudioWaveformView : public SeekableWidget { Q_OBJECT public: AudioWaveformView(QWidget* parent = nullptr); //void SetData(const QString& file, const AudioRenderingParams& params); void SetViewer(AudioPlaybackCache *playback); protected: virtual void paintEvent(QPaintEvent* event) override; private: AudioPlaybackCache *playback_; QPixmap cached_waveform_; QSize cached_size_; double cached_scale_; int cached_scroll_; private slots: void BackendParamsChanged(); void ForceUpdate(); }; OLIVE_NAMESPACE_EXIT #endif // AUDIOWAVEFORMVIEW_H olive-continuous/app/widget/viewer/footageviewer.cpp000066400000000000000000000134431370472574300233370ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "footageviewer.h" #include #include #include "config/config.h" #include "project/project.h" OLIVE_NAMESPACE_ENTER FootageViewerWidget::FootageViewerWidget(QWidget *parent) : ViewerWidget(parent), footage_(nullptr) { video_node_ = new VideoInput(); audio_node_ = new AudioInput(); viewer_node_ = new ViewerOutput(); connect(display_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag); controls_->SetAudioVideoDragButtonsVisible(true); connect(controls_, &PlaybackControls::VideoPressed, this, &FootageViewerWidget::StartVideoDrag); connect(controls_, &PlaybackControls::AudioPressed, this, &FootageViewerWidget::StartAudioDrag); } Footage *FootageViewerWidget::GetFootage() const { return footage_; } void FootageViewerWidget::SetFootage(Footage *footage) { if (footage_) { cached_timestamps_.insert(footage_, GetTimestamp()); ConnectViewerNode(nullptr); NodeParam::DisconnectEdge(video_node_->output(), viewer_node_->texture_input()); NodeParam::DisconnectEdge(audio_node_->output(), viewer_node_->samples_input()); } footage_ = footage; if (footage_) { VideoStreamPtr video_stream = nullptr; AudioStreamPtr audio_stream = nullptr; foreach (StreamPtr s, footage_->streams()) { if (!audio_stream && s->type() == Stream::kAudio) { audio_stream = std::static_pointer_cast(s); } if (!video_stream && (s->type() == Stream::kVideo || s->type() == Stream::kImage)) { video_stream = std::static_pointer_cast(s); } if (audio_stream && video_stream) { break; } } viewer_node_->set_media_name(footage_->name()); if (video_stream) { video_node_->SetFootage(video_stream); viewer_node_->set_video_params(VideoParams(video_stream->width(), video_stream->height(), video_stream->frame_rate().flipped(), static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), VideoParams::generate_auto_divider(video_stream->width(), video_stream->height()))); NodeParam::ConnectEdge(video_node_->output(), viewer_node_->texture_input()); } else { int width = Config::Current()["DefaultSequenceWidth"].toInt(); int height = Config::Current()["DefaultSequenceHeight"].toInt(); viewer_node_->set_video_params(VideoParams(width, height, Config::Current()["DefaultSequenceFrameRate"].value(), static_cast(Config::Current()["DefaultSequencePreviewFormat"].toInt()), VideoParams::generate_auto_divider(width, height))); } if (audio_stream) { audio_node_->SetFootage(audio_stream); viewer_node_->set_audio_params(AudioParams(audio_stream->sample_rate(), audio_stream->channel_layout(), SampleFormat::kInternalFormat)); NodeParam::ConnectEdge(audio_node_->output(), viewer_node_->samples_input()); } else { viewer_node_->set_audio_params(AudioParams(Config::Current()["DefaultSequenceAudioFrequency"].toInt(), Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), SampleFormat::kInternalFormat)); } ConnectViewerNode(viewer_node_, footage_->project()->color_manager()); SetTimestamp(cached_timestamps_.value(footage_, 0)); } } TimelinePoints *FootageViewerWidget::ConnectTimelinePoints() { return footage_; } Project *FootageViewerWidget::GetTimelinePointsProject() { return footage_->project(); } void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enable_audio) { if (!GetFootage()) { return; } QDrag* drag = new QDrag(this); QMimeData* mimedata = new QMimeData(); QByteArray encoded_data; QDataStream stream(&encoded_data, QIODevice::WriteOnly); quint64 enabled_stream_flags = GetFootage()->get_enabled_stream_flags(); // Disable streams that have been disabled if (!enable_video || !enable_audio) { quint64 stream_disabler = 0x1; foreach (StreamPtr s, GetFootage()->streams()) { if ((s->type() == Stream::kVideo && !enable_video) || (s->type() == Stream::kAudio && !enable_audio)) { enabled_stream_flags &= ~stream_disabler; } stream_disabler <<= 1; } } stream << enabled_stream_flags << -1 << reinterpret_cast(GetFootage()); mimedata->setData("application/x-oliveprojectitemdata", encoded_data); drag->setMimeData(mimedata); drag->exec(); } void FootageViewerWidget::StartFootageDrag() { StartFootageDragInternal(true, true); } void FootageViewerWidget::StartVideoDrag() { StartFootageDragInternal(true, false); } void FootageViewerWidget::StartAudioDrag() { StartFootageDragInternal(false, true); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/footageviewer.h000066400000000000000000000031611370472574300230000ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef FOOTAGEVIEWERWIDGET_H #define FOOTAGEVIEWERWIDGET_H #include "node/input/media/audio/audio.h" #include "node/input/media/video/video.h" #include "node/output/viewer/viewer.h" #include "viewer.h" OLIVE_NAMESPACE_ENTER class FootageViewerWidget : public ViewerWidget { Q_OBJECT public: FootageViewerWidget(QWidget* parent = nullptr); Footage* GetFootage() const; void SetFootage(Footage* footage); protected: virtual TimelinePoints* ConnectTimelinePoints() override; virtual Project* GetTimelinePointsProject() override; private: void StartFootageDragInternal(bool enable_video, bool enable_audio); Footage* footage_; VideoInput* video_node_; AudioInput* audio_node_; ViewerOutput* viewer_node_; QHash cached_timestamps_; private slots: void StartFootageDrag(); void StartVideoDrag(); void StartAudioDrag(); }; OLIVE_NAMESPACE_EXIT #endif // FOOTAGEVIEWERWIDGET_H olive-continuous/app/widget/viewer/gizmotraverser.cpp000066400000000000000000000023101370472574300235430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "gizmotraverser.h" OLIVE_NAMESPACE_ENTER QVariant GizmoTraverser::ProcessVideoFootage(StreamPtr stream, const rational &input_time) { Q_UNUSED(input_time) ImageStreamPtr image_stream = std::static_pointer_cast(stream); return QSize(image_stream->width(), image_stream->height()); } QVariant GizmoTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job) { Q_UNUSED(node) Q_UNUSED(range) Q_UNUSED(job) return size_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/gizmotraverser.h000066400000000000000000000023741370472574300232220ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef GIZMOTRAVERSER_H #define GIZMOTRAVERSER_H #include "node/traverser.h" OLIVE_NAMESPACE_ENTER class GizmoTraverser : public NodeTraverser { public: GizmoTraverser(const QSize& sequence_resolution) : size_(sequence_resolution) { } protected: virtual QVariant ProcessVideoFootage(StreamPtr stream, const rational &input_time); virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job); // FIXME: Do something about audio? private: QSize size_; }; OLIVE_NAMESPACE_EXIT #endif // GIZMOTRAVERSER_H olive-continuous/app/widget/viewer/viewer.cpp000066400000000000000000001052641370472574300217750ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewer.h" #include #include #include #include #include #include #include #include #include #include "audio/audiomanager.h" #include "common/power.h" #include "common/timecodefunctions.h" #include "config/config.h" #include "project/item/sequence/sequence.h" #include "project/project.h" #include "render/pixelformat.h" #include "task/taskmanager.h" #include "widget/menu/menu.h" #include "window/mainwindow/mainwindow.h" OLIVE_NAMESPACE_ENTER const int kMaxPreQueueSize = 16; CacheTask* ViewerWidget::cache_background_task_ = nullptr; int ViewerWidget::busy_viewers_ = 0; ViewerWidget::ViewerWidget(QWidget *parent) : TimeBasedWidget(false, true, parent), playback_speed_(0), frame_cache_job_time_(0), color_menu_enabled_(true), override_color_manager_(nullptr), time_changed_from_timer_(false), prequeuing_(false), busy_(false), our_cache_background_task_(nullptr), autocache_(true) { // Set up main layout QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); // Set up stacked widget to allow switching away from the viewer widget stack_ = new QStackedWidget(); layout->addWidget(stack_); // Create main OpenGL-based view and sizer sizer_ = new ViewerSizer(); stack_->addWidget(sizer_); display_widget_ = new ViewerDisplayWidget(); connect(display_widget_, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); connect(display_widget_, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor); connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrix); sizer_->SetWidget(display_widget_); // Create waveform view when audio is connected and video isn't waveform_view_ = new AudioWaveformView(); stack_->addWidget(waveform_view_); // Create time ruler layout->addWidget(ruler()); // Create scrollbar layout->addWidget(scrollbar()); connect(scrollbar(), &QScrollBar::valueChanged, ruler(), &TimeRuler::SetScroll); connect(scrollbar(), &QScrollBar::valueChanged, waveform_view_, &AudioWaveformView::SetScroll); // Create lower controls controls_ = new PlaybackControls(); controls_->SetTimecodeEnabled(true); controls_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); connect(controls_, &PlaybackControls::PlayClicked, this, static_cast(&ViewerWidget::Play)); connect(controls_, &PlaybackControls::PauseClicked, this, &ViewerWidget::Pause); connect(controls_, &PlaybackControls::PrevFrameClicked, this, &ViewerWidget::PrevFrame); connect(controls_, &PlaybackControls::NextFrameClicked, this, &ViewerWidget::NextFrame); connect(controls_, &PlaybackControls::BeginClicked, this, &ViewerWidget::GoToStart); connect(controls_, &PlaybackControls::EndClicked, this, &ViewerWidget::GoToEnd); connect(controls_, &PlaybackControls::TimeChanged, this, &ViewerWidget::SetTimeAndSignal); layout->addWidget(controls_); // FIXME: Magic number SetScale(48.0); // Start background renderer renderer_ = new OpenGLBackend(this); renderer_->SetUpdateWithGraph(true); renderer_->SetRenderMode(RenderMode::kOffline); // Setup cache wait timer (waits a few seconds of inactivity before caching) cache_wait_timer_.setInterval(Config::Current()["AutoCacheInterval"].toInt()); cache_wait_timer_.setSingleShot(true); connect(&cache_wait_timer_, &QTimer::timeout, this, &ViewerWidget::StartBackgroundCaching); // Remove pointer to cache task if it's removed from the task manager connect(TaskManager::instance(), &TaskManager::TaskRemoved, this, &ViewerWidget::BackgroundCacheFinished); // Ensures that seeking on the waveform view updates the time as expected connect(waveform_view_, &AudioWaveformView::TimeChanged, this, &ViewerWidget::SetTimeAndSignal); // Ensures renderer is updated if the global pixel format is changed connect(PixelFormat::instance(), &PixelFormat::FormatChanged, this, &ViewerWidget::UpdateRendererParameters); connect(&playback_backup_timer_, &QTimer::timeout, this, &ViewerWidget::PlaybackTimerUpdate); SetAutoMaxScrollBar(true); } ViewerWidget::~ViewerWidget() { QList windows = windows_; foreach (ViewerWindow* window, windows) { delete window; } } void ViewerWidget::TimeChangedEvent(const int64_t &i) { if (!time_changed_from_timer_) { Pause(); } controls_->SetTime(i); waveform_view_->SetTime(i); if (GetConnectedNode() && last_time_ != i) { rational time_set = Timecode::timestamp_to_time(i, timebase()); if (!IsPlaying()) { UpdateTextureFromNode(time_set); PushScrubbedAudio(); } display_widget_->SetTime(time_set); } last_time_ = i; } void ViewerWidget::ConnectNodeInternal(ViewerOutput *n) { connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot); connect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot); connect(n, &ViewerOutput::ParamsChanged, this, &ViewerWidget::UpdateRendererParameters); connect(n->video_frame_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedVideoRange); connect(n->video_frame_cache(), &FrameHashCache::Shifted, this, &ViewerWidget::ViewerShiftedRange); connect(n->audio_playback_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedRange); connect(n, &ViewerOutput::GraphChangedFrom, this, &ViewerWidget::UpdateStack); ruler()->SetPlaybackCache(n->video_frame_cache()); n->audio_playback_cache()->SetParameters(n->audio_params()); SizeChangedSlot(n->video_params().width(), n->video_params().height()); last_length_ = rational(); LengthChangedSlot(n->GetLength()); ColorManager* using_manager; if (override_color_manager_) { using_manager = override_color_manager_; } else if (n->parent()) { using_manager = static_cast(n->parent())->project()->color_manager(); } else { qWarning() << "Failed to find a suitable color manager for the connected viewer node"; using_manager = nullptr; } display_widget_->ConnectColorManager(using_manager); foreach (ViewerWindow* window, windows_) { window->display_widget()->ConnectColorManager(using_manager); } UpdateStack(); if (GetConnectedTimelinePoints()) { waveform_view_->SetViewer(GetConnectedNode()->audio_playback_cache()); waveform_view_->ConnectTimelinePoints(GetConnectedTimelinePoints()); } UpdateRendererParameters(); // Set texture to new texture (or null if no viewer node is available) ForceUpdate(); } void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n) { PauseInternal(); if (cache_background_task_ == our_cache_background_task_) { StopAllBackgroundCacheTasks(true); cache_background_task_ = nullptr; } cache_wait_timer_.stop(); disconnect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SizeChangedSlot); disconnect(n, &ViewerOutput::LengthChanged, this, &ViewerWidget::LengthChangedSlot); disconnect(n, &ViewerOutput::ParamsChanged, this, &ViewerWidget::UpdateRendererParameters); disconnect(n->video_frame_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedVideoRange); disconnect(n->video_frame_cache(), &FrameHashCache::Shifted, this, &ViewerWidget::ViewerShiftedRange); disconnect(n->audio_playback_cache(), &FrameHashCache::Invalidated, this, &ViewerWidget::ViewerInvalidatedRange); disconnect(n, &ViewerOutput::GraphChangedFrom, this, &ViewerWidget::UpdateStack); ruler()->SetPlaybackCache(nullptr); // Effectively disables the viewer and clears the state SizeChangedSlot(0, 0); display_widget_->DisconnectColorManager(); foreach (ViewerWindow* window, windows_) { window->display_widget()->DisconnectColorManager(); } waveform_view_->SetViewer(nullptr); waveform_view_->ConnectTimelinePoints(nullptr); } void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n) { renderer_->SetViewerNode(n); } void ViewerWidget::ScaleChangedEvent(const double &s) { TimeBasedWidget::ScaleChangedEvent(s); waveform_view_->SetScale(s); } void ViewerWidget::resizeEvent(QResizeEvent *event) { TimeBasedWidget::resizeEvent(event); /* int new_div = CalculateDivider(); if (new_div != divider_) { divider_ = new_div; UpdateRendererParameters(); } */ UpdateMinimumScale(); } ViewerDisplayWidget *ViewerWidget::display_widget() const { return display_widget_; } void ViewerWidget::TogglePlayPause() { if (IsPlaying()) { Pause(); } else { Play(); } } bool ViewerWidget::IsPlaying() const { return playback_speed_ != 0; } void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_manager) { override_color_manager_ = color_manager; TimeBasedWidget::ConnectViewerNode(node); } void ViewerWidget::SetColorMenuEnabled(bool enabled) { color_menu_enabled_ = enabled; } void ViewerWidget::SetOverrideSize(int width, int height) { SizeChangedSlot(width, height); } void ViewerWidget::SetMatrix(const QMatrix4x4 &mat) { display_widget_->SetMatrix(mat); foreach (ViewerWindow* vw, windows_) { vw->display_widget()->SetMatrix(mat); } } void ViewerWidget::SetFullScreen(QScreen *screen) { if (!screen) { // Try to find the screen that contains the mouse cursor currently foreach (QScreen* test, QGuiApplication::screens()) { if (test->geometry().contains(QCursor::pos())) { screen = test; break; } } // Fallback, just use the first screen if (!screen) { screen = QGuiApplication::screens().first(); } } ViewerWindow* vw = new ViewerWindow(this); vw->setGeometry(screen->geometry()); vw->showFullScreen(); vw->display_widget()->ConnectColorManager(color_manager()); connect(vw, &ViewerWindow::destroyed, this, &ViewerWidget::WindowAboutToClose); connect(vw->display_widget(), &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); if (GetConnectedNode()) { vw->SetResolution(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height()); } vw->display_widget()->SetImage(display_widget_->last_loaded_buffer()); windows_.append(vw); } void ViewerWidget::ForceUpdate() { // Hack that forces the viewer to update UpdateTextureFromNode(GetTime()); } void ViewerWidget::SetAutoCacheEnabled(bool e) { autocache_ = e; if (autocache_) { StartBackgroundCaching(); } else if (cache_background_task_ == our_cache_background_task_) { StopAllBackgroundCacheTasks(false); cache_background_task_ = nullptr; } } void ViewerWidget::SetGizmos(Node *node) { display_widget_->SetTimeTarget(GetConnectedNode()); display_widget_->SetGizmos(node); } void ViewerWidget::StopAllBackgroundCacheTasks(bool wait) { if (cache_background_task_) { if (wait) { TaskManager::instance()->CancelTaskAndWait(cache_background_task_); } else { cache_background_task_->Cancel(); } cache_background_task_ = nullptr; } } void ViewerWidget::SetBackgroundCacheTask(CacheTask *t) { cache_background_task_ = t; } FramePtr DecodeCachedImage(const QString &fn, const rational& time) { FramePtr frame = FrameHashCache::LoadCacheFrame(fn); if (frame) { frame->set_timestamp(time); } return frame; } void DecodeCachedImage(RenderTicketPtr ticket, const QString &fn, const rational& time) { ticket->Finish(QVariant::fromValue(DecodeCachedImage(fn, time))); } void ViewerWidget::UpdateTextureFromNode(const rational& time) { bool frame_exists_at_time = FrameExistsAtTime(time); // Check playback queue for a frame if (IsPlaying()) { // We still run the playback queue even when FrameExistsAtTime returns false because we might be // playing backwards and about to start showing frames, so the queue should be prepared for // that. while (!playback_queue_.empty()) { const ViewerPlaybackFrame& pf = playback_queue_.front(); if (pf.timestamp == time) { // Frame was in queue, no need to decode anything SetDisplayImage(pf.frame, true); return; } else { // Skip this frame PopOldestFrameFromPlaybackQueue(); } } // Only show warning if frame actually exists if (frame_exists_at_time) { qWarning() << "Playback queue failed to keep up"; } } if (!frame_exists_at_time) { // There is definitely no frame here, we can immediately flip to showing nothing nonqueue_watchers_.clear(); SetDisplayImage(nullptr, false); return; } // Frame was not in queue, will require rendering or decoding from cache RenderTicketWatcher* watcher = new RenderTicketWatcher(); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame); nonqueue_watchers_.append(watcher); watcher->SetTicket(GetFrame(time, true)); } void ViewerWidget::PlayInternal(int speed, bool in_to_out_only) { Q_ASSERT(speed != 0); if (timebase().isNull()) { qWarning() << "ViewerWidget can't play with an invalid timebase"; return; } // If the playhead is beyond the end, restart at 0 if (!in_to_out_only && GetTime() >= GetConnectedNode()->GetLength()) { if (speed > 0) { SetTimeAndSignal(0); } else { SetTimeAndSignal(Timecode::time_to_timestamp(GetConnectedNode()->GetLength(), timebase())); } } playback_speed_ = speed; play_in_to_out_only_ = in_to_out_only; playback_queue_next_frame_ = ruler()->GetTime(); controls_->ShowPauseButton(); // Attempt to fill playback queue if (stack_->currentWidget() == sizer_) { prequeue_length_ = DeterminePlaybackQueueSize(); if (prequeue_length_ > 0) { prequeuing_ = true; for (int i=0; iStopOutput(); playback_speed_ = 0; controls_->ShowPlayButton(); disconnect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::ForceUpdate); foreach (ViewerWindow* window, windows_) { window->Pause(); } playback_queue_.clear(); playback_backup_timer_.stop(); } prequeuing_ = false; } void ViewerWidget::PushScrubbedAudio() { if (!IsPlaying() && Config::Current()["AudioScrubbing"].toBool()) { // Get audio src device from renderer QString audio_fn = GetConnectedNode()->audio_playback_cache()->GetCacheFilename(); QFile audio_src(audio_fn); if (audio_src.open(QFile::ReadOnly)) { const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters(); // FIXME: Hardcoded scrubbing interval (20ms) int size_of_sample = params.time_to_bytes(rational(20, 1000)); // Push audio audio_src.seek(params.time_to_bytes(GetTime())); QByteArray frame_audio = audio_src.read(size_of_sample); AudioManager::instance()->SetOutputParams(params); AudioManager::instance()->PushToOutput(frame_audio); audio_src.close(); } } } /* int ViewerWidget::CalculateDivider() { if (GetConnectedNode() && Config::Current()["AutoSelectDivider"].toBool()) { int long_side_of_video = qMax(GetConnectedNode()->video_params().width(), GetConnectedNode()->video_params().height()); int long_side_of_widget = qMax(display_widget_->width(), display_widget_->height()); return qMax(1, int(qPow(2, qFloor(log2(double(long_side_of_video) / double(long_side_of_widget)))))); } return divider_; } */ void ViewerWidget::UpdateMinimumScale() { if (!GetConnectedNode()) { return; } if (GetConnectedNode()->GetLength().isNull()) { // Avoids divide by zero SetMinimumScale(0); } else { SetMinimumScale(static_cast(ruler()->width()) / GetConnectedNode()->GetLength().toDouble()); } } void ViewerWidget::SetColorTransform(const ColorTransform &transform, ViewerDisplayWidget *sender) { sender->SetColorTransform(transform); } QString ViewerWidget::GetCachedFilenameFromTime(const rational &time) { if (FrameExistsAtTime(time)) { QByteArray hash = GetConnectedNode()->video_frame_cache()->GetHash(time); if (!hash.isEmpty()) { return GetConnectedNode()->video_frame_cache()->CachePathName(hash); } } return QString(); } bool ViewerWidget::FrameExistsAtTime(const rational &time) { return GetConnectedNode() && time >= 0 && time < GetConnectedNode()->video_frame_cache()->GetLength(); } void ViewerWidget::SetDisplayImage(FramePtr frame, bool main_only) { display_widget_->SetImage(frame); if (!main_only) { foreach (ViewerWindow* vw, windows_) { vw->display_widget()->SetImage(frame); } } emit LoadedBuffer(frame.get()); } void ViewerWidget::RequestNextFrameForQueue() { rational next_time = Timecode::timestamp_to_time(playback_queue_next_frame_, timebase()); playback_queue_next_frame_ += playback_speed_; RenderTicketWatcher* watcher = new RenderTicketWatcher(); connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrameForQueue); watcher->SetTicket(GetFrame(next_time, false)); } PixelFormat::Format ViewerWidget::GetCurrentPixelFormat() const { return PixelFormat::instance()->GetConfiguredFormatForMode(RenderMode::kOffline); } RenderTicketPtr ViewerWidget::GetFrame(const rational &t, bool clear_render_queue) { QByteArray cached_hash = GetConnectedNode()->video_frame_cache()->GetHash(t); if (cached_hash.isEmpty()) { // Frame hasn't been cached, start render job if (clear_render_queue) { renderer_->ClearVideoQueue(); } return renderer_->RenderFrame(t); } else { // Frame has been cached, grab the frame QString cache_fn = GetConnectedNode()->video_frame_cache()->CachePathName(cached_hash); RenderTicketPtr ticket = std::make_shared(RenderTicket::kTypeVideo, QVariant::fromValue(t)); QtConcurrent::run(DecodeCachedImage, ticket, cache_fn, t); return ticket; } } void ViewerWidget::FinishPlayPreprocess() { int64_t playback_start_time = ruler()->GetTime(); QString audio_fn = GetConnectedNode()->audio_playback_cache()->GetCacheFilename(); if (!audio_fn.isEmpty()) { AudioManager::instance()->SetOutputParams(GetConnectedNode()->audio_playback_cache()->GetParameters()); AudioManager::instance()->StartOutput(audio_fn, GetConnectedNode()->audio_playback_cache()->GetParameters().time_to_bytes(GetTime()), playback_speed_); } playback_timer_.Start(playback_start_time, playback_speed_, timebase_dbl()); foreach (ViewerWindow* window, windows_) { window->Play(playback_start_time, playback_speed_, timebase()); } connect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWidget::ForceUpdate); playback_backup_timer_.setInterval(qFloor(timebase_dbl())); playback_backup_timer_.start(); PlaybackTimerUpdate(); } int ViewerWidget::DeterminePlaybackQueueSize() { int64_t end_ts; if (playback_speed_ > 0) { end_ts = Timecode::time_to_timestamp(GetConnectedNode()->video_frame_cache()->GetLength(), timebase()); } else { end_ts = 0; } int remaining_frames = (end_ts - GetTimestamp()) * playback_speed_; return qMin(kMaxPreQueueSize, remaining_frames); } void ViewerWidget::PopOldestFrameFromPlaybackQueue() { playback_queue_.pop_front(); if (int(playback_queue_.size()) < DeterminePlaybackQueueSize()) { RequestNextFrameForQueue(); } } void ViewerWidget::UpdateStack() { rational new_tb; if (GetConnectedNode() && !GetConnectedNode()->texture_input()->is_connected() && GetConnectedNode()->samples_input()->is_connected()) { // If we have a node AND video is disconnected AND audio is connected, show waveform view stack_->setCurrentWidget(waveform_view_); new_tb = GetConnectedNode()->audio_params().time_base(); } else { // Otherwise show regular display stack_->setCurrentWidget(sizer_); new_tb = GetConnectedNode()->video_params().time_base(); } if (new_tb != timebase()) { SetTimebase(new_tb); } } void ViewerWidget::ContextMenuSetFullScreen(QAction *action) { SetFullScreen(QGuiApplication::screens().at(action->data().toInt())); } void ViewerWidget::ContextMenuDisableSafeMargins() { context_menu_widget_->SetSafeMargins(ViewerSafeMarginInfo(false)); } void ViewerWidget::ContextMenuSetSafeMargins() { context_menu_widget_->SetSafeMargins(ViewerSafeMarginInfo(true)); } void ViewerWidget::ContextMenuSetCustomSafeMargins() { QString s; forever { bool ok; s = QInputDialog::getText(this, tr("Safe Margins"), tr("Enter custom ratio (e.g. \"4:3\", \"16/9\", etc.):"), QLineEdit::Normal, s, &ok); if (!ok) { // User cancelled dialog, do nothing return; } QStringList ratio_components = s.split(QRegExp(QStringLiteral(":|;|\\/"))); if (ratio_components.size() == 2) { bool numer_ok, denom_ok; double num = ratio_components.at(0).toDouble(&numer_ok); double den = ratio_components.at(1).toDouble(&denom_ok); if (numer_ok && denom_ok && num > 0) { // Exit loop and set this ratio context_menu_widget_->SetSafeMargins(ViewerSafeMarginInfo(true, num / den)); return; } } QMessageBox::warning(this, tr("Invalid custom ratio"), tr("Failed to parse \"%1\" into an aspect ratio. Please format a " "rational fraction with a ':' or a '/' separator.").arg(s), QMessageBox::Ok); } } void ViewerWidget::WindowAboutToClose() { windows_.removeOne(static_cast(sender())); } void ViewerWidget::ContextMenuScopeTriggered(QAction *action) { emit RequestScopePanel(static_cast(action->data().toInt())); } void ViewerWidget::RendererGeneratedFrame() { RenderTicketWatcher* ticket = static_cast(sender()); if (!ticket->WasCancelled()) { FramePtr frame = ticket->Get().value(); if (nonqueue_watchers_.contains(ticket)) { while (!nonqueue_watchers_.isEmpty()) { if (nonqueue_watchers_.takeFirst() == ticket) { break; } } SetDisplayImage(frame, false); } } ticket->deleteLater(); } void ViewerWidget::RendererGeneratedFrameForQueue() { RenderTicketWatcher* watcher = static_cast(sender()); if (!watcher->WasCancelled()) { FramePtr frame = watcher->Get().value(); // Ignore this signal if we've paused now if (IsPlaying() || prequeuing_) { playback_queue_.AppendTimewise({frame->timestamp(), frame}, playback_speed_); foreach (ViewerWindow* window, windows_) { window->queue()->AppendTimewise({frame->timestamp(), frame}, playback_speed_); } if (prequeuing_ && int(playback_queue_.size()) == prequeue_length_) { prequeuing_ = false; FinishPlayPreprocess(); } } } watcher->deleteLater(); } //#define PRINT_INVALID_RANGES void ViewerWidget::StartBackgroundCaching() { if (busy_) { busy_viewers_--; busy_ = false; } #ifdef PRINT_INVALID_RANGES if (GetConnectedNode()->video_frame_cache()->HasInvalidatedRanges()) { qDebug() << "Video invalid:"; foreach (const TimeRange& r, GetConnectedNode()->video_frame_cache()->GetInvalidatedRanges()) { qDebug() << " " << r; } } if (GetConnectedNode()->audio_playback_cache()->HasInvalidatedRanges()) { qDebug() << "Audio invalid:"; foreach (const TimeRange& r, GetConnectedNode()->audio_playback_cache()->GetInvalidatedRanges()) { qDebug() << " " << r; } } #endif if (autocache_ && GetConnectedNode() && (GetConnectedNode()->video_frame_cache()->HasInvalidatedRanges() || GetConnectedNode()->audio_playback_cache()->HasInvalidatedRanges())) { if (cache_background_task_ || busy_viewers_) { // Something else is caching right now, we don't want to do multiple at once so we'll check // again in our next interval cache_wait_timer_.start(); } else { cache_background_task_ = new CacheTask(renderer_, false); our_cache_background_task_ = cache_background_task_; TaskManager::instance()->AddTask(cache_background_task_); } } } void ViewerWidget::BackgroundCacheFinished(Task* t) { if (cache_background_task_ == t) { cache_background_task_ = nullptr; } } void ViewerWidget::UpdateRendererParameters() { if (cache_background_task_ == our_cache_background_task_) { StopAllBackgroundCacheTasks(false); } GetConnectedNode()->video_frame_cache()->InvalidateAll(); GetConnectedNode()->audio_playback_cache()->InvalidateAll(); renderer_->SetVideoParams(GetConnectedNode()->video_params()); renderer_->SetAudioParams(GetConnectedNode()->audio_params()); display_widget_->SetVideoParams(GetConnectedNode()->video_params()); } void ViewerWidget::ShowContextMenu(const QPoint &pos) { Menu menu(static_cast(sender())); context_menu_widget_ = static_cast(sender()); // Color options if (context_menu_widget_->color_manager() && color_menu_enabled_) { { Menu* ocio_display_menu = context_menu_widget_->GetDisplayMenu(&menu); menu.addMenu(ocio_display_menu); } { Menu* ocio_view_menu = context_menu_widget_->GetViewMenu(&menu); menu.addMenu(ocio_view_menu); } { Menu* ocio_look_menu = context_menu_widget_->GetLookMenu(&menu); menu.addMenu(ocio_look_menu); } menu.addSeparator(); } { // Viewer Zoom Level Menu* zoom_menu = new Menu(tr("Zoom"), &menu); menu.addMenu(zoom_menu); int zoom_levels[] = {10, 25, 50, 75, 100, 150, 200, 400}; zoom_menu->addAction(tr("Fit"))->setData(0); for (int i=0;i<8;i++) { zoom_menu->addAction(tr("%1%").arg(zoom_levels[i]))->setData(zoom_levels[i]); } connect(zoom_menu, &QMenu::triggered, this, &ViewerWidget::SetZoomFromMenu); } { // Full Screen Menu Menu* full_screen_menu = new Menu(tr("Full Screen"), &menu); menu.addMenu(full_screen_menu); for (int i=0;iaddAction(tr("Screen %1: %2x%3").arg(QString::number(i), QString::number(s->size().width()), QString::number(s->size().height()))); a->setData(i); } connect(full_screen_menu, &QMenu::triggered, this, &ViewerWidget::ContextMenuSetFullScreen); } menu.addSeparator(); { // Scopes Menu* scopes_menu = new Menu(tr("Scopes"), &menu); menu.addMenu(scopes_menu); for (int i=0;iaddAction(ScopePanel::TypeToName(static_cast(i))); scope_action->setData(i); } connect(scopes_menu, &Menu::triggered, this, &ViewerWidget::ContextMenuScopeTriggered); } menu.addSeparator(); { // Auto-cache QAction* autocache_action = menu.addAction(tr("Auto-Cache")); autocache_action->setCheckable(true); autocache_action->setChecked(autocache_); connect(autocache_action, &QAction::triggered, this, &ViewerWidget::SetAutoCacheEnabled); } menu.addSeparator(); { // Safe Margins Menu* safe_margin_menu = new Menu(tr("Safe Margins"), &menu); menu.addMenu(safe_margin_menu); QAction* safe_margin_off = safe_margin_menu->addAction(tr("Off")); safe_margin_off->setCheckable(true); safe_margin_off->setChecked(!context_menu_widget_->GetSafeMargin().is_enabled()); connect(safe_margin_off, &QAction::triggered, this, &ViewerWidget::ContextMenuDisableSafeMargins); QAction* safe_margin_on = safe_margin_menu->addAction(tr("On")); safe_margin_on->setCheckable(true); safe_margin_on->setChecked(context_menu_widget_->GetSafeMargin().is_enabled() && !context_menu_widget_->GetSafeMargin().custom_ratio()); connect(safe_margin_on, &QAction::triggered, this, &ViewerWidget::ContextMenuSetSafeMargins); QAction* safe_margin_custom = safe_margin_menu->addAction(tr("Custom Aspect")); safe_margin_custom->setCheckable(true); safe_margin_custom->setChecked(context_menu_widget_->GetSafeMargin().is_enabled() && context_menu_widget_->GetSafeMargin().custom_ratio()); connect(safe_margin_custom, &QAction::triggered, this, &ViewerWidget::ContextMenuSetCustomSafeMargins); } menu.exec(static_cast(sender())->mapToGlobal(pos)); } void ViewerWidget::Play(bool in_to_out_only) { if (in_to_out_only) { if (GetConnectedTimelinePoints() && GetConnectedTimelinePoints()->workarea()->enabled()) { // Jump to in point SetTimeAndSignal(Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->in(), timebase())); } else { in_to_out_only = false; } } PlayInternal(1, in_to_out_only); } void ViewerWidget::Play() { Play(false); } void ViewerWidget::Pause() { PauseInternal(); StartBackgroundCaching(); } void ViewerWidget::ShuttleLeft() { int current_speed = playback_speed_; if (current_speed != 0) { PauseInternal(); } current_speed--; if (current_speed == 0) { current_speed--; } PlayInternal(current_speed, false); } void ViewerWidget::ShuttleStop() { Pause(); } void ViewerWidget::ShuttleRight() { int current_speed = playback_speed_; if (current_speed != 0) { PauseInternal(); } current_speed++; if (current_speed == 0) { current_speed++; } PlayInternal(current_speed, false); } void ViewerWidget::SetColorTransform(const ColorTransform &transform) { SetColorTransform(transform, display_widget_); } void ViewerWidget::SetSignalCursorColorEnabled(bool e) { display_widget_->SetSignalCursorColorEnabled(e); foreach (ViewerWindow* vw, windows_) { vw->display_widget()->SetSignalCursorColorEnabled(e); } } void ViewerWidget::TimebaseChangedEvent(const rational &timebase) { TimeBasedWidget::TimebaseChangedEvent(timebase); controls_->SetTimebase(timebase); controls_->SetTime(ruler()->GetTime()); LengthChangedSlot(GetConnectedNode() ? GetConnectedNode()->GetLength() : 0); } void ViewerWidget::PlaybackTimerUpdate() { int64_t current_time = playback_timer_.GetTimestampNow(); int64_t min_time, max_time; { if ((play_in_to_out_only_ || Config::Current()["Loop"].toBool()) && GetConnectedTimelinePoints() && GetConnectedTimelinePoints()->workarea()->enabled()) { // If "play in to out" is enabled or we're looping AND we have a workarea, only play the workarea min_time = Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->in(), timebase()); max_time = Timecode::time_to_timestamp(GetConnectedTimelinePoints()->workarea()->out(), timebase()); } else { // Otherwise set the bounds to the range of the sequence min_time = 0; max_time = Timecode::time_to_timestamp(GetConnectedNode()->GetLength(), timebase()); } } if ((playback_speed_ < 0 && current_time <= min_time) || (playback_speed_ > 0 && current_time >= max_time)) { // Determine which timestamp we tripped int64_t tripped_time; if (current_time <= min_time) { tripped_time = min_time; } else { tripped_time = max_time; } if (Config::Current()[QStringLiteral("Loop")].toBool()) { // If we're looping, jump to the other side of the workarea and continue int64_t opposing_time = (tripped_time == min_time) ? max_time : min_time; // Cache the current speed int current_speed = playback_speed_; // Jump to the other side and keep playing at the same speed SetTimeAndSignal(opposing_time); PlayInternal(current_speed, play_in_to_out_only_); } else { // Pause at the boundary SetTimeAndSignal(tripped_time); } } else { // Sets time, wrapping in this bool ensures we don't pause from setting the time time_changed_from_timer_ = true; SetTimeAndSignal(current_time); time_changed_from_timer_ = false; } if (!isVisible()) { while (!playback_queue_.empty() && playback_queue_.front().timestamp != GetTime()) { PopOldestFrameFromPlaybackQueue(); } } } void ViewerWidget::SizeChangedSlot(int width, int height) { sizer_->SetChildSize(width, height); foreach (ViewerWindow* vw, windows_) { vw->SetResolution(width, height); } } void ViewerWidget::LengthChangedSlot(const rational &length) { if (last_length_ != length) { controls_->SetEndTime(Timecode::time_to_timestamp(length, timebase())); UpdateMinimumScale(); if (length < last_length_ && GetTime() >= length) { ForceUpdate(); } last_length_ = length; } } void ViewerWidget::SetZoomFromMenu(QAction *action) { sizer_->SetZoom(action->data().toInt()); } void ViewerWidget::ViewerInvalidatedVideoRange(const TimeRange &range) { if (GetTime() >= range.in() && (GetTime() < range.out() || range.in() == range.out())) { QMetaObject::invokeMethod(this, "ForceUpdate", Qt::QueuedConnection); } ViewerInvalidatedRange(); } void ViewerWidget::ViewerInvalidatedRange() { // Restart the cache wait timer cache_wait_timer_.stop(); StopAllBackgroundCacheTasks(false); if (!(qApp->mouseButtons() & Qt::LeftButton)) { cache_wait_timer_.start(); } } void ViewerWidget::ViewerShiftedRange(const rational &from, const rational &to) { if (GetTime() >= qMin(from, to)) { QMetaObject::invokeMethod(this, "ForceUpdate", Qt::QueuedConnection); } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/viewer.h000066400000000000000000000156641370472574300214460ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWER_WIDGET_H #define VIEWER_WIDGET_H #include #include #include #include #include #include #include "audiowaveformview.h" #include "common/rational.h" #include "node/output/viewer/viewer.h" #include "panel/scope/scope.h" #include "render/backend/opengl/openglbackend.h" #include "render/backend/renderticketwatcher.h" #include "task/cache/cache.h" #include "viewerdisplay.h" #include "viewerplaybacktimer.h" #include "viewerqueue.h" #include "viewersizer.h" #include "viewerwindow.h" #include "widget/playbackcontrols/playbackcontrols.h" #include "widget/timebased/timebased.h" OLIVE_NAMESPACE_ENTER /** * @brief An OpenGL-based viewer widget with playback controls (a PlaybackControls widget). */ class ViewerWidget : public TimeBasedWidget { Q_OBJECT public: ViewerWidget(QWidget* parent = nullptr); virtual ~ViewerWidget() override; void SetPlaybackControlsEnabled(bool enabled); void SetTimeRulerEnabled(bool enabled); void TogglePlayPause(); bool IsPlaying() const; void ConnectViewerNode(ViewerOutput* node, ColorManager *color_manager = nullptr); /** * @brief Enable or disable the color management menu * * While the Viewer is _always_ color managed, In some contexts, the color management may be controlled from an * external UI making the menu unnecessary. */ void SetColorMenuEnabled(bool enabled); void SetOverrideSize(int width, int height); void SetMatrix(const QMatrix4x4& mat); /** * @brief Creates a ViewerWindow widget and places it full screen on another screen * * If `screen` is nullptr, the screen will be automatically selected as whichever one contains the mouse cursor. */ void SetFullScreen(QScreen* screen = nullptr); RenderBackend* renderer() const { return renderer_; } ColorManager* color_manager() const { return display_widget_->color_manager(); } void SetGizmos(Node* node); static void StopAllBackgroundCacheTasks(bool wait); static void SetBackgroundCacheTask(CacheTask* t); public slots: void Play(bool in_to_out_only); void Play(); void Pause(); void ShuttleLeft(); void ShuttleStop(); void ShuttleRight(); void SetColorTransform(const ColorTransform& transform); /** * @brief Wrapper for ViewerGLWidget::SetSignalCursorColorEnabled() */ void SetSignalCursorColorEnabled(bool e); void ForceUpdate(); void SetAutoCacheEnabled(bool e); signals: /** * @brief Wrapper for ViewerGLWidget::CursorColor() */ void CursorColor(const Color& reference, const Color& display); /** * @brief Signal emitted when a new frame is loaded */ void LoadedBuffer(Frame* load_buffer); /** * @brief Request a scope panel * * As a widget, we don't handle panels, but a parent panel may pick this signal up. */ void RequestScopePanel(ScopePanel::Type type); /** * @brief Wrapper for ViewerGLWidget::ColorProcessorChanged() */ void ColorProcessorChanged(ColorProcessorPtr processor); /** * @brief Wrapper for ViewerGLWidget::ColorManagerChanged() */ void ColorManagerChanged(ColorManager* color_manager); protected: virtual void TimebaseChangedEvent(const rational &) override; virtual void TimeChangedEvent(const int64_t &) override; virtual void ConnectNodeInternal(ViewerOutput *) override; virtual void DisconnectNodeInternal(ViewerOutput *) override; virtual void ConnectedNodeChanged(ViewerOutput*n) override; virtual void ScaleChangedEvent(const double& s) override; virtual void resizeEvent(QResizeEvent *event) override; PlaybackControls* controls_; ViewerDisplayWidget* display_widget() const; private: void UpdateTimeInternal(int64_t i); void UpdateTextureFromNode(const rational &time); void PlayInternal(int speed, bool in_to_out_only); void PauseInternal(); void PushScrubbedAudio(); int CalculateDivider(); void UpdateMinimumScale(); void SetColorTransform(const ColorTransform& transform, ViewerDisplayWidget* sender); QString GetCachedFilenameFromTime(const rational& time); bool FrameExistsAtTime(const rational& time); void SetDisplayImage(FramePtr frame, bool main_only); void RequestNextFrameForQueue(); PixelFormat::Format GetCurrentPixelFormat() const; RenderTicketPtr GetFrame(const rational& t, bool clear_render_queue); void FinishPlayPreprocess(); int DeterminePlaybackQueueSize(); void PopOldestFrameFromPlaybackQueue(); QStackedWidget* stack_; ViewerSizer* sizer_; QAtomicInt playback_speed_; qint64 frame_cache_job_time_; int64_t last_time_; bool color_menu_enabled_; ColorManager* override_color_manager_; bool time_changed_from_timer_; bool play_in_to_out_only_; AudioWaveformView* waveform_view_; QList windows_; ViewerDisplayWidget* display_widget_; ViewerDisplayWidget* context_menu_widget_; ViewerPlaybackTimer playback_timer_; QTimer playback_backup_timer_; ViewerQueue playback_queue_; int64_t playback_queue_next_frame_; RenderBackend* renderer_; bool prequeuing_; QList nonqueue_watchers_; QTimer cache_wait_timer_; bool busy_; CacheTask* our_cache_background_task_; rational last_length_; int prequeue_length_; bool autocache_; static CacheTask* cache_background_task_; static int busy_viewers_; private slots: void PlaybackTimerUpdate(); void SizeChangedSlot(int width, int height); void LengthChangedSlot(const rational& length); void UpdateRendererParameters(); void ShowContextMenu(const QPoint& pos); void SetZoomFromMenu(QAction* action); void ViewerInvalidatedVideoRange(const OLIVE_NAMESPACE::TimeRange &range); void ViewerInvalidatedRange(); void ViewerShiftedRange(const OLIVE_NAMESPACE::rational& from, const OLIVE_NAMESPACE::rational& to); void UpdateStack(); void ContextMenuSetFullScreen(QAction* action); void ContextMenuDisableSafeMargins(); void ContextMenuSetSafeMargins(); void ContextMenuSetCustomSafeMargins(); void WindowAboutToClose(); void ContextMenuScopeTriggered(QAction* action); void RendererGeneratedFrame(); void RendererGeneratedFrameForQueue(); void StartBackgroundCaching(); void BackgroundCacheFinished(Task *t); }; OLIVE_NAMESPACE_EXIT #endif // VIEWER_WIDGET_H olive-continuous/app/widget/viewer/viewerdisplay.cpp000066400000000000000000000164201370472574300233560ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewerdisplay.h" #include #include #include #include #include #include #include #include #include "common/define.h" #include "common/functiontimer.h" #include "gizmotraverser.h" #include "render/backend/opengl/openglrenderfunctions.h" #include "render/backend/opengl/openglshader.h" #include "render/pixelformat.h" OLIVE_NAMESPACE_ENTER ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : ManagedDisplayWidget(parent), signal_cursor_color_(false), gizmos_(nullptr), gizmo_click_(false), last_loaded_buffer_(nullptr) { } ViewerDisplayWidget::~ViewerDisplayWidget() { ContextCleanup(); } void ViewerDisplayWidget::SetMatrix(const QMatrix4x4 &mat) { matrix_ = mat; update(); } void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e) { signal_cursor_color_ = e; setMouseTracking(e); } void ViewerDisplayWidget::SetImage(FramePtr in_buffer) { last_loaded_buffer_ = in_buffer; if (last_loaded_buffer_) { makeCurrent(); if (!texture_.IsCreated() || texture_.width() != in_buffer->width() || texture_.height() != in_buffer->height() || texture_.format() != in_buffer->format()) { texture_.Create(context(), in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels()); } else { texture_.Upload(in_buffer); } doneCurrent(); } update(); } const ViewerSafeMarginInfo &ViewerDisplayWidget::GetSafeMargin() const { return safe_margin_; } void ViewerDisplayWidget::SetSafeMargins(const ViewerSafeMarginInfo &safe_margin) { if (safe_margin_ != safe_margin) { safe_margin_ = safe_margin; update(); } } void ViewerDisplayWidget::SetGizmos(Node *node) { if (gizmos_ != node) { gizmos_ = node; update(); } } void ViewerDisplayWidget::SetVideoParams(const VideoParams ¶ms) { gizmo_params_ = params; if (gizmos_) { update(); } } void ViewerDisplayWidget::SetTime(const rational &time) { time_ = time; if (gizmos_) { update(); } } FramePtr ViewerDisplayWidget::last_loaded_buffer() const { return last_loaded_buffer_; } void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (gizmos_ && gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())), size())) { gizmo_click_ = true; gizmo_drag_time_ = GetGizmoTime(); return; } QOpenGLWidget::mousePressEvent(event); if (event->button() == Qt::LeftButton) { emit DragStarted(); } } void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { if (gizmo_click_) { gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size())), gizmo_drag_time_); return; } QOpenGLWidget::mouseMoveEvent(event); if (signal_cursor_color_) { Color reference, display; if (last_loaded_buffer_) { QVector3D pixel_pos(static_cast(event->x()) / static_cast(width()) * 2.0f - 1.0f, static_cast(event->y()) / static_cast(height()) * 2.0f - 1.0f, 0); pixel_pos = pixel_pos * matrix_.inverted(); int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * last_loaded_buffer_->width()); int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * last_loaded_buffer_->height()); reference = last_loaded_buffer_->get_pixel(frame_x, frame_y); display = color_service()->ConvertColor(reference); } emit CursorColor(reference, display); } } void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) { if (gizmo_click_) { gizmos_->GizmoRelease(); gizmo_click_ = false; return; } QOpenGLWidget::mouseReleaseEvent(event); } void ViewerDisplayWidget::initializeGL() { ManagedDisplayWidget::initializeGL(); connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ViewerDisplayWidget::ContextCleanup, Qt::DirectConnection); } void ViewerDisplayWidget::paintGL() { // Get functions attached to this context (they will already be initialized) QOpenGLFunctions* f = context()->functions(); // Clear background to empty f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f); f->glClear(GL_COLOR_BUFFER_BIT); // We only draw if we have a pipeline if (last_loaded_buffer_ && color_service()) { // Bind retrieved texture f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); // Blit using the color service color_service()->ProcessOpenGL(true, matrix_); // Release retrieved texture f->glBindTexture(GL_TEXTURE_2D, 0); } // Draw gizmos if we have any if (gizmos_) { GizmoTraverser gt(QSize(gizmo_params_.width(), gizmo_params_.height())); rational node_time = GetGizmoTime(); gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); QPainter p(this); gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size()); } // Draw action/title safe areas if (safe_margin_.is_enabled()) { QPainter p(this); p.setPen(Qt::lightGray); p.setBrush(Qt::NoBrush); int x = 0, y = 0, w = width(), h = height(); if (safe_margin_.custom_ratio()) { double widget_ar = static_cast(width()) / static_cast(height()); if (widget_ar > safe_margin_.ratio()) { // Widget is wider than margins w = h * safe_margin_.ratio(); x = width() / 2 - w / 2; } else { h = w / safe_margin_.ratio(); y = height() / 2 - h / 2; } } p.drawRect(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); p.drawRect(w / 10 + x, h / 10 + y, w / 10 * 8, h / 10 * 8); int cross = qMin(w, h) / 32; QLine lines[] = {QLine(rect().center().x() - cross, rect().center().y(),rect().center().x() + cross, rect().center().y()), QLine(rect().center().x(), rect().center().y() - cross, rect().center().x(), rect().center().y() + cross)}; p.drawLines(lines, 2); } } QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos) { return GetTexturePosition(screen_pos.x(), screen_pos.y()); } QPointF ViewerDisplayWidget::GetTexturePosition(const QSize &size) { return GetTexturePosition(size.width(), size.height()); } QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y) { return QPointF(x / gizmo_params_.width(), y / gizmo_params_.height()); } rational ViewerDisplayWidget::GetGizmoTime() { return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput); } void ViewerDisplayWidget::ContextCleanup() { makeCurrent(); texture_.Destroy(); doneCurrent(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/viewerdisplay.h000066400000000000000000000133151370472574300230230ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERGLWIDGET_H #define VIEWERGLWIDGET_H #include #include "node/node.h" #include "render/backend/opengl/openglcolorprocessor.h" #include "render/backend/opengl/openglframebuffer.h" #include "render/backend/opengl/openglshader.h" #include "render/backend/opengl/opengltexture.h" #include "render/color.h" #include "render/colormanager.h" #include "viewersafemargininfo.h" #include "widget/manageddisplay/manageddisplay.h" #include "widget/timetarget/timetarget.h" OLIVE_NAMESPACE_ENTER /** * @brief The inner display/rendering widget of a Viewer class. * * Actual composition occurs elsewhere offscreen and * multithreaded, so its main purpose is receiving a finalized OpenGL texture and displaying it. * * The main entry point is SetTexture() which will receive an OpenGL texture ID, store it, and then call update() to * draw it on screen. The drawing function is in paintGL() (called during the update() process by Qt) and is fairly * simple OpenGL drawing code standardized around OpenGL ES 3.2 Core. * * If the texture has been modified and you're 100% sure this widget is using the same texture object, it's possible * to call update() directly to trigger a repaint, however this is not recommended. If you are not 100% sure it'll be * the same texture object, use SetTexture() since it will nearly always be faster to just set it than to check *and* * set it. */ class ViewerDisplayWidget : public ManagedDisplayWidget, public TimeTargetObject { Q_OBJECT public: /** * @brief ViewerGLWidget Constructor * * @param parent * * QWidget parent. */ ViewerDisplayWidget(QWidget* parent = nullptr); virtual ~ViewerDisplayWidget() override; const QMatrix4x4& GetMatrix(); const ViewerSafeMarginInfo& GetSafeMargin() const; void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin); void SetGizmos(Node* node); void SetVideoParams(const VideoParams ¶ms); void SetTime(const rational& time); FramePtr last_loaded_buffer() const; public slots: /** * @brief Set the transformation matrix to draw with * * Set this if you want the drawing to pass through some sort of transform (most of the time you won't want this). */ void SetMatrix(const QMatrix4x4& mat); /** * @brief Enables or disables whether this color at the cursor should be emitted * * Since tracking the mouse every movement, reading pixels, and doing color transforms are processor intensive, we * have an option for it. Ideally, this should be connected to a PixelSamplerPanel::visibilityChanged signal so that * it can automatically be enabled when the user is pixel sampling and disabled for optimization when they're not. */ void SetSignalCursorColorEnabled(bool e); /** * @brief Overrides the image with the load buffer of another ViewerGLWidget * * If there are multiple ViewerGLWidgets showing the same thing, this is faster than decoding the image from file * each time. */ void SetImage(FramePtr in_buffer); signals: /** * @brief Signal emitted when the user starts dragging from the viewer */ void DragStarted(); /** * @brief Signal emitted when cursor color is enabled and the user's mouse position changes */ void CursorColor(const Color& reference, const Color& display); protected: /** * @brief Override the mouse press event for the DragStarted() signal and gizmos */ virtual void mousePressEvent(QMouseEvent* event) override; /** * @brief Override mouse move to signal for the pixel sampler and gizmos */ virtual void mouseMoveEvent(QMouseEvent* event) override; /** * @brief Override mouse release event for gizmos */ virtual void mouseReleaseEvent(QMouseEvent* event) override; /** * @brief Initialize function to set up the OpenGL context upon its construction * * Currently primarily used to regenerate the pipeline shader used for drawing. */ virtual void initializeGL() override; /** * @brief Paint function to display the texture (received in SetTexture()) on screen. * * Simple OpenGL drawing function for painting the texture on screen. Standardized around OpenGL ES 3.2 Core. */ virtual void paintGL() override; private: QPointF GetTexturePosition(const QPoint& screen_pos); QPointF GetTexturePosition(const QSize& size); QPointF GetTexturePosition(const double& x, const double& y); rational GetGizmoTime(); /** * @brief Internal reference to the OpenGL texture to draw. Set in SetTexture() and used in paintGL(). */ OpenGLTexture texture_; /** * @brief Drawing matrix (defaults to identity) */ QMatrix4x4 matrix_; bool signal_cursor_color_; ViewerSafeMarginInfo safe_margin_; Node* gizmos_; NodeValueDatabase gizmo_db_; rational gizmo_drag_time_; VideoParams gizmo_params_; bool gizmo_click_; rational time_; FramePtr last_loaded_buffer_; private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources */ void ContextCleanup(); }; OLIVE_NAMESPACE_EXIT #endif // VIEWERGLWIDGET_H olive-continuous/app/widget/viewer/viewerplaybacktimer.cpp000066400000000000000000000025361370472574300245430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewerplaybacktimer.h" #include OLIVE_NAMESPACE_ENTER void ViewerPlaybackTimer::Start(const int64_t &start_timestamp, const int &playback_speed, const double &timebase) { start_msec_ = QDateTime::currentMSecsSinceEpoch(); start_timestamp_ = start_timestamp; playback_speed_ = playback_speed; timebase_ = timebase; } int64_t ViewerPlaybackTimer::GetTimestampNow() const { int64_t real_time = QDateTime::currentMSecsSinceEpoch() - start_msec_; int64_t frames_since_start = qRound(static_cast(real_time) / (timebase_ * 1000)); return start_timestamp_ + frames_since_start * playback_speed_; } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/viewerplaybacktimer.h000066400000000000000000000022321370472574300242010ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERPLAYBACKTIMER_H #define VIEWERPLAYBACKTIMER_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ViewerPlaybackTimer { public: void Start(const int64_t& start_timestamp, const int& playback_speed, const double& timebase); int64_t GetTimestampNow() const; private: qint64 start_msec_; int64_t start_timestamp_; int playback_speed_; double timebase_; }; OLIVE_NAMESPACE_EXIT #endif // VIEWERPLAYBACKTIMER_H olive-continuous/app/widget/viewer/viewerqueue.h000066400000000000000000000026631370472574300225060ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERQUEUE_H #define VIEWERQUEUE_H #include #include "codec/frame.h" OLIVE_NAMESPACE_ENTER struct ViewerPlaybackFrame { rational timestamp; FramePtr frame; }; class ViewerQueue : public std::list { public: ViewerQueue() = default; void AppendTimewise(const ViewerPlaybackFrame& f, int playback_speed) { if (this->empty() || (this->back().timestamp < f.timestamp) == (playback_speed > 0)) { this->push_back(f); } else { for (iterator i=this->begin(); i!=this->end(); i++) { if ((i->timestamp > f.timestamp) == (playback_speed > 0)) { this->insert(i, f); break; } } } } }; OLIVE_NAMESPACE_EXIT #endif // VIEWERQUEUE_H olive-continuous/app/widget/viewer/viewersafemargininfo.h000066400000000000000000000030771370472574300243520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERSAFEMARGININFO_H #define VIEWERSAFEMARGININFO_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER class ViewerSafeMarginInfo { public: ViewerSafeMarginInfo() : enabled_(false) { } ViewerSafeMarginInfo(bool enabled, double ratio = 0) : enabled_(enabled), ratio_(ratio) { } bool is_enabled() const { return enabled_; } bool custom_ratio() const { return (ratio_ > 0); } double ratio() const { return ratio_; } bool operator==(const ViewerSafeMarginInfo& rhs) const { return (enabled_ == rhs.enabled_ && qFuzzyCompare(ratio_, rhs.ratio_)); } bool operator!=(const ViewerSafeMarginInfo& rhs) const { return (enabled_ != rhs.enabled_ || !qFuzzyCompare(ratio_, rhs.ratio_)); } private: bool enabled_; double ratio_; }; OLIVE_NAMESPACE_EXIT #endif // VIEWERSAFEMARGININFO_H olive-continuous/app/widget/viewer/viewersizer.cpp000066400000000000000000000063711370472574300230510ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewersizer.h" #include OLIVE_NAMESPACE_ENTER ViewerSizer::ViewerSizer(QWidget *parent) : QWidget(parent), widget_(nullptr), aspect_ratio_(0), zoom_(0) { } void ViewerSizer::SetWidget(QWidget *widget) { // Delete any previous widgets occupying this space delete widget_; widget_ = widget; if (widget_ != nullptr) { widget_->setParent(this); UpdateSize(); } } void ViewerSizer::SetChildSize(int width, int height) { width_ = width; height_ = height; if (!width_ || !height_) { aspect_ratio_ = 0; } else { aspect_ratio_ = static_cast(width_) / static_cast(height_); } UpdateSize(); } void ViewerSizer::SetZoom(int percent) { zoom_ = percent; UpdateSize(); } void ViewerSizer::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); UpdateSize(); } void ViewerSizer::UpdateSize() { if (widget_ == nullptr) { return; } // If the aspect ratio is 0, the widget is always hidden if (qIsNull(aspect_ratio_)) { widget_->setVisible(false); return; } widget_->setVisible(true); QSize child_size; QMatrix4x4 child_matrix; if (zoom_ <= 0) { // If zoom is 0, we auto-fit double our_aspect_ratio = static_cast(width()) / static_cast(height()); child_size = size(); if (our_aspect_ratio > aspect_ratio_) { // This container is wider than the image, scale by height child_size = QSize(qRound(child_size.height() * aspect_ratio_), height()); } else { // This container is taller than the image, scale by width child_size = QSize(width(), qRound(child_size.width() / aspect_ratio_)); } } else { float x_scale = 1.0f; float y_scale = 1.0f; int zoomed_width = qRound(width_ * static_cast(zoom_) * 0.01); int zoomed_height = qRound(height_ * static_cast(zoom_) * 0.01); if (zoomed_width > width()) { x_scale = static_cast(zoomed_width) / static_cast(width()); zoomed_width = width(); } if (zoomed_height > height()) { y_scale = static_cast(zoomed_height) / static_cast(height()); zoomed_height = height(); } // Rather than make a huge surface, we still crop at our width/height and then signal a matrix child_matrix.scale(x_scale, y_scale, 1.0F); child_size = QSize(zoomed_width, zoomed_height); } widget_->resize(child_size); widget_->move(width() / 2 - child_size.width() / 2, height() / 2 - child_size.height() / 2); emit RequestMatrix(child_matrix); } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/viewersizer.h000066400000000000000000000052761370472574300225210ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERSIZER_H #define VIEWERSIZER_H #include #include "common/define.h" OLIVE_NAMESPACE_ENTER /** * @brief A container widget that enforces the aspect ratio of a child widget * * Using a provided width and height, this widget calculates the aspect ratio and forces the child widget to stay * confined to that aspect ratio and centered within the widget. * * The aspect ratio is calculated width divided by height. If the aspect ratio is zero (either width or height == 0), * the widget is hidden until a valid size is provided. */ class ViewerSizer : public QWidget { Q_OBJECT public: ViewerSizer(QWidget* parent = nullptr); /** * @brief Set the widget to be adjusted by this widget * * ViewerSizer takes ownership of this widget. If a widget was previously set, it is destroyed. */ void SetWidget(QWidget* widget); /** * @brief Set resolution to use * * This is not the actual resolution of the viewer, it's used to calculate the aspect ratio */ void SetChildSize(int width, int height); /** * @brief Set the zoom value of the child widget * * The number is an integer percentage (100 = 100%). Set to 0 to auto-fit. */ void SetZoom(int percent); signals: void RequestMatrix(const QMatrix4x4& matrix); protected: /** * @brief Listen for resize events to ensure the child widget remains correctly sized */ virtual void resizeEvent(QResizeEvent *event) override; private: /** * @brief Main sizing function, resizes widget_ to fit aspect_ratio_ (or hides if aspect ratio is 0) */ void UpdateSize(); /** * @brief Reference to widget * * If this is nullptr, all sizing operations are no-ops */ QWidget* widget_; /** * @brief Internal resolution values */ int width_; int height_; /** * @brief Aspect ratio calculated from the size provided by SetChildSize() */ double aspect_ratio_; /** * @brief Internal zoom value */ int zoom_; }; OLIVE_NAMESPACE_EXIT #endif // VIEWERSIZER_H olive-continuous/app/widget/viewer/viewerwindow.cpp000066400000000000000000000057361370472574300232300ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "viewerwindow.h" #include #include #include "common/timecodefunctions.h" OLIVE_NAMESPACE_ENTER ViewerWindow::ViewerWindow(QWidget *parent) : QWidget(parent, Qt::Window | Qt::WindowStaysOnTopHint) { QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); display_widget_ = new ViewerDisplayWidget(); layout->addWidget(display_widget_); } ViewerDisplayWidget *ViewerWindow::display_widget() const { return display_widget_; } void ViewerWindow::SetResolution(int width, int height) { // Set GL widget matrix to maintain this texture's aspect ratio double window_ar = static_cast(this->width()) / static_cast(this->height()); double image_ar = static_cast(width) / static_cast(height); QMatrix4x4 mat; if (window_ar > image_ar) { // Window is wider than image, adjust X scale mat.scale(image_ar / window_ar, 1.0f, 1.0f); } else if (window_ar < image_ar) { // Window is taller than image, adjust Y scale mat.scale(1.0f, window_ar / image_ar, 1.0f); } display_widget_->SetMatrix(mat); } void ViewerWindow::Play(const int64_t& start_timestamp, const int& playback_speed, const rational &timebase) { timer_.Start(start_timestamp, playback_speed, timebase.toDouble()); playback_timebase_ = timebase; connect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWindow::UpdateFromQueue); display_widget_->update(); } void ViewerWindow::Pause() { disconnect(display_widget_, &ViewerDisplayWidget::frameSwapped, this, &ViewerWindow::UpdateFromQueue); queue_.clear(); } void ViewerWindow::keyPressEvent(QKeyEvent *e) { QWidget::keyPressEvent(e); if (e->key() == Qt::Key_Escape) { close(); } } void ViewerWindow::closeEvent(QCloseEvent *e) { QWidget::closeEvent(e); deleteLater(); } void ViewerWindow::UpdateFromQueue() { int64_t t = timer_.GetTimestampNow(); rational time = Timecode::timestamp_to_time(t, playback_timebase_); while (!queue_.empty()) { const ViewerPlaybackFrame& pf = queue_.front(); if (pf.timestamp == time) { // Frame was in queue, no need to decode anything display_widget_->SetImage(pf.frame); return; } else { queue_.pop_front(); } } } OLIVE_NAMESPACE_EXIT olive-continuous/app/widget/viewer/viewerwindow.h000066400000000000000000000032071370472574300226640ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef VIEWERWINDOW_H #define VIEWERWINDOW_H #include #include "viewerdisplay.h" #include "viewerplaybacktimer.h" #include "viewerqueue.h" OLIVE_NAMESPACE_ENTER class ViewerWindow : public QWidget { public: ViewerWindow(QWidget* parent = nullptr); ViewerDisplayWidget* display_widget() const; /** * @brief Used to adjust resulting picture to be the right aspect ratio */ void SetResolution(int width, int height); ViewerQueue* queue() { return &queue_; } void Play(const int64_t &start_timestamp, const int &playback_speed, const rational &timebase); void Pause(); protected: virtual void keyPressEvent(QKeyEvent* e) override; virtual void closeEvent(QCloseEvent* e) override; private slots: void UpdateFromQueue(); private: ViewerDisplayWidget* display_widget_; ViewerQueue queue_; ViewerPlaybackTimer timer_; rational playback_timebase_; }; OLIVE_NAMESPACE_EXIT #endif // VIEWERWINDOW_H olive-continuous/app/window/000077500000000000000000000000001370472574300165035ustar00rootroot00000000000000olive-continuous/app/window/CMakeLists.txt000066400000000000000000000014241370472574300212440ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # 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 . add_subdirectory(mainwindow) set(OLIVE_SOURCES ${OLIVE_SOURCES} PARENT_SCOPE ) olive-continuous/app/window/mainwindow/000077500000000000000000000000001370472574300206575ustar00rootroot00000000000000olive-continuous/app/window/mainwindow/CMakeLists.txt000066400000000000000000000020331370472574300234150ustar00rootroot00000000000000# Olive - Non-Linear Video Editor # Copyright (C) 2019 Olive Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(OLIVE_SOURCES ${OLIVE_SOURCES} window/mainwindow/mainmenu.h window/mainwindow/mainmenu.cpp window/mainwindow/mainstatusbar.h window/mainwindow/mainstatusbar.cpp window/mainwindow/mainwindow.h window/mainwindow/mainwindow.cpp window/mainwindow/mainwindowlayoutinfo.h window/mainwindow/mainwindowlayoutinfo.cpp PARENT_SCOPE ) olive-continuous/app/window/mainwindow/mainmenu.cpp000066400000000000000000000651551370472574300232100ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "mainmenu.h" #include #include #include "common/timecodefunctions.h" #include "config/config.h" #include "core.h" #include "dialog/actionsearch/actionsearch.h" #include "dialog/task/task.h" #include "panel/panelmanager.h" #include "tool/tool.h" #include "ui/style/style.h" #include "undo/undostack.h" #include "widget/menu/menushared.h" #include "mainwindow.h" OLIVE_NAMESPACE_ENTER MainMenu::MainMenu(MainWindow *parent) : QMenuBar(parent) { StyleManager::UseOSNativeStyling(this); // // FILE MENU // file_menu_ = new Menu(this, this, &MainMenu::FileMenuAboutToShow); file_new_menu_ = new Menu(file_menu_); MenuShared::instance()->AddItemsForNewMenu(file_new_menu_); file_open_item_ = file_menu_->AddItem("openproj", Core::instance(), &Core::OpenProject, "Ctrl+O"); file_open_recent_menu_ = new Menu(file_menu_, this, &MainMenu::PopulateOpenRecent); connect(file_open_recent_menu_, &Menu::aboutToHide, this, &MainMenu::CloseOpenRecentMenu); file_open_recent_separator_ = file_open_recent_menu_->addSeparator(); file_open_recent_clear_item_ = file_open_recent_menu_->AddItem("clearopenrecent", Core::instance(), &Core::ClearOpenRecentList); file_save_item_ = file_menu_->AddItem("saveproj", Core::instance(), &Core::SaveActiveProject, "Ctrl+S"); file_save_as_item_ = file_menu_->AddItem("saveprojas", Core::instance(), &Core::SaveActiveProjectAs, "Ctrl+Shift+S"); file_save_all_item_ = file_menu_->AddItem("saveallproj", Core::instance(), &Core::SaveAllProjects); file_menu_->addSeparator(); file_import_item_ = file_menu_->AddItem("import", Core::instance(), &Core::DialogImportShow, "Ctrl+I"); file_menu_->addSeparator(); file_export_item_ = file_menu_->AddItem("export", Core::instance(), &Core::DialogExportShow, "Ctrl+M"); file_menu_->addSeparator(); file_project_properties_item_ = file_menu_->AddItem("projectproperties", Core::instance(), &Core::DialogProjectPropertiesShow); file_menu_->addSeparator(); file_close_project_item_ = file_menu_->AddItem("closeproj", Core::instance(), &Core::CloseActiveProject); file_close_all_projects_item_ = file_menu_->AddItem("closeallproj", Core::instance(), static_cast(&Core::CloseAllProjects)); file_close_all_except_item_ = file_menu_->AddItem("closeallexcept", Core::instance(), &Core::CloseAllExceptActiveProject); file_menu_->addSeparator(); file_exit_item_ = file_menu_->AddItem("exit", parent, &MainWindow::close, "Ctrl+Q"); // // EDIT MENU // edit_menu_ = new Menu(this); edit_undo_item_ = Core::instance()->undo_stack()->createUndoAction(this); Menu::ConformItem(edit_undo_item_, "undo", "Ctrl+Z"); edit_menu_->addAction(edit_undo_item_); edit_redo_item_ = Core::instance()->undo_stack()->createRedoAction(this); Menu::ConformItem(edit_redo_item_, "redo", "Ctrl+Shift+Z"); edit_menu_->addAction(edit_redo_item_); edit_menu_->addSeparator(); MenuShared::instance()->AddItemsForEditMenu(edit_menu_, true); edit_menu_->addSeparator(); edit_select_all_item_ = edit_menu_->AddItem("selectall", this, &MainMenu::SelectAllTriggered, "Ctrl+A"); edit_deselect_all_item_ = edit_menu_->AddItem("deselectall", this, &MainMenu::DeselectAllTriggered, "Ctrl+Shift+A"); edit_menu_->addSeparator(); MenuShared::instance()->AddItemsForClipEditMenu(edit_menu_); edit_menu_->addSeparator(); edit_insert_item_ = edit_menu_->AddItem("insert", this, &MainMenu::InsertTriggered, ","); edit_overwrite_item_ = edit_menu_->AddItem("overwrite", this, &MainMenu::OverwriteTriggered, "."); edit_menu_->addSeparator(); edit_ripple_to_in_item_ = edit_menu_->AddItem("rippletoin", this, &MainMenu::RippleToInTriggered, "Q"); edit_ripple_to_out_item_ = edit_menu_->AddItem("rippletoout", this, &MainMenu::RippleToOutTriggered, "W"); edit_edit_to_in_item_ = edit_menu_->AddItem("edittoin", this, &MainMenu::EditToInTriggered, "Ctrl+Alt+Q"); edit_edit_to_out_item_ = edit_menu_->AddItem("edittoout", this, &MainMenu::EditToOutTriggered, "Ctrl+Alt+W"); edit_menu_->addSeparator(); MenuShared::instance()->AddItemsForInOutMenu(edit_menu_); edit_delete_inout_item_ = edit_menu_->AddItem("deleteinout", this, &MainMenu::DeleteInOutTriggered, ";"); edit_ripple_delete_inout_item_ = edit_menu_->AddItem("rippledeleteinout", this, &MainMenu::RippleDeleteInOutTriggered, "'"); edit_menu_->addSeparator(); edit_set_marker_item_ = edit_menu_->AddItem("marker", this, &MainMenu::SetMarkerTriggered, "M"); // // VIEW MENU // view_menu_ = new Menu(this, this, &MainMenu::ViewMenuAboutToShow); view_zoom_in_item_ = view_menu_->AddItem("zoomin", this, &MainMenu::ZoomInTriggered, "="); view_zoom_out_item_ = view_menu_->AddItem("zoomout", this, &MainMenu::ZoomOutTriggered, "-"); view_increase_track_height_item_ = view_menu_->AddItem("vzoomin", this, &MainMenu::IncreaseTrackHeightTriggered, "Ctrl+="); view_decrease_track_height_item_ = view_menu_->AddItem("vzoomout", this, &MainMenu::DecreaseTrackHeightTriggered, "Ctrl+-"); view_show_all_item_ = view_menu_->AddItem("showall", this, &MainMenu::ToggleShowAllTriggered, "\\"); view_show_all_item_->setCheckable(true); view_menu_->addSeparator(); frame_view_mode_group_ = new QActionGroup(this); view_timecode_view_dropframe_item_ = view_menu_->AddItem("modedropframe", this, &MainMenu::TimecodeDisplayTriggered); view_timecode_view_dropframe_item_->setData(Timecode::kTimecodeDropFrame); view_timecode_view_dropframe_item_->setCheckable(true); frame_view_mode_group_->addAction(view_timecode_view_dropframe_item_); view_timecode_view_nondropframe_item_ = view_menu_->AddItem("modenondropframe", this, &MainMenu::TimecodeDisplayTriggered); view_timecode_view_nondropframe_item_->setData(Timecode::kTimecodeNonDropFrame); view_timecode_view_nondropframe_item_->setCheckable(true); frame_view_mode_group_->addAction(view_timecode_view_nondropframe_item_); view_timecode_view_seconds_item_ = view_menu_->AddItem("modeseconds", this, &MainMenu::TimecodeDisplayTriggered); view_timecode_view_seconds_item_->setData(Timecode::kTimecodeSeconds); view_timecode_view_seconds_item_->setCheckable(true); frame_view_mode_group_->addAction(view_timecode_view_seconds_item_); view_timecode_view_frames_item_ = view_menu_->AddItem("modeframes", this, &MainMenu::TimecodeDisplayTriggered); view_timecode_view_frames_item_->setData(Timecode::kFrames); view_timecode_view_frames_item_->setCheckable(true); frame_view_mode_group_->addAction(view_timecode_view_frames_item_); view_timecode_view_milliseconds_item_ = view_menu_->AddItem("milliseconds", this, &MainMenu::TimecodeDisplayTriggered); view_timecode_view_milliseconds_item_->setData(Timecode::kMilliseconds); view_timecode_view_milliseconds_item_->setCheckable(true); frame_view_mode_group_->addAction(view_timecode_view_milliseconds_item_); view_menu_->addSeparator(); view_full_screen_item_ = view_menu_->AddItem("fullscreen", parent, &MainWindow::SetFullscreen, "F11"); view_full_screen_item_->setCheckable(true); view_full_screen_viewer_item_ = view_menu_->AddItem("fullscreenviewer", this, &MainMenu::FullScreenViewerTriggered); // // PLAYBACK MENU // playback_menu_ = new Menu(this, this, &MainMenu::PlaybackMenuAboutToShow); playback_gotostart_item_ = playback_menu_->AddItem("gotostart", this, &MainMenu::GoToStartTriggered, "Home"); playback_prevframe_item_ = playback_menu_->AddItem("prevframe", this, &MainMenu::PrevFrameTriggered, "Left"); playback_playpause_item_ = playback_menu_->AddItem("playpause", this, &MainMenu::PlayPauseTriggered, "Space"); playback_playinout_item_ = playback_menu_->AddItem("playintoout", this, &MainMenu::PlayInToOutTriggered, "Shift+Space"); playback_nextframe_item_ = playback_menu_->AddItem("nextframe", this, &MainMenu::NextFrameTriggered, "Right"); playback_gotoend_item_ = playback_menu_->AddItem("gotoend", this, &MainMenu::GoToEndTriggered, "End"); playback_menu_->addSeparator(); playback_prevcut_item_ = playback_menu_->AddItem("prevcut", this, &MainMenu::GoToPrevCutTriggered, "Up"); playback_nextcut_item_ = playback_menu_->AddItem("nextcut", this, &MainMenu::GoToNextCutTriggered, "Down"); playback_menu_->addSeparator(); playback_gotoin_item_ = playback_menu_->AddItem("gotoin", this, &MainMenu::GoToInTriggered, "Shift+I"); playback_gotoout_item_ = playback_menu_->AddItem("gotoout", this, &MainMenu::GoToOutTriggered, "Shift+O"); playback_menu_->addSeparator(); playback_shuttleleft_item_ = playback_menu_->AddItem("decspeed", this, &MainMenu::ShuttleLeftTriggered, "J"); playback_shuttlestop_item_ = playback_menu_->AddItem("pause", this, &MainMenu::ShuttleStopTriggered, "K"); playback_shuttleright_item_ = playback_menu_->AddItem("incspeed", this, &MainMenu::ShuttleRightTriggered, "L"); playback_menu_->addSeparator(); playback_loop_item_ = playback_menu_->AddItem("loop", this, &MainMenu::LoopTriggered); playback_loop_item_->setCheckable(true); // // SEQUENCE MENU // sequence_menu_ = new Menu(this, this, &MainMenu::SequenceMenuAboutToShow); sequence_cache_item_ = sequence_menu_->AddItem("seqcache", this, &MainMenu::SequenceCacheTriggered); sequence_cache_in_to_out_item_ = sequence_menu_->AddItem("seqcacheinout", this, &MainMenu::SequenceCacheInOutTriggered); // // WINDOW MENU // window_menu_ = new Menu(this, this, &MainMenu::WindowMenuAboutToShow); window_menu_separator_ = window_menu_->addSeparator(); window_maximize_panel_item_ = window_menu_->AddItem("maximizepanel", parent, &MainWindow::ToggleMaximizedPanel, "`"); window_lock_layout_item_ = window_menu_->AddItem("lockpanels", PanelManager::instance(), &PanelManager::SetPanelsLocked); window_lock_layout_item_->setCheckable(true); window_menu_->addSeparator(); window_reset_layout_item_ = window_menu_->AddItem("resetdefaultlayout", parent, &MainWindow::SetDefaultLayout); // // TOOLS MENU // tools_menu_ = new Menu(this, this, &MainMenu::ToolsMenuAboutToShow); tools_menu_->setToolTipsVisible(true); tools_group_ = new QActionGroup(this); tools_pointer_item_ = tools_menu_->AddItem("pointertool", this, &MainMenu::ToolItemTriggered, "V"); tools_pointer_item_->setCheckable(true); tools_pointer_item_->setData(Tool::kPointer); tools_group_->addAction(tools_pointer_item_); tools_edit_item_ = tools_menu_->AddItem("edittool", this, &MainMenu::ToolItemTriggered, "X"); tools_edit_item_->setCheckable(true); tools_edit_item_->setData(Tool::kEdit); tools_group_->addAction(tools_edit_item_); tools_ripple_item_ = tools_menu_->AddItem("rippletool", this, &MainMenu::ToolItemTriggered, "B"); tools_ripple_item_->setCheckable(true); tools_ripple_item_->setData(Tool::kRipple); tools_group_->addAction(tools_ripple_item_); tools_rolling_item_ = tools_menu_->AddItem("rollingtool", this, &MainMenu::ToolItemTriggered, "N"); tools_rolling_item_->setCheckable(true); tools_rolling_item_->setData(Tool::kRolling); tools_group_->addAction(tools_rolling_item_); tools_razor_item_ = tools_menu_->AddItem("razortool", this, &MainMenu::ToolItemTriggered, "C"); tools_razor_item_->setCheckable(true); tools_razor_item_->setData(Tool::kRazor); tools_group_->addAction(tools_razor_item_); tools_slip_item_ = tools_menu_->AddItem("sliptool", this, &MainMenu::ToolItemTriggered, "Y"); tools_slip_item_->setCheckable(true); tools_slip_item_->setData(Tool::kSlip); tools_group_->addAction(tools_slip_item_); tools_slide_item_ = tools_menu_->AddItem("slidetool", this, &MainMenu::ToolItemTriggered, "U"); tools_slide_item_->setCheckable(true); tools_slide_item_->setData(Tool::kSlide); tools_group_->addAction(tools_slide_item_); tools_hand_item_ = tools_menu_->AddItem("handtool", this, &MainMenu::ToolItemTriggered, "H"); tools_hand_item_->setCheckable(true); tools_hand_item_->setData(Tool::kHand); tools_group_->addAction(tools_hand_item_); tools_zoom_item_ = tools_menu_->AddItem("zoomtool", this, &MainMenu::ToolItemTriggered, "Z"); tools_zoom_item_->setCheckable(true); tools_zoom_item_->setData(Tool::kZoom); tools_group_->addAction(tools_zoom_item_); tools_transition_item_ = tools_menu_->AddItem("transitiontool", this, &MainMenu::ToolItemTriggered, "T"); tools_transition_item_->setCheckable(true); tools_transition_item_->setData(Tool::kTransition); tools_group_->addAction(tools_transition_item_); tools_menu_->addSeparator(); tools_snapping_item_ = tools_menu_->AddItem("snapping", Core::instance(), &Core::SetSnapping, "S"); tools_snapping_item_->setCheckable(true); tools_menu_->addSeparator(); tools_preferences_item_ = tools_menu_->AddItem("prefs", Core::instance(), &Core::DialogPreferencesShow, "Ctrl+,"); // // HELP MENU // help_menu_ = new Menu(this); help_action_search_item_ = help_menu_->AddItem("actionsearch", this, &MainMenu::ActionSearchTriggered, "/"); help_menu_->addSeparator(); help_about_item_ = help_menu_->AddItem("about", Core::instance(), &Core::DialogAboutShow); Retranslate(); } void MainMenu::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { Retranslate(); } QMenuBar::changeEvent(e); } void MainMenu::ToolItemTriggered() { // Assume the sender is a QAction QAction* action = static_cast(sender()); // Assume its data() is a member of Tool::Item Tool::Item tool = static_cast(action->data().toInt()); // Set the Tool in Core Core::instance()->SetTool(tool); } void MainMenu::TimecodeDisplayTriggered() { // Assume the sender is a QAction QAction* action = static_cast(sender()); // Assume its data() is a member of Timecode::Display Timecode::Display display = static_cast(action->data().toInt()); // Set the current display mode Core::instance()->SetTimecodeDisplay(display); } void MainMenu::FileMenuAboutToShow() { Project* active_project = Core::instance()->GetActiveProject().get(); file_project_properties_item_->setEnabled(active_project); file_save_item_->setEnabled(active_project); file_save_as_item_->setEnabled(active_project); file_close_project_item_->setEnabled(active_project); file_close_all_projects_item_->setEnabled(active_project); file_close_all_except_item_->setEnabled(active_project); if (active_project) { file_save_item_->setText(tr("&Save '%1'").arg(active_project->pretty_filename())); file_save_as_item_->setText(tr("Save '%1' &As").arg(active_project->pretty_filename())); file_close_project_item_->setText(tr("Close '%1'").arg(active_project->pretty_filename())); file_close_all_except_item_->setText(tr("Close All Except '%1'").arg(active_project->pretty_filename())); } else { file_save_item_->setText(tr("&Save Project")); file_save_as_item_->setText(tr("Save Project &As")); file_close_project_item_->setText(tr("Close Project")); file_close_all_except_item_->setText(tr("Close All Except Current Project")); } } void MainMenu::ViewMenuAboutToShow() { // Parent is QMainWindow view_full_screen_item_->setChecked(parentWidget()->isFullScreen()); // Ensure checked timecode display mode is correct QList timecode_display_actions = frame_view_mode_group_->actions(); foreach (QAction* a, timecode_display_actions) { if (a->data() == Core::instance()->GetTimecodeDisplay()) { a->setChecked(true); break; } } } void MainMenu::ToolsMenuAboutToShow() { // Ensure checked Tool is correct QList tool_actions = tools_group_->actions(); foreach (QAction* a, tool_actions) { if (a->data() == Core::instance()->tool()) { a->setChecked(true); break; } } // Ensure snapping value is correct tools_snapping_item_->setChecked(Core::instance()->snapping()); } void MainMenu::PlaybackMenuAboutToShow() { playback_loop_item_->setChecked(Config::Current()["Loop"].toBool()); } void MainMenu::SequenceMenuAboutToShow() { TimeBasedPanel* p = PanelManager::instance()->MostRecentlyFocused(); bool can_cache_sequence = (p && p->GetConnectedViewer()); sequence_cache_item_->setEnabled(can_cache_sequence); sequence_cache_in_to_out_item_->setEnabled(can_cache_sequence); } void MainMenu::WindowMenuAboutToShow() { // Remove any previous items while (window_menu_->actions().first() != window_menu_separator_) { window_menu_->removeAction(window_menu_->actions().first()); } QList panel_actions; // Alphabetize actions - keeps actions in a consistent order since PanelManager::panels() is // ordered from most recently focused to least, which may be confusing user experience. foreach (PanelWidget* panel, PanelManager::instance()->panels()) { QAction* panel_action = panel->toggleViewAction(); bool inserted = false; for (int i=0;itext() > panel_action->text()) { panel_actions.insert(i, panel_action); inserted = true; break; } } if (!inserted) { panel_actions.append(panel_action); } } // Add new items window_menu_->insertActions(window_menu_separator_, panel_actions); window_lock_layout_item_->setChecked(PanelManager::instance()->ArePanelsLocked()); } void MainMenu::PopulateOpenRecent() { if (Core::instance()->GetRecentProjects().isEmpty()) { // Insert dummy/disabled action to show there's nothing QAction* a = new QAction(tr("(None)")); a->setEnabled(false); file_open_recent_menu_->insertAction(file_open_recent_separator_, a); } else { // Populate menu with recently opened projects for (int i=0;iGetRecentProjects().size();i++) { QAction* a = new QAction(Core::instance()->GetRecentProjects().at(i)); a->setData(i); connect(a, &QAction::triggered, this, &MainMenu::OpenRecentItemTriggered); file_open_recent_menu_->insertAction(file_open_recent_separator_, a); } } } void MainMenu::CloseOpenRecentMenu() { while (file_open_recent_menu_->actions().first() != file_open_recent_separator_) { file_open_recent_menu_->removeAction(file_open_recent_menu_->actions().first()); } } void MainMenu::ZoomInTriggered() { PanelManager::instance()->CurrentlyFocused()->ZoomIn(); } void MainMenu::ZoomOutTriggered() { PanelManager::instance()->CurrentlyFocused()->ZoomOut(); } void MainMenu::IncreaseTrackHeightTriggered() { PanelManager::instance()->CurrentlyFocused()->IncreaseTrackHeight(); } void MainMenu::DecreaseTrackHeightTriggered() { PanelManager::instance()->CurrentlyFocused()->DecreaseTrackHeight(); } void MainMenu::GoToStartTriggered() { PanelManager::instance()->CurrentlyFocused()->GoToStart(); } void MainMenu::PrevFrameTriggered() { PanelManager::instance()->CurrentlyFocused()->PrevFrame(); } void MainMenu::PlayPauseTriggered() { PanelManager::instance()->CurrentlyFocused()->PlayPause(); } void MainMenu::PlayInToOutTriggered() { PanelManager::instance()->CurrentlyFocused()->PlayInToOut(); } void MainMenu::LoopTriggered(bool enabled) { Config::Current()["Loop"] = enabled; } void MainMenu::NextFrameTriggered() { PanelManager::instance()->CurrentlyFocused()->NextFrame(); } void MainMenu::GoToEndTriggered() { PanelManager::instance()->CurrentlyFocused()->GoToEnd(); } void MainMenu::SelectAllTriggered() { PanelManager::instance()->CurrentlyFocused()->SelectAll(); } void MainMenu::DeselectAllTriggered() { PanelManager::instance()->CurrentlyFocused()->DeselectAll(); } void MainMenu::InsertTriggered() { PanelManager::instance()->CurrentlyFocused()->Insert(); } void MainMenu::OverwriteTriggered() { PanelManager::instance()->CurrentlyFocused()->Overwrite(); } void MainMenu::RippleToInTriggered() { PanelManager::instance()->CurrentlyFocused()->RippleToIn(); } void MainMenu::RippleToOutTriggered() { PanelManager::instance()->CurrentlyFocused()->RippleToOut(); } void MainMenu::EditToInTriggered() { PanelManager::instance()->CurrentlyFocused()->EditToIn(); } void MainMenu::EditToOutTriggered() { PanelManager::instance()->CurrentlyFocused()->EditToOut(); } void MainMenu::ActionSearchTriggered() { ActionSearch as(parentWidget()); as.SetMenuBar(this); as.exec(); } void MainMenu::ShuttleLeftTriggered() { PanelManager::instance()->CurrentlyFocused()->ShuttleLeft(); } void MainMenu::ShuttleStopTriggered() { PanelManager::instance()->CurrentlyFocused()->ShuttleStop(); } void MainMenu::ShuttleRightTriggered() { PanelManager::instance()->CurrentlyFocused()->ShuttleRight(); } void MainMenu::GoToPrevCutTriggered() { PanelManager::instance()->CurrentlyFocused()->GoToPrevCut(); } void MainMenu::GoToNextCutTriggered() { PanelManager::instance()->CurrentlyFocused()->GoToNextCut(); } void MainMenu::SetMarkerTriggered() { PanelManager::instance()->CurrentlyFocused()->SetMarker(); } void MainMenu::FullScreenViewerTriggered() { PanelManager::instance()->MostRecentlyFocused()->SetFullScreen(); } void MainMenu::ToggleShowAllTriggered() { PanelManager::instance()->CurrentlyFocused()->ToggleShowAll(); } void MainMenu::DeleteInOutTriggered() { PanelManager::instance()->CurrentlyFocused()->DeleteInToOut(); } void MainMenu::RippleDeleteInOutTriggered() { PanelManager::instance()->CurrentlyFocused()->RippleDeleteInToOut(); } void MainMenu::GoToInTriggered() { PanelManager::instance()->CurrentlyFocused()->GoToIn(); } void MainMenu::GoToOutTriggered() { PanelManager::instance()->CurrentlyFocused()->GoToOut(); } void MainMenu::OpenRecentItemTriggered() { Core::instance()->OpenProjectFromRecentList(static_cast(sender())->data().toInt()); } void MainMenu::SequenceCacheTriggered() { Core::instance()->CacheActiveSequence(false); } void MainMenu::SequenceCacheInOutTriggered() { Core::instance()->CacheActiveSequence(true); } void MainMenu::Retranslate() { // MenuShared is not a QWidget and therefore does not receive a LanguageEvent, we use MainMenu's to update it MenuShared::instance()->Retranslate(); // File menu file_menu_->setTitle(tr("&File")); file_new_menu_->setTitle(tr("&New")); file_open_item_->setText(tr("&Open Project")); file_open_recent_menu_->setTitle(tr("Open &Recent")); file_open_recent_clear_item_->setText(tr("&Clear Recent List")); file_save_all_item_->setText(tr("Sa&ve All Projects")); file_import_item_->setText(tr("&Import...")); file_export_item_->setText(tr("&Export...")); file_project_properties_item_->setText(tr("&Project Properties...")); file_close_all_projects_item_->setText(tr("Close All Projects")); file_exit_item_->setText(tr("E&xit")); // Edit menu edit_menu_->setTitle(tr("&Edit")); //edit_undo_item_->setText(tr("&Undo")); FIXME: Does Qt translate these automatically? //edit_redo_item_->setText(tr("Redo")); edit_insert_item_->setText(tr("Insert")); edit_overwrite_item_->setText(tr("Overwrite")); edit_select_all_item_->setText(tr("Select &All")); edit_deselect_all_item_->setText(tr("Deselect All")); edit_ripple_to_in_item_->setText(tr("Ripple to In Point")); edit_ripple_to_out_item_->setText(tr("Ripple to Out Point")); edit_edit_to_in_item_->setText(tr("Edit to In Point")); edit_edit_to_out_item_->setText(tr("Edit to Out Point")); edit_delete_inout_item_->setText(tr("Delete In/Out Point")); edit_ripple_delete_inout_item_->setText(tr("Ripple Delete In/Out Point")); edit_set_marker_item_->setText(tr("Set/Edit Marker")); // View menu view_menu_->setTitle(tr("&View")); view_zoom_in_item_->setText(tr("Zoom In")); view_zoom_out_item_->setText(tr("Zoom Out")); view_increase_track_height_item_->setText(tr("Increase Track Height")); view_decrease_track_height_item_->setText(tr("Decrease Track Height")); view_show_all_item_->setText(tr("Toggle Show All")); view_timecode_view_frames_item_->setText(tr("Frames")); view_timecode_view_dropframe_item_->setText(tr("Drop Frame")); view_timecode_view_nondropframe_item_->setText(tr("Non-Drop Frame")); view_timecode_view_milliseconds_item_->setText(tr("Milliseconds")); view_timecode_view_seconds_item_->setText(tr("Seconds")); // View menu (cont'd) view_full_screen_item_->setText(tr("Full Screen")); view_full_screen_viewer_item_->setText(tr("Full Screen Viewer")); // Playback menu playback_menu_->setTitle(tr("&Playback")); playback_gotostart_item_->setText(tr("Go to Start")); playback_prevframe_item_->setText(tr("Previous Frame")); playback_playpause_item_->setText(tr("Play/Pause")); playback_playinout_item_->setText(tr("Play In to Out")); playback_nextframe_item_->setText(tr("Next Frame")); playback_gotoend_item_->setText(tr("Go to End")); playback_prevcut_item_->setText(tr("Go to Previous Cut")); playback_nextcut_item_->setText(tr("Go to Next Cut")); playback_gotoin_item_->setText(tr("Go to In Point")); playback_gotoout_item_->setText(tr("Go to Out Point")); playback_shuttleleft_item_->setText(tr("Shuttle Left")); playback_shuttlestop_item_->setText(tr("Shuttle Stop")); playback_shuttleright_item_->setText(tr("Shuttle Right")); playback_loop_item_->setText(tr("Loop")); // Sequence menu sequence_menu_->setTitle(tr("&Sequence")); sequence_cache_item_->setText(tr("Cache Entire Sequence")); sequence_cache_in_to_out_item_->setText(tr("Cache Sequence In/Out")); // Window menu window_menu_->setTitle("&Window"); window_maximize_panel_item_->setText(tr("Maximize Panel")); window_lock_layout_item_->setText(tr("Lock Panels")); window_reset_layout_item_->setText(tr("Reset to Default Layout")); // Tools menu tools_menu_->setTitle(tr("&Tools")); tools_pointer_item_->setText(tr("Pointer Tool")); tools_edit_item_->setText(tr("Edit Tool")); tools_ripple_item_->setText(tr("Ripple Tool")); tools_rolling_item_->setText(tr("Rolling Tool")); tools_razor_item_->setText(tr("Razor Tool")); tools_slip_item_->setText(tr("Slip Tool")); tools_slide_item_->setText(tr("Slide Tool")); tools_hand_item_->setText(tr("Hand Tool")); tools_zoom_item_->setText(tr("Zoom Tool")); tools_transition_item_->setText(tr("Transition Tool")); tools_snapping_item_->setText(tr("Enable Snapping")); tools_preferences_item_->setText(tr("Preferences")); // Help menu help_menu_->setTitle(tr("&Help")); help_action_search_item_->setText(tr("A&ction Search")); help_about_item_->setText(tr("&About...")); } OLIVE_NAMESPACE_EXIT olive-continuous/app/window/mainwindow/mainmenu.h000066400000000000000000000161041370472574300226430ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MAINMENU_H #define MAINMENU_H #include #include #include "dialog/actionsearch/actionsearch.h" #include "widget/menu/menu.h" OLIVE_NAMESPACE_ENTER class MainWindow; /** * @brief Olive's main menubar attached to its main window. * * Responsible for creating the menu, connecting signals/slots, and retranslating the items on a language change. */ class MainMenu : public QMenuBar { Q_OBJECT public: MainMenu(MainWindow *parent); protected: /** * @brief changeEvent * * Qt changeEvent override to catch a QEvent::LanguageEvent. * * @param e */ virtual void changeEvent(QEvent* e); private slots: /** * @brief A slot for the Tool selection items * * Assumes a QAction* sender() and its data() is a member of enum Tool::Item. Uses the data() to signal a * Tool change throughout the rest of the application. */ void ToolItemTriggered(); /** * @brief A slot for the timecode display menu items * * Assumes a QAction* sender() and its data() is a member of enum Timecode::Display. Uses the data() to signal a * timecode change throughout the rest of the application. */ void TimecodeDisplayTriggered(); /** * @brief Slot triggered just before the File menu shows */ void FileMenuAboutToShow(); /** * @brief Slot triggered just before the View menu shows */ void ViewMenuAboutToShow(); /** * @brief Slot triggered just before the Tools menu shows */ void ToolsMenuAboutToShow(); /** * @brief Slot triggered just before the Playback menu shows */ void PlaybackMenuAboutToShow(); /** * @brief Slot triggered just before the Sequence menu shows */ void SequenceMenuAboutToShow(); /** * @brief Slot triggered just before the Window menu shows */ void WindowMenuAboutToShow(); /** * @brief Adds items to open recent menu */ void PopulateOpenRecent(); /** * @brief Clears open recent items when menu closes */ void CloseOpenRecentMenu(); /** * @brief Slot for zooming in * * Finds the currently focused panel and sends it a "zoom in" signal */ void ZoomInTriggered(); /** * @brief Slot for zooming out * * Finds the currently focused panel and sends it a "zoom out" signal */ void ZoomOutTriggered(); void IncreaseTrackHeightTriggered(); void DecreaseTrackHeightTriggered(); void GoToStartTriggered(); void PrevFrameTriggered(); /** * @brief Slot for play/pause * * Finds the currently focused panel and sends it a "play/pause" signal */ void PlayPauseTriggered(); void PlayInToOutTriggered(); void LoopTriggered(bool enabled); void NextFrameTriggered(); void GoToEndTriggered(); void SelectAllTriggered(); void DeselectAllTriggered(); void InsertTriggered(); void OverwriteTriggered(); void RippleToInTriggered(); void RippleToOutTriggered(); void EditToInTriggered(); void EditToOutTriggered(); void ActionSearchTriggered(); void ShuttleLeftTriggered(); void ShuttleStopTriggered(); void ShuttleRightTriggered(); void GoToPrevCutTriggered(); void GoToNextCutTriggered(); void SetMarkerTriggered(); void FullScreenViewerTriggered(); void ToggleShowAllTriggered(); void DeleteInOutTriggered(); void RippleDeleteInOutTriggered(); void GoToInTriggered(); void GoToOutTriggered(); void OpenRecentItemTriggered(); void SequenceCacheTriggered(); void SequenceCacheInOutTriggered(); private: /** * @brief Set strings based on the current application language. */ void Retranslate(); Menu* file_menu_; Menu* file_new_menu_; QAction* file_open_item_; Menu* file_open_recent_menu_; QAction* file_open_recent_separator_; QAction* file_open_recent_clear_item_; QAction* file_save_item_; QAction* file_save_as_item_; QAction* file_save_all_item_; QAction* file_import_item_; QAction* file_export_item_; QAction* file_project_properties_item_; QAction* file_close_project_item_; QAction* file_close_all_projects_item_; QAction* file_close_all_except_item_; QAction* file_exit_item_; Menu* edit_menu_; QAction* edit_undo_item_; QAction* edit_redo_item_; QAction* edit_select_all_item_; QAction* edit_deselect_all_item_; QAction* edit_insert_item_; QAction* edit_overwrite_item_; QAction* edit_ripple_to_in_item_; QAction* edit_ripple_to_out_item_; QAction* edit_edit_to_in_item_; QAction* edit_edit_to_out_item_; QAction* edit_delete_inout_item_; QAction* edit_ripple_delete_inout_item_; QAction* edit_set_marker_item_; Menu* view_menu_; QAction* view_zoom_in_item_; QAction* view_zoom_out_item_; QAction* view_increase_track_height_item_; QAction* view_decrease_track_height_item_; QAction* view_show_all_item_; QActionGroup* frame_view_mode_group_; QAction* view_timecode_view_dropframe_item_; QAction* view_timecode_view_nondropframe_item_; QAction* view_timecode_view_seconds_item_; QAction* view_timecode_view_frames_item_; QAction* view_timecode_view_milliseconds_item_; QAction* view_full_screen_item_; QAction* view_full_screen_viewer_item_; Menu* playback_menu_; QAction* playback_gotostart_item_; QAction* playback_prevframe_item_; QAction* playback_playpause_item_; QAction* playback_playinout_item_; QAction* playback_nextframe_item_; QAction* playback_gotoend_item_; QAction* playback_prevcut_item_; QAction* playback_nextcut_item_; QAction* playback_gotoin_item_; QAction* playback_gotoout_item_; QAction* playback_shuttleleft_item_; QAction* playback_shuttlestop_item_; QAction* playback_shuttleright_item_; QAction* playback_loop_item_; Menu* sequence_menu_; QAction* sequence_cache_item_; QAction* sequence_cache_in_to_out_item_; Menu* window_menu_; QAction* window_menu_separator_; QAction* window_maximize_panel_item_; QAction* window_lock_layout_item_; QAction* window_reset_layout_item_; Menu* tools_menu_; QActionGroup* tools_group_; QAction* tools_pointer_item_; QAction* tools_edit_item_; QAction* tools_ripple_item_; QAction* tools_rolling_item_; QAction* tools_razor_item_; QAction* tools_slip_item_; QAction* tools_slide_item_; QAction* tools_hand_item_; QAction* tools_zoom_item_; QAction* tools_transition_item_; QAction* tools_snapping_item_; QAction* tools_preferences_item_; Menu* help_menu_; QAction* help_action_search_item_; QAction* help_about_item_; }; OLIVE_NAMESPACE_EXIT #endif // MAINMENU_H olive-continuous/app/window/mainwindow/mainstatusbar.cpp000066400000000000000000000053251370472574300242450ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "mainstatusbar.h" #include OLIVE_NAMESPACE_ENTER MainStatusBar::MainStatusBar(QWidget *parent) : QStatusBar(parent), manager_(nullptr), connected_task_(nullptr) { setSizeGripEnabled(false); bar_ = new QProgressBar(); addPermanentWidget(bar_); bar_->setMinimum(0); bar_->setMaximum(100); bar_->setVisible(false); showMessage(tr("Welcome to %1 %2").arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion())); } void MainStatusBar::ConnectTaskManager(TaskManager *manager) { if (manager_) { disconnect(manager_, &TaskManager::TaskListChanged, this, &MainStatusBar::UpdateStatus); } manager_ = manager; if (manager_) { connect(manager_, &TaskManager::TaskListChanged, this, &MainStatusBar::UpdateStatus); } } void MainStatusBar::UpdateStatus() { if (!manager_) { return; } if (manager_->GetTaskCount() == 0) { clearMessage(); bar_->setVisible(false); bar_->setValue(0); } else { Task* t = manager_->GetFirstTask(); if (manager_->GetTaskCount() == 1) { showMessage(t->GetTitle()); } else { showMessage(tr("Running %1 background tasks").arg(manager_->GetTaskCount())); } bar_->setVisible(true); if (connected_task_) { disconnect(connected_task_, &Task::ProgressChanged, this, &MainStatusBar::SetProgressBarValue); disconnect(connected_task_, &Task::destroyed, this, &MainStatusBar::ConnectedTaskDeleted); } connected_task_ = t; connect(connected_task_, &Task::ProgressChanged, this, &MainStatusBar::SetProgressBarValue); connect(connected_task_, &Task::destroyed, this, &MainStatusBar::ConnectedTaskDeleted); } } void MainStatusBar::SetProgressBarValue(double d) { bar_->setValue(qRound(100.0 * d)); } void MainStatusBar::ConnectedTaskDeleted() { connected_task_ = nullptr; } void MainStatusBar::mouseDoubleClickEvent(QMouseEvent* e) { QStatusBar::mouseDoubleClickEvent(e); emit DoubleClicked(); } OLIVE_NAMESPACE_EXIT olive-continuous/app/window/mainwindow/mainstatusbar.h000066400000000000000000000026471370472574300237160ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MAINSTATUSBAR_H #define MAINSTATUSBAR_H #include #include #include "task/taskmanager.h" OLIVE_NAMESPACE_ENTER /** * @brief Shows abbreviated information from a TaskManager object */ class MainStatusBar : public QStatusBar { Q_OBJECT public: MainStatusBar(QWidget* parent = nullptr); void ConnectTaskManager(TaskManager* manager); signals: void DoubleClicked(); protected: virtual void mouseDoubleClickEvent(QMouseEvent* e) override; private slots: void UpdateStatus(); void SetProgressBarValue(double d); void ConnectedTaskDeleted(); private: TaskManager* manager_; QProgressBar* bar_; Task* connected_task_; }; OLIVE_NAMESPACE_EXIT #endif // MAINSTATUSBAR_H olive-continuous/app/window/mainwindow/mainwindow.cpp000066400000000000000000000511771370472574300235520ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #include "mainwindow.h" #include #include #include #include #include "mainmenu.h" #include "mainstatusbar.h" OLIVE_NAMESPACE_ENTER MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // Resizes main window to desktop geometry on startup. Fixes the following issues: // * Qt on Windows has a bug that "de-maximizes" the window when widgets are added, resizing the // window beforehand works around that issue and we just set it to whatever size is available. // * On Linux, it seems the window starts off at a vastly different size and then maximizes // which throws off the proportions and makes the resulting layout wonky. resize(qApp->desktop()->availableGeometry(this).size()); #ifdef Q_OS_WINDOWS // Set up taskbar button progress bar (used for some modal tasks like exporting) taskbar_btn_id_ = RegisterWindowMessage("TaskbarButtonCreated"); taskbar_interface_ = nullptr; #endif // Create empty central widget - we don't actually want a central widget (so we set its maximum // size to 0,0) but some of Qt's docking/undocking fails without it QWidget* centralWidget = new QWidget(this); centralWidget->setMaximumSize(QSize(0, 0)); setCentralWidget(centralWidget); // Set tabs to be on top of panels (default behavior is bottom) setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); // Allow panels to be tabbed within each other setDockNestingEnabled(true); // Create and set main menu MainMenu* main_menu = new MainMenu(this); setMenuBar(main_menu); // Create and set status bar MainStatusBar* status_bar = new MainStatusBar(this); status_bar->ConnectTaskManager(TaskManager::instance()); connect(status_bar, &MainStatusBar::DoubleClicked, this, &MainWindow::StatusBarDoubleClicked); setStatusBar(status_bar); // Create standard panels node_panel_ = PanelManager::instance()->CreatePanel(this); footage_viewer_panel_ = PanelManager::instance()->CreatePanel(this); param_panel_ = PanelManager::instance()->CreatePanel(this); table_panel_ = PanelManager::instance()->CreatePanel(this); sequence_viewer_panel_ = PanelManager::instance()->CreatePanel(this); pixel_sampler_panel_ = PanelManager::instance()->CreatePanel(this); AppendProjectPanel(); tool_panel_ = PanelManager::instance()->CreatePanel(this); task_man_panel_ = PanelManager::instance()->CreatePanel(this); AppendTimelinePanel(); audio_monitor_panel_ = PanelManager::instance()->CreatePanel(this); // Make connections to sequence viewer connect(node_panel_, &NodePanel::SelectionChanged, param_panel_, &ParamPanel::SetNodes); connect(node_panel_, &NodePanel::SelectionChanged, table_panel_, &NodeTablePanel::SetNodes); connect(param_panel_, &ParamPanel::RequestSelectNode, node_panel_, &NodePanel::Select); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTimestamp); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); connect(param_panel_, &ParamPanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTimestamp); connect(param_panel_, &ParamPanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); connect(param_panel_, &ParamPanel::FoundGizmos, sequence_viewer_panel_, &SequenceViewerPanel::SetGizmos); connect(PanelManager::instance(), &PanelManager::FocusedPanelChanged, this, &MainWindow::FocusedPanelChanged); sequence_viewer_panel_->ConnectTimeBasedPanel(param_panel_); footage_viewer_panel_->ConnectPixelSamplerPanel(pixel_sampler_panel_); sequence_viewer_panel_->ConnectPixelSamplerPanel(pixel_sampler_panel_); UpdateTitle(); QMetaObject::invokeMethod(this, "SetDefaultLayout", Qt::QueuedConnection); } MainWindow::~MainWindow() { #ifdef Q_OS_WINDOWS if (taskbar_interface_) { taskbar_interface_->Release(); } #endif } void MainWindow::LoadLayout(const MainWindowLayoutInfo &info) { foreach (Folder* folder, info.open_folders()) { FolderOpen(folder->project(), folder, true); } foreach (const MainWindowLayoutInfo::OpenSequence& sequence, info.open_sequences()) { TimelinePanel* panel = OpenSequence(sequence.sequence, info.open_sequences().size() == 1); panel->RestoreSplitterState(sequence.panel_state); } restoreState(info.state()); } MainWindowLayoutInfo MainWindow::SaveLayout() const { MainWindowLayoutInfo info; foreach (ProjectPanel* panel, folder_panels_) { if (panel->project()) { info.add_folder(static_cast(panel->get_root_index().internalPointer())); } } foreach (TimelinePanel* panel, timeline_panels_) { if (panel->GetConnectedViewer()) { info.add_sequence({static_cast(panel->GetConnectedViewer()->parent()), panel->SaveSplitterState()}); } } info.set_state(saveState()); return info; } TimelinePanel* MainWindow::OpenSequence(Sequence *sequence, bool enable_focus) { // See if this sequence is already open, and switch to it if so foreach (TimelinePanel* tl, timeline_panels_) { if (tl->GetConnectedViewer() == sequence->viewer_output()) { tl->raise(); return tl; } } // See if we have any sequences open or not TimelinePanel* panel; if (!timeline_panels_.first()->GetConnectedViewer()) { panel = timeline_panels_.first(); } else { panel = AppendTimelinePanel(); enable_focus = false; } panel->ConnectViewerNode(sequence->viewer_output()); if (enable_focus) { TimelineFocused(sequence->viewer_output()); } return panel; } void MainWindow::CloseSequence(Sequence *sequence) { // We defer to RemoveTimelinePanel() to close the panels, which may delete and remove indices from timeline_panels_. // We make a copy so that our array here doesn't get ruined by what RemoveTimelinePanel() does QList copy = timeline_panels_; foreach (TimelinePanel* tp, copy) { if (tp->GetConnectedViewer() == sequence->viewer_output()) { RemoveTimelinePanel(tp); } } } bool MainWindow::IsSequenceOpen(Sequence *sequence) const { foreach (TimelinePanel* tp, timeline_panels_) { if (tp->GetConnectedViewer() == sequence->viewer_output()) { return true; } } return false; } void MainWindow::FolderOpen(Project* p, Item *i, bool floating) { ProjectPanel* panel = PanelManager::instance()->CreatePanel(this); // Set custom name to distinguish it from regular ProjectPanels panel->setObjectName(QStringLiteral("FolderPanel")); SetUniquePanelID(panel, folder_panels_); panel->set_project(p); panel->set_root(i); // Tabify with source project panel foreach (ProjectPanel* proj_panel, project_panels_) { if (proj_panel->project() == p) { tabifyDockWidget(proj_panel, panel); break; } } panel->setFloating(floating); panel->show(); panel->raise(); // If the panel is closed, just destroy it panel->SetSignalInsteadOfClose(true); panel->setProperty("parent_list", reinterpret_cast(&folder_panels_)); connect(panel, &ProjectPanel::CloseRequested, this, &MainWindow::FloatingPanelCloseRequested); folder_panels_.append(panel); } ScopePanel *MainWindow::AppendScopePanel() { return AppendFloatingPanelInternal(scope_panels_); } CurvePanel *MainWindow::AppendCurvePanel() { CurvePanel* p = AppendFloatingPanelInternal(curve_panels_); sequence_viewer_panel_->ConnectTimeBasedPanel(p); return p; /*connect(panel, &TimelinePanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, panel, &TimelinePanel::SetTime); connect(param_panel_, &ParamPanel::SelectedInputChanged, curve_panel_, &CurvePanel::SetInput); connect(param_panel_, &ParamPanel::TimebaseChanged, curve_panel_, &CurvePanel::SetTimebase); connect(param_panel_, &ParamPanel::TimeTargetChanged, curve_panel_, &CurvePanel::SetTimeTarget); connect(param_panel_, &ParamPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTime); connect(curve_panel_, &CurvePanel::TimeChanged, param_panel_, &ParamPanel::SetTime); sequence_viewer_panel_->ConnectTimeBasedPanel(curve_panel_); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, curve_panel_, &CurvePanel::SetTime);*/ } void MainWindow::SetFullscreen(bool fullscreen) { if (fullscreen) { setWindowState(windowState() | Qt::WindowFullScreen); } else { setWindowState(windowState() & ~Qt::WindowFullScreen); } } void MainWindow::ToggleMaximizedPanel() { if (premaximized_state_.isEmpty()) { // Assume nothing is maximized at the moment // Find the currently focused panel PanelWidget* currently_hovered = PanelManager::instance()->CurrentlyHovered(); // If no panel is hovered, do nothing if (currently_hovered == nullptr) { return; } // If this panel is not actually on the main window, this is a no-op if (currently_hovered->isFloating()) { return; } // Save the current state so it can be restored later premaximized_state_ = saveState(); // For every other panel that is on the main window, hide it foreach (PanelWidget* panel, PanelManager::instance()->panels()) { if (!panel->isFloating() && panel != currently_hovered) { panel->setVisible(false); } } } else { // Assume we are currently maximized, restore the state restoreState(premaximized_state_); premaximized_state_.clear(); } } void MainWindow::ProjectOpen(Project *p) { // See if this project is already open, and switch to it if so foreach (ProjectPanel* pl, project_panels_) { if (pl->project() == p) { pl->raise(); return; } } ProjectPanel* panel; if (!project_panels_.first()->project()) { panel = project_panels_.first(); } else { panel = AppendProjectPanel(); } panel->set_project(p); } void MainWindow::ProjectClose(Project *p) { // Close project from project panel foreach (ProjectPanel* panel, project_panels_) { if (panel->project() == p) { RemoveProjectPanel(panel); } } foreach (ProjectPanel* panel, folder_panels_) { if (panel->project() == p) { panel->close(); } } // Close any open sequences from project QList open_sequences = p->get_items_of_type(Item::kSequence); foreach (ItemPtr item, open_sequences) { Sequence* seq = static_cast(item.get()); if (IsSequenceOpen(seq)) { CloseSequence(seq); } } } void MainWindow::SetApplicationProgressStatus(ProgressStatus status) { #if defined(Q_OS_WINDOWS) if (taskbar_interface_) { switch (status) { case kProgressShow: taskbar_interface_->SetProgressState(reinterpret_cast(this->winId()), TBPF_NORMAL); break; case kProgressNone: taskbar_interface_->SetProgressState(reinterpret_cast(this->winId()), TBPF_NOPROGRESS); break; case kProgressError: taskbar_interface_->SetProgressState(reinterpret_cast(this->winId()), TBPF_ERROR); break; } } #elif defined(Q_OS_MAC) #endif } void MainWindow::SetApplicationProgressValue(int value) { #if defined(Q_OS_WINDOWS) if (taskbar_interface_) { taskbar_interface_->SetProgressValue(reinterpret_cast(this->winId()), value, 100); } #elif defined(Q_OS_MAC) #endif } void MainWindow::closeEvent(QCloseEvent *e) { // Try to close all projects (this will return false if the user chooses not to close) if (!Core::instance()->CloseAllProjects(false)) { e->ignore(); return; } PanelManager::instance()->DeleteAllPanels(); QMainWindow::closeEvent(e); } #ifdef Q_OS_WINDOWS bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) { if (static_cast(message)->message == taskbar_btn_id_) { // Attempt to create taskbar button progress handle HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, reinterpret_cast(&taskbar_interface_)); if (SUCCEEDED(hr)) { hr = taskbar_interface_->HrInit(); if (FAILED(hr)) { taskbar_interface_->Release(); taskbar_interface_ = nullptr; } } } return QMainWindow::nativeEvent(eventType, message, result); } #endif void MainWindow::StatusBarDoubleClicked() { task_man_panel_->show(); task_man_panel_->raise(); } #ifdef Q_OS_LINUX void MainWindow::ShowNouveauWarning() { QMessageBox::warning(this, tr("Driver Warning"), tr("Olive has detected your system is using the Nouveau graphics driver.\n\nThis driver is " "known to have stability and performance issues with Olive. It is highly recommended " "you install the proprietary NVIDIA driver before continuing to use Olive."), QMessageBox::Ok); } #endif void MainWindow::UpdateTitle() { if (Core::instance()->GetActiveProject()) { setWindowTitle(QStringLiteral("%1 %2 - [*]%3").arg(QApplication::applicationName(), QApplication::applicationVersion(), Core::instance()->GetActiveProject()->pretty_filename())); } else { setWindowTitle(QStringLiteral("%1 %2").arg(QApplication::applicationName(), QApplication::applicationVersion())); } } void MainWindow::TimelineCloseRequested() { RemoveTimelinePanel(static_cast(sender())); } void MainWindow::ProjectCloseRequested() { ProjectPanel* panel = static_cast(sender()); Project* p = panel->project(); Core::instance()->CloseProject(Core::instance()->GetSharedPtrFromProject(p), true); } void MainWindow::FloatingPanelCloseRequested() { PanelWidget* panel = static_cast(sender()); quintptr list_ptr = panel->property("parent_list").value(); QList* list = reinterpret_cast< QList* >(list_ptr); list->removeOne(panel); panel->deleteLater(); } TimelinePanel* MainWindow::AppendTimelinePanel() { TimelinePanel* panel = AppendPanelInternal(timeline_panels_); connect(panel, &PanelWidget::CloseRequested, this, &MainWindow::TimelineCloseRequested); connect(panel, &TimelinePanel::TimeChanged, param_panel_, &ParamPanel::SetTimestamp); connect(panel, &TimelinePanel::TimeChanged, table_panel_, &NodeTablePanel::SetTimestamp); connect(panel, &TimelinePanel::TimeChanged, sequence_viewer_panel_, &SequenceViewerPanel::SetTimestamp); connect(panel, &TimelinePanel::SelectionChanged, node_panel_, &NodePanel::SelectBlocks); connect(param_panel_, &ParamPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp); connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, panel, &TimelinePanel::SetTimestamp); sequence_viewer_panel_->ConnectTimeBasedPanel(panel); return panel; } ProjectPanel *MainWindow::AppendProjectPanel() { ProjectPanel* panel = AppendPanelInternal(project_panels_); connect(panel, &PanelWidget::CloseRequested, this, &MainWindow::ProjectCloseRequested); connect(panel, &ProjectPanel::ProjectNameChanged, this, &MainWindow::UpdateTitle); return panel; } void MainWindow::RemoveTimelinePanel(TimelinePanel *panel) { // Stop showing this timeline in the viewer TimelineFocused(nullptr); if (timeline_panels_.size() == 1) { // Leave our single remaining timeline panel open panel->ConnectViewerNode(nullptr); } else { timeline_panels_.removeOne(panel); panel->deleteLater(); } } void MainWindow::RemoveProjectPanel(ProjectPanel *panel) { if (project_panels_.size() == 1) { panel->set_project(nullptr); } else { project_panels_.removeOne(panel); panel->deleteLater(); } } void MainWindow::TimelineFocused(ViewerOutput* viewer) { sequence_viewer_panel_->ConnectViewerNode(viewer); param_panel_->ConnectViewerNode(viewer); Sequence* seq = nullptr; if (viewer) { seq = static_cast(viewer->parent()); } node_panel_->SetGraph(seq); } void MainWindow::FocusedPanelChanged(PanelWidget *panel) { TimelinePanel* timeline = dynamic_cast(panel); if (timeline) { TimelineFocused(timeline->GetConnectedViewer()); return; } ProjectPanel* project = dynamic_cast(panel); if (project) { UpdateTitle(); return; } } void MainWindow::SetDefaultLayout() { node_panel_->show(); addDockWidget(Qt::TopDockWidgetArea, node_panel_); footage_viewer_panel_->show(); addDockWidget(Qt::TopDockWidgetArea, footage_viewer_panel_); param_panel_->show(); tabifyDockWidget(footage_viewer_panel_, param_panel_); footage_viewer_panel_->raise(); table_panel_->hide(); table_panel_->setFloating(true); addDockWidget(Qt::TopDockWidgetArea, table_panel_); sequence_viewer_panel_->show(); addDockWidget(Qt::TopDockWidgetArea, sequence_viewer_panel_); pixel_sampler_panel_->hide(); pixel_sampler_panel_->setFloating(true); addDockWidget(Qt::TopDockWidgetArea, pixel_sampler_panel_); project_panels_.first()->show(); addDockWidget(Qt::BottomDockWidgetArea, project_panels_.first()); tool_panel_->show(); addDockWidget(Qt::BottomDockWidgetArea, tool_panel_); timeline_panels_.first()->show(); addDockWidget(Qt::BottomDockWidgetArea, timeline_panels_.first()); task_man_panel_->hide(); task_man_panel_->setFloating(true); addDockWidget(Qt::BottomDockWidgetArea, task_man_panel_); audio_monitor_panel_->show(); addDockWidget(Qt::BottomDockWidgetArea, audio_monitor_panel_); resizeDocks({node_panel_, param_panel_, sequence_viewer_panel_}, {width()/3, width()/3, width()/3}, Qt::Horizontal); resizeDocks({project_panels_.first(), tool_panel_, timeline_panels_.first(), audio_monitor_panel_}, {width()/4, 1, width(), 1}, Qt::Horizontal); resizeDocks({node_panel_, project_panels_.first()}, {height()/2, height()/2}, Qt::Vertical); } void MainWindow::showEvent(QShowEvent *e) { QMainWindow::showEvent(e); #ifdef Q_OS_LINUX // Check for nouveau since that driver really doesn't work with Olive QOffscreenSurface surface; surface.create(); QOpenGLContext context; context.create(); context.makeCurrent(&surface); const char* vendor = reinterpret_cast(context.functions()->glGetString(GL_VENDOR)); qDebug() << "Using graphics driver:" << vendor; if (!strcmp(vendor, "nouveau")) { QMetaObject::invokeMethod(this, "ShowNouveauWarning", Qt::QueuedConnection); } #endif } template T *MainWindow::AppendPanelInternal(QList& list) { T* panel = PanelManager::instance()->CreatePanel(this); SetUniquePanelID(panel, list); if (!list.isEmpty()) { tabifyDockWidget(list.last(), panel); } // For some reason raise() on its own doesn't do anything, we need both panel->show(); panel->raise(); list.append(panel); // Let us handle the panel closing rather than the panel itself panel->SetSignalInsteadOfClose(true); return panel; } template void MainWindow::SetUniquePanelID(T *panel, const QList &list) { // Set unique object name so it can be identified by QMainWindow's save and restore state functions panel->setObjectName(panel->objectName().append(QString::number(list.size()))); } template T *MainWindow::AppendFloatingPanelInternal(QList &list) { T* panel = PanelManager::instance()->CreatePanel(this); SetUniquePanelID(panel, list); panel->setFloating(true); panel->show(); panel->SetSignalInsteadOfClose(true); connect(panel, &PanelWidget::CloseRequested, this, &MainWindow::FloatingPanelCloseRequested); panel->setProperty("parent_list", reinterpret_cast(&list)); return panel; } OLIVE_NAMESPACE_EXIT olive-continuous/app/window/mainwindow/mainwindow.h000066400000000000000000000106131370472574300232050ustar00rootroot00000000000000/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 . ***/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include "mainwindowlayoutinfo.h" #include "panel/panelmanager.h" #include "panel/audiomonitor/audiomonitor.h" #include "panel/curve/curve.h" #include "panel/node/node.h" #include "panel/param/param.h" #include "panel/project/project.h" #include "panel/scope/scope.h" #include "panel/table/table.h" #include "panel/taskmanager/taskmanager.h" #include "panel/timeline/timeline.h" #include "panel/tool/tool.h" #include "panel/footageviewer/footageviewer.h" #include "panel/sequenceviewer/sequenceviewer.h" #include "panel/pixelsampler/pixelsamplerpanel.h" #include "project/project.h" #ifdef Q_OS_WINDOWS #include #endif OLIVE_NAMESPACE_ENTER /** * @brief Olive's main window responsible for docking widgets and the main menu bar. */ class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); virtual ~MainWindow() override; void LoadLayout(const MainWindowLayoutInfo &info); MainWindowLayoutInfo SaveLayout() const; TimelinePanel *OpenSequence(Sequence* sequence, bool enable_focus = true); void CloseSequence(Sequence* sequence); bool IsSequenceOpen(Sequence* sequence) const; void FolderOpen(Project* p, Item* i, bool floating); ScopePanel* AppendScopePanel(); CurvePanel* AppendCurvePanel(); enum ProgressStatus { kProgressNone, kProgressShow, kProgressError }; /** * @brief Where applicable, show progress on an operating system level * * * For Windows, this is shown as progress in the taskbar. * * For macOS, this is shown as progress in the dock. */ void SetApplicationProgressStatus(ProgressStatus status); /** * @brief If SetApplicationProgressStatus is set to kShowProgress, set the value with this * * Expects a percentage (0-100 inclusive). */ void SetApplicationProgressValue(int value); public slots: void ProjectOpen(Project *p); void ProjectClose(Project* p); void SetFullscreen(bool fullscreen); void ToggleMaximizedPanel(); void SetDefaultLayout(); protected: virtual void showEvent(QShowEvent* e) override; virtual void closeEvent(QCloseEvent* e) override; #ifdef Q_OS_WINDOWS virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; #endif private: TimelinePanel* AppendTimelinePanel(); ProjectPanel* AppendProjectPanel(); template T* AppendPanelInternal(QList& list); template T* AppendFloatingPanelInternal(QList& list); template void SetUniquePanelID(T* panel, const QList& list); void RemoveTimelinePanel(TimelinePanel *panel); void RemoveProjectPanel(ProjectPanel* panel); void TimelineFocused(ViewerOutput *viewer); QByteArray premaximized_state_; // Standard panels NodePanel* node_panel_; ParamPanel* param_panel_; SequenceViewerPanel* sequence_viewer_panel_; FootageViewerPanel* footage_viewer_panel_; QList project_panels_; QList folder_panels_; ToolPanel* tool_panel_; QList timeline_panels_; AudioMonitorPanel* audio_monitor_panel_; TaskManagerPanel* task_man_panel_; QList curve_panels_; PixelSamplerPanel* pixel_sampler_panel_; QList scope_panels_; NodeTablePanel* table_panel_; #ifdef Q_OS_WINDOWS unsigned int taskbar_btn_id_; ITaskbarList3* taskbar_interface_; #endif private slots: void FocusedPanelChanged(PanelWidget* panel); void UpdateTitle(); void TimelineCloseRequested(); void ProjectCloseRequested(); void FloatingPanelCloseRequested(); void StatusBarDoubleClicked(); #ifdef Q_OS_LINUX void ShowNouveauWarning(); #endif }; OLIVE_NAMESPACE_EXIT #endif olive-continuous/app/window/mainwindow/mainwindowlayoutinfo.cpp000066400000000000000000000055371370472574300256630ustar00rootroot00000000000000#include "mainwindowlayoutinfo.h" OLIVE_NAMESPACE_ENTER void MainWindowLayoutInfo::toXml(QXmlStreamWriter *writer) const { writer->writeStartElement(QStringLiteral("layout")); writer->writeStartElement(QStringLiteral("folders")); foreach (Folder* folder, open_folders_) { writer->writeTextElement(QStringLiteral("folder"), QString::number(reinterpret_cast(folder))); } writer->writeEndElement(); // folders writer->writeStartElement(QStringLiteral("timeline")); foreach (const OpenSequence& sequence, open_sequences_) { writer->writeTextElement(QStringLiteral("sequence"), QString::number(reinterpret_cast(sequence.sequence))); writer->writeTextElement(QStringLiteral("state"), QString(sequence.panel_state.toBase64())); } writer->writeEndElement(); // timeline writer->writeTextElement(QStringLiteral("state"), QString(state_.toBase64())); writer->writeEndElement(); // layout } MainWindowLayoutInfo MainWindowLayoutInfo::fromXml(QXmlStreamReader *reader, XMLNodeData &xml_data) { MainWindowLayoutInfo info; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("folders")) { while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("folder")) { quintptr item_id = reader->readElementText().toULongLong(); Item* open_item = xml_data.item_ptrs.value(item_id); if (open_item) { info.open_folders_.append(static_cast(open_item)); } } else { reader->skipCurrentElement(); } } } else if (reader->name() == QStringLiteral("timeline")) { Sequence* open_seq = nullptr; QByteArray tl_state; while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("sequence")) { quintptr item_id = reader->readElementText().toULongLong(); open_seq = dynamic_cast(xml_data.item_ptrs.value(item_id)); } else if (reader->name() == QStringLiteral("state")) { tl_state = QByteArray::fromBase64(reader->readElementText().toUtf8()); } else { reader->skipCurrentElement(); } } if (open_seq) { info.open_sequences_.append({open_seq, tl_state}); } } else if (reader->name() == QStringLiteral("state")) { info.state_ = QByteArray::fromBase64(reader->readElementText().toLatin1()); } else { reader->skipCurrentElement(); } } return info; } void MainWindowLayoutInfo::add_folder(olive::Folder *f) { open_folders_.append(f); } void MainWindowLayoutInfo::add_sequence(const OpenSequence &seq) { open_sequences_.append(seq); } void MainWindowLayoutInfo::set_state(const QByteArray &layout) { state_ = layout; } OLIVE_NAMESPACE_EXIT olive-continuous/app/window/mainwindow/mainwindowlayoutinfo.h000066400000000000000000000020171370472574300253160ustar00rootroot00000000000000#ifndef MAINWINDOWLAYOUTINFO_H #define MAINWINDOWLAYOUTINFO_H #include "project/item/folder/folder.h" #include "project/item/sequence/sequence.h" OLIVE_NAMESPACE_ENTER class MainWindowLayoutInfo { public: MainWindowLayoutInfo() = default; void toXml(QXmlStreamWriter* writer) const; static MainWindowLayoutInfo fromXml(QXmlStreamReader* reader, XMLNodeData &xml_data); void add_folder(Folder* f); struct OpenSequence { Sequence* sequence; QByteArray panel_state; }; void add_sequence(const OpenSequence& seq); void set_state(const QByteArray& layout); const QList& open_folders() const { return open_folders_; } const QList& open_sequences() const { return open_sequences_; } const QByteArray& state() const { return state_; } private: QByteArray state_; QList open_folders_; QList open_sequences_; }; OLIVE_NAMESPACE_EXIT Q_DECLARE_METATYPE(OLIVE_NAMESPACE::MainWindowLayoutInfo) #endif // MAINWINDOWLAYOUTINFO_H olive-continuous/appveyor.yml000066400000000000000000000010021370472574300167750ustar00rootroot00000000000000version: "{build}" image: Visual Studio 2017 environment: TRAVIS_REPO_SLUG: olive-editor/olive # Hack to not build the "continuous" tag (https://github.com/appveyor/ci/issues/486) # FIXME: Will unfortunately skip release tags skip_tags: true install: - cd C:\Tools\vcpkg - git pull - .\bootstrap-vcpkg.bat - cd %APPVEYOR_BUILD_FOLDER% build_script: - cmd: .appveyor\build.bat #artifacts: #- path: Olive*.zip # name: Olive Portable #- path: Olive*.exe # name: Olive Installer cache: c:\tools\vcpkg\installed\ olive-continuous/cmake/000077500000000000000000000000001370472574300154745ustar00rootroot00000000000000olive-continuous/cmake/FindFFMPEG.cmake000066400000000000000000000140751370472574300202520ustar00rootroot00000000000000#[==[ Provides the following variables: * `FFMPEG_INCLUDE_DIRS`: Include directories necessary to use FFMPEG. * `FFMPEG_LIBRARIES`: Libraries necessary to use FFMPEG. Note that this only includes libraries for the components requested. * `FFMPEG_VERSION`: The version of FFMPEG found. The following components are supported: * `avcodec` * `avdevice` * `avfilter` * `avformat` * `avresample` * `avutil` * `swresample` * `swscale` For each component, the following are provided: * `FFMPEG__FOUND`: Libraries for the component. * `FFMPEG__INCLUDE_DIRS`: Include directories for the component. * `FFMPEG__LIBRARIES`: Libraries for the component. * `FFMPEG::`: A target to use with `target_link_libraries`. Note that only components requested with `COMPONENTS` or `OPTIONAL_COMPONENTS` are guaranteed to set these variables or provide targets. #]==] function (_ffmpeg_find component headername) find_path("FFMPEG_${component}_INCLUDE_DIR" NAMES "lib${component}/${headername}" PATHS "${FFMPEG_ROOT}/include" ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include PATH_SUFFIXES ffmpeg DOC "FFMPEG's ${component} include directory") mark_as_advanced("FFMPEG_${component}_INCLUDE_DIR") # On Windows, static FFMPEG is sometimes built as `lib.a`. if (WIN32) list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib") list(APPEND CMAKE_FIND_LIBRARY_PREFIXES "" "lib") endif () find_library("FFMPEG_${component}_LIBRARY" NAMES "${component}" PATHS "${FFMPEG_ROOT}/lib" ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 "${FFMPEG_ROOT}/bin" DOC "FFMPEG's ${component} library") mark_as_advanced("FFMPEG_${component}_LIBRARY") if (FFMPEG_${component}_LIBRARY AND FFMPEG_${component}_INCLUDE_DIR) set(_deps_found TRUE) set(_deps_link) foreach (_ffmpeg_dep IN LISTS ARGN) if (TARGET "FFMPEG::${_ffmpeg_dep}") list(APPEND _deps_link "FFMPEG::${_ffmpeg_dep}") else () set(_deps_found FALSE) endif () endforeach () if (_deps_found) add_library("FFMPEG::${component}" UNKNOWN IMPORTED) set_target_properties("FFMPEG::${component}" PROPERTIES IMPORTED_LOCATION "${FFMPEG_${component}_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${FFMPEG_${component}_INCLUDE_DIR}" IMPORTED_LINK_INTERFACE_LIBRARIES "${_deps_link}") set("FFMPEG_${component}_FOUND" 1 PARENT_SCOPE) set(version_header_path "${FFMPEG_${component}_INCLUDE_DIR}/lib${component}/version.h") if (EXISTS "${version_header_path}") string(TOUPPER "${component}" component_upper) file(STRINGS "${version_header_path}" version REGEX "#define *LIB${component_upper}_VERSION_(MAJOR|MINOR|MICRO) ") string(REGEX REPLACE ".*_MAJOR *\([0-9]*\).*" "\\1" major "${version}") string(REGEX REPLACE ".*_MINOR *\([0-9]*\).*" "\\1" minor "${version}") string(REGEX REPLACE ".*_MICRO *\([0-9]*\).*" "\\1" micro "${version}") if (NOT major STREQUAL "" AND NOT minor STREQUAL "" AND NOT micro STREQUAL "") set("FFMPEG_${component}_VERSION" "${major}.${minor}.${micro}" PARENT_SCOPE) endif () endif () else () set("FFMPEG_${component}_FOUND" 0 PARENT_SCOPE) set(what) if (NOT FFMPEG_${component}_LIBRARY) set(what "library") endif () if (NOT FFMPEG_${component}_INCLUDE_DIR) if (what) string(APPEND what " or headers") else () set(what "headers") endif () endif () set("FFMPEG_${component}_NOT_FOUND_MESSAGE" "Could not find the ${what} for ${component}." PARENT_SCOPE) endif () endif () endfunction () _ffmpeg_find(avutil avutil.h) _ffmpeg_find(avresample avresample.h avutil) _ffmpeg_find(swresample swresample.h avutil) _ffmpeg_find(swscale swscale.h avutil) _ffmpeg_find(avcodec avcodec.h avutil) _ffmpeg_find(avformat avformat.h avcodec avutil) _ffmpeg_find(avfilter avfilter.h avutil) _ffmpeg_find(avdevice avdevice.h avformat avutil) if (TARGET FFMPEG::avutil) set(_ffmpeg_version_header_path "${FFMPEG_avutil_INCLUDE_DIR}/libavutil/ffversion.h") if (EXISTS "${_ffmpeg_version_header_path}") file(STRINGS "${_ffmpeg_version_header_path}" _ffmpeg_version REGEX "FFMPEG_VERSION") string(REGEX REPLACE ".*\"n?\(.*\)\"" "\\1" FFMPEG_VERSION "${_ffmpeg_version}") unset(_ffmpeg_version) else () set(FFMPEG_VERSION FFMPEG_VERSION-NOTFOUND) endif () unset(_ffmpeg_version_header_path) endif () set(FFMPEG_INCLUDE_DIRS) set(FFMPEG_LIBRARIES) set(_ffmpeg_required_vars) foreach (_ffmpeg_component IN LISTS FFMPEG_FIND_COMPONENTS) if (TARGET "FFMPEG::${_ffmpeg_component}") set(FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIR}") set(FFMPEG_${_ffmpeg_component}_LIBRARIES "${FFMPEG_${_ffmpeg_component}_LIBRARY}") list(APPEND FFMPEG_INCLUDE_DIRS "${FFMPEG_${_ffmpeg_component}_INCLUDE_DIRS}") list(APPEND FFMPEG_LIBRARIES "${FFMPEG_${_ffmpeg_component}_LIBRARIES}") if (FFMEG_FIND_REQUIRED_${_ffmpeg_component}) list(APPEND _ffmpeg_required_vars "FFMPEG_${_ffmpeg_required_vars}_INCLUDE_DIRS" "FFMPEG_${_ffmpeg_required_vars}_LIBRARIES") endif () endif () endforeach () unset(_ffmpeg_component) if (FFMPEG_INCLUDE_DIRS) list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) endif () include(FindPackageHandleStandardArgs) find_package_handle_standard_args(FFMPEG REQUIRED_VARS FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES ${_ffmpeg_required_vars} VERSION_VAR FFMPEG_VERSION HANDLE_COMPONENTS) unset(_ffmpeg_required_vars) olive-continuous/cmake/FindOpenColorIO.cmake000066400000000000000000000060641370472574300214350ustar00rootroot00000000000000# # Copyright 2019 Pixar # # Licensed under the Apache License, Version 2.0 (the "Apache License") # with the following modification; you may not use this file except in # compliance with the Apache License and the following modification to it: # Section 6. Trademarks. is deleted and replaced with: # # 6. Trademarks. This License does not grant permission to use the trade # names, trademarks, service marks, or product names of the Licensor # and its affiliates, except as required to comply with Section 4(c) of # the License and to reproduce the content of the NOTICE file. # # You may obtain a copy of the Apache License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the Apache License with the above modification is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the Apache License for the specific # language governing permissions and limitations under the Apache License. # if(UNIX) find_path(OCIO_BASE_DIR include/OpenColorIO/OpenColorABI.h HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" "/opt/ocio" ) find_path(OCIO_LIBRARY_DIR libOpenColorIO.so HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" "${OCIO_BASE_DIR}" PATH_SUFFIXES lib/ DOC "OpenColorIO library path" ) elseif(WIN32) find_path(OCIO_BASE_DIR include/OpenColorIO/OpenColorABI.h HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" ) find_path(OCIO_LIBRARY_DIR OpenColorIO.lib HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" "${OCIO_BASE_DIR}" PATH_SUFFIXES lib/ DOC "OpenColorIO library path" ) endif() find_path(OCIO_INCLUDE_DIR OpenColorIO/OpenColorABI.h HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" "${OCIO_BASE_DIR}" PATH_SUFFIXES include/ DOC "OpenColorIO headers path" ) list(APPEND OCIO_INCLUDE_DIRS ${OCIO_INCLUDE_DIR}) find_library(OCIO_LIBRARY OpenColorIO HINTS "${OCIO_LOCATION}" "$ENV{OCIO_LOCATION}" "${OCIO_BASE_DIR}" PATH_SUFFIXES lib/ DOC "OCIO's ${OCIO_LIB} library path" ) list(APPEND OCIO_LIBRARIES ${OCIO_LIBRARY}) if(OCIO_INCLUDE_DIRS AND EXISTS "${OCIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h") file(STRINGS ${OCIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h fullVersion REGEX "#define OCIO_VERSION .*$") string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" OCIO_VERSION ${fullVersion}) endif() # handle the QUIETLY and REQUIRED arguments and set OCIO_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenColorIO REQUIRED_VARS OCIO_LIBRARIES OCIO_INCLUDE_DIRS VERSION_VAR OCIO_VERSION ) olive-continuous/cmake/FindOpenEXR.cmake000066400000000000000000000137261370472574300205700ustar00rootroot00000000000000# Module to find OpenEXR. # # This module will set # OPENEXR_FOUND true, if found # OPENEXR_INCLUDES directory where headers are found # OPENEXR_LIBRARIES libraries for OpenEXR + IlmBase # ILMBASE_LIBRARIES libraries just IlmBase # OPENEXR_VERSION OpenEXR version (accurate for >= 2.0.0, # otherwise will just guess 1.6.1) # # # Other standard issue macros include (FindPackageHandleStandardArgs) include (SelectLibraryConfigurations) find_package (ZLIB REQUIRED) # Link with pthreads if required find_package (Threads) if (CMAKE_USE_PTHREADS_INIT) set (ILMBASE_PTHREADS ${CMAKE_THREAD_LIBS_INIT}) endif () # Attempt to find OpenEXR with pkgconfig find_package(PkgConfig) if (PKG_CONFIG_FOUND) if (NOT Ilmbase_ROOT AND NOT ILMBASE_ROOT AND NOT DEFINED ENV{Ilmbase_ROOT} AND NOT DEFINED ENV{ILMBASE_ROOT}) pkg_check_modules(_ILMBASE QUIET IlmBase>=2.0.0) endif () if (NOT OpenEXR_ROOT AND NOT OPENEXR_ROOT AND NOT DEFINED ENV{OpenEXR_ROOT} AND NOT DEFINED ENV{OPENEXR_ROOT}) pkg_check_modules(_OPENEXR QUIET OpenEXR>=2.0.0) endif () endif (PKG_CONFIG_FOUND) # List of likely places to find the headers -- note priority override of # ${OPENEXR_ROOT}/include. # ILMBASE is needed in case ilmbase an openexr are installed in separate # directories, like NixOS does set (GENERIC_INCLUDE_PATHS ${OPENEXR_ROOT}/include $ENV{OPENEXR_ROOT}/include ${ILMBASE_ROOT}/include $ENV{ILMBASE_ROOT}/include ${_ILMBASE_INCLUDEDIR} ${_OPENEXR_INCLUDEDIR} /usr/local/include /usr/include /usr/include/${CMAKE_LIBRARY_ARCHITECTURE} /sw/include /opt/local/include ) # Find the include file locations. find_path (ILMBASE_INCLUDE_PATH OpenEXR/IlmBaseConfig.h HINTS ${ILMBASE_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR} ${GENERIC_INCLUDE_PATHS} ) find_path (OPENEXR_INCLUDE_PATH OpenEXR/OpenEXRConfig.h HINTS ${OPENEXR_INCLUDE_DIR} ${GENERIC_INCLUDE_PATHS} ) # Try to figure out version number if (DEFINED _OPENEXR_VERSION AND NOT "${_OPENEXR_VERSION}" STREQUAL "") set (OPENEXR_VERSION "${_OPENEXR_VERSION}") string (REGEX REPLACE "([0-9]+)\\.[0-9\\.]+" "\\1" OPENEXR_VERSION_MAJOR "${_OPENEXR_VERSION}") string (REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" OPENEXR_VERSION_MINOR "${_OPENEXR_VERSION}") elseif (EXISTS "${OPENEXR_INCLUDE_PATH}/OpenEXR/ImfMultiPartInputFile.h") # Must be at least 2.0 file(STRINGS "${OPENEXR_INCLUDE_PATH}/OpenEXR/OpenEXRConfig.h" TMP REGEX "^#define OPENEXR_VERSION_STRING .*$") string (REGEX MATCHALL "[0-9]+[.0-9]+" OPENEXR_VERSION ${TMP}) file(STRINGS "${OPENEXR_INCLUDE_PATH}/OpenEXR/OpenEXRConfig.h" TMP REGEX "^#define OPENEXR_VERSION_MAJOR .*$") string (REGEX MATCHALL "[0-9]+" OPENEXR_VERSION_MAJOR ${TMP}) file(STRINGS "${OPENEXR_INCLUDE_PATH}/OpenEXR/OpenEXRConfig.h" TMP REGEX "^#define OPENEXR_VERSION_MINOR .*$") string (REGEX MATCHALL "[0-9]+" OPENEXR_VERSION_MINOR ${TMP}) else () # Assume an old one, predates 2.x that had versions set (OPENEXR_VERSION 1.6.1) set (OPENEXR_MAJOR 1) set (OPENEXR_MINOR 6) endif () # List of likely places to find the libraries -- note priority override of # ${OPENEXR_ROOT}/lib. set (GENERIC_LIBRARY_PATHS ${OPENEXR_ROOT}/lib ${ILMBASE_ROOT}/lib ${OPENEXR_INCLUDE_PATH}/../lib ${ILMBASE_INCLUDE_PATH}/../lib ${_ILMBASE_LIBDIR} ${_OPENEXR_LIBDIR} /usr/local/lib /usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE} /usr/lib /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} /sw/lib /opt/local/lib $ENV{PROGRAM_FILES}/OpenEXR/lib/static ) # message (STATUS "Generic lib paths: ${GENERIC_LIBRARY_PATHS}") # Handle request for static libs by altering CMAKE_FIND_LIBRARY_SUFFIXES. # We will restore it at the end of this file. set (_openexr_orig_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES}) if (OpenEXR_USE_STATIC_LIBS) if (WIN32) set (CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) else () set (CMAKE_FIND_LIBRARY_SUFFIXES .a) endif () endif () # Look for the libraries themselves, for all the components. # This is complicated because the OpenEXR libraries may or may not be # built with version numbers embedded. set (_openexr_components IlmThread IlmImf Imath Iex Half) foreach (COMPONENT ${_openexr_components}) string (TOUPPER ${COMPONENT} UPPERCOMPONENT) # First try with the version embedded find_library (OPENEXR_${UPPERCOMPONENT}_LIBRARY NAMES ${COMPONENT}-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR} ${COMPONENT} ${COMPONENT}-${OPENEXR_VERSION_MAJOR}_${OPENEXR_VERSION_MINOR}_d ${COMPONENT}_d HINTS ${OPENEXR_LIBRARY_DIR} $ENV{OPENEXR_LIBRARY_DIR} ${GENERIC_LIBRARY_PATHS} ) endforeach () find_package_handle_standard_args (OpenEXR REQUIRED_VARS ILMBASE_INCLUDE_PATH OPENEXR_INCLUDE_PATH OPENEXR_IMATH_LIBRARY OPENEXR_ILMIMF_LIBRARY OPENEXR_IEX_LIBRARY OPENEXR_HALF_LIBRARY VERSION_VAR OPENEXR_VERSION ) if (OPENEXR_FOUND) set (ILMBASE_FOUND TRUE) set (ILMBASE_INCLUDES ${ILMBASE_INCLUDE_PATH}) set (OPENEXR_INCLUDES ${OPENEXR_INCLUDE_PATH}) set (ILMBASE_INCLUDE_DIR ${ILMBASE_INCLUDE_PATH}) set (OPENEXR_INCLUDE_DIR ${OPENEXR_INCLUDE_PATH}) set (ILMBASE_LIBRARIES ${OPENEXR_IMATH_LIBRARY} ${OPENEXR_IEX_LIBRARY} ${OPENEXR_HALF_LIBRARY} ${OPENEXR_ILMTHREAD_LIBRARY} ${ILMBASE_PTHREADS} CACHE STRING "The libraries needed to use IlmBase") set (OPENEXR_LIBRARIES ${OPENEXR_ILMIMF_LIBRARY} ${ILMBASE_LIBRARIES} ${ZLIB_LIBRARIES} CACHE STRING "The libraries needed to use OpenEXR") endif () mark_as_advanced( OPENEXR_ILMIMF_LIBRARY OPENEXR_IMATH_LIBRARY OPENEXR_IEX_LIBRARY OPENEXR_HALF_LIBRARY OPENEXR_VERSION) # Restore the original CMAKE_FIND_LIBRARY_SUFFIXES set (CMAKE_FIND_LIBRARY_SUFFIXES ${_openexr_orig_suffixes}) olive-continuous/cmake/FindOpenImageIO.cmake000066400000000000000000000102131370472574300213700ustar00rootroot00000000000000# # Copyright 2016 Pixar # # Licensed under the Apache License, Version 2.0 (the "Apache License") # with the following modification; you may not use this file except in # compliance with the Apache License and the following modification to it: # Section 6. Trademarks. is deleted and replaced with: # # 6. Trademarks. This License does not grant permission to use the trade # names, trademarks, service marks, or product names of the Licensor # and its affiliates, except as required to comply with Section 4(c) of # the License and to reproduce the content of the NOTICE file. # # You may obtain a copy of the Apache License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the Apache License with the above modification is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the Apache License for the specific # language governing permissions and limitations under the Apache License. # if(UNIX) find_path(OIIO_BASE_DIR include/OpenImageIO/oiioversion.h HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" "/opt/oiio" ) find_path(OIIO_LIBRARY_DIR libOpenImageIO.so HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" "${OIIO_BASE_DIR}" PATH_SUFFIXES lib/ DOC "OpenImageIO library path" ) elseif(WIN32) find_path(OIIO_BASE_DIR include/OpenImageIO/oiioversion.h HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" ) find_path(OIIO_LIBRARY_DIR OpenImageIO.lib HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" "${OIIO_BASE_DIR}" PATH_SUFFIXES lib/ DOC "OpenImageIO library path" ) endif() find_path(OIIO_INCLUDE_DIR OpenImageIO/oiioversion.h HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" "${OIIO_BASE_DIR}" PATH_SUFFIXES include/ DOC "OpenImageIO headers path" ) list(APPEND OIIO_INCLUDE_DIRS ${OIIO_INCLUDE_DIR}) foreach(OIIO_LIB OpenImageIO OpenImageIO_Util ) find_library(OIIO_${OIIO_LIB}_LIBRARY ${OIIO_LIB} HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" "${OIIO_BASE_DIR}" PATH_SUFFIXES lib/ DOC "OIIO's ${OIIO_LIB} library path" ) if(OIIO_${OIIO_LIB}_LIBRARY) list(APPEND OIIO_LIBRARIES ${OIIO_${OIIO_LIB}_LIBRARY}) endif() endforeach(OIIO_LIB) foreach(OIIO_BIN iconvert idiff igrep iinfo iv maketx oiiotool) find_program(OIIO_${OIIO_BIN}_BINARY ${OIIO_BIN} HINTS "${OIIO_LOCATION}" "$ENV{OIIO_LOCATION}" "${OIIO_BASE_DIR}" PATH_SUFFIXES bin/ DOC "OIIO's ${OIIO_BIN} binary" ) if(OIIO_${OIIO_BIN}_BINARY) list(APPEND OIIO_BINARIES ${OIIO_${OIIO_BIN}_BINARY}) endif() endforeach(OIIO_BIN) if(OIIO_INCLUDE_DIRS AND EXISTS "${OIIO_INCLUDE_DIR}/OpenImageIO/oiioversion.h") file(STRINGS ${OIIO_INCLUDE_DIR}/OpenImageIO/oiioversion.h MAJOR REGEX "#define OIIO_VERSION_MAJOR.*$") file(STRINGS ${OIIO_INCLUDE_DIR}/OpenImageIO/oiioversion.h MINOR REGEX "#define OIIO_VERSION_MINOR.*$") file(STRINGS ${OIIO_INCLUDE_DIR}/OpenImageIO/oiioversion.h PATCH REGEX "#define OIIO_VERSION_PATCH.*$") string(REGEX MATCHALL "[0-9]+" MAJOR ${MAJOR}) string(REGEX MATCHALL "[0-9]+" MINOR ${MINOR}) string(REGEX MATCHALL "[0-9]+" PATCH ${PATCH}) set(OIIO_VERSION "${MAJOR}.${MINOR}.${PATCH}") endif() # handle the QUIETLY and REQUIRED arguments and set OIIO_FOUND to TRUE if # all listed variables are TRUE include(FindPackageHandleStandardArgs) find_package_handle_standard_args(OpenImageIO REQUIRED_VARS OIIO_LIBRARIES OIIO_INCLUDE_DIRS VERSION_VAR OIIO_VERSION ) olive-continuous/cmake/MacOSXBundleInfo.plist.in000066400000000000000000000023731370472574300222230ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${MACOSX_BUNDLE_EXECUTABLE_NAME} CFBundleGetInfoString ${MACOSX_BUNDLE_INFO_STRING} CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier ${MACOSX_BUNDLE_GUI_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString ${MACOSX_BUNDLE_LONG_VERSION_STRING} CFBundleName ${MACOSX_BUNDLE_BUNDLE_NAME} CFBundlePackageType APPL CFBundleShortVersionString ${MACOSX_BUNDLE_SHORT_VERSION_STRING} CFBundleSignature ???? CFBundleVersion ${MACOSX_BUNDLE_BUNDLE_VERSION} CSResourcesFileMapped NSHumanReadableCopyright ${MACOSX_BUNDLE_COPYRIGHT} NSPrincipalClass NSApplication olive-continuous/release.txt000066400000000000000000000003531370472574300165760ustar00rootroot00000000000000NOTE: This build is by no means stable or intended for serious use. It's a complete rewrite of the entire program and only here to simplify testing of what has been implemented. For any serious work, stick to the 0.1.x releases below.