pax_global_header00006660000000000000000000000064132171032450014510gustar00rootroot0000000000000052 comment=f6ae506c14acb223bdc196124efd4f35d6ffa2bb Quaternion-0.0.5/000077500000000000000000000000001321710324500136375ustar00rootroot00000000000000Quaternion-0.0.5/.appveyor.yml000066400000000000000000000021311321710324500163020ustar00rootroot00000000000000image: Visual Studio 2015 environment: DEPLOY_DIR: Quaternion-%APPVEYOR_BUILD_VERSION% matrix: - QTDIR: C:\Qt\5.8\msvc2015_64 VS_FOLDER: Microsoft Visual Studio 14.0 PLATFORM: x64 - QTDIR: C:\Qt\5.6\msvc2015 VS_FOLDER: Microsoft Visual Studio 14.0 PLATFORM: x86 init: - call "%QTDIR%\bin\qtenv2.bat" - set PATH=C:\Qt\Tools\QtCreator\bin;%PATH% - call "%ProgramFiles(x86)%\%VS_FOLDER%\VC\vcvarsall.bat" %platform% - cd /D "%APPVEYOR_BUILD_FOLDER%" before_build: - git submodule update --init --recursive - cmake -G "NMake Makefiles JOM" -H. -Bbuild -DCMAKE_CXX_FLAGS="/EHsc /W3" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX="%DEPLOY_DIR%" build_script: - cmake --build build after_build: - cmake --build build --target install - 7z a quaternion.zip "%DEPLOY_DIR%\" # Uncomment this to connect to the AppVeyor build worker #on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) test: off artifacts: - path: quaternion.zip Quaternion-0.0.5/.gitignore000066400000000000000000000000151321710324500156230ustar00rootroot00000000000000build .kdev4 Quaternion-0.0.5/.gitmodules000066400000000000000000000001161321710324500160120ustar00rootroot00000000000000[submodule "lib"] path = lib url = ../../QMatrixClient/libqmatrixclient.git Quaternion-0.0.5/.travis.yml000066400000000000000000000013641321710324500157540ustar00rootroot00000000000000language: cpp matrix: include: - os: linux dist: trusty compiler: gcc - os: linux dist: trusty compiler: clang - os: osx install: - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; else sudo apt-get update -qq; fi - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install qt5; export PATH="$PATH:/usr/local/opt/qt/bin"; else sudo apt-get install -y qt5-default qtdeclarative5-dev; fi script: - mkdir build && cd build - cmake .. - cmake --build . --target all notifications: webhooks: urls: - "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MGtpdHN1bmUlM0FtYXRyaXgub3JnLyUyMVBDelV0eHRPalV5U3hTZWxvZiUzQW1hdHJpeC5vcmc" on_success: change # always|never|change on_failure: always on_start: neverQuaternion-0.0.5/BUILDING.md000066400000000000000000000162371321710324500153670ustar00rootroot00000000000000# Building Quaternion [![Quaternion-master@Travis](https://img.shields.io/travis/QMatrixClient/Quaternion/master.svg)](https://travis-ci.org/QMatrixClient/Quaternion/branches) [![Quaternion-master@AppVeyor](https://img.shields.io/appveyor/ci/QMatrixClient/quaternion/master.svg?logo=appveyor)](https://ci.appveyor.com/project/QMatrixClient/quaternion) [![license](https://img.shields.io/github/license/QMatrixClient/quaternion.svg)](https://github.com/QMatrixClient/quaternion/blob/master/COPYING) [![Chat](https://img.shields.io/badge/chat-%23quaternion-blue.svg)](https://matrix.to/#/#quaternion:matrix.org) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) Quaternion source code is hosted at GitHub: https://github.com/QMatrixClient/Quaternion - checking out a certain commit or tag from GitHub (rather than downloading the archive) is the recommended way for packagers. Quaternion uses libqmatrixclient that is developed in a separate GitHub repo and is fetched as a git submodule. To get all necessary sources: - if you haven't cloned the Quaternion sources yet: ``` git clone --recursive https://github.com/QMatrixClient/Quaternion.git ``` - if you already have cloned Quaternion, do the following in the top-level directory (NOT in lib subdirectory): ``` git submodule init git submodule update ``` There are few tags so far; there will be more, as new versions are released. ### Pre-requisites - a Linux, MacOS or Windows system (desktop versions tried; mobile Linux/Windows might work too) - For Ubuntu flavours - Trusty Tar or later (or a derivative) is good enough; older ones will need PPAs at least for a newer Qt - a Git client to check out this repo - CMake (from your package management system or [the official website](https://cmake.org/download/)) - Qt 5 (either Open Source or Commercial), version 5.2.1 or higher as of this writing (check the CMakeLists.txt for most up-to-date information). Qt 5.3 or higher recommended on Windows. - a C++ toolchain supported by your version of Qt (see a link for your platform at [the Qt's platform requirements page](http://doc.qt.io/qt-5/gettingstarted.html#platform-requirements)) - GCC 4.8, Clang 3.5.0, Visual C++ 2015 are the oldest officially supported as of this writing #### Linux Just install things from the list above using your preferred package manager. If your Qt package base is fine-grained you might want to take a look at `CMakeLists.txt` to figure out which specific libraries Quaternion uses (or blindly run cmake and look at error messages). Note also that you'll need several Qt Quick plugins for Quaternion to work (without them, it will compile and run but won't show the messages timeline). In case of Trusty Tar the following line will get you everything necessary to build and run Quaternion (thanks to `@onlnr:matrix.org`): ``` sudo apt-get install git cmake qtdeclarative5-dev qtdeclarative5-qtquick2-plugin qtdeclarative5-controls-plugin ``` On Fedora 26, the following command should be enough for building and running: ``` dnf install git cmake qt5-qtdeclarative-devel qt5-qtquickcontrols ``` #### OS X `brew install qt5` should get you Qt5. You may need to tell CMake about the path to Qt by passing `-DCMAKE_PREFIX_PATH=` #### Windows 1. Install CMake. The commands in further sections imply that cmake is in your PATH - otherwise you have to prepend them with actual paths. 1. Install Qt5, using their official installer. If for some reason you need to use Qt 5.2.1, select its Add-ons component in the installer as well; for later versions, no extras are needed. If you don't have a toolchain and/or IDE, you can easily get one by selecting Qt Creator and at least one toolchain under Qt Creator. At least Qt 5.3 is recommended on Windows; `windeployqt` in Qt 5.2.1 is not functional enough to provide a standalone installation for Quaternion though you can still compile and run from your build directory. 1. Make sure CMake knows about Qt and the toolchain - the easiest way is to run a qtenv2.bat script that can be found in `C:\Qt\\\bin` (assuming you installed Qt to `C:\Qt`). The only thing it does is adding necessary paths to PATH - you might not want to run it on system startup but it's very handy to setup environment before building. Setting CMAKE_PREFIX_PATH, the same way as for OS X (see above), also helps. There are no official MinGW-based 64-bit packages for Qt. If you're determined to build 64-bit Quaternion, either use a Visual Studio toolchain or build Qt5 yourself as described in Qt documentation. ### Build In the root directory of the project sources: ``` mkdir build_dir cd build_dir cmake .. # Pass -DCMAKE_PREFIX_PATH and -DCMAKE_INSTALL_PREFIX here if needed cmake --build . --target all ``` This will get you an executable in `build_dir` inside your project sources. `CMAKE_INSTALL_PREFIX` variable of CMake controls where Quaternion will be installed - pass it to `cmake ..` above if you wish to alter the default (see the output from `cmake ..` to find out the configured values). ### Install In the root directory of the project sources: `cmake --build build_dir --target install`. On Linux, `make install` (with `sudo` if needed) will work equally well. ### Package Packagers are very scarce so far, so please step up and support your favourite system! Notably, we still need a MacOS maintainer - Quaternion sees no actual usage/testing on this platform yet. #### Flatpak If you run Linux and your distribution supports flatpak, you can easily build and install Quaternion as a flatpak package: ``` git clone https://github.com/QMatrixClient/Quaternion.git --recursive cd Quaternion/flatpak ./setup_runtime.sh ./build.sh flatpak --user install quaternion-nightly com.github.quaternion ``` Whenever you want to update your Quaternion package, do the following from the flatpak directory: ``` ./build.sh flatpak --user update ``` ## Troubleshooting If `cmake` fails with... ``` CMake Warning at CMakeLists.txt:11 (find_package): By not providing "FindQt5Widgets.cmake" in CMAKE_MODULE_PATH this project has asked CMake to find a package configuration file provided by "Qt5Widgets", but CMake did not find one. ``` ...then you need to set the right -DCMAKE_PREFIX_PATH variable, see above. If `cmake` fails with... ``` CMake Error at CMakeLists.txt:30 (add_subdirectory): The source directory /lib does not contain a CMakeLists.txt file. ``` ...then you don't have libqmatrixclient sources - most likely because you didn't do the `git submodule init && git submodule update` dance. If you have made sure that your toolchain is in order (versions of compilers and Qt are among supported ones, PATH is set correctly etc.) but building fails with strange Qt-related errors such as not found symbols or undefined references, double-check that you don't have Qt 4.x packages around ([here is a typical example](https://github.com/QMatrixClient/Quaternion/issues/185)). If you need those packages reinstalling them may help; but if you use Qt4 by default you have to explicitly pass Qt5 location to CMake (see notes about CMAKE_PREFIX_PATH in "Building"). See also the Troubleshooting section in [README.md](./README.md) Quaternion-0.0.5/CMakeLists.txt000066400000000000000000000122131321710324500163760ustar00rootroot00000000000000CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) project(quaternion CXX) if(UNIX AND NOT APPLE) set(LINUX 1) endif(UNIX AND NOT APPLE) include(CheckCXXCompilerFlag) if (NOT WIN32) include(GNUInstallDirs) include(cmake/ECMInstallIcons.cmake) endif(NOT WIN32) # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) # Set a default build type if none was specified if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build" FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() # Setup command line parameters for the compiler and linker CHECK_CXX_COMPILER_FLAG("-Wall" WALL_FLAG_SUPPORTED) if ( WALL_FLAG_SUPPORTED ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") endif ( WALL_FLAG_SUPPORTED ) if ( CMAKE_VERSION VERSION_LESS "3.1" ) CHECK_CXX_COMPILER_FLAG("-std=c++11" STD_FLAG_SUPPORTED) if ( STD_FLAG_SUPPORTED ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif ( STD_FLAG_SUPPORTED ) else ( CMAKE_VERSION VERSION_LESS "3.1" ) set(CMAKE_CXX_STANDARD 11) endif ( CMAKE_VERSION VERSION_LESS "3.1" ) # Find the libraries find_package(Qt5 5.2.1 REQUIRED Widgets Network Quick Qml Gui) get_filename_component(Qt5_Prefix "${Qt5_DIR}/../../../.." ABSOLUTE) message( STATUS ) message( STATUS "=============================================================================" ) message( STATUS " Quaternion Build Information" ) message( STATUS "=============================================================================" ) if (CMAKE_BUILD_TYPE) message( STATUS "Build type: ${CMAKE_BUILD_TYPE}") endif(CMAKE_BUILD_TYPE) message( STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) message( STATUS "Using Qt ${Qt5_VERSION} at ${Qt5_Prefix}" ) message( STATUS "Quaternion install prefix: ${CMAKE_INSTALL_PREFIX}" ) message( STATUS "=============================================================================" ) message( STATUS ) add_subdirectory(lib) include_directories(lib) # Set up source files set(quaternion_SRCS client/quaternionroom.cpp client/message.cpp client/imageprovider.cpp client/activitydetector.cpp client/logindialog.cpp client/mainwindow.cpp client/roomlistdock.cpp client/userlistdock.cpp client/kchatedit.cpp client/chatedit.cpp client/chatroomwidget.cpp client/systemtray.cpp client/models/messageeventmodel.cpp client/models/userlistmodel.cpp client/models/roomlistmodel.cpp client/main.cpp ) set(quaternion_QRC client/resources.qrc ) QT5_ADD_RESOURCES(quaternion_QRC_SRC ${quaternion_QRC}) # Tell CMake to create the executable # (and that on Windows it should be a GUI executable) # TODO: MacOS builders, should MACOSX_BUNDLE be specified here as well? add_executable(quaternion WIN32 ${quaternion_SRCS} ${quaternion_QRC_SRC}) target_link_libraries(quaternion qmatrixclient Qt5::Widgets Qt5::Quick Qt5::Qml Qt5::Gui Qt5::Network) # Installation if (NOT CMAKE_INSTALL_BINDIR) set(CMAKE_INSTALL_BINDIR ".") endif() install(TARGETS quaternion RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) if(LINUX) install(FILES linux/quaternion.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications ) install(FILES linux/com.github.quaternion.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo ) file(GLOB quaternion_icons icons/quaternion/*-apps-quaternion.png) ecm_install_icons(ICONS ${quaternion_icons} icons/quaternion/sc-apps-quaternion.svgz DESTINATION ${CMAKE_INSTALL_DATADIR}/icons ) endif(LINUX) if(WIN32) if (${Qt5_VERSION} VERSION_LESS "5.3") install(CODE " message(\"Deploying on Windows is only supported with Qt 5.3 or higher\") message(\"Bare executable has been copied to the target folder\") ") else() get_filename_component(Qt5_WinBaseDir "${Qt5_DIR}/../../.." ABSOLUTE) install(CODE " if (CMAKE_INSTALL_CONFIG_NAME STREQUAL \"Debug\") set(WDQ_FLAG debug) else() set(WDQ_FLAG release) endif() execute_process( COMMAND bin/windeployqt --\${WDQ_FLAG} --no-system-d3d-compiler --no-opengl --no-multimedia --no-multimediaquick --no-declarative --no-test \ --qmldir qml \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}\" WORKING_DIRECTORY \"${Qt5_WinBaseDir}\" RESULT_VARIABLE WDQ_RETVAL ) if (WDQ_RETVAL) message( \"windeployqt returned \${WDQ_RETVAL} - check messages above\") else() message( STATUS \"Quaternion and its dependencies have been deployed to \${CMAKE_INSTALL_PREFIX}.\") endif() ") endif() endif(WIN32) Quaternion-0.0.5/COPYING000066400000000000000000001045131321710324500146760ustar00rootroot00000000000000 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 . Quaternion-0.0.5/Quaternion.project000066400000000000000000000204551321710324500173620ustar00rootroot00000000000000 . cmake $(ProjectPath) -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=1 mingw32-make clean && mingw32-make -j4 mingw32-make clean mingw32-make -j4 None $(IntermediateDirectory) cmake $(ProjectPath) -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=1 mingw32-make clean && mingw32-make -j4 mingw32-make clean mingw32-make -j4 None $(IntermediateDirectory) Quaternion-0.0.5/README.md000066400000000000000000000207171321710324500151250ustar00rootroot00000000000000# Quaternion [![license](https://img.shields.io/github/license/QMatrixClient/quaternion.svg)](https://github.com/QMatrixClient/quaternion/blob/master/COPYING) ![status](https://img.shields.io/badge/status-beta-yellow.svg) [![release](https://img.shields.io/github/release/QMatrixClient/quaternion/all.svg)](https://github.com/QMatrixClient/Quaternion/releases/latest) [![Chat](https://img.shields.io/badge/chat-%23quaternion-blue.svg)](https://matrix.to/#/#quaternion:matrix.org) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) Quaternion is a cross-platform desktop IM client for the [Matrix](https://matrix.org) protocol. This file contains general information about application usage and settings. See [BUILDING.md](./BUILDING.md) for building instructions. ## Contacts Most of talking around Quaternion happens in our Matrix room: [#quaternion:matrix.org](https://matrix.to/#/#quaternion:matrix.org). You can also file issues at [the project's issue tracker](https://github.com/QMatrixClient/Quaternion/issues). If you have what looks like a security issue, please contact Kitsune Ral ([@kitsune:matrix.org](https://matrix.to/#/@kitsune:matrix.org) or [Kitsune-Ral@users.sf.net](mailto:Kitsune-Ral@users.sf.net)). ## Download and install The latest release (with links to cross-platform source code archives, as well as archived binaries for Windows) can be found at [GitHub Releases page](https://github.com/QMatrixClient/Quaternion/releases/latest). Packagers are very scarce so far, so please step up and support your favourite system! Notably, we still need a MacOS maintainer - Quaternion sees no actual usage/testing on this platform yet. Build instructions for the source code can be found in BUILDING.md. #### Windows The archives published on the GitHub Releases page already include the necessary subset of Qt; you don't need to additionally download and install anything. For those who want the very latest version (beware, you are very likely to find it not working), automatic builds for Windows are packaged by AppVeyor CI upon every commit. To get an archive, surf to the [AppVeyor CI page for Quaternion](https://ci.appveyor.com/project/QMatrixClient/quaternion), then go to "Jobs", click on a job for your architecture and find the archive in "Artifacts". Once you unpack the archive, **delete or rename** the "bearer" directory (see "Troubleshooting" below for details). #### Linux Unofficial package for Arch Linux: https://aur.archlinux.org/packages/quaternion/ Quaternion is at Flathub - to install, use `flatpak --install https://flathub.org/repo/appstream/com.github.quaternion`. This is still experimental - please make issues at https://github.com/flathub/com.github.quaternion if you find that Quaternion doesn't work from a Flatpak. ## Requirements Quaternion only depends on Qt libraries version 5.2.1 or higher. On Linux, this matches the package base of Debian Jessie and Ubuntu Trusty Tar. On Windows, all needed libraries are included in the archive - you don't need to separately install anything. ## Running Just start the executable in your most preferred way - either from build directory or from the installed location. ### Before you run it on Windows Since we can't rely on package management on Windows, Qt libraries and a C++ runtime are packaged/installed together with Quaternion. However, OpenSSL libraries (ssleay32.dll and libeay32.dll) are not installed automatically because of export restrictions. Unless you already have them around (e.g., they are a part of any Qt development installation, see `Tools//opt/bin`), your best bet is to find and download these libraries yourself, and either install them system-wide (which probably makes sense as soon as you keep them up-to-date; make sure the location is in your PATH) or put them next to quaternion.exe. ### Configuration and cache files Quaternion stores its configuration in a way standard for Qt applications. It will read and write the configuration in the user-specific location (creating it if non-existent) and will only read the system-wide location with reasonable defaults if the configuration is nowhere to be found. - Linux: - system-wide: `$XDG_CONFIG_DIR/QMatrixClient/quaternion` or `/etc/xdg/QMatrixClient/quaternion` - user-specific: `$HOME/.config/QMatrixClient/quaternion` - OSX: - system-wide: `/Library/Preferences/com.QMatrixClient.quaternion.plist` - user-specific: `$HOME/Library/Preferences/com.QMatrixClient.quaternion.plist` - Windows: registry keys under - system-wide: `HKEY_LOCAL_MACHINE\Software\QMatrixClient\quaternion` - user-specific: `HKEY_CURRENT_USER\Software\QMatrixClient\quaternion` Several settings are not exposed in the UI: - `UI/suppress_splash` - set this to 1 if you don't want a splash screen - `UI/condense_chat` - set this to 1 to make the timeline rendered tighter, without gaps between messages Since version 0.0.5, Quaternion tries to store your access tokens in a dedicated file with restricted access rights so that only the owner can access them. Every access token is stored in a separate file matching your user id in the following directory: - Linux: `$HOME/.local/share/QMatrixClient/quaternion` - OSX: `$HOME/Library/Application Support/QMatrixClient/quaternion` - Windows: `%LOCALAPPDATA%/QMatrixClient/quaternion` Unfortunately, Quaternion cannot enforce proper access rights on Windows yet; you'll see a warning about it and will be able to either refuse saving your access token in that case or agree and setup file permissions outside Quaternion. Quaternion caches the rooms state on the file system in a conventional location for your platform, as follows: - Linux: `$HOME/.cache/QMatrixClient/quaternion` - OSX: `$HOME/Library/Cache/QMatrixClient/quaternion` - Windows: `%LOCALAPPDATA%/QMatrixClient/quaternion/cache` Cache files are safe to delete at any time. If Quaternion doesn't find them when starting up it downloads the whole state from Matrix servers, which can take much time (up to a minute and even more, depending on the number of rooms and the number of users in them). Deleting cache files may help with problems such as missing avatars, rooms stuck in a wrong state etc. ## Troubleshooting #### Ever reconnecting though the network is fine If Quaternion starts displaying the message that it couldn't connect to the server and retries more than a couple of times without success, while you're sure you have the network connection - double-check that you don't have Qt bearer management libraries: they cause issues with some WiFi networks. Try to find "bearer" directory where your Qt is installed (on Windows it's next to Quaternion executable; on Linux it's a part of Qt installation in `/usr/lib/qt5/plugins`). Then delete or rename it (on Windows) or delete the package that this directory is in (on Linux). #### No messages in the timeline If Quaternion runs but you can't see any messages in the chat (though you can type them in) - you have a problem with Qt Quick. Most likely, you don't have Qt Quick libraries and/or plugins installed. On Linux, double check "Pre-requisites" above and also see the stdout/stderr logs, they are quite clear in such cases. On Windows and Mac, just open an issue (see "Contacts" in the beginning of this README), because most likely not all necessary Qt parts got copied along with Quaternion (which is a bug). #### SSL problems Especially on Windows, if Quaternion starts up but upon an attempt to connect returns a message like "Failed to make SSL context" - you haven't made sure that SSL libraries are reachable by the Quaternion binary. See the "OpenSSL on Windows" section above for details. #### DLL hell If you have troubles with dynamic libraries on Windows, [the Dependencies Walker tool aka depends.exe](http://www.dependencywalker.com/) helps a lot in navigating the DLL hell - especially when you have a mixed 32/64-bit environment or have different versions of the same library scattered around. OpenSSL, in particular, is notoriously often dragged along by all kinds of software; and you may have other copies of Qt around which you didn't even know about - e.g., with CMake GUI. #### Logging categories When chasing bugs and investigating crashes, it helps to increase the debug level. Thanks to @eang:matrix.org, libqmatrixclient uses Qt logging categories - the "Troubleshooting" section of `lib/README.md` elaborates on how to setup logging. Note that Quaternion itself doesn't use Qt logging categories yet, only the library does. ## Screenshot ![Screenshot](quaternion.png) Quaternion-0.0.5/client/000077500000000000000000000000001321710324500151155ustar00rootroot00000000000000Quaternion-0.0.5/client/activitydetector.cpp000066400000000000000000000053331321710324500212130ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Malte Brandy * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "activitydetector.h" #include #include "mainwindow.h" #include "chatroomwidget.h" ActivityDetector::ActivityDetector(QApplication& a, MainWindow& w) : m_app(a) , m_mainWindow(w) , m_enabled(false) { const auto chatWidget = w.getChatRoomWidget(); connect( chatWidget, &ChatRoomWidget::readMarkerMoved, this, &ActivityDetector::updateEnabled ); connect( chatWidget, &ChatRoomWidget::readMarkerCandidateMoved, this, &ActivityDetector::updateEnabled ); connect( this, &ActivityDetector::triggered, chatWidget, &ChatRoomWidget::markShownAsRead ); } void ActivityDetector::updateEnabled() { setEnabled(m_mainWindow.getChatRoomWidget()->pendingMarkRead()); } void ActivityDetector::setEnabled(bool enabled) { if (enabled == m_enabled) return; m_enabled = enabled; m_mainWindow.setMouseTracking(enabled); if (enabled) m_app.installEventFilter(this); else m_app.removeEventFilter(this); qDebug() << "Activity Detector enabled:" << enabled; } bool ActivityDetector::eventFilter(QObject* obj, QEvent* ev) { switch (ev->type()) { case QEvent::KeyPress: case QEvent::FocusIn: case QEvent::MouseMove: case QEvent::MouseButtonPress: emit triggered(); break; default:; } return QObject::eventFilter(obj, ev); } Quaternion-0.0.5/client/activitydetector.h000066400000000000000000000035231321710324500206570ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Malte Brandy * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include class MainWindow; class ActivityDetector : public QObject { Q_OBJECT public: ActivityDetector(QApplication& a, MainWindow& c); public slots: void updateEnabled(); void setEnabled(bool enabled); signals: void triggered(); protected: bool eventFilter(QObject* obj, QEvent* ev); private: QApplication& m_app; MainWindow& m_mainWindow; bool m_enabled; }; Quaternion-0.0.5/client/chatedit.cpp000066400000000000000000000077471321710324500174250ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2017 Kitsune Ral * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "chatedit.h" #include #include "chatroomwidget.h" ChatEdit::ChatEdit(ChatRoomWidget* c) : KChatEdit(c), chatRoomWidget(c) { } void ChatEdit::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Tab) { triggerCompletion(); return; } cancelCompletion(); KChatEdit::keyPressEvent(event); } void ChatEdit::appendTextAtCursor(const QString& text, bool select) { completionCursor.insertText(text); completionCursor.movePosition(QTextCursor::PreviousCharacter, select ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor, text.size()); } void ChatEdit::startNewCompletion() { completionCursor = textCursor(); completionCursor.clearSelection(); while ( completionCursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor) ) { QChar firstChar = completionCursor.selectedText().at(0); if (!firstChar.isLetterOrNumber() && firstChar != '@') { completionCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); break; } } completionMatches = chatRoomWidget->findCompletionMatches(completionCursor.selectedText()); if ( !completionMatches.isEmpty() ) { matchesListPosition = 0; auto lookBehindCursor = completionCursor; if ( lookBehindCursor.atStart() ) { appendTextAtCursor(": ", false); return; } for (auto stringBefore: {":", ": "}) { lookBehindCursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); if ( lookBehindCursor.selectedText().startsWith(stringBefore) ) { lookBehindCursor.insertText(", "); appendTextAtCursor(": ", false); return; } } appendTextAtCursor(" ", false); } } void ChatEdit::triggerCompletion() { if (completionMatches.isEmpty()) startNewCompletion(); if (!completionMatches.isEmpty()) { appendTextAtCursor(completionMatches.at(matchesListPosition), true); ensureCursorVisible(); // The real one, not completionCursor QTextCharFormat completionHL = completionCursor.charFormat(); completionHL.setUnderlineStyle(QTextCharFormat::DashUnderline); setExtraSelections({ { completionCursor, completionHL } }); emit proposedCompletion(completionMatches, matchesListPosition); matchesListPosition = (matchesListPosition + 1) % completionMatches.length(); } } void ChatEdit::cancelCompletion() { completionMatches.clear(); setExtraSelections({}); emit cancelledCompletion(); } Quaternion-0.0.5/client/chatedit.h000066400000000000000000000040641321710324500170570ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2017 Kitsune Ral * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include "kchatedit.h" #include class ChatRoomWidget; class ChatEdit : public KChatEdit { Q_OBJECT public: ChatEdit(ChatRoomWidget* c); void triggerCompletion(); void cancelCompletion(); signals: void proposedCompletion(const QStringList& allCompletions, int curIndex); void cancelledCompletion(); protected: void keyPressEvent(QKeyEvent* event) override; private: ChatRoomWidget* chatRoomWidget; QTextCursor completionCursor; QStringList completionMatches; int matchesListPosition; void startNewCompletion(); void appendTextAtCursor(const QString& text, bool select = false); }; Quaternion-0.0.5/client/chatroomwidget.cpp000066400000000000000000000422071321710324500206460ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "chatroomwidget.h" #include #include #include #include #include #include #include #include #include "lib/events/roommessageevent.h" #include "lib/user.h" #include "lib/connection.h" #include "lib/settings.h" #include "models/messageeventmodel.h" #include "imageprovider.h" #include "chatedit.h" ChatRoomWidget::ChatRoomWidget(QWidget* parent) : QWidget(parent) , m_currentRoom(nullptr) , readMarkerOnScreen(false) { qmlRegisterType(); qmlRegisterType("QMatrixClient", 1, 0, "Settings"); m_messageModel = new MessageEventModel(this); m_roomAvatar = new QLabel(); m_roomAvatar->setPixmap({}); m_roomAvatar->setFrameStyle(QFrame::Sunken); m_topicLabel = new QLabel(); m_topicLabel->setTextFormat(Qt::RichText); m_topicLabel->setWordWrap(true); m_topicLabel->setTextInteractionFlags(Qt::TextBrowserInteraction |Qt::TextSelectableByKeyboard); m_topicLabel->setOpenExternalLinks(true); auto topicSeparator = new QFrame(); topicSeparator->setFrameShape(QFrame::HLine); m_quickView = new QQuickView(); m_imageProvider = new ImageProvider(nullptr); // No connection yet m_quickView->engine()->addImageProvider("mtx", m_imageProvider); QWidget* container = QWidget::createWindowContainer(m_quickView, this); container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QQmlContext* ctxt = m_quickView->rootContext(); ctxt->setContextProperty("messageModel", m_messageModel); ctxt->setContextProperty("controller", this); ctxt->setContextProperty("debug", QVariant(false)); m_quickView->setSource(QUrl("qrc:///qml/chat.qml")); m_quickView->setResizeMode(QQuickView::SizeRootObjectToView); m_currentlyTyping = new QLabel(); m_currentlyTyping->setWordWrap(true); m_chatEdit = new ChatEdit(this); m_chatEdit->setPlaceholderText(tr("Send a message (unencrypted)...")); m_chatEdit->setAcceptRichText(false); connect( m_chatEdit, &KChatEdit::returnPressed, this, &ChatRoomWidget::sendInput ); connect(m_chatEdit, &ChatEdit::proposedCompletion, this, [=](const QStringList& matches, int pos) { m_currentlyTyping->setText( tr("Next completion: %1") .arg( QStringList(matches.mid(pos, 5)).join(", ") ) ); }); connect(m_chatEdit, &ChatEdit::cancelledCompletion, this, &ChatRoomWidget::typingChanged); auto layout = new QVBoxLayout(); auto headerLayout = new QHBoxLayout; headerLayout->addWidget(m_roomAvatar); headerLayout->addWidget(m_topicLabel, 1); layout->addLayout(headerLayout); layout->addWidget(topicSeparator); layout->addWidget(container); layout->addWidget(m_currentlyTyping); layout->addWidget(m_chatEdit); setLayout(layout); } void ChatRoomWidget::enableDebug() { QQmlContext* ctxt = m_quickView->rootContext(); ctxt->setContextProperty("debug", true); } void ChatRoomWidget::setRoom(QuaternionRoom* room) { if (m_currentRoom == room) { m_chatEdit->setFocus(); return; } if( m_currentRoom ) { m_currentRoom->setCachedInput( m_chatEdit->toPlainText() ); m_currentRoom->setShown(false); roomHistories.insert(m_currentRoom, m_chatEdit->history()); m_currentRoom->connection()->disconnect(this); m_currentRoom->disconnect( this ); } readMarkerOnScreen = false; maybeReadTimer.stop(); indicesOnScreen.clear(); m_chatEdit->cancelCompletion(); m_currentRoom = room; if( m_currentRoom ) { using namespace QMatrixClient; m_imageProvider->setConnection(room->connection()); m_chatEdit->setText( m_currentRoom->cachedInput() ); m_chatEdit->setHistory(roomHistories.value(m_currentRoom)); m_chatEdit->setFocus(); m_chatEdit->moveCursor(QTextCursor::End); connect( m_currentRoom, &Room::typingChanged, this, &ChatRoomWidget::typingChanged ); connect( m_currentRoom, &Room::namesChanged, this, &ChatRoomWidget::updateHeader ); connect( m_currentRoom, &Room::topicChanged, this, &ChatRoomWidget::updateHeader ); connect( m_currentRoom, &Room::avatarChanged, this, &ChatRoomWidget::updateHeader ); connect( m_currentRoom, &Room::readMarkerMoved, this, [this] { const auto rm = m_currentRoom->readMarker(); readMarkerOnScreen = rm != m_currentRoom->timelineEdge() && std::lower_bound( indicesOnScreen.begin(), indicesOnScreen.end(), rm->index() ) != indicesOnScreen.end(); reStartShownTimer(); emit readMarkerMoved(); }); connect(m_currentRoom->connection(), &Connection::loggedOut, this, [this] { qWarning() << "Logged out, escaping the room"; setRoom(nullptr); }); connect(m_currentRoom->connection(), &Connection::joinedRoom, this, [this] (Room* r, Room* prev) { if (m_currentRoom == prev) setRoom(static_cast(r)); }); connect(m_currentRoom->connection(), &Connection::aboutToDeleteRoom, this, [this] (Room* r) { if (m_currentRoom == r) setRoom(nullptr); }); m_currentRoom->setShown(true); } else m_imageProvider->setConnection(nullptr); updateHeader(); typingChanged(); m_messageModel->changeRoom( m_currentRoom ); QObject* rootItem = m_quickView->rootObject(); QMetaObject::invokeMethod(rootItem, "scrollToBottom"); } void ChatRoomWidget::typingChanged() { if (!m_currentRoom || m_currentRoom->usersTyping().isEmpty()) { m_currentlyTyping->clear(); return; } QStringList typingNames; for(auto user: m_currentRoom->usersTyping()) { typingNames << m_currentRoom->roomMembername(user); } m_currentlyTyping->setText(tr("Currently typing: %1") .arg( typingNames.join(", ") ) ); } void ChatRoomWidget::updateHeader() { if (m_currentRoom) { auto topic = m_currentRoom->topic(); auto prettyTopic = topic.isEmpty() ? tr("(no topic)") : m_currentRoom->prettyPrint(topic); m_topicLabel->setText("" % m_currentRoom->name() % "
" % prettyTopic); auto avatarSize = m_topicLabel->heightForWidth(width()); m_roomAvatar->setPixmap(m_currentRoom->avatar(avatarSize, avatarSize)); } else { m_roomAvatar->clear(); m_topicLabel->clear(); } } bool ChatRoomWidget::checkAndRun(const QString& checkArg, const QString& pattern, std::function fn, const QString& errorMsg) const { if (QRegularExpression(pattern).match(checkArg).hasMatch()) { fn(); return true; } emit showStatusMessage(errorMsg, 5000); return false; } bool ChatRoomWidget::checkAndRun1(const QString& args, const QString& pattern, std::function fn1, const QString& errorMsg) const { return checkAndRun(args, pattern, std::bind(fn1, m_currentRoom, args), errorMsg); } bool ChatRoomWidget::checkAndRun2(const QString& args, const QString& pattern1, std::function fn2, const QString& errorMsg) const { const auto nextSpacePos = args.indexOf(' ', 1); const auto arg1 = args.left(nextSpacePos); const auto arg2 = args.mid(nextSpacePos + 1).trimmed(); return checkAndRun(arg1, pattern1, std::bind(fn2, m_currentRoom, arg1, arg2), errorMsg); } bool ChatRoomWidget::doSendInput() { QString text = m_chatEdit->toPlainText(); if ( text.isEmpty() ) return false; if (!text.startsWith('/')) { m_currentRoom->postMessage(text); return true; } if (text[1] == '/') { text.remove(0, 1); m_currentRoom->postMessage(text); return true; } // Process a command static const QRegularExpression re("^/([^ ]+)( (.*))?$"); const auto matches = re.match(text); const auto command = matches.capturedRef(1); const auto args = matches.captured(3); static const auto ROOM_ID = QStringLiteral("^[#!][-0-9a-z._=]+:.+$"); static const auto USER_ID = QStringLiteral("^@[-0-9a-z._=]+:.+$"); using QMatrixClient::Room; // Commands available without a current room if (command == "join") { return checkAndRun(args, ROOM_ID, [=] { emit joinCommandEntered(args); }, tr("/join argument doesn't look like a room ID or alias")); } // --- Add more roomless commands here if (!m_currentRoom) { emit showStatusMessage( tr("There's no such /command outside of room." " Start with // to send this line literally"), 5000); return false; } // Commands available only in the room context if (command == "leave") { m_currentRoom->leaveRoom(); return true; } if (command == "forget") { if (args.isEmpty()) { emit showStatusMessage( tr("/forget should be followed by the room id," " even for the current room")); return false; } return checkAndRun(args, ROOM_ID, [=] { m_currentRoom->connection()->forgetRoom(args); }, tr("/forget should be followed by the room id")); } if (command == "invite") { return checkAndRun1(args, USER_ID, &Room::inviteToRoom, tr("/invite argument doesn't look like a user ID")); } if (command == "kick") { return checkAndRun2(args, USER_ID, &Room::kickMember, tr("The first /kick argument doesn't look like a user ID")); } if (command == "ban") { return checkAndRun2(args, USER_ID, &Room::ban, tr("The first /ban argument doesn't look like a user ID")); } if (command == "unban") { return checkAndRun1(args, USER_ID, &Room::unban, tr("/unban argument doesn't look like a user ID")); } using MsgType = QMatrixClient::RoomMessageEvent::MsgType; if (command == "me") { m_currentRoom->postMessage(args, MsgType::Emote); return true; } if (command == "notice") { m_currentRoom->postMessage(args, MsgType::Notice); return true; } if (command == "shrug") // Peeked at Discord { m_currentRoom->postMessage("¯\\_(ツ)_/¯"); return true; } if (command == "topic") { m_currentRoom->setTopic(args); return true; } if (command == "nick") { // Technically, it's legitimate to change the displayname outside of // any room; however, since Quaternion allows having several connections, // it needs to understand which connection to engage, and there's no good // way so far to determine the connection outside of a room. m_currentRoom->localUser()->rename(args); return true; } // --- Add more room commands here qDebug() << "Unknown command:" << command; emit showStatusMessage( tr("Unknown /command. Use // to send this line literally"), 5000); return false; } void ChatRoomWidget::sendInput() { if (doSendInput()) m_chatEdit->saveInput(); } QStringList ChatRoomWidget::findCompletionMatches(const QString& pattern) const { QStringList matches; if (m_currentRoom) { for(auto name: m_currentRoom->memberNames() ) { if ( name.startsWith(pattern, Qt::CaseInsensitive) ) { int ircSuffixPos = name.indexOf(" (IRC)"); if ( ircSuffixPos != -1 ) name.truncate(ircSuffixPos); matches.append(name); } } std::sort(matches.begin(), matches.end(), [] (const QString& s1, const QString& s2) { return s1.localeAwareCompare(s2) < 0; }); matches.removeDuplicates(); } return matches; } void ChatRoomWidget::onMessageShownChanged(QString eventId, bool shown) { if (!m_currentRoom) return; // A message can be auto-marked as read (as soon as the user is active), if: // 0. The read marker exists and is on the screen // 1. The message is shown on the screen now // 2. It's been the bottommost message on the screen for the last 1 second // 3. It's below the read marker const auto readMarker = m_currentRoom->readMarker(); if (readMarker != m_currentRoom->timelineEdge() && readMarker->event()->id() == eventId) { readMarkerOnScreen = shown; if (shown) { qDebug() << "Read marker is on-screen, at" << *readMarker; indexToMaybeRead = readMarker->index(); reStartShownTimer(); } else { qDebug() << "Read marker is off-screen"; qDebug() << "Bottommost shown message index was" << indexToMaybeRead; maybeReadTimer.stop(); } } const auto iter = m_currentRoom->findInTimeline(eventId); if (iter == m_currentRoom->timelineEdge()) { qCritical() << "Event" << eventId << "is not in the timeline"; Q_ASSERT(false); return; } const auto timelineIndex = iter->index(); auto pos = std::lower_bound(indicesOnScreen.begin(), indicesOnScreen.end(), timelineIndex); if (shown) { if (pos == indicesOnScreen.end() || *pos != timelineIndex) { indicesOnScreen.insert(pos, timelineIndex); if (timelineIndex == indicesOnScreen.back()) reStartShownTimer(); } } else { if (pos != indicesOnScreen.end() && *pos == timelineIndex) if (indicesOnScreen.erase(pos) == indicesOnScreen.end()) reStartShownTimer(); } } void ChatRoomWidget::reStartShownTimer() { if (!readMarkerOnScreen || indicesOnScreen.empty() || indexToMaybeRead >= indicesOnScreen.back()) return; maybeReadTimer.start(1000, this); qDebug() << "Scheduled maybe-read message update:" << indexToMaybeRead << "->" << indicesOnScreen.back(); } void ChatRoomWidget::timerEvent(QTimerEvent* qte) { if (qte->timerId() != maybeReadTimer.timerId()) { QWidget::timerEvent(qte); return; } maybeReadTimer.stop(); // Only update the maybe-read message if we're tracking it if (readMarkerOnScreen && !indicesOnScreen.empty() && indexToMaybeRead < indicesOnScreen.back()) { qDebug() << "Maybe-read message update:" << indexToMaybeRead << "->" << indicesOnScreen.back(); indexToMaybeRead = indicesOnScreen.back(); emit readMarkerCandidateMoved(); } } void ChatRoomWidget::markShownAsRead() { // FIXME: a case when a single message doesn't fit on the screen. if (m_currentRoom && readMarkerOnScreen) { const auto iter = m_currentRoom->findInTimeline(indicesOnScreen.back()); Q_ASSERT( iter != m_currentRoom->timelineEdge() ); m_currentRoom->markMessagesAsRead((*iter)->id()); } } bool ChatRoomWidget::pendingMarkRead() const { if (!readMarkerOnScreen || !m_currentRoom) return false; const auto rm = m_currentRoom->readMarker(); return rm != m_currentRoom->timelineEdge() && rm->index() < indexToMaybeRead; } Quaternion-0.0.5/client/chatroomwidget.h000066400000000000000000000070401321710324500203070ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include #include #include "quaternionroom.h" class ChatEdit; class MessageEventModel; class ImageProvider; class QFrame; class QQuickView; class QLabel; class QTextDocument; class ChatRoomWidget: public QWidget { Q_OBJECT public: explicit ChatRoomWidget(QWidget* parent = nullptr); void enableDebug(); bool pendingMarkRead() const; QStringList findCompletionMatches(const QString& pattern) const; signals: void joinCommandEntered(const QString& roomAlias); void showStatusMessage(const QString& message, int timeout = 0) const; void readMarkerMoved(); void readMarkerCandidateMoved(); public slots: void setRoom(QuaternionRoom* room); void updateHeader(); void typingChanged(); void onMessageShownChanged(QString eventId, bool shown); void markShownAsRead(); protected: void timerEvent(QTimerEvent* event) override; private slots: void sendInput(); private: MessageEventModel* m_messageModel; QuaternionRoom* m_currentRoom; QQuickView* m_quickView; ImageProvider* m_imageProvider; ChatEdit* m_chatEdit; QLabel* m_currentlyTyping; QLabel* m_topicLabel; QLabel* m_roomAvatar; using timeline_index_t = QMatrixClient::TimelineItem::index_t; QVector indicesOnScreen; timeline_index_t indexToMaybeRead; QBasicTimer maybeReadTimer; bool readMarkerOnScreen; QMap> roomHistories; void reStartShownTimer(); bool doSendInput(); bool checkAndRun(const QString& args, const QString& pattern, std::function fn, const QString& errorMsg) const; bool checkAndRun1(const QString& args, const QString& pattern, std::function fn1, const QString& errorMsg) const; bool checkAndRun2(const QString& args, const QString& pattern1, std::function fn2, const QString& errorMsg) const; }; Quaternion-0.0.5/client/imageprovider.cpp000066400000000000000000000062131321710324500204600ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "imageprovider.h" #include "lib/connection.h" #include "jobs/mediathumbnailjob.h" #include #include using QMatrixClient::MediaThumbnailJob; ImageProvider::ImageProvider(QMatrixClient::Connection* connection) : QQuickImageProvider(QQmlImageProviderBase::Pixmap, QQmlImageProviderBase::ForceAsynchronousImageLoading) , m_connection(connection) { #if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) qRegisterMetaType(); #endif } QPixmap ImageProvider::requestPixmap(const QString& id, QSize* pSize, const QSize& requestedSize) { QMutexLocker locker(&m_mutex); qDebug() << "ImageProvider::requestPixmap:" << id; MediaThumbnailJob* job = nullptr; #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) QMetaObject::invokeMethod(m_connection, [=] { return m_connection->getThumbnail(id, requestedSize); }, Qt::BlockingQueuedConnection, &job); #else QMetaObject::invokeMethod(m_connection, "getThumbnail", Qt::BlockingQueuedConnection, Q_RETURN_ARG(MediaThumbnailJob*, job), Q_ARG(QUrl, id), Q_ARG(QSize, requestedSize)); #endif if (!job) { qDebug() << "ImageProvider: failed to send a request"; return {}; } QPixmap result; { QWaitCondition condition; // The most compact way to block on a signal job->connect(job, &MediaThumbnailJob::finished, job, [&] { result = job->thumbnail(); condition.wakeAll(); }); condition.wait(&m_mutex); } if( pSize != nullptr ) *pSize = result.size(); return result; } void ImageProvider::setConnection(QMatrixClient::Connection* connection) { QMutexLocker locker(&m_mutex); m_connection = connection; } Quaternion-0.0.5/client/imageprovider.h000066400000000000000000000036031321710324500201250ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include #include namespace QMatrixClient { class Connection; } class ImageProvider: public QQuickImageProvider { public: explicit ImageProvider(QMatrixClient::Connection* connection); QPixmap requestPixmap(const QString& id, QSize* pSize, const QSize& requestedSize) override; void setConnection(QMatrixClient::Connection* connection); private: QMatrixClient::Connection* m_connection; QMutex m_mutex; }; Quaternion-0.0.5/client/kchatedit.cpp000066400000000000000000000147741321710324500175760ustar00rootroot00000000000000/* * Copyright (C) 2017 Elvis Angelaccio * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "kchatedit.h" #include #include #include class KChatEdit::KChatEditPrivate { public: void emitReturnPressed(); QString getDocumentText(QTextDocument* doc) const; void updateAndMoveInHistory(int increment); void rewindHistory(); void forwardHistory(); void saveInput(); KChatEdit *q = nullptr; // History always ends with a placeholder string that is initially empty // but may be filled with tentative input when the user entered something // and then went out for history. QVector history { 1, new QTextDocument() }; int index = 0; int maxHistorySize = 100; }; void KChatEdit::KChatEditPrivate::emitReturnPressed() { if (q->document()->isEmpty()) { return; } emit q->returnPressed(); } QString KChatEdit::KChatEditPrivate::getDocumentText(QTextDocument* doc) const { Q_ASSERT(doc); return q->acceptRichText() ? doc->toHtml() : doc->toPlainText(); } void KChatEdit::KChatEditPrivate::updateAndMoveInHistory(int increment) { Q_ASSERT(index >= 0 && index < history.size()); // Only save input if different from the latest one. if (getDocumentText(q->document()) != getDocumentText(history[index])) { history[index] = q->document(); history[index]->setParent(nullptr); } const auto* nextDocument = history.at(index += increment); q->setDocument(nextDocument->clone(q)); q->moveCursor(QTextCursor::End); } void KChatEdit::KChatEditPrivate::rewindHistory() { if (index > 0) updateAndMoveInHistory(-1); } void KChatEdit::KChatEditPrivate::forwardHistory() { if (index < history.size() - 1) updateAndMoveInHistory(+1); } void KChatEdit::KChatEditPrivate::saveInput() { if (q->document()->isEmpty()) { return; } // Only save input if different from the latest one or from the history. const auto input = getDocumentText(q->document()); if (index < history.size() - 1 && input == getDocumentText(history[index])) { // Take the history entry and move it to the most recent position (but // before the placeholder). #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) history.move(index, history.size() - 2); #else history.insert(history.size() - 2, history.takeAt(index)); #endif emit q->savedInputChanged(); } else if (input != getDocumentText(q->savedInput())) { // Replace the placeholder with the new input. history.back() = q->document()->clone(); if (history.size() >= maxHistorySize) { delete history.takeFirst(); } // Make a new placeholder. history << new QTextDocument(); emit q->savedInputChanged(); } index = history.size() - 1; q->clear(); } KChatEdit::KChatEdit(QWidget *parent) : QTextEdit(parent), d(new KChatEditPrivate) { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); connect(this, &QTextEdit::textChanged, this, &QWidget::updateGeometry); d->q = this; // KChatEdit initialization complete, pimpl can use it } KChatEdit::~KChatEdit() = default; QTextDocument* KChatEdit::savedInput() const { if (d->history.size() >= 2) return d->history.at(d->history.size() - 2); Q_ASSERT(d->history.size() == 1); return d->history.front(); } void KChatEdit::saveInput() { d->saveInput(); } QVector KChatEdit::history() const { return d->history; } void KChatEdit::setHistory(const QVector &history) { d->history = history; if (history.isEmpty() || !history.last()->isEmpty()) { d->history << new QTextDocument(); } while (d->history.size() > maxHistorySize()) { delete d->history.takeFirst(); } d->index = d->history.size() - 1; } int KChatEdit::maxHistorySize() const { return d->maxHistorySize; } void KChatEdit::setMaxHistorySize(int maxHistorySize) { d->maxHistorySize = maxHistorySize; } QSize KChatEdit::minimumSizeHint() const { QSize minimumSizeHint = QTextEdit::minimumSizeHint(); QMargins margins; margins += static_cast(document()->documentMargin()); margins += contentsMargins(); if (!placeholderText().isEmpty()) { minimumSizeHint.setWidth(fontMetrics().width(placeholderText()) + margins.left()*2.5); } if (document()->isEmpty()) { minimumSizeHint.setHeight(fontMetrics().lineSpacing() + margins.top() + margins.bottom()); } else { minimumSizeHint.setHeight(document()->size().height()); } return minimumSizeHint; } QSize KChatEdit::sizeHint() const { ensurePolished(); if (document()->isEmpty()) { return minimumSizeHint(); } QMargins margins; margins += static_cast(document()->documentMargin()); margins += contentsMargins(); QSize size = document()->size().toSize(); size.rwidth() += margins.left() + margins.right(); size.rheight() += margins.top() + margins.bottom(); // Be consistent with minimumSizeHint(). if (document()->lineCount() == 1 && !toPlainText().contains(QLatin1Char('\n'))) { size.setHeight(fontMetrics().lineSpacing() + margins.top() + margins.bottom()); } return size; } void KChatEdit::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Enter: case Qt::Key_Return: if (!(QGuiApplication::keyboardModifiers() & Qt::ShiftModifier)) { d->emitReturnPressed(); return; } break; case Qt::Key_Up: if (!textCursor().movePosition(QTextCursor::Up)) { d->rewindHistory(); } break; case Qt::Key_Down: if (!textCursor().movePosition(QTextCursor::Down)) { d->forwardHistory(); } break; default: break; } QTextEdit::keyPressEvent(event); } Quaternion-0.0.5/client/kchatedit.h000066400000000000000000000103361321710324500172310ustar00rootroot00000000000000/* * Copyright (C) 2017 Elvis Angelaccio * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KCHATEDIT_H #define KCHATEDIT_H #include /** * @class KChatEdit kchatedit.h KChatEdit * * @brief An input widget with history for chat applications. * * This widget can be used to get input for chat windows, which tipically corresponds to chat messages or * protocol-specific commands (for example the "/whois" IRC command). * * By default the widget takes as less space as possible, which is the same space as used by a QLineEdit. * It is possible to expand the widget and enter "multi-line" messages, by pressing Shift + Return. * * Chat applications usually maintain a history of what the user typed, which can be browsed with the * Up and Down keys (exactly like in command-line shells). This feature is fully supported by this widget. * The widget emits the inputRequested() signal upon pressing the Return key. * You can then call saveInput() to make the input text disappear, as typical in chat applications. * The input goes in the history and can be retrieved with the savedInput() method. * * @author Elvis Angelaccio */ class KChatEdit : public QTextEdit { Q_OBJECT Q_PROPERTY(QTextDocument* savedInput READ savedInput NOTIFY savedInputChanged) Q_PROPERTY(QVector history READ history WRITE setHistory) Q_PROPERTY(int maxHistorySize READ maxHistorySize WRITE setMaxHistorySize) public: explicit KChatEdit(QWidget *parent = nullptr); virtual ~KChatEdit(); /** * The latest input text saved in the history. * This corresponds to the last element of history(). * @return Latest available input or an empty document if saveInput() has not been called yet. * @see inputChanged(), saveInput(), history() */ QTextDocument* savedInput() const; /** * Saves in the history the current document(). * This also clears the QTextEdit area. * @note If the history is full (see maxHistorySize(), new inputs will take space from the oldest * items in the history. * @see savedInput(), history(), maxHistorySize() */ void saveInput(); /** * @return The history of the text inputs that the user typed. * @see savedInput(), saveInput(); */ QVector history() const; /** * Set the history of this widget to @p history. * This can be useful when sharing a single instance of KChatEdit with many "channels" or "rooms" * that maintain their own private history. */ void setHistory(const QVector &history); /** * @return The maximum number of input items that the history can store. * @see history() */ int maxHistorySize() const; /** * Set the maximum number of input items that the history can store. * @see maxHistorySize() */ void setMaxHistorySize(int maxHistorySize); QSize minimumSizeHint() const Q_DECL_OVERRIDE; QSize sizeHint() const Q_DECL_OVERRIDE; Q_SIGNALS: /** * A new input has been saved in the history. * @see savedInput(), saveInput(), history() */ void savedInputChanged(); /** * Emitted when the user types Key_Return or Key_Enter, which typically means the user * wants to "send" what was typed. Call saveInput() if you want to actually save the input. * @see savedInput(), saveInput(), history() */ void returnPressed(); protected: void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; private: class KChatEditPrivate; QScopedPointer d; Q_DISABLE_COPY(KChatEdit) }; #endif Quaternion-0.0.5/client/logindialog.cpp000066400000000000000000000120021321710324500201040ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "logindialog.h" #include #include #include #include #include #include "settings.h" LoginDialog::LoginDialog(QWidget* parent) : QDialog(parent) , serverEdit(new QLineEdit("https://matrix.org")) , userEdit(new QLineEdit()) , passwordEdit(new QLineEdit()) , initialDeviceName(new QLineEdit()) , loginButton(new QPushButton(tr("Login"))) , saveTokenCheck(new QCheckBox(tr("Stay logged in"))) , statusLabel(new QLabel(tr("Welcome to Quaternion"))) , m_connection(new Connection()) { passwordEdit->setEchoMode( QLineEdit::Password ); auto* formLayout = new QFormLayout(); formLayout->addRow(tr("Matrix ID"), userEdit); formLayout->addRow(tr("Password"), passwordEdit); formLayout->addRow(tr("Device name"), initialDeviceName); formLayout->addRow(tr("Connect to server"), serverEdit); formLayout->addRow(saveTokenCheck); auto* mainLayout = new QVBoxLayout(); mainLayout->addLayout(formLayout); mainLayout->addWidget(loginButton); mainLayout->addWidget(statusLabel); setLayout(mainLayout); connect( userEdit, &QLineEdit::editingFinished, m_connection.data(), [=] { auto userId = userEdit->text(); if (userId.startsWith('@') && userId.indexOf(':') != -1) m_connection->resolveServer(userId); }); connect( m_connection.data(), &Connection::homeserverChanged, serverEdit, [=] (QUrl newUrl) { serverEdit->setText(newUrl.toString()); }); connect( loginButton, &QPushButton::clicked, this, &LoginDialog::login ); { // Fill defaults using namespace QMatrixClient; QStringList accounts { SettingsGroup("Accounts").childGroups() }; if ( !accounts.empty() ) { AccountSettings account { accounts.front() }; userEdit->setText(account.userId()); auto homeserver = account.homeserver(); if (!homeserver.isEmpty()) { m_connection->setHomeserver(homeserver); serverEdit->setText(homeserver.toString()); } initialDeviceName->setText(account.deviceName()); saveTokenCheck->setChecked(account.keepLoggedIn()); passwordEdit->setFocus(); } else { saveTokenCheck->setChecked(false); userEdit->setFocus(); } } } void LoginDialog::setStatusMessage(const QString& msg) { statusLabel->setText(msg); } LoginDialog::Connection* LoginDialog::releaseConnection() { return m_connection.take(); } QString LoginDialog::deviceName() const { return initialDeviceName->text(); } bool LoginDialog::keepLoggedIn() const { return saveTokenCheck->isChecked(); } void LoginDialog::login() { setStatusMessage(tr("Connecting and logging in, please wait")); setDisabled(true); auto url = QUrl::fromUserInput(serverEdit->text()); if (!serverEdit->text().isEmpty() && !serverEdit->text().startsWith("http")) url.setScheme("https"); // Qt defaults to http (or even ftp for some) m_connection->setHomeserver(url); connect( m_connection.data(), &Connection::connected, this, &QDialog::accept ); connect( m_connection.data(), &Connection::loginError, this, &LoginDialog::error ); m_connection->connectToServer(userEdit->text(), passwordEdit->text(), initialDeviceName->text()); } void LoginDialog::error(QString error) { setStatusMessage(error); setDisabled(false); } Quaternion-0.0.5/client/logindialog.h000066400000000000000000000043251321710324500175620ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include "lib/connection.h" #include class QLineEdit; class QPushButton; class QLabel; class QCheckBox; class LoginDialog : public QDialog { Q_OBJECT public: using Connection = QMatrixClient::Connection; explicit LoginDialog(QWidget* parent = nullptr); void setStatusMessage(const QString& msg); Connection* releaseConnection(); QString deviceName() const; bool keepLoggedIn() const; private slots: void login(); void error(QString error); private: QLineEdit* serverEdit; QLineEdit* userEdit; QLineEdit* passwordEdit; QLineEdit* initialDeviceName; QPushButton* loginButton; QCheckBox* saveTokenCheck; QLabel* statusLabel; QScopedPointer m_connection; }; Quaternion-0.0.5/client/main.cpp000066400000000000000000000062071321710324500165520ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include #include #include #include #include "mainwindow.h" #include "activitydetector.h" #include "lib/settings.h" int main( int argc, char* argv[] ) { QApplication app(argc, argv); QApplication::setOrganizationName("QMatrixClient"); QApplication::setApplicationName("quaternion"); QApplication::setApplicationDisplayName("Quaternion"); QApplication::setApplicationVersion("0.0.5"); QMatrixClient::Settings::setLegacyNames("Quaternion", "quaternion"); // We should not need to do the following, as quitOnLastWindowClosed is // set to "true" by default; might be a bug, see // https://forum.qt.io/topic/71112/application-does-not-quit QObject::connect(&app, &QApplication::lastWindowClosed, []{ qDebug() << "Last window closed!"; QApplication::postEvent(qApp, new QEvent(QEvent::Quit)); }); QCommandLineParser parser; parser.setApplicationDescription(QApplication::translate("main", "An IM client for the Matrix protocol")); parser.addHelpOption(); parser.addVersionOption(); QCommandLineOption debug("debug", QApplication::translate("main", "Display debug information")); parser.addOption(debug); parser.process(app); bool debugEnabled = parser.isSet(debug); qDebug() << "Debug: " << debugEnabled; QSplashScreen splash(QPixmap(":/icon.png")); if (!QSettings().value("UI/suppress_splash").toBool()) { splash.show(); app.processEvents(); } MainWindow window; if( debugEnabled ) window.enableDebug(); splash.finish(&window); // calls app.processEvents() ActivityDetector ad(app, window); Q_UNUSED(ad); qDebug() << "--- Show time!"; window.show(); return app.exec(); } Quaternion-0.0.5/client/mainwindow.cpp000066400000000000000000000474471321710324500200150ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public 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 #include #include #include #include #include #include #include #include #include #include #include "jobs/joinroomjob.h" #include "lib/connection.h" #include "roomlistdock.h" #include "userlistdock.h" #include "chatroomwidget.h" #include "logindialog.h" #include "systemtray.h" #include "settings.h" MainWindow::MainWindow() { Connection::setRoomType(); setWindowIcon(QIcon(":/icon.png")); roomListDock = new RoomListDock(this); addDockWidget(Qt::LeftDockWidgetArea, roomListDock); userListDock = new UserListDock(this); addDockWidget(Qt::RightDockWidgetArea, userListDock); chatRoomWidget = new ChatRoomWidget(this); setCentralWidget(chatRoomWidget); connect( chatRoomWidget, &ChatRoomWidget::joinCommandEntered, this, [=] (QString roomIdOrAlias) { joinRoom(roomIdOrAlias); }); connect( roomListDock, &RoomListDock::roomSelected, this, &MainWindow::selectRoom); connect( chatRoomWidget, &ChatRoomWidget::showStatusMessage, statusBar(), &QStatusBar::showMessage ); createMenu(); systemTray = new SystemTray(this); systemTray->show(); busyIndicator = new QMovie(":/busy.gif"); busyLabel = new QLabel(this); busyLabel->setMovie(busyIndicator); busyLabel->hide(); statusBar()->setSizeGripEnabled(false); statusBar()->addPermanentWidget(busyLabel); loadSettings(); QTimer::singleShot(0, this, SLOT(invokeLogin())); } ChatRoomWidget* MainWindow::getChatRoomWidget() const { return chatRoomWidget; } void MainWindow::createMenu() { // Connection menu connectionMenu = menuBar()->addMenu(tr("&Accounts")); #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) connectionMenu->addAction(tr("&Login..."), this, [=]{ showLoginWindow(); } ); #else connectionMenu->addAction(tr("&Login..."), this, SLOT(showLoginWindow())); #endif connectionMenu->addSeparator(); // Logout actions will be added between these two separators - see addConnection() accountListGrowthPoint = connectionMenu->addSeparator(); auto quitAction = connectionMenu->addAction(tr("&Quit")); quitAction->setShortcut(QKeySequence::Quit); connect( quitAction, &QAction::triggered, qApp, &QApplication::closeAllWindows ); // View menu auto viewMenu = menuBar()->addMenu(tr("&View")); viewMenu->addAction(roomListDock->toggleViewAction()); viewMenu->addAction(userListDock->toggleViewAction()); // Room menu auto roomMenu = menuBar()->addMenu(tr("&Room")); auto joinRoomAction = roomMenu->addAction(tr("&Join Room...")); connect( joinRoomAction, &QAction::triggered, this, [=]{ joinRoom(); } ); } void MainWindow::loadSettings() { QMatrixClient::SettingsGroup sg("UI/MainWindow"); if (sg.contains("normal_geometry")) setGeometry(sg.value("normal_geometry").toRect()); if (sg.value("maximized").toBool()) showMaximized(); if (sg.contains("window_parts_state")) restoreState(sg.value("window_parts_state").toByteArray()); } void MainWindow::saveSettings() const { QMatrixClient::SettingsGroup sg("UI/MainWindow"); sg.setValue("normal_geometry", normalGeometry()); sg.setValue("maximized", isMaximized()); sg.setValue("window_parts_state", saveState()); sg.sync(); } inline QString accessTokenFileName(const QMatrixClient::AccountSettings& account) { QString fileName = account.userId(); fileName.replace(':', '_'); return QStandardPaths::writableLocation( #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) QStandardPaths::AppLocalDataLocation #else QStandardPaths::DataLocation #endif ) % '/' % fileName; } QByteArray MainWindow::loadAccessToken(const QMatrixClient::AccountSettings& account) { QFile accountTokenFile { accessTokenFileName(account) }; if (accountTokenFile.open(QFile::ReadOnly)) { if (accountTokenFile.size() < 1024) return accountTokenFile.readAll(); qWarning() << "File" << accountTokenFile.fileName() << "is" << accountTokenFile.size() << "bytes long - too long for a token, ignoring it."; } qWarning() << "Could not open access token file" << accountTokenFile.fileName(); return {}; } bool MainWindow::saveAccessToken(const QMatrixClient::AccountSettings& account, const QByteArray& accessToken) { // (Re-)Make a dedicated file for access_token. QFile accountTokenFile { accessTokenFileName(account) }; accountTokenFile.remove(); // Just in case auto fileDir = QFileInfo(accountTokenFile).dir(); if (!( (fileDir.exists() || fileDir.mkpath(".")) && accountTokenFile.open(QFile::WriteOnly) )) { QMessageBox::warning(this, tr("Couldn't open a file to save access token"), tr("Quaternion couldn't open a file to write the" " access token to. You're logged in but will have" " to provide your password again when you restart" " the application."), QMessageBox::Close); } else { // Try to restrict access rights to the file. The below is useless // on Windows: FAT doesn't control access at all and NTFS is // incompatible with the UNIX perms model used by Qt. If the attempt // didn't have the effect, at least ask the user if it's fine to save // the token to a file readable by others. // TODO: use system-specific API to ensure proper access. if ((accountTokenFile.setPermissions( QFile::ReadOwner|QFile::WriteOwner) && !(accountTokenFile.permissions() & (QFile::ReadGroup|QFile::ReadOther))) || QMessageBox::warning(this, tr("Couldn't set access token file permissions"), tr("Quaternion couldn't restrict permissions on the" " access token file. Do you still want to save" " the access token to it?"), QMessageBox::Yes|QMessageBox::No ) == QMessageBox::Yes) { accountTokenFile.write(accessToken); return true; } } return false; } void MainWindow::enableDebug() { chatRoomWidget->enableDebug(); } void MainWindow::addConnection(Connection* c, const QString& deviceName) { Q_ASSERT_X(c, __FUNCTION__, "Attempt to add a null connection"); connections.push_back(c); roomListDock->addConnection(c); connect( c, &Connection::syncDone, this, [=] { gotEvents(c); // Borrowed the logic from Quiark's code in Tensor to cache not too // aggressively and not on the first sync. The static variable instance // is created per-closure, meaning per-connection (which is why this // code is not in gotEvents() ). static int counter = 0; if (++counter % 17 == 2) c->saveState(); } ); connect( c, &Connection::loggedOut, this, [=] { statusBar()->showMessage(tr("Logged out as %1").arg(c->userId()), 3000); dropConnection(c); }); connect( c, &Connection::networkError, this, [=]{ networkError(c); } ); connect( c, &Connection::loginError, this, [=](const QString& msg){ loginError(c, msg); } ); connect( c, &Connection::newRoom, systemTray, &SystemTray::newRoom ); connect( c, &Connection::aboutToDeleteRoom, this, [this] (QMatrixClient::Room* r) { if (currentRoom == r) selectRoom(nullptr); }); const QString logoutCaption = deviceName.isEmpty() ? tr("Logout %1").arg(c->userId()) : tr("Logout %1/%2").arg(c->userId(), deviceName); const auto logoutAction = new QAction(logoutCaption, c); connectionMenu->insertAction(accountListGrowthPoint, logoutAction); connect( logoutAction, &QAction::triggered, this, [=]{ logout(c); } ); connect( c, &Connection::destroyed, this, [=] { connectionMenu->removeAction(logoutAction); } ); getNewEvents(c); } void MainWindow::dropConnection(Connection* c) { Q_ASSERT_X(c, __FUNCTION__, "Attempt to drop a null connection"); if (currentRoom && currentRoom->connection() == c) selectRoom(nullptr); connections.removeOne(c); #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) logoutOnExit.removeOne(c); #else const auto i = logoutOnExit.indexOf(c); if (i >= 0) logoutOnExit.remove(i); #endif Q_ASSERT(!connections.contains(c) && !logoutOnExit.contains(c) && !c->syncJob()); c->deleteLater(); } void MainWindow::showFirstSyncIndicator() { busyLabel->show(); busyIndicator->start(); statusBar()->showMessage("Syncing, please wait"); } void MainWindow::showLoginWindow(const QString& statusMessage) { LoginDialog dialog(this); dialog.setStatusMessage(statusMessage); if( dialog.exec() ) { auto connection = dialog.releaseConnection(); QMatrixClient::AccountSettings account(connection->userId()); account.setKeepLoggedIn(dialog.keepLoggedIn()); if (dialog.keepLoggedIn()) { account.setHomeserver(connection->homeserver()); account.setDeviceId(connection->deviceId()); account.setDeviceName(dialog.deviceName()); account.clearAccessToken(); // Drop the legacy - just in case if (!saveAccessToken(account, connection->accessToken())) qWarning() << "Couldn't save access token"; } else logoutOnExit.push_back(connection); account.sync(); showFirstSyncIndicator(); addConnection(connection, dialog.deviceName()); } } void MainWindow::invokeLogin() { using namespace QMatrixClient; SettingsGroup settings("Accounts"); bool autoLoggedIn = false; for(const auto& accountId: settings.childGroups()) { AccountSettings account { accountId }; if (!account.homeserver().isEmpty()) { auto accessToken = loadAccessToken(account); if (accessToken.isEmpty()) { // Try to look in the legacy location (QSettings) and if found, // migrate it from there to a file. accessToken = account.accessToken().toLatin1(); if (accessToken.isEmpty()) continue; // No access token anywhere, no autologin saveAccessToken(account, accessToken); account.clearAccessToken(); // Clean the old place } autoLoggedIn = true; auto c = new Connection(account.homeserver()); auto deviceName = account.deviceName(); connect(c, &Connection::connected, this, [=] { c->loadState(); addConnection(c, deviceName); }); c->connectWithToken(account.userId(), accessToken, account.deviceId()); } } if (autoLoggedIn) showFirstSyncIndicator(); else QTimer::singleShot(0, this, SLOT(showLoginWindow())); } void MainWindow::loginError(Connection* c, const QString& message) { Q_ASSERT_X(c, __FUNCTION__, "Login error on a null connection"); // FIXME: Make ConnectionManager instead of such hacks emit c->loggedOut(); // Short circuit login error to logged-out event showLoginWindow(message); } void MainWindow::logout(Connection* c) { Q_ASSERT_X(c, __FUNCTION__, "Logout on a null connection"); QMatrixClient::AccountSettings account { c->userId() }; QFile(accessTokenFileName(account)).remove(); c->logout(); } void MainWindow::selectRoom(QuaternionRoom* r) { currentRoom = r; setWindowTitle(r ? r->displayName() : QString()); chatRoomWidget->setRoom(r); userListDock->setRoom(r); } QMatrixClient::Connection* MainWindow::chooseConnection() { Connection* connection = nullptr; QStringList names; names.reserve(connections.size()); for (auto c: connections) names.push_back(c->userId()); const auto choice = QInputDialog::getItem(this, tr("Choose the account to join the room"), "", names, -1, false); if (choice.isEmpty()) return nullptr; for (auto c: connections) if (c->userId() == choice) { connection = c; break; } Q_ASSERT(connection); return connection; } void MainWindow::joinRoom(const QString& roomAlias, Connection* connection) { if (connections.isEmpty()) { QMessageBox::warning(this, tr("No connections"), tr("Please connect to a server before joining a room"), QMessageBox::Close, QMessageBox::Close); return; } if (!connection) { if (currentRoom && !roomAlias.isEmpty()) { connection = currentRoom->connection(); if (connections.size() > 1) { // Double check the user intention QMessageBox confirmBox(QMessageBox::Question, tr("Joining %1 as %2").arg(roomAlias, connection->userId()), tr("Join room %1 under account %2?") .arg(roomAlias, connection->userId()), QMessageBox::Ok|QMessageBox::Cancel, this); confirmBox.setButtonText(QMessageBox::Ok, tr("Join")); auto* chooseAccountButton = confirmBox.addButton(tr("Choose account..."), QMessageBox::ActionRole); if (confirmBox.exec() == QMessageBox::Cancel) return; if (confirmBox.clickedButton() == chooseAccountButton) connection = chooseConnection(); } } else connection = connections.size() == 1 ? connections.front() : chooseConnection(); } if (!connection) return; // No default connection and the user discarded the dialog QString room = roomAlias; while (room.isEmpty()) { QInputDialog roomInput (this); roomInput.setWindowTitle(tr("Enter room id or alias to join")); roomInput.setLabelText( tr("Enter an id or alias of the room. You will join as %1") .arg(connection->userId())); roomInput.setOkButtonText(tr("Join")); roomInput.setSizeGripEnabled(true); // TODO: Provide a button to select the joining account if (roomInput.exec() == QDialog::Rejected) return; // TODO: Check validity, not only non-emptyness if (!roomInput.textValue().isEmpty()) room = roomInput.textValue(); else QMessageBox::warning(this, tr("No room id or alias specified"), tr("Please specify non-empty id or alias"), QMessageBox::Close, QMessageBox::Close); } using QMatrixClient::JoinRoomJob; auto job = connection->joinRoom(room); // Connection::joinRoom() already connected to success() the code that // initialises the room in the library, which in turn causes RoomListModel // to update the room list. So the below connection to success() will be // triggered after all the initialisation have happened. connect(job, &JoinRoomJob::success, this, [=] { statusBar()->showMessage(tr("Joined %1 as %2") .arg(roomAlias, connection->userId())); }); connect(job, &JoinRoomJob::failure, this, [=] { QMessageBox messageBox(QMessageBox::Warning, tr("Failed to join room"), tr("Joining request returned an error"), QMessageBox::Close, this); messageBox.setWindowModality(Qt::WindowModal); messageBox.setTextFormat(Qt::PlainText); messageBox.setDetailedText(job->errorString()); switch (job->error()) { case JoinRoomJob::NotFoundError: messageBox.setText( tr("Room %1 not found on the server").arg(roomAlias)); break; case JoinRoomJob::IncorrectRequestError: messageBox.setText( tr("Incorrect id or alias: %1").arg(roomAlias)); break; default: messageBox.setText(tr("Error joining %1: %2")); } messageBox.exec(); }); } void MainWindow::getNewEvents(Connection* c) { Q_ASSERT_X(c, __FUNCTION__, "Attempt to sync on null connection"); c->sync(30*1000); } void MainWindow::gotEvents(Connection* c) { Q_ASSERT_X(c, __FUNCTION__, "Null connection"); if( busyLabel->isVisible() ) { busyLabel->hide(); busyIndicator->stop(); statusBar()->showMessage(tr("Sync completed - have a good chat"), 3000); } getNewEvents(c); } void MainWindow::showMillisToRecon(Connection* c) { // TODO: when there are several connections and they are failing, these // notifications render a mess, fighting for the same status bar. Either // switch to a set of icons in the status bar or find a stacking // notifications engine already instead of the status bar. statusBar()->showMessage( tr("Couldn't connect to the server as %1; will retry within %2 seconds") .arg(c->userId()).arg((c->millisToReconnect() + 999) / 1000)); // Integer ceiling } void MainWindow::networkError(Connection* c) { Q_ASSERT_X(c, __FUNCTION__, "Network error on a null connection"); auto timer = new QTimer(this); timer->start(1000); showMillisToRecon(c); timer->connect(timer, &QTimer::timeout, [=] { if (c->millisToReconnect() > 0) showMillisToRecon(c); else { statusBar()->showMessage(tr("Reconnecting..."), 5000); timer->deleteLater(); } }); } void MainWindow::closeEvent(QCloseEvent* event) { for (auto c: connections) { c->saveState(); c->stopSync(); // Instead of deleting the connection, merely stop it // dropConnection(c); } for (auto c: logoutOnExit) c->logout(); // For the record, dropConnection() does it automatically saveSettings(); event->accept(); } Quaternion-0.0.5/client/mainwindow.h000066400000000000000000000071021321710324500174420ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class Connection; class AccountSettings; } class RoomListDock; class UserListDock; class ChatRoomWidget; class SystemTray; class QuaternionRoom; class QAction; class QMenu; class QMenuBar; class QSystemTrayIcon; class QMovie; class QLabel; class MainWindow: public QMainWindow { Q_OBJECT public: using Connection = QMatrixClient::Connection; MainWindow(); void enableDebug(); void addConnection(Connection* c, const QString& deviceName); void dropConnection(Connection* c); ChatRoomWidget* getChatRoomWidget() const; protected: void closeEvent(QCloseEvent* event) override; private slots: void invokeLogin(); void joinRoom(const QString& roomAlias = {}, Connection* connection = nullptr); void getNewEvents(Connection* c); void gotEvents(Connection* c); void loginError(Connection* c, const QString& message = {}); void networkError(Connection* c); void showLoginWindow(const QString& statusMessage = {}); void selectRoom(QuaternionRoom* r); void logout(Connection* c); private: QList connections; QVector logoutOnExit; RoomListDock* roomListDock = nullptr; UserListDock* userListDock = nullptr; ChatRoomWidget* chatRoomWidget = nullptr; QMovie* busyIndicator = nullptr; QLabel* busyLabel = nullptr; QMenu* connectionMenu = nullptr; QAction* accountListGrowthPoint = nullptr; SystemTray* systemTray = nullptr; // FIXME: This will be a problem when we get ability to show // several rooms at once. QuaternionRoom* currentRoom = nullptr; void createMenu(); void showFirstSyncIndicator(); void loadSettings(); void saveSettings() const; QByteArray loadAccessToken(const QMatrixClient::AccountSettings& account); bool saveAccessToken(const QMatrixClient::AccountSettings& account, const QByteArray& accessToken); Connection* chooseConnection(); void showMillisToRecon(Connection* c); }; Quaternion-0.0.5/client/message.cpp000066400000000000000000000047621321710324500172560ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "message.h" #include "lib/events/roommessageevent.h" #include "lib/user.h" #include "lib/connection.h" #include "lib/room.h" Message::Message(const QMatrixClient::RoomEvent* event, const QMatrixClient::Room* room) : m_event(event) { Q_ASSERT(event); using namespace QMatrixClient; if( event->type() == EventType::RoomMessage ) { m_isStatusMessage = false; Q_ASSERT(room); auto* msgEvent = static_cast(event); User* localUser = room->localUser(); // Only highlight messages from other users m_isHighlight = msgEvent->senderId() != localUser->id() && (msgEvent->plainBody().contains(localUser->id()) || msgEvent->plainBody().contains(room->roomMembername(localUser)) ); } } const QMatrixClient::RoomEvent* Message::messageEvent() const { return m_event; } bool Message::highlight() const { return m_isHighlight; } bool Message::isStatusMessage() const { return m_isStatusMessage; } void Message::setEvent(const QMatrixClient::RoomEvent* newEvent) { Q_ASSERT(newEvent); m_event = newEvent; } Quaternion-0.0.5/client/message.h000066400000000000000000000037631321710324500167230ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class RoomEvent; class Room; } class Message { public: Message() = default; Message(const QMatrixClient::RoomEvent* event, const QMatrixClient::Room* room); const QMatrixClient::RoomEvent* messageEvent() const; void setEvent(const QMatrixClient::RoomEvent* newEvent); bool highlight() const; bool isStatusMessage() const; private: const QMatrixClient::RoomEvent* m_event = nullptr; bool m_isHighlight = false; bool m_isStatusMessage = true; }; Q_DECLARE_TYPEINFO(Message, Q_MOVABLE_TYPE); Quaternion-0.0.5/client/models/000077500000000000000000000000001321710324500164005ustar00rootroot00000000000000Quaternion-0.0.5/client/models/messageeventmodel.cpp000066400000000000000000000350631321710324500226220ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "messageeventmodel.h" #include #include #include "../quaternionroom.h" #include "lib/connection.h" #include "lib/user.h" #include "lib/events/roommemberevent.h" #include "lib/events/simplestateevents.h" #include "lib/events/redactionevent.h" enum EventRoles { EventTypeRole = Qt::UserRole + 1, EventIdRole, TimeRole, SectionRole, AuthorRole, ContentRole, ContentTypeRole, HighlightRole, RedactedRole, }; QHash MessageEventModel::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); roles[EventTypeRole] = "eventType"; roles[EventIdRole] = "eventId"; roles[TimeRole] = "time"; roles[SectionRole] = "section"; roles[AuthorRole] = "author"; roles[ContentRole] = "content"; roles[ContentTypeRole] = "contentType"; roles[HighlightRole] = "highlight"; roles[RedactedRole] = "redacted"; return roles; } MessageEventModel::MessageEventModel(QObject* parent) : QAbstractListModel(parent) , m_currentRoom(nullptr) { } void MessageEventModel::changeRoom(QuaternionRoom* room) { if (room == m_currentRoom) return; beginResetModel(); if( m_currentRoom ) { m_currentRoom->disconnect( this ); qDebug() << "Disconnected from" << m_currentRoom->id(); } m_currentRoom = room; if( room ) { using namespace QMatrixClient; connect(m_currentRoom, &Room::aboutToAddNewMessages, this, [=](RoomEventsRange events) { beginInsertRows(QModelIndex(), rowCount(), rowCount() + int(events.size()) - 1); }); connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, [=](RoomEventsRange events) { beginInsertRows(QModelIndex(), 0, int(events.size()) - 1); }); connect(m_currentRoom, &Room::addedMessages, this, &MessageEventModel::endInsertRows); connect(m_currentRoom, &Room::replacedEvent, this, &MessageEventModel::refreshEvent); qDebug() << "Connected to room" << room->id() << "as" << room->connection()->userId(); } endResetModel(); } void MessageEventModel::refreshEvent(const QMatrixClient::RoomEvent* event) { // FIXME: Avoid repetetive searching in QuaternionRoom and here. // The right way will be to get rid of QuaternionRoom altogether. const auto it = std::find_if( m_currentRoom->messages().begin(), m_currentRoom->messages().end(), [=](const Message& m) { return m.messageEvent() == event; }); if (it == m_currentRoom->messages().end()) return; const auto row = it - m_currentRoom->messages().begin(); emit dataChanged(index(row), index(row)); } QDateTime MessageEventModel::makeMessageTimestamp(int baseIndex) const { Q_ASSERT(m_currentRoom && baseIndex >= 0 && baseIndex < m_currentRoom->messages().count()); const auto& messages = m_currentRoom->messages(); auto ts = messages[baseIndex].messageEvent()->timestamp(); if (ts.isValid()) return ts; // The event is most likely redacted or just invalid. // Look for the nearest date around and slap zero time to it. #if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) using rev_iter_t = std::reverse_iterator; for (auto it = rev_iter_t(messages.begin()); it != rev_iter_t(messages.begin()); ++it) #else for (auto it = messages.rend() - baseIndex; it != messages.rend(); ++it) #endif { ts = it->messageEvent()->timestamp(); if (ts.isValid()) return { ts.date(), {0,0}, Qt::LocalTime }; } for (auto it = messages.begin() + baseIndex + 1; it != messages.end(); ++it) { ts = it->messageEvent()->timestamp(); if (ts.isValid()) return { ts.date(), {0,0}, Qt::LocalTime }; } // What kind of room is that?.. qCritical() << "No valid timestamps in the room timeline!"; return {}; } int MessageEventModel::rowCount(const QModelIndex& parent) const { if( !m_currentRoom || parent.isValid() ) return 0; return m_currentRoom->messages().count(); } QVariant MessageEventModel::data(const QModelIndex& index, int role) const { using namespace QMatrixClient; if( !m_currentRoom || index.row() < 0 || index.row() >= m_currentRoom->messages().count()) return QVariant(); const Message& message = m_currentRoom->messages().at(index.row());; auto* event = message.messageEvent(); // FIXME: Rewind to the name that was right before this event QString senderName = m_currentRoom->roomMembername(event->senderId()); if( role == Qt::DisplayRole ) { if( event->type() == EventType::RoomMessage ) { auto* e = static_cast(event); return QString("%1: %2").arg(senderName, e->plainBody()); } if( event->type() == EventType::RoomMember ) { auto* e = static_cast(event); switch( e->membership() ) { case MembershipType::Join: return QString("%1 (%2) joined the room").arg(e->displayName(), e->userId()); case MembershipType::Leave: return QString("%1 (%2) left the room").arg(e->displayName(), e->userId()); case MembershipType::Ban: return QString("%1 (%2) was banned from the room").arg(e->displayName(), e->userId()); case MembershipType::Invite: return QString("%1 (%2) was invited to the room").arg(e->displayName(), e->userId()); case MembershipType::Knock: return QString("%1 (%2) knocked").arg(e->displayName(), e->userId()); } } if( event->type() == EventType::RoomAliases ) { auto* e = static_cast(event); return QString("Current aliases: %1").arg(e->aliases().join(", ")); } return "Unknown Event"; } if( role == Qt::ToolTipRole ) { return event->originalJson(); } if( role == EventTypeRole ) { if (event->isStateEvent()) return "state"; if (event->type() == EventType::RoomMessage) { switch (static_cast(event)->msgtype()) { case MessageEventType::Image: return "image"; case MessageEventType::Emote: return "emote"; case MessageEventType::Notice: return "notice"; default: return "message"; } } return "other"; } if( role == TimeRole ) return makeMessageTimestamp(index.row()); if( role == SectionRole ) return makeMessageTimestamp(index.row()).toLocalTime().date(); if( role == AuthorRole ) { // FIXME: This will go away after senderName is generated correctly // (see the FIXME in the beginning of the method). if (event->type() == EventType::RoomMember) { const auto* e = static_cast(event); if (e->prev_content() && !e->prev_content()->displayName.isEmpty() && e->displayName() != e->prev_content()->displayName) return e->prev_content()->displayName; } return senderName; } if (role == ContentTypeRole) { if (event->type() == EventType::RoomMessage) { const auto& contentType = static_cast(event)->mimeType().name(); return contentType == "text/plain" ? "text/html" : contentType; } return "text/plain"; } if (role == ContentRole) { if (event->isRedacted()) { auto reason = event->redactedBecause()->reason(); if (reason.isEmpty()) return tr("Redacted"); else return tr("Redacted: %1") .arg(event->redactedBecause()->reason()); } if( event->type() == EventType::RoomMessage ) { using namespace MessageEventContent; auto* e = static_cast(event); switch (e->msgtype()) { case MessageEventType::Emote: case MessageEventType::Text: case MessageEventType::Notice: { if (e->mimeType().name() == "text/plain") return m_currentRoom->prettyPrint(e->plainBody()); return static_cast(e->content())->body; } case MessageEventType::Image: { auto content = static_cast(e->content()); return QUrl("image://mtx/" + content->url.host() + content->url.path()); } default: return e->plainBody(); } } if( event->type() == EventType::RoomMember ) { auto* e = static_cast(event); // FIXME: Rewind to the name that was at the time of this event QString subjectName = m_currentRoom->roomMembername(e->userId()); // The below code assumes senderName output in AuthorRole switch( e->membership() ) { case MembershipType::Invite: case MembershipType::Join: { if (!e->prev_content() || e->membership() != e->prev_content()->membership) { return e->membership() == MembershipType::Invite ? tr("invited %1 to the room").arg(subjectName) : tr("joined the room"); } QString text {}; if (e->displayName() != e->prev_content()->displayName) { if (e->displayName().isEmpty()) text = tr("cleared the display name"); else text = tr("changed the display name to %1") .arg(e->displayName()); } if (e->avatarUrl() != e->prev_content()->avatarUrl) { if (!text.isEmpty()) text += " and "; if (e->avatarUrl().isEmpty()) text += tr("cleared the avatar"); else text += tr("updated the avatar"); } return text; } case MembershipType::Leave: if (e->senderId() != e->userId()) return tr("doesn't want %1 in the room anymore").arg(subjectName); else return tr("left the room"); case MembershipType::Ban: if (e->senderId() != e->userId()) return tr("banned %1 from the room").arg(subjectName); else return tr("self-banned from the room"); case MembershipType::Knock: return tr("knocked"); } } if( event->type() == EventType::RoomAliases ) { auto* e = static_cast(event); return tr("set aliases to: %1").arg(e->aliases().join(", ")); } if( event->type() == EventType::RoomCanonicalAlias ) { auto* e = static_cast(event); return tr("set the room main alias to: %1").arg(e->alias()); } if( event->type() == EventType::RoomName ) { auto* e = static_cast(event); return tr("set the room name to: %1").arg(e->name()); } if( event->type() == EventType::RoomTopic ) { auto* e = static_cast(event); return tr("set the topic to: %1").arg(e->topic()); } if( event->type() == EventType::RoomAvatar ) { return tr("changed the room avatar"); } if( event->type() == EventType::RoomEncryption ) { auto* e = static_cast(event); return tr("activated End-to-End Encryption (algorithm: %1)") .arg(e->algorithm()); } return "Unknown Event"; } if( role == HighlightRole ) { return message.highlight(); } if( role == RedactedRole ) return message.messageEvent()->isRedacted(); if( role == Qt::DecorationRole ) { if (message.highlight()) { return QSettings().value("UI/highlight_color", "orange"); } } if( role == EventIdRole ) { return event->id(); } return QVariant(); } Quaternion-0.0.5/client/models/messageeventmodel.h000066400000000000000000000047551321710324500222730ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class RoomEvent; } class QuaternionRoom; class MessageEventModel: public QAbstractListModel { Q_OBJECT // The below property is marked constant because it only changes // when the whole model is reset (so anything that depends on the model // has to be re-calculated anyway). // XXX: A better way would be to make [Room::]Timeline a list model // itself, leaving only representation of the model to a client. Q_PROPERTY(QuaternionRoom* room MEMBER m_currentRoom CONSTANT) public: explicit MessageEventModel(QObject* parent = nullptr); void changeRoom(QuaternionRoom* room); int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QHash roleNames() const override; private slots: void refreshEvent(const QMatrixClient::RoomEvent* event); private: QuaternionRoom* m_currentRoom; QDateTime makeMessageTimestamp(int baseIndex) const; }; Quaternion-0.0.5/client/models/roomlistmodel.cpp000066400000000000000000000202211321710324500217720ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "roomlistmodel.h" #include "../quaternionroom.h" #include "lib/connection.h" #include RoomListModel::RoomListModel(QObject* parent) : QAbstractListModel(parent) { } void RoomListModel::addConnection(Connection* connection) { Q_ASSERT(connection); using QMatrixClient::Room; beginResetModel(); m_connections.push_back(connection); connect( connection, &Connection::loggedOut, this, [=]{ deleteConnection(connection); } ); connect( connection, &Connection::invitedRoom, this, &RoomListModel::updateRoom); connect( connection, &Connection::joinedRoom, this, &RoomListModel::updateRoom); connect( connection, &Connection::leftRoom, this, &RoomListModel::updateRoom); connect( connection, &Connection::aboutToDeleteRoom, this, &RoomListModel::deleteRoom); for( auto r: connection->roomMap() ) doAddRoom(r); endResetModel(); } void RoomListModel::deleteConnection(Connection* connection) { Q_ASSERT(connection); // TODO: Save selection beginResetModel(); connection->disconnect(this); for( QuaternionRoom* room: m_rooms ) room->disconnect( this ); m_rooms.erase( std::remove_if(m_rooms.begin(), m_rooms.end(), [=](const QuaternionRoom* r) { return r->connection() == connection; }), m_rooms.end()); endResetModel(); // TODO: Restore selection } QuaternionRoom* RoomListModel::roomAt(int row) { return m_rooms.at(row); } void RoomListModel::updateRoom(QMatrixClient::Room* room, QMatrixClient::Room* prev) { // There are two cases when this method is called: // 1. (prev == nullptr) adding a new room to the room list // 2. (prev != nullptr) accepting/rejecting an invitation or inviting to // the previously left room (in both cases prev has the previous state). if (prev == room) { qCritical() << "RoomListModel::updateRoom: room tried to replace itself"; refresh(static_cast(room)); return; } if (prev && room->id() != prev->id()) { qCritical() << "RoomListModel::updateRoom: attempt to update room" << room->id() << "to" << prev->id(); // That doesn't look right but technically we still can do it. } // Ok, we're through with pre-checks, now for the real thing. auto* newRoom = static_cast(room); const auto it = std::find_if(m_rooms.begin(), m_rooms.end(), [=](const QuaternionRoom* r) { return r == prev || r == newRoom; }); if (it != m_rooms.end()) { const int row = it - m_rooms.begin(); // There's no guarantee that prev != newRoom if (*it == prev && *it != newRoom) { prev->disconnect(this); m_rooms.replace(row, newRoom); connectRoomSignals(newRoom); } emit dataChanged(index(row), index(row)); } else { beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count()); doAddRoom(newRoom); endInsertRows(); } } void RoomListModel::deleteRoom(QMatrixClient::Room* room) { auto i = m_rooms.indexOf(static_cast(room)); if (i == -1) return; // Already deleted, nothing to do beginRemoveRows(QModelIndex(), i, i); m_rooms.removeAt(i); endRemoveRows(); } void RoomListModel::doAddRoom(QMatrixClient::Room* r) { auto* room = static_cast(r); m_rooms.append(room); connectRoomSignals(room); } void RoomListModel::connectRoomSignals(QuaternionRoom* room) { connect(room, &QuaternionRoom::displaynameChanged, this, [=]{ displaynameChanged(room); } ); connect( room, &QuaternionRoom::unreadMessagesChanged, this, [=]{ unreadMessagesChanged(room); } ); connect( room, &QuaternionRoom::notificationCountChanged, this, [=]{ unreadMessagesChanged(room); } ); connect( room, &QuaternionRoom::joinStateChanged, this, [=]{ refresh(room); }); connect( room, &QuaternionRoom::avatarChanged, this, [=]{ refresh(room, { Qt::DecorationRole }); }); } int RoomListModel::rowCount(const QModelIndex& parent) const { if( parent.isValid() ) return 0; return m_rooms.count(); } QVariant RoomListModel::data(const QModelIndex& index, int role) const { if( !index.isValid() ) return QVariant(); if( index.row() >= m_rooms.count() ) { qDebug() << "UserListModel: something wrong here..."; return QVariant(); } auto room = m_rooms.at(index.row()); switch (role) { case Qt::DisplayRole: return room->displayName(); case Qt::DecorationRole: { auto avatar = room->avatar(16, 16); if (!avatar.isNull()) return avatar; switch( room->joinState() ) { case QMatrixClient::JoinState::Join: return QIcon(":/irc-channel-joined.svg"); case QMatrixClient::JoinState::Invite: return QIcon(":/irc-channel-invited.svg"); case QMatrixClient::JoinState::Leave: return QIcon(":/irc-channel-parted.svg"); } } case Qt::ToolTipRole: { auto result = QStringLiteral("%1
").arg(room->canonicalAlias()); result += tr("Room members: %1
").arg(room->memberCount()); if (room->highlightCount() > 0) result += tr("Unread mentions: %1
").arg(room->highlightCount()); result += tr("Room ID: %1
").arg(room->id()); if( room->joinState() == QMatrixClient::JoinState::Join ) result += tr("You joined this room"); else if( room->joinState() == QMatrixClient::JoinState::Leave ) result += tr("You left this room"); else result += tr("You were invited into this room"); return result; } case HasUnreadRole: return room->hasUnreadMessages(); case HighlightCountRole: return room->highlightCount(); case JoinStateRole: return toCString(room->joinState()); // FIXME: better make the enum QVariant-convertible default: return QVariant(); } } void RoomListModel::displaynameChanged(QuaternionRoom* room) { refresh(room); } void RoomListModel::unreadMessagesChanged(QuaternionRoom* room) { refresh(room); } void RoomListModel::refresh(QuaternionRoom* room, const QVector& roles) { int row = m_rooms.indexOf(room); if (row == -1) qCritical() << "Room" << room->id() << "not found in the room list"; else emit dataChanged(index(row), index(row), roles); } Quaternion-0.0.5/client/models/roomlistmodel.h000066400000000000000000000051741321710324500214510ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class Connection; class Room; } class QuaternionRoom; class RoomListModel: public QAbstractListModel { Q_OBJECT using Connection = QMatrixClient::Connection; public: enum Roles { HasUnreadRole = Qt::UserRole + 1, HighlightCountRole, JoinStateRole }; explicit RoomListModel(QObject* parent = nullptr); void addConnection(Connection* connection); void deleteConnection(Connection* connection); QuaternionRoom* roomAt(int row); QVariant data(const QModelIndex& index, int role) const override; int rowCount(const QModelIndex& parent) const override; private slots: void displaynameChanged(QuaternionRoom* room); void unreadMessagesChanged(QuaternionRoom* room); void refresh(QuaternionRoom* room, const QVector& roles = {}); void updateRoom(QMatrixClient::Room* room, QMatrixClient::Room* prev); void deleteRoom(QMatrixClient::Room* room); private: QList m_connections; QList m_rooms; void doAddRoom(QMatrixClient::Room* r); void connectRoomSignals(QuaternionRoom* room); }; Quaternion-0.0.5/client/models/userlistmodel.cpp000066400000000000000000000115731321710324500220060ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "userlistmodel.h" #include #include #include "lib/connection.h" #include "lib/room.h" #include "lib/user.h" UserListModel::UserListModel(QObject* parent) : QAbstractListModel(parent) { m_currentRoom = nullptr; } UserListModel::~UserListModel() { } void UserListModel::setRoom(QMatrixClient::Room* room) { if (m_currentRoom == room) return; using namespace QMatrixClient; beginResetModel(); if( m_currentRoom ) { m_currentRoom->connection()->disconnect( this ); m_currentRoom->disconnect( this ); for( User* user: m_users ) user->disconnect( this ); m_users.clear(); } m_currentRoom = room; if( m_currentRoom ) { connect( m_currentRoom, &Room::userAdded, this, &UserListModel::userAdded ); connect( m_currentRoom, &Room::userRemoved, this, &UserListModel::userRemoved ); connect( m_currentRoom, &Room::memberRenamed, this, &UserListModel::memberRenamed ); m_users = m_currentRoom->users(); std::sort(m_users.begin(), m_users.end(), room->memberSorter()); for( User* user: m_users ) { connect( user, &User::avatarChanged, this, &UserListModel::avatarChanged ); } connect( m_currentRoom->connection(), &Connection::loggedOut, this, [=] { setRoom(nullptr); } ); qDebug() << m_users.count() << "user(s) in the room"; } endResetModel(); } QVariant UserListModel::data(const QModelIndex& index, int role) const { if( !index.isValid() ) return QVariant(); if( index.row() >= m_users.count() ) { qDebug() << "UserListModel, something's wrong: index.row() >= m_users.count()"; return QVariant(); } QMatrixClient::User* user = m_users.at(index.row()); if( role == Qt::DisplayRole ) { return m_currentRoom->roomMembername(user); } if( role == Qt::DecorationRole ) { return user->avatar(25,25); } if (role == Qt::ToolTipRole) { return QStringLiteral("%1
%2").arg(user->name(), user->id()); } return QVariant(); } int UserListModel::rowCount(const QModelIndex& parent) const { if( parent.isValid() ) return 0; return m_users.count(); } void UserListModel::userAdded(QMatrixClient::User* user) { auto pos = findUserPos(user); beginInsertRows(QModelIndex(), pos, pos); m_users.insert(pos, user); endInsertRows(); connect( user, &QMatrixClient::User::avatarChanged, this, &UserListModel::avatarChanged ); } void UserListModel::userRemoved(QMatrixClient::User* user) { auto pos = findUserPos(user); if (pos != m_users.size()) { beginRemoveRows(QModelIndex(), pos, pos); m_users.removeAt(pos); endRemoveRows(); user->disconnect(this); } else qWarning() << "Trying to remove a room member not in the user list"; } void UserListModel::refresh(QMatrixClient::User* user, QVector roles) { auto pos = findUserPos(user); if ( pos != m_users.size() ) emit dataChanged(index(pos), index(pos), roles); else qWarning() << "Trying to access a room member not in the user list"; } void UserListModel::memberRenamed(QMatrixClient::User *user) { refresh(user, {Qt::DisplayRole}); } void UserListModel::avatarChanged(QMatrixClient::User* user) { refresh(user, {Qt::DecorationRole}); } int UserListModel::findUserPos(QMatrixClient::User* user) const { return m_currentRoom->memberSorter().lowerBoundIndex(m_users, user); } Quaternion-0.0.5/client/models/userlistmodel.h000066400000000000000000000044651321710324500214550ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class Connection; class Room; class User; } class UserListModel: public QAbstractListModel { Q_OBJECT public: UserListModel(QObject* parent = nullptr); virtual ~UserListModel(); void setRoom(QMatrixClient::Room* room); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex& parent=QModelIndex()) const override; private slots: void userAdded(QMatrixClient::User* user); void userRemoved(QMatrixClient::User* user); void refresh(QMatrixClient::User* user, QVector roles = {}); void memberRenamed(QMatrixClient::User* user); void avatarChanged(QMatrixClient::User* user); private: QMatrixClient::Room* m_currentRoom; QList m_users; int findUserPos(QMatrixClient::User* user) const; }; Quaternion-0.0.5/client/qml/000077500000000000000000000000001321710324500157065ustar00rootroot00000000000000Quaternion-0.0.5/client/qml/ToolTip.qml000066400000000000000000000021161321710324500200130ustar00rootroot00000000000000import QtQuick 2.0 Rectangle { id:tooltip property alias text: textContainer.text property int verticalPadding: 1 property int horizontalPadding: 5 property Item zParent: parent width: textContainer.width + horizontalPadding * 2 height: textContainer.height + verticalPadding * 2 color: "#aa999999" Text { anchors.centerIn: parent id:textContainer text: "Gering geding ding ding!" } NumberAnimation { id: fadein target: tooltip property: "opacity" easing.type: Easing.InOutQuad duration: 300 from: 0 to: 1 } NumberAnimation { id: fadeout target: tooltip property: "opacity" easing.type: Easing.InOutQuad from: 1 to: 0 onStopped: visible = false; } visible:false onVisibleChanged: if(visible)fadein.start(); function show(){ visible = true; zParent.z = 20; fadein.start(); } function hide(){ this.parent.parent.parent.z = 0; fadeout.start(); } } Quaternion-0.0.5/client/qml/ToolTipArea.qml000066400000000000000000000013471321710324500206110ustar00rootroot00000000000000// from https://github.com/bobbaluba/qmltooltip import QtQuick 2.0 MouseArea { property alias tip: tip property alias text: tip.text property alias hideDelay: hideTimer.interval property alias showDelay: showTimer.interval property bool enabled: true id: mouseArea z: 21 acceptedButtons: Qt.NoButton anchors.fill: parent hoverEnabled: true Timer { id:showTimer interval: 1000 running: mouseArea.containsMouse && !tip.visible && mouseArea.enabled onTriggered: tip.show(); } Timer { id:hideTimer interval: 100 running: !mouseArea.containsMouse && tip.visible onTriggered: tip.hide(); } ToolTip{ id:tip } } Quaternion-0.0.5/client/qml/chat.qml000066400000000000000000000364051321710324500173500ustar00rootroot00000000000000import QtQuick 2.2 import QtQuick.Controls 1.0 import QtQuick.Controls.Styles 1.0 import QtQuick.Layouts 1.1 import QMatrixClient 1.0 Rectangle { id: root Settings { id: settings property bool condense_chat: value("UI/condense_chat", false) } SystemPalette { id: defaultPalette; colorGroup: SystemPalette.Active } SystemPalette { id: disabledPalette; colorGroup: SystemPalette.Disabled } Timer { id: scrollTimer interval: 0 onTriggered: reallyScrollToBottom() } color: defaultPalette.base function reallyScrollToBottom() { if (chatView.stickToBottom && !chatView.nowAtYEnd) { chatView.positionViewAtEnd() scrollToBottom() } } function scrollToBottom() { chatView.stickToBottom = true scrollTimer.running = true } ListView { id: chatView anchors.fill: parent model: messageModel delegate: messageDelegate flickableDirection: Flickable.VerticalFlick flickDeceleration: 9001 boundsBehavior: Flickable.StopAtBounds pixelAligned: true // FIXME: atYEnd is glitchy on Qt 5.2.1 property bool nowAtYEnd: contentY - originY + height >= contentHeight property bool stickToBottom: true function ensurePreviousContent() { // Check whether we're about to bump into the ceiling in 2 seconds var curVelocity = verticalVelocity // Snapshot the current speed if( curVelocity < 0 && contentY + curVelocity*2 < originY) { // Request the amount of messages enough to scroll at this // rate for 3 more seconds var avgHeight = contentHeight / count model.room.getPreviousContent(-curVelocity*3 / avgHeight); } } function onModelAboutToReset() { contentYChanged.disconnect(ensurePreviousContent) console.log("Chat: getPreviousContent disabled") } function onModelReset() { if (model.room) { if (contentHeight <= height) model.room.getPreviousContent(100) contentYChanged.connect(ensurePreviousContent) console.log("Chat: getPreviousContent enabled") } } function rowsInserted() { if( stickToBottom ) root.scrollToBottom() } Component.onCompleted: { console.log("onCompleted") model.modelAboutToBeReset.connect(onModelAboutToReset) model.modelReset.connect(onModelReset) model.rowsInserted.connect(rowsInserted) } section { property: "section" labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart delegate: Rectangle { width: root.width height: childrenRect.height color: defaultPalette.window Label { text: section.toLocaleString("dd.MM.yyyy") } } } onHeightChanged: { if( stickToBottom ) root.scrollToBottom() } onContentHeightChanged: { if( stickToBottom ) root.scrollToBottom() } onMovementStarted: { stickToBottom = false } onMovementEnded: { stickToBottom = nowAtYEnd } } Slider { id: chatViewScroller orientation: Qt.Vertical anchors.right: chatView.right anchors.verticalCenter: chatView.verticalCenter style: SliderStyle { // Width and height are swapped below because SliderStyle assumes // a horizontal slider groove: Rectangle { implicitHeight: 3 implicitWidth: chatView.height / 2 anchors.horizontalCenter: parent.horizontalCenter color: defaultPalette.highlight radius: 3 } handle: Rectangle { anchors.centerIn: parent color: defaultPalette.button border.color: defaultPalette.buttonText border.width: 1 implicitWidth: 21 implicitHeight: 9 radius: 9 } } maximumValue: 10.0 minimumValue: -10.0 activeFocusOnPress: false activeFocusOnTab: false MouseArea { anchors.fill: parent acceptedButtons: Qt.NoButton onWheel: { } // Disable wheel on the slider } onPressedChanged: { if (pressed) chatView.stickToBottom = false else value = 0 } onValueChanged: { if (value) chatView.flick(0, chatView.height * value) } Component.onCompleted: { // This will cause continuous scrolling while the scroller is out of 0 chatView.flickEnded.connect(chatViewScroller.valueChanged) } } Component { id: messageDelegate Rectangle { color: defaultPalette.base width: root.width - chatViewScroller.width height: childrenRect.height // A message is considered shown if its bottom is within the // viewing area of the timeline. property bool shown: y + message.height - 1 > chatView.contentY && y + message.height - 1 < chatView.contentY + chatView.height Component.onCompleted: { if (shown) shownChanged(true); } onShownChanged: controller.onMessageShownChanged(eventId, shown) RowLayout { id: message width: parent.width spacing: 3 property string textColor: if (redacted) disabledPalette.text else if (highlight) decoration else if (["state", "notice", "other"] .indexOf(eventType) >= 0) disabledPalette.text else defaultPalette.text Label { Layout.alignment: Qt.AlignTop id: timelabel text: "<" + time.toLocaleTimeString(Qt.locale(), Locale.ShortFormat) + ">" color: disabledPalette.text } Label { Layout.alignment: Qt.AlignTop | Qt.AlignLeft Layout.preferredWidth: 120 elide: Text.ElideRight text: eventType == "state" || eventType == "emote" ? "* " + author : eventType != "other" ? author : "***" horizontalAlignment: if( ["other", "emote", "state"] .indexOf(eventType) >= 0 ) { Text.AlignRight } color: message.textColor } Rectangle { id: contentRect color: defaultPalette.base Layout.fillWidth: true Layout.minimumHeight: childrenRect.height Layout.alignment: Qt.AlignTop | Qt.AlignLeft Column { spacing: 0 width: parent.width TextEdit { id: contentField selectByMouse: true; readOnly: true; font: timelabel.font textFormat: contentType == "text/html" ? TextEdit.RichText : TextEdit.PlainText text: eventType != "image" ? content : "" height: eventType != "image" ? implicitHeight : 0 wrapMode: Text.Wrap; width: parent.width color: message.textColor MouseArea { anchors.fill: parent cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor acceptedButtons: Qt.NoButton } // TODO: In the code below, links should be resolved // with Qt.resolvedLink, once we figure out what // to do with relative URLs (note: www.google.com // is a relative URL, https://www.google.com is not). // Instead of Qt.resolvedUrl (and, most likely, // QQmlAbstractUrlInterceptor to convert URLs) // we might just prefer to do the whole resolving // in C++. onHoveredLinkChanged: controller.showStatusMessage(hoveredLink) onLinkActivated: { Qt.openUrlExternally(link) } } Image { id: imageField fillMode: Image.PreserveAspectFit width: parent.width sourceSize.width: parent.width source: eventType == "image" ? content : "" } } } ToolButton { id: showDetailsButton text: "..." Layout.maximumHeight: settings.condense_chat ? contentRect.height : implicitHeight Layout.alignment: Qt.AlignTop action: Action { id: showDetails tooltip: "Show details and actions" checkable: true onCheckedChanged: { if (checked) chatView.stickToBottom = false else chatView.stickToBottom = chatView.nowAtYEnd } } } } Loader { asynchronous: true visible: status == Loader.Ready anchors.left: message.left anchors.right: message.right anchors.rightMargin: showDetailsButton.width height: childrenRect.height property string evtId: eventId property url evtLink: "https://matrix.to/#/" + messageModel.room.id + "/" + eventId property var timestamp: time property var showDetails: showDetails property string sourceText: toolTip sourceComponent: showDetails.checked ? detailsArea : undefined } Rectangle { id: readMarker color: defaultPalette.highlight width: messageModel.room.readMarkerEventId === eventId ? parent.width : 0 height: 1 anchors.bottom: message.bottom anchors.horizontalCenter: message.horizontalCenter Behavior on width { NumberAnimation { duration: 500; easing.type: Easing.OutQuad } } } } } Component { id: detailsArea Rectangle { height: childrenRect.height radius: 5 color: defaultPalette.button border.color: defaultPalette.mid Item { id: header width: parent.width height: childrenRect.height anchors.top: parent.top TextEdit { text: "<" + timestamp.toLocaleString(Qt.locale(), Locale.ShortFormat) + ">" font.bold: true readOnly: true selectByKeyboard: true; selectByMouse: true anchors.left: parent.left anchors.leftMargin: 3 anchors.verticalCenter: copyLinkButton.verticalCenter z: 1 } TextEdit { text: ""+ evtId + "" textFormat: Text.RichText font.bold: true horizontalAlignment: Text.AlignHCenter readOnly: true selectByKeyboard: true; selectByMouse: true width: parent.width anchors.top: copyLinkButton.bottom onLinkActivated: Qt.openUrlExternally(link) MouseArea { anchors.fill: parent cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor acceptedButtons: Qt.NoButton } } Button { id: redactButton text: "Redact" anchors.right: copyLinkButton.left z: 1 onClicked: { messageModel.room.redactEvent(evtId) showDetails.checked = false } } Button { id: copyLinkButton text: "Copy link to clipboard" anchors.right: parent.right z: 1 onClicked: { permalink.selectAll() permalink.copy() showDetails.checked = false } } TextEdit { id: permalink text: evtLink width: 0; height: 0; visible: false } } TextArea { text: sourceText; textFormat: Text.PlainText readOnly: true; font.family: "Monospace" selectByKeyboard: true; selectByMouse: true; width: parent.width anchors.top: header.bottom } } } Rectangle { id: scrollindicator opacity: chatView.nowAtYEnd ? 0 : 0.5 color: defaultPalette.text height: 30 radius: height/2 width: height anchors.left: parent.left anchors.bottom: parent.bottom anchors.leftMargin: width/2 anchors.bottomMargin: chatView.nowAtYEnd ? -height : height/2 Behavior on opacity { NumberAnimation { duration: 300 } } Behavior on anchors.bottomMargin { NumberAnimation { duration: 300 } } Image { anchors.fill: parent source: "qrc:///scrolldown.svg" } MouseArea { anchors.fill: parent onClicked: root.scrollToBottom() cursorShape: Qt.PointingHandCursor } } } Quaternion-0.0.5/client/quaternionconnection.cpp000066400000000000000000000032251321710324500220700ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "quaternionconnection.h" #include "quaternionroom.h" QuaternionConnection::QuaternionConnection(QUrl server, QObject* parent) : QMatrixClient::Connection(server, parent) { } QMatrixClient::Room* QuaternionConnection::createRoom(const QString& roomId) { return new QuaternionRoom(this, roomId); } Quaternion-0.0.5/client/quaternionconnection.h000066400000000000000000000032021321710324500215300ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include "lib/connection.h" class QuaternionConnection: public QMatrixClient::Connection { Q_OBJECT public: QuaternionConnection(QUrl server, QObject* parent = nullptr); protected: virtual QMatrixClient::Room* createRoom(const QString& roomId); }; Quaternion-0.0.5/client/quaternionroom.cpp000066400000000000000000000125321321710324500207060ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "quaternionroom.h" #include #include "lib/connection.h" QuaternionRoom::QuaternionRoom(QMatrixClient::Connection* connection, QString roomId, QMatrixClient::JoinState joinState) : QMatrixClient::Room(connection, roomId, joinState) { m_shown = false; m_cachedInput = ""; connect( this, &QuaternionRoom::notificationCountChanged, this, &QuaternionRoom::countChanged ); connect( this, &QuaternionRoom::highlightCountChanged, this, &QuaternionRoom::countChanged ); } void QuaternionRoom::setShown(bool shown) { if( shown == m_shown ) return; m_shown = shown; if( m_shown ) { resetHighlightCount(); resetNotificationCount(); } } bool QuaternionRoom::isShown() { return m_shown; } const QuaternionRoom::Timeline& QuaternionRoom::messages() const { return m_messages; } using QMatrixClient::TimelineItem; void QuaternionRoom::onAddNewTimelineEvents(timeline_iter_t from) { m_messages.reserve(std::distance(from, messageEvents().cend())); std::transform(from, messageEvents().cend(), std::back_inserter(m_messages), [=] (const TimelineItem& ti) { return Message(ti.event(), this); }); } void QuaternionRoom::onAddHistoricalTimelineEvents(rev_iter_t from) { m_messages.reserve(std::distance(from, messageEvents().crend())); std::transform(from, messageEvents().crend(), std::front_inserter(m_messages), [=] (const TimelineItem& ti) { return Message(ti.event(), this); }); } void QuaternionRoom::onRedaction(const QMatrixClient::RoomEvent* before, const QMatrixClient::RoomEvent* after) { Q_ASSERT(before && after); const auto it = std::find_if(m_messages.begin(), m_messages.end(), [=](const Message& m) { return m.messageEvent() == before; }); if (it != m_messages.end()) it->setEvent(after); } void QuaternionRoom::countChanged() { if( m_shown ) { resetNotificationCount(); resetHighlightCount(); } } const QString& QuaternionRoom::cachedInput() const { return m_cachedInput; } void QuaternionRoom::setCachedInput(const QString& input) { m_cachedInput = input; } /** Converts all that looks like a URL into HTML links */ void linkifyUrls(QString& htmlEscapedText) { static const auto RegExpOptions = QRegularExpression::CaseInsensitiveOption #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) | QRegularExpression::OptimizeOnFirstUsageOption #endif | QRegularExpression::UseUnicodePropertiesOption; // NOTE: htmlEscapedText is already HTML-escaped (no literal <,>,&)! // regexp is originally taken from Konsole (https://github.com/KDE/konsole) // full url: // protocolname:// or www. followed by anything other than whitespaces, // <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, ), :, // comma or dot // Note: outer parentheses are a part of C++ raw string delimiters, not of // the regex (see http://en.cppreference.com/w/cpp/language/string_literal). const QRegularExpression FullUrlRegExp(QStringLiteral( R"(((www\.(?!\.)|[a-z][a-z0-9+.-]*://)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))" ), RegExpOptions); // email address: // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars] const QRegularExpression EmailAddressRegExp(QStringLiteral( R"((mailto:)?(\b(\w|\.|-)+@(\w|\.|-)+\.\w+\b))" ), RegExpOptions); htmlEscapedText.replace(EmailAddressRegExp, QStringLiteral(R"(\1\2)")); htmlEscapedText.replace(FullUrlRegExp, QStringLiteral(R"(\1)")); } QString QuaternionRoom::prettyPrint(const QString& plainText) const { auto pt = QStringLiteral("") + plainText.toHtmlEscaped() + QStringLiteral(""); pt.replace('\n', "
"); linkifyUrls(pt); return pt; } Quaternion-0.0.5/client/quaternionroom.h000066400000000000000000000051051321710324500203510ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include "message.h" #include "lib/room.h" class QuaternionRoom: public QMatrixClient::Room { Q_OBJECT public: using Timeline = QVector; QuaternionRoom(QMatrixClient::Connection* connection, QString roomId, QMatrixClient::JoinState joinState); /** * set/get whether this room is currently show to the user. * This is used to mark messages as read. */ void setShown(bool shown); bool isShown(); void setCachedInput(const QString& input); const QString& cachedInput() const; const Timeline& messages() const; /** Pretty-prints plain text into HTML * This includes HTML escaping of <,>,",& and URLs linkification. */ QString prettyPrint(const QString& plainText) const; private slots: void countChanged(); private: Timeline m_messages; bool m_shown; QString m_cachedInput; void onAddNewTimelineEvents(timeline_iter_t from) override; void onAddHistoricalTimelineEvents(rev_iter_t from) override; void onRedaction(const QMatrixClient::RoomEvent* before, const QMatrixClient::RoomEvent* after) override; }; Quaternion-0.0.5/client/resources.qrc000066400000000000000000000011561321710324500176410ustar00rootroot00000000000000 qml/chat.qml qml/ToolTip.qml qml/ToolTipArea.qml ../icons/quaternion/128-apps-quaternion.png ../icons/breeze/irc-channel-joined.svg ../icons/breeze/irc-channel-parted.svg ../icons/irc-channel-invited.svg ../icons/scrolldown.svg ../icons/busy_16x16.gif Quaternion-0.0.5/client/roomlistdock.cpp000066400000000000000000000147351321710324500203440ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "roomlistdock.h" #include #include #include #include "models/roomlistmodel.h" #include "quaternionroom.h" class RoomListItemDelegate : public QStyledItemDelegate { public: explicit RoomListItemDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) , highlightColor(QSettings() .value("UI/highlight_color", QColor("orange")) .value()) { } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: QColor highlightColor; }; void RoomListItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { QStyleOptionViewItem o { option }; if (index.data(RoomListModel::HasUnreadRole).toBool()) o.font.setBold(true); if (index.data(RoomListModel::HighlightCountRole).toInt() > 0) { // Highlighting the text may not work out on monochrome colour schemes, // hence duplicating with italic font. o.palette.setColor(QPalette::Text, highlightColor); o.font.setItalic(true); } using QMatrixClient::JoinState; QString joinState = index.data(RoomListModel::JoinStateRole).toString(); if (joinState == toCString(JoinState::Invite)) o.font.setItalic(true); else if (joinState == toCString(JoinState::Leave)) o.font.setStrikeOut(true); QStyledItemDelegate::paint(painter, o, index); } RoomListDock::RoomListDock(QWidget* parent) : QDockWidget("Rooms", parent) { setObjectName("RoomsDock"); model = new RoomListModel(this); view = new QListView(); proxyModel = new QSortFilterProxyModel(); proxyModel->setDynamicSortFilter(true); proxyModel->setSourceModel(model); proxyModel->sort(0); view->setModel(proxyModel); view->setItemDelegate(new RoomListItemDelegate(this)); connect( view, &QListView::activated, this, &RoomListDock::rowSelected ); connect( view, &QListView::clicked, this, &RoomListDock::rowSelected); connect( model, &RoomListModel::rowsInserted, this, &RoomListDock::refreshTitle ); connect( model, &RoomListModel::rowsRemoved, this, &RoomListDock::refreshTitle ); connect( model, &RoomListModel::modelReset, this, &RoomListDock::refreshTitle ); setWidget(view); contextMenu = new QMenu(this); markAsReadAction = new QAction(tr("Mark room as read"), this); connect(markAsReadAction, &QAction::triggered, this, &RoomListDock::menuMarkReadSelected); contextMenu->addAction(markAsReadAction); contextMenu->addSeparator(); joinAction = new QAction(tr("Join Room"), this); connect(joinAction, &QAction::triggered, this, &RoomListDock::menuJoinSelected); contextMenu->addAction(joinAction); leaveAction = new QAction(tr("Leave Room"), this); connect(leaveAction, &QAction::triggered, this, &RoomListDock::menuLeaveSelected); contextMenu->addAction(leaveAction); contextMenu->addSeparator(); forgetAction = new QAction(tr("Forget Room"), this); connect(forgetAction, &QAction::triggered, this, &RoomListDock::menuForgetSelected); contextMenu->addAction(forgetAction); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &QWidget::customContextMenuRequested, this, &RoomListDock::showContextMenu); } void RoomListDock::addConnection(QMatrixClient::Connection* connection) { model->addConnection(connection); } void RoomListDock::rowSelected(const QModelIndex& index) { if (index.isValid()) emit roomSelected( model->roomAt(proxyModel->mapToSource(index).row())); } void RoomListDock::showContextMenu(const QPoint& pos) { QModelIndex index = view->indexAt(view->mapFromParent(pos)); if( !index.isValid() ) return; auto room = model->roomAt(proxyModel->mapToSource(index).row()); using QMatrixClient::JoinState; joinAction->setEnabled(room->joinState() != JoinState::Join); leaveAction->setEnabled(room->joinState() != JoinState::Leave); markAsReadAction->setEnabled(room->joinState() == JoinState::Join); contextMenu->popup(mapToGlobal(pos)); } QuaternionRoom* RoomListDock::getSelectedRoom() const { QModelIndex index = view->currentIndex(); return !index.isValid() ? nullptr : model->roomAt(proxyModel->mapToSource(index).row()); } void RoomListDock::menuJoinSelected() { // The user has been invited to the room if (auto room = getSelectedRoom()) { Q_ASSERT(room->connection()); room->connection()->joinRoom(room->id()); } } void RoomListDock::menuLeaveSelected() { if (auto room = getSelectedRoom()) room->leaveRoom(); } void RoomListDock::menuForgetSelected() { if (auto room = getSelectedRoom()) room->connection()->forgetRoom(room->id()); } void RoomListDock::menuMarkReadSelected() { if (auto room = getSelectedRoom()) room->markAllMessagesAsRead(); } void RoomListDock::refreshTitle() { setWindowTitle(tr("Rooms (%1)").arg(model->rowCount(QModelIndex()))); } Quaternion-0.0.5/client/roomlistdock.h000066400000000000000000000046311321710324500200030ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include "lib/connection.h" #include #include #include #include class RoomListModel; class QuaternionRoom; class RoomListDock : public QDockWidget { Q_OBJECT public: explicit RoomListDock(QWidget* parent = nullptr); void addConnection(QMatrixClient::Connection* connection); signals: void roomSelected(QuaternionRoom* room); private slots: void rowSelected(const QModelIndex& index); void showContextMenu(const QPoint& pos); void menuMarkReadSelected(); void menuJoinSelected(); void menuLeaveSelected(); void menuForgetSelected(); void refreshTitle(); private: QListView* view; RoomListModel* model; QSortFilterProxyModel* proxyModel; QMenu* contextMenu; QAction* markAsReadAction; QAction* joinAction; QAction* leaveAction; QAction* forgetAction; QuaternionRoom* getSelectedRoom() const; }; Quaternion-0.0.5/client/systemtray.cpp000066400000000000000000000040111321710324500200410ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "systemtray.h" #include #include "lib/connection.h" #include "lib/room.h" SystemTray::SystemTray(QWidget* parent) : QSystemTrayIcon(parent) , m_parent(parent) { setIcon(QIcon(":/icon.png")); } void SystemTray::newRoom(QMatrixClient::Room* room) { connect(room, &QMatrixClient::Room::highlightCountChanged, this, &SystemTray::highlightCountChanged); } void SystemTray::highlightCountChanged(QMatrixClient::Room* room) { if( room->highlightCount() > 0 ) { showMessage(tr("Highlight!"), tr("%1: %2 highlight(s)").arg(room->displayName()).arg(room->highlightCount())); m_parent->activateWindow(); } } Quaternion-0.0.5/client/systemtray.h000066400000000000000000000034241321710324500175150ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2016 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class Connection; class Room; } class SystemTray: public QSystemTrayIcon { Q_OBJECT public: explicit SystemTray(QWidget* parent = nullptr); public slots: void newRoom(QMatrixClient::Room* room); private slots: void highlightCountChanged(QMatrixClient::Room* room); private: QWidget* m_parent; }; Quaternion-0.0.5/client/userlistdock.cpp000066400000000000000000000047021321710324500203370ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #include "userlistdock.h" #include #include #include "lib/connection.h" #include "lib/room.h" #include "models/userlistmodel.h" UserListDock::UserListDock(QWidget* parent) : QDockWidget("Users", parent) { setObjectName("UsersDock"); m_view = new QTableView(); m_view->setShowGrid(false); m_view->horizontalHeader()->setStretchLastSection(true); m_view->horizontalHeader()->setVisible(false); m_view->verticalHeader()->setVisible(false); setWidget(m_view); m_model = new UserListModel(); m_view->setModel(m_model); connect( m_model, &QAbstractListModel::rowsInserted, this, &UserListDock::refreshTitle ); connect( m_model, &QAbstractListModel::rowsRemoved, this, &UserListDock::refreshTitle ); connect( m_model, &QAbstractListModel::modelReset, this, &UserListDock::refreshTitle ); } void UserListDock::setRoom(QMatrixClient::Room* room) { m_model->setRoom(room); } void UserListDock::refreshTitle() { setWindowTitle(tr("Users (%1)").arg(m_model->rowCount(QModelIndex()))); } Quaternion-0.0.5/client/userlistdock.h000066400000000000000000000034211321710324500200010ustar00rootroot00000000000000/************************************************************************** * * * Copyright (C) 2015 Felix Rohrbach * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * **************************************************************************/ #pragma once #include namespace QMatrixClient { class Room; } class UserListModel; class QTableView; class UserListDock: public QDockWidget { Q_OBJECT public: explicit UserListDock(QWidget* parent = nullptr); void setRoom( QMatrixClient::Room* room ); private slots: void refreshTitle(); private: QTableView* m_view; UserListModel* m_model; }; Quaternion-0.0.5/cmake/000077500000000000000000000000001321710324500147175ustar00rootroot00000000000000Quaternion-0.0.5/cmake/ECMInstallIcons.cmake000066400000000000000000000304771321710324500206630ustar00rootroot00000000000000#.rst: # ECMInstallIcons # --------------- # # Installs icons, sorting them into the correct directories according to the # FreeDesktop.org icon naming specification. # # :: # # ecm_install_icons(ICONS [ [...]] # DESTINATION # [LANG ] # [THEME ]) # # The given icons, whose names must match the pattern:: # # --. # # will be installed to the appropriate subdirectory of DESTINATION according to # the FreeDesktop.org icon naming scheme. By default, they are installed to the # "hicolor" theme, but this can be changed using the THEME argument. If the # icons are localized, the LANG argument can be used to install them in a # locale-specific directory. # # ```` is a numeric pixel size (typically 16, 22, 32, 48, 64, 128 or 256) # or ``sc`` for scalable (SVG) files, ```` is one of the standard # FreeDesktop.org icon groups (actions, animations, apps, categories, devices, # emblems, emotes, intl, mimetypes, places, status) and ```` is one of # ``.png``, ``.mng`` or ``.svgz``. # # The typical installation directory is ``share/icons``. # # .. code-block:: cmake # # ecm_install_icons(ICONS 22-actions-menu_new.png # DESTINATION share/icons) # # The above code will install the file ``22-actions-menu_new.png`` as # ``${CMAKE_INSTALL_PREFIX}/share/icons//22x22/actions/menu_new.png`` # # Users of the :kde-module:`KDEInstallDirs` module would normally use # ``${ICON_INSTALL_DIR}`` as the DESTINATION, while users of the GNUInstallDirs # module should use ``${CMAKE_INSTALL_DATAROOTDIR}/icons``. # # An old form of arguments will also be accepted:: # # ecm_install_icons( []) # # This matches files named like:: # # --. # # where ```` is one of # * ``hi`` for hicolor # * ``lo`` for locolor # * ``cr`` for the Crystal icon theme # * ``ox`` for the Oxygen icon theme # * ``br`` for the Breeze icon theme # # With this syntax, the file ``hi22-actions-menu_new.png`` would be installed # into ``/hicolor/22x22/actions/menu_new.png`` # # Since pre-1.0.0. #============================================================================= # Copyright 2014 Alex Merry # Copyright 2013 David Edmundson # Copyright 2008 Chusslove Illich # Copyright 2006 Alex Neundorf # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. include(CMakeParseArguments) # A "map" of short type names to the directories. # Unknown names produce a warning. set(_ECM_ICON_GROUP_mimetypes "mimetypes") set(_ECM_ICON_GROUP_places "places") set(_ECM_ICON_GROUP_devices "devices") set(_ECM_ICON_GROUP_apps "apps") set(_ECM_ICON_GROUP_actions "actions") set(_ECM_ICON_GROUP_categories "categories") set(_ECM_ICON_GROUP_status "status") set(_ECM_ICON_GROUP_emblems "emblems") set(_ECM_ICON_GROUP_emotes "emotes") set(_ECM_ICON_GROUP_animations "animations") set(_ECM_ICON_GROUP_intl "intl") # For the "compatibility" syntax: a "map" of short theme names to the theme # directory set(_ECM_ICON_THEME_br "breeze") set(_ECM_ICON_THEME_ox "oxygen") set(_ECM_ICON_THEME_cr "crystalsvg") set(_ECM_ICON_THEME_lo "locolor") set(_ECM_ICON_THEME_hi "hicolor") macro(_ecm_install_icons_v1 _defaultpath) # the l10n-subdir if language given as second argument (localized icon) set(_lang ${ARGV1}) if(_lang) set(_l10n_SUBDIR l10n/${_lang}) else() set(_l10n_SUBDIR ".") endif() set(_themes) # first the png icons file(GLOB _icons *.png) foreach (_current_ICON ${_icons} ) # since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty string(REGEX MATCH "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" _dummy "${_current_ICON}") set(_type "${CMAKE_MATCH_1}") set(_size "${CMAKE_MATCH_2}") set(_group "${CMAKE_MATCH_3}") set(_name "${CMAKE_MATCH_4}") set(_theme_GROUP ${_ECM_ICON_THEME_${_type}}) if( _theme_GROUP) list(APPEND _themes "${_theme_GROUP}") _ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake ${_defaultpath}/${_theme_GROUP}/${_size}x${_size} ${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR}) endif() endforeach (_current_ICON) # mng icons file(GLOB _icons *.mng) foreach (_current_ICON ${_icons} ) # since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty string(REGEX MATCH "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" _dummy "${_current_ICON}") set(_type "${CMAKE_MATCH_1}") set(_size "${CMAKE_MATCH_2}") set(_group "${CMAKE_MATCH_3}") set(_name "${CMAKE_MATCH_4}") set(_theme_GROUP ${_ECM_ICON_THEME_${_type}}) if( _theme_GROUP) list(APPEND _themes "${_theme_GROUP}") _ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake ${_defaultpath}/${_theme_GROUP}/${_size}x${_size} ${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR}) endif() endforeach (_current_ICON) # and now the svg icons file(GLOB _icons *.svgz) foreach (_current_ICON ${_icons} ) # since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty string(REGEX MATCH "^.*/([a-zA-Z]+)sc\\-([a-z]+)\\-(.+\\.svgz)$" _dummy "${_current_ICON}") set(_type "${CMAKE_MATCH_1}") set(_group "${CMAKE_MATCH_2}") set(_name "${CMAKE_MATCH_3}") set(_theme_GROUP ${_ECM_ICON_THEME_${_type}}) if( _theme_GROUP) list(APPEND _themes "${_theme_GROUP}") _ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake ${_defaultpath}/${_theme_GROUP}/scalable ${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR}) endif() endforeach (_current_ICON) if (_themes) list(REMOVE_DUPLICATES _themes) foreach(_theme ${_themes}) _ecm_update_iconcache("${_defaultpath}" "${_theme}") endforeach() else() message(AUTHOR_WARNING "No suitably-named icons found") endif() endmacro() # only used internally by _ecm_install_icons_v1 macro(_ecm_add_icon_install_rule _install_SCRIPT _install_PATH _group _orig_NAME _install_NAME _l10n_SUBDIR) # if the string doesn't match the pattern, the result is the full string, so all three have the same content if (NOT ${_group} STREQUAL ${_install_NAME} ) set(_icon_GROUP ${_ECM_ICON_GROUP_${_group}}) if(NOT _icon_GROUP) message(WARNING "Icon ${_install_NAME} uses invalid category ${_group}, setting to 'actions'") set(_icon_GROUP "actions") endif() # message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name} l10n: ${_l10n_SUBDIR}") install(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/${_l10n_SUBDIR}/ RENAME ${_install_NAME} ) endif (NOT ${_group} STREQUAL ${_install_NAME} ) endmacro() # Updates the mtime of the icon theme directory, so caches that # watch for changes to the directory will know to update. # If present, this also runs gtk-update-icon-cache (which despite the name is also used by Qt). function(_ecm_update_iconcache installdir theme) find_program(GTK_UPDATE_ICON_CACHE_EXECUTABLE NAMES gtk-update-icon-cache) # We don't always have touch command (e.g. on Windows), so instead # create and delete a temporary file in the theme dir. install(CODE " set(DESTDIR_VALUE \"\$ENV{DESTDIR}\") if (NOT DESTDIR_VALUE) execute_process(COMMAND \"${CMAKE_COMMAND}\" -E touch \"${CMAKE_INSTALL_PREFIX}/${installdir}/${theme}\") set(HAVE_GTK_UPDATE_ICON_CACHE_EXEC ${GTK_UPDATE_ICON_CACHE_EXECUTABLE}) if (HAVE_GTK_UPDATE_ICON_CACHE_EXEC) execute_process(COMMAND ${GTK_UPDATE_ICON_CACHE_EXECUTABLE} -q -t -i . WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}/${installdir}/${theme}\") endif () endif (NOT DESTDIR_VALUE) ") endfunction() function(ecm_install_icons) set(options) set(oneValueArgs DESTINATION LANG THEME) set(multiValueArgs ICONS) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT ARG_ICONS AND NOT ARG_DESTINATION) message(AUTHOR_WARNING "ecm_install_icons() with no ICONS argument is deprecated") _ecm_install_icons_v1(${ARGN}) return() endif() if(ARG_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unexpected arguments to ecm_install_icons: ${ARG_UNPARSED_ARGUMENTS}") endif() if(NOT ARG_DESTINATION) message(FATAL_ERROR "No DESTINATION argument given to ecm_install_icons") endif() if(NOT ARG_THEME) set(ARG_THEME "hicolor") endif() if(ARG_LANG) set(l10n_subdir "l10n/${ARG_LANG}/") endif() foreach(icon ${ARG_ICONS}) get_filename_component(filename "${icon}" NAME) string(REGEX MATCH "([0-9sc]+)\\-([a-z]+)\\-([^/]+)\\.([a-z]+)$" complete_match "${filename}") set(size "${CMAKE_MATCH_1}") set(group "${CMAKE_MATCH_2}") set(name "${CMAKE_MATCH_3}") set(ext "${CMAKE_MATCH_4}") if(NOT size OR NOT group OR NOT name OR NOT ext) message(WARNING "${icon} is not named correctly for ecm_install_icons - ignoring") elseif(NOT size STREQUAL "sc" AND NOT size GREATER 0) message(WARNING "${icon} size (${size}) is invalid - ignoring") else() if (NOT complete_match STREQUAL filename) # We can't stop accepting filenames with leading characters, # because that would break existing projects, so just warn # about them instead. message(AUTHOR_WARNING "\"${icon}\" has characters before the size; it should be renamed to \"${size}-${group}-${name}.${ext}\"") endif() if(NOT _ECM_ICON_GROUP_${group}) message(WARNING "${icon} group (${group}) is not recognized") endif() if(size STREQUAL "sc") if(NOT ext STREQUAL "svg" AND NOT ext STREQUAL "svgz") message(WARNING "Scalable icon ${icon} is not SVG or SVGZ") endif() set(size_dir "scalable") else() if(NOT ext STREQUAL "png" AND NOT ext STREQUAL "mng" AND NOT ext STREQUAL "svg" AND NOT ext STREQUAL "svgz") message(WARNING "Fixed-size icon ${icon} is not PNG/MNG/SVG/SVGZ") endif() set(size_dir "${size}x${size}") endif() install( FILES "${icon}" DESTINATION "${ARG_DESTINATION}/${ARG_THEME}/${size_dir}/${group}/${l10n_subdir}" RENAME "${name}.${ext}" ) endif() endforeach() _ecm_update_iconcache("${ARG_DESTINATION}" "${ARG_THEME}") endfunction() Quaternion-0.0.5/flatpak/000077500000000000000000000000001321710324500152615ustar00rootroot00000000000000Quaternion-0.0.5/flatpak/build.sh000077500000000000000000000004141321710324500167160ustar00rootroot00000000000000#!/usr/bin/env bash flatpak-builder --ccache --force-clean --require-changes --repo=repo --subject="Nightly build of Quaternion, `date`" ${EXPORT_ARGS-} app com.github.quaternion.json flatpak --user remote-add --if-not-exists quaternion-nightly repo --no-gpg-verify Quaternion-0.0.5/flatpak/com.github.quaternion.json000066400000000000000000000012411321710324500223750ustar00rootroot00000000000000{ "id": "com.github.quaternion", "branch": "master", "rename-icon": "quaternion", "rename-desktop-file": "quaternion.desktop", "runtime": "org.kde.Platform", "runtime-version": "5.9", "sdk": "org.kde.Sdk", "command": "quaternion", "tags": ["nightly"], "desktop-file-name-prefix": "(Nightly) ", "finish-args": ["--share=ipc", "--share=network", "--socket=x11", "--socket=wayland", "--env=QT_QPA_PLATFORM=flatpak", "--device=dri"], "modules": [ { "name": "quaternion", "cmake": true, "sources": [ { "type": "git", "url": "git://github.com/Fxrh/Quaternion.git" } ] } ] } Quaternion-0.0.5/flatpak/setup_runtime.sh000077500000000000000000000003261321710324500205240ustar00rootroot00000000000000#!/usr/bin/env bash flatpak --user remote-add flathub --if-not-exists --from https://flathub.org/repo/flathub.flatpakrepo flatpak --user install flathub org.kde.Platform flatpak --user install flathub org.kde.Sdk Quaternion-0.0.5/icons/000077500000000000000000000000001321710324500147525ustar00rootroot00000000000000Quaternion-0.0.5/icons/breeze/000077500000000000000000000000001321710324500162265ustar00rootroot00000000000000Quaternion-0.0.5/icons/breeze/COPYING.breeze000066400000000000000000000222301321710324500205330ustar00rootroot00000000000000The Breeze Icon Theme in this folder Copyright (C) 2014 Uri Herrera and others This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . Clarification: The GNU Lesser General Public License or LGPL is written for software libraries in the first place. We expressly want the LGPL to be valid for this artwork library too. KDE Breeze theme icons is a special kind of software library, it is an artwork library, it's elements can be used in a Graphical User Interface, or GUI. Source code, for this library means: - where they exist, SVG; - otherwise, if applicable, the multi-layered formats xcf or psd, or otherwise png. The LGPL in some sections obliges you to make the files carry notices. With images this is in some cases impossible or hardly useful. With this library a notice is placed at a prominent place in the directory containing the elements. You may follow this practice. The exception in section 5 of the GNU Lesser General Public License covers the use of elements of this art library in a GUI. https://vdesign.kde.org/ ----- GNU LESSER 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. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. Quaternion-0.0.5/icons/breeze/README.breeze000066400000000000000000000002401321710324500203550ustar00rootroot00000000000000The icons in this folder where imported from the breeze icon set. Repository: anongit.kde.org:breeze-icons.git Commit: 00f3ea7a763dde4d676ece8186c1cdbe52f6c2fcQuaternion-0.0.5/icons/breeze/irc-channel-joined.svg000066400000000000000000000074161321710324500224100ustar00rootroot00000000000000 image/svg+xml Quaternion-0.0.5/icons/breeze/irc-channel-parted.svg000066400000000000000000000074431321710324500224170ustar00rootroot00000000000000 image/svg+xml Quaternion-0.0.5/icons/busy_16x16.gif000066400000000000000000000526741321710324500173060ustar00rootroot00000000000000GIF89a  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~! NETSCAPE2.0! , HA$؎AᚶyӱXp:~eD3fy+׮@qU9IGpݸq #Eu-hl(=SGМ&RsΠ.d֬oǬ n'mx<0 ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$HNsђp\7X0\8~%̳_dMFmUܶqGP6m ԉ@@5:pM:+axv 2݂fZ*KM3Ҹ^½ɶ6~p=۶po} ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$8?q0\uQX7~ۺ#G bv;fm9ڶ9q`9ln{p`k׸u6YZQz H*O}׍(n;J4iƑEl 7BnL޼L0 ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$(o׽[:M,?lĉ+G0ar6$z߲lU4qq804h )(?@BdT[R J$X<㶭`9̙&B538X]p5~p˶p`n} ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$?nS0uuX"i‰wP۫b lWo9e LY6)&M:yAmzv7mcsl719JU%jƯ,ad (.! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$n?m;ۭueX"?eԼy;F7N`wĵ+xN8#ke"M aÀ5hPсPy#mNxM D2,pĆ#Rƌ11Ό5*f ҅9Lx`@! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$-?lSx۪uMH0Ca͸q:.7Nv޶+.W8cث5'[ϟ%Hkn|HڲmA 5~: FH a N2Sp3-Ć[~.M޿! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$ ?kySxP'vH0[6~mۆ-bB'N :vڮ+NV8#-iۡC7[lg\Qu1qQ XU秒/_} '.]wBlwڴL0 ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$?hq0$vXCXe֌8#:uמ+Ń#-V,gщN7XZt`GkW+m-\;u;JƯ#]d/,fCA$nրoVEL0 ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$?eiۡuݽXКS]{F8tӆy+N7묽#MuN`ϟqVt 9D#W0&{iXo7v=-[5%9EƋ\eW`@! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$maa ڞuݍXZ5~`Ylp2; @sV0]&p=sG)R ӦnF-8(r| ^_@l&ndƌ@d[oۂV49G; %b L`@! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$^]u]Xp4~RULo"ۂ8 [`:I); Nw:?-zt`9<5.iei&KoKzȽDn4Zcs@~ ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$m?[Uu1X4~BIKm{\8 :EK|V:?-zt98`]c+OJR+gr 4XCn@x &! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$x?XQPuXY3~49s&+?mb\8d`:AՎHt : AZQd#N8`)WOvx#(L?wرv9rᵫgܻg{ǯ.r|W! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$hm?UA۶u͡XP2~{&y\6lyh@rNV0]nͽjGP"E bNOB.N lǎ+ѩK4~ W/\w-|,q tT]~! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$XQ1˶ُtםX1~r3F?kZQ7}3 :9;Ŏ`6BdF: ZڰaGc:a SΝ;QW~ș37M?p n۶v-l]~..! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$HmN!ö0ٌtqXp0~i j8Yz`:5Ď w֫9?-zt;tծ`;qUNK \fyfp4w׮[En!tm} ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$8K uAX0~`U?jš0[75 :1Ďvv9رZP-[GT`:Y @uT1FPIlO[΂鎹Cƒ̝LMBf ! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HA$m?HP؆tXН;~X?ic7r =v{Net= :˜v?t с#NR]c4PT_3j6v$p ӑGr  L`@! ,  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~ HAH°.Dhv/B-# ,SD3xG笵ug,./c#6dۗ8'Nv\埢'Z`C)T-}Xʶh_>Ǵ{F*/*H@M*9LXO >/6aVNM{1}, w Bl#K+Me8`&h&m8 P,³6T5=<*W ÛBXz0Np C(9*,#Cd,>-0<ҾG$J1][eLZ7!Uq i!GXH*FRW2V9|i GyHx+>g-Sc#y29#`c/;,$%:ʬKu@xd$F{D<ٲ$WhΫӊ+8 v0H<7tZڳ ރs#}ڠ婱 9c\$Y!RKjlvX,)BP,s6T5w eV}L}Ě#Eg=xڋ eeƻ Qӄ:9BķLNP[V't@FcviHTm AҪ-\p&^VMnU o?Q,7 YI-|шv {qBD%jj#'(-m3J E lSaDk'^>BeZxEǁBx{OoavUo§L,[orX+A* #>=W@vrhXB;Phx(;[QsmB8 ?,4pleIENDB`Quaternion-0.0.5/icons/icon.svg000066400000000000000000000102021321710324500164160ustar00rootroot00000000000000 image/svg+xml Q Quaternion-0.0.5/icons/irc-channel-invited.svg000066400000000000000000000105451321710324500213230ustar00rootroot00000000000000 image/svg+xml Quaternion-0.0.5/icons/quaternion/000077500000000000000000000000001321710324500171375ustar00rootroot00000000000000Quaternion-0.0.5/icons/quaternion/128-apps-quaternion.png000066400000000000000000000226231321710324500233100ustar00rootroot00000000000000PNG  IHDR>asBIT|d pHYs$$P$tEXtSoftwarewww.inkscape.org< IDATx}yŕy]շԭ[B^$^l{ǻ=3?goݱo33`؀l!07F-HnWuݙoȌ̈VuW~*Uvdߋ/^Df-B -B -B -B -B -B -B -k ծ\P/_lZa0&R -3p0yNpl=R_6%^Sp[=P2o: #Dp_ p&s `٢(]ژ=FMs\X6&tf"W`s!ù{1#4F[xނͷYo\{68!`+'MڔA %.;.DB09aB`Sc@n3Τ.J6W]YֱWY'4 'lޒ7W:M![!*@vII _PzC&C:c 8 W.ٟK۟96=8NMr&ަ \0^"L)9!_BL3Н`0"['G_Z6of}' F,N8Rtx@:ِǑ;@! ;ͩs?q+V|WoJ%~"?ZtG<狯cIqȿcock "p+[&?k375{wG;3qB"0! eG|^m1%i f9ؓ-9v릶'i 6v'Gy`H8Tpxyay$g4 b }_krǍ|1K] kf" ey'"\cy)wwbeډ.A VXX"$D$_η+pR1T-6~侦u, S5e L&ySC:F%~.k{I]:cjyGaQwLExe*boq%i$üC f(#E¾I}Y#E XߦsLJ^|\^DqI=fBҮ Lz4֣n g#Es#Ovذ|"_@ò'*/M?\>u,<a(kvL?[EtۯԚ_ '<~7,c"_\&U]@lPsYͯymSdYMX;R .4N΀tymNqCx`<̠~m@v qS{48DcSڅ|eb6D1=Qnbh0gU&$l-Yȕ9J6G$tX1U{/oHv4P[H3"_;prαobr?؜90E!p7M,7N4?3%ϖ @azϚ|{ae E>˒_m׋9On[?ψ89^WxN펶&K=Ejo.ߝT8^gK\4<كdW*8/OЛ*m_7H[YEO"QS4c]7#/لvb?~ w@%|L>1~pV6%a>+ qM1#^s%D4T̑{J3#Vvi:j"~sߛˉ9 0?!g!b0{/xzn2ܸ.:'Pܣk?҅BF p[hc|5};+ms{f yS(G Tĥ|D^)$81KS{ o9lbu/-hװUr%u?"svLL9k00|:5|xm5E7>4dKEϪp)|?>>{A|xI)p])T10o `N`%]I=V䋆$>rYpÃ{䦕; |Uݻ<.yƔ + dG/k/Ou:tp8GLuᄏpm]?c̉$lEy1db4pï0ܴBͣz^Eoa \6PeK7Y8`-MM'.Ick. a .:՗ʡ|}3M, 9xlܴeٲjjG^p8?K0 3hh|};%3q\{P{s&+d3M'm?^xA%]HuRHuL/1;뗩`So={{p^/q ADo߬ gL4hL BOגwb",,09T"xrQi WoiO@*[^,+|7yO;@10U O,x9K0 uQ'*iCבBtc#N h¿>;D/v)_@h#_6ǽu TGC ~ڲ#WJk^TW(EsNo}wɬi`XFc'WЫ'`9j'pOˣ]Vl, /y\E'|@0u`~lI}١F bڸi=mB.kOX+P粁3fZ4M(xᬐ"vN9& AՎ )}ȈtTCTO|70f_>Hσ؝ÎE%YqlXTI!ǹi4Hƴ7-zo^a(hpo}~ᛗ@ABՇ?(9 m=^,yĻy(ls:q(B 'W-.x 5,GSOi۴Vgb  "MT|r>x@~W6\ P/PI=RДI>8frJ{^ 7D(H{'JJLh̫Tޒ(9sCQɺШMXӟIj?bY@`QՔvlp8[^Wm#xz!%kZ,,)4.i5]1b͌|p|uO<7s]vΘHX6` (ۏD#]6@evX6\_ʭK~K'!ӑx~r$V%S5E4L {]ɮj2ܓ2l\uZ2.m5w;ç'pIpSLuqN 2$N&@Bo-i&]R e2l\цʁ{q@Xq< 4=!L63u}9C4EJ_4򉀵*r_'ŏZx-Ce:@-,F`P6Pߵȇ*8B].`x1/vqe;Ƌ ˒sW; ΁$(ԁ0^⩷))6 6ovXL';fWC%|!|| >(oj a0kaˋ=`. /MJo'8@y}l`_3NаTEOffV4k$>C/:գbiM .C2J=p ;G,#teH'kX➐rV*BcΨ#1Z[r،gdOM9,pp]ܩA'˧z$>V|& Vxe :1 m_]f~ .+0eu4 2up=o:10u?U7hCg1L+/PCHfk "t.(6ǿ ūy=C-C/--eTnHXs8bQY`&IԊ٢qWp9[j\;7@=~5|Q(`b\&vm|_by*כ{_ک cH2~zFchXSxgD'<t#Q==lE[F%T!ȗBK Ehxڗʮ_N*> ʹFk0^xQ@IM5KߖFѰx3X B.M1e 3No&c[ 4uf徘h+Cً$DʐwGO5ߏX^T1<ES`=\1逸SM6 c0û{LYAxVKh!Bp^ƽaQBAa6hE>=`9 `Iwf<e"Tk^)-}dĆ^iSCKW눅rӴthTH%/"`s`爪.\dP@NMfP5)8- -ݶ4eҋAOz]}K%K|3J9ŽCNXÓ6S)<9yB`|<<v GXna%$(ĤWya_}Z޽%xj:fc/ȖS{ǚAoh]#@UgI Cy|aEm rHŽx oa  u2PB l`V*E>=hH \ļtm'0 B$ ,<{ˬ6 HNjkH|ycފ'?}NJ`Yh|D\?>y; BzGDƀ?] r@{CHhq 2S}04oؚJϣɂSiq_[;wjy=Ҹ hc\*b]qܴ"1wq|6 3{ȚaPB?A2޺w©! JGv/ 81E ]΀y~zryyBJi70 _by\71U#2Lyh@G\çe,ʣ.5OʳhoX%jo |ؐ91\MIKLU`AL L5*rA*gx˧$1|nCzjwkgdďJ>?~e%[e=|xFmɱ"pH3\a6C8s^ : \ur LwFu\EЕqUXխ?bMNEy6=rsm&9yY_dk?ݠ6zߖ6}C#|'oؚ ;2_4˳L\Wu>u7Vx("4j~Zwp㘳 prygEe?zᅵގOm肮k mP΃)w~8rYu7z[8cewY]Gl i5_7'Srw ~Fyr#%Ҁ;*LJ9zS ~#ewrBj.!䈗8P q)Ĥc+ :#G")PZѝe/8y44̙Ȣ bnqӑ~t]sVU@J1dBZD" M#q oYT bxiQe]Zu?-)?k|xjXʳܰ1F:v%O#/B^O\ ˸JU=I߼ЉTC B;c;7{37gbF:/<Ǐ_PVg6ڣH0#̩o#];t:E8oA\i/pJ'`ט[ ך #wO) VX-߆pɲ8%,2 X 1`8`84JFwܐhg.i۝9og݋ҽ]6|IۢevqsyܵCޏR#M%_fNdUp;z,-*Pռ3nV~q՝2BD3*]OOdԉ9}Lwa2@,Upt=9O1~[z`8oa:g3eQ5!f+Gt+ju)3v3:[9kuex \WL =eD!#J"'oڱ9a!$woA ,LXCis%4ɱoH`;RYNjTIDAT:ftg`ӊN' jk: 0ƣ'Cã+I`418kϬf Ar>emQ)`iެ13ltz xxh_qZ5oZw.To?]Rj/`a8fS胏0f1]}Ӑw: ̈́y}>ǂv3CSB|%I auyxZృwŅ;gݸmʿЍ~k1"0\-"cǰie.O`yMp~e*P g|n^ kUF_[GjU8KAT8 Ș|>Vplg\@&0q΂X^6[O Yx|CF|PG f :n<7.!`qg>EgRXyP$h:0o%<:p/R;BN4Iv|&ΐi-Dp@P{uQ @ߒƭO>KSgyݑIY#V": A>=-ru:~5(uec<@/n8A,N t-"w X%p O}N5~@0{3ϭ6sLv^@Qs׶?/#~2啋kCRC䥯c/&:^;XEz+Pqπ^/G Gܘ#-}JI2N&UǏi}1~DS+ m6q:%U5 8N=~uvlZXGԭg'L}@4[p0hoFI|L1@`gHsσ;6/ץ̶* 8# σ;?GzyATs7=uKv)e)-=ԼZ6Iŏ`ډ(@):jFCHou_B -B -B -B -B -B -B -B ?Sh 3IENDB`Quaternion-0.0.5/icons/quaternion/16-apps-quaternion.png000066400000000000000000000012241321710324500232160ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs|4ktEXtSoftwarewww.inkscape.org<IDAT8=kAμzJbBbl|AH(/ ""` +?@R b%B 1IsEsX%:O91<#?O:/:u>T%xcB &YpH ~Z~4:LS0>z⪧+P)E̲+KH7+ SEീr)P=>k3GbF$abFIÍkj7X љ@;v6h4S^^ju?H=˛Z ̑ZňBC>GCm@3561un+H#uJ~'6+4[ spv D[Ilh+2j@lf[@6U[:$dK>* D jF25sg\dEj=By y ],?5Aђe!U-afPR._-6`z/:A7q1nowf#?"lIENDB`Quaternion-0.0.5/icons/quaternion/22-apps-quaternion.png000066400000000000000000000020061321710324500232120ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYsXXtEXtSoftwarewww.inkscape.org<IDAT8KlU7B[)HR,$jD67&jpa0DӅc׺.4QVX ARʹәo:qKJҳ:9痛s/BhX=k3[-{⿆ij>[ADS>,5ï|ܪ醚Ņ+ ٦L?#lM}]p1Db5p*hh=+UciMj̧OExRc=AqAس}S9'gP]>n^*Om3/2r|bU*`P bṔYr 8upTSH=X7 U>7){.&J.6(u)ݭYݾ|Lok*\>Sedyً/'r84^ezLQ ^?x&JJYfs?qqv 9U3m3ԃU !UCC66RԛVbf!2q.4U! dqc.%DbpA }mK_ZԜA@.^ ̗fFWLUaޡz\}e :&&5TDǀ;/^]C_uV7 j̚N ^ǟ@qυ+IENDB`Quaternion-0.0.5/icons/quaternion/32-apps-quaternion.png000066400000000000000000000027711321710324500232240ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs : :dJtEXtSoftwarewww.inkscape.org<vIDATXm\UϹΝٙlun%P( 1M#RZ'~MST M~j"Qm5DD %b/hݝ;s9m]rrd%?P搵3༊"9:׶}okU{ oYϞƍzp8糫 9"~w?c^k6\ljb)lN1kzL#23[{z=4hrWDajC_ #\NS􊘁XoXW[;Sk~<ݹqPس!ĩ3)z m ?zA;^̻[W+}G~l7H|v^iPxK%@{ Ʉ VVr /l YCGߞVazhs9^hjmbђݻ_l[R@KTc=6'sqťx͠6o?X"F8_d aS///)N*겡p5F%3x~b+LԯǛL<w;-PƵf3%t,\\;h;ks>;*!wB_PŧGKxkѹs[ >p5 8W"0R5ahv<© )c^ԡIsxIuWM6-d6Tz V }b(st 8UAqXr19ܺj«2PJ<ⱳH@Nt'ߖe'8^ɹfn(ļ}!Zk3J|_-t'GgX{eءj+*Cm+Dň(ă+]#qIum  ! DDg>zJ7r5IENDB`Quaternion-0.0.5/icons/quaternion/48-apps-quaternion.png000066400000000000000000000051171321710324500232300ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDAThk\eϹҋݖ,k@-X ʭA E!H5Z` "A##bҫV@K+^fwnsfvt|lvvw88 ݻ|xR&Xtd+:&8iE 挑bۋ8+B?=tQWnlJz-?( UF\GHPAƗЪn̅LҞ-.M!*+={ͅ#_@7]%ߐ##x6'K+G ْ"ٖ&gT /~ƾcN`mhOlI ~ZpBƏ._43jy{a힐z}?&g)P֗6g5;\?ǡ [l̇FOӛ}Ҿ˃+{xO0 $, םǛt(hғ0VY=˲l+@2hl3h2mv ,y5@,˩W sள|Nvo6g(Z"X xCΪsX2Oo^j2ў檥Wf^s(W3#/o= }@$cWc:S|Z\\*Q N `MU_(\=6۳,ݸR%`B]P$ҺJAUߑXc&/HjXsa[b)p,%ް?`T+RјDPLSg=ę֩5UȖ,y{QwZ5=\ZOF1 bGXםc<[K~v &h^p_'1M0TD5$;l_g'e|," DX {Cma Z/0ĚHN GL jVy ,h+rV [!`ThE;VGzwC>a~0P@`U *mO1ojnhI#rRq XLnc5Js<6@io^}/ϊ *;>%r:*}֞dKuBk~liKm룅<He|MUoV:Q?\=ОqZF9"& D yc̔{D I8 N4 $@hM|LF߈D^zC~zNe':NUQF2(E#2|ρ{(/=}ʅ_:Ig3zϐq WΩ9i w屎UXkyg_+|+MK+;KcGX]bn$=(I T)դXǭÚ=|>t3MgJBκʮt$Y8#I^vlWE\='IϨoD8(~ֆQٝURZIU̦Լ%d- ͜qX]Ab]-EgZ/KӴyԷMRaq|_ѬL$aJIENDB`Quaternion-0.0.5/icons/quaternion/64-apps-quaternion.png000066400000000000000000000074101321710324500232240ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsttfxtEXtSoftwarewww.inkscape.org<IDATxyp]}?.ᄃ'Y%CBS1; -%I` NKeBBBwg%Liô -5CH Y [W/v~},HөΌF{|#czL1=ס>oQlt/\j,P'(C: (@xrC^4OV^c=c&'-SS0eRt4h!ԂzP (Xf=恝{-yNwmBUyp° 5Ot#Hu;~P8 TD O|T5r|+ҿ. 8t0hP4县(-pJ\s2^)w~i(T}ظpVAfͧ>H9E5ժyM|0Xe/74UP|ao]S ϊS'PAU_\59wTƇ/ذbɒ~{ j x|;eugD? g/{YX`玊.!'Z?6үnH P)JI6xnW;G(-gL佡~_^,:ak|o[c[ hiK~({=| ?HbxbĿ%\$O8"}u|R)kB#\#׼up xT%P(IFx2|,NKҁ<5_S0=`2!Jm|mJX+b(~{mN6X1`fx!$O3na#x[1P 5CVx_\x/ +2 o]5s#zX6Wyjk5ikR7' 8qN8g~d7x͏#X27j$;JUo2LC__eX9Ϣ(j/ E-KpZ?OV! ZC6yeJ^ ^ |N", P¥r؛e5IlN׀8R߫aw9k6jJl>zHcp.h\C.g]ᙓHxf #~ts-!6lu~EezlyibUl`EVauY||n-F0߅6rQ`9ÒckE3F`):->.^i\#m6o% 1/aPǻՀp$jV!Pd0Cc LW4) }U\iO gsBZh4=uO\C] 9s2Z (8]=y\?  _| nuD|'J,I|q8+3罼7r[HVP^U왴"vkm1V*CIe2}r|^ZSN\4BI¡Ftg_ьfsaPh}K bf!ަ-pbs<_;L5ȮYhӗa%0X8 [aVqn\d )lVzx@&?bfu\Yyt3]=ےad<"tȈ_M$ 2i1EO>jVeۤqx}?§qCȈR:OT8V{j;K LN:chIWuQfQJv5hXq|M~y(ۨne}u@C0 8sB/=v1[묰YA+8!R1m8>qfm8 rn:*6 7?$ڪChul.iy{TIO69E<͍B-#xdk&YABCH怣esݞL9du%9#o5qu8q,8Z`E`۰}Q-^tOj vUUm-*Gb4Ԣq"gUnq"01 u<jP`N[C^GJa$Qi^wi^m}XGI3[`=իժho(nZ^baOū!@h|c]sFfcFy`=>[Uw|0IC;$>~C^>4ÎZ^F,mѢvoo*˻x99F=,?6LMKD)`ڳ˵{[X/@=MޭE9NTzT"v#'C8⳧ʯt>(@ٕ v{wuW*81sm~٣Y1`v,>AࣕV&heEwBpއ1XѼ? *kǯ/3`rÿi/}- _ckϮjR÷ kV=Z=7-Os݄8'ht !/ܾsl|r#4a~_+FzMO,w~a˿!=hsB=PQm|ffɅ |Et 9@r@^5/a+.>!#o{TiyPȯp\ɂ&nR']`kKm#'l0pY}FN*Pٞ?SS֜ٺܱ&OP }`76h(Y'}'$#W.8! ڜcaC<7;.O$ۣ_v~'hz_?Ȃ'6vt 8\GU/!?DbP tS ́qO>7bŀ͆]3Kq[uUY2kt8٥E5llX6?6[0$Еi,td_ 4v| pz+c&:ٺ˜M͘6 ~.Hcg|$c֗7tu*,öwaIJAY(g3NHP]/C]~zay3c{yZ :#Of(Y^w,czL1=w(UIENDB`Quaternion-0.0.5/icons/quaternion/sc-apps-quaternion.svgz000066400000000000000000000101531321710324500236030ustar00rootroot00000000000000AWquaternion.svg[n#Ir}(_aV1Jv^D%)\,^}"N%2=]S++/'Ndpfno/&88Tdi-uyueHo벼fɺ.Lj)>^}nwbR7+6r16M-w3٤/hl]h}U.6Is/C%11"Fx-Ӈx25u5O5@G oC6h ]~W,Zf6+g?c2fɲ\i?w`mznE5zY^_L Ol?H9K}xx^^L0wQU~[2o߰ j4/w1;xYEmV?2[z5 =,-R5\TU4Ob"dbڷT* uK"1@۶o'le~.Ƽu ٔ}i)^䛼|^,jҽ G .&Hj`L>96,#56j; Mo؛l}6l7Ǖ*??y6fq=8&sJ CU+ ƏwkfwH+bku*?mVzjI?gu57 †Pᰵ\Y[ςos"|KSxU]bPas0#jĂ'0/bLwP"K<\ CK#Ņh1;]"Bc~X6q-O( :i9W}uinۧs8OLt'Lz3s*[σ:{Qg.|= jSD5.y t~NOv Jg{D{# V)7$sPL,m+|O oԡߎkˑY)jvmYbfK.((@̈́z Atz"f!VO +*OШg\-G%ڭ V19c{YoOs0;b`:Q򟶳oFlo#wL' K!*%;T<\-SpUtK2u)ǝ-6Z;B+-Q>:={ɺ_\s^-=NXO"[l~\bb,{-^rx8s ggr$~)4RrIcEg_ *^g2)/C"qI~x%sIeK`HG6zmq>C_% o`D?EiΘ̼羦Fv)P%8,Z#:g=NmyAKO܎n)$s;H~M:Hq֔W{lvͼ`[Iﻅ# %a(pOR_q9~ٞYBVk9IßI^O)K 2mp^eյe^,Gg^U@yuﱦ_~N?,=m^>x_.]Ҋ*w}8h^Oؤ~5ԶJ7 l7^Ɨt,m|/Ͱ*%=~ 7.Y<bӦ]TWUhI!η-qJgxճ6h2GJdkV:Kﭴ]@B 4w G?aA%P.тvP^[F9[lַqq| l"Y5+V~u[_n{! l7aӻ2?Y?Ĩ]UKbsV[oˬm?W wP- ^iTeh=[zapʻȿdq #/_ޕeveMixجke QP$F7?8Bz{U0 ~!=(ˍe6tVv9O)w~ǒ-\BpiyWd=E?,o׀rscSQكR.5 1O 1[#ħ1E{6Xg,Ud`M_@Cə~ʙpL.  +B"[3,Q5h1WT%j+h*f-VY1%)n0ZN#H+b`t00V؅TU@WZȃ tbZ7F#wpK`X':qa)8l 0c"*AB7+Q,-3 E炂Y-qJyE  +b&r70gU6BT b8.BRTS`pߣoBeDGê1X&F/FaKgS%(-P7A^o?+{N x}KTZ@9mU࿁YWކ|X] +:dìc[Zk]<G5[&M(-M7Æ(ɳCQ<u![tI R RFVq (rё!%jFXk >r3_H"bn(htM9y {9>=#g\' 2XRiUf23(L V4GF "r"O"CmP4ѵ.`kD&U Lh*z(tџI $R<@\+j$45н"@:xpB!B^^CVs;܄=DidQEj$)V4GXW@X >Gv=C8U'\e34!FXnATã ZqOJR1•<σq$ Yѱ,YS x#d=T4pXD&%~)$2Q@ExUDAOlOz+ *I TX 2ECD +tफ़@ ?qAp /&_0X\vָгcjit/ DdA ᎀ E֥;gҰ.hc°́V s +S2 "!$c-n*ījI`XFn)4DIʄXG2 j =te4te`NUἤ=\_\h |@F^ 6fCppVzކ3hݛ-~F+YI/YQ5A }9xڪON[yS 3&#G&١:HKs:3;z0bE"g"ϥ_$>oBD9l[m]7fBFQuaternion-0.0.5/icons/quaternion/sources/000077500000000000000000000000001321710324500206225ustar00rootroot00000000000000Quaternion-0.0.5/icons/quaternion/sources/quaternion-green.svg000066400000000000000000000431171321710324500246340ustar00rootroot00000000000000 image/svg+xml Quaternion-0.0.5/icons/quaternion/sources/quaternion-red.svg000066400000000000000000000431151321710324500243040ustar00rootroot00000000000000 image/svg+xml Quaternion-0.0.5/icons/quaternion/sources/quaternion.svg000066400000000000000000000431021321710324500235300ustar00rootroot00000000000000 image/svg+xml Quaternion-0.0.5/icons/scrolldown.svg000066400000000000000000000034161321710324500176650ustar00rootroot00000000000000 icon_newmessages Created with Sketch. Quaternion-0.0.5/lib/000077500000000000000000000000001321710324500144055ustar00rootroot00000000000000Quaternion-0.0.5/linux/000077500000000000000000000000001321710324500147765ustar00rootroot00000000000000Quaternion-0.0.5/linux/com.github.quaternion.appdata.xml000066400000000000000000000013531321710324500233560ustar00rootroot00000000000000 com.github.quaternion.desktop CC0-1.0 GPL-3.0+ Quaternion Matrix Client

Quaternion is a cross-platform desktop IM client for the Matrix protocol.

https://raw.githubusercontent.com/QMatrixClient/Quaternion/master/quaternion.png https://github.com/QMatrixClient/Quaternion quaternion
Quaternion-0.0.5/linux/quaternion.desktop000066400000000000000000000003711321710324500205570ustar00rootroot00000000000000[Desktop Entry] Name=Quaternion GenericName=Matrix Client Comment=IM client for the Matrix protocol Comment[de]=IM Client für das Matrix Protokoll Exec=quaternion Terminal=false Icon=quaternion Type=Application Categories=Network;InstantMessaging; Quaternion-0.0.5/qmatrixclient.kdev4000066400000000000000000000000661321710324500174640ustar00rootroot00000000000000[Project] Manager=KDevCMakeManager Name=qmatrixclient Quaternion-0.0.5/quaternion.png000066400000000000000000015224461321710324500165500ustar00rootroot00000000000000PNG  IHDR~ӹ pHYs+ IDATxwtTEnz%ЛRl( **(JAQDPA"Ut&[hݽ!! X $;wf]go c*"""""""""r3hod"""""""""rcH˖' hT@4hmI+& ;9GzHaoN}-l۵[tvnuR .m9ړ3%*5+Wi{vu(Ɗ bFDjJү]nlXXDY *pzMSvsusxZEDDDDDDDDFptr_DBЄ#& 5ͭFxxxt>/6 CӜEDDDDDDDDJ.d50kD+7sf4EDDDDDDDDW yXԔg4YDDDDDDDDc2(IIGFa\],ϕQ?9+򬀢L6-iתżXX-f͗8sa E&UMf3f'L.2#tlpe|D*/X1o/zwJڵ/>codHD`&,<r\+Ԭ oe8n\*&'+2fjW]HQ7Z~];-4nPP+HRR2g#.s\ D;qkvnךlje#)U8J>mN]:ߏt9zz[ H209kŬ Z]jʳݝ2͸/O1N'ZKQۃ$7OUiSB$N.;ÝtİOP̑NN׮0?}.eNz/=7apl8~>ڱoo;Ĥk>Oصg/.Z1qY"""ric=JxDTcŃ\mrEuL&zuJmXt% ͮϙ&mZݞ(Sg~Ƴal۱3C[WQ%]2h.&7ˇ &r\:VHBY_+l'sDCE|:ډ2KaXqDži{Ys.|80g \]:]Mpw'19={]kdÜ_QlƠa/fW۩}kW̄ik#g?iP~<|eV=qsu%ba֜9uLwq &))3d>b_}mZRקo4[ժҫ[,\H0MAo#o43?Sl0#_CU[&)))*QOO/0YZ}'@!'eJ$1)kb}W^G5 \ |El\|_gq.?~*a9fʖ ϲW2Lѕ4`ԙ x/`ڀa<;IN۰dbbż)#oRp>GGL%*c2lgdb44+`GXgm9;rX0fG̗矡r icYdd\ٔi{8GYq3qk՜G_{FWFu냋 |8WWMBʔ&B]s߽:\J%?@bRQa}n֪aW?g?QjeX'6o͍߳yԭ]dnbW =y ֫Äi3ٹg/..μƫԯ[m;vj;#߱i3bYaSupg̸L&<џ1oB"""rkixeij?`gYy?/Zbwd2ѻդav]cO_/Tȗְ^]:oϋУk\r^v~l_%6̤;xb#*DVìbh$ -;arpf.[wjZ:KWAaw >V0QDDDN.ԮM4OOA?x$=s}{ayu0 HII#)%))%󼇎Фa"N\\|unW?SnZ;˦c?'Rjel ҕw\狈bsqJ(ap Wᑑlز(,[Ifv,]|ҴQ\gw?a#1!vdɲډ%VRB|Ań"\S(S x<fndϏRp b"0_t} f1/ж`4YDDD̒Xf]{:LyG5L&LEGLy ylVII9^[3YR!prĤ$.sO1v'Gd &0O>}?_\y.ԗ.?6X?^Y0 *2w?oᰰpr KA\|<żrذ^]*U(5d~ ,52K)HE_Gsb6hÚnuJr,FŌa2.YwJ:1>wf= @jZ_^\1㢻<y{y@ZZ;,7cјL&*+ˑc)M=u&W,{²ytjך orY}}ޥn,_Ʈ~\S6 m܌db]݃w_7c(\ᤥ绞Ck׫'wلOmXt%q~ """raڳa4[J3s҇ٻ9giXnv0,^>ʔg c =̄%Z!`i+f'G܋ :箤""""&傎,Ygz'~@|| LF dfO>Fjj*Iɬ۰!h]9"؏&ӫGW:_bf6o1'11s͞rEKcӬ _-6na)<ҷ7ɓ0m&iFEIkW)ω |0q*C~}OH`u^R@6|ƳO=I ̓LfY[L6)~'2 BH Ϳ"zn3Y4S8=B7 .ûM"11DDDD0tؖNf}^\\[k g7-`۵M%[ѿ#7رǥ@:tNǞ3fO-ޚu,S>O4"لٽ,ϊlJ=BN2V!pRͪ8:MXODDDDDDDvVD#mZЄd<#-X%}h05IDDT!(OCdT#+(("(_ bŒ/# N_eا^做ޗU }|bY:#8/Yr> #ŕJqqRFcM4]4m3 h4ڀYL8cZw<E?n92RXGDq1|m1Bf"煮\ (mᷕ<:a2O1mj4ϕȼH#"H lH #697J6El2?HA[1^JѢlӆj_ndæ㬥9o5p*0_@@6gT_ַ8lw17i\6agP-^4+@z2)gr¤D$3Gn q""""""""Rdo%/ۖU}EYx @V-H_6ǒaXHeUPjO7f`K>qU[8 WH.IrM]nߞJgY5Y?izv#gO񾛑eo3x4gs ΰSm+Y>jct;fpj' {}GKi[;}xӪ}"N9Ѷ]l{8Ӌ.=p*#K<~QG6Q4jP(;{Gyf~T[Ma§mcƬLd@ɘظO) HRt ?ە."""""""""򟣀ME"""""""""b7EDDDDDDDDn (P)("""""""""vS@QDDDDDDDDD즀J l69BrJJQGDnnTPYK.539BP "rkѣTTF7EDDDDDDnM a8DRot3DDDDD:RL@T("""""""""vS@QDDDDDDDDDvk(ȭ\L 3$%g.FҥR2~7"""""""73"[w`cqqųTZ&MpZ)"""""""73<&V+K,F׾Y|%V:LDDDDDDDrٟP>s]S7o0/>89ٳal޲)""""""rPɅ[Ы\LL{?e .Cgߐ?o`giߙ֣D.}]%7e""""""s<R@1E/wy4o݉vX+p/2g{G-#HЊ/x}#tԝν+87ЇS^<0l"f:WƍGkӒvmZWuC͈bauj< )8 Z4guX,e_['ܙǿδWt)AH2u)0w`F-Oϓ~/tU7p)=L?OeJҽ#/;oq~c#98v~=> I['Ss9dAns3|Pc\֮Z̢&0q,FMcM0 i"m)δ~a _?{'17>eL^J/Mcs2ךae0s ol?$FԪ]Bw] 3^A MGs7p<. S5{*5eZQ#L.q5eKYuX* }s+ 0!Nh 3;2yzE{aʔgՊ"Mv|/%9=?,埠z~KUgrBkE|T=Q5s1`Yuz<(9~g܆RS cX2c:Qm}Ң9xFI cl^v'Τ z=) `1GL8nRL.BFq?svFOul $;ŴS,CӲ*ĉAKeu؀͖wNS'[j)D73|@jPoʃu}1A΀sY `ܵ~9kK PNFkx!*R!{MjWvgf7*ת㟧8 Ò,=Dղ$OS$~&mN"\f=C3G$vzNMg2A;Pps֛G|{$P0/܆J*BdÑs={pw#..#WZU\t5Z%o"]3MLGc>| ("T!ǗkQ<ݞf}A,6}MhIhJB<>YEUV<句ڿK݁J ֱ9'݋$SH;_WIBJU4x5Q9 "H %Ŋq:QDxOŃ(n#"" 0 ףWPnD>Ų1Błn5?27;%<Ͱ{+DR~9<3B -hw%CfSBEDDDDn1(3a-g8Dɒ?7;Ұ0&̛Ǥ^f~zi tDn?oy|VEft:NaP&yxxCRv q)K'9~B qJP֮I$%9lOfiء<Ղ_~ŠXdK37f`K>oƹ=1s RlgwhԱ9=Y~1ws4*S2餦]I?q.eAo9Bd}|Vk$sT+`#J>칍?@27z4ׄбC;:vhwU7"?__Wdn9?.z)/>{ժ[܁HzZ:18k-s~+X\9܀#?MY} """""D-q*7NRA9C:ӡ@2 *;%ךJuelqJNg9=aK +bJM%D#29q>W]{?V~-[H?9 ܶerliovrc.E)K&1lwؐoɟHsBӇ? QbTn;M-*FuI=ag-f\a&<ъ̉G3%~qٷM:f.LNmxU^1.IFslXͦ YJ,A E~t:'S}XYGy{Tk5U`͞es<|2wq*7ć@V`[I6;=׎'`89Q ~~קe&[ԫz@s&0c̃/S.SƮۀ~m >(@ɘظy ڽ]|W~6[8sjy6?p|իUIF88\zwPvlng|Rcn2r"K_jL~ڑE z)8$I@ dv'{oP%A+ya ڿӖ[?y &Mfw6Z*Z]ڧtO^{~=kyEDDDDDD7E&eppx՜ t6/?^@[7UV<3O?^IBYDDDDDDrڂR-<>B|]1,q4 pV2ؼ9x2b4,pp3fq^ehm )gIl:SJ!i@1Q'S 䱏Uq%B`m|ﲤ. 'Â} =(OɎů, kKE| EDDDDbaϞ ۍn\L5pt`6Env/>ڕc{Y\QrDV2#&NpAcZѫ qy,)l3S^{=R覈%>|=^:ZUOyV0Qb/RE`bIC(kta:ɋ*Jq%JuVep5p)ٔyZ6J|{Z `iLvw=t=ų~/ɉSWqDDDDDn0ͦ`-R l?Xk(M))) <=̕ꋯυW`b"ߟiq"ҎUӓc}}}H"= (\)("7%wwwHJ&_TPnIxR̗۔GN=VR)51)9""""""" EU4>svם'b fvf3OIo|}M>B:aW>j ~?A |,翑68bŖÑQdv%'(S^px),Q?S2["s򾛑2;='26:+-g^Lyk }(1@zg.h^sIzI0yr1iʉPsczukmF8ereqk?U/ҕ'uz;>.[GehCy؀G7<–.fg{""""rLg[N }+}%"WH<;_mWH~f?fݘL5o23ph;4>QDDDDn7dж C%{m&MeXVlW_/૯e6VuoGP4ەV\O΀:U\蟞Vgϸѭ(<Śyot+DDDDDN񑥼u4𭐝=(o=-5l{v:ƍ^vSu4^ 4ѻ wJgg-|mU0QDwJo +W0oŗW3#p&[YV =GS1JWGwQ[:t(:_= _sϙfs&Zne%$X~*""""""r1C gRCǛWồ0;c8[릏f :toIpb_|<*>/+ӵr.^{xxݻw(*%55_ZrJuoGs]wJjnV(Lf:Uwbdcξ pMUwe@Z:C q3_+wYI?MW:dt-gii"`Ax9Vka%""""""r+3fa+հ`2_[0x6{O]gM 1Vft#_MDƶ (ޥ+j_Ewk?mg&fŐ6k*&TC8ߎ[@C\o>_MViV?J:e|o'Mb`̍n܂ia2a^`Xޙ!\h#%Lx d+b3NOqfrJfqMpm' (ߚw|A?mN_OmfRP{=O!asÚ soҥ3Y˹[΁ƞ&̀WB2̀ܯ4@QDDDDDD@OCjHX;w8QV{^4jf,|> S,<,ze|]ѕ6E338oDȯ|kmmS&s fCXO^VALz/MÙi#ޥXI>v5IDDDDDDDtj+Lsk SAsd^Q拿!#=_ NR|9 l[[q. RTj b{+W,^Jfp(O _L?q4^(1=90ӣS1RuQߥ5E;w#ukCB[zTtnm%Hh44 \S P+p6e15Ls|!! fz4zr1eth4R8p G lJ '#)C9@̦+X2%B9vZ\:gcx'5t<=8WIĬMYCxp˙7  &feM!ND#3 ;Pt0esΤWqIm&L4*saw|}. t0;ŲfXdo*뉗Étݦ< ¶6C?[]ՙe!>Ʒ'-cMW[)N<ȅ3 Rm 7h\H-ڽF7ADDDDDTvgBBS(ꃗu}Tƛ>jvJ%xZB ލ9?oGxo ͛ţ5onE_<p"1ZVDP%凧*?|6@hF5λA @V?;dʵ,^ulp{9ttKرhRuYDDDDDDDlFucD{ s"90b;'E`I͚}NKĉ+:ɿ /8}]K% %DDPBPKi%%0nP΅wov(<}XfN͙ؽ9sfAaNn16Ȇ,i,XZ&J.2{W*Քֹ~'TyךDw6LZCޚݙQ{ra6WPh*uΨR+:au,2Ix/M ]T)lCq-usD vv~rXH 'YEAAAA^uT+04~:*-2_U\`{$,'֚iL}м??ijh; Cl|_XU=R?Fe,;_9O1axD@QAAAvIl69 rKɀ+ZJMR0ѨRŻ_jU 3{AAANAs]O˸b.b ) \]9O0id.tx89rT^^)cKYnV, wEaשQ01mLؒyH:42iV7ʛҔ+)Pi4h? j]ߌڑUYZcBL|//R/P߭"A jz@F_   ¿P\hQ |OZq% (' wF{ZYκبC=ZWg"범y^HnwQ/^]NbLm:~D빥   ¿P ֲ?z^r'{͡^ÙlB yAyj"u`aCN"KE ~ȏkORe# =wx-g d\.F7wAAA%=|M%Vpn |ՓUG[Icbt_%ֱ16mk{$,9΄Pnj[/Z,^ )=( ^:   ?K)ˢEF!޺ucǦZr?ݺu^pʳ,,O5%Kmy6Iϯ&Bj{8v[|{0x'D{e_h{yțؼΧt mư-+sSjЊ`  qNQl^T,Ls_(?Kz2@8vXFj}F˲ сb!Vl71iw08YOJ2aԻ~o ?&ߍ˞|02l(贅SNj߮nfv]f'SYݫD9čxyBt[_J9CwP=ŋYAAgYxkM3Mu_n /?^&o3f}׌ sڲ2֋dCpZBHĴKn֛ȜPe_TX0Oh!G fg,";Pf[͐ >0,<˨O39wL;*1(]Gpo$z}Jl=wgs(A\}&U:}muϺdnoSZ^xG'0pHW*Oe<ȸ %, BRۍ+)G(? $, <hA2D:E   OUҒ#AW2\w8*%,3\Ȳ=pۃԫGDi՛8ksp0i bf }ӥ~|wl { .\3iƌJ4~(]FҠZP:)MLqziD:rb= _}u:4^kq5Zf>`dgܑ 꽓VS>Lkdg-n{[:o67kD|i^Ee6G|thΠ]N2U'f^).1}[&wb ħ1H>j7|·5YԹ-_w&wfr,l2b 4/f^+&;<m d2sw[#}bl'b4EoD>\~MbY{,9vD}Ik6991ǁO  f5%w5c0g|LdИ6 3Li%=[1t_L2tl4<9G$֤'~4Am|v][0dOt6gP]gNR=mfr̸ aVeeb-'e1]ƒ zrm4i\Mi2{oH43~ԑ.+3Ź]h=2#>%]W=@Mcz֌ő\Ԥ+h0˧ܺ#ے;1>(>y?=]Wğ' l64ѩxv$ 88CZO;l03B\u%]f'>&WbaL>lRsgY7g݆a%obۧI,?~zFflf649oi^(i9L6_uh7q)\ci}-t ѡbà٤Ϩ} Ra;fXX,l $l)b;}{dzxv_##i7Hv-a'݅N Jy5W^R\C 246mrq,uח{_[ߖ¶^Q_[H6)Y#_'ӬJiM:7 V#a=OϧZy~z] C AƼӨ3W] &q}LەFNtuZ59dؚУ-و-*PCB@}'cӄ4iЀuaغlߙ%Ц¿Ÿ:Z#]f+e7R?j_Z<5f#IHW!j3$En)mF; Mb{u?΢Vߔ ;%2uN Xe>VPQ|j+ iI~Fh<)zkqp:4gd OM)ɡ$(4{3c3ҳlha=(.ͨn'WOx"ZO,ʤZP$!8ԁǓ* U6'1!(0Gq19cx#]jYV` %l1Fqsñ=Rx%.)P(X,sH  $"(>H|I;cF2qC9rNJ#LƘ)ˋi( i;e&o氠w+TA|P֚.ybg"0aAd=)ݭ/'I:6X.|??$n~ GVOAh_z.Scbj|w$IjL:N%Ii&,Up,P>{Q?&mJ F1;9< Ȓ7W_ʊ5+Bx>Dᴼgu ɂd'@J8e &8MVaAF7LѨ0&.aBD]%NL/RA|ѡ4b _cBx#/3K;4+}ɈvBxrXaԟ=_у5=z;M )xXTDF$7jW4aNψ}X6B[ dESgCkBy~DLY2/JL&>oU^{+&oRazW*>ϵT2H2aߙ-ðȵfuДK*F2mA+ޑcdZ+Z-?ɴz/TUZ O˾(F|P)EL̻^)YBIv+3)QF %kPX2S(Pn-c'2Ž;Wf[KHH,T &خ%㈒bU)1hC^7OPe*Sk%|Պ^Yγ''NI>jX|%*F7cO""?:"8(ն`"uxy~o7yF2aj .GZ&}oɂut)]}ԋ_x2!QF$t͋XZjJchj4foXL8% \kv _#F0) &x UQښKxDyՒ* Usʼ'?!"TT7KP_ZD>y\!KkFy͢ѥlE G=Ҭ{Ԭ׊¨3v(UAn5mXqk:8PRS [;3&5 @e&$0<%Ԇ MרQWd45^n7nI 8mlًrt t.BNmC7~՘b |P'kFUl 6_~# ,eSYokl-7`f 2B$TIGY>2 ;z|+O\qXJIo k}.\ .lcI;`Si"JƯ*)[K<ƞ,!WS6p<؁ʝ돳ІP2HT ^q1Ĥn7΂Y+͝;8E!'r1q;?EO F/T/p. mcF(Y(_73'پ[6HNmEky*$RSz;8f+W"]+Wo>YӰs?oh4֕[3]}@ Ȭz8ل;,z=+zsc6Eʀgvp,(;X,jbBπgZTtb96DFMʘ=KgW9y'4jcAk1"0:e7nQ;YZ3VuO82S fcyRdKɢLVHJR5Uߝ%|ټfonof 38kIU)ɂ³pg&8_N r5K&&NRušh-xkUZdql(_v3/zBb%>f7ԝ406fOO>[>?:^=9o#_SGoݒ`KqW'b!ra:w+AlK}stƍS[c@~ZhZǍF]O'u&~}ݬ^jlY3ĚOw3jfiL$bt69`M*ڀvv0,IrC9HCYx,TAvzZ8C7W ֕A?>ߞ<1F3 wF0W)(N9cKۣx+5?/FHZnw`吜ԡq-LЄe|ݯ+7g ҅3hpT)Y `BFh6i-'IV}m#G ^㨛I.7,IPwdVɌ,!%ԥ.֞ 3`j'ޞF-;qKclJ$n]frt5MցV5rL.ҏKxRdž'ZA&nrIfhͩ~ۂ^rf8T^ksޛ#Ήdk&v.ViCƒҮsjeyf&kʠ߱!s jS/Moʼn]UL֔r%5XRTŗ, #eV"O(MBbPOFhF![xk7"2z*ƇDGM)FDRdq(y/?Ӏx ^-0 $7JwD>{,h:_%XjIBc^526Fv*q 0jx KMrɭG#G!)E3`pc2q-՗P+.ЀfTs6mr4c`VޤE,;M4bh|6-oOҡ|yZ t3eD:}6f,MP&.Te >w(Щ\8d/jX|tyξp+|1mV!GMb?3cK NoàMzнց)rdqS֣y,̸AW13D2{># =6z$.0uLt1Ҡ[ nˢΛbuRo͏z. {J`$\a"  *KQ3 IDAT ghXxDϝ?`W4أ3 x{S09u eJ2ٔHApqh}7 &ԦmA[$6,po/#4m]aD+xJ.P$#;b  v'% ,'=`&|< (6JBvڱ5 u;lIZtIsɯCGGt(v-GӢDѡVdT ́b7[=RwQaĪ5qTժ28;.euڱU4.!ؔV3INbBĂaáСUƗcԉ}_Sb""1xzafPNH$<#&inuXB#SQ݆K`/vx`ի2qpGTDQv&/OLi$"$ aéH?ͭB " 9bMɩ|۵hr1LT_,eH)Q2&//IaCVӷ7Bc613&ЈX0xcdqH'P*3RXxDcN᭪U[ޣ_H`\UkR΃廡S>|סT`ҪTqoT>5lfP-|R{/XȧtD]kf[EtV4rw,a\Ŝn7a6Іrb>Gk5s-7Kg㮝3s/ImF==M@ qOR\PA )P2 Hh>e8BKfzr$Tѥ^Ra T'7yV1JgZ*:[uI/>TtmQuLi$F/|/Ph-K3MBKBt*Q~ИϨL^90e }$]@SF}R5tSI* ɣiHS`ƐyZ+>Iv2 PM%*>?$&/3츤ҦIq_ʦhB|ӧ  EAF28}t?۶ng[5~ٷ[wnem6%G woa D\}l۶~Nis?AŪYx+ڰ̓ZMlWwf̝۹\{Q3hk8F˚؀Ukd'ͿK;l)~gH)'طzæbDɱ^1'^B[e0kA"d 7ͳg;xKAv2m/BnG;c/S,rt\Uy=|;rd vgg9]zԦ- E.'.IChłA%.l(xYdg q(f :<8* @p Ua$nP+l*0ZMhvFxx, fMGbP+ ިH+JJ)qĦ6aHnaDKf<3;N2J"N."E *Tnѻab7Bv@m2Wec׵4Iv#DFP-i'_Oc&T*n[6fEn7.{ 6!y?&GTxNkCp"O8fkۑзMtpTTEXBZȩU)qN EwlDĩ1dQ\9yktTKX Sc3#ˆx.[6%&Ksv}΢/ .u  RH&*A@R* _yLJE`cZ~I&.17LbQ%+}ɓCãh#Ϭˀ0/N[9ey5'1(SĂ#u52(#1\\X4=hH~ .MҷsX]FsfTnÈ8_Ы_`NvBkyρ!hb0]LgQ=fcC"Y畦~@G.PT&aY1u.?Mv}جҋ3ӾZoQY~t.afMZĮHޥiQIN)5f56<7Wnm1LSEΊE#!f-E?YIq1HgبXmE7>~U_DV {xW_ȃM;ơ*D-qˏbq90xtbz  -v8h sv|!nrЉ;Rki?&G$.Kz5E4n䃡V7)pJ}D>(\A߉;xRv)t(pgҠilcG! OKF4gsBsїog4F@P8xW͌SP DgѬJtu kvC>tXA)[JQe+;k+Kz V41\L?>[vHҨ$o a03${`8oMH quEh_ΊYe%+`ǹ; 9- \O2aWlFrbǷ>fɏ7 M[';}4͟pP*3-ɇ'+zͳC0q 7m pOՏ2%%`;73S"{,;p{W4ͯ%f&%.ًj}&3q~4)o,mx3aU^A{3/pbqmɾh5Uoq?NԜLT16 ~yDʀ^7-L9Cѝ(}!Kn%n7zNbb"^77lmpa.וSQRomy[ .ci>4Gy*g#Hp S  zO6JPxn*M9yHNZ5;g>K]}M/0u=pkTAž[^#vHKǏpr(U \ ve **ٌ6i E&""P`ȁgr9r=N]x\>trb @}s!]xD @9W *լF\ ;Syp2h?H|6͙oԐ®e+Uְc,mkFEP*6yڇ(-ZǦ&7mݙRE,#Q?NY&6nL䒡>iK40rM8hzXN5۶yn[lkVq:UX>~^u˔GcXO^%/d+jܬ;EqR5ˀ*0qR[;FQ˘S⃫:?ɕllSVB>nmdJp֎[JT?=_@nӕ}b>CQF RƏ܁Bm3iȈLjH~C^lܻ{V1 Vw2ipYw'eD|WfL>=ɕYm3{#,^W?OG&^ƒvW8~=ng:<[4oBr;0rץ߿CSZd WrR2,j g}$~򑿀/?{)yzRM5n;Z u\?X]-ׄxŸ<{_!ܻ4իFA=?`&Yn+j14.+(:P8N@Z XGQ<}keȭMStl,r^uk;OHٿ0߬ʫ 8ĥ̷K&5*ͯwq< ,W "wՊx$ռm/*[㎭ d|u4Ӫ==Q''jx%= dVoڻ VI&BQy,f#: 0J<,oVq֠q D)Jj,ToX/l)_?x\QrOPebNvK^J$ɃeU|Q#a,RW 7ٸz -iS@畗\9NKJ˫4oSM|( K%!rR?g$M,@QIt<8>#Rrݿ:sGpF@N @8k9߮&y *VT(Q%$u(Ve#nq'؃re={{z<0P~C*Z3Pɗrxrظ;0)g6]sEygV<=*1'YDQA$Hΰ9Lw ;$p̳;*uU6qXWzuWõXG@9U$|StՉu{1_\EWRSAA4汿YK]Ϣ`&6C׺^*vlIрG"hqM>n )ee_kȐ}вԽ r>J%_?g /FFWƍBW_&T2#i@xҽ[|b۷xi sz3s+KVXp& }b~.np?,r(X9=U?AZ;p)Hۈr˯U1a` M(v}[Ǡ:l޸n?Ǝi4ʙ} 0r;ӫ ?EKH[_6۱ `^4.AӴX3.........ZV8˷ü}I^_9y6YPg=K#/bɍO hSt0:Ϧdt8p^9qdg#V7Z~Zȗgrfr,aR~S מ >EĐؼy_|G&Mi֨ս-7-]iׂg ˬ`iZ 5.IlOqbiWqMUln6@ػ}5&ԏ%D1t}}OճHn̂ժ_{KwP."1lMdRgߟ>P6EWqtGmOӦ OCnT\oND_$4Ϊfڹ<{ !(@6eӈ:LjjdDfdRH>jsL r>oD~I$PP1KZٻf9H25]dПS?óq5Ǟs{gխM.Em/s"q^I$WmݺJ^NiY:9Vxdܹ3̊WA(X,-FTU3g7>ŋdx GjrH qQUXŇKSZ@aZ8mXUX@Y|:)I)rK6N\N,̂܃wOJ!=(ָגdwp@]ۼ=T֘gLښ|d! ze)(~h9I.mE5R JMo7t8R=ch$gSlBC'B*xHIOBot2ӞCÃztƘ-,؆B:fC_}:H+[@,1hb۟;tIIdő{쭼|Yj1#ȏuѠgQm2J H%Cx 3Yu\\\U\^.|k翱Kɶ*,0Ĵt>a ޏ&s۬wMANz|K X<< mMծ]q5O0oO.^u57s˻vp5u%+.Ͼ~4I#KTѓ1.l^4^Pķi،3.:8s\;Ӓ is8TȇSK}߿x17g̡0*O)ؐ#\}w??ƶCm_ f /<}<6g]5gc\} n"e 3M ^7\]]+ſ*zB&Md> ;ˤGVk&ib WTbIK::(#+ȦСp@dz5I[3oMF|=䖰n*,U\Hfn^q90Xzipb"ݻyzFJqQFfug۟=7L~!…LvaC Hҋn#[ټ0;S{G${~fþ? a썔"ozv|9?b |#3Z|pB_R1֎v$[ٚѐ&:Qu$ж_gKPX<}0_ܭTf OAtI DsyvV*,*^/6+P*H=Yɨct<=d(+`fL]ӓuT2[^GH[FڀAtd9T:^_3ZN8c癋d;n yЃSoOv!D !uFOmSC&Fّ羺cn w q^"=1 }oexp\1l*KPlȿL'qɛs '91|rW!V>&͸rn{ -g[xx^}RZ"$/~me*˫rSԯ`d1u]oOϷQTVE2({5`msyKh Xo i5q&]Pcg\Ɩqۻ.g0n\X|o|ʤRHfFJVEe,) _qA)i${ܤ2-8VcqxBI~=C, xc|fAe$EdbUQ\TJ$#A12 U $U%uI7¯9G8#B‡J ɪ`|:)ި|A72JyHDQTXJГDzZ2 }AG'ҿ}VmXU% R2SWW=32 K-2IgŅ%DBo}mbUȪKI'{Ư$PVDq0̌ rK(.)=&|Ji+EG1ߋAkT`z2I\ApTRF;  X{a+^(&#ZD{ϵ0'Z\*91vqf׉^9HƤ3ڬ0H̭fǓSÒK$dԩ>u" x9`NKBDjVo`@fNDO\DbWgGոZki9@Or5cz<5ƼFuw<4"ŋ]iǛZ1\<_Z|ub@ÛErQ@X_ޅܵ+ *ڴ4hœӒ;⥨+f޴_rE hI{ Rb) 鈇RÂRX:\O׸/7<wHxO~<-;~fkY RVY/>B>\2 ܯIGX9e$e]Pf"7>ȉZ?6f/a0%o"geY25G4Ż6C|(J0Šq,^9ޔO+~OQ2t ^%_y;ngꍛD'y$cZ⹕x~*wٓ;:4?[@:hlcͻ,;+yY\\`o2OQm},t3u;+?$/CwHX*ZV^I&eM<]IQO * Í.p- 1p)V:]r#g.7|_ސӎ%Cbz]Z <>ѝ3j^OOH&kpQExq'zo<,AZ֜|̡:IQxNhQApyE<&;7ɵLDs^3<ˮrnxٟ[͖{39|PN)#1Nv9 -zhh9GL睉-s3}ԃyO?C17b|k?*RPζSeTAۆY$!3{bͺ~f.--eɲ唔+i׶a J)wjRټd6maDŽɘ[ɡ~.s6o-fϢ}4$Q #wz8.j /s >?aO;/HȨGn[Gs(Y58YtP:kNG67mKd͌KWռr}~S2GMPāSue|]PNùfD?.............Gn1MoQ" 5+>g_͛g{whmVMjvݵ4iEŊX/ʢu1pUI{ޛMzyt=Pv.xp+=.jOl}qA!&_ck:At(g܋'Qމ|7~F_{rxpt /|+w/CEv9\\\\\\\\\\\\\[5`c'Qa:mARA #9o ^ZNY]؀NmI-r!?N73Ûvbhз?w :ۖpH3W3.٦/(aХ7r\??\Iip3z?f޺;y>~} :T"oGﰤhp5@4]'ngӘ: $Zw!\=1]YV׀ ʇ< _mSRg"7;c_O|n|Ĕ;y֊mM]y/gY|6|7e֣sXQۖ nZx cF5|ǥsQD s&Mɤ8!cGє+@4==EdvBoȳRL7\VY7Ywt~щu=ȥX(1סX>zϿ2/ԒonAʬ⭫QfGӎcߓ`_t~zɡ)6Ϝm+pKw4nxdcy$^`;neUg'1mKOy#5[rƽ,n-~#C./pe"&4rO;g<ۯ]OӘ0yO{_}n'S}dk:]\\\\\\\\\\\\\\2݈cy;iiшva.$=s4!NKMtZ֞{p䋅|KT-.]rj$zwўt׉x iC=DjˉZ!@ IDAT# uxv Z4è3\MtNM7ؿb{^~=>ɒYI,M{j_*RG COt֑G`(YVr멋Mr fkAڹ<Aʶ 8 GssxF_7>8Renf)|Y&z^>}1ҸqFeZ2rd? KT!l787w0X .d[H*̆}КYʛR!*bySXhV.I?5QnekFC։p-]\\\\\\\\\\\\\\~WR ghnrޗ'?K͑)5^Qqɶ'j=wcħ|1fgpqq ;,+VҥsچutHXb%{i vm_ B'TJ6)!wWRH\bZ8 ˲oD17Su{L:Ms"ՙ7P9~E} gLpwJ׹_^/89_mxzHO ʁ  `:-?I[)J (1%VRJ*)ۃ?o?XePƳN^bb?r҇qI'^yԠe,^J@|]7J?BLb 3X9z&Ŀ˳Ȳ_>G)R !D#jGoG/k/DퟎB[(]B˧ [hi(; f>OXC*S;վ׬wsBMBgRR!0غe;?XF|\<zLӲpt]0 :mˠt4%(+#3KdҼ a*H Ja:R)L)1-iYhT @me!4! }xݲ,,)hX>GiOǃN3k 躆%eXR*]x^<J) D {1 @H^>DJ ] p_ˠi%R)TКB c@`v!@DƇfhPB9θK"1´, ]G8cEBž!Ƒqi/kИNCix.M.Rv]~+2&4 ðkxsc9)0 CPQE͡cBmڇPAv[jv]תͭ5TR\uSep߈ӲBoo}|~ieU!=n-" }9Dz,=w)#s(i94}%HJuM1Mi?oCzj禡1P>weҴ+i!+P j/&rdĽ_"ڻϡ9 OƬͼe<3>6!= mNۉ';K{+ [`sL45ǚcqءBt,Ku?Tj~ؗRV{)\j5,ea*eReхq2GxIKAI ZTI2‹&< t 4DJڂM* aز`tO\\XB f!0{ .͑& #z E41I!X@4MR!tChhJ;ڮR@SYMP !6JI( I[8jHa ..p> Ѕk$`Rق tK [TCmD(qd 8Ml!Е8 BG( DI/-@9CBaR(%-(iGK"1P P%AnU9e@aW5H9*h l>$D^X@7N4(4[F9B2Qb>Rڢ쳫498F5%O;6$⊐{QJJдng-l7vl_i[PYrE]%?r$4cxZ)H+dhӏ+$h3$0»#(}PJ a%L ˴Pvfp;s y4M,K/Gn3BYx/VJB W"g4i^LҼ_UT!F&6z}|̀>a]HFxev1\+(D?<Ų&5DXyĶh!1Y; @9x{_M G9uE cEc3eYwTKuԶ Ae  )L) Q"PxB`j^L< hJUQ+EH8R",#2tp,$J*?i7 * M ε5-,HK:)$8A" ^[ 0 p,!4d 0ЅP 4m%0-l1bl1F ]-(MC궠+.,Ke%lKI@Bv{ G\#hBEM)--JCmm %#/#m:vYRՖ!UjrM Mӝ~#l+K"dUXPQ3"pE鈇#> !>F *U-^um'q>±X!;4Ӗ4 o\AUO\B2_Y2-4U> 2r@ǃUzkICt_Y@MmYdx<4>bYԕcm)kmЅ#^ZgLĴ$c?p:a5,|,B"p Xy /c1\{UO]%5GLitFt![2 D .5xmt-DY:H˲==']?F䡳OJ D3w~P3TjƢe`Dо5ۡ|CVy5/Cիxmy4DŐ qS iEDePBD[Zm$^{RB u#|hIJKCVU//GYA0- C0c$SQYa[Y*41 ala@Bb"i'`#i1zTW A lAcah@o  <dm ($Eir5X]hqqfv5TrP*G$#9¥#Iί\|ēK.hk*bT) ' jEUMe{%~B,WLYc&̜ɥ5"t##s+2u1a-plbOSWqYB#.)yT.v"Q)Cf%j^vq65Դb%Eo:eb|U+պhZ3h@KYQ15<; g{]6ݥf[م]iEDX XwAlK;%lKa  BnNl;eǡi@ЎCgGmQN3h!ʇi$ 9ٔD&Dq fGa U S4t m _1l‰WMr JGGX/ytvyw>!AR B·rDJMDdDKe[(h\Z0"ݑr\5MO'V"J<kJ7"n8Ba( M$ c,꺎"\HX>RrTPB8‘Мh=![D"KkԶ@[v5G쑶˫HMCPJ'4#kzxE,9'z{hџh7[0"tI-T\i v ǽqkp v_J9.5еPJ|'"1y: G,#X5:dH̳RH˲?~Y`{g/GQ離{$9ICwD"pQ/^"x] EYDQEV=!l3UkIy gf&}_jOoZR a6+>!|HT'bb̎d`%JRVq-(wDkVf .m0Ճֶz%w^B|'WҴ=nƌ/yٯ7~s߳eFcq{ .c᣷Y̏{}r͜qݗ%D&T^2[q|wb&`d9\*t^V=?Le)]čyg^/{B,՝e?0]HyXcwgNT;bUxdl7o13:'$VtV_:+.M6VuY~q׼M9P3.gx=[͜ ֬;G_ڈۏ7@•ǿ_3B_YJlr!?ح[_^+hCѝy,(_ ,uA&KVeN1ſhuh D($^acg01kD*!H) icRb]+1P P6!bdQH$U4#!nPOFIVӨb۰0D% QaaUH6Z%+QҔ$MIFk**irEVê$AjڰrÙ( g)LLo#%} kPsslM`+e!U.k@8 \8Lظ0+Lxd\Vj3+$x*@UImf?F!;Nh(Gօ[kLSt,W9HA`*QB }fwpZ2X:.&3lwUj ˌ1&HH?ȗ)2;*$}{lٴ|V*nt0SmiDh 48i)2eZ hT+wvϦcAm\mƏA@ m:T jR( )06"N]|T;dҬ\>zsN=,a0uΑY ȮnE~<4-`w_1qe{UjeջVe6F#qi`@,Tﷲz;s`mg۳5gmk[q~+_ᤓNj [_~D~p-'R4f! IDAT0N<g]{ {`O]FQۃlm5s9'j|SOz1;\pGmȬri},O; P>3]Ȁ{>~0kGd߷'EZ5Buq`NNō7/`Uwx/_x3䉡aF[q'oK|oe{|m[6wd`m{<}f> $827}K5m1Cc"xIf-$mw2$=I8p"{-[xz4,0۱3ɱs4`w&:a吂 z-<ֳ[l1]ZlAWpw`N}=*~ .b+b@z6OȱWYqM >>z lx7+}|{dyx긆??Bv7Nad/`hSO;Կog8r^EpG#ۏښO_1W|x3vS.={ټ'N>匤13w'x(l(=tWy/SlOi7pzd[9kleW~|׷*dEu^ъ I^7kG>f bn?۩EQDlQ2WЕȔ^$"ul]chGj5IJDP aQ2BF1F F:!2RGD+ ,)bD,i24<.!BR.BRoi4vHA\R)RRaxxFA$" -* :MεfUU$iú:a]t(ej `? ŕADh m3ZF~-Wqqݺo:@rPC8UWx wJCᨘ^]vFYnf6 GWD(Nfx]cR@+BUr 6c]S8Gp!!O˭l"XII6*`O)flOd;4ZYP!iD8*~<$3.0L^kq3u fXiԍY4Zh?vA)&.eI~|}8c!~Bx0.߲xқxKՏg5>-a'ݒ.k~5wZ|/˿sk~Es5;яdigqJp4:;/ V0C}BVnJjvevf-!-O3|ppRw7.zz Cw]9IBjrߵrqݭs۲ڨQVhzDtq/^d{gњdmRC7nnĚCaJ};w/K;S/1:ûf/w'<9KoosW^}n?:}--|T.R~.~{\`??+=+YfroS .#gqm22D~ ν>[YwIuɬ?wS>V9Q$RY;7dj/ӦOdz*ʂ(FJ)RIutdৰ.DVT"MLS.)JTjU:Zhbc :H2:2Q J*JSTRReڄ*^l2 J "r*37)g(D"rIrF{a9XXbTj)z{7eP=PRGQHJRKA$,T#K{8_@D0`Fc.Vg4)Z%`T*qو:i:^ʪ #)٬_ݢU,.ű| ᔔm23*Ve] *H؇Y%܈$sϑ'IڀV}uNx[e廿Z٤A*M1ڹ"^)O b,tu.JgL_XZ}LbJvQIj$$feirҾ,*trӴzG#AƵzJҶQajLW4IH& K۝&)i#AkM*$@RoF#^S)I$ Fkb!H #C RۮĪ/ֶmMc>)[N׽s`O_usZorOctj>1 _k&\UEnv|Al~-ܶ~#+ x\?@6 iMDf_nm>;9Î7xdpkr7Q&ro>t3cv6~!Pb3,X'~6]鋠ށnz4+{VUZv]SL/jz\w#{Q kV>-v+UjRсh(ɎI~Ǧ~g8heCü;f^ƥ2q㣬VhRtϘk^?m1ƛyx2LCw_ Ɲ\vL;h(جRF]db,ub6[S0k 8m?p]a|tL{s۸^nGvGʔXP#y!6=z z; s3xtF@N~- s7孶gr{$ ûDN" lYr5K-g5 434_E1==Q֔2N R.*Q )"ʲD9.d+"U+tT*Ԫ&Oaڔ>k56T㘎JjjD TK1htauX7Xʩ@) (WtacB` C:0HDiYø ںZhe]V.($#WȀG'2u`,#<ƽb[wp DF+ڶMkÁI"@_#H8$䅀BiLvwhLWzi˴.usO}bK;PL΄L͘`wە^=-n پ5>#BVj-*䜄`ФJ٘Fg]9.6VMgeCx Ѫ=ƃ+ kEgR* FyefNu*M̝ށ˴4 P6zxTǮB ܩzѸYTdKwh$$iB b~ȾSX&mmk[`=}+̿LNۿkE7ֹq|oq%[p,ZxoDj/ayC,Y:ʛġ7Z(FX›/aq_w߿5x%KpTVMBϳsәod2P7=fUO< ]^^I|a0!uU79LD_nۿ۳e޼ 36ބYUX]$v3nwј5ij.A'Loͦ 6ݸN^s371&YsO/੧&N{ozBO 8\0{ ns^3.@$KylL!k]tOd☷]}Ul9˺ޙ_6^k5_UyxYBzwE]KYE.bp@_a Lv0i꼪L eUB窲[x+2:g8x)I]fs;g3F4⓺EM׏E{ օ |?- &\٪=s8/[e-.B$,yF }b086p@A9y"〫?Z P k.i8EMkCh>_2ij ud?߈/3{ eLhgʷަM.Øy "ySDpn~E'ʲ2 Yz1.CkWܹ=,NO U) aH6m6.D=k[ֶ%{ْOe0`j~&*wF=e'}!G*sNi8u?[|d;!V̵s9bu01'npaT sC9_Ų7O<ϒvs"NL%&/^{.o['rSض5IoCې-GVyyT7ށm1]Mf9[35P vt,T9m`tLވ3Wb6,y\p[ٖɕ 9l9;) {$: ̿D>~xgغ;?~mmn\{yuv54 8v۴i?ō '7e`Ѡ,Jr뇈fPFsIp^ 2H'ŋ*n͕ ckAsٍ0i+7Q5`;ab^(cqD.)\P]Y%jL$":%NGT ǔ2HƹW0X7N $I"$Ij AH0&=0` Tѩn`TB%) $νOkFFW PK( qFj.cXiQbyU-Q˄4[IKb鈞†SΕ"R2e >$!Dd|Zu5wsj>)mb/Zaƪ4;avvS"jcՄ~.F|\=;xpLd(lFH߃F[X,%Bl~l{rPWia38G+'\;u=~ܲ1R/14ڀIYc=Ak'29eXթSx-qv= ֵfco}$9 {*ޛwn\~iݒٌCY~Z<5Ǟz}8tYnCOq9e~opy/EuZ0?&z}/ N߇vyϼC -+/XF)}} {:mk[hQy-;O.!HXܹ]^92uq܌o5aNY,`~{z;ucZ+I4]gż2> #,^5L">'E Lۚٓ]\0z#*-ڗw]iʕ}LFXMS`S$ Ms)E<}\ ، (ϼh fgiW<У?y6~U ywA>lǹ.LGVd7 N¯{wG mexc=ynϦeʨPA%eiF"SԁCvsjE4ĺ5Eh] :U2J BFtuwSu!U#$Ql=#lSGttuZ("đ єb\KT+HJfv{BkQDR&" RDRF\rTK҄SIDRb]e.%XR)cf*@&"ic"1"I$ܩ1_gK\Lvѳ#BX*0.ngNrvsϱ N )]Gg^V,$A ,.dX2!ƊtkF=/¨4Y؊i-<FC7s_O{m 6W@/Vd/Ӻ ѹ۷ں;,Rujdž.F?̝7fvٚIC{*n?~J*kd:~HݾmgF)M%ٸ1+T ɐ$..Cu1p@*s |x0W|4Mzcv&V#U4UnL[]Fq )mcR5&vqbz~(o6[~liۺlpdn Jѣ)`h$40fI4(YgkrV^÷,[etֶ{n>x˯8_T-/bQij0*FYŭׄ*~v9ulXN1?s=)q4fn+hFV-yz|,;ؒʠx;XGQuӿɮ캩}@0E `:͎t6G}j7ecnw[{Q\/pw}#_m./Nb.9>2{:Zמ3_]2u|-٠X~ɼՈޭ83{?9|wv|;Gs{;/?2PIdTJzߛSJvkv-~&ğa<'-`-J=Xl̿w),|m)7V-a*fFeqƁAmXm@uǻ@5>`@gpG%chN-t?6˔7I21۹c]D*7Bc.qҹ:pWJ5!0 #T~8cǫ@:V鯫M(hAW ԳxHW+ɻ+ۤWuW)V}鮹6AG懮q+l_ ʁE?, /끲24㞖hcEy!dV.JQY7x_cvH˗ss\vaOwFno=^Q~ o9?Ĭ|osE|rWxe[wbF0p.ml]qE'ƫGj4"_t^W?fa|[u!лQoӿÊ0*b}:q7ݜJ%6l6mw?3#+ή2@:jL$j *G(*qXRG4GB0b%ZN̤IR32# *i4 Tl|8BkMVc͚5ttth4kiBDիV6tum&HA\.322֚Qj qcard.YB\FJs#lRJ}<l?:? RC2eӏ b a \\(;PV8?[J:I1t e4 #XH$민֕XH1,iV)k2!)EQ -\s*sYF9pqv7Wǔ۴x7gⷍ&Yka?_1ݎEw+Wܦh㿆c!.-߄u{T[FڮZۇ 1h3vdk1w۵+("bT5lj3up2])&/kJ43oZO~߶6kNxV^'g;= ֛5^+7eR.שS"fvnf'FXzǽE@$]"+|﮿ ֶz~smm{ɽ04H $*C~o16mmk[js>QN //ɌCZ^4؞p} ׄ}ަ|^IVNm2.Ʀ}BiSA .iyn=P۴֤i4{\-D0&XEuU6ͷ8&u.(rtSjK`BY7uR!RPckFn l r& gYl{Jj)F'F2pCkm*{YB̚cdǖ "ԈER=a}K5Glo;_6퉢G4i~LŠ8|Y2G|7?l{}_mߎ¸Xy}梌.AXf-лDܬ: !9qeƪpav1ԟغ @Eq<{QT|&܈#I체 @+p5LqI  DF,Ȳ#wuuGFHGTJeL) 1.f%Y* #!Mq)$IBgg'i'@T*DQ0JFa:kTk5RjZX6iB*H\emtO1Ш7c X%n´R랁Ηg9ce1u )*òp,)i^wchtRPNM.[cb09=4)f92@3((2BҰ?}Y) c~mkX _uR vhH=CrDI5iA]+Pʇ&h+ֶWz|ֶmm?h&TGws2ՍsZPorlQbK01Nۧ ǵCqVezVD2Zl0w7aF8b~_{U2EQUD5)˖3̟,K.:т)(fj_}suwwKGgMrɓꢫ.Jqɂulr_]]e&MDWw7QQ*HӔ~z{{RDVZFZVZAww7[JqΎN**]̜16ژJbJTUˣYpu }1l>8e2s2B<)Pf-*SXMfx;{b;GpžG/+!z6|KY 1|A|mk[ֶV}gblɻ mj?!hO ?hj#WB-Qd̢u6i'MSW^ &{w}]e뭶dv|EŞBloҌi_+ޮ[`r tl;շ (.ӌ #VkxyoJ-OG&{I8%<[sy>/>/i_1[~-9 }:Xy ֶmm{l|-2Ǟu#[ma}ibśL]<"HbFk 1h{`/0XV1$hj.5khY(*GIUK,VUG(ka 7!F+WD`ʺJYj(0CiFLM@]'ƺ׼d q4A9!D7=@xj=Fń1ͱyBB ? 2>WJJC+VY:o9b!>Fdx8!-<.u.r1WqШka˵5OǺ){۬hWv"\dӈM2na8ʨ\쯩#l7=ڭDY4Q> 2_[ JRvlHJcݘUNHc)dۻχ!&PL ? #\8cگ6لg/~JTݻr)~R0 QV؇XZ5{sb֦ZuS_䲠 Ewz в\zTvyq4Qn,_A^?xߜ>os63}G_i/y4\p*o,s7[ݮ?<^7<+iSG\{N} =t} ֶmm{x6fpXs֪̉g" 0>wnmrU,F8MpMYOK"⒅,(ilX`CXUd5ph%0̈ZLHclL*h0:u*ݬX(:I]JRsQBdٛe7e J @QhCC7q)&*OSNY?y\~x#?ۚ@906cZ+Ȫ'Y!vp-*La!0-JM 9* ΔY&h(|d~ˠ4۵o[EYm\Ok':٘zBvt4}FGG3Kc``"| PiT! b84iՙdc/7#^)X[d_~M3Gh"ex6{V"s)O2&_K4X\M%>˷'y_7?hﳱPY<.oh<ܳ,Y({@^KXc\j@e&ۿf[fo(_~ٛw=4,]44}furn~Me7=+^Zy'暿ANْ9kb#ON??x{oT7%gNL9>j5 YW<lơ:cw(<2~p%iq6\()ǜz|xݳuYyY|/g|]҄Ce.`“abQ-Nkeyfo _ب 0Cɗ356}9H~?my>+!ș]W.U|k?Z1|)؋箹g=ǚggr]!9w)/:k6hŶmmk[^k^DY/Dg0`_ +a]`)tyi5!s5JZY_ǔ\|F$@)J R4(5"RlՂ|Kc$)!ɈXXjLO$(˗,A+EZZh4+Ke*  322:j520i$ʕ =q̊+Xt)Jή MKVXFȁ4p#-B.Z;H!\1mwƻo98.C81 > p`a}<6ŹTTeml =\c\sYsDGL5q#-Ot㰮@p;;寁0x/ 1H>wx|~k>w_?Tg6Al6&[ Vui0ƫ9=UQ7.+!D }~ dirEnZc9vbޯݸ!B=O"S+༾պ;OUf,}O/Vq#-dp[N`)E>wz YO\y=~lڪ??]L\҃!5nkϞom|3rSWr)o`"#wqG _rj}>qB>p΅q4.>l0g ~vܱ|'sћ3zY|g|K8|XoqW|&q ߺ W*@i}V.>lfF意gWy_ts$н+o-r;Q\ֶmm'"xp@^+k;cPpE`n$JS%@Ze(ı`.MĴw7tԨTV5*J $iReᒵ`$cj*CC xc&16JkmjJVhIԺ8^EWWrHz DALfL!fTABm8+q_׸-*GP7^lQo*H-Hc7t ]Cw`?g}>)I41(KJ3]!MuMAd_ո όOS5oUr]S IDAT0a[>mMc[L0?p:cƎ3 >̰/;tAB.OD7׳h4]ZM/McL xq8Zi09|Jt$Gfea7XV!Oz>j[ Ӏ_RV"a!Xҕ 6iw2w^[odX, q"#AX]o{ՠ6}KT.{w@1u[WqVv=<>t(۽D]ގszJAsveŋYl}۪g7ۤpl9+Vr-WssQz{lß/NQ=o7߹v6K\r%(D$P ?~( eAѕ _/b""a,la❛ITWw\y9nN2Is#m@>V۞+!)ɳc\I.>m2fv[B"RY81bL79"D4U@$Ph0ZgCi}>x'6{ Nl,.HVVVNqHX<.g|;yg">sXO ;;6@8S˰'dji֩eN|Oyõ]&lӡ{֋qT/jw)X8y*S,ЈZ`Wo"{|_4|־m1;S\ L R"Iävzg*XYeUVYei P U,6!&A20Y?Q Dة2Z5m€tdYs5 2+c xJ>mߒ2BrBפi FRA`jێ$:E6&+$56^Q2iI 误ӬF*6Bd(2lȠEsv zE E@= .a5Z eyq紆TM%҄ZA$qLńA:v)aksD't:GX8B k H8'*AMbj$i$V B}$6kE(h56Kd)Qj&A(jzng?@D&ZNG D'%:*k&I  1 DqBO0Wcv6t ,ndxB iJ'2>Xxah09U"Ƞu3TjMָ~m4qT,esչxyb,FU@ I M"\'Un28ksc e}<2Ja]Ȳ:! {YR}!W}[g0..aAc#.|㮿n"W@>NL-3ZP;xj!3dau<6̔y@df种)sXE6Uְ*IS2)^jW3ۤ2&E'6p}15ZJjF0nq]5>edɿݚf92Ȇ-:QB#Z4B;^K_ qmeՆ`S˚skZpI67Xo"?*C'w2W|a_e]7 ]7v̙~Ǖ'Orp!7N^O{(S/s.ܑXnC6P.ɞ6{/{-KEi9xPz suW(ztabϥoom{*** ʮ2ϖ()+s\Ү*oin9-2t ,LJ""/d*"ML,sp~.r\rŜ ؿā} D.l"P{X8bjzo>fftmX\\dvvyja.LMM13;,33/,07?{VqA&K,..2334{cvqfg~qiwK.dٟ`v~yffgbzn/Ei;/.0@ۡn155^ >ghOuX\ZdznZTV=-So6hw.̳Vu6F*3u.vƗfnʂ vc1v1+} n@H 7iUٯ<_K|3#?rL'J,N }U|Tp25u:sMNm" q9+Kb0룲߿Eg5WccpcB'=]Y3qǔ>ܤƟ;n;]s/F+gNqgORkEb|\" }|n!l4MѩR*`7|6[|sC 4Z53j7)Fӝ`~V8D W`sF-hCΛ3(`wG=ly=a/~G̎x׶&Կ^{oY.<;;|+[>q?ϊr_}ϝCa :5Qn&."~!|ױL= |H_G?_/|d(y x߿a9?(dn; 7nqR]R(VVYeUVmh+/:VVZTPg&/z*o& r}gkn*rhvX[Ȳ[5KLdW9 WMu-Fq7Zm "T$դZ0 *uJ0`4huۿ }jzd1%^~Oth^[Av+WI "SSt-:8" C1t:ty†TkDqLyyz!V @38&ISFVI4 1Xà?@NZIX 9x4MvlmmQՈ^G3+V5?N$tk5FjU ٢Qo O!u ÐNVeYvLs֘\\>uws /[;+b.Ǒo\;1H%Ke|fmwNJ; LM^~[&L\gw&)_SQ}9wo3?ƁBxɩbm]>KdG}؃>D/1;=EP!+bpvWZsLw{!d8d)ke֚Zjֹpn@)_%flbq_}\1`|@cy|:fiҚK7phK'>,'r׷;_ 6~<+g_'x=g<u^[xF_UyKxou?t0lrO31[o|boo#+ J [[߸|EMVVYewzns{nWm~G$}7/ OU @A1grtg2I6IW^MM",re0,_G)g;.Qۺ!-~a\@䉓\x4-a 33Ӵ[ 0)q4D M-HSA=d4 hG; Qg][uekk hLKna=Jovk)rX0Hh1;3K4 LuF#9Jt m4z5ve6={0poZI='XZ\dmu4Ii6K` hekkˎ!4 h# GCd-diifh4 E4jJ !LOOsȑ̭r21%=pVzN媍}.^PY(8& zPcbxMfHYFiZ14F^AH_NRcm__ |x*;p_xۥ,va\q-r(,n$ qypS..?E\:SEkZAJN/k 06/~(]ZVq 2FQRem2 C;K2ܿxCO}нYka(=z}Rexsrc /T|Sǵ8~r!׹qc p8ſ]#/b}xO@.]xo-??}ox"HO|%3Ol=`D@ $dц0ܦwo}+Ϻ*V ߓeD[\B &H/0Ka%`9$IȣRJ(nRQH4Nm AJCH  C8E!ffBӧF  #IJVgss'DQ AQ뱽mRjM BCFh0 )Ah!`4$ kj5LFBH˧CEjuFA$I6joNm;looc$QR>HfI4`mmzp8ĉyjLI2:]k?vhDb{{@)VQ!v,z1I19gw陃cv*!^lc}u3|٩+_gʼnatl&fcڛIM"@) {lUvB3j,`vKl]ŵ0[Ҷ1R{PN.flBJl w؞?X(wƔ4.F.-+Ȳٛz]GE¡"[x_B?h;Huڌ&6DThmI6'; ú1mn: m#.Nqzc9u F("M˟P͔yۧy}.bX[}Iюh6C_?_\;[t= ~]ܚU4^*Wx/sɱv/%/|~Ko%M̉'i۷ x>_{W 2=XYeUV8Po_"&%2yJ6IUx{YzBi2vl}"/G|p@A)u2S!ՆQ?" ,.Γ)VE BWhja ![Z h$Uk2h5 z@1;?Glmm173ưiU(vnGZ7gIFIPA&ZFwj*62 0HhB=M5APcjj->I{f2DSC8&0H$`45 Y0 8W%aN:%s:em0$ ÈxhcVFQN5jh`0@%i区ƘܽWp+S)νTJI܉,[!?7|hM{&M?&S\'),BQV` x?|boRԁ)Nulq:?%bUש@H?ߟc tŔ嘊n ^o  q-GNMYCM=rçX-8f|߿/[ǒǿ|zsXr6eO7&W^eDHge<_na3۩;ω\˿W]A~Zy%^c kn؟O<1-*V^b'NeŞ[ LqL\] t _(IT-t(ǫ/'\|.6$;7T4u¨!B(R6;ja0J bH *A0<66).n )stgv{nQ"LYMLlvtsy:{!cn߈NS:<2 AzNՊz6:]fff{4-Z+mv%Di\h0&~mlomiB‚0$Egc=S{aFPYf!%6.q3*#1~$92wGv@*Ƙ?W10!^6%hc&|fy㒫urd6vʰAG9$ BPԍzq y_'sNJ9fp0hO?du9\S? 8%`7BhDte*T?%(@i1^syw= ji%1hQMJ@*تRH<ܲYq6ա.[u7w? o) ǎB>޿nlrZ H։7FT|$*l#Ug_& }Ƴxw=iIf{$1ԙjŜ8LdjK{vw?a߁Y9Ǐ \^9ϻqkʷ>nEen'[\xsWݻݟt_OF|6U*vI Vܩ\NyE IDATA/fWLvD9@,EDnv4SKg 6!\6\9klњ [lFQD=sW$!1@'$qqlm10DqJb4 zNM(ziJ`4b6V$i8lZH! Ð^Gs :HiJ-;䙴mR<[kӦި!qcm7`MoG]` ^-fgfٳS'O|4Q4" B Mv8B7rܛu̡Q3I- +y+_9Ҷ3r`i^wy~ F$:r3k~i[o 'W]|y֪^~g;ZTg Ϲ?~9ϳ<# ^Kis?q _>.qO᥯|&c"VVYeUvXy_p礤;C" gP;N\1c eOc}THQ̔UNA.bՐ+8fR*ce 50C%DQ- HO gtJ$ nZ]CiCbkc4IX_]qUZVHFшp@#6CjY.8e{mW /*[_S^׬f?zʓ7%﹊ sxd?,)~ }D~)wE9UݚլlQxM@r8ćᅳx+swzy )V0*el,S96rmrY7@sB\m<$by GjH S!ĺy $# k#@Heb*HEHNdb eIIP At0"Δ(buec qDQvo)U* Hhj6 ^>MgIT8M%cN0;=C8YA.'t n%$qI$9Ǭd,A)qlUPIvOݿ98ɮ_z23ژ,`!tLc|Mn:36oD;q9%8_}4 (j1IN~=xBEQTgr&Ua3POg*)&p~K0fL*@B'{A'Yk;vѧ~Փ`e7+jg.wu Tmn~{U(P_n_Oe5M .:0KVonjMxHHt3">?G,hfVa 03`gTeUv_pp1.h.^7]_j>zwk~~^gB;Ϳģp?0}7EFӞ[uPv y&t~O~Pν]gk--g7xP]x*ȹ1oKNa$ BbS8 ОHfْJ"e0Qa$5C &mLhCӝZHА[- AޠVspA=ӧIRA i]6X[[#4uf}9 zDȬa͂T"-}ÓE9Y;-/[pMwfv'Zb<3%8@ /o)>9Qχ2;2&q7uj:IF^(66aB$ٜ7&ZٵA"EYY9u9pwEKǥ9SZ7o"Ϩ 3.y_u Ďq*oS+&$ԃJ*:5Uy H-83=6{ =Gm$2[w准',cۤf~Npas,P;t4Zg*t1`:yYZSYicLTgs ,We{aEcJRlEw,6ՐQH8Ѷ/0XUt6u0q {2k_d7K*vKrֱXˣͳ&=twokޕA0c!(@DdqI1lZ *D-@  dCX9:(^!$S*Se@E) 2mBK1J-DR"äO#l'1Z!1kR3Dqx  LJ&(l 2ci!6+!C@ 3`EFx0c0)WFجбJzeչ68p4PFhic7fZ*s`㿈Ԣ2mX{.YU%5:P'V*U:ؔ|da9(3u,qRE4!MuUy&okLkg!KB()8\v {;cXمM 2iJ>K}2~i/*l,PЩ: 8 sڍ1iIiV84nŀm 5$S!:H+I bYY$AV&}&Ơ\+XYe}X`0mk5HnݴԘӹ7x.|0\|х9_?>{p{/~S0_\^z0󁷾_~8P|xݓ3~<2Y[_}=~MWZ2:N\YeUVٝܢL !T^Ė?DlAumru³)N~:z.mxw}]kcijwٜRmB( rH:z}@z*;7].ٱK/qPܻ7\B]^7]hߕ8s*?^>}5دK^>#fx _xZ|mܫxuޖO+7Gpř*No;)a_ڴ[ ³B3#餾j$D wWLAR6a ^ Q#"J5T ІZlhԅtÐ @'Mi1 !=P $wlsJg~^p 0^G,,tDAϧjIب3cS:[)ttz{# k4-0 6ƛtCce$р 9t {D0>t]TDq̡CsW;5ih4QRg~ $2dRepyi{* |j @5?_e  \w*l𓤌]_y|{'/Sԅa'=e\_zX %cjg}lj0ʁK{3=G~%\I}Q#9Y1Zw.a2\YNl] $JPq#'*V|&mݦ@w8М;K**sEqwK$[c{}wj3M3N8>QS{餅mh!I$lÜ R5ZRdjݟ*+0lK&f i4 c44hLe7#$MIҔp*R8VX(F j!QfE)'VkCFfF&k5EpɕRkH%0J#A^DٰiJǒXLMOhWʩS GL(M(&)Nd(Q !$/rCL>4>e\Ǫixܚ&t֎3fn&wޭ[ u )-"n+ 'Mv>S1c/4lвcB/V&dB;)3 VQW(&]|}RVomnmsrG)Eij˰>NÔq>͐>LǔՎ[y)XYeU͘R=<Cqfy*o7@27 q6@yRhoYS^ަfuo\ɲK)sUTg~hMM+dRؤf4% D1%Cd(RHjrhh%#ffflln5677`0 MSz>7;Jfs{Ri^g4Іh4" jlllP G#<A0Y7#-6Gw7ĩӧ!Ihԁ Т4/|* IFÈ89zoh6QӘ(!"/ruod h z/ᘯru6^*qhC(,x={<{vcљk9P˜TʻB5 jZ=dc; ˩$Iמ1&ªX>)* rMj-OB})z;uAYfpIM`"Y-*3WpɠRXsj?Bh)zv٤SB->v|d@ؐ?7 3.fޯGE-TTYBKxT:߯DL9i&Ak"hgpcLUVYeYS**V"d_}3*B\-\]Bk`L6NV6a7:^a8eEc3GQ*uqz)((P*HQL(Mw~. 678՛IO'ViJj4*P %v8g^l4 USƞ=j5No~۴Z- `ii~4M0pdxr!Nf0l7iw;LMwXY]AyaJ#lW% C dcc{uu]@*dbIB](Bc2@hC IccSr^:V:ve8 R煟l|( FQ9~vE.QǏ y;z~OX0=3E4[ g p`T4IHY]]c]x_BkMM5HFj4sϾict\z-DȬ,<)%WsШ$z2, Me(2reTV*Jj0?㴿=8,2X? Ě)qYr;\m2^WjEaIdvS< %ðFęnUQ;o%{a]M61Al8w`HSۢr?yO]<~wt*[`P*|0IUS'@2P tʫ^ /|]vPWc] _k]~{BAQ!(I ӝntCqW2(J }h@jDXc׷aum56775FpH׳q͔` !(W>}:_8oziJz=אR(x={, 33p&h;or :4M7{fU&E`SA)Ef 6uH1'rxMϖ[my7I!KHs.gncۯ[PJL s4>E+v+Tej˃on;cFD3ٕ*C!Rd \4JBŵۇƸ4)WP 5(퀙;C;<ɓ}|f*Imo5(, rwW+=ϋ2mB2wuHE (|^.C$&SCeT31q*--ƊZ:%ڶvdJCW嘓ƝT;tF̻~B"Q}>!$a``uطwsssϗRz0>>i4qݸq#L؋l5i4QJŹz=DalbtNC{,˸ov,0 W< JT%"1!9-q码_/[GOK{.xإq%Ocho/~:%dg,EklS'\j-$f􄚊L'M~,WCGu#F2 a [-z+U<e&&2>>ݻ9?V{lp\}=vJPaii yY;A+ j5Pj~;S 27{E斘(U8Iq hjI{`#aT*4Z-<) q(*i2xoUdLN: 0!Z(nq NUMV}(i8h! Z*v{3:Qxi\@T%#qm!+h7wcw:o!;,Ir*N*̈́|JPyR"<όwXеǖՍdъ.R7UZƕh3J01<i#*Ir(e3_zrj4H1]$IGbY"1'#" V+^3Vt:+3¼6nuvQ6*3oI!s?܂;HӺK[~diD4qQ9YXfCIh!:ЎJ$ Ԓ$MI^O&<4-b!=("UVhUZ}!TH8L !ZIY k`=?֮8w:?-w\ww\ĝBI((QDw3:]uG릚**z֞nJ kܺ,Aڭߴn4bXU*]$XC8U1JIb/6.==DaDJXZjk/R@{@(!@cvBC@p!HRvInsA{Rb+;w" hA[imQ}z|!& C퐙9dRF!VA0$B|CkڐZVB{>()"IR{x#0)LUwHA4iGҊ" C(o^JTQb}$ T%Rz[_vwؒ.ZR" c8cbtc"%aJH͵*Պw%: Du/'I"KJⶉC kNw(>(*4m6VlϤ3^YQM.YKum+0_zsb7<Ɋ9*0 ٞT:1G! [J`h%=&$*!!do(YrxxtԾ+JCE)&TݼK.V*֜M]ÅIac SCdK8"Mjǂ^O>ʣ&ʎ_>u=_{T(rTHs_[}&=8>?b6︜_,1p7=$*{;\0g}_N :ȷvͳ0d>_ꑬR^ϳ+\{.y&?I1zgl5 _G/΢cԔ%ͳpxߦOG*6G5٥?>^6 iy}/#x8gx^x~\%| s_Ň~Oy#zq @^s'>%'Vv.oǾ]야o{o{x|/5*SR݅P,QD%IZ; Bj51PXģ&9:7y5[n !{Z Y5H)^rvQl3 *xU"$BK"QxzW\ xxKvTJM4fi.̣Tc4M(X{ZS FI&&C4 ֜p ߷4Q;^J>mډ F [-8f팎FvޞO?_vM;n322KKKA!KKK 8N=;vڵ똛e ,6}UDQLkIR%"6lZhW 8|xuֲlqFٱc6od5F?K TU Az{ze~n-CӬөjIT, 8IH#w63.AO%f)q޷tj!5H -ދb|=Cum%/*3ܜlYCN{"im난tOG8weaY"%,]egZuN{D#u˲N7"[nt#`:eK8&z7M#Y|^fۣDywMg.jE*$FDĸccaLAtGw=禅=iL;]\d?t> sO k*r}8{+ '7̓ fsl#x )X?]|Ww9'pʐs~Q<}08[1,`^ǰ}ٖ)Q]J( zuL:Q3J3J(QDƵT<oMnEߊPk_V^;c{7⡨Jѱ#tY%KZ!r,#Z2XwXt,*6DHHxDB%,w|y~О=\k kpiXqA8&I[nnS ~mF5kزe & $IqGfin7ݻϣoQ<=u׮h =j45*Q j=Nu Z 6:4~h *AghxёQ&$ `<Ǜ IDATC$@K.BS̎B;+J! LNq8O&DQJ!.(\rl))p'Sf #uZ!LbJY]5r,*=mtϝS|Q)-p1S-mK(m8|D\E"ƾ쬇%_p*n4d_qw 3:~Jؚ=nǘ+uJ4V ,v'%qq]#= C<)}qGaVLB|1V`O_E8Dm=+#͎?˧K@fuwv/M>+i:!X;; 3yj5O{|泼y.81Ʋk~P(kF/]K.%ojrUk`#fi5b%J_Y+1d @tmX*9y 3nJ7Q$&W9QI@'PBF6H@h$\顄 *!u Mvn@4[:I27?LOO5TU'P-CFdj,,.055$c'cC__0;?_ Rh6ͿFaZfeAa8"J"'gjj2!<8ؾqvoی2jo CBz*&1=3CIL" kׯ^0{Ǵ Jـ^ !P8FkӬҎ:~dyP$1d4s[fZw$FA-ĊJ3jM]d IٹI3 s.]r3!j=ɒH&q,†K;!F@$hZ6N qۢUʸBm6٥92%68׍YTdpٺMNW,}z[?[7ó*Vtp+3L["$rنAPA&1R;ڒ+ݯKfUw~4kkCu̚ 㯿UӷfןԷמd6T7|xwu7OxC%];_1k> +1|3Pw)WEv.z~7Ȩ_QNڅ6Bz(WpNcQDSsB 5s"U@Q..E}Ȓ$˴wS>XbjĨ/ݔDm+0ɮJlXdF/SWY)$F3hFG WLizO/sQWÄy|?@DD)~m;)Ib;Xl,F!*l6i[#OѤR1j]v~k 0V!4{-܂4-StIlki* aVo!#s(“ť%< F(8|0f0iEzϣR1>ˍe& Ӈ1u鋪q5R23={ I,LjCbro6\'M %C1o~ePFiuJɔ (V2Q)HD)w;*yFVEEecY.LLsA73{w mx^Q,CJCiE$x<>Ә)2T@Zm.e~F%}7UX*lag.n\UY%*tαIJ&kaHf;\0Q Vz(KPq T%VV6% N U{i\CeՆXqy:{ ,÷KJKcƦVJqZyAZfM~Ϙ<R&2YQzi贌OSלoow _},㏲#ÌƯf Jp͒-g6-ț[DGY\+ E! ,"8'FbH!U9/}l;?'٫x/ij^v}ٳ/ ĦM|%J(q\^$̊pvM}X,3[%taޓ$*#a5ej Rٽ,^!=(U$0Č!:W*DU% mѢ{tz/VHZ'bH8М]A&>pl+0^r-<>W8^szG\[_T&8O8\ĩO/&s݅GWGyEGYd K E4*<>a gn2K7S￙7|Zt|oih'~rT/W_],xC((ϚVD%Ⱦ;rdF"v[TI^#wH"!蒈EWB X]$MGY%K~"Ib&W>1-򅶢S9X(B%M"_1ۘ㪟]Ђ0x%aئ*QQRehxSO=ZQT*S=8ͮ۶kE3}FVFO¾Jm۶3}A%u 'H; dbb郇8=Q}}}umjn::D$_Za:dʟ~nIl**lBCfxR"F(EeXb ^JXDhjPE^f7Ӫ<#Uش?.NZ/K.Y͙;V.9/t7),<%2uS&AHK!{%tgd[KQq y$:fuv;cy:%({uv/'+̛idbqcM_m[Ntua:ݸden^>vm2:*늛cXp߱ʿ#Sjgy(Uu:,!'];*77ʭOzCO<]YOp{ qooO8٧[}u]R[ӌnhEƥ8Z,p~b.ܐ̯ūu?|_wxy >ykxGNA>O79"yZ[v :٢Ù8|q>*q!}{e7{^;3~O?~ˮ|LSxW]p27|}\}}7񦇽x4yMOv1aُO^\͛z~p yڟT{ǰt.QD{ Dbű;@#l;"vѴ!u1J;=M-Wꘗ`8ha yNHFI4.J)aiKe F- 1Ucnn (U F߽Ь7˜{2ϚqvzqpjVŮ]S=t 6Cd||1fgf9|$hY77)֌ Iғ4M֭]Xke0ah`zNF"9댳8p7p-zU$Qr&LI%hJNI)=(q"wE7KT{>RHTqfՈ3JϨh/K҅(s{FЭZaNeMa #7+ZL|a ,lSx;ܯs.vTڛ & /*IDd.\lw[>0J_TAiIo#髴!RHAn槶YS|_H IIlٱM!1烐('%&<)=$f1te_۲=ƍ!2-!I#f\6 yIt֍ 5ImHA4q'1̾\j.]6/y)OXuGOiHۋd5DuDǂ;g]flGZ↝3(-!fҷ_O/ݯ陙oݏh;'>e|_>|ҫv&~3sχ?w5zg8+/ O<s.&37k84̷J8B^+'_ /:%-~良K输8>Gygxs6036y"?;is{6s)Y6>szXsv}EkƇ_Z>}.o_EްcϽ4tSy _3{_N%J(qO`,Fi׍H,s$B9;{m]Mc{n5{m7jFG!k ٣YֽRhX ׶$ z H@DCvJ4Ol%>ӎfzPafv+?QhKrRl߱Ņnu;Ql4^aa~|fBcF0$#Zwfiq f߾$q8o`ff)88u8pc۷fٻw?}FyUZ-NLԞ )]"R.}l᯵;KRX&Eb1Tʹ1ʻ22}dǸQ쑚3E՚R O*1wu.)Ҹ{ª1S&F=睼#a7Ʊs-nć]{m`gs)iV(ۨ 8J:Xz IPhKm^,1I)XDaрVϱ*NmY`\I"&Qd63\ Q(Q*}mؑ3"I]v((^4T"'r夣jC<8k3Uig~S)#J.:GE뾞tw|HCvQwQF[ND*u!#@3qa^uݧxDݫddb_[AK(q,(.C>d #u=Gƹ}~ћY>w#^yo Fx>uq۟*sc ;/ mjۖG?WpK`r+{?<_,2ϹTPknoo/: ?}|g+@z=Lz/ HnpV{M^i/E#~_3Y)\ S!{!ͽ'+ſ_R({VrZx?9۶JBD% Xj27ծ_+)M uG nğ!Ύ,m/.ҹBT \;]Z$w绢+kɡ$ѹ@qm\$IPQB zT+5f$тF'PZppz8NA?- [n*DST  N$Ejr-,//33=@[_CDaLxUJvrJ0V>}}LϺ؄'%r n !$l4 Rݽ8JdSTÈ[oBZ ZOVU̶.Ay2e'i!U CD涔d49cg Y/|*ϬͺXZb)KvV0&vNpTVin7׎w~1Yp寘sD+=Fl+EQH c6lљ%)`5Pkݙ#%"XO3tE6\~m݊JPK bucm#SEKvyn)&QyFGvHsN8uR^{뛾ȫ5ddk>j=dq%w-M Eܲ{48px߼zk[ QJd2CS|N|8|0$Z֯Oׯg4KM_SECx~wo<mLNL?{4u,jMG2@Oy׋ëOio;^1 lbvE6 迨U6r|~\φcteD%J(KJs9jnʣ"iB!!D{_\.dҙ-r E.Tn2vR6G+YIے*t(jԬI==A{JCAj=PPך0V쿯N9TFƩlή]!I*4OxGUTaP,K3Tj!C U7mf}7磄ƫ_242 '޽X\Xj$WAHR4f[8af~|<|Y$FH lx~4DFA])EQ~QLZ, :I]V=?@J1srRdڏ>&{QQ^D_c.&1lI)혷F3cԎTuꞪ3WYei?{)g̵9f*l;NnnR"TkcpgZ[I"R7XW]{Rk7SRQْ4xdbBJc=ڴ݊QtƲtb9 akH7WDJ^)$DsU͢,3.[ZZbWqhƅ /ee^\McivR0IbN{º| c36RV ³fڼ [0!KJ/=J-]aߙ͏\v;xkd>cc/vƒhF/~/3 zx5dvؿ'对)Pmt;Zss\/s.;AEҳ7(PI("'4BJ$I$N7uD llc Jo $1q6,j1گ;v-&֭aLMdݚ * J)֮`jr/hCzz{r$d 184@O? |TH}YݿA$$'!Z (2E1*^;RQ)g $c"I(l*4Tܕ\J"?4vd]V*d$% Zkbdq1C>mv] }%DdPw!J%2%UgM;lTjmI!򌼞(D)# ]PT" cA2UNlt.vz6 i4&LI7%}kyv,s&I +MJ+It(QC j G=mURlABdrm}AdQXxHtҍ:/ .6%*VKTznm7R{L\8K '*%uvlteA))Y,L b$MLE'DQdJCnj:TBx<0L^kTqmm Ŕ0/% $1g:?)e8g;T'yQes.QoҙLf]=ō9B!kV M|j+c.|0J!~L_}.|,{\ gu9 '>Q>\ٯ0J8}.Nky˗W^U[70Lz{%u_Ww$sӿwOR;x 8 v*Z+vibO a7uNt^ef{R*& C|+q\@(|E8+{^Wם.˔tsձJWJaFhvHw^fA-9׶kDQg#n,>[LeKs7`2r;sIz 9Luc<˳>*Wp8'+LLS!2xBwlǍ۞y߭TᶛHCrROz}[}߃4ֱx.0=u>-QDw)xXo>k>x܏ gkx^>xcۗ[{2Oxًxم뎡ܓ Kn9.oNt<\L{4d'=?Y4d䖯-LX^gq"uݗr×?ƾSKhٽ~>/g|2,,h_z.4O =!a;d~~Ç!z{ZS *!ٻg/.sh3|̈́zN;wPܹӸ*M7A% B4A$V6^ERxDILPSšH$o 8D+{Fw&4 {iʭPHO%'o/!hZa2j[S$#e-RW1ޫ"QӨn_H GJIq@+lEdM|E70JD{$:"J(xOG4R AB %jG(hZHLjJ$^ըäUjDmH\&#V0B&A`b5F a##,-HZR gq~$h?HZJ̔gҷZ&5kƙ(XXXR_’DH}Q:#!=P~3{c T+UN=u+۶o'|eae˖V+wy4 &;Z> ĚN885?f~aLҕTyxAXq!  L;Bf}s˯n)֌2;7Ƕ;8xzFx3(r׹wl:Ȫ"K(Aq7DhƈƍDcb ( (80,>w{Q]}=whp9]]{ՙzyW`blط?3S!* w czzz(p 388HWwӓ%Zd022N[[A!OϢknŞ{7o< w^Z[[v 29=Mo -RV޾>a !bS$-J#0 hv݉WkI秛6qw^Ȩmh 'aB^lݺ;wJX!QVioo'!T#>JT*e&&&( hbE8"#8bϞ}L£ɩI*U|etl|>Ith;qiimZC=q]LLL03e7ݽBBJF me``A39Q:+%6ʩDiʴ1V!'OHRژBJ$m쐅2U,RÖmuusͪ]g|5: ")[o~7e>x*>`R0]YSX箳FÏC bnz^r QYj.حs46YThIi6PNMMX#ѷb}J0Dj(KZvjs>. DZ |#øX4``6-[z8}Ɏlֿ&h &DM4DO#:4LQeYcCI)jr\JlunD(\7﹔Fɍ5"=ʴJ)íxDG ā$엙.Xh1fJsJ0==]x#"t>˖`hdȐj|JOzLMNQ.i)b\f޼NH"3|G+] =ubDx^B~sP)fAЪ58v!!9]" H)(nXKvie4%V:/4dc? M l*u˒;O恇p#`Z|ڞB$i)Ȕ4SDF3JF$mkvuP]Oڙ)eߗBl&ȴ/;Ȥ}ﶧy*d R)l=Lfv/> C( ȥJIBB9K(YbѶmSM'<9 ҠfH)~vgneC& $^ rgJL(v?;mcM4QCPl&h"A*$aêE97BkhKLYCtsK(f˟nDQg iêՙvFqF0f“TdL>b-ғ_X1쯠*6Ig*A@G/kQ^I@i uaa2ee#ZՓUy Ho7 g=AUmI%Kٶ%UKJQ9ވOKY}lۜl֨ykmR kqk&uJ"D)kU4x[+齞4Asu*ߨ*Z}2L_@(E}iLx["%,q(;ě3s Wg)'^fosT pDwV t u3%pGV#8N'϶3ZJI!Ǧb} o8U6(DJ7_Wa <!x(QCy¨(}02x 3S*Q, ,9>l>H˒9}xolI&ŪȰBKxRxY o`j(hnWiHA =b@j"mRJJxB*5Q{NBH"[%Z)O{I,ʄ*ǫ ߛطwLOZlab|e˖`mO\AJjXe֭( <K,ޓk IDATevx  GEviLOOO˱m6֮] 3=peK151I_oWbjjq'? BHF)Jah̬& c$ZPT*2 gHF\ L`G)VC_7r.<'@Cv4"ԌRT]YB-{}%m8⚚*1;g&nkOk㻱9 x#B TbmZr*n+fC^>4>^7QY> U bY)?i$ؐԚXi:Nw<:t12Q\`|"D)mޛh5hM4DM44" iVG0P#.0B[5GaR@PZgvspY5FhѺf*͉WsJ>!,yʾDm8RYbjBr(2}8"?qH88D)AρTUjLw<"L0ژi)3s/LUM,|"$QWjb|'(k @FE>tO)TlT}=(rgQl6O{|BDaȮ-;A8{~7`A7K[B:۶o% TmۃN`thԘJ|ېOL!TBLh!9Q" HdrPN8G(0&بɀ)+Ɩ{&?4^_BՑM.l}2ZR+b60N[R^svhӈ@JRY .A=5y #fQa(DZ|/ b$K"vUZ8) kn-R͘&$'Q*i,y^GXEvs~Z;ov( 6[42Uie  P =3xJM%OV552\$}k+CDǧs!D27B(҆D6=KiqM`1 mh0N `=lۺZ%Slit.⸍㣣Ę^ ͚5k8StO@4\Я1UI(Ud2'$B$X#%4|<7$3" AJ"jrJiXRR߂nDKW]63z A*2YݽUթlr:UuTgn74ׯElt6m% ݴ h-([w~Ό!cEm:mOgC7j_6sX6h3щv'O`UMH᪵N54mK2;vm9ĝ׾dI_[Ҋ(<Wa:Q2O y~3tIJ3U6*[! 9EO|}[]a=](bz/~ Jf= G;h=bM4DM<Ț=?P&YX;Tl:؃TH"0ʷQٍ_SŬ~og׎EK8mM+=d'%jhoi3R"<] iru ₠$V* ڧ%# pm&C,Xɶ[Yz1 `zje˖1=5ͯD֚UV!ɢeKXqat/#ZpST "5o*VLLLҳ֎z̙ZφO#\ iy" v~:IkN".mL:EQ܄K&KIK" AQ#1mv); +mֆեtij I%Ւٵ%ĝKdӺ~Q[Kk0m{ݭ[# |5u0rmgeI[[:i: i"w>{O.B$$acͭoko{~kTKujsH#7o'GS2ϒ zMkV{~#}mqCBxHy|y0Cpq+9eZ7!_(pq+nAł8 =4D;C'i&h&~SH΁.{gPUOPkT~U#1kS-`p#hLhYm3SWK*m:#SS:Չ< s>% %(Ȏ8J)֮[H0 tBJ8ЉK L$\!UTDŽaXgJkIN=5C6Cc5nV%Ψ'1R#ILc- 蔈5^{QSeOvja0M [^m.'yuބA[{ q11oNϼ"Րj9brt8B[KOJZ)PO{5_[.7M˿w] 37_ +MbM4DM<B%Bԙ)${~z.${-.K]'ӈL< *KjT!惥}6I?cFJׂ Pi*}@4ӓSxvF!4%5E!t:]ygPehT? Kϲ{{224/?X,R.W S3SLMO{0\.#W,$c'سgclRBbKΗ@$%*#|OXZ #x!V &pUS.i}s66Hd.;wk>fɺ| bai֩I:k;W=~tɟ8ڼkHEu0!DUZ!ڴVe_ـ4:WgF@kV-])[/&%F6pHԬ`ާK% 0#tԬp4~H1˝i@l3 g-ך:(% lVަSәUkC̪86DmY+yb3Q)4'扭gE)&VQlXve|<ϨuIS?>LL"j)#f`hWp6ڼi: >-8=Mҙ? ^3w1g-?%B[Țk/yiz{7o,2s S≠oGc_x=?6i]W7&DM4Dd/ؘL˒^j9ڣ<;]c<Fr>YUד=͕O#eS=䦭itYB H10JbB"ď5S'䖴23љ)X9r28Ȫ"3FQOyT*[ٹc]]O GJ'*Fe۶m!=%U& !ZE"?ZkY|9###T*97(!@kXQ LMM@ 05OA*1%tH6 άB*J1}? )tK^frvXE{h(48SJF&T^=P޼5+l! `qSgqrn]Uk)qEF 륄,RC H9DƹNR*4dx¬y[%5dLF\N$5P&0J敗nvu٭V57&)RS#D͗%au.QQDmɒӪZV֧bB(v>˖/6kO|T1-->[vIr̚<} rUvh++fHT*$h=|6{8ʫ[ׇL?M0< Ysx^9j K; _w|o#~VB񪫮 ox!k&h?TojIVؘ{!f.NxuQsn:{B*=;m>skGQ\b>Y%% $J CaLI.Rq6{)qǵ}%uUo]8>q%q d悙%$J4"Oor!$XEZgmx%6vleV> -qf^f}K|d%3{sg'9oogKv |kxb|>uy7=ʾ*tE;nCl'[.]k= 'n h[r,Pf⊯obPcyћkNY0ۿ|?OdAOx+,<⹼o^/ -|şf_+?Ǎ/-߾>ν(?5xy'zXxa7\)6 P7g;{E\ƻ?y*-O}{N,ȋu >nK&>OWLJ7}2ʛoz'Ϙ0gɯ"ܻA Ŭ{ɻx}O0Ly0AA!n"1:8O^ ^CFzXx _p(mٿo?K/cANJjJ[k7x#QpB:(&''9|ZZZZص{7W&RdèV* wvrI'pb/~AXT.H5e`sF*'DCJ40ڻ֫SS$!C&[RP!$HؒvJ V CֹN]Y$&ʩCGR@EV' tUiCHJkUm'f$&n&ZyNMagG$v T['&tI9!Mkhǚ6D)5J(/ Z]hkw(̾cf+@*N@'Ğfɒ53YBj֍rLk$?mb͓~:M뒖n_exM.MD)ml*)ۘ[{}<0!ܩ'VJ'{R#RbY+pQYI [Yp'~7z_":Tx&FHd 7]0r3yg_x}S\8՟3>E]1s?>х!7%j?k.囗FK@O ue_|o| /e ,:ls|Iw.W|&6p:^0*~-kyn^N P<~.d ?=ϼ6N"[pG9n&-uI);7C+/ןL[-gW|鯩M|]p"]z˾}9(/^n6s23.zrZKW_n?Ok?`_S}*.~ͻx9qWn[/1_x) 85r!G:_ɋMx+aJM4DM4qףt2ѽ,Pye_4% Fy {lfG)MBq8 O.1& af4#S~dM{h1LQozo'hQeZ@ ޺1|VF'Ʃ!f] eV[!JjB193ݻFl{bJz=Mimtr5"峤;OnlY#a}kMU1AM7sqwM̵VuD`VQ}e׷QG QnY̓͵{]Z4 L'*1~?㌊O5Z٨WeZƬ$I)}@XEM}H!q'`}g#CٴRxݘ8+))W_oL%'oK,/vDZQEki-#~.#GŦOw*{17odlQhM\+($ C9T`GmU IDAT7M?Ŏӌ텄6c"{P츉zEx*=o?߽qg]3 v+$1o7;lWtx"N͋8&SDe/=vZsp?@Utu!9Ml̤_zܩ9?g٩'z`f응tϵo•qO(/ܘ!sWիv7L3C~r㳒-7Iss~O6{'\ ?{v^ ۺgVh{;P3x3p#\g\p&xƱ ٳw_\UC1u>7PꪫROQrM731>Cww7#LOO#IeN}%! O 25ѕj4Uf:`<HTeÖod;4QIZ7--Qh %y&u̵ի5JX3/lVV?:]tSwg|f~0pyӇ&q\7/64R6B#vYek6pۏZk/g Q5?1~)Ψa{~q@/Lt>V!y -c~{7"{i**3ak<G = C%oEKNx˶7|o7ޱ,g&E k[b%1y+>x/GJJ[4SOF[,A;|e{zCet`ֺdu oqCq Oi{bVZ[@b>/__U>q$x>e^$d Nb#|=p =>P}KsGxV^Gb I&6DMFP&P(Niv}AɴJʪ!ü)$LL2 6d}gK A)BH%хNT P(b! (A&"4Z =8G21r8dٰnC8l%he~zaz!/Yvgy&w1\5fE7xmk:UROZeqዚ3} $L <1{.eg>oe͸ksR:%jԩEƏa"H~Bv ;5r Ӻ.neZAK?#e]ndJlB&޽9 x`Ra`d !5ǭ]JwK;ȵ10عw)b:xRtmo5rݑ4fݼ\|ykYC)G/-/;z>A4έ,8z%c YP:cX;ee'h' K R<ٮN y>ee|a5b5'ѷ?_~p8ο` oW|_q|gGe;OQg\Ox5/gŊin9 '5P@X\.<|3wr[Nce`X^Z<|gM's) nM ,_v:]5y61k}7UΞ(#V6,G1;||bwbWrVwC}'[&{C?$[__-װ.Cs7 ܶx.~,~F^gՎiO?4?=\?j&h "Y[5Y=&Ch2SGl9"1_ltXٓjkkYBe.n\SQNù6&"(2?kٛDcM@OxXS cO |iJH4C"WJr#iLLNtJ֮@!C舮.,$=f###LMϰfZ.[%(rc@Jʕ{oazz21:%Yx)K->J bE pZGqEKz8찥u^Z!T9rz֭>)vzI֬^M{{;۶ng~,Yx۶UA%U Hd^kEf 양"Qj83xuQE,>xIt'/4""BU{eݼe/yZ~y??M|{[{9wr_#2γq_͹/^'oKUG?;WS^~?T`>?\v3}Z?B7z#Ox/,:54k䔓=rh.q+^ęg?}\h;|5t#r湯Mr;{B@q^~/2}sf͗:ś߲Rκ5/~,Otɳ|s"/qmZ2:6;{C?̉'y?'/:85o֞fh`Q{1ˊsgs抻t-8ÒE)N-'sݝx&CK\pp9pM\ |#jaV=WKNnP,5\+{GϿoժ݋ë^KOpAM4?aญDDM<㎺CpȋFHNF}"uf!,I7g 3FgVy?kUú\Q"#殟D2U2K_}DDB!UyO.ٜVC B(5[ZikGAh“&pV/ߦ%/ azڗ*Xڳ)ZtR.yٳg>4-"===}|CCClذ! ֭gtu# )Xh;v젻|﹗Ke[ }hd˪g]{6'5WN"l[_Z$vR$(Rp3E5ٱa97?i>;#I@UR{L]-UżՋ8~* ew{Jh9(0DLϔ]hizO}|9ɱ[xK~vgg"kX(0\ :>-qo?>]?ynu^iTHւLD8qA{۾w^_g-)ʻOUY~3wvevQ!%_qo4.yuhB\5+K?#D# *03 3>sl=tW}9鮮3<_Ǽ>+~yr̞}4f.#Z^zI+~0^x+;} 0 +ey Ь[^=y3=. c~uZюQ;S o2T+Fd=tKY(k M F&UyR Ǟ=}G244ă>H`ݺ |6nf|ϣ[gxx! @ Ag{;zmVA>dFsl޼y sQT{7sfbdd )AР ! (tټi w6FK)Rz@ם7yYdzutEv4Ȋσa;F7wK-2WnkRCl}us_myI55Ǥ}M qd.i9 U 5 e5q]ֱ(80mr1@$Cx[UA{xJײ!SUNWgee.ߧaA5>]Z}m˱ub 3y0`?9qi:N*ߢUi hqv[ut`?؆]4jn0<ѠZmCQ(Fgom߼!v Rx?f^3鰀TV̪6r7봏?7@Ȧ/x7_5gʞ,OMO>b۱غm;VNǹqz+>o?'ʷ%bs/3GDK~ |f~?\]aVXaӀF|)6ΰضg+fJދߑJDt&NYRd[V̴ -\UO(>S_FƋK7?RBFI6mAA hmk%Cjr {.w`۶twwmvPA$ B*mmV/1:2JTBjK zTifFP¸C4uEJ5s]ǂhhdl2N#Lkb3mYV #jB!#NqیJv z lv( o:|"QY'k%⾵ä ܎(i]܋3eh^)PA~ Ĉ_e R R1Ց%QmMBx:d'Nptwbn.'nik6 uώ,wJME^1#=ޅF)%J%>ntfӳ@ep?tԘfߴ> pU\[vYfa-h'i Q.r=\3lsgvo{%|EKRBҿ {$џ ZVOQ>/{*fh0}!^K7+f>Ӟ"'ٳg-y̯vj8v؃;v2wk4غmcigo!_䥼?~?È'o|ke4\G$?Wsp۹o͊s,`%l\sVXaN8 jlwLT[y)tϭ]-ms[Y%Slݺ鸼iJ}3Z#"?( !QZ8xaMYH,+ԴHGqEgYEq`O?6U IDATSS̝;3<}!Ggg'*Yf m;ذn팎qIR)WXp!K.\.3|;׿$ZÒ%K3gJe˗MHYw)c=Tju~T#P (e*AA}Z&9'<<PhUc*@ :Re N暛 trnQ;;=|,~0?{OQ~ Et0/ {T_TgbTFI 2 !Ph`2Z͆h4b+6ҩO jS9x~/JhvgR$.};bs$Jȼd9qN)٭3*老= cF#.~^ˬBѭPZ6ECK7Q[W2zd*(ۇRZeeoe暹ۼLl/ƕ}y}Z391ɝ?Hk[wBP-Wo`llh 6R&&f8.7y]&V7~o]-{F _v>z{T}gZ%͜w/^+rq^tk>Y^sT5)o/|kUYVXaO4w{kypSO5S5;G?h"B;^$k)4Zqb#^FEtG"#djFh?^F ,4BF*zC!Kt0 iooV`BV<={ٹsW sfϡIB]V{9<2$ { f-<:.kkaG grd\(Fab RG!l4j ʥ2:RCl\glYv{6 Is4 ,lb> aϛr4D]4Jc`\ ݲr-qu1l*b:s2Vgڟ?ؙr8sTXA\֔<9kr/ͮ{&6m{. KIXydՄ{{Ϟ+qoў'ҙy\tN-pa[f6*yxUU+\]'&H(JtP.W} BZIw Mg(-3 +~,P(΋69w/R9*D|v0Õi G[lم[iM5@1.2~bj ZIZ|$L G"O&(&!K$_ZC!Z]vqw2w\󧌍ɭqک1 `l 7-dΝ 4PC ~C,Y$r.ɉ ЀJd5|'֚JBhP7hI?b]'&"R(3+RH&L Td/k\5B&kLw MfkYu3"XO䎛3\BWh6n_\0-;w2a/ԅeUߺTxY ̺@ -|ZM{luvͽضOWX})9Tש:dۜfn]k_ݱg>6kuɍyZf]T*yw t"[frrBZwmZ;wTHZT1ٴYv(COjP&@QQeϚsaVXaO4&2&!2Ri-]U]LD.@BĝYis@m9BTf: ey kLܪ|U^gzt3S38'i-(1}! @A5XI@f3s2(j:6* y'x'~;s뭷R|LNNR"+*-U>Rp l۱ZôYz͛ă>ȃ>#4̝7aS5R 2Z@=hP*@CR6@S*QZAIGbj4dx ڤ&p$bP }6iUNvLRGCi42.S Վ<@f!Eg8xqHIy2zN>oLsr>!B: PU^,$rUjig^V ;wB6Wޛ>sm'n߹lviuM}dUj]mv[ш H9pÖf85؆a?H}/ނP{Žl--U<ߣR-l"_B 7O0 Ê  OJj °A\B!èAL/že+baVXa=K  |bR2 4Se<) IqF޹ۧY)ӎG+#KW!LdL D-ZkJ'=62T )} !Bq5u G靷!F)qQ*8pK/Rp)gn.]ݻٵkjO>KpS=o7rBJ::;?B Vfg.\gy۷m'd%:tn Z244駞J\o#TYryQV[9?/w!{w,$c8Rzex^D,0j7scHi_A`/&HL !fda| j8#-6 eu_F?>:Hıq  Uh۬Z)(QEGj*N"a=Uպ+Gq##0C$l!Q?뢈#(ɹvy.Z`5'1`IޙU@ƀtՔ8[flUG7f=.Ztbvg!=& Z RѶϝŭsoUajsLt^MwsˏQo!a@>7^̬YmTQ4n"* VXa)V + {]|eU<3)9fn*@mB#a9v4O-/C3bXOeaBt8j Duт xj&FI 3 [B Bzx7`BE'4&e Jkg~ .qsN%/6o~!۞JR#Zs'/_9srZ+F@ZWb֬Y̛3<4̞]Yl>sR -ZDgg'+W$D{d=6o~,]y[̙ʼn'a|tK]qcUA{kY7"7Bt2¨nџ,H@Ɠ/:.+ެr٩2JV"eeTZ,{u$jR ݾrf\E5N<>a2m9gmvmXmP5 pj"LgXWNaĬ=yU&Un=hJ[M_Va>q,fv-7f˲v&4O͘=6~Lʔ)w{HԇR n}j] ;|i^yѫG>[_{3P +왴(VXaV3hYb-Lb3Xw{d+66VsL ᣱiЦZ~Lh{ԋn.G Kq{NuIba&f @䊪Zx!2}-5$Rjt200hLNQ)*ٳA1|InF* Yu*c.J=== X`%366CCC tRN9殻bӦٽ{77ndb$CCCrˏofb|裏 Fz 1<:Ėmu&'Koo/;v0(CC48ޡ#0SqVf7UtҎm2skbZ`lJ~bD2䁬r5 (;ڽ/C2Oc8taGOMaV@ +žA 3Am1)8`v&40Y R)KD0ㅰ0' NjDtR(Z0qئ-IUm3,Ĕi* QB!d&v-L- Ҕ8D6USY *\7q'fq! ԡaQ}-RJQ\-Bb}: RT4RS}ڪU:4!={8S,\CTe c̝;۷s?GtoxOn/|ዸ{)ˌs10{ln6/^̮]{{Xh/z ٵ{9cp<h }!}VZTBD4_ Oj0 Me) “I D5cGk%QeܧBxDx>XA\'{Ns4OQ)3}O$gA HR h4K֚x@ +l@ +žaɕ&0kZ']ՑݗZę9NW i$"O:&VYˈ>q .deTewe`aZ93."onr$"5R8Q$y{ZQ oMyvo#phBBVJgϞ]_0s6_kNʥ2\Z{.:Yt~)ܹs93M| zzzPJcf͚EZej6oLmmmZu,rʕ2--U|RHGꢳ[AϟK.}vƍOuV<ϧhDE%FFc"  :4q&=/6eD"(D2]87֓qd!t7ˬ֖8#ʛ Ղ27# ϖ Qeu!T6mO$eUiu0tU*[ViiVׅLź + ]-'u~EOSzzLbrŁU]]bv)a -öC{sǗ)ʵkbe`& CieNakwlem's4!Bǿry + KVXa vre^YnoA{!gva֜5暭FWyfnZ26{0t 3wkIb&$V)u"h-wzZD6<6맯nV^͖-[8eÆ T*LNN%K3\Rڵ jWo~;: O8,νs|TD)Gi8\ $xD(B#] J^P)yh) C "p"/#xBTZJ%љeԷ+fN$&KR~\~9H) ۳mvT l E6M#hDlk4|3G1X3!w79@H(̓^b륒 Qssӎ8`#e.yX3;L{T*=ӏCkMStq1P&cJ2C Lk~hGs 5ՠX2՝Yݱ8z_Xa[ + +4t0w!؇Z GHyMͬbjFmD~(wtjfYxU=fhuژ NIk 3-(TF{&9>i@aUO^SJBJR*D _3!<< AyT-y9F{ロ 5k6=lJÇikmC Yf r/_s- %Jl Auؾ};,Z.:;;yϾ8p 'tCٵs7HС4(UѨ|yzø窐z,R(|D/SK!ԑb !;Q4$0rҋ`QJʀ5x҂|#x3@ ZE`\h^ $Hn&Qr=rLM4@JEI\$eU+Mds֚P%ۍ @D}zF'ќ`H'-8RprUo* ANrc痍ie=ѵ۾ #Uyq~)ON Q^P*NLQYk؄5 lF- Ix)"e91P69_*z 0׆K`iV1<$@NFe+f&*'$/qddzu5K\m&>)%g4J'%3ja!#C;;9HCtZ)3ܘ` s*z_wu +(VXaV3h3) k6{LYenxصvBRkMDLHFO]j/y1?<' [킳V2`+Ju'5I %,M6UGPҀ R!B(UREHV⬳΢M=Ɓ攓r뭷h"N:d R @לDWw's%;<,YBܹJڵkٽ{7ytuuLզ{3}BmN\䗩jLMhoo4$1)`VQHWMJςЀ!ި!ZS=T=f^miAu j04 JCo-;,&3ɛg͔Wq"Dn7!떗7m]#31{/qۗŗ*O ;ׅڶUqwqS[gN5K,v[m˹Vu.Gah7w_wu +g(۷喝=6+9Ï?wݿbY;o{=]§fVXaO0uL>Y+L,=pa.4lȚ :L{UyۚW~zQ?yf3Yv=_EXB  LTA OP H ^K$g\6FoT*h4شicp\(^clb !/_,;;l4€}7FI6Fqm- -m2pT*+e0 hA& IxA2UR-G}Pm211rdWUJ2a3Jh+K<$^(RQy%'b>m\؍UL36!kDWG=`cuر;իWs= V~p dz5H!ÆRV< :Z ÐO>q&,]5kNdݺu q-ը.J ۻu^Zeddٳg3<q{nyYݺF2@(˳5)9ݬq C7[G})ElvkR}lYB|_ZfiL]tgǞt]y:WFy;L] .lfUi甞6kޞ:wm-'aI8K7\ o N/x[ˢԶS_sԦ!)3'5(^s5 q֭\uUm ,8z=S6O{e + -|Hi7&eY3dGr5^tOSM b,UAŬ#3ſ:YR5 cAj&B ͛O\{xǼyx^FRa||^aѢEpB6o… 2JttsA.bz-bbbOe5MYLNL0w}ؽg }6W,g˖ۑP+_[/t/;B\@Uc,;={~7bN\xe:@&{oF̂lٹ-g&@f-v57a.ʂW ڦAum+lٶdn߻ʃ8VkwtBf^]neU„hnR,4A&mvžxeѽSڵ=<8mc({%Vϧͯ>}k%毗 CZzCi)Z /yOwOOw7[#gO kjO;PtUW]?yf7|w?>F*y}'k;|;L> zYUʔ|?㚿IngC;is.ѫtw!^''?-=NiZ.+x)\}Qrny1y6q+_=y[?/X/7o{=7EEeoxӶs/{ +E˨Q֚2f幊+\G ?<3hUTh`a*|.hE}\̡/TRJ(%WB8j%Z+x g,z::hmm!MRaɒ%(3wJ)Yh#c#y >sb]\+W"dΝ:t "СCtuwaFFF8䵌w^%K]hV.cbbP,]HPoʦ͛84DRK.f``̞;-m,X4!.\VmX6VX_U+T h044im/dΞ6&bּ.JA R\Eg! z|.8΂7-BHi\L3IPx̀MRs9 QL?2er$d*2/e=McYf5d'[vld4,fGߓL9aff]^y}e@`mrz> + [|FEZ5yM_$I\&s e-/:Kiݹb$yf^:N؆Oxlڮet-O;﹮{Wص !Bt+wk+Ϣ޺ =?chhꉯ}~8c o@גΏ{@ +,]Zs/ye K)߱&?}k޼g=33k? nbv7y;Gw{|2柱jz/sҗ_8{>:>ɷ?p- o;9?Dyko]C`|o_ǔq'eH:Ww}sv{>n>~c zW[eqY+v<%&ȇF|i LwC%<]N]s컋n4?|jawqSſ]2el?C_捋}R^ڿ/N[L#|W..qa'^K@ g޳anq_=o﮼Y/|WF8;*n.>_ǻ3| IO{]O;^7 !~Woj*zyx\Cnfz#?e&VXa[Hi0YdĴ V@l:.^F3 gBBLO?&ofwu@rtc$9}X_3I!A`:}z..=$I<{6)fxV֍B'~s/e_}jp6h|/|XZ|oݟ_ws#|[k{$Q8w>>n^v},_3/|Kh-7mo;o/UmOȻo(cas<BiЕp7edh;e,:,f!wpW Qǿ׿kb=qW R>qIϛ㡐{9) }nN]F/1Ե0q#y .3q-S/ r +~#L\3qbhhZ !G5SƑ2 mZI5 s>5S"j{av.!Q;䩠Y*(_B8 #f:' =i.RHxÂSਘ@(j:T0oH(eio( 3@ ,MbPS &'NK0T xuj52RCqLj(K7p0*3EʥՖmĘzT ?IT$K(Vxxh T*ϴ>ñtdp& B:'J7 ۗJ^O{ c,b%$&>ɖo^8k5eA7IH%WYUe9If}`b:=&<^74s%='2&f%OLչ[cV[=V>~YrBg/ևi[e](S :7t׳bEGjJ Lڗ,ռ嗿;y=gp?f2-p ^uJœf׃'9Y^};7qFV;\:/}!yDZF rMsc1i8yܾ|Ǜٕ9gF/{;8oI4?>|o`>+"7c_>&u \UTZrrZ;@N9ҭ>0s??Yg|eOj;y#{1Zzn雔<7no?nC ]uTCIt:nzk0`(`p`g~dٰ|:zף{'?4}j;9'= R" 1T\-SoK>™ +Ž`̀Zd5mfyj?UHC/lkY<73>ϯQm6Sd v! '"v5AY+gXF!X+"B*%ߧbB+ʔ+U,]B{{;;v`匎g߾}lܸRĬٳe/ܹs;5=#,[c9~3m۶}s(J8pV/_'azw%Gu7Mؙݝy5HZ*d$E$2ψd6~d0&0$0 ,!Y!QwrC?J ПUBl}sk~Bޡ={sNVXOFJҥKꪫزe wZrԤ>z"Eb82%gR5=nzNtU#u˝f,'T B7IrCpa):A9,gILLj?= r,Jm(#3M;g A#!DGnL1L+MDi_iJe Ye6CQrLj:+Dl2=$537DS`wڶ[9j'~cIйG#ۚ1S72f/ژ;rA/=U wG??@?|*ϯIKGz/_U c9y \KԹck_fi%/e2맯qgJV¶`Μ9i<<}|yٟmuyW:~?50Ʊ9 0uӃny2sDВ~/"AesGywmwWn*-֟m?Tp~Sw}Ioq#4 i5<=_<yJlF_!_[/-#; T7b|__'i`YQ|kx՝û60H3~Y]2dȐ!|UgsAzNs3j1ɐzSI":%H3BYPOV\|۪ ?R$eF#^"g@6? $KS&(PƦF7xGa˺xk^ŋٵk"{XjS*R~ёQ\v:::ظq# v"dt.cӹp!mȝw֭[Xn HCCMM,^܉mehH)WZm;\|ڵWVٲeK,C8/}%#Z*? mّP@)lKI cMj#,*Z R{ˢ?E]71.w-|qo_<[κ[o*7Ǯ|#͙~_GG;,4O̟W825ݢ$NVnǾc?ç>N^lq弨=O|sky佼7[L^LdRuͥm$+@X1A}'?p6V^}ML TήcY#GYje|2PspY/ykwf;+CC-;it3WsRSG= EKW ?|T8Y&5 >A>BrLCCB:::'LJ q>p}QT畫c{{;srqz{{q ŋBZaxx& sX"c޽ֹ,Yӧټy RBss }|֭ۨ܈<~&*FDHc` }|SHpLS+ejle p?2<&c7W52:qu zefCx4L~M)JT¶ԏeE6׆6&f0X"R-LI!D$L2^??zItH'^IQoRd- s٩6b"\%ˡU}$6jWl3Exy,MZ&P&獔2TI숴K{rŪ]vp'jSb>u'wlQBS~0Rr|j#G?tp;F\b.ͩRHXp-x'w}QO@ds蛍wM~|;=\˕ԣ[_~=W>u>aƽ T^d`rӹ;GOPo˯<>FqQϣ~,8H0Ygkyϟ{O"sW~cǙX>2K'8GXux#oo'o-6‹;n/>vnzϜyW|ӕɇ&ȇ7~IYcߝÒj_ܻ>J/V!C 2TPC w6嚛oK QD{٧> ڋQ(8SvU6q׈]-#QM BOI +SBWI#+tS4KR(ȑ#tuus}ٰaro~nSL+9OzjFGGmB2<2p4bɲt̟ǻݜ|yyoѣG9rQաAVXGett~j|SX,2>>LMMHK]dqo9ljc(2@'.u7MzNV"%$I?;jt9B=rq" &7l[%A9./Ljbd<ЙTY5 &$n+Ʉ#2TF :IfiKeơKۚ>fBd*NYL BL&m_Ī\xg#ꝏʁDj[̬ L4BQ2L\MW B%ed^km9=Ot_ VUlG{*H,NKY? ۘA!ZmF3Rlh[\C-譌c[rl jYPh%o97v~ݿ_ &ty,n-Bu۾ܺQ(/ pOo ,׹76;/u5|~.+lT?1s w[LLxu|˦\kw)?q~,|uo|{'pʟc9JKzΆ ox7O4w׽Og\Knn8>^qr˸n7sbo}|qͣ.^s˙w68O7,=aΝ\|хIyMmo{[TyW/o=,sc\s ȖpysO;C4}28zr!DOͬ ݾқfZ}P*tFZo/Nftg?=~=5YflT,42&˼d֝ؖIRj7DY"0A~߽- 72:'lƕ?sŌ T82ϖ2ҹkXXl5Hʇ붤M[XBp5jϼBYm_w }eV]Ϳ뼶,+o}n~{z>g:[ˬ)Kgg'\s ccc466.ǎ9Xt)^ W\H:V,_SOm_"NvnV<8=vNz*Z[[#VE=BPG)J S("Ӳ,*bߓ E*2BX8NHcj|>OVwX-RĬ+ByBZBSK#Z\>yq9W!|l2R8jVĥ * RJTZMo9%_ȫ~C0΢ql*`Vt\txApl''hnnƯBp]R"!R("ȱUA| vR= fzQoH[/~>צY=l4 S5MzCMR&Eh53Z7Rj.˦Rlwdxt q&Mdbdavhke=f:aVY!V+ SAEv.vfIY^k=܌, ZHs-ΐl!y/W{.jӯqO[l|VdȐ!C6VPp@{)ސF̦4m gJ&D]2Q*PUM4?Ye[jؤ0^U+32lvI )9}4RR8 :;g뮣Dww7۶o6]FP`l|jU o}a֭[TB{[]]wzؖCP"=rv."=Pgn𵪶P(@T jbՊ"[kUql\*GQȅ.B'z %I<+$rS24JT"iqX-wN KMvYHA?d!'؎{RɀZʱmEWkU"bj(*Պ5$%R):C[/({JrI*+s p IDAT5Hqdb8OÇ AĜ!}N۔U!N9A)ˍSi6RN5B~ڡ -ΤICsuS,5]fdW;/RA"Ol7Ni;L t57ir$1u41\VUB(Ҵф9f2>mnڮt4QkVFNv 1W^awS~hosO̢q< ?q/=GP̐!C ~Hf&557e3V_,3aqvl횱D{b4DL t֯۲LtFne=NێHܛmFjjCsdo}If``,Z{9K =zG2<4DPÝ;wqa|lJr ,)8@X+v/-1 /6 n l~@Sܨ^qBgկ hs_s]J SSrR1"Y˵ "jn ;cZAJ9s[{<(Q  TZ8" &0,DXF,f||y=q8v|{-sA'{GcCA04<<.ߴgyRj(Ċ)\qp!D/94I#;w#ݟY,,?f8.Y<)pnH ?Ӷ"?8oR 3徐ce 2H2dȐ!K ;C1`vW^Y& ;kU sHf6tYkp|^^m#O| 4ZFSգܧ7R%F'LVRn*ƔhZYz5|}y.M͜|֭Ys=5khljk9TUz!:,P,{E"Yz97\=8q8ne˖OP(ٽk7\x{'osE3?rznȡ#xˡejb.WOE]ȁXz9B<ʕ+9x tCwO"ݚ1Β%KVs=?qK.[n)Npyp1ZZZرc̟?;Xx1Yh+V￟e˗srǎQXj%{ؼy3,fUi&* |]vٺu+_W^.fJ%---y^Wb6۶mcɒ%\r% 7@Vcڵ9Ղd MfSD6 @تC`[O4y$<[X41w3VaB(US]3ILeQoԛi/}$W$'}IdJ**iebc;}f"ؖ(kZRfLIP|¶-|_őm Hf`mK'Ik9oԵ2C3Y9w28;6#C /2B1C 2dx X:&X|B(7@in^{ur!Q =fcc\$2%GЌ ͭ2bYjkfRn½~"x>6f?6Z7=nLzH_onێb nxi[|c[?7ۖd Wr a<xH`.զ(%,W qm;t̛ϛ֯?N~i,[ʯگ{!< -bʯ*n=Ge+qWS&&Ƨx. &&e.bU$֖'2^K/YM P֘VYf!e NJuXz9[Gow/;\[.ZCKK ms[Kw):k }:;;:=Fj2vü6J%|gxF\Ҏ84hhh`ҥ޽e˖k.,ˢ!6lRe1 xg9s) Oo)&'8~8sڴy+Yd1)O199>òC 8};ܱM6qo H _@DJb*]nz Cec) Tb_T[l;@Ho:,cB RH9[*#xh&hG$ vl,bufVmVe]OݣǷְ,,;ܶ繑zTZZ}?IjGMy$r6TBsBw'C ~2dȐ!KMI X)db/Mx9 F ٧mY /MUN΄z(3ϋ&>U}҉jIF*Mu&]4ܾHͣ>ʡC8~8\^oNEl߶.chx[XKS8 =]FFFYlͭN9看p :cڵ*r /Xjm`1wnv&W,kcxh&>$===9r߽vΝ˖-[Xr%GÞv144_Lkk+MMM mƢE4eLLL d444p)immgaʕ϶[zV1>1 211ɍ7GᆵHSS3 ,cݸ$Eyի^<K,aΝLNNo>FGGkvAV/RC-ZJ32<̖-[سgo~󛙘g۶ml߾rySa[֮]˭Jww7_j5W|ӧimmapp;wP.W(ˉ,yU:&V#䗎?&ƱDe SMh>;Q鄲e*=K34Qi{j30Fk>۶!$&̰ Rދ@'=.Bu]aP[+L%_`Ed&*$_f7ia=s^Ʒm&&&ٶu7k׮Gö9uJ%`rr۶innfllCnBTСCyN:Eww7SSSt1}穧bhhB>O!cjjG>&3>>Ncc#J k.JE&ymr9yҥ[s],&+Qݻ/"ovE"Ν;y'ػw/Q,cժUttt]+RD\^@GMk er9#G҂COO---`4Gz{{.ccc %=== $KZZ͋ȩD:OCNHmw6[w]uMԖ2mLw >svm4 u܈iRTEّ1/|!"2K6QX:^HPqj)bt8=m@<4k1=4q&E2dȐ!FF(fȐ!C ?QU7[^}`2˹i@MC\O:FoُԌ:K*qvi#T{^l27b!ǑRd&xZ/`6T+U\S*5s{illasxghllԩSuݴ47GsVFa8å\i;i֟Ŋ}'|Z|ZT*rSL259H>_Cr"1Qd*ccYCC*$?#G/IJl,+ZR,]ɮp yqrNqC  |D  QD82v-qN?RJ>KAf8=44$r9qQ.)295EP$S.WB+211L_*e!__z֦fVzU} MS]oF5˜igV4 Ђ e4 i:%q"duH19iy٧EǥJЅ܏IXʥ]C[Mer]A*̆TaD Gg2uMRec +Kp"0܄m*j^3߂ 2dFF(fȐ!C /1MY[:s3a(I҄ &bLxhV$3דVיg"ogcfȈTLoÃa<0 PNO2 #:H ft7B*W\ASS?xӯ5\ho 3?w2wn+}DZO0gNo?>7oeYd +Vs!ݧkٽ{7ˮXh敯=ݻƆ.lٲK~ػwJ*26e6>qZ 'Ea[5 5yr9E zG*5}?@jBCCUPjV86|j%#5T%!uCؕeJj5zV]׍_]mxr:3-^ q( LN*RP(MMMLNNR,"< +5vcTRDRƶ,/.B@Z柔~4g P1C gB,ᦫzN2#L`󷩎3LkYLkjL&v|™yVyn*@B qZݧDS6Z]G$UMX_b,&3{}xesN*>(ɱ$lR*]ANKllj܄-}NxnkR $i+Jc[}dȐ!O62B1C 2d!@ T ohӛfHn͍૧ߥa%Q7 nCTؔD(o :0l?Mf,$M7USI!.K/exx'xK_I[[msۑd֭\u՜=|8"8G̜9lܸ 399Ś5kbϞb _噧7SVijlf5XͲKj."}U=ruֱlr֮^˽ 7#<ƒ<8 +uSHi2(˩2~SSSj*B!AhRVQ*~B0:6B> 7}*ar۲Tc!( 8CR!c6JbF:M" jbRJB )t]|." 4j\.fCkmТZb(5p!B4c!L27IW#M:~$L/(fz͵0}:LDlLcj16}MLm\5 E}>IǂLBH5k9ꓥM&ᖶ󴛯~>f$nD9#bK?bVlWP4ݻ ~HG{B45 2dȠ#W~}WJ? K2dȐ!CFY'Kd=R0y6I+F;=Sjc+4)8oe,jt&ɒy&fRr}I}TջސkhE)UZL"vդpbSoبܡm@JI3$ܤT귇~GrFFF顫Ӝ8q۷MM8q.FGG9v8g||G}  ~JetfΝ444`FGEXp%H(ç9/bHw)֮Ywy.d r[ne%^=I3 TLpIcfzQR2OMjY5NbT#u3[}?JvbszmH?HYH-=[y' ?|<َzX:^ahd۲fRX+!^bsJ,fϖO/,W't^@%P @y(ejRF/xLu~> i~2GG&*FpP0!Ï2b 2d"9N\3gƛ`&?͍4rXҊ6iPɚUombu;=Y.gz3o_$CHe*K)Lr7WumC)TYz5&6Ͼ}سgAe޽>Ķm<={c1 .rJb&'{۶m <*aV%E{9Z}~ T@1Cw}v Z @?O g 32+rQ]8rfքb[%L&, Oeh.ν rf˫Ih,&,&s IDATϚ_uڠ>& )~41-]I=iA21sVMll#'BDct bRzS~_rYI&jUe}8neh5lڮKWOM4&Ϸd8tA!Xe+Ѻ_Pu6ى9ĝx1+/Tѳ$0XqOLp ,"o;." aYVFǰ{;޵e_x=mmBgK.fȐGPl|<^'zY2dȐ'6i<v2bjfoBŸJӚJٮK3>V9[H HR"J o>) Ũh"$yl*IEujQ|J8cOeꐲ"V / z|Fdž#wk6[P|5Qug%4F.lhSbܾi=yoO?3|?sX9Y}a 2dȐaV$H2P2i*0V7iRzJm3+=gKmJo땭73=-&'_TNkoP, fJ!mZTt]OGXvieITmM-İ@uHuqD}~I&jJI׏idݒJ΀^It,|:wft[~ɭD= [_k+D}3j:bgl.^x?BTṼ Yj?'c|Ba ;g !C=^B?<7p}0GK $x"}X׊Ĕ:fe<^s q]<7غuC=Dgjj;w/|۲p]wv*2SSeFJ%2|9sp Gj-L" R4U bpDDuqlJ%S"$|ߏ},$mķ U1)[ߠ\_PXB{yx\93`zIDJLjC0WD,0cWӕ6oj|Ӥ!*¤6!#AI1,aaI.@QT%ZQ)0\oU}.E{؏Xs5AIH:cHc MZ,<$<'dr!92Z|L%Ҕ:NA< mILcx`㻙8Ga/ mԊSad3@}d]HHa]JR"}U kP,@ B;E YTh%^Wfܴ2J%Cmh[GCJߙze˻e Hg83"O7oAdc3dq)=]p+[=)y7><_D隸|1g6u}}'wHn|>3#ܴŴ4C 2dy}>3FhHB]$0` b1l8ˍcfqu[bb_Ɖ؎ cU $mhi6hszէN!0ر}^=hN꩷}e2 B/f"|4#/0G&JW:ME4'B1\FǪm:WYlPai}ϋU#u)V ҈PHW$CI^ 6BCI@R_f%fٸq24͓'pBmF}CB.<6M455R0uT֮]Kww7oիWGӄI|ߥFكIX(樓kL# }=GJ?"2$JZ:n0J-$AQ$*$ s9" &d$TaGz\hHhb)d، M+PUs)!CuȦWSQh7Vwed$ɪ72iCPTDF/)f<1P_0^^HPZ#|#J^h2 PnVє&:gMNŮGx3NΔ{y by#1^CSQ;5yƝK:td .*K 4a&ʫ5'6*d42)Iɠ!_kY굉RA]lKPhcbCi"z g7$(`-,&}!YN8cq"B(HyfCyefEUUS'OI34:JK1O]]ï[bM?[v3T;םP$k-c7lqY;ba_]r,;r*rFם_!+ *@/BoPHE]-ʛďte5?Gі8qͶZR,6^(tn9EjP?KIH۶szA5qL:I%7]²eK;ٿ?\s5\wz:;h[tsȑ#\rɅ/V!se޽LjH.eҤII.d͓<;v1ktvɵ^yXyZ9n6G1P#lh*L5>"#b}^q#ըK[c'̗f[MbPg@eTۋ9fSpf`O?dx5rDn~s}3_Ň6^·~',oK > M7ݫ/VFe> )JTubC~eJ?]F@J޷i4 10u< !mlG8۞|mO>v+ *u@|t[#,WVrSIkO63vAvAM~‰7#p;mϩ/f #żuB+-e"%d2A*`Q[k\ȢEB՚d90c Mk:u*S41k,02:„6m465y_0l6GWWG[[\a̙ΌYU3)IS!( %jȯ8\׋ [LBͼO4t.2"r$t-74"?Tg?Gj;#44N:4#<\Q~F#6~w?r}r/@ǺMMo3OD-͝hx1BYe]Z/&>R{IzB|oj'~完3g'~(R;>)wXyz~ %LKaF|+ p+<{J ,!0}SҿǍo}H$(#˘qTnc՘k'J!L!8U` -uqftc;N.폟O\Ii# BOK нw2~ JG_(`ԆR?6K[H 5m㑌;OU}I͹W!_|)癭[rrrgӘ瑨cތ̚1S{LJ.); '_^8 |+v Oz_Qf|}=#cO¦x wo9>><۞9ʠ.ɘ%BO8_n>t_+ *`.a1p4E1:;y'(Kr0=sDxٯHC 㑊$SDeaY6N" ,\׏BM\શ"r$B% R(af'JHW IX"^ڷS`9lO=$daoNMM V7]NWW<rϦQr ##f<#P Jy]]eY<-H&|P1  = uNDʙK @C@ %hoWE2>2!Z4Huy<ӣX7QTj`MM%dg²BknjFe)/s%D5ɧ+b|L닷ۏ'焌.3? Q^\g'f}n&~60)R CK*#=/daPt(KzeB~q,~-KI{PF+"{$MgcVJ<$XaT@"}eHN"%8DfBBT*ވ|$^,p D&-wBnv}Γ\y:'7#w0esOFJU/d)\cY﹡{~L o;䖉{Ɏvoj5>gaD Hv~F9ȿp?ǪecUy:}o5|;<g:aVb}?6`7/~ _Y:l'yo~I3<\7C:䁑o%='o;˫\^Ƈy{+x5U^a;/ IDATF !g$eߞ}0]%WʹNRz7?ܾ||6屭y"A9̵~/7.MO~j\]!+ *x`.ʅڙSWˉ/ .S+FĞavk/^)yL`<%b8*VzBFW4aEB$aXa *mm?VW >MMM$S  J4i seqrD;^{ 3f̤P(>GgG7tvu208H2`ټGe%L:^P6.前9wf{1Fq <%J86^;Q:LRa`bZV$ =&acYAlJ/!}}fc<>a[>=!yjyUP4FsRc%(JSLۜkЪ%}P,0+G[R ?GXycT:o9?g˶y7u=fLTAiu9eYo oP%Tii^_=zBQVKc /QK?P},Hu, v"S#uiMqKWDZ 2=qhЦI:'{b&nMh)ֶeAW !SL!M3y0R('m7Q?E˗. ːeY9нr k_K?;-R:hR@wqÂxdS/7=wNU> Q\wU|$G6s-w1a5C ޣ\_ca72sdyxI3>o%z4XTcͼC7{r>,^Sv|8I? KX {ϻU -]HcZklfvo ,~e60!쐚t e x,RL807;7hçyOr* *W025JTyF~rʔgUXVgQ\XK%Q ;J rHQ{3L3r$j<5~.H F(*""c*ON[|~D:a ;25YH ( XZ&-5 ŜxT^w W.G?۷1iRl2VZtwws%>7 X9q .6믾%Kr+SUUźu[!p]7QNLrdkTnϥ*;fʓ!#&bQѤ3e¶c!ѵ 6ϸ9;^ U4VǷC'.?p_ g7 %bWG'"IXI3衻 ʧqmJPz> {v = )5WG}¶Xeay\UE5C 93+ __@ * ~_b$d .X$< $Y2Q)R PESSK/-xjSXӽ=̘9T28r9r }< ,^K>?ϣ0Ԫ*ؽ{w7^;o>S4m[QD2ٳN2+T訑7RDaaJ UezZ $ux'R,mdW!*XPU1"2 Ba PDHX1VdTXHҡ2ʼWCD :6qp<M˘kNT-˲#) ´j۶ZfzHr{RyP}/my>2,;Jk!t{4+.ۖH$x~Aı/5 "*$Rui[juecHoA"! H0w "d f3kC&!yϜƛoySZ>ov'?ʒu)z:+<ʼn +j>9Q0ucƙfIC;Xr_2eLrT<ĉ7asωW_z`nX`?gb[K wxgА|<\r.8+$G '-*>TPAnB+%.0V7C--cϢT(÷]Pj98Xlw,U}Qrm~ c|/R۹ dQb B CţVTa-eCާr O*.J-w6mzs;)|%H144̬Y`r`!ݽH]IO~9z1ؖE2d۶mp¼Ag_$XLDH@˶-+~E&s ٶ Ķ,1UJPbxo tNJ ʒ9ՠ{0{=?9oko(_w5#Ow_X/HmyxXIfL̑]yQy?;ygy\xn9ora-L>C{`+9Xo[VNN 4Z[ҽ+_RkuiiKn睋Ik ;<#=+9~߿^C2/׷0NF(@w *q4ʨ 4oB3IX[+\p>F+`^-SOR}qT C U&]cTf(uEg^e +"B"<<̇(za~j6ɄرcmH$硇555L©NG8q"lDgg'XN"0d|_>[bhhud2ض͋/'ϓ\f2$I<\6[(jr$dJpfq)LEWZkTw%xWqx|E #Ԋu wHg{+s̓C끔aA[*rVhYf[S|h;,5kqqF@a(dUhkLN3Mrtxy]PFJhB Db '(__(JƴH,)|D/4Lo%)r#\X:8Vd^kǤ͜7g۩?s8 'q F #8DBC_']ɧ> _p?]Eïʁٗǒ~7O]옵?UO [ʕ *7 YG ʣg E~H"Ral#,aa# p1dhc1j*=􏩖qbΩXy:S"PJO CSe!0-rFs!Se̊ыV"CxmI"ؤ66IGN>RH,F e8 )#~!n>Vx $l بPiݖ H$k0i MpR)'EIs`5յd3kkIrfTVѶ!~_?ddhre~|~'7mzΞKq#< I-Bg=<ԓX \M/`Ozp>>RD Tw*“>># Nw]\} }xAy%myRTxrGB`%!`e#@H<+w-,G%HKa+W e@sIeHR; X2q}@Z`'lL*;8I;Tv",,!@2R(Q_D9H\%J8w(y٠]ڥi RHXiIE@Ba!$% I'ps +uHCxض $ʽ~ttDLc')|,+b$3a'a#-@^ca Wȫ9sIV4{-+t=q,c Y ^w8z8sF@Rm +|. ʿ*%UEu]lu=!u(H$8"8F,C2S$SI|ϧI&$Ii Ҷl<'Nw ѸV1R @ {(u$Jlm388H.l6ӧUرkS9 MYPUUŒ%Kؽ{wDfO4([dYGHӜ:u*Nʖ-[( L8ɓ'{nȏ퍌c,|^K(gR  #}2 K o?4|/䕚̶|>_T,KI2uP%DR5!>4<"yúl( r91zT'asUTB!(BLAc! Nsl"*= H2 BѶm.ad[PTL%-T:B@&#Ѽ2L}q~ۚ>E#dCWXa:y\Y:ߕFUmڵs3&'H|__pSo|读B(VPATPs_Д[p8y8zra%57-olq㓩>2\q(R*2p]l0WJ=Ȩ wb)՞"˗:%pIzaݸGlެ[M6Ppq}T*z.GG IDAT!LLΫ o?BJذagf߾}n˶cYw'NnϺuDcжqy֭[dܹ̝;ٲe b%ILd2k.ׯgǎ?~RE͟?ŋsy^DVimo{dCSOdRK2ql͛ض͔)S룩3DŽ رcK,aŊlذ!=7g8Ǐckx嗙:u*k֬Çs7k.:;;immG?Ǐ@Ass3\s W200Dss3 /_]wE[[ND%9 fvJa,C@Z;zmw]xꮧપ*?Ϲ5kMM5d/sQjjʑH$X`>{>eYX.Dĉ3f`Y<^먮ȑ#\zlܸCfj::NqepϏSO2%Ln@"ٲi.r! ajwӧSWWχ?\hjjd'Kk׮eڵ޽8piӦ8"2u9z \ .!/_Fxf rzrI^xk׮P(CPϚ51|6l@[[5s{nոKKK 108D]]-k׮"ei*u xYn3gg%L0{l:;;( 9rںj}Q̙C&ԔCtuuMCCB:q422̼yؿ?;vﺅ^xB@P`ƍ,Yl6ˮ]H:Ӫ;cHJKPGӊE^ʑt&Mu2IWWB2 vJԩXz1Lb;l.ld2dDZUnHsߩpZuY"8 z?΋/)+-_ƛt1DCC⪫bٲe ;S/4q" .)'cY;wIJm涶wI&Q]SN__-<1ͬ CX)=fLJ %4NuIr@rUU젳Ʀ_)UPA!*bTPA0Ñ_(06zu1.jn]xH 1\E;UF.f6Z=CH& Yt7 |M4F }Q[>#*$eڢΝ8iD"e2m*n!H=G`Yg L&{rY-ZȞ=aEyz{=y1.2N<ĉ9s =Vԩ:t3fș3g<_bBST_|Xn-[`֭455q>LKK TUeBj{nf̘֭O֭ G.$³/YGww7o&S__ǩSQxfs$`dd'J8}4mmmK?~3graBqvmL0cǎӧ&NѣG\\.ѣGٷo//2Bd``}N6CCCQ86}|"088@*bl۶cY@)Sb244 7\/p̜9^z믿| X'X*jjپm߿|}Movy8y$ۯN8:jkjI%̛׊eCvEMM W_}矿ItRn,Z \vٛxfNoS[W{kGgg''L`SO3ϐL&oի>M2et._ԩS9k6S=$S zj :V=w. -`tdd2/c`pq bma>à1 RnƶeKè*Tݍe^! [A)\ȥH'4 @GT%%RzFaĔ,59HgL<7doWfAJY_lb)̘t:T2mTzN*ފ+9co}/bY6)[f9gw*\SԩS*4ӱ?s~ﻤ3)Pp 8?*NudϞ= cvet89?@.U`OCCC |?8!\ 6022?*:†<|0qȈŶ(o)SX|9<(e裏FR*˲r qEƍ 6,Yc=8 |[z5455Q]]OFF0ӧO~f\;v 3i$ΝwҥK9r{/ArJ+y衇:u xϤIxꩧdxQ\G6mǎsݻd2IUUWapp|>O?t8êUhiL{{'\ ﺛ32.g ]]]\3}}l޼Y)7 HgR qk.N^zq E x!zzI:]]~@{{;//<<===qRviﵣΟ%3V67J@ѱ h5`ɜkOBϨ\&Ce/S<nRFa҄A6n)Tغ2 <?k+bT-XT?E* cQ82YĮw3a'+=+UGkjK&ÄשTP XATPAo [ Ǎ}O8((ʅE0SԐ"\T4,W޹*8RT_RH4u#S!DXj+B3XfDI74x@"TWWE;v(svڵev޾^\[L6ͩS'>ɓ'q]_ȵZr9y'hhh$@OOUU9&42o<^|V\AGG?qfddz9Xl۶Em\}zS#Hf455qsw ϳ|2ؼIâd;ӦO#Ns%yfhmˉ'8$֭KE֭[K&43gd]dY>яH$9q8[lf˖qֹ\{5Q(9shoomBvg?r }}}-"ϲeغu+k֬A@]]]2{l̚K/g֬YtttpEill"+o}+@hBxH)Yp!_VLڼa,.ExG>|i&>7 ̙ܧ,X ^XRiWzc88dP]U/wqR6mg{a KY:KG&)WM&&kbQ1jl[l(H>SNqʜv)$|x3,[lq͇iooh4֭[I&DQ Wڵk5 M3eXo/2zX>^wy. H3,bT2롅(X'f1TuX8du] xRuEQpzXδU)S+DBtdF,^8[.BgWӇsiXi9 ƞ[6#>'O= 2 ,SE;gș8Ad1 D+Ei"2WHO` }k(zAddZZgq~ǓVZtZfa`RL~ M'L`4eYk*=&"$*SQ$ DKA3|~]n PTTB\|ܱ/+~<&L@ss+ >={]R>w۷oGQ|…g!I2۶mcʔپ};<a.rss2e /@Mhmm FMY N>dV\Iqq!ƍ㬳bl߾ Z[[9aK1}%%%de4iTV!:@X,Hqc),,j(455M}̙3;˗3{lLСn/Æ cє "+2`11(**BOE2Fgq:;;ٿ?{\~?FQ&OLII%K(..FU-4@GOOmmmhFYY9"$77lqH8ftuvb&kVTTTFG{zE!Lݍ?`YQXKdPU۶\S7o}{EM&$"K475 0D"_oK(v0%uCA4&EdFjwMI'B0죐soag’V48>']K`$(~bh?Q01t۴Q ڄ$hcM/-K֑LOw~zӠrG!+u3 2FQU Re"J\ 20yUs}vG mG󩯷M65m*pCc?(`I]WQ S7FuYח D# k:i&膎"n4 4 D{",u2XBDEQTEВ*n xACz&LOyM86Ӗ7*h&vCÎPNCg,%9m6T]c%5-zY[$ D]5ݧ"I Xh gl[6`n}'EN; O 2 \CŞ3;u6$( &lmYZ3Hj&y9'Tw͜j5o>t)/psCtϸAtRTTtvtQPPL0Naa!+?\ɘ1cضmee444Df-{1JٳA,㕢"jjjXlV*Ax9tڵM6L&$ G4uNa( cƌaӦM /ՍcDQ;z)EMؾ};uݭX)k,tvvljb#I---nm;C9|i$ 8>Da&~_RQ9e_$LOMMJ/LBɴ"&䡇"ۋ?`PY)`6jw3vX{z#̢\ ٶ}xZZڸ瞻]IQ|pP#e刢D[[xx<Φ555$ 3g˪U+zOgӦMǻ B0h LӤ{ɓ'e?GY&itXIx@ aTU gHe%駟F4Yz5>U3a& H$┖cY`0HtgP(Ȏ;Odڏ ٽzX.t]g֭( N=C׫CB9$Ib1VZK746Stuu \ѩ( X ߏ Qh*fA HXQ`\JUӃw2 EѪ))D#۔"C%A$7]豉PVaA8!d=;Z61f}ǁ.D4.t}X8Fi` }Zc3 giy`+xq麖jz~DUS]TӬK٘z!!Gk:"YX՞lYNE܊"K{5_aܸ,:j=ML[[Зx⍣4ݘijԽ"J5zb`ܫ 8l/\ՠhSha7 [m &,wHAםٛ-"c9J$KjQ g4M 2 3'W6%(X;$ ao (1,/p b-ǫ;qsSB)&}~|H|Cho'FN%3.߻rcQz\>76_D.a\ \xun iI)9t&%M"}z.)Ħ crB18'#ؤXeCV% 'ĉ?)5+z1"9SE4 @]5'I҂ֵEADEwt]GYBԃO."f N7u MicD9u9~.(!X䤢( sIfMfAd)Pc669щh0$u(ʒY=⚟|ݺu9'f9imgʹP~&ald+o kF7=A䦳"^> ^u+_9[.;β^ @k||Y@Ӝ8n+ȏ4ʃL8x0 y_0NO7]q(|mcśxp\nw>w~g s)~Z[WPXoYu I ̛;VRqod9)+ ѹ;x6㏷7룲a &k^]9K{/Å陿Kߟ;xq`ƕ࿲s2O]҃s?@s|bR] ܹ 2\ޅ@?zK:I]}xi.oy!8P@cvH#>Ɓ`F8g1l) "䬓r5ES+QZŔ;4f``^( `b,U J>wW^}5Ͽ"r X0L{I&`G&>`0ȤI'P:q$4!C* 1c:Ǐd߾z$EB&OĠ|6nFMN0@f=8܅ST$F?YeFŴiS:ryw+9r$OvBZZ6tUKOי4q,=h4ʤI)**"jD{{cED*;wְv:-ZDAAn)ѺSTXD"pᙂU3 ڪ5U'Nt9NX,(Y~4MCQO($qrrtc$;&TeD2$C{I2>H4MԌb. (;FU/L]G4v@Ovv{c1 I$444 ,F"pTu]'&CeTCCӃl޼i gYO! sX5΅}h&S&ERDb(}_GEW}+OD7k;j9k"X3 2߆ϔw0 fҝxK7m2р!! ȒHR=@ +H'RGMB9 m /P]ⷊC}o'Ʃ~X1{!`@cQs9?+V||gW$3G37vA>5n^m? E`8W\8_ӹ|vE'2}#!Gm}o~ʇsy-*,؇ݒ X (s) :g+'a>sWjS@ػMޯWBd{x^f< @CC흌5?d޽d 6ܼ"|LC!6m…g믿޽{֝jݺuL4..jReL4kZ$Y ѣ6mO<)_cۄ ܹD"Aݞc Y2v܉ |e38p)YYYD"Y!Xwg+$I";;h4(t=4"Ԅi#V="ve_tT` rrrAurrDQp8?JAAek[dNNv`͚5Vw")_ΦM5j$x\y3qDC]]h &0en_J<c1\/PUUE$aǎ(>+ 6PQ1Ʉ غm+~ŋ#I6l4 f͚9C<gϞ=k'YhUUUl߾|DAY)..A}'Np8LUUp-[0rHΝ˿ۗXcx4M .`ԩL:B-[$K$$SMeq4 ggH&=g~Cz[ZbpEEL>]X|9gLgƴ,}=u$Z15M)C& 1K֥чsjNN &UWR ݰRyE}c:i1= bd7C'i#}ӎiϭk8䜿5R:&kE;+5yS"7?i`Ԅ(KrYdtUD@ Y1g-] S=%zKd($~짞Vg)s SP~{;if=Kc)'Y?YF e[{x緸aԙNp~캑'l8$Q( (! y$ C7עq9&QSa Sj$5 S0E͛7(}<77םˮ.0Mh4Q쩵e?=IWW;|&dYrk;^s_6 qYLz-̙$IȲ:t+V~H8l666rg( \EYY444ܹs1 ̛7%Kgɳ:d05kְfӧ`[shhjd„ ,_%Kqq1fbΜ9_)'#cǎFe^z%:;;9r%%\bKDW^FS;cH CttvPYQ,ˬYbj,//';;ѣGA2d֭4i$1|XUOx-U(pyg`۶T ')'JAȢ")DzzpV-Mfg#K2ў1MZTU%??+Vp饗M]][ne͚=%K0kl*+%T}֯g|b&wbԩDz:عs2u:{-9:1VD} l@0Ltz^tz rLNմ<^-!&z<4r҆ @S?(ZغY0 m'=&/WKyMDJkyk Mp8Cmvݢ @Z >=[sU\Q9'-IWFA/>sBqm!Ň*C3ZƯ$ޮEoG U|y'(osG8%~E 6с\PBQ@d3<\ D"yxd7sY\X-9OKW^#9 Hm{IcՑw^_#Q%=`c0.ȧm7; F!}eH`֑22 ey:nC߽PwD~u0J~[1W{M0opqo뵓‘qZvב>Gsw}9x0Ća0'Wpƍ)QK 3N8q;_g_4 #F&\x7x7!݇i۔AKW|887?^}36(oO/pt#v^#z;no;Z#$sB׸5a Uܽ$ah(YL5cF`=nPZZ{$|>CuVjxǘ0aow" rr9 b߾L0䄜\Fۙ1k`RWWϘ1ٿ?cĈ|GTWWM7Dgg'P .dd63ضmӧOtP ET5j$N=Tvk1 QU#,\ilmfMEEg/\iٳP(Dݾ}̟: ,3$ ===az`"rܹtu3i$.]֭[)((>߇a1nX**ug}2r),,$ڵ(--eUp˖IQQXuk?fɈ*4Mcwn=z4| `\tvvj*JKK4<'wEiiB蚥p ׳uV6"2[6o!{N=#K2{eʕDQ:D0^`׮]J"t s7( MMMlܸ]QUh4ʝwI^^<CA4U՗^N2$[tP{z޶b G 1 ,I~NW!Ɇy8!e1cK3=$hY$uoH_ sw.Sc㶜ާ>';J$Ir;EimG[T%u.^׹8d[JMD)m6.x"AhP 'ZCuWQ7G3 G\cGgn;cY g\d{q;f?9EkN?XkL)48J-f4DoJP#s0rlz |nP1 3wW}|u~>aܹ, }SQs&_o^9~d`›?1뻏IGdl3+~Q.*/ϯ?}]0xY~hs1rэ1Ry{x?r-?i4$ zNrO_\#+{g=k>u2?7o]Q3@ш3ޯ?ByNο%o.W| o;CF_ŷ,㖫~3of_*M;׳8vgMuZzarha9)KdY?uE}0,x Bab+M(L'LER;c YH߫xno6o@ v$,{.ӟBA~3t04Mb0@={RVZN0dmB!:;;iji`̙ZZ[Z)ˣ2rsؿ?pYgr/KP(DYY`XqGG2rhN=4~i8C q P4M#!"%%%~F.H$\~D,FUi"˨6I(>L' N2$#;"MXx4\+bV P=TD,<<)sH"(!3~;7MDMX3 (T]Kfڦ9N1SĽDrRa)iHO/nKIUS3=CzOVmzx(á$n/A(>@oǫ\Up-{콟ykǐ-ꘚOQIR1ߴɏ~"?}f S;؆ [g:FKfiؾi Ws{}{/?eG_1wk:d?\^r/ Ā$bfE\] 1UG7_8pd"6W|?r蔛yϼ[~w=7|ΐ`60{S 2_*@iN䰅bz[ _:?SI;;<dha"*.i^΅]EW"D>E0v'ާ"9Ⱦ{1b à%|>\SSC]] H$yGlg Lvv6YYY8pEQ~^x2`Y5xQsU_`ժ\sfInʖ-[xgmEFaaرDQdceVU/$Yq7q15%$W) $z0l0 6܈d˖dYVҪmN8932ؐy^ry|-u]bYlx)Z[Z'L"C-B%CX9rT޷w/rpd2:\.Ǐcnv,A(RݻzB~۹f `ΝKPժsnr!DjmۦP(P.pmBqtT:Dd0A"VcSmۦ)2P*.W@Ro˺' J*u>VE/5aEe&H2xҁCUR U-A;oGQ ˊH}LܣV0FzuCƵq0 ?(J=5T5q#2`GQ\EIW{kwb}\f#!#w$GwVc{BJ傭S=,}m]K;Fz6SMeJ(=Dz PR ej?V7*߼y;+@ށm:|=$;yp@x?=jOl/|駬ۗÝ^zr|kw0^O02/>F~U>)_k\1n|Ӽ]}67}\ ?y;}\?[xV+^-f9Mϳ7 f/|#曙s?q^߾7mEs₎vJ#Dܗv_d 秿}XX_`-j S;o+%.-N6ԈFdQΦ#Z:azh9c:Kx<*Fs&L$oĮ4ȭ'S F.e4ozRHi@:VΕHDdy_8bP,,'8g}6Œ37oӦMchh hiia``ۊB`Y6MMelvq\8ͪ bZGjFc<DZ5bǪU-<p)PRe7iEڊj 7_L'||幻G̾ar~g=FQwO6̉7܌ޯw2|?$$Oܱor)ムuyȷq b.@0p'|o:d}W8k^+~V_Ǜ:g!}ӧ鴔4LGOMF$0hd 7m~_풦?VшSq4WΫ7!>0(JQ6jpvڨ~]ozm ֪2c=LbD)qBIXX_+bhCJP,cՔjgA+Ă,2aӜi엽m;v0p0N2SO /$J`xG7o.]dpp3fp㦛o"H΂ hii$ IDATW]N2䳟 H '/r9XI8ybS̙R2˖-СønfFGLxvDZ3g,[ g9Q,NJR"-/#%A(艀a, ձǦb-V Ljws]slƮqP Ƕ_0l^ΊŪQyoMdJ㵑LT|͉caxG_N+/Ê+ %*TJj4ltzPf Qe0QC#~X5y!+e|򇸼T"$_7ZXocwګݸԗ5oでV_Ŗ.u%[ٽ82o2T^tN8Ӧ>ΙGN >5́;kϛOyg5{4b#'Zh=K ؈FHQxՂɪZ*^v[@ZsLj'JSª x[hIemX>l&j( A;2(WBIJάL@hB)e\z®LY,ǍE(f4a@2ċ҆e/V%Il<;Eqb(!:&Ʊ}J&;"f1g="QHs} 208Y].q|4]4fncD(61\JS!rigXngq˗/axx#>NP` zJ*0 56a\ :TfQq6^˲R2{>R(e}MuZј'G`2ǂ )=CXtEO ĵ#Rt /j,,&P$V uFaZ#?0-+Nfe\lߟGm?.MS^^΃kC O0uTĉomxQUllog4|>&3e>p,Lby֟kgNmhPlD#шF4%zuԲJz[`*PzFUmLARz.u4%IYWVզ/ラ;3ӔIȀm[G?QR):;;f bYs!Hp=q&:;244?q&M_ĦMdӦMR)ϟ?O,L&͜sb摑rR D&!SL={v3ctNlvƗ6 |ٟ1TͳihqӀ:՟x`"@Onno7`}g7qXٖgus.s =Wҝ5'fKi"f_ FFKM#@/oGZ{!;~}.?-6E2k٘mdxRNhwi٭%rو?N4b#шF4,R~0'So65Nw +lN>ORYu()Xtg:F* ^TI) %BTߞ]$)5q^>\.WR=ϋگ6$Y|B̙Ν;`v\fƍ<3\uUضo ###\'HWQ pzk>Ɓf,Xp3fLg`||w;7044eYL+ od͒}W߼Yc63r>6D.(Z6 ؈F4hKZvF|2Ƒ7T#ڭUNJ#SYzţA U騑KT&j[QיۈjcPaFuP({n:Lks O8](&+Ʊml>KSk~|kEAmLhii! C+2H L 0 t X &(}Y.eIY."__R/yS%_]|v޿j;*/;7zzǿ,VY5{gx?͗9F4 ؈F4hK|hКIL4D ^ SKVǚO;s7qz^JC ?lێ]hmFz0d\dQQvE Cɹ J¾UW|>)}^Wp+&R+l657'9s&latRַrwr Xh1#]]3FNʊ+} ߏX#(Į]=,XRc̙ttCzLGG:Bs=;w~(Juٳ˗ԩS=}Od9d㌏OV<Bz0czyBOʅ!^6jrU)s,U- F.,KH)I{0[( axx֓43}tصkmmmL2ٲeÇ93h8v _<###l&M⢋.k:< 7/gdduŎӳf'kr)p-0<|LC̚5͛0<<)d?b1ϊ+m|>O{{;TGyg}o}L6>f͚Ŷm۰A~|=pwk.Bgnosl¦M뮻>4[ 3P.B0&M} X6T ˲( G8zǙg xGWW j*6mĎ;hJ)JL2?x@9[ d2ǹ Xlo l6+֦LBGG#ڵ2::_̗e-[ƟM|`߾}8իM/YqJ6nȊ+(Jy2twuo>nL&(/fs9 01>N <׺U MPc\OH9(UVvv"gJ>`ЎZ& cO%01[ i`Ӈet,z9 ؤ%ړƘ`aޱ,b3f5o5CC1:BXFJp=h֝jny5U<*$4POjW$q ڬp6 / zW'n[o% ;:hnnf׮]tuuJ'Q, oƲ,&&&?)%CCC̜1)'S,)\v\vNI6!\.eF t$ܘ~dԃJUhEJJT gZՐ.]|ؠ!YjRIZ)ySm!PYB0 rʠF]1qM|{~tWJ AVklFD>(j!"@)k U iPHɈ2$QR',z/C k;*hq몔@CJ@>1KsJ q?(#ZhXAn$#3ZبP]Uea!qG>9xa^\y\.nm!)ˍa]ŔdōhD#^h4b#шF4/a lFtv䓗Nk֬7 ̘1immeڵ>|LY3g'|vVZwmZZ2aȟ s=K.7UVq~|>UdYN[AOCG=JXU]X aU*[o_F@|Ԗm??j$ l}ߏe""9&xY/;f7M[ Jo~d&/jF4x4b#шF4/qԦ=_aHXdbbB+40ғzZ-u6*<׺gqTSB}~dc#@`u+#u5Q 0$bHmQ2@("4k֬a#;1“y,ˢLscN."Yt)ׯgǐ2 /-o,{Yt)}}}J…'R3ftqfN=>%\\-dZ={r="Of֬x^NZ&yk_+yffɒ%~izJLFSS] +_J^@Td2wfΜI"_׽uݻ3|Z[[H&\|qXw/۶muĻլ[e˖Q,fҤI gnZ[[R Hc,YB\fI|=;wą{-<͛fʔ)dɤbh˲hii!J8P(p'n::D>_͚.0QWw uY:/^̮H8 >|4e2;pQJ{z022-?)&300!ډ\WibboB>mLj $Hm!bAk!r R*U\3swVժjGTiК)آvӊɸ m4W)7QnA: 3 +/l+2wQZn =k||X"Xj*q*B3O탪#RknՎf-E (͚LVj5:er"erKqysx#?NiD3R{n΍hD#GD(6hD#F->"3::p}D"l577viNtWmZWT""xǂC(uT[HD.1澄|J)~v]4W]u;\# ^p1Y\'I&D2`e1\,1<& CR$Vb޼,YrٳÊaH,^۶1<<†N`ҥ8MP+q]iӦNhinaْCP9A)Sq M&N%tM$J~Ƴ9J"x𰪃d8f<̙3SN9۷o>nU5 x MƂ ؾ};>'t]]]<Ӝ~8p&O:P Y_RҚ`4޽i5x:(JaQQāQ{Pz0ڱXRQǡm] B[Dby 汘q`Ԅq=R߱O&VRK;{Q2PqDvӶdr#e 1}U)Uk?{fu0!Ni^XшF4O=^R|yшF4jz73B-rM6 ySJK[z 8t=(lN/Vۖ]vbHd4a֩Zh9c [I- h ?mDutqFy|BEXh?G3:2{)JtuMbٴd +ضm{.R,L&J%nݻ1|0&1:: l߾}ٶmT1nٲe ٳ~)%AlRaÆؑy޽xr,f( L2H$8tb VMHLY!lV}+I "AA )HԔQRP*ضe+P,IR8Xx%nnd1^'Ӕ!ˑp *JXi+tjȣ Hf%je(چk1dBcoucs=C9Yx ժ đ KK_W)[FelA]Rsa4 RBCjUS+>YF8;> T~)Q a Z} K=}fj&5Mt *2~gZhD#%}2}8$՛efޒ?t<ć ~6煯ΕW2Eo[#шF4Bq)섞SURt E b.t۶cEW]/&<|#cʲldXIH 0`FD (u@He RHMԊaR=A|>ϏnlplZژ>}&6l`ƌvA2T',8^6n0>w}7sRt*،H&hiiaxxBx27xeL2ım"r9srW2::\wyjzYnRJR$R8SO=ET aH[sݻˆfrxrݥ"o|k  2tttpp~4C/J~mqLBTָ֋^ SF4hDu/Jy~/ynoqc7qdVOe!hD#8i&X' 59 2_'$)섫nQjbhLzctXު'81VTRW0_">ZŠ:vަ +}'%%,TJSA]*S~y*- 0@DRBJDha S!l Onq 477P 7]C8MkK+bE7280@2d|d\9:.YF!r.E@Ȇ~HhJeI71'ˢx*\BqH!6%U)tTR>qpWMI*墴̐&FGI~dAcYcc@=U6vpl\m[|A~GKҩ4BK|/R!<.GĔ+pt겯j@&Cu2$\'.Pp\.%D‚TZmضM\reۦ)U7 GOsS!\.#s*` bPC6!/D*$èTתdŠ2R 5(lU,"^H)c^sVAYzqʴRkSt@ۆ /6[ R5EP63XhUtt%a$ݶx R&5weEjgʄPNɄR!*C0חT++E4? k0Ď&(Mf Vhy=i4Hc_cYb`»zӨZpwzQmM%Uʘo4NS!ee7mUx߲(G[XQhYH,K!9)_dX+lH,cڇvyӖ-^&hIꪫI,\=D ʓ3?D{{K7#~9$$I%d'8m[Ku@QT)RYA0|? r,vH|"䩴DTp0V J+{$I єnRDz(<aRn)~ b NV/,We32dt^D ^A)QMJUWSAP2 qm[+,j(" %B1Lqq8b(tJږ SFV*86Vj#u_-{:Wo>0wU0QChZIl +Z5EM2YbG0"2V2`qD,Jq*(Xꗽ@ʠ*^_)e<"e[S=[S-mjhg$a ^wW"ş T`yUe l|_A=ƅOh~& Ty T[0}(BؼQ?hD#/:P4?q>T}^cƾʾ}V፿4r^n {Iˏ=gi\Ep|߮0yW_>F84?׹~Jz{x iӔ_/ueg+ o/X{ug]\F?sS\K:c3ց<_'YSͭ_?|d7cNgʺ}r ?|'%(tO^wQL;d럸ucrOx;v5>r1 xϿбhD#~AŜhYTYBy,T J+V؟VJ;C5* LOZ#ìEU @STߚvPvh<-,KVA5*ϝXg" !(t]:C+, +X˫__a&>ϒOp饗q+ 0㢋.|/$} ͧ lݺrL:!U=!}J%Ig&pd4l6L&b`^RRIl"c[6AQ,ikk},KƞUeԪKT ubGjY:"ϓL&/xnLk/:Of-Eֲ7}MT_kR) "T4}}D?a$BR-δD+ kT~P_璛iDO+ˎṐڪ/C,- ""czTd{߸σf<ϫr4t8֨ݨz,C V)DW=](c6D !*4>)0Fe̋UF&)Йf@yo2A &Cyӳ:_: mDcQ6-9N6 feaٕ1#[(ܷ6ӹIGQшF4^Oyu5_lڟseYn~?{uZ!lOk~nOG_:f{{hC9ΠyW|Wg:=UӐ19xT! 0[> y%3ȗ_9˧}Ǘgح?PwtΚ׊΀_{WY:~-X,ז1\WDڍhP)Tv W `g4*pfVư8>|sՃ1gmdd*Jo} =,5ɼG>1/KLJXkD#шc(f{ s3HZǻ,w,"Sl?053/,RrSlnZܱ~ oL7*U۬}L2&%@W\?^7\pDDp/%!@ɞ23]UGթ>r?rzK/pᗮgVcW0g>w%;_̤@JΙ jB?ӧsٚYdhٜu4:63\X )B HJF5)TnjaH#ʣ s,^-qǏ8 ,`…C&+TZ#d*sRj4rH[]G4]qu+%Q8 y}"Uլ*d=gO)}jLrRQ5Y,C"*rQkO:I,x?ps4qa>ruZB 7%:?<)A޼ܶyΦҾr/4 ^ P~G>}=p{B 0wmPX@Rbi2[۠BJޭꞃ/Kƛ?ZJ]4Aœ9褣3 JPZNnNCH&ۻE0q2B1<; by>SH!P i9'J1zL|~GuCFZ"Ҹv5Ly,Jel[>% 8PCDj(&IN)ϑR]ԉB F*byFRn=zq#GC!4呗G[[U1A6!Nش\şd fhh@ H4eႅ\}|{24?--L0Ç1mTt]'?? }Nf͚III @R6mēO>eY,\ .}/SMKK 466|<444 4}TRa[IJ᪤3q=]ƗGTeǍOUd>Q)8 A|[q RY&Puuv3mZHO!"l:t>tÉi*.lj P}լݒ J|d/s*k]Hu'QJ;ϲ^ZS#{*J[&qyo,)NK7m{}+Dr{̶ ~]Tǯ.3T :Om'VL-d&$KmIv{al96m's * pY ܱi1bէ]4Mgθu$Q{]sJ(:#;vW]鑉%%\b)B1R8-͒|_Dp/o?>eyg ez{`KQ!E|4(ܺi)kYk>ɑM7uaaA>zk+-@-- -H+ȇ6ZRe ʁڻ쏎oMLC_Ud>yݴ0c /SNJJ!RHχj %Go, =sxx^232qmIƘPĺK Wv $<u?kw-.kB )o{]o[n[na(BHz8U)=ƄIU.,,${ҵ|s%"@ˠ|DaM^e-Oq׺c ق׸󡽜 s/ƧoDzkzMo(ԯ{M4.\Ɇb N=,NSH!R;!ExN,qĜXugx 3u'ݯ"D ;EGBH%K۽POTd!>^c=9{deX8cRO!Aw3g*lxt]%|rVZɜ9Yl)_ͬ^+Ws-NH}{rI0ujEEEhΜ9s9LP՗c&3fNM(**bƌlC q Zho#c e\NB@oo/#0ϠG}Qfzb۶Q__Ͼ}{?Gmm-iL^͛elܸ[RTTp8L]]hY~?>7$LbI\(ϖDL8 `RUiEH2D4[nLӤ***1cYYY̙3r.B-<ˉG`K/Q?'&ܐ2 CIo8*IS9?';E&Ad%l?F$:g hMW9ヒ|߀ϏN\Qvu\u7>t/+{"I9Oa)>#Twdϊ%AC!VYDLǏ1cF oo:e2'Np FFFزe ===?~{۷`ƍCKZZ̟?%+VXضM(d``"z{0(BTT6rrDhkm306u[g?YztسgwǕW^IkK ǏƸ=TH" 0ݱl%,U>U\bQQ9*d­fՓM.Lf^sjGx Ͻ#\U=X&q'CyE7T|%f$ Kb'*9&IhU~i| È۔V,Q~Hs*05`^bXjFTP]׽x*+2ɘO!1媫6KdpFġE~<宺iT_)uxe'>"3KL/`Ck-yON%y RH!doDZt>]w`|qW?e{/7x.DHWsU%)<әt پs朲̌SO!v}nhB'Vg9v6Ѩ纏B~B yb4{3 0@sT72Z, i"IHT:lSvKwoB;Xy:ҁщ?BQ`{آjb^/MlD׈p\h&`>L rs)(䝝;^3iSEEE ٳw/Ӫ1MZ[Zħ̚1#uu45GVVE|lzzzDL9sazN'/?] 33 [omA6mFtIĒi:g̘AWWD(` <>==Ѩ7v/^%\}Gd$J$%)(( #=a.rǑ:9tMM' e|EZo3g 줩\lقm\ve̝;Ç먨0&M"=;oٳg?vs]̏cZ222ؿo?c⮻D"|る.X=999`[yy~">ÇK8jb~ZDF"z|kXn_lBX2I:/^OEuPxJEE7jG!l+%A%Y$dTsb祥bXGTR'UUـGrm^Cw6Y2Vmu\l­TEF>&uSTjɵ6EܘUq疿dNIle$ y\;,!b٬-rVuݞe}IlD6NTsb&y-Oπ<%+Oyb;wpsN{zꞇ ww|{ߣ`u̮8RH!olm2>7gj0 @g}3*U2<-]c&B ) p<+zh'ScCa``O3T#/bqT5H4BH$ןԉ1TV?B}^g8ܲ\k|>,ϒLօCؖdu 'v4ߏe`?~L9Z&i:>E__3gΤC3exhP:344A4:BII a@g޽Ldҥ|S\JOii)ii9rj&VN 3y$N: 8 $vb֬YDQn-[TWWsK8x 1}tΛ̙3ٷoPW_}i̘1tC6mdddBYyf!CN&l3NgWY9H-..!rs ENnmmm1 X% 9Q]^qtr~&ue6>3|e*skQ"-n Y!rԜld}DT{Ĩ -.k2/-$M.Ĺjք=Jz9p#%Տ$$X*UX FyN%BeԌڲl_IPL:M+ȵƑ r'qmŹF~<1N!7B )B )8\c&рKjp6MAɌ |1*XHTgHݐ3NJ6=)BeYQQةnvݟ}>C|)uSQh 1׍!h;1* 7S?q DoD2q'xc/K&iAYN2"T-IIt&)f>=ҤO7xrg}m3BʞaLZMM4NR=@ /Daa}}D޽ɡ4B!|iSp9g388Ĕ)S׿5TH]sN|>CClٲO|<(]DPL!RH!A5 ]q5,7yƺ[98 p?:C}9'my(PQ$qE8&Cs|b$#jT ONXEO$evtM 17M]V$2,B8n꺮c41@A ۍ}#4[fCFv&EE%&;JĄ(+-$--VLH{{;K(-^l Cő#uFcC3ᣣBi!&L 7oͽ̘1Kg}|>X~Ü<pGh"[ؿo]#o|9sf33hmG .`ӦMlٲ"0"(>'6*>h4Jnn]<7;pOe4ƙ kq @tdG~;wMZZ'hk4MvA]] ұl,X~mZ i17iDQ]W 'p:KE#J85˴sb(&аFL4]çABCUt '{χNԊ5+bƹ+;n75ܸZ,TPKŊF۲,²2&DAa8nN :mc٦JR'h%pD״Xp Xμmwsp] ^k_7rݑٮznz$*0zf'kD5;Wf0|`tsb%6U8 \sB~m'}ܲ,4[ޮ$}~,^ށ3f?@*Ħ-Ttl?eY ~6{鵃/vf蘶>#{m|pcj vg&;35dԹ:0=~Ƭ]W_*4_^ϐXGs _1gd;ql"QyӸrUkTi\^JcV)$uQDjW%SgK:ۮ;u==<ē46Iwo%ܹ`0H ϢN;@{{;o߿w] f!0Mntq~رnO<M__6m"p1صk7oly~vbE|~|Gkx$O>]1 Yt)<3Mk[̛;k`<:DWw53fp,f,YGEFZYf1m48Um"͛ǞZ\'xe\ĪI8Dθqafe۳_}%mtdѰ&7>^>!b4pz6-${]U t"a8eYlen XۮC'W%ޜ!~=5q'H#K*7RTelOEpJ8]˪b,M^uU.buw˵ݤHbq $^uQcwLZ]VUs݋F!vɍoD5择L+8Y靵PC н5=:--\u&[ˊk4a+1ƛRiD$ĔsSxo ŽQű[wԉq޳gl*y?T=[ `wy3s>%)y|:Ixŷ/!|~f~""E>|}yGL^ yEx'=@yՏ^{6wCX}WȜ̄j 9^FU1e񗜪f<Ahy7e74Z^ 817}_Ƨ8ǝ?4Rb )B )gm|<5j i6ǹIS$*JTCR!{I>k6Tz2T1q$SGTF*$l~45 4 χ;+3}~(455dΝ˃>H]]GR  ˣQa0 ,>j?[n )))a۶m )++a%Xx1̘>7lb5.ÔNxdΦ/_EGGEEBl޼!XAVv6Y|sŲllۢan6zzzrj;<1 ؿoP\z5477Ak{;LD"m]KG[&i+12t=+rd.%1*˭7G"ZK^`]^n0x}4޽/A")y$V؀B *q dT砑PؿkrNݨ!ae^#9Q\slBb,6HܔQ3Y@'BUCJ24FW{"\UVS"*'GuwVId!0}DJN(IWcRF1_;?6n"-N0_IEٳ9Hg2Ugi+~~7g1n>xvɝ\n%wбa~c6e@`ǟxҟډ_[_- ϾU4=\s#\اvjS\?U!'q>Wj.}fJgE_Iqo(߻ usgv|R_/!nRH!RF8j1'msSx bT)A~??SAxr9)W,XߍHTI4T=sf\Šc_o۶릨;.:zL$dv,+it'65q\mWm3"tf$2YYYQ\\0W_ΐ￟7xRV\%˗sqJHO{7`Ҥ*rpgo`Ҥ*#vL< Τ ]QS3(iidq%}~=kyvZfVV:Ot'N2u$,a144BAA>mmtvvqFfΜԩӨfǎD"iniBAvv>8\Eb},^!={0|gҤI\qs!##cG`غu+ydgf֊c\^ǎHp܋mvbNHɴ@ruӛr. Sѩ^M<N%<!@˝XU Ur.ضޙ8R0^a )qKK`nı5/˳e<6=N-iv,$(!\kNy«| hMwm^|]!lG4'vqmHrUU%n$9UZ4R*&[!1K|$պ į4 h4:\uNLJ7V[{SxopN4挛޾F:XY:dI{﹞s  N䲛Oplt {2TNˏ~5\TS@ۥb>zDy6o*(2 x%_MU@dT!P3ﳿWUrO{ӸC3ɑK)Ź{v578NS_P(`ZRB )B lF5 mS881ִX\*5Ctww BfcK#]BQ"a&[qe*R${S)0bLVS(&j\{(N Έwb>a0رh_E?iSٺu+999,_~1̚UM47o&;;YfáC>}EGG'U'z{)-+̌ v͑#uqHӦM%140@g ,[6AuNeXe n{H$fm]v:9qJܗ^z5|ǏkyWBʎ;8q"Y9~?v"3.+M6q1t]g|>jkkٺu+ݜ8qٳgLG{d;ͬ,^z%-.`iuďEWn.ǜ FdQB=%H PtIJn?A/nXx!fMNq ٮ{X#M&c|=DlJ9KڹwQ ʻ麎m$h8Pbk 71%eݜʸrφJȕ#99v)1#Kwv3uHco41Ƴ}*87i:nնcXŒ$W @&Ʒ+^]UDcb]3S0lEilYdyvC9LL/s:f~Ae qug5/( 71*MP{-\a~,(O70帱Zxxb[#mQL%63UUg$V5>OW+mĿhջCt84DQ;[G>`URH)B )40=->, [8Y2UUzМ{,ܛMd`p!#~?,K甜SwQd$S85ZqXλ)OE &z.Qm-T&CO(=2RqT\Y$uE}FtI&kį{LG)0mZwɷh$C/y9)S2K+L/8E`|ŐK(ӰԿk #|Eu9k'9ϸ馟R;kUΗ_[},5]s~榫7}!wƬG/Oz3OT|_,Y^F'24?)B1RH!# ')>fTT1IeYnR%;"q%k(X20d wm$$ ē/<PL$FƺNW-hp]%5~-<3tCbqnn {Fe lt4W];F9YtKz9r7|̘5֯_OUU&ؼy ƍì[6봶/сoIݻٹsMXɪcݺxG?L*y9r#~'l֖'r(W_ٳHz|ttt̘^&`ƌ|ݻvvZ.2v͊+0 LBFFSL={0c vl ǎsq c²  w|qg yJ:nTv9$dm[h Nh.٦bYՙƓDm*344p2>k2벦yѨnImd%e"5O=&cE7n Iso@H"˟8ۭ#ͽs ?]^MmT]% &TRs'ו9:0] dMNa03w3|n|yE їip],xm &S6.@e7rs L-(!f.k^#\RH!R">'ڐ @C` ;.˧aĻ :Uݲ\P 2_1Z8翦Ɍd%S$SU%^%_=USaaYDuS>%칮˦^e9n#GiQT^^;ui6`6~Z6oJFv 9rH$B(S0ǟ @,a Y̜9K/͛ߠ?dg3k=IRYYAmodRU=pU<#p ma6mC=D |_#`ZS&OtuP\\̼9sX~Ŝ{b;;Ё̛71g<835qeҖFG{(!Є z1 7TLQ!DB*D1Y8o5Iْb%x >΢R  v\Ad퉁r5!\SwIPgN.G(Gya ^ cZ/A̝ײ,lXR. a麬nx{GjY"]Q]G4*\.;/]Rqkj!4p8Loo/iiiddf3IUhpUd%%;9TN2uZ,U$pZQ5$gfB74uqL2K/YN b/"K.%##>az{{XZi!L n3|v0<ˡC#7 lL\4 4Xh3OI8{"cȲ8vӦNJK?r~ lݲMΎN::㾩0r6C\R!ݸxvǏľTIJ3\qce8|qKC*f20|O n-ݲ))q3.dQtKe1QQv{NpIxHPq[!FWw9ꕐF^>K<"IJbIo=BPSHFt#>',nFo4w|hZ\[!bGj2 Wt~plwV$~D*/:mk+s KkyϞ5b|k#7m2k #t?C4}W%_%qGkc,S?O|ZGne7.7}ٶjgi%KʽKzJ\!FH;Ou?Lrt{'OĝbzRHAũ?K~pwL~8̦_ziii~L8ht'So_=|?+_%RH! ?$3NuPK$YQs'33l[HIO8tD;ؤ"^MFԈcןmXu]JQ-8c41Gx$ap)\"Wakap饗p+io`멮\ue{%|>>+VlR4M0/OϮJjjj줪j9s{'"D- 7gzEYlb)*T `0kN~F{v~ςLNM_kDĿ=giejTfxߚ0ޚᗟg,-Ͽ(uYz?"*K$",ٳ1}9F#ds1x;ٱ}JkZmEWXYzֳ01ˋ,:H 7b,T+TS!Y ٌ=[X }lx9+]\ .τvhC;pMP@. d EpC!U9J9h7.K5RUVQ+,^ yG9{,[nOjU(S֯ RhZSS@E ^z)[ gygGzk?=,Yx1Bo1ȼyC 0`]vdjrsc|صkX9gҥfYl'Ng ^|InW+褌iRԁg=Yϱv Tp2BT!шwW*8SSS RKRCy,@{Jw1ovʥܗS@vO퓣Hֆ$>EI (La G4́y\8ŠaN4+K8=c=rǏ1Z|IzFGGE)׾5FFF"p,Kp~|~߿;chx>S<أ!M>rws MOOd i={ؽkW\GXxcF9TeكGh 8vG&R3/Rٙy{wTQ?",Dk[-RL\A(A 힉F NS*'<`'>:QaT*.Y\?ȠQug ZTdOJ%e.WB- =u5pnoX(=1*uIҩ1͏uY 2Aj @jZ6V˷&%6SP !A<[?Wx7,ޛvz^'>i%m5yK_f3h`xVњǟxC|2֯ǎ{WeYfG0N駟cyT j  j`hJBa)eR*@f`p17#^sO-x~Ne Ey9ϻyv!YPy&ǰ sE( bh#92di⺭A KK⏣-Cn^E }V䮦2y8&%̹6^i:)%Il!vehG==mAXpE;*ri|9A=j9|~ ?&=rEx1A2̞YHYk 9%qGE\ָֹ :fw5zNms ԕklv-!@<7 합]o{oC<2<',- 7`bzn (dlbH)6(wҔyݽ_7غe#Ci>0/r?&Q?|ݝ=YzֳMpU%EE!SeXhcsEP+?PFWRJiLmwS3g=h0X+nT{ĭ;UG l.J'Xann:n'iJP7 XH֡ '8#pH(J*z\52(Ȓx+ cݵU*,$Z)7AS\v%>,>dh\U)FPKg "3 RJKQL"re +y~Nm2$4. |K\vxL|3O*0kϕ鸨.͉:NHxMp1!cr:D!Wdg}=]1)"n.m-$4PϱYf6nu?W yѳ5fh+VQT6gvрbL03]c|bW-E+NqILMN3;=C#hqkχեUg=Y,,܊*B ӺϵF6Y_Ut9 0 a6K\R*S.e[t/,37뮅\ߙ˵[uX\fyʾW(Ϲk;rMѕͩIt:֤iJXmh7[Pl' VB`vv-Q,)B/25)iQ'&ᕥ1XȊ\uD(F)>?l2,Z)7lB)"v~E afaVZNǂ%X4I;aɒe,[>uW]u,###])AW]y%8u*@TR:!iߏN٨uZ4MZS*\+4վ FB0Hdg1Rf1y&gg,D`pM p t# +ڤRD)HM a'nc!C6 6M,TOw;tr…2B=saq$܆WzֳS㸍ӌgjfTkXjQ`` S$v;cHB+?}Wxd;'~[6Spd 73>?ÍK5O=0|>_=Yzֳ]%(,rH69Wb9 _\mfffVEnq9AmRP<[k}YTb j$4M$I#֬7^;|?.\ y[Xؼw2Wo2 կ0ib:𯘵9MӬZkUQN)Utw^\Ů).1њ<{[|a>E`زa9kV1=uɱP(_indAv;ܭ1G"S/ы}?[?/B>;>3?y= у=Yzֳ0j`~N+.tU|IA?.Tt+Y1ZMfgfT*@;5dercNNAX,&gKk&;MSZFf- K{Mνxv6ĜcvNnG*ƤƩ\3E Vf"PAEKCAJ* x3gqIΝA2/<Wdrjnrr~&7o7/RrQ[ b<*2###?~Jrӧ2,v8;7 m MQ)Mp!%I2W\y۶mѣ1==e0&y:e? ?1~ӌ8psuCSL .o9p h㟝S b}ljH-"Rx%'q*GTx +' Ω@rM CLYT[ !\DHc q!(e5~3DiJT)J}T4Z-֔q xEeiPWDcA-uE6R069,̰bݤ搮bZߏYP1bak-.P= 8n>k@譇Yے1 /6c 6p)~a >˖E%0pY ӄ@P{Pn&I,1Lx`g=Y涋eaZMF3WmĪcW]KOj4Zmnv9}LONgnE/kGƗμ_{Mԍ|w N׿yu}!vN mg~G͇:mw\&YzֳlNKR\T0[4/vDpO"^KQRkٱu__sawNk׆'WS+e!SCq`Ԇc1V5 0l]}XZֻF`=虪/ldsC^ !hZ;"(}󹄷3cU` KW4{gX m^۰mqgEa\c*.\7b&m ^0LEE;8nma]nz%}zֳSq9oX勈2!&M8L=O;71pS7wq737sq>ɧ7k˅Ye?9?7(͛wqng=YzֳLbw5#-(rn2WX38QT,Xe HIjLLLPTT*NYwPt׭~ wd`#LHl6ߓegF$gq2w=.T  !T"S81 P3zM5 ]I)>k;)pa+18H@Yկ;g>WP*=s)$I-o_{3R*דhT/5l*Yl%]v) &&&Xr)۷og 񶷼$]/-6n4 j7ϳfZ^:`Yr6.r>O2SfHMJݤ6Scp`+]ߨU%Pq6rjRJqWY}\.WbZS*ET(E"VJTBSF mJI+iBVˠ "AZT2cVi\K/qF7M\nXv3SLONaa钥G/Ŗ-[$+VKG`hp>g8uoxC;gbbK6g3q[BǏr)ovFΝcUhm8~}e7`}YJ}\cGk2ʁpسdSֹ:7yV{T1ǵ P[%H+M0 Uags3dy* Ts̛@S !1%$R)+$֫&]V8{*氠6&B'A@IZ]ެu ,(zЪuJ0IIC]T,ỳ!Cyd(ո %wt 8rqƐmAE_#Mm8B sQ{ba]V֩.i5le[x_=LO7]Bj:S w@fp|d|l ``+\Ʊ8t︒F3<ÊKyk_ c,gϼʕ˩k9uYNYd)'sIlvq^} <~$<3xEO箻Ċ+c()wPT.])cu I˹WU2C=?ĩRFCRki[XmPQD V~.^̊+uYKqL_Za,rZ=>k׮emc8|0˖.spa5a>̼yXt)k왳|~|;癧G%*74-o~#7J'zVv=(_߂1moeᢅ gۍ;8pھ+N/ /XUqӍ?IN8I;IZkWq3lv-m288]GJQTm\vf޾Ħԛu΍Q)UX`Wf {Xd K/Zl4hZhf=KcH`%RePOj6p({d^RH<1Og7g?.Jl&1_bb4εo8Y.Fw]sva"x'ɔEh" PТ9cseVgY,x، wTw([{ֳg]4v(U$-Q-]WZm!2jR\\}9v\CO־lW[YU8^~Շ_K~O&- [y=[2 /QzCK/|?㦏OqObhPYzֳܔu,TݮT,,]K_{qXB 6YSe)W*(2_bL:@1;anO\v.ZgắaP|e1Xfl+ 4F)57R`LRdʙ_xG9*쩦u()DPJp1a|]ΎqQN^OPY|9/>UB˹a>];w"AR*~+_f9z(+W`!ӟ/ ;-ofiZ%$a 7j3ĥi5[̛?b8֮q.Z;vw89r8xvpmqmn|j,ZL}#=5\u۶Wchp۷m Z&/+7o69Ͳ'?ŻxO= ͛6ILen>tQaS$0Gd*BBbR7t,E2l&W9e;Uw,f-68&c2oy>>!@2ca]%, rn!CL `Ndء͒.g>:]JOk,mݾ2)$ñ jqbieZxukGY6Y}h ŐjSy؏};y &3Jeflұi'7a"O6ņ%ribS :m;~6{ֳyx@J!Tlcd͵TYz)/p͓sKU~*˔}\-y7^^}Pb-?s|e[ WE\W9봎O~ozֳg665ע/27?>6~Eh3wHKſ*D ?CPZRT7o^Z+Eʒu9Rk ExjHvg`6+岝eIg5{Ea+xe* nfɟDD"Hkooƫmt1 S,@ yҌ *'B(z\ FsFg? PǒeK^#/Wexx!OSQrJ.۸=REs4 -[ʪUh,^y)E%5W^y%o{8~{=͛,~}<#s7(J jJZ6N>kumϊeX`)صs'׭'~'w+gOLjq=6]]KNt li֨ qm8p!33(+v*6֮M}$> B*Ŗٳ\~=^kYt)ÃY|9Y,\1$RAjOcui1Kngxp>&f*ljKg_|u\B$131c=ٴaMy #/{ɩr}`~>{J“{Pu3g6ng΍ eV􉓠-N;L}[7|᝜;"O.fӻ;w掹-&v;Tie;Yq*\笠KԹ ~I] w`Y%t 1WBx%$ Bܝrd=Eufgs7&i< Y6DY%؎,8R8Q7gl}&.B:.!?A]| kQBI|L,"k JsL{mxxqܤn(Nu kVׅh>7þ'vl|BƢi.=Yeys7P ELЮg<.8#gB1o|mWo\R^jg=Yzg]^.)%,^S\ؑ+ݺ^ ]FfvviJRǢ[₶0@h0IZVLm?D= W*9I CZA\RH2S@ c}GzEM YVm_RAXyhۘDc#kYd45ok_Ł1==M7]_ | /G>pv^<}r̚5kظ2V\Akʉ7o nf7nټr.Yw ;nr 4M(k֬#kcǟ M.d-WlšV1ߥ^SfS\y,\T-Wgn,XҮXuZRgf7IffgF*߀LNO199ۯet|4I9u4>JqĉSR?06LCンǏs񦛘 ׸le /\vȁ$IJ2G`æM9|/@}j3g0~nC1;5@q>'"&-G06yI'<'ChۈKJ2| ӟu@Hߵm\6$IxNḦ́V;eSII\hr'9}(4%i)6Y֤0OpX@݁$crp>! J$I~h{*^>cPS$sjg &Mq*kåumt}R)B>OZ_]bv*^ST?uGsNܯCp*odhbni 7z/=Jq2cDQ1K5)ƤWY8bo9i׸}?M=.B1PQJ O?us'G=ɒÜ:7oN'~+.V5zֳg=5tq&͕v,( Jl\Z;BRb<,2PT*w,5EeW թW jfM+iw$R DkKyU \v tzQ\Ltn{CA-\$ &'S, Tn>%d1-۲һ$R )4"L p &DVrنx; wF[+UZJqKnծqI b``p>nXjz֚!.RǏ#eꕫh'mΏOf2;h d%T*t7ȋGN0x!gNȋ'NFϞcvbcǏsi*w/+V`fb=wsӍ7QR^|j@Шש̰ѝ{I9Kr)V r`TS)ٻw/8ZkΞ=˞vR@kmF|ҋP yG0Fr]NJ)RJ%y执(U4M*}|z?{1fio)X'c5Z'):iS*HMb+HR4.h5DqRVELJJa,X($$f c>]"d$Uj&v>Z&RFsB2}T=)e@RHXbZ%] EZdT`Ϥ.:Zp(ld%N=&Wc\`dw6]g"*_!DDUY9l&OqTto&,bZEh.|5 IDAT'CY~\pg+)>ֳW0)A8&Rʽ#C6K<(w~GZzq NL8nX11=Yq׿7;-7b]g=YzֳmZT NaI&hGɋH Љ!)Kp8[lwbg}"BJTT~1S 59ii4N}l5K~q-NCFfhQjR]9.q "b| U"•h4}FkSBfC'bJ{I"h9("%ʑԦX람^  FujKsNF15|+y|9yiA' IS08--rugp?qDb||ݟZ/avz$Wh70_Ё#J% <(KZ x'P(;w1V,YƷu/~6m#i,^;4f??jsLNL[[_.sAtȃ~_i[k_B?QIH&F>`)D0~ETq~|k sR&s+5xWKk@'-F 'N @ijlD k$Krn!YI5`$bH-1ZK9.[N[plIJ!HJ$A3j ")KeL;! %xŠ(nlt'Ͳp YpoEԢMCJi"$svw:!"bܰ lsPن &wR C%cEzD\;pdJJq%28:k 0 0:E0&Mv:.&M2H&oWς10*rs%N|X/U(&r ~>UgB/Z#{O@InCH"WZHv\Z.ҹ"޵{glKʎzdHENn5əq&ʪA{A,&Qczv{|6\Ug={ֳg=+[)6ZȒXkD""& tGbp:gDŽF] $ zT`4&Bnl63aԈ*~`P)K}!B-OaS+q9Qp.F--p{3  82h`IXzuf޽{9̑#GP2'djrschd"8Ddͺuh??"'yLje d䥳<(V*^~!t9jf6iq Z 062Ɗe9:Q6iP)V8=,hgf=rJqFISBӆz:ň I6t@$ Ui’ BxYOdޮ*mٸ5isVP%2wp}QM FxeB J6*,m\b6b d؇Qcإ!5&5mNɻǨug=LamFmP@1uYCa5\ OWJe!!nczͶ턣.{FBr,LAAWt-!!Pnv(x?J],~}ܽ:]C zXV p-WtGt0UE0BNu?I glBRJT# _lMҿ`)}fRRQ"IRaߓO7a@<|Bzֳ͌=Yzֳc!ϳs+.ĸ[kkmݽ,*^L4Ơ-F9fH0l4kYvVbLp kM#{\n\ 2|/SC(%<B@S yՑhIXpJD {}b jCgB4Mv͑kH q9f||4_-Wo~5#gGxGx$m2R֭3g8?~A.]UW^7MN>|-W\I[oٳ>} 0:z$IXr Ǐ}aىIRgSc*"B 7@ ZWER0SSHfY?g2 N3 h;]bW`[dr 'x^t+@iG|yp-mBSKiX5{ֳ{ֳg=4;V'sA޽Pv |qӽ0XwwemZe^gr+if!Wf2xB5(CLmZD.kp^7DK)Aڂ%n<4M)`gR*΁}XJv6+@kXki4)j Xd />!Wq| w>˖./9aVXCɟI;Ɵx4o7j˵],'b??Κ5Q6Sc`$Ii 039ˢ (WBxWL;פMQ) (&M;o+KQ%S)*4N+}FА Z wsAƢK B,@.AO? DߓZtPraLˠ#:K2m-hu` K*%- | U /#$$2AMdUۭNQd-Qbq.d{"etA%Qh5muМЍ Cr-yK?8{U0nOLc lߙZxZ:9nn^1]=bS4mݕT~|~:@МپW$mTF꒵aXCk6lèK !AXPJ"b8k\7ֳ>!̓?:iz3O~=q9Gٻ5&X(VbX*n'HK]u& 1*ИsppۅgPV`2՞ ]R"uY?XZ.w tea]Vdz*왶5ruk8-PEXЂi4@01,q1%mL|Xy=i (N#,i[!*bܸq8c_X#=N1>}:'5f$ q( mhh`[[;7V~?R!lټͼR&Bc¤Ler20SPG.Ҿ+\vd_6z0=[D)vaȁa)S:YO/3p .I Ӹ]1Kݜ 6atn۬:Nѝt$03W<حJ愛G?R̹%KW6=8sAȴBJPM nis6]Z47\S;qy_35ƣ_8sw{ |uL{$e[^O\7k*@bX*VwMp&Sڸ;k'FJT0`a\bc|wtcMW^c") CLޑ4ss?{n#3}5NBKMVxuspB2!`:d u\B)zt4JVaWr tPsXxtR>N9%˖[Xq{Ç'ϱ@GG7o+.C"jkjiCǐ*Eg{lټB*-\ΰa#f͌;/GN;ڵxV $$kZ2bƍ9|1Q:TJ䫐RBJQ-$ͯWݍ ]& Lt}hjmcvccUjP2$qJ2 -EqOfn WDH`M+|)$ڮ{0Q &j7Ixbw@R;U֨(&׈5"1(+-B3]+i!$ާs3$k \{\d^W*Ne*Ct +DIY KVer|xpK㮺Џ~2~{RJ{36Z=QHU&c WjL1g :yY6;mۓphGFfv.1LYmZK~|vl/DR5s$QUTב婩nbê{J(uz BhEXx#tm3Jkxe\? cۿ%u޾?Ce'kN7Ls? b?y~wp|zWWb$g\8/gT PX*VU4 @{ LYn˞0Q8ŊslIOXoY0' v1 )TS,[U 4vs,Id< )m8H+8J6q S1YBmF6`. > dбQX"B(*%YUbTEZBR(0I_2@jLq5JgD A n /<-7bӦMJjDRXkxG9o~L2zJ ~f+ng!466ҾmQpB~s,`lٲUUU]B#ٴy# 6 aM=m۶qjh۴8BJ40-TmrA&?ULa @DZq%\01(2F`ɺC8囁t]BA@`$K!6Klv*x@Br8F*Ͷ+ x? iܔk K㣺>(8m&jTrix. Jb(WI'GOJ++}^9]h'1C+f[h۞DB45$`MaCGʨ-hNgwp7S尩ii}i|O],F;Ns&1Hܦѐ M#PHک ,>=ȆaXVN5ǸgsoǮUz @ 0Ϸ8Ъ;8N} d(PJCܺk4(.mkOY}I9c"2XknN I73eL*V# <F:ѾћW3cb+uϮ52f8lxne@MnVڑ%|I)rGr^ql)#Gu󩝡w|3o~= y'.C3Џ勏`br^I_ ⚓CF;c93ZOkda>_zDk4c_#3"wȏG2pc苟`> wQ+-Od4O=\z ~Wu%w>O/yO}Pvο8߹Ó֏OMnJO/iO|~=3L^x?aś r3ȝO}>?!EŊUbXEl"D`3C<=ڥ,PR8ftHI72Q=׵J'B8"V˟S;` t-IՒ JifCV sh{Mq)Qs`!nR/Pbp =wL-kNb`c{<%D}(W^y=]= d,^:nGlڴK{&7.z!^"ƍ?=kƍAcq7nmmF݅^8f=:V>fϞMX`Uj~c}GX|9O`K/3a IobQ]S.*k-8 ÜDLstQZh0G>@[ݹ"<0Dc24.M\-2K;7yi_nVYI0(P ;RIFvz1ݽS*bU , G6h}Ncb]!;76k*7<&+{vxᏁ~׬/Cڤ.?$u2$j}I Դn}cDV 4i]s<׷3ѵ)W4hZxqTm}|\?c:(.~e"Ysǥۙ}'Ԋ;_\y-~{)~NG[V}P>s7٭cPQ=q6?dW/be3g㧸{m3\ϝW^G=<;o3߼p.E?Ci{{sy78Vμ~.׏-ʏ.䂯p 0|g`e?Ç|3w<,-`\~l.6hS{sNgF7sYqב?⌡~So [p?O'h{KO=`(OO4gVQX*V+9Li$ UD(u=j6lF0 6@ha]%"H/ыRؗ@xJp*~h)tvvH)k-xb~ieRHe[0ҨDhVh2U4xh&vz7d %Y`? \jqm)<r`-ww e.ALH.[ AIbAi>\LP!TR@6b{~_ +p4,{^%o9hg-{@V);Ru]vjlRĔ_~,+Usj^?1tSN&/ӎK2EQ؀T=i .&iaIh̗vj.^v"Hı9*VvM۾ Ơ d6_0HcOޮۚMSsƬX(1uBD]44P] Cm9En6RQ()EEq%qwW8ad~@2o k3EûS1#2t6gw-q0b<`_]5`"wɌ wOF_9h\n9P(?qWz43ۉdQ̷]I'{P\e8d<9N||6sa/=@5O?sS8Gyf }@~8_bW@^if8NڏŚea-l2HP6`:ǮgL5'NOY,F}+VUb{m#O'sJp7.Z;V8SP粿x9`lF+J P"0mCH-R6PzY!Hݙ^΅*v˨euݶ];\ H:qM@F˯gw%b2qբ|5-̓h't#F a5477C6d82IPZL2.f̘Aٶ1cF#DIcJn:inl&/u1u)TS* b\L@E7]M&f1v/ЩS9-,,_FIgH-Rяs ]&lw$tK`un>Us/<6`2'tMrVuS4(T8U!Ia4{30N)D=YMcoZyܺ $ Jd<+ۭkc23)PɺM )jT\g3/e, Eqx&qv3`3~FYJ5m+ӃN蠼IU~HĸZ2e.?4'9۷Xjfۨd5q*_̂Yض]CkklXeALd9FRa帗M˞/'ON3e s\Da* owg_:C'nev1( D;xO*:@6JO&=2c`sUz #VSÆrY߶z;yb6b![z0(0aztvYSOßA6߀^twZڠ,u7t_?Hشi3 J 2|hƎ>p8f)RqQlbgEq|R"}KQdabZkS0 -|t an{l耀@̅dU Si;72,HK B:6, X^ns }`S,B!m 7ީU&FH7R6n^U̙3w#w- O=uo˽aNb\'O a\.-Pf0@)W_.T9>&.nht}]q7]uSXsN f,ǐ'rɏ0Wh?k;ۭ6orf00m#l{|w%1i!x:-!6 ]vy2s EX|?k֮?B̛? 6XhbI'#d'CegP ;:m.ŝuJt-{J(`ɵI,WO腡ukDC)J? ݴa##G4hHBu0p,лe c6AVt>v cǍ@> /U`˲'?{qޡ3/3F"{Yy@K篤a\Uȝ10zMҶu+! (++_dy.F1Myz׽-eShwNlh{u!D[_Ay=fL Kw|iͬ9y޽1hl\US~>=s72][Em,[A_󓧎A>[V<V[ -NlT9?#z俅@1R1?[8Cw#c1^*VUb70_ QY1?b4@ J4mKa:qMDXN9lLvŞ 2yͨ0Bֽ.Zy[U1$Μ%0mۥOԋ%R(>, ~>u T; *!d.PT Ţ=|&0AHFGk,؉;4,Bd8W[Fi]ƕ*G/w3|.X"Zļg%4j42zV[G ^A ) tuvR*>0cƍ˰3v, ,` k>Fo{Q1Bdl`6Z7U܎Ɏld4ep0 s?Bcr~CqB`U%7sQcݩviܶpBA@UC uRL |R&{`30X[@j?gp"ti;J)$247 XGA.sH"fCv9fBiQB?}fo(oUi;~  iyFGTcB/Xom!MKJ)&& `#k.1U'Ol u2WN[B&78:F/݆')YMeCN8!tebAoA$?QzCZ7aFPV1v^x5D%=f;.ރjb i0[UՃ)3܏: &if>)Hk"GL?|מּlϸ99XVe\XE oS_1_HM84}?Ne;xkwײj[FpǦI /||iL9DF/=Z:Ν8l|p=]A⿾(Vqfyܲ(?qu\~՘&Ǯ:8C\7Qs/4FjzqZI`ֶm}z+^{rx>UOߞađ36mr9poȡ;x<񍣹v:Tbvݛ}}G7sQu<o+mot9&Yqo-X|6nL'&RT}Ԁ~~ߝ @!L`(ҌҞ+-a*t2=n lR_؟kl\.j{VS6q\ l,<)tJyVXa7͑"As82\ʴMirU*CcaT!w3:QE(,P @Ȁ.,\ĺ U- s5յ5D6`}}S=55|g=ƐAQJS)cPR0d K,f1DEtxMZ f)yr[@.<˗տBku,:< ZfpNd_1jpO*jZFı}Ol|VbXWR%RqF;9,'8юHjRD.#ĥm7dPsg7~>-Ͱ@&n앃)u>u[L*Bv0q!VkOŊX,WU!GuK-eH!?n{sL8߇Yb gzQr%1r(,YnLSn@Gwvbhhi`Γ9j8^OuЃf1}i1} QYkFn bͤ%E.'TнzIN jD4ڠ?DqeJ3Ot:}>=A `ӃeaO|7|`&}C"ݜvs 7~ݳ* - >k+*[gr@|LTŶ:a{ϣ,\Z[e92 ᇛ2!#C"os lVe@Mc0ϕ'J۾= 63C[~f)6n}hĸIضEŲ(R bi O=OlaŊ7i߸U&i#Öm4 eޡ^\`MA-Z#:DXA -Mu&VZ>Gu6F=5esCuѤZnL)aez iMckg(?*{?7'nlf0&nWJ5}7Y_r\;F 50O.@+..J@yZg1Ѝ7 ,1.Vtvwsqq©xb[lڸc9GNum ΘAGw zC<E\6m{FƏ5ylXP@kZ $ВRg62yDƍCog/Xp =BRTn;l*̑W7P[OR[ELExj. W ss:$旕^".J+iW@M]Ib:htT&Ov dR g8S6*20.YndOg]~a_{MT5 Le ,B@YeOUd͵'3ٲ_f+m%Iu:\rxb8v?@q+_]Q9~%if'rf-\6V2?GXgO[m/꓾OUe 0iC,},S3CsϴsʼnpImt#s?v:`65=7YP> Agtos~7̣&<^$zoxM=Tؐ +kf7gFljV Ad H+EK Z?\ IDAT)e:6q̈́fnij4o&{/ȅ9J"q1=q#h1kVAMWg== BE)ضgwٙe+3nkVFJAWOuM s,~cÇP駞f횵eH =E&ݴ jm6:;McM"ٺn#83 8 s|)7ن?w|TȽpX&Q*xBBx4?f K{ur!\HڑQf}o}_e._Y/| ?KuYi,4m~]q\*SC wO_!-:0[WW/0oSv }hLv>$nڲTw_+?oܳq攉˿. z}ߏ>O][_"F(% to$Wӂ5 i$Vh6֊ba3-cgF C+QQȩWSըX@#ck*c轓2m:/|[?_Y;9Y F-/]x9<%f=\Mv5_Z#\ʙ%^х\noͥWyzZ| 'fҚ[X*d.H*;I!&5^$ dHVR ]-Lb$ 8(+}\u}:+eug7nUɸT ?Wr_,8nGZk ł7B#,)t*ObU.D@<0H)3+$@q7Bĝ+0I9ݚKM.sϱtrVYú5k*~a{c4@1Xn!bE-@kMkk+?gȪ]L0KQAHAoHu}Qb4kנfUKEbzر ׿fu7^qc2=O2(vR׀"j*OQA9pqL}VbxRF%3(Cn!dΣ kfu2ǽ|O*2uJAPnl98>rݸ0˴=׷qJ~Z}@ZsO>C׉{@ŽkBtm$_€fvu/zYe6^HuUQV(my]z Ȩ2%{Wb(8g?.K)Ű/Gέ}vozDA\ͳ|ɂ{|z~4~.7}n(M+p|SWL?X&}NdRm|\sg%?ꮨX*VSp[^6)Brr>0.W&BörEvʼ2p:eCUD֥,Qke;)~|H+RH闛0eIY7+م(F]y2Q.KZc@(Z))$㔌GN;AÆY1iXb̛74Io֭]]sZJ*:QJ \.G)"t ;f ;Oۅ=n|R3ׯ#ɩƍXʠXݺM45Yb;:e:;:&}`);!]= ˠrDBx\I*9⠟Z9Qrk9E{p#G\4wUb?@6VB,)NT,J?E~. DpY?q:qMeeCquĬ]_<`i&NQo6~b~ J6Q*F:b@@Ƹ1i"FQRA- Djr*0! r<ӧOg֭lܴc{CG W`iSc-id֮^ɓhok3d0w{c^lhiyٰn=SNa݆ 䫫0͛Pǀgok Б'Mݧa!x|Z?w>#:v:g3geHO|џC|HPw} #2ʺguMf+]JپH߅U^Zs.>Xֱq9q܅Zt (UBITDjM)^<DŽa5ݥn3$DHB']kknb*V15fiz><vibm1|K\O4=9L? O~9OBY'0dpæ^N[Z$Vs<’E~_8يUbؿ^]BZ}(Vod 7g?JEDQsn`|n򂾮^Y06rϮ->(n|5d?evVsM`7N49D679#Ҳ DŽ0..nv (I 32'nwntR: zq,X7G>jc/jjXxgAm]5DˆUkY["73vh573d` 6!YƎMTR(W1jn`D,EDWG'5uUDEGͬ]zz{xX-ڷn%JH S7$ Jȸ:UnZ!dF~S%s6u!M\Y'i]nuK e!\{(]e/7oٱHJۇ"e'-(T໾pT m8WRd>ڨ?"ظ*Pq1ƭ[]/†Tw(!04;S7I'uP(M}VMڜ\}vOw,u`,LoW>wur\xY` ʟɮ,MPgֳ u\"9r[ʿcY(YblǢ}\B`"z"Y8dru˺ʣT؆1CAP Jv-X*ۻ[kzr՞ALoj^}k_bQOO=QsC8fO00RncɚP?x0_>{̪ZOu1zhӻxl)vB#{%܍=9mrQncЮc^c9Jny=_fwQ*VY49:KHnCW7Mfcbir!uNACQ- ˨~\>2aegpW$0 _ ò{oO锼Oߍh~}>6/:"bBi*:* ;$ |@ir# smܞ*B҄2`̘ 5mRUbPK UA@,[ﻟ&о-M(ӱ8ذa=7js=;b4m]1ƲbJJQĐø1r$&g,^ M476RZ#FP,Xr%Yl޴RH֭8&D*.8@(&Skke6"ڄSwURxvq 6ƟL 9W"uɟo> B7G\}(~Y˪D*ٿ3{!T_U{V_%;A$v؁ ʟjۋYvbVLA( $Exc*u8^},wvϭD׮]],|sjپ@O@.Uf[\巯VJbSg@ie}&A95pY}/%*V(& +}КCVmmW<; X*w(n|>>qvLtV%C7-{E w#7AU?V.O 8|ųc7F]ekԶf#.ᚏM5\{\eM;Q~:+vs1EΜ['߹eTUbVm\@HU|S~űB˅ųӷbɓR%Q@xm7YWE-6aUd6=8|u&0ьK B8IU9e/jWTF3/TcأjU+id%l޼xꩧyyI,zs-MxO_E4bTi*D"M(4bw$BYP4pe%w(1 , EmHdm$C)EHRoq3se_.&$b1D |ĘKIk%F@de\m>T:]}/WzsN:Uuw}ANY+c>XUqE٘'qn16QpT% |b鉭++}36+8~ /I"im1V =pOan*PN{~6bƐܮP|V~!e ˰89'OyI)´1C{]:#r ̲uTw`~P22@Eheʍjh܏nm:/1+x|aM6 JӴx n Zox1 mPNZ%K6:ZsS\ӽw| @ӽ9RI1gӮ"- I,1Ϧ<׊v;<&NԔKJI ܻͱpV_wb52r\!1!JN5B]Z׺ֵfyZ׺ֵuMx^%)g.`XfYֶ8//BH<P$Ę/܂WmP1+ei#wuu t z5&NY´ H J9`|׊ 5%RE0c8H`]^d:sqsu Ak5A~(}~_i H0T **h-XR^6>i[dFJ@Kc08q=/xv;_7iyo$zI@j,eѢAl'LMsQ3CeA7!!%|˱Rp܉'r ?IVXAFF&G%kBk,MbqčTҔz\ qFAKP ,P\|};^ZsMRF(&&&"|ݡ# cU:Bcz!Vo IDATlA*7_w rƍ ?= |aAYH̰ z=di"Lkz{jXk9&$%%9𮺹.YnmԧPJ#„< gqF"(W)Xi0,AAZDZ%^TV}яcRΥȖZWx8*e1JTZ6W> +@P5w_mCM7k]Z׺n]صuk]/{4K^XNjݽ2naVW/ڂi PF*6P+ 8]3] :1~g%=O{*)v _/7~q]hteB6o-43?];a[~Q^{Tƹ;ב?٨ЛFaӷp{Ya[la|tlf;wjhNPO4erj+~%f˽_8SӓL`Ek-eGv6n`zfMmbdt^.bxN~HUBHh\pMc%@f\pNZ( eMMbpQ tN/{UΝWENr<(._z`HҔ=;Cgg@[~;sZIŲ%C?qgfԌn{75hL[֪ ,a5ajvu;/|㞱I=ǒ}đlyp+{Fy8)J][{X'5A]صu=eU(vk]Z׺4ZyRMYAwXѭd*NӾv_3v ^]skEy>_+wybX`< Nޮ=_ۘ4XҖEhH$M`tBcC"*ҋTuAk18Սfu6 `%eh #c]qU+gIcΝ7Fc¡Ŝv49CXf5Y'r23qc]2qQl:pN?TFF[ẖ BЃ[sΤo`IO 7Tw_;c ΑR:0i[5~?y Zq -tIzTIC esuZZ.~Ӈ0GmJQ}}D˵=SXg_?7 .ḱƻK`TZC!U%[m\xq!R>ԀJ$)ij@RkH =.ⅶ H(0?߀:63@0i ʼn?_ט䎱Gx|n?{EXZEWk]S.PZ׺ֵu q5]eڴAE9@ cwP1,zb[ bU1Hu,\Ok!>mWt, .IGW:D){|]X-իXAצd\::G AJ@iP\FhP_T*},.kޚ͐@)\^jk%O>&b ~RD9xf9'iBf2R~ 1ak,/=|N84>xy1OpʳOfGdɪ;-h }}lt9cX~Fk7Ŏ,_14 "`jΞݸsN=]cw<5{Q+{4KNR~p@ J3ӓ rJg\XmW8}ٻ>13=$~87eKb-Mӿpu3s'#ZAhdLS #dI6QDq >`1D< Y8V$߻!Ks\mu T^׷Co],rɍ;]LpCVe@ǀ,6!p)P box!҂{Ce@roʫ7@t B}Z-aTG/YVrKl~/v]Zמub׺ֵukO(4.lssP*2aY|e%`71VϏ!Riẘf)T뼨q:NJpT#](U*K) [V,̙~(FTR4)ƤS4aŲe-cxx%V^3::X2wr@/v-w.޳kVqǍ73k/xA\ёfUH!% 3sl}h "9CzM䍌SO=]w1YADK01;9/: .|5W~[ΝL300xٯ>Ƨ? FvhhTdҦ;q';s,;QڝgMc(+te@vꔼ*2o(N ڀ= ZI9i[J9!*M, UR@H]HBPù5-2gH juI#Ɛ7Z;%iek02`rkmCQ!S5N UW^IuPLXP1`m+ck8{1 $#>uYTmhhE•iXɼ"?(. .35",7PBp `qkIdƍ5 ]~uƝSHd\J4iOԵ,ujoO^r(_qst඿{k>~̶r~穟|z׺tY(vk]Z׺ZTq"d@6B "UB5]N bށTF⯓**jў:XhZˆ)VXs_ B¹N1 u iZ>e3 Nw"8ߵ=ٹZ'%ti,Zwޅr)095ʑ x-p͵H픋ͼfgfIUҰrhb._Uٟi*2!TI>7JUu!{]!ҋպbsbXI jK+v NLPqx ZRZnBJx8hk%jZKj` d {~pRB3hX2Ik28ll^)y ŪgŘ.>zFBܰdE Kd%e?@qXHFE.aEzT"3x~[[H+-g<&qeh ĹL[(E2][ 9{PN+6a~uP);!#AEMZz n' 6BӴ4s:]u1In;Ym5Jȟ&?~yO& I翑w^x ?U?}ٷ{ě7|oL_ksډ_gw?`>½~\~駨/^~盜KxN[]l]صuk]h 65+EP턅tR)VS!)vY8Vm,.TKiNy*B[ Ǽ @@TF1l b[) m H"*ߋgueT*)BI20ʂ,g$*Ҿ:Գ&V fNVXAZ9g֭[ٳgZ)֬[Dž^;N931>ΡGm,]\~߹Ys{YuZ//{̍пp]["Ş=,[eYi54k6>V% ²,fڵH#~ݽ[dbici¹)[m}ēR7J17@;WVL;Pyh$; !J+LIQĒlAw S1ΰ 16xlLۿUL:Aƅ3Yϭo½km%yl^!lF(#̋an}Lò¼](We;d /آnš6iņA$m.+C兒Miڶ{ %GnoȴA{()*VsKL@ Z)TH| ctZ-AhM3ȳ klgh4h6i4@ZM1<#%]=油'툁|oYbޱG?5_[&y_::A2p3/./> N d\͟SY]o=|?ϳ6 p/wcO;gsy_. e]صuk]hedkAu%֫U`,Ï e/ccE!t"]>SVʮN!+[JAV]*BXd+u^岬6 j¯OA("VunrJ2>1vۋ6q0 -Yw8eM05^ty۹.a1Ǚ/}!yXkľ}S28!];o|$~3|㪫:'=D> lR5B :'Mٵa,9[y`i>>fT;Yz9޿m;I |L15CM%z\ԪV+-5q8?NJicAk=%F[ijRwNkN cLzԁ!TMR@q^1S9W.k1U8?.'[@QL/dv} #tS:|!Ėtmxyw`A9Wllm>zxR`cf6 W6hڐ$ J,'[ʗ`0zǥ?|8\#gq{<@vN/8tŅ4RHlط?|FEGw8uy^nW?hg&U|vvpɋ'KݼuKoew][>{9لy)o>e1=W#8?x۹l\sN~rsW!/>c\1^ L& IDATDKk]صuk]h._U[OlxHJ+h `_kj pqDXfc)%C I_p;Sxg^C{H=-@hGKYtvXoZ fahv1$Oܽb Kgf FX\ˤFZH"Q4uگ>GFo_{FQ2Cf:Gr8ׯcAzN-RIAj f'H JRîݛ9']_[,˩o2/|ϭev~_qDϾɧ=m"/۾׼/'!.y֛ͲjHY~x /%/W}0k׽?QVq ~̛C\+/4?bN@r_;&yKIh.vsou 'Z׺ֵu9@ZzA<1C`fL$v n(J@;`GCHdAHn~eOb$>Y,ZZ#p~+d _dRRPJ5/Z'X j#DK\M[صV|rk|`I,X,[#7E߂~W"]ųdu,Y5װG1uMh"S|窫yز!K`-?Y1W~#w?O\˗쳟֩I8˖ "7suRRa:zl\;wlrvǶ"6r U(9*3fIZEM& :HhPU U5.cl+YEssd`pZWD6\ `!ؼW6}f*GԥKtP?= 87X~in/T*N:o캓>P>?f\엱N]Z׺ֵ_FE Y1] (=1@p,B8,^eT+(Ssb9OdRG a2cMO(#^,ư1>7.SZʰBp~fn!{$wI`ats3sݵ(v;{ٻw/[X>1L}PB!$vwNO_/IRed+{annk5LMMqur׾TcmFRa _%C¾ȐM9yo.mì\-oAF+jB!f4MF֠Va!Q FRIT!M%JC+_H؂~X$"RYӍ::ez8YЋ< C^f(TLBHd4m\JIlҶ 2XաWYZF'|_xehw. 4B9UvlŚ~Y{p^U,a-VҤ[l!l6ux-&mn.@ȫ= y; ,yF &G4sP)hO&PD!e/P$T)U<UԊE ?]yJ*ށBx.odj?kCt<|mN7Ib:j?}57ƶ},-dCR_[ȣy|5m獌DYl)<P<,czIOaׇf-X~'>w/{fK/ 6SC1hGϥ,+ AWe}һ>Wol/;!FA/dJ*ЁJDEѡct=@c^*zS l (>M6#g>I}*vk]Z׺Yg/e~~kUS5̏ x/‚1cVRI2B\\ j=#pÌ@e;%兡T=BDiX@EѾX-_Q*tJb!=vsT ,;HqCkC@*I6jTc*<(~Ҥ|Fo\Ǣ%c7>|K_!JOÎ;L6?XOrџ]hjn[oV9q'>KعqnV^7s$̛VPU 6[CV7(I{,C&Si=JJbtVb9Q%3*(d}6TjdV:%d:7soԪ5HcIBDgMgEx8˴+L(!n]oN.,!P W(6ĂL«yɭ~0EݔWha/gs?WŞ(0S@S80.t}R(~)sֹ A$X F ڀPh#F9 @u#sssdYFȜ힍TcSZ X Β.QH%MR0tu[Q]G_?=3u&1gfs,CI)$M?{ ƻ#ZI¼Ԛpjx^,,akZ\Vk𞈓uv]מFs㷱}n'=_=_y-?b/^ ##MLLtzR/ez ea},[NJ#WxûKYsy9TVZ&Wٷo8ɼEXܟO_.yG+^u<%kP@|W?)HTZ׺ֵumED` b]'Ea᤼򦼘VrTh-B,7E|+ۚhz}vXpde@X}r}Y)9R[EiSНh <3/+ijZA"HU1,^nf`p!BZp '0:~Gm>իWCs:($TkUg^-W. u],dzzjLMN377U`&<׿ #RhB~se=K*i~z{z*NJHnrQ\t2{q+2ֶxzfc} @ȅRվ5lOHCq\n$JV#]!T$iJV0VfX ]SNg[ LSZ*0k1&R xeLg$$^幋ϧM[lfibZ54M^i)kj,334Yǜj+̜w Zhyֹ8Nj5,dYh 1P-[[\P[TR唡 pڹkVMidcf?g0n62@٤]ziԑF92|Jewo#~;Q (N,wZYN;1VmX|*ɲ:k?=>5'y9{Nfg/D?w!_a/9SO癗|O\!=Q-%bynF3_"w=".8j i>ΣM0tRyW;I]:NXYL={ki <4&|%Jx|Hg9>6FxC5ͽkκ'l?:sSʞVś>{sϿ378o O;[>-iE?~x rч/㶽M*7s;.76{qg\²ogNq{^Gr~w1^vֻx?ҹou2ws~ݽFu5?O^''/pűw}]c/8}C+II-/sx7rۮuk]_mB1Z0aV h_HEV6Vch6me !\Vb_Nkw!$i9, ][!$ԈsYqP ivz]^01 :.S9PY _ѝk wWKդJ:EZ+V+&՞* } =3TRrIO8Bo]x}˗3XFUEgꕬ\%r&_BTRZFRKvFwEֹw9Ukn3l Qt0w߶ h!sUr JEz#8˺U+ٳkMYw}V1רxb^pu1<7],'+ :3(NdY$iџ Ryb8tɄ$E7 %PEC?#F&ŤUi YbQ $ ܐaX+˲OlI[fyԝy<)dyyI&Ҋd,[[5$HB.!T,.QIH* }}}2>1Al);ia\!\ E?YhMiԗ>ƇY>JYuR̛~!|"c][cF% I뽀isf͌f֤>Jn {q ZS!||P T$24R hϡ!LGyNa[}Ok}NX)t%ƺxRZ?l3}⢍'n<'իSħ'+ xoy@Qrk-fX5^{1شg!|=y+98x8oQ.8,:^t-O>&NxO_F~)i[KTeykO({x5z f|Q[?x~;9sg=?9|_sw{÷3>fJ]<ʂ>NN+.nw}(˖Pŷ׿O}D/.~E|xe'Q_]+wrқ߮} _[8 0k]Z~,v YeaP*vn 1(BUsWm)MbSFʼnRRe?ura._:]v.h-.MKXVM…v#t~WTH|fN mꖲRJp? 7;wRU?8LJi6뮺m;ޱnV-op[o\ɮϽ1<1~`crb9-`6ol6HZl-! 5$ʹ#L2Am6ZնP/30ӜuƠ+7rMu"- JyRӇq]#HѢdPMZa< 췢]6BZ/ tM^9 ш IDATmLQ)f=ɫ+<od{DP?☗U͗}:+n_3%gq~A+_gn~u׿_颃eͧ?{oQvw:t $4H@@Gy88CGq\#*"nA}ٗΞtӝ}}sNUߪ:u}n',mPϗWs=Yj;~_/ W|U/k._~97}Cd3? yFWmG(3_|[83'}%lrnF=~rP^ʖ߾ӹ}h/ (ywُWOy6"O/>|,;Bv#^wpN}1qٯ?~oy(/L=.qXo9|K9fYyo^Ȱ6` i٪a95Q vQ+n_x]e*ų퀉x ^*B9q.x1'&IszE,3qMcg> B1PޘY[)ozm{ceuNT@^Yt[o uPO+p#͡zFu Ϲş]r≮,>ȶ {,ӥeg>x/s-x]{Xw1Yc7lew~S_iNÜzOe9yFN9-]ʮw"v;s.` T;+ؽQN9u>1þac9X/"TO~=emtMҀ{}ݿ5 ޽E֭]C]׌LASlWQ ΢C9USHb٦z) .N)^@&zH"`EIZ?(W)."$wcǺRf<($aH`YGLP覠_#JF8+F+)̓dZ>/y:5OA}P?5t*@O)\ݠAM't:e%"Ɛm" L=(B)GQբN;\d.?QJBx۶ogcb$sRoiu:qxO`P/ { 9ym0!vV6!MI7wu R,,W}C#}ݩ^36NiLCR/޿3T:f8w,Ř;|`csYa;S̳9q^x߇xχs}p*~wu>!g^;5⡏i)G=л^ OgGu}fVzwqOZo>Y\z9&w:~;yK~CXheAiDK9-'fF6??uk8}`c>L<.u+c[yK8ӷt: KyٍS[^9pl/fA+@;n(_( ~F侻r>x|1BHXXMHP'M!ޑхq1M>ӯWb=vI鲬H<>x>wgڤTT,%;'nAEL!mԟ^R[)l  MRxꦦ*4N _6*Ś9ݻ8ung]wًY+ٗ=n<>t+|cuwp⧯`(ޢ( ehSPOY;?Ũdy:e<78tEhT@ RPltPJTM#1 p&*{R: #]>mq)mxT2c*zllpz4.su֔Z@j+Jo4S%;41ӊCe<{ ڵ4 [5nx@!^],QUb/aVnD9ЊKUU޽twtqE)Ɠ[0ks0B܁] G hj*,$J4ZP|*T {cF#h4 +\L4'ǻZAQ+"e1TUE$%Jp1`=x.a\%Omu\xQ0oe8JBbѥ9}X) `Pc t̞WP[73mr)-V:&æ rW0>B 3NԹ z(5ŘK?(p>>Z3w̩\m?ÏpQz?=!~L)Y{mWʍ}WŎ}!@`6״5{{θ |߿|zܗ?{; xz~'{'e;ٹk Ojz^+vVY3=bN:ż~o?qwc/Gf 炫Đ"fkfߦjPpAb`AGOgt,D`OAEkTpkb4c+ep׭,uI,Wy8Gs%arG }%W5o5L&Qe,YQ) 꺦Z1%4Wni-q$&'JMC6K}lݺ=W䧜8g?3.H2<^qg4P T|Ihza(#}T+sk!wXĝ4`.}sq,ʀ@{ѾFi,گiU4蔍<$J?)Jx(lr6M#q(2zk|pcpG)ڢegCyp8 ]$&!vt9vH9H Ma!nv-@XI;0f<2]d5p)A̡ kҧ(Ea>MFkw: 658J%s}ÇaRM1(G2*=GD,* H,D\Ԕ>(i *Auø̠`|!2m3tVM+N̞εY{Ih!}R:͹w`n9 6\tGEv,]oxo}|/r)?v?O7quǟɹS<ƅqNxG͇F/旎c;y>SC?z*ϟqco|!87pw]9}땼x:z G:yl'01.hrW*\zs3wbE9xь1 ~rXgC"-ڵ\gr떽]͊3O+vvtj*fAF%i8Y~=KݘzG$mY1.PۆƊ*8/f,5͔v<PJvç?)vq##:h&Kv G_І%:ڵkT8E y$ߢ(d,75 ETZpLJY+µ1h<+L$) 4SQQ2 "tPShqw^4Rqʁ1hDXӠ RIK9$^>nXfŻ&j~e>)٫\n*);!󌺶ԵMc9 mxۺ=7 .c D6+BBɒiQ}qc| UP&%v_Ysh@kO2V * |ӀQTe)8A)p *HU 5җ JR&^T"68uѓUUhQQ<ԕāTJ7$5mP΢{ fShB&q^ qڠ cѢ#̓ay37,nJ;{pU7߮y,x|?b>dwFVt}\mY8_|r<(s"LlvT7uE&F7y9Py;ȅGHXrK|%•Ws˷+~Lvv/Ú9g P\ryx4s` 6לu8U@?M**~~20_pE_Tnb2]WݑgPיT=rK}lV2QEK#,cܶ?v*=5r `<i& TM2YY\\byQB4ud2ZQ6uk$F\ejk6^\]G3(vwm p ss'dtNY77<,h*W l3eY8z24x+ ZFj[. ɀWxD]7 CULaF%d% duX B5+n4N[VsY+uSZiqQn@[C]l!X2jW5*TP_9[Kݛ 1X[-QYZw n{+gu)w;:qXѝ8qZPhJc( Dqk3 gQYed@ h \߬ė5 ф6?SMJ(B5_u.@RtiJ-Wn nB]#YyQ1\2 RbI*jV?:wZyBb?1Heu[&TJb ݙwg)g!͵88Z(l͂`.:T'6g/)` Q.Go#3g9.$َF.u{ ?ʏdf?U&^«gg-<=|l'H Z[m41 cn:^J)pJV6嚜\5V2ſsp}ucZ;Yb&J[ 0 b)6)r)6MYvسgɄ%WPD ^LɄ$@=Zhdx}17?d:+ci:drńÔ#Q.O'P̍FY74J+ X֊ c#~4@0T Y0JSWS`0*KEؐZI+XpmMmZ}I[DCHb *+h)Db *iC_M-އUT@sie@XJ-4D $80Y]g"d#DcCLEjT53EʥS#h5 LDHuv.$ C6 @M3Y4@L *zqMVm$[Z;78{b*qz$q6 ::ꂨ+WXQj6xR)dC>&*tz/ކ0C:mTC. 'T˿G 06g%rllu;*@oxѸ`3m=nzKC8` 6ؿ6jt$8 .:,Y9稛Z@a!”$.n[.Fc~hbUp^a@#ʙ+jgi2`gbhè71@‡<&$FQ@\9+Ѽ)-h)3>dlqQXvo,`pd7ܤ45K ߹۷nխym&l2% 1)_ךB+z2P ^F5N~(jb:e,Ec4L'Kd%ZG&S8'm2k'18o!iX{qu&d^0*>!1²{ƚE;qYs]jul%cغ:Q- c>T Laύ)i8dyY\gz>@ N)#AUu4t@ئ0C6]>9F^ -pinjր7l(* g SL1wHa%mtieV![֢f8s zS3Qšy3ek\W26(;ܩxǴ#Ho0!NMsePయDa,i/Lni NUFQ &&i߿#lڿPOP'=?3͙&` 6׶ECT%I\PCuRLVh|Kj5N) b꾎2/ \rUI6Ks_}q+ﲗT: c) ]E'7(;1:>?ž%5 CCʯ\Q0S(GpnuS X,>@S:s_q+X`VE$q*zx zfm& ZQò>{T*2:\RVs<faaH`S!He4hRw `)+{%r39[⊲Xw|pn7 C&vQ~ƼVal)G]傋s8Tpغ&# dsUTqMC_%gwsּh,GۃRPǶ ƫ۪=P#Sd*BE]K&v>V`ǴjPFQ5 &nh443 ]=f eÇ3ϱX뮻N;l:uhn#6`(+6ooOt1l;X'9$݉HK>(mddfx>1lX0%\JkMӴjY [wÈradqTXJ[s7n6o滿[yk_#CN?L۾ O}Sq+ƛ;§qEm6檫^¾}{ٳg7KKxFMHkW:|/5,nn?a *ܷ+=q߻ @ql n*iBl8AACp냞7Ɫ(kcJE誈"ʕ}< L^(M?~O&{$x _-g)b >Q Dxbm}PnEܫ .ER6X?gA,Q9&_[۞*) !clo2WЫm.Ke3`cC:UTap*'|aOR$ViZ2yuMduhoo5;krj@FE\$P~AN Zn:]c؁nBjpm" eHh!^peMC PUrݤU99r8G㭸ކ&I]|(h:s`bFxc44R_s9f|ȧ?9֭[/K.5kpgSvɳ.yW]֭[u]LJ>!oO~2zپcW^gp-7siy+mf:]SOfϞӸ[Ps dzu,-%Svwl%q _{A؇1Ѩڬ1 5:,H@޿gҘPOz2?ЄX9 T̯;~{=xll 6` Y_78*g"ȉ 4IMM}@aj5J)t05_`J˯.qaWuksny@UVSn57Eb,B@%Dx]ĒLMw/.BݬͼRS%M0L:Pc2wsa=0Ky 68ucB}q tR[n]6RNTV-  PPjJk1'"+I4d*S\h\ϟkJBCVO6 @?=k{,ؐ&RԈIV`OH 4FI9mtRZ1eºm&STՔ:9](#P,Y+ Lǔ bBV1u(d9*m4(̍ N;^+ټ4nV>l?Us8p-[>șgla'g#h(JC8iq±;ftc֭g9,,ؚ[nk1¹x$cz$هR}2??o9ukhĉ' XXgݺ5vPm870J:4p #ٖBM^^sDm[E* 8/HkOɕlkPllh)Vw(ZN*vЉ-; X`Sz$_L},W{;fQnZ_Rʼn5$HV(Уu\ ]XJ}:W(Fs霣,K:d#Y ĺff['.~ͬk9b=JSTc/.G0kaq)QJ؆i0!ARJwJ臀7xD@G2@{|6tm&cG9dlC:?2(1;}3"[ƣ@߶(pIkwqBt1d4Bʧ!6g!uyT 8+:(ѽTRW\hH1Qd(㶑T8t z O}֮n*横 KK9G,/)z*6%ss%֊,үgݺxڱFD:A94m8[E|/XJn4>V#|-ɍDǹ;Wf%6~V` 6X8` 6`G&urYR jʲ^'Lj+ 'T`%e hU;s&W*iUJnȱlQU`uሳ.Wy l*h\Ly;Zh}DU׵@fԱ-1ƂTGAq d ؤ8(шBNRôs%%fގ_(MTuc*~3w1; I- R_Vy"T*NJD`WRZ ((~~${mçĭJ;M̘ܾ'*|$t@;o&6Aj5_cX=:\1~kj\BeF)\`emG$|KKKx-LQ۸L$DzŶUWAWcѶo v7xČj\ۻ}DCP mf7 Zy]w ^^p}Gow9-[2p/OY\sYgb Cic3|ӟGҗ .x*7wC)dJYXX3Ǟ}m o`iI2ۿ_h?yu1g6̕2ah9Εͱ/sxWZ|ꫩW;*G̿w+/W,Ѝ 6`um 6` vut΂*-UW!/1w=W٬|^e6/ֺuqRB،eDUu@FtKϘt֭NDLeͱEZi6A)LpQTUR/~'۬_MArA1 {"zv%X>:`Mu)V`dD)@ rpRRQ!>d\R9n&;o֩lFw~Z~ru!|ɏ]V"`JcVA-B ):bxną^yǍ7wl媫/46dž R_{{;͛OGa4{^υO:O>5kֲwTUx4=S:HFOz0,4el5>Djo~R1^TWH1PM~GpQj3` 6X8` 6`G>(v1uU*Ȫmr" QY9. }ޛ?;WLE(bz<Kfp1B\~}EjJXrBgΨJ%H,-FC.4su:jgT!r~曟>s6L+Jz_CY8̍T])HrB87o>~)Ɋs8ӺBylZ$Jche>Ę IXlK1( yL-Bpe2M#?=Zjv֊=l*EZQ9ncΠG3i1^t O}Sy% ;Zt:a6mfyZЪGpEk\ȱc4ga~-zֳ)bxSN>_B63Vb(NnV5w =k_sEq'я~믿ci$qO  vE"{tgkq!܂s|c}@ܔwXZD8(I^QDwՒ8N.swG 6`m 6` vm5`,s 3g@Qe.>S龫A\J>'Nbr\u%C_R+eC-,[ #. s^纮ZwgA>hZTPӪp}sN|~.[$޷;t+ʘ2^"=/1A!$%ԯֹ +* JXmxeeV<ʻuYAso ٴ۝g#x4`O8x4:+꺦!aֿ}j,m۬g|֡|pJ>֝>6e&^xO-ss\tŜ{9?K4uCYXg~~tʁؾaοB~o an~-۷biy (<̞(L:xÍ83ps=rwXG? &ӚM6qp7Tq ٻOspL&8_VF1[\ir\\ĺ>L"zW7#QFԊ(h2/ 0Wb \Azt5Z>bo<*)qKhD$Oa.sє da۠pҋû NbAvaاlC^XVI c΢~ =9gq?NgyE()O1n`tSTAexo:V3"|:ʁEH# fA}EϏ ryewJ%}PކoGH<8Laϡ5eI5N)zZsӔ{@~y߮]h5/yB\gCo*xw*mP[믿;|X[Bct 2aBbt5=ӺQcLؗMijGE(oޣ{shF8Oei0Xnjb4մA-*,w{<-:g?yVx_m;)Wu4iv~ׯe$Q]2LQJ»fWb^S hDLH${.F)3CXl(1*퇡]{3P)n5Qpaf{4]ܐoƯa~oa߽my16`_ (0 6` ڑJE]p XEC"h9 8@IfΤ6UX*,R6Ϗ Q`*bJ6Tckw Eqm\<nQh9UH3\uc  QEHa(.o8 y@.C[*RN)K+?rDQ{\pZ #.JA+ѝW󮅇\h62C[4hϽ󡜱*bϩz 2%@P4&$PN(VUP* E=R"ƘsyZʠ"IǬu!ZM*Bi)jPFuq8q;Drs | $_;7dJcю &@t(cZO B׬a~FS ƣ1e\#LQnC,QYf X^4aCkڄd8ҰҦTLԡKctT!h#ǽ%ph, ш( 1a|B 8f'dcş quUq=p}Q7-5?1xpL&$˲C]IbnnDaN,i.ldRQ%sy$iNݳS ٸp &|P$A&Z\^>W1'K Kl sRd1ZkljF)g4.ӽ2Wxge wNƙ ߽&]Y|Wo~n&lhɭ+SQYkSĨx]tIj]Ϭ9r,wg#hʑiDq EQtΏ aGt䂜եu&']t| a2RGWՍ+o/{ :0 ¶Xշ S*kpfl;1 8GteTjq/--%Aަge,OR 8i/gX#񀧱`eQB{Ox) ʲW\)Gr<NQyeQNdDHK#N%7l6ɡaOtZ`6WnPᴔZU5Jfܲ,ԍխ26o9gO%:?/|3oT@6]w317X5L K֧ !!{cy{+mQjJmjHr0VGscF{>z\r(O%if.BWq}픢׷1MǍьcC)FכE#bO){vcDa)1 %Fm$eg<ݖεYSail^FEA=1)KDY` zRQ:lM F~{\%P҇f֚xUX`_}ߙ/G]6/L~MC/]}_,[X?0/9} n=W͏X/MomaWG*F/o]G?[ܻw-Q \yX-&~o_Y~͗i:Pk {mo{['ݟ/lxYGo`EW 3Ks_0lևy~V>(YdXEp0}Xݽg1CfuZ,Oz*oݘ~l>mzѷmLk1WMH/j8KqY+7*\8%/]k!<%ǻNl%$r ! ?T0 ݴAmIZxU+T`dÖd3m,:$ԱNΏge ΄6Nvq%q *(:Է1HX Axr~8K?<sxߨB&Fp7LH`*{m-(mbfנK)%&A4\ȬE,cDy  LnI^Lys]GbڭYDl2NZ͑HýsBQO/yI 4MB2JyLYbj-Z)ڲ/beٜFwDhQ]:oΦJ;ݸ4Ji&~"cRűP* 6oB/g%^w9Q\M8|TZcYkd~nNDQmHc4e9 aBH023X˷'習wAhۧ<<ۖL_œ֜>a75O_2r?\ͥl]|;]G 7_.T|W?^.O?#dw~[ٳl)6,q"KocQ\K#Kw+#Zml`<dDwrucY;1k}fzɷ傇D4Ul_9FcP*ƽ 11 jncyk19!CUwkծ&Aɼ*KN+&Wp)4ҠKqLyRڴqHIO2XTJK3"?.El`moObw2Eu/#Q"GZ.q%,F*INƣƾc\݂y\T&P6|CŮ|MPڦ cX6HLG0J1N,(˂n0e.;z_U})t:2.(C ^D@G HDpE ^/Ƚ\1;Ip{j^ywز |vGE،;=Ѹ{ >wgOģ{݉⨀_xԓp@ wq%'=Sŝē~R,nE.z?~Cw ,|{N}p*žw1t:͗wz,O/k\\M^BwYp% ;n=V>W} Wo9k< n|'w=}9x_{#~.ypKǼK3~<?xmއN}ݖ^BQưNCa$=wm%׼I4&+FT>Aֺ,%R(c0TXВm)Z}IZ}s_?O;oO~Z0o9h8v.=@F9uӠq*sJ_DҶ9o3ȤZXL(??:* Nȗ17"pxP guxScP P!)Jxy4F":DC pP ],`H'_j=DQA:!UTzK o + Ɨ2Es*4&h 1_ae CA̵yejK nEVI].@ ^۪SfUԡ|>ޯ5il0w?Oj.š!s c+QA1L4WF)lBJhf3si{,q>4[gB 4b0QI'{(->܌b>\5;GpҎV6aFퟃ#c^t/»»C}_7ĩ2|˧7^ $C߈'e`|Q?}p#W?  }sٝ7 ;'O>/7ݟ u8u$C9?ۓs)W O=Lo[o? Aj6hHm N!JE,ΔRI%)CsUn>.iq U=%kh DB S*:W[lJ)̓2IQ1}^=JLxܨLk9RS "l9B?~~9ȔjU'!.By8̯!njNoQm\qm'l|oO7[MG{[: gmNU7bvv>7_?swvܥx |ξN뾍'P^+/UϤݪ@~sxAso=Ix?k0~I{N5'{6̻a_??76RXn l{&y۝sݳ{/^ށ#bQ;q v7mcP7m.sW}?w>x7womSg>Ǖo=x͓>9=Syq;wݻbo-m9|o>n#VgU -,p9o0c+%j*kw*Wp)Dy;檮|y%خ5/ „Cpy@yѺ*x?ƕz;9 S||t~rF3ERL:ȗa* ED1P(Ձ"L//sX(ATs5nm >cM]J9;tN Ȝl}(n**g[HICЃBʉhìn(p'@*@yLC4'f ++X][GU7k J`Pr5S L'RǹhѸT,3}y40ZQY@U!]/@]5P A#xۘC)+/d3Զ֢ix1 PJiO0NQŏ)l5*REzOT\&"l̓L/6XvS"s9 c(ty4NpLnj86/<|H!+ڙ):hDH_o?}oƇqC'w?;bsI P&w? O*FC߇/eg<w:e pgeػ8e[-nTX}XÁv} S\K_Y-[o?vey N0v/#z{=~ OONo0ǧe\XGulqv`p`رE\`9nn7G#0Rþ7ے?G<"s)3^@/v@P*S`  umQeZHm9:2Rw)Eu̪ u]c2,1 QȿT)1IqEA xٟ%&Ʀ0*)#xTnB~E1DQx4(`۠qD =T) F]"mDtZ1mvl߾wNz #ea<c< \5n{9۝@BD[ZP{ дi1)߅?Dz`#$Moöf5U5|no&~ /jnxooxsO^[=\\_ 3Ëv̽sN%^o:]r OjEYzjNz啸3p4+҉g};]iGoAo~6})sQ]w%o=@?{g5Hr񰻼sN{% 68}.nG> >ڊk\B}Qx`_9% \ӏیr8>1{74NXi' 4+x^Ǟ6/^? zɇx[o06r@&$,d8K=/be|aŊ*-s΋ @ @k.v'x(u$ˋ]y8//1* *\m ')oZF P-%mLy:VfsT,U+G#PhN#1 :xJAmHц2w:LN^kӒǠ(co7*oo<_]U<=XS{_M*FUjz3zߘtC^>dMG:{qwfBL-=vK?]OV y>aHmفұ7\yv8h48b'_M8Ώo?N0L\;oǛ^''(w~ͯcs߸ozKq֛oBt EGc^xh;N߽/( NW_|'7cVƝtp#E*ЖOrO XZCi P6"*BkxK}ͅ*A y6y]XJ>3j)Ceh  BvnSMÈІ4! k BݶPp( b*jfT- )htV5!2-  =A<.("RFH<2F!({|T#*RoE<Km8SÙ}|*(Ln,MQ%N:X:v'FFc0յu۷YfujP5JKK MUa޽XZZ®]AQ4 A\ld}} 8Ω(/-aqਣwbiyᨈ 8X`cg<\gtΈc ;G0.1.xTy_3\?ۏí[o7_@&?+_*v][ǧ'袋:M⒫7T+8ci8{z뭷i7㿼/~˸<a~[o?iCx&A{_kf,)x&-XYkvBK/Õ#٦ ] ʲDQM$ՐhM926:7z|X *._{Rs>;RMyXq|_} #bIqNٓsAaKE9T=\GcNзS5[" qዔqU]:Th[%\Hז[oû]hV@I啂S< 袌*m'8xjBK y[m@+Q%I9ېId ;ENOC}ZX/r\>*t A !TW!FǬ*H3zMp-P6*:,oJtRU[1i:~tT;Gߢ\|"ssy p.?gLa|P Ơi  Cn(Q1P6E'^K!Q%bnQjl]>+n{U`<^lU\{n¾5T:ppϺT|4F%f0d2R 7o&E{?=څCb;Yq˖-( ,|(NE `(ʛNJŧL;QA#nC/(L[$VwQboU!D cҋ(W*yJE~L쭷z뭷& ((nRX" k s=R*>7i+Ux{|mh_d{{t:ʜronLő$#N,p'buuЬ4Dh<H!D @̛G/V)rH==0E c@>q@cmx/)>+^k9lUs!v0pEX)!X)mTJh3pQM@ "6!) h(_*N7 Onk7A@r-ӬMa|ڔi5,AQ@0.L4T»*xȨQX 3*CCM;vY &S,j39v("=|I+ \SJ@; `gcˇm+ s"Ű)˰IΙBAF|檮g8l``X*d/GSmېZTuxh MU7Ͱi&w7 fSpw8*t)4VƴN|x80ԧQ"ErUwOoR%.LJ?d?ʶwu)S_T)8gROw?v[TdByΦi:~#UXR#6m^(Ppa K(ChSBhVJk`Rkd; ,Klڴ)*"Ip-$\#|>=x(+RzRyjՙG1PM>qqpc15)$ӝ.]47H$_T&S{WW\R86Gb|cp8 UUj` hM!VVQ%KcǗkkk3Z6 VWWo>߿?/PNyE׍/sp֢%xzUy! 7NՇ0?Yyyسiݬ^Ik9ɗXݑ^vp{~- O*>{ 9܊3z ([oۭ`r?\*,$ D $|,qm˲90"U4R9d 3ޞa>h%J+4m w 2,Z2 *J@+X8=$|ۓ4 irбZu QPiɟV*5>y (KjAMSA\CАe s$L~ziqn\P6'^\B*_` X[]p>xP7r5lPq9YxbqD}>X\R?B äM(+er()obʳ؆{`T vii` /XZZmp^XsGjy|,@k Ea{ F/<ܾR-Ч s˕v^~L!!"?,'HkU5VA;R)8[cmpC\=w`@m= T%u1iLLXp`e4d}sX^^<WYcC5 qPI%]y4X灘R j+ Xȗqs/T)N|ݗJ9,iR&w,zHY/ǀs*ygwvU'JЫ9[o?z뭷zm#L}څ:5ZuZ@ nH'‹[TȂ.J+WȐhV0Yc=%y+O.s w }YSUS(4^`8xiH`vɠNE*Z`FY:-"!|^5Tl [,)cETA%x8b܂^!|~A`u!7ybR8!h[ @0\(PW%FMPp^Z 4:D} 5}dsgoh 0 /@U * M q8 (0Vnc2Phʲx<2ʲ@U)"wHhɢ9&+%傇om72n<z(T f()ߣߋRqp_X0]`}uu1nܷ 4ؽ&ZcuuJkq.@UUسg&XGŃFq*ݻ`-1ԋ{T `L믿9uQr_Vh&A1)fJ2*EUw|?ɹ\7dF+y|F% 0s!W "o0_^CUgA!}g[oZ?3[oۭhr umj7-UR (*6+ r&U0f cg|nk,J*\&yHڢB@*"D!x4@r=˰) YyagA9K=1çA T9+ePc t^0>xF"+[WZ`HJGʲRơ9J*K-|A&N!ܔ;J `"  =VV1`cm 1_CQCo3pãSPZyNqƾƅqRƦQrԅZ4#6_fh6\ yKKKBq9ZXwýsmWX+AZ: ︐o|MȹER&sUQhtMʉE5Wq p1.BCpTPC/4<4 }jV.!pҘ`) ܎䜨u[hy{뭷歟{뭷zVE\B}мvU*_wQ-I; @Z˅>߷T|%W1+WG(f: 9`B)_hCt$Us@bEমC,{2DBڃO,-l5ppP%UdʧnTEy(Ef?P*CӀISkP3+o{,hPM*Ls+ @iVGf3;X8Uv ABa e;,U5C!/a@K`;0?n[iB/ZSifPWTdP.DX#h9f3TMMME9 XWPRX(+I]-mnXlK)nAVLN`EWr|vf00ԛy1=ko. UwB8JqәŖMaBHI]RkZ l(`؂0Sz J0*ŀpl8*Avjre C4> ڐ";J JE{E³{ )+cLr9YxO`iL@S4$in E!+LR/P`i;8,[ .~P[oz뭷z-M* ciyqv/sUg[%G>( 1iIAQAyxU\U%9"/.yUH]ưQOVE`(NJ'U{;_@R @^SQm0au~1lN;L>KOr?0Y n}C FxÃ)7p\{xV#D66 qsՖ4 % a{[-Y6srBP0Z Φ)l^)ZciihH! uP^rN_j3'B ù cxkaEQ0(@o9WxZc<vamhVWWaM*Uzv`<Cu=EpJW{zC/ ^Xk `mƝnpz~i/L:i f%?PQx i-6}/yqv_[o@z뭷nQGŕՆ Kj#U :9T 1c 8˰6HL o|tUD D3̩b JҊUZŤU嶑FC>4EsB91p*񁂼 Hq<@.-1(aFy[ t||s@*(Mt| Q^Tm4w̦][7oBYŘo+)2 ?g]K (R4a`P4$m*Ր~sZi@m짋NN }+= QU6`u} Z,//a֭k̪ 6&0Za<Ɣشim`hf3LfJS0E(Ҙ ѧbA9G) (m4X[[:)6mڄ`c nw:Eef8~ EY؅|v~#繵 +9=bw1EXcD+}"̝[o?z뭷z-_z݅+ +O) ;+6 yRm\Ņ[$*0<.=9rp 8Uj; #ںm@{) "0[ P+#(Kb:!PXlwZ(o3R%$xeL խZ//`tA,X s@"pٹ\TJcZ4 I}6(X޴p͕c;Ha>|o2-K)*s',υyѳxU`0 gwRkT&)k1ش̔; k|QUzx 4Nw1u]c8b8@EBt:IQGe~4 ibJ#8g|yIkctL9ԏJG1Go$YIqZ ~@eҗo f3cP%cR(ʴ"mz뭷~fMv=P쭷z뭷[$?B3>J@ l9b+{ЪrE/XAbp8SJuBr-}rFy -YQ)sc !y{%1ৈ IDAT՘")BZn?C vWSo @j{<* UVDF김ҽ1DjCЂݷϑ@D,} hN @>Xf, ۩@Ezxu9\Y(LeLpt^9U vX+LӤT`4ayy9K8Ul1p Q@䘓 dȽlouW.Ia|>˟bW9H )8յuL3(G1!G=MScho?'P6Gۼ,FF<}рu]cee%fpc<cii ZT3RN:Džhh @`JQET6Jj,}4PGaqMgzayƁJw')^΃ݗ2=y˹UC{뭷[{뭷zJb.  jN5a.خj0Wx\`IPpp~E vHa"@nBV%hE2tZ+r7(y)gt,]* J`KHI~B͘Z !DeJDJ)*HUUl/xbT"cR}ηC+QSo`"* TnwsY&}L9LȒ *It}jՈP8Q ʣ}jr'z<0^a(bB+]9ilkcnζ<30`K~*i"?2-##;1 Ǵ<.zw\L^T$/Rͧ$úkka4a<h6EL@ThlMDMgp۶nCcg5fuj_iy(R2_{7?6 V%;l+G}4?p:gT[E\^X@t=u(\3 ls?I/D1|.u]uz7)݇C<-, ! 9:jA*1E\pR>]ZRZZ>>POhTāmpL*[҆q70jCYZ+_kIPL!AoC0P|a([\yFP .( i6 0p@`>T́Á=J,1ZB 7D ˼+ruV1/O j* q \PAڀv0!h0Jc4a0R{džL#X wyFT44#8g4U@1Kʺ>E_<%_@0|"?2s@÷4;AJe7A`f~}9_b67ci)Bce M/ଇPF gSc,oބG(lQEsa4  9lQ+xi&lۺ;vh 뚨L6x4"(SjST11)gU}Ҫ^i.~?0jaH-a^wCh44}* <]m}EY@Pz-([o-h*@(S81Fh>ſ) Т-h|.ZkZT B!or!›MӴ(ζEQx&PäP2h)0RÞC4LI,RH̼R-Xm&simІe*)$0QzߢGX+ă$][lZ Uk{OajO *ڥ0/YA*@9 ׌<8A3R>Qn6EU]mjFCKPOՔ[mSY k7;!Bw!X9ӬD~͋Zw.R 1r#j "AjR=yPs@=sС:((h GXW@76Z4Z;)"WKTk3 gm `۞R9ifR,aEb:ZT@C> .n!zr_' Ѵ@\=k&ec‘+_+MBǰYRނA'ojVd{e Y,x[-*9 6*#Ќكpޡ 5pM) |˖MaJTe)J% 2w>O=d[,Gx>3t8c$ʂ%8m Yk'lHlOqmmV00uVE ,=B]@ E6zR A0+cJ AG5ͻJ)TUl*t*Kb֭شi јͦN& uLS 6oތM1`ElkZ:s5!Ttjm:c =,BHseZ 9~\yEyW~pZߛűqNƎm[o7]tEz뭷~Zm` I縍-aBN |gf19L(T>csO m5x(U_.ZX.z.RjFRO tUoj5~'uTG"UI%쳼]Bq8>~SXG@{m#N[agSQQjtn׏hH%!3ޤ_.F>run^&F sN0UU kP4a<8M 5nۂgkSSro=1m+AlvԞr,w+> t)_<R*+!Mcl 51d2d=)SG](J:OmἋJcZRehD/)6 Gش-[`M(AaGshZ(6X^^&zCZjp.(P(06ƽq 7f5'a9qS\DiZ;jR[kJm*Ȼ硾1(~"sqqex꿼5LlO/'}kʹ[TxҶ>3߁༃ה{ (Rtc|8]une_w9FrP!NKoH** Qz \zֲ,0aAջS^@ nq$t;l6`| svld;*rP3f_KHT~/3(XBUUpFli|l k |LY3n h *=XZom0h8S$5t:C;1\*gk-qB X0Yr-[k5AW>KKK tsCpM9|BX9@E5l[>D(霴+nǡ4FNU'K&=`I۬.}p o8;)mo v-m1aovsU(hx#+<qRo[o}&sNk?T[r1%-[b9Z5a*h!/s#U# uZ*jE]/f@#M}*Fr_tEϐ+dGyNdнNr['g <IJԢPI] A =o9"ۏ PC[ҍ π堄 !hpH `,|7ZkeIgە)/bu˕.+y-+LrxVP!k7q}XhJ++٬qpFc t9SucB@U՘ȾG?D{1N1Lj++N U6*XЪ@Y aIbM~L&8uRwRNM,Jra*ܕSB@Qt>wF/?T,rȱ>& {\vk/v2P2#q܏{뭷z7 [M XʠG:su+X*c **Z2rɅ$o &nE`%!9|ȕyZGJ)(!(VJ!(2PE1  @Qи Ԉ,ܒx<`@(BAdI='+y?;ӅwmCE[ 7ȇ:c79Bk)y:ҜijUrO;,1 (( : ]Rka1^UݟP2H P!;wLg3i/ƣ1Rf@5NM fFaPipZVVVufK<(eEz\p)4^oeQ9C > 1窏!XeKh` 7e>@/rW{,uxg.O_\o7qYENjgov#8s;/vP/s.7z @Z w#/ux5w֛G\\w~G1G_Ż6|ף3~98SVfx_fu{^}mG >[vg.;`K |k7&xs>Coz뭷S\?yQ$+;h*)Cb"N%PJy2|M+Z9ŇU|\+B\YŸ._9keʟyبl"X+")cd{IŨ<\"헞U2HUg3PHд $A6ReT%tBIX=Zb7;4\!e9͡l2Ju0/RP Tˊl) g,A*g11QKj.Dc{JdbyXklRpqa lj@rw*k "m0D]X[[McIg4|cغ;g*MPF>[`'dwqUVa:Glߎ&IgEJ\ P5)Z}W\fu]*kTkkX] xJ@}RnE x:6oތeed^c+NJ1W%I4S68 FC:^Ckgs $p<}Z~Ha~7{H Z? LObӯf,?v~'#􋿍7aP<g]Mmcn>iGD8p9>|{qgPnىS8w\?ksnɯ,\gko}s3Wާ.}׿?zΫgo} (q Wwz cs+qy/'?=i'⧼x»9[p>>zLu#jc`3xyoćp?7<=xCV>W} Wo9kyoϲIX᣼ȓ Wp((Gi9t]R~a= :az e*б 'B,:L)^HvLn"elO8<=tߜKM85u7_R1| Z43|,ƟTq;ȶ/& p JVp<.BAt=R=(DZWCA^'7d_t7P}T;p[^Uk 9`  !ay0 \@FAfQ!A Ȑ99ə^SwWk '*<{u}4Yu(z_ S{8~Ɋ?`iZ7 MUwKT[HjzfwC{/6]R{}ӂSrGnFA!pcjI v\~ eRRf4ynu|Q2/+LPZ]sc˰ڌ,;9Y,Hs0}2m2;K1еTG󪪽:VEcO e6tNYVLSFITd>K]'}]wug(G"AnX54[2be2V2M6?]y7Z=l{[ȟ gW7=8u;%pR;~}&oÕ 3ߟ 4mGnۮz뭷_NKaⲘmas1*\]|rn_UHZ UZHm2x.kwP@"D'!}Vhxӽ,\[+d<ި %dwv}>3]?YMܶMU9\6n,n0Xec@ii3I; Ҷ9Qt?C /!M@6]UqpF̧tc8xqj6_GBb|J)ȳ`pPe9++#áSYdJ3TReT*8mhtnBese==a}eȎ7{] ;.NԖJ)2\b;͘N&_c}}lNU>;F)h8`lݲq-νk `QϦ jM]n IDAT#*KfY'w;pdv0oh4j֗zeNq;7i[p߾wGa3pWqXi78d;Wbo|ԃxIꔽ|罏'f^r޹5+#u WlШܛw`|.v;z뭷RBZ#6Vah3 = !O ^61Ơ"t^)*`76k }c\p/M':Jt q0pp8>~;Hw}}kڔv>_x9D!w .nZ7}_U>U21U;:wAQTWLJ[gǭI^nqk2'_}6ﻐ|{Oz,P}<;=3ozs .4[/Kv} ԭy ͩTk\i'⏹}qW˸wp;ow |ZvK>dzN5O~|?Zw=Cy~=Vύ|6{wyʙ[bfBv PFoxyࡇp{K`_+r?>'^Yg#>BNپ s's]~9Co`}\q;ïS+[on}/hާZxt;vLWش$R6spI]SP\ލ0,T-j݁ .n}T֥ ;ʘ> e 8-6KzeJߋaa_1-o zZѥO/s7ֶIK{60$@϶㦁QRa6.5m6J1lXV?u)=i()Hj1ƩĄT`w=u4$ΘCTKB <h}1d!UqLkq\Ze_Blg iCt|>o 2wFg +E(<)B1ƭuTF"".7(㵻I- DZUUS !$JJDzه2`P2n\˲d>3.J6,9kkklٲ{,,(en`Zg;&Š1HWvp<<3Enn1r )N^ߊ6JdC30N,Mѿ.>{u}% &?&ٹ c"v-,<\ϘհN??2y ہ_+wǾZm(d~[o/u747 |RJȳ %%բlwZ"V lp) q<(SePpK]n]Bʦx,ʤ~wiPy޸-KZ+bbHCn}=sb74J RjuShΩr-qyҟqceca6'}m:`@f(( ,.Q۶P)'~---׫l42_ S7AEQ0Gg&˲;ƽ_o8L(6ml.៯ߟ\ф5lA[\vٴZN.n,9+|ǎy Ͻ!CW>q_gOauMV!ܧy={#{M]v_*Ʉk{NozS`Pv sym'\kw]| P$O&#~GLeNN;*ikלof|ќrE栻q+7<*qiz뭷~l-Ci`$l8] ~ .]0| >`ͦkj*W<"z6qT y^7eUUuϹ:%Pf0DnQgʼ~20% `غucaMr bu P45h\""eJɎ, f5Vʽ.+T|݄.+z41 e_B"laW] \MY@F t> J] kYJa vX0UjUt槸 =uree g40@ qϼq!D]ո)*vX,LƵ70Apظ0x|.}6h)E7J澳E7~l*3"Wi݁AjK2ևlJedY:8N)hL3!`|g(܇%h5W.zb*(QBZa*sh:Y,p8`4PXTBm(uǹ}lHA_ufbvt=ńkC^mmhc ; 7#>L 8]W{uo?<_CoƦ$Ld'_[PY_{[|p1cQc?W7`v~f'/rtL쭷z뭷_&[Bzφͬuj- ncq Tɗ0!x-L{{e7_1Mx~:+71=lRb1n˾̽8n<Bdti|V'\{\<.⏦eL!28x],)$%mtkp.i2j 7uj8@ <߾cZ3lc/Kΐ/iqIl hC**GrŷWFR"Qւ6z!bWh]=J sgZBx-[wkڹ-rSຮfL&*%L0O6m(,a^>ϙNH)FM]Ax^55u#2_\!r۰^."BN򖠢Fq>SqX(Z@‡ֈ vwp,d,KF!y74aWRJEHk[d&36֨8Gw  Ϥ u*>c)=U}ỹA7e=Of{6;l?GΜs_+/n;nq&ozxM:y9^? /zcxx++q>8GY\{Cl=8?.nׄ/, ,[۸nw)yMoHo'݆V_m͉>jz`Ϸxs6?͍|׼9𪷭+&O'@ cn'_Lҽ[z뭷t6q@!@vBAh7kT>$.CN@nbA³0l,MA_ 2`0SZ/ByC}cV5Uǥ}La9f箮]Aqۤ7}Nz|}8eeB ,A-Sjc&|6WsP[Le_qy>Knq=uN{X Lx<˨uMJ(Ds2 {*a,tDkڂʜJoe1VdVi u0CXA{M$Uwa <f s9h\}ȇ{CJŕnJUULSШTU݀tYM795ޕ^b 1U3De kMK`&z^H,2k@sw>RJpPdO¿OӮ ;UPC 89g]λgVqyѧ񤗜Ɠ<LJuɻ([o0)$ndk7X&ba ZVrk|AqK^p T. {f@Xԅ m?/ugKh\V'Нؐ%vuġ/{z+_a߅`m,Sq;:Ő'a{;aXVi}v b'lfc ?];,W uH%uSas |rBm 34*:]k Əu1smVB8RAS$mLsh?SUͼp>ajKakbHk,QvzZ" @7^X{؂6ֆYYYi(/]K$79b|eeMsb=j/x0%H.2E.2T>hy(ƿ"QWqUS3Yz媟cz uxhߺ),Y];!\Ģ(sId?00ƒeP'U):L h X:f 0CcqQ8b6Skx}MԉxmD/"xs1(pm7wZ񌯽{1H_{"urpԵ\iv_-N{ Xr>ZvѭyMu2Fx3wS5v=Y{뭷zZ qu1l4Чe TIց\HK]ucXõx3jlx%<'(R8m⦅2raIJ%nS*ϸ~^k8St%sp1؍qYAvd]pφχ@7 gmJxg^WِH!ahba= fNK\pM px)Cq="֢ GJ\JbqDԌEU m 9Bb@%(DI%oFP'\v|j=7 lׁUf Zp]ם[0L|0| uE-[Z3KbN9ł,Y]]`0`>_`kM]yEwFI6$iAX3^Y'$Pqme8Wl\ !\گtM8v wلPb zԨ$]dYP9?C| IDATʅf6`0Y Y΅\Q-JX ݍWݨ*^YƗuEineYUe㧷kh>zٿrMb `|G 쯟+nhFh`J6Ή\~E/5m=WM~Ȼd^rڵBߒgջ~&!oz?90wﭷvM@3PDo[o]ocHӂK_.RuQ0/- (6WzPuvBvJfwm; sH#>jݴP*Gvpsj@zi!Tkgx?쯟P L9'?敜暣yԛ7:@%ꭷ+{뭷zZ H1a b6{aӞTYnS3U1`HcfuZ+{Qv>wx;oՙ|ʋd-&[o?@z뭷6*wmq S\$ߗ=X%.o|OlR)U2RtMeIz,m3UϺ\/.#9-Tl/8MK 1ڶZZ״T M1ւMR!'Xs1ú,M?xu9Ujۆ Ġ m5^<.^;m@.w92BPH.Xu5hC ^!EQ4E 1䠌UJҵ"WcM(0lú=PŢ\.:eـ 7uPRF~ߨ&shp54J)3_}_Hoq8f02 jv7nCv\tsL-.goRzvcUP=so_z[o[oRgoR4tc݅)x f>LuqTA&Oϸ\1`JqbǠB qg2w>M'-&uJdcC_j܆ɤE=\ZYhE]K Xtp'rrB;ֵIZ nbes!lO{kS=ݘpm\I2=K!ҁDDJ*9u]6kJ諲,;$-.9!xQ\{D0Ƣtq $+_`&v yv.eX\xLU,* }k* +:4Cg>q޽_t?rcL*c\|Oϯߩz뭷@z뭷ޮoK6R&3W 3\fONZJe.!c2K638[8,bfx/9|/kpTg+_3= >c2~ٿ./ӎ4rY { P2Ďtj2,ڴ0m)"Ək<;b/3dQOAyC^P $n@zԠ SfKkM.v!&A]httjkUU ܉ˢH@7ISf *ߺ8Z "]P3 *čYk]mfy)Cjz'KSdlEE B]W0/Am-kF \7L:bϗR2K: z"EQ,GpBJT١1 6x1y"X*%I8ĢiK "dq1ϲک\\XI) cB41CCȝ<\FhLTLeJ`]aAוcEF #j| ñ/6C ֐n^JM 2dR+h0d>pCʲn3!}r s"EM͵I9\&@[ʹ֠TP3A7V dd13!kK>(l|6WM?(YcL&mӺ֔e! j)@D,# VVVȲufuU)kWF*E.+qU.оIH y1,rꪤԺvYTZXݱC ^ uPc?M2նey:B&YݜqjV;t.R?[/`uKAlqJ)!už={ؿZdB*xYa>JLYL3ʕ1b80 5v7!ud!AOo[o@z뭷gPt\wupQᕆřRcBڢpl u?` Bcȉ0mmDzMPf6P&kiT#<3V@6֩. UFn܉-%WI]gs\T [P"\8[ B\7Ug WJBO`T ״рD*o}PnR:7hڒ+ay.ژVukԴNJBI4,,(f|uMUyڹqKAJ }¶" -ut Bj]62@0(3dP>3("PaC6ڰNKʃgc1R2VLJfU];7c)05dYN$w]ϔ/oYr4iZkkpp/vj6A@ |`}}d2a>/r.Zq.?ksoQJd큈rEByf,c)6b޽Mx`~!gϐ&v}ȝK*ܮr`Vʼҹ8+$) "hܩTdRPWNpf޽^q 2EBSYeY c4RfohF Q*+iyw> 碟eE,& mڃ]k&ՄtJ h`ZRyp_V,o.":2 ߉soFbo[o@as*$;QVXhAHjnL uU<:74Š 7M1pQSЗ©U5|޿.&'1:7]`crCn,½xvc5 @'u\%x*i6DZѶqҁ~2Ŕh ƀjըADɅ.1bxb*׳){΄q3-[6SE8GJNvLDB2tMkrһJ׬5 <<*q+j3jLQ\ Rdm] 6)˒l5EGf ʹ6o7а8`_"W'X+{yu¹$.n tmݬS%RT#RS&Jպ?2C22scIHE]L&l6GA^8բ˘jt@m:0Θ MX߭u֥gbvX|7XWBE^dM[%fٺu+yŢfe͛Y]]qYǧw^]w܂Gsg2z뭷z尰A:E.nCh=qΫmBZ!\aCUεzVA`h'n.VID閪5Kpk6 l'+L|Wg) /뫴^b(ś81MkS)67&D( cbPuKW kBfb7΄2FcQԵv0|ΪF{&ރAcZ7q⠮hӦMlݺp [tIyJA׶]ڍ1X*):գ1Lbs#͌!B큜!%v!UI\1^}bF#(Sp1:>0ML֩*hTpA[ټy3B{e}}~f k*lҸ] 0ZedU`71A@فc,TPf~!KRJ /d{՛`ݵp}}tn=^]]a41LB`61(r>, \­}Xrn p8!X`kp\`AX,X_sc`8RUdqxtB;t`5-(S>Ep_97of8߷|>kxH4zx[RÀE]R5kdYʘUFaRv>cwy,EHn޺[o(Pp#o{ {!sۼg1=s L?,[xͿ^o?Wќx ;]<[o6a#/$Ă 0#(eMf0C9>-47x6RlT-TTj-Ez!ײ}ZuKZ *X^OTGr&׽.vsmCпmڮ;w ݬ㶈IZ49ʻj\Fdm "0.SBkDhSC3LݻŬ { .Zڵ=i{e Pdž]0/rI^ਏi rҵFY3D E.*T@cV.+x]-p4,jOAm c 6 9زe EQPך`0(طo/kkNw~%Vټy3y\SHl]6HD6ix3h_GEXҩ_c׮=]Yc^'< b[uքx>6c,ϝ0cGl޼]W/1o*ј"w*aQu\)6(%CG:'޸{?x7'_$7+wrEO<ȣ8\z@ZD~uSp^BP?kSȮ6l.SI6޵wֺ+z(+5*adf_yebOxwVمFiT{({Zׅ8U]{v*4ehe !ǒѹhդ(e0e[Aa14ƻ7w,(2c]@%]DI¢JX֖¶,kO$ϝ[e<~.ryS%5a1c2Ih]8snlmǤ g\7T>dw>lYn6R`i,"䔕f`\ٔr1CZNf9 , {#C{֞={Lf q֭[3ouu!\,{ٽ{/t *'l=4r T.rp *FC4PD15UU3/ܪa1Riapv}*ZiګM]լeYbeӦM C|٬Y+fL&Jo.p8 ϝ z([l⪫bmmLIjy7qtcec6TUx<&sv^Le8kX+݃rzeػWpnHl۸ ;7:R.钟Z;T>L:ehPCq{`%+++ny]Ve(T%lɅ 5R|ʹ'E9g2x4d<1^]Y;)[ovc(||Nd ^@?=xGŋ]5D`9?!(fs3?7噼qd~xSW_vw6%.V^d͞>C)~UWsGi#㎅Ou[sZ]?V_˧~.W KYC9:kI[o?u@m~nUi1VtnZ.AcW͑K;u>T b(C1elԀ1j^YHwgHO*!C([_h[ygni=b;>YQeEcaU0 8<+(Rբ+k jZƀյGւ=;`NEe\L1)5ThD&`UVlŏ#P&g3a, SӺreVy9{S\)8lݺ~,.]pm4V,J97ۢزe wii]EĞ+);w^Ancr}"1Z#$1ƀ5X(J{E2ԊY!C.+44*7-h2 w3wa(5JI'>4{\L)dmoq:ZdYX{^hS*IS"i<BxhkvNt].>.afNhgsQ̯BlgaFio0۵Ͽ?9d?XOi(/ 3[wwdE:'.KTP$QDQI^@D"%AT.IEQ("rEKݙNz<?{L{W}l @ldgސO+&]lvȧ8M4_ %Iع.6<5X{[s.=[apw޵D k.?_v>SNؗ r1cu88jq1ŜKd?_ 3XNٍrmOywL3up9k8㝖BZod">Y0Yz|o3ɓ9sL=D_oGu8%lAe,NRX)wlk3\go'9 r盿yḕ v ;h3 I675UkZRHS ys=3T!JkؿYI-70lJmՙ-C#eYIcڽ39}4ևlh 5u^s-nʹ=1\=5c#+13@Iƺ43IqR %BJ)k)m;PJ.R% B+U}N $ V.Yg1 ^|E͟?E1<S娖H v' IT+(r A3\.x_Xt0P(I6G5HMd*/jң(NRGOTtpvLET)e}z3 Rg[VA@jt^P8,e~C#_|TJKA>|.~/\_~<ہñ6Wh+P:GLNh콗pףӛ5+Cv⧮G3)xMg_,%m 4&pl_r04 ۣ˹ )$sʥOo,Zҿ鞜ySdO>áKg|7,W}#z ذpGhtwfH1CƇ9-ؓ 7>{oWh-kx~_qz_[-stΧ9~is䣧ݸKX7Xp~.~슿]sg|ϱub2b~:ܴ蝜yY\Μp _eȡc^-ʶ5N/&gp/fi;9;ܸ{?c\ʇ?ן/ݗJ%/ޡ Yz:3g#2NhJaeͧN+.Śs:>7xs~.4*ɴhs|skO9O_}dCf`hF3eѨdz.(-Z#$@RjFcΦWԨOuwU[.PZok3p-}ϭ#0VV}ZֳauusF]zY[5 .h2^*ܾeV*fldef4,@+Rwa" AVFez$ĆvrNl]od0#H!h<^x& A{{;CCCHa@D`2"c̢5cwSVɅ!===qDZ@z[45GB#kY,*I IP:A$ڤ H:HSKw ءtT.h4w Bxᘂ/qla5e avm(lmOFh]m)mX kQȰ}%شn=罴hrXFYtttC9)1mC5RJ2cMaBNH*>~Zfax>aw9.og7SO ȰKR8kMb@JTKaOjyB(V^?T*UJiPhAJ$l Ō$_z2ey)=,>s\OJ٩J%)*T*U7z):[GPAr\jD  $iVs/i؏vzR)U3BRl^3^]<2r%[@~jJV\6y ]"n1r'?}OjŦLl̻ڐw+{u6 ,m,Y٧E;t><:[7&}so[َ㫞]Rρ> mY͜&[pMa ˻]'%V/)G|l;Cl]{7ݷ̝a^Hm -3. yVE@9z%Hzvb˗zDCۗ%GwOdwܾ,yy}iChM- Ϥ[=7js,7wczC|ũ_8H6iº~,.{5ߌf4&5Q;ςK,2"Z!s_9[;L= Y[kԋ$n }ưطrLƢe㶁 鶍 e&F@eq C{\}; m_ V_Yehm 2iRy褼 LZHBOU'K#Pjn{ӬXReueU)[[-<TJ%KKa>ē XJ8M!116$-f||Q&''ƌeֹ)R},CF[;j5m='I@ )XCB? >@-@ <Gnj322q\.ߗLNN0==ETZ-SZ !s tuEwޞ̤9s:3gC{{[B83Ekƫk=/ڱLتk=_#W/`hF3xMw?+پg6X!`lTxq- ByqTY! f@<7:o%UM1S.bg;Nk)*޵Ͻ3"ya''|QR;SE m7蛏WZձ>tU{8s\ fu.}ySg`X`<$&1fѼ5hkқGl5^>hhܘW-yK]t;<[)Km6O7bhu3`~ 9^/WShF3Fc!,YL7U5@'Ș ~24@ΘT 4 E.Io2#@,7]@,4-Ͳ%wE'K)ȍ@̶\ \|vs utiq٠U ?sHh-=>n?r_km5`  k<*n[xR8} 4֚n 94QZ[[?44h**RJ&&) 311iZ[XI8! CՈJ%dBxAش^ki~R)>TLJ )NjsT0J+LfQQ3㻦 [VVjJNZ[[)Eӯ\bxo;qjCl70 E y$N54w/ۓqh3IHdG a @#J%5AS,Yz5]]]tttdj KLC&v#+F?FԲCn %5ISkLkjV<0LA(rM{ִ 8P(ftt,KZ~aд LعSAj]Rғ^kfMwxho+9nf|۞]BM,Cw~޼9߻g:s܇;^f{k(.}F%IQ;|l]~zSx˻Plb~ ,儯>*g.) x;=x7>%\1{1$Aы+.|'q^á?x1p—>}#Xy@k mJwݾWo`OaRs{[UE5}o+e{9g6;JFs6|s"6ܓ?ڗZ[```+GZ5L> { 6Hk`bs+g~40ьs㒔T$Jgi/c.C‚QJ) BrVYSHQKEMcv?j2Iui! B鴤 %M 0rhve@]}5ru.`UU ml48v?7@,.~]bH`5};Q_OB! B!6:H2T )N X > ʶI)`TNX=4 --̙E5/<,#)HP/OQ b 0Uh&'c<_8mcvEqSQx `vIN:AQ HٜB[vn ׈X6,Fx&EiGqD%)؛.D1b|>Bz[#'uO?YtV)k !QŽtP&*AzRHDQx¸y:X=w$EZY IDATŮqʹccQ6eZs'ZB}\R?GCJR \k I/^ܹs&#G{k+rŀJeΞ4O(4N\r f8attARV)JBTv mZbx}YNVͬ|oY+A% It(kRMڵRJB\NMce a yҴ1r/D^o$F:^iJAu'1SϲѨDT͜ a t݌WBNL{;MtͷɆڛ7k9sH'ōW"+餠twћ:?KjVu>zwg1LJLTyX/寠@Yxls??˖vxb\{]hTng .v|ņ ށ2*)yg>;,oT1̝-5/vޗ=^ 1ʬ~ ^(*dFr?x|DG k>^: ko op2 '_G%_w mF3JcE "cv*\H5si>" B/ߗIsS$$:G$qeb !J;P× G> Q_J2] &TUcb%!R"l>*ecم,]^ *VDKOx-OxD#@'hrAKcF,l6n*|:!N=')UB%Ac"@x5v /PI8*!P4,hM/CrDRM I5Bb<g!x"]']Rb`hg}ey|ZR**jB%RDfjւj5 ȑχ --a.cűXP.%Tʊɉ2ũ2hI.O@:SFM૾',ښ#Z|#搩>,@oEtXWb2IT$KA!NG[ 0,%"! =AzڀR\ FjHIK.GK.GS8Y!g)!'xO$ZHi\a&IDTRa. ϥiFemÒZG$j5rs-h%X*~hG.cjjRjZZYRc$ c>b5 [ls%FaH>'{p@kk+ ,`OPEqȡrGp'?i8hvypiokn]x#j1˔* *NZZZ(688HXdA9=K$f3i^H+*؀JGaѱFEAJ#<)yAh n {_sW@xR#H=AK ЗxRϭ!(6X]C;M _ *~9|?Z~|ݵ39 c厗|-gSj޿^^=O.G/q?mw{m1^W=Gߝyкgnc[urW|\zW1]O*o>ٜPmlϱd}8Ǵy7}<*_ɇP Z!*e߉}7?Yݱ,3 o=_}/еw絜wƍ<3|.sCvx*])γx_迎_[$顟2ťϥa>%',/|\>7X⤠gk\x)^yv;ꋧ/Cĕ|2y{[{m;񹋦8:O{򩯾7zFnˏqIqޙGIǂ7pXs8~|0c-Izd#\'slu霷~L<Dzd4{}3ьq^IK5& TSx^-ղ\ƞZl4k D3ʲ칍?M<فi=tBu z,dz}BR] CkԺtzVr6&ntn{̈VXYj:XVMIm0=H+mL ȀZk9&I1eXbJZM=IsT@z蔅h XZ. eS0Z)SkE6DIʦ:.86' Dbqk{2p0jZ-ijYvJ`Iشn3L]xr"uMǨicn3p'ɋtLS,7BXűbmii! bbfIMcxtuuQ(Vaϯڨ1tf" X=Pˬ~|kʙP* C04^.PhA } !=d]VO(VȞCzf#FHJ5J+cݜXjK,a޼y >S$*F\8BfQes!jiF׺?ˬ9mvrM4QJje+e@E4${k2* daHf=$YwWNzJzؽ-yU_~Y\1y]sjJń]Omc)~K~ٳU4uv3Nfǹg#>r9[_f{OeŷalsQOs{;a{agOݠ^)s3[Fd<9T`S8$٦y v|<.Y8&g#םW G^x5F3^h_gm掎xƒ=V[n>.r#jZiSRc9꽏p]gۤtW9\Ï븜x};oƸmϹeV_ol5޶6}3? g@8I'2a(J;[0D gق4:fW@s54[)e 낌|.NH.kScSg$YYX]n:ѴItv֚?dxݘ&\khC9rz88:Jvu_{RPGsz_en4N؁{7d?p{q=;pUgxẏދf\w-9r_t='n 0w@ߖo?u4_n9OJ7\/Neo>N؁\f^{?n=X~E\qz3T.}_.0ȲS.c+.Œ;ދ/=- {-a;⾯G8/rx_s~ϒO]w)tO Y^ P zr/??ڗoN̶hF3ZMBwhaB2O\5\A-t8\ms3V6 5^hi!:eTҺpQ{($+6}W'-cҭӷS AExJ#1@}O>aʠԌ[oOrl5q8erv}1C(LȖpOGGGBZB@{{;A (XƓ@9ًTx}FlֹÑ[rT5QQV3esLH95ـ>Bqgư+5I:Ff})gchc!x˳ilKkDQch-4^q6 Cx^e^عƤCv/ rj\%#X?xȂZ઱\lk@#jqSӕrUIimm5=OVIbl܆s鼧<;_ٍ dRi5'/> WRLJg`8MGSayq(J(0 j'DqrL9n$Y6/B311A__gʕJǺSkmL* SSSA@gg,@{ 8d^u}6O!oԺ@ cQ℉I%4˅ 2|)wi{`#ƼLH86E) \=vZXY簤en쾬`0`yLC?b ȟyp g\fpjK^G?-ZGڙ=X^1:>wu^? 16j H7s!'yyh)Km4yϧA},Eح/&rba\saR4hF3j}`$E.[IbGF XllpNyh|)0D+ i$B(× RF<)QH%^h &L_<[=C]{n8JJ2#F 3RtuM(yH+Ϧ2.שnGMS O>BzxRH1B,mۀgެ ѓJpOAqtMKU л=M:k,cʂv,ʥ,;+u`7\ȕOD9-g ²'+9dM2Dm}B4" {ɇgraGHA B061N ÀՃ1]]]PYrT!$Q0!d@ʚzښ\eݩCRN*wvQN\f|F?rA^Vo'* HiǘP :^Nö{.ҕ+@=U pNLLP,ۦ֚07l(frj8)iX^*<J?$q  )xUoJCϡ/% 8xvmޗwoyϧ.΅>'}vsmOSpݽ=ȁVQWbo[\w7^j@ñ8ybn/sX}쵆Ǟ;|熳N؆~v2{ܖ]iM7X{+-%塭g--000@~#VA !s^=3hhF3ьfg)CAd Fd~Vpe: YƉpҩ]))Dִ,.ns#2S},5B^,D0.a6cY1kbƺNТ3,)I-OI4S%P$)R CiZeɹ*ch si!LD3q GhՐ6.,`/ڰ2-]hm@Pmr^3SG.@BCrSme`HJ 肷d}|H8B!AGxA`ܭJ#e?Bm/oA()ʘ> )9aCkDal1}C%:3J:|0 |Vʴn>… 3grp%wI;/K'cK. hsέC< ߿Qw2)'W@c0~y&?_OoM ++Y'9zoo{ɡo,0r\q"b5\[.;1ky3wdsS-gϊ&،f4h?!ji} SgDt] p5Fx3$M{`HAF]cJg V#^.,U5,fSN˫w+.jM |L2[(fr-}K[ZXk5@lz R̍F^ lU e)Rf*JPhcd#$JBX DA{i CG8qcU%poS\)cʒo~jn֥,'/(]{mm\鞣)9i4E;1Zmiy=#N4 %$AusGHƪ/X/] i ؔty}Ga̙1=l.ioG=FMFC2K)saH.Z$Iͽn.ıB%AT ,l6ϓ <ϲvejAkॵP~Mc2/,aąaPTY10 r 3::00`BHDT2@WT+UO52N^TJ!BH"3>]DY R |>\nm;K1G5}FQri:fx~zSm6AGP|eitC9r.sѿvH 8C9Orqof#l,}|~}_.N[SћOF6s3ьh<7mᮟEhZIU etGFGyGy駩V+$*r) ]КwjddvՋg!qmLZvqi!e477U99Kbtڦ4Z.g^ipY0Z[Psc肢R̈A@ )F0- {=ϫn]`^;I5kqو,F@qk@\Þ 0I9G' pɤ&(R& +9@ Uxq,ZPrೄCu(N^hJgXCBz)RG6m3^ q8IfFj?$xh!QG /է2,QƍW-t]@M5MC&F' Jq(C4qvL֗'m[V]g~&԰ii:D1(haiYj5cY:̖]P@}XbL\`5-Zj ]*28:͢(2૨gy[F&;<@(Ԅ1.?o--Gˁoیuc#~×wmr^m۸<7hF3ьZT۔p5cCnѳ~=0ݺe؈tݴNt9vQmA g52RhBeKՕeZ}'24גWP@J ˬld=+{\g^ ht?g6frF)\9)0,?qLӆOzL w.'BIM$qT)4mSd L0c)0RgbbFL(IM%}Fhc442]>URc;2ms5$@i[2U8K|bϰ=^'BHa{selh%SL6,a!zCJ)RK) $:jlAgWb@oMm)< 98 6#|Ϝx-He8vunesYR<ϣqN3kM˖mLMMmH!\0&7Z? DZ rttɩ)<' JS$\Q +TLiETFJ/3T֍ۤ-9s"IbHgVm݇aIQФE9-cԂy|Qg \$)Mz.---lP0(Cè$HR:;0T4q Q&V)NMQ=B D#qw 7oPsl۳!/ށD L\U?oa'mI0MhM9M͖iF3ьf4_uۚega/#VQzIĠBp$I@g֧l%zP>YJXӸXڽk :!RB[>n]tgq42w_> qM}eΫIlh^;5ַu>=]l-R#&gZzҤNJ$1$QLeX9b:C $Z!c"e]f2uz<3jH +;-=ݾo5{B8F&uկy9=ՕfޙTk|1 QBp1|h' \'y',19S'˶-*Xِg[͇CZ!#ļy ' $G~ncI1j['|HB;%=e$B px_R*{- FNlDQBdHG4!I(InjT1&Ƃ2I۹9f(fZ"u]DxTvUqp1L2Dn)(iL:Dx\3N qJ4)0m5Z[T),Fkd>J2 ^C( QJ ٦!E3=P5Ęyц)+Q1Zr&0Smjf>O8URFP+O}iR\JHdžKĪTA7SٳI߹83b Z&$(k1(IJWJeQڄ6ח]njA,l:#K9JTb`ߞO^g><#-*60tjבMV*$C |ŸJ$h9<-Hb ڤ.8p3q\8MKmP]Ex2Fy$딤L]if޺aM8ƏY@maEQ:~ܔ2AT !22*r\Ԩ}~ q!u4mkaoriX)&74THLQlݷ=AZ%j5z#֍zQ>C=L4M06@ҵ^ֺi>[\5 [Tp=/3Zȃu|֚ c8p$6ҊD2# cC1902IS,!J+nj xCEheL(&Ji2g<ˈ83RÜ9sucT)W*J|kcLp ᯕ& PH IǗTJejENO&|~[:_|3[e+dbrb (tbU)q"(U7,Jkf Rɐ[JG!M -CH%.jhHI+V-Β <eu=I=nȪ&^^ש*Ծ7S*pJ48[Qʨє%VC mȭ͌&m+y%J-k$mV^|.=CH6FzВdDLm/אchTDXHtFUJ +!q"u%4EvQasݑHCH!!Cd5R$ rJ:KR4e43V .[aP#GiIӯVGzkFI& i'[K(imE˳(քvҩlc? ö}0XK>*jm#K^Ϫ-QYKlD)eW'IВ$5| B#Jll6 r6[):qizy|mՌs=3wdkCM貟ݧ*-qXVSr0Lgeծq㕽l=ךN}aK.iH^kq&Z+|dr1SJ7h& A1IRW6S8F A#``G:xvR"%ټ)H>G@d ,|;Ǒmc)I&V\E:WY)e<\ǡVR.@5f@FDAH`pA+/Z T¯T i4qA[bGj$ 'vK MWLjѱB:/F s(ƼA q=sŒQIs9CJc@S1S,+&U%$! fe֬p.Qy0I#}tJ#QWJa˜!MH2"ihqnB-@HKaEZ@=7,˓Yb *S[IB(1NDŽ%lF:7%HL" B؄Fa@ܗOKii}}}XS cHȼ3PʸW*Lq>g,a"N"jDBLn߬%f< AJrƙbq$"|@i$NS0h!"]w͹iR$aO-8BJcE!Zmn SL[dR4YҲfaƛ4*Jkݺja@W IDAT3}Kzı o6AlM T)Yu-#'_@  (P@E MN8k*m"1ob 7ZjCe0 {|88ҒPơ59dTd):7h4fLDqć?O=Ï<9GET#IL~6*tlq颴!ȓ(B%IJvdkĽHCM.IQv>OڹkVU'-AdQIZ7?0'h ۮV$ F5R'JK*J%Sy;mR*!qfjiEQ97ƕ^g׶Ī%)]*yqKuh4F8h>SUAS*q\5JegI@ ,RB1V u?L{cWe%+  (Wh%MuCPTw4tQml a'^ [msRGAK剅 ly-ee̼I;isB)$'$1 t(㢚/DѮ$<0i2ZgUIZ!J2&bږ: 5YT)J٤oB`&^e )*%qB A8A1>8T 颧g.NOW7Çc䨑3.y.QJ+5du=CHIE nJ7ڙ *+!Lՙ0jH!e^EjLr\4%L?$|n͵j뭹쪫yo,/WI&$1„0' C*͵R ֭| ! œO SuT'r&Hdθ&)qdے _0Bd@;m=nRgp^]k *FNc>E ([Z!-zAy.J4s^ yhIáZa]0D:Wi#o^U*Ð L ex+WJNWfs\.ei,lxRrU|1۵*S.n~-J!o1OXZ"5Ir%syPlE,mz8nAh4 ZrLXKr)B (P@;)x[s;IF--S`?(/~:Kw_VOd[W3c?M(Pa-<'#4!V [^16gagh2Ikk/vwd_rk N,,$׆y)U:*:$Bt5 ߜI2($"㠫;gC"U1jR-WEmOK E]2BRԟ1Kv0" $bZ/4Z8H8Zj"I#hDk^'Qztuwy#1$kjllsRjh\ϣ/]^z=,6rjeF]sU>elH^N-) x.Bݔd sOI(hMHcYMȣ3Ob눝%SRVe2-+s A5qd -ƌdv'TwgB|DPTDM14Cabqt k@ &8'L)Iz,fr9sѵs)fmHJ' y4v.[rȒPyu5$揵YuUE%}L<\c$XYbΌ'!4)TF.FQDTnScvu}?ktt(OS|6׆'IBdN=\6.JEBj2m`Ӫ-1\.MZw$$JG-. 8n#@=kS%QFIc$h6ҡRtIzDqVљ^q]A_*$!M{uuufƌDQٳߵnݯ UkxQWz:9Xw "]:'3? sK3^u^\u˃<7$N/˭5%K~RkoϡF3Z?Kwgw2[,;?i W Sy(P !I2%HGҿ͏ٜlgU"5YpݖOy]v(6v7Bϼ3Qm5SHfIN%LF뼿&ߞl%ߏ=/ҙB$-Kh(-_2!)Ж,OlΫ=Zq(m 1B֩OkLŎ}Z95=ϣRU8D z& BMM($&b{{\8Ӽs|ֺ6JjBRW^RWW0J6č̐s+)êͣDk8t]' [vI,бQ -Of"7O;C+&kЭӿ)QD ] ~q$D( HHL8K@g55S5(x4Kj7:(4B 51_|*8K,yR~Il_˧N}?{=6V)fÝ@16ؒ&LED:A6lgX24qLu\I uēIҚ/$$[ sO%_ˬ)wFHh@iM >ÇvF=vͳc>E^9x+IL馪u4Mc2888TUa>Iu)-9mǀ:6g$ 9s3׎8QR~ 0`$}(8IH ,VrgHb-O ]]j5$& ' Q%)K tb?jYw nG v/(I?e|3]H@3y 9q'O[ 3 l.t*l1]?8>E& (/%H6UVm UT vcfU<0N7֬v9^{h#_ˑbvkS6Y~pb0#+C&=J+tbVͪT:$a(̽ΨR\.¦i'zrv%J&Z*ϼ9N4,lR\U6\sR};.I`A3$h6 RNT5F0jh{9l$=L^ZWrJRAxp.Gxd@$8 4*aH[bHgݤUƑYh#AƌE4o#|Ĭ(semiۢkum8i.= &/УuG!WQC )@8HVZ:vk"5&4;C L GnnPkSfk7\umC͵ Yw[ΔKWWk&wuP׳z6IZ$ DT ,7q:gd߮Q[yG>檴yZ4!L=v7un! ^}df?z=K)2 4kp&u,nxn:N؄N=/5Y.9n|⬿!TNڒW;?u*kt 3gK.aқC.+]%s.,}/șg]#N^fq 5;Q(xZaԫ>?Siw.;,\z֯7vvGqOɩ ;f#*SbwJo1sUQ;%\sm6XObc~WA4ιy gY;X#Ωxlw>s;!6Mtc3;+QS}Q`Gߜ;|vZZ8 #WeǽW3f[f=z (P七cCi-n%#U rP3m}N|1'SGy*D'+6_%;o-:ÂdNgFzaQfmnyH>̼宝Rr;Þ"Zo/8lUs~u;&Zu0J$)(\cUTdOM^$h){lH9b#gq1qQ˸Hn -ґdj"V%ZV'E&!eFƽENb"t.?hڙZ'8@ erQ\yl_gnM>&pQF&-ˎos cDachန4m#MKzH5Ib]|]J~ )܇86Bdᮖ,53m:% ֪-EkCjXS6]>UYXІ m0‹+J[*eY`Im)9~AtA SRR*(JٽXg6NӧOCڬVq+JQ8XdB߅NYAJm'0,hs r9ẎqScJ2&Im)0zv81FbԶ7Nb(&"\sl RZ2*0:ƕR⹾y9)SԤI7vF@ ,bBq%/\KIzl=a쵅zkn߮}ⳜL_~Fo1%/++#Y~8okʛG/G%MGMG^s:9↛6S_pp'rэ5~9{qe@/O=wN{<~0Ow/sf_=+\r/5iӋ&sW>5sGqpU2A.||Ư%wqG~e)ㄝ`vW5"^`8&tQc*[pȤ;\cO;]Δ/SLזKo̯7㤇W%黏aS~ >x=/̭G}D;ǝ+MgՑ$[/-P@vX[GI>Yxc'醖h%RVVRjW[vKfǴTIciWWܦ0NRI{,OrD o/֩j#);D&2)kcmCy.:3,QTqs,Z2%_^:QL3Q)<ϥVPTӰ`DA`WXHRqVkH,Rٕ TRX$aH4ODq5B+RVzbXV_[BQ6Z'!(t" nCy2@ۈe۞[϶r?Y8}E-2G ƽńU CXj);ڃ=$yq D_{ƕ\z>:%:("V sqPH!}1pɍA0_H?GζI=[cV)&<v[DQ)uKZ*U8dߛ7B- b_2 '*q5'$SAvU0SO:xnFx9if)%gΠˤHBįmygy['eHcW/# mGi(Q*} }]r7b#V2 ._FGn<<ߐ}J'$"|.Ua򉺞G4I }p$)k$ :" "uenBH*ymf z396 (P@tet^7f~|L/?,Km} 飯YV<?0yYeU[ V`eȗ_ 3vڄy~!\rIx. ؤĚ'ny|%vgF8ߒ1_J V'~m%FwuS|q덙}ݼfqO[oGaPlS^i.+;ODfU4 V'U:_s햤D%ٚTA'Ndkz1|pAϜY;g.,DRQuSu!]\&({qU *:OJ<Ǩ#q8HGK8u#CcRiۘ8cCXc$%Qy2]8?!B*?q}MH$m"UUJ!\;5tJ Ua=9#GcȻj+e| R0 3Ui$~TAeȔ6,5L+(hP׳hנV$#:絝ka+߆ɼ}NI1a~MNMj$"Mvޔ*qdy²lQ*r(sZ̍N.!϶f2D l6;# %UWӖzF}Xg†)=>4"0rJLE'UBK\Δyuj-I!%ZZa֟Jms=JLe+*bs'lHO!zݶU>B~@[H2o }ҵl;~m2qTqߠH>r47ۊ\u<\!г߀覧U1s^dל|4+~WOæ>C<3&^ݾ΅P3'%0$e /{ok?<}t)90kp|jftm͹wg)yK.=m:jc5d/t`Çٿ%a)qL |_ }%t1䎺 q[F}}69g̀ѣ{gX_]w\k\ #@> MVjFʔ 69Ha$Ib§@ d,DRƒNVU3_kkQV~h7y%< 1(s;f߮̓a` VR {nFʡ?_l5!G’bT֦,D+ 6_GK@cZlgF>;QhB|praV f8. IDAT`s 4S ik]ݩNPIBReK1O u128@j#͛!i5@j ZSLD!&_ٛGHǨ0V)R1"EBֆ26Fi\lՈiw1R|ҝ^0=Wc«=WUZkvnŗ^_w=UK$0nGġ&V *VF=e@82#˒(KNVd;,.Aν*<) Z4Mb0oDbUg:@F$ɵg]d%0D:5:D [AV%o6WUke_f՜@FFUy%ng;ؾ+JY[\6ZkMZRgY`iHW{_a:oRS'qV 3HK啝#֋z5U3KFA٤Rd}HR4BwFF}YFF=F h_0s2c^QKba3ÚaF_,`0Գ7(PSEF(NyfƷ"+岿C3_[Fd6~{]v̓_1g.0d?s`e{`tR>|$9^fʜÎ%~ϑfX]63en޺vyU'*?敋 _ak99k5bHi|X|@}̺ֈ|M W}} 04iY@ B*|WEAC6?!MB ?<4~xi Y <2]X:?N{ ^}ق- Ey'y136\^JWes,n6l2O\}TW`Ksg}#[?Y`YbznjB<~w ͗"~z6$^}Dg$ h45ݔ,u?o &bpxeTmޒa7lS0Z>? ߹o{Xyצ6?5_d˕sF f3P(^N ƜٳqGaTفp:_'Ύ2rﯼJv~18C8rFkF[7ߤ4+^`7a^-h7bӥ>j5.4@ (P@ |[ιo-[}<*Sblrq+ʠgp3w;,&p?9ͤsߤ|lmW}TNfG/`b/;m [+vytk _]&|K~߿b DQfϙ;w3>ZkVw rv#,tO!T,|rˆG-tEiOr7'_eZWeoW&-1ԫmփ'PTꂎzg|ἱ\="&785{nߢO>j:򻻊p (P@> X|sx)6`vxTN_}&s#:5ſ%s."(]wQpKy/ދ9qEpixGy;~m&k^!MHr(~pa]^4z :^?1o>jՙ8"_k]Z 2I_Ee ckq䗹m5fm{}ɏz[XO?gDyQl83_N1;@s\q3,oy'3^W0rҺL0}౟é@.=s NI\@ @RHb=tD]!ߐI[*|Ph<é>걿fi39epoN;y;e/_)0rrl}WWȾ/po.<۳,.wᅝgnX. fγrON2ݛ[,ƌ7x`NVxj鷉挗y깷Px]cY~UXzP1zכzV`󍗣 2Wx n1ˬj}~o)/ޗ]ƾ˴sˑl0WX`i͗dX>-ּy |ˬR\t>\>4zk?epȳ6=Oˆ~<_$s4/+nFwd+<}G{!79&*&?꩔f5gYo ՜jIY O1 țQ4A_ʺ#$V搝VdI.ɓlzLZ2uLۡ (P+,΃3_dy>0%&,oէ=蝊/W9[VW> 3p۱GД-qsy1?%o5$ <{_r M%O[e\]̎#S?]b;s8.xx]dhx}de1gFf] qxc_X <(![4&Ƙy *R0Λ|Ux<_ywsVQݗ~fIvI,Đ[n~j.4n5Zv8*'+o"\w|זP_&._ڄ3G@mG~Vi @&x.w0QI|gwfL/^`̆!a5ռi`~:x q"p\3n$k#φ+'1Bه{*k:DDW{='&u~kǃs裋U@ArwՁ&1*tO#sK Z'1.DWz.ɴEez{8Cq|d5# =<[_.mGCwWb4%z~_Z4.zw[==\{0kKAҘܨ̰i2ЗG (PS='nO]ĄH&m\3Yn|/ƞPç_qo2#b?.}r8o3ok< Ma=YǣY>Y#8+43~\ws't%'_^Kz\\%XRE|<;={|}ػD";{] 0&n_kK.\yn,m, H:\sn ⿋P,PpfWb+:2όyo`}{'*н ,=},Od-NފWG*XIsӜ-f[1;w.?sn}wBY>+9su&۝C&p27͘Eis\=3F]9:5X|YQvIN[5Y.9n|⬿!C^)__*;r({6 8 #WeǽW3f[fu^dԏws-/keO?,nwv,AU8inuSg&,!|gy mKn!`KVpu1,s؞g\$d\f<^$wWV,;̞o{U0[*MV[weZ8d׳Nf>w8ġLN2k?)y#ݯ0"Bg"_?4\OÎy, f/T'bEj1Ysޱ,_w?M)[;N7 p_N;~Gr_$ cze^ǏH3v8Ymq0ћxdVHɳg$1vfnRW1N% q۟졷ƱCIgIvr.֙YGso wcsWܠDGKp g> ]@ |Jtm,GgzW*#y!q#K[q1?ӯڐ rw3;;>_ݰ.sO)ù "5x?rn> n,vܯooɹW9|ۛu'u'#~ X\Q q/Z}QPQ?ScXwppэ7s_7GsyOxp7t#p\q'sq9мrl+-.>fF{zKo9_8_qxm‹x症p_g-W]uTN6XY;$T@TPDTBR@iiZXlA`yyvs93蜺rT+qsL7]{R2I:{+ض}3W,8#}ؗڝvppLhKD3blA΋ oDc٪n}T2]]vufDlڦ=xsKh5vMeWb#hVg*9iRx. lJc([30%%)|oiѬ5Zt6KK@^^ݽt 2nNI EA*[yvB[56Bp¬$8K&VJt H8NhԦ)-[C&rwBrRќپM[vsz&%T1 KSQC*c9 ?/;t\6&t }+;VoHE7 J4CɈ‹x+^ng$c˦+J:A۞;pPьم}P"ãQwڻei+`ו`^W7ҭ:{5(AF[Р:9Q5%y7K^u U2дS3\e̋ઞܽ[\V%cC )+I(Yg&W(dHٍ6Y` ^j g5ꖖ\ͻ5G%̅5K!D`.~f.NI[I[DvɑI'M6_-D:PDo]ـܹB *p:".u:$l+J}art9~Z%*ن>mQK ך^wLʣ$d<ߩ2f曇8PֵUߺEhu*I܎eįzeԥhվ2­"5dǧ>b^I)dyQRAgwQ{`M*KYxI&aщ. ȑЖMg1` 5 Fy!V ->b"KBi)q H;{1S*P xR}{j,'sA~35a`>vs wpn,V7 Һ fdkx\Ѫ T8wd*6bkQćpwη,,/rzl,R\ăйptsAH\9{%$cwv'ߩCz<9_.iowC@|bf\,曬?jpdH2zWgrBI2Ҁ67$*5rʼ6y.?A<+ ze+U(4B[ww!ne%'OLeAXs:E;x/hz\,YQF! 79=PFԥS\DņqQ?dFti9iO̶ިgT[ቦ_y IDATKM%BƬiT)^JoS ]7* ^0v%` '`ї+&a-GꄔK|sqkqLJ.f'"3z\`pZYi^>g5$=;}̼FɤKOSpvPR$fSduYZ{# ?x^S2ҳ H&E1F,"jh_i1f )!KVA-3SFxYB8ZD# ;sKe(6n81gIbzixK,q;iVFZeGmґ6$Y[&1ׯhBRX<6d#E͑@|w l$_[ǯ'-졡{'ڳD)ڀABdl:h=iP^站'(,ZSlȸƀq 8ȧ/uKP!W~C֘Ańsȗ; t啩!ٸbkS;]j?[?1x&k;>ʦi˸jɷSA+~&ߛm;[#y0,{D Oܧf_%z( ɵxxh!6o$I"weINuW\'3珰΃uexK ^p[*w/\|L7UWd^T#V(xCRY]\<ǠJGw_˞V#/HQqZR؃ު}ߦŌkW>ΰ=h%/G9(QSFGҿ#n_Ml< yЉ*17fČT1^Gf^-L,6>>'nDzvHBr@綍C;f{G3%~"}{VeΟy),uP叇\]6\&|2߃ӹ6/`' SQIҒ@LuCU͹_u6ߴDPK6pd4m3Esl gn܊ :G%v~H2Mh*׫(RQ2 ZNV ,8~Ik2j)wz'c5Qt`1;?}I_6LvG @G@zk*ͽ9*n~:>-lX8a[bQ赐aD[75wc֗|1Q;`S+m8~Sn;5|[!Cbƍ3ڿAh;YNz N6Eb`TSȔIyɽB]̛cf19TΤ%|1ߏm2rMxczb% b`bj؟>XvE/w'?߈̲,{>'h/Jz:9o{EvcZ2sQ5O^2=!1sSf :Lc_'ߣƸ"_8qW¸x~3߯@ſ?74ߢ)6U Nn1i~,SV+oØOUňѮD+i3gbԨv ]f&hCV[j""G#,MVd6s&&Tϭ9D#jgWr+FJS Zo7@* h3s{F}7؟2$a%J#VEV l$1>7GUvLI$X8{>pI089SIE_LZf$EUg ]er7NRGQB$Nx8<|Dб$jML.x<;/0z7gΐ  fM3bb%<ո0R&VM&jqf%O'˳Ӊ.  Ǭ3;?1yXSȵΔחj<9-̷AAxɩ1*2Ibh!g)s"Ynb/! _DI7򍿻_ɱ,]AAx==Vwǡ+IKDd ͯ%ws)OZF&\."(    + ¯QF=f&h|={Q+7#3ÈEFwYcgAuZ[q﷜]#6x _SZ>V=v-͒k >_f88İw|ۇ'ȉ[X]ө?CM$bl?Jdw9C:~a>pn|ݜ0G`wv6L[PGK'Y    C/̥ug89Ѫկ y)_mhT&UsH*U+y:yqLM18WhIצzb%7lŌ64Anٜwś8Rw'=3ۼ̋)\_'~GP 9Z`-X3oPv|xAu0<$ O-.    ,<q-%:OԲGV3fTd1 ;8U>nA9`L6g#hocAHV kT kcŋZeŽ;G7ul & 9ET&UA 2ќ7Aѷ7QsqX>Ll3pμ+Fa\CcZǢc xTkNj\ †6d1sL1Rԅa{vۺ    ³Lfi~쀗ƉoJ C0uL:98ȩs|Dm@HpCtŁj׮V7j4\t QcNfc7HHlb[(C _PW #&&غ    ³e8d"@Tf MI簨j> f%4C8.qDc #o66@[ʘvqPbq7jll2d9Y;y p LyCQD+Ǫ2u}n-&IYղ#z?$ #ac>>""    3[ZJxn21G1$\*!;J<pm_Rv:4ɽLra<=Od䌫hux`]eUZ5qA&~0t$8ŕl^tJ=ׅ?NelѷH$r&&oq6}/=X-/OdS醦פ/’S?aR_eL 司^    t=>n%uxix[7v(,Ei-nBRAehz"NUҮCwW񑇱ݜ1qg: ȠGa]J _|2t+Ƒsvr~9YǠkº,=d7(o6o1A'e)3yyL};uqmЋI3ޣ.     <5R?˲ pyjլAiՅϟ@,sc2 BzȤU"V˔oῤƸ"_8qWzݟ    ѣ>0''p7lu1&{-gSBJmx OGwmQû8;u"T LOuQDZG̙(   ȳ̻zouvѿt[{ 4/Ϳ׈6U)""gXΧs#ٞBXv7m~ CnMl9\%JA $bj"dV}rس1C^ޫ7/>fmjMqHT>>q!YK;d/}ñПxa3nZv#.i j3sŸaMdG>v#!vWMgO(|,f-v{́y|;"+vLf1a?t`ʻ2}ggDεr#g8|& U4p"JC?w{$GǗ<իӪKz9B*4alY7}#%G%܅KbQA1;HnE(UƙĘt֦)ΩgvSgNGܘ*K[WS64BK;| ]QұAƺ;A%!"724rNص~xDm;F؛l>|>E<ς_95LaȰ:Z0ī-e?)RR ^5/DZƟ@U@k&U4(iޡ_n0dpH?W'$D}jրIxl/;UՂ9Jyщ)14GJ)$[Qnj\̒FbrG}*N*rOL d %~ilX-v$)$ftdDJRv' ꂿiV2HCAwmVL2ENumL6J ;V I.G2`!S;qi7L32Y&qq~VhbF.S>XRrt/%Lzg%SIp݆)-T"Z\dkncd#W(ɺ6LiɤU8PcX˔l$Q_CHKNìSʰ[XPHJ1`8]7|N}T=v9b[)ٞ{Q$'cp{W,rr0%lVͻ 'Ԓ,_Fkj:φL֟j u2\Z0>ðȭd54sf0O:LYv)k޷XMAɼ;DI8xū!jl;fxb]2d^Ȅ9ɮD7?2טxzJV~CWϜz oU:UWX0+]HPo|]ʠ"^c}F6A>CwHDUU>ie-LK'CU7FkOc?0a^DcP'y*)'3$C|R@njܟ=zY!X6`Lc;Qo`trVoka;˲st25y!wEE\Rᇘ1a>;!Už}Z7XG$AxF옒¹y3 (Wj|*U+C4s}hp ,OCFVƮȶ9fYcAA6wSJJ )DFEqeXn4m^;9x89| ~+i8x=CvB1J75^jE9k cNJt[AŜVEf(N!$)}hJ<7qe?rV>u0jdg(?RNgz#X+e_w<1}%2ґgW0cVTlàK\c >l+(.hùLݛ@E2}?"Ůtw=%d Ѕޯv׻4hx]522yvC.2<_"au}~ v森ܟ3_?)f2|5k!<ό!X#JٙfCe\~cLe80~JȇRo< M?sݙ}1w߈0I<7b'p1>4ް%LUW{? ~'0K9J|U9\3cZ:ޔ1(,9'!&fu |ӳ ڂ7QØu"ZcR׌WV圉PɌUxg71`P-тN̕eټO^ͅD9*Ɉɡ:NG22}}4Qjq%8| #Zy`θ IDAT!'3 2jUJ& q])ԌѿDXx6=_Bm-{#)+1hٷTCb`2 {Ƞ/|R;ܱc2L= Yo2AjH92Whiz5fFmCAw*bXqc _ƽ8, "t<k;{Ql;Fũ*[6 iƵ[E<ڶ&pInQRPOÔ*NdEC ̸ŭlqQ~9KNl5lz1l=ycʛn+T2O>}1ߕUz|>9|e ~&3xUo:uw=c>sA~z~Jߛ/0wBj\ߏ7f.>xadO\L7f\^iï·C8nvkHg#*=9,F^OأUp2i0v0iܧ7Ņ_4ās8+F}dz3!*B)cL ҉6-ԠC҈3ꚕ\JMMCj:9s0vRH8l V=w?82,66sn'41֭˘L&v׼ 5}eD;S O#0&bö35kD"JX3b~/J7`9og瞷Gѯ.-}){SINiMٶe|I۝|:cmњ߰z [v3oTaʍ3;pJfn u6gκۙߦ.ݳx-@B[G/aM#+zRJ2)ڿo vh)m};wՇ>gsy[Oe,|ه`>q;wΠ/`a[e YI8t/2Kbʾipl߻;[w\o>TAjVߥ6Tu 6,.8Tv<%[%HXIt@JT&3&m;u|׃=*T5]kvO?^S`.ػWⱨݩXƳɭ;w|%%Fwذ-o2mV Cps9%4 @FnC[|+Юs4. -:QC\J(m+J֤Q)SZ?F[M ]Co=O'4q*~c٪n}T2]]vufP:`ו`^W7ҭ:{5I0qoAxlQ} Inhڠ AbHqY9*eZȳ{l6RS9}6WΝ "<3LB>>x⦇8R,Ԍ#C傓FDt7_#aޥ٨!K(DN7kMfhܱ/EZzX?k{V/22@ng$dNkO>Q G;]x24NiTMIxxE&ѥ# U2дSF̋ઞܽ[a{/idTفq4Id۶pZ JP*:՚7/ nil#442wҥȸJd7$FBQddCA?_iA&){X,Sa %#L#5;^u*ML נg C*Jd2RQ]ӡ1~* I@Mid()Q*8bz(Jx*dȔ^4{BsDRN'CBK:pN&&/oLD. _%E2<׵& ICp o2#IЌ枉ܼMu}9yB+ќ{G ]i敯*?UuÞɽ; 8bOĈBGPd]kM +`M$.㓊\fWPuj8ˑpB4V\SJB=^IJʎda {PR G*0i}1e'vO Tҳ>P5Ԣ[d$G& ɰPHrԎj@xFISNJ&I&V؉wTOHT$t O`@qs~(4`Ө>tz+K*l*xz˕v{Č҂θ8|/C.! ŒH!McO Cx:V&$':z"瓁tx>텷-ܩ \8bx J yᩒyUUg~5ށ% QVo}'j5,c\!jbIKKgU酝]$d젒 H26dMy,f3O4o FԽܾթM-i[Qmv0`ÜuSTƮZ/z[fJ@g,bFVc#6֕||Yؔ+[Yjb I5a+Krr=rF/?c%CJr<<MT+t%tw'R)b[rYףIK+ГLj GxD] uXST _p/\Inny'!䅓oLِrR.&9L!6Ŵ -/}.iw}^dBbl"ƈLq ݋C^"͚J\w缿*'ډ2tvdx{lNP\l){T!3{1>uRW :#7`MgQLwGS;$lB )]pwsnSI0?[)!+fPAAxR]Qpw3b8\O?nlHe ЕD 0U^W'dKpދ/1~ll̈a Pn^QbfSxR`ϭS5 Q퀇|1onIZN[~a"_"qIE*&[x;9'&mnÌNE$f=H;EdyɈ("ds8W\ˆ̈́-9k P)q?3 ‰}Vn97X~.jX|] 裸j6pI.^:Jy,βe oي)> xbʸ?2z_jO9+(r"K XîS h>.V銫k16(ݸHM&)'7g> }6mQacϨ`]~a&n%e2E\$5-L%zԢ>a]ո燑pvHJHg?bQ <$H=:Xy܆&qvpɞOYOq>Il|? ȽyC"s '91+^YÒJbZu<uïJxR1gޔ8ǯ/̅YobK&Ӱ~L 6]IMʱۅgGƳL~ _ R`p3`;G <[Z\[kBI7|\THdpg/Hf\]I;w0k]|%4]^ȵ:[1yq<~2Ȅ]?ߖt^򙇩Q#,l q?QqCJ4e%ZtaHG0 \xVĐgA֕Jiٲ>e]H'\U,2 ņPx|_ٳRHjqJSj<ٳI7Z [1$jӢй덷W֗cC8l& ETE HU@c/X@޻HQ@Aj*f2Q>ޙ;wg~jCQIx z؟(T-?˞•GZD\Q-|ؼh)-.p&ptJd%'o&5.ʃ-u;ur&NőbO$H6l;FrZ*wNĥx.EK+dX^muqn [~ 6L-MDAɵFBoEJ!5R17.5KiC- W]8.omAٻEQg%V w@TeЪV.=@ pƳwj.lJ2*07qԳY;w:1@bLbq$=f;\V+QQs®װ* IFY#P^qoX8' Zv:r.рpbՖk$94#r2QV@Aq)\jzwB,9yG\@:.4z^D\͎ɩOoė$nƥ3ٛ+]dTE;na Y!MP@ T 建ӹDl15!(SL3gﰥܓχ po%mhh ϱ7`IIvF!G۴Cȧii "L~ ;CvOk4>>eD}F^v$m`|dk6/Q<+dҰ}s݊I+<lL#y"ԈQOYMXg~)4еIRi D3гCG:4Ky6J)M1J]cҵDJ@V Ð̰aEV$,*5&! _-n׿\qeRf1ITLTPPYq` &]ә}/}ٿ,x1f=de-oU5_&򡀚Z䍱cX4y1U7v=X)PԳ:ͫ+Lh}o$К k"!~*~q$CgNb+݉L,m[aHjw/Vbأ0-;a{+FԸs[3o\M^};k 9i<=i=NU;5{\._Tbx$JAch]1C?AB_+}^!`^ CNH]#g>{'BYJ*ӕa0pԳ<6\ .wFx' bs9O4e`N湒\ -HqXRq{ =:!~YKTj=AjСoMo*uYҋ{z嫻pfx T%?ueaazw ٳ^7xgh6'e%kcѳxl],]!9,\wg,]w-HQQLa:JҊ3?vG;D%{)(<o'S6Xd:w… 1r#JKKo߾/z@y췂-m9|(ԨQd>rmN:yg%K$ÖATTW^ݺh޴8&uMwNL^2*5[I?J:?o_$ߦ7‹j ?X F=S,5xyntRPŐݒ@|Kά/ *L:pd84T { EGU3^Zsן`g$f..a#-^ಓBB5i $Cu6Db1i%^jd3nk3=T _#Ƹ˖L| =v.^^v(6ENQؙNb|6w{\'ƒ%_dO.R{ؖg eR{–G˗@?.Nk">&͟{?6^'2bVXⱨt`O.RbOdž68IO' _:|%AqXILHGs2Ce@ _(v9JF ͷĞcBxl9r3©0D'fT!.9lMP,jx}]{f_=M( H9X)/u/Ct\Dk߅#Ӥ+̿kԝI&lGr(}iKv`{ 8, .^ub"$ɨjju trHvc==Ob"ѫ qK)qZ2.p8&D4~# PPރzq{&;I^wy,t $4d aҹ۩LMFTZĜސHUd :΄?Pb"Jo&44.}gN8莕%RzeϪ'w%LR7ЯtΆgS6k _sG믖:#BFOC:$tT^~"cѲ"A*j-@ nN%_E#e+2,I|\ ^棓5bG[dy* IDAT ;iU#|Ȋ^wG#1)l5dĂO>ڛG # Y?8w5G߹w#۷j_!,vjzqfa5oW )=K5| L ;cr%-/ * 1Q xobLj*=:raZ0re?\9d)Ft-{iN^ RMgt6Ah-!I/Ke}V8#gvA1i Oxi`v&3u^^JL>#\_qb,N2*Cl)|;;gn"Pfgi%@@쭘|;(BL=l!HZ!r@ ?/_Sݻx ۱iӪ%j>OZz'zSihRtlv@`q;jkqvHL v酣j?v#1GQٓ.aك=6HL&@Mίs9HFQ'U|A+!xxAՠ=܌$Ha0=Pn,wq·Ͽѥ̜58zZ!cMSy' b4K ,@ ?鈓́CIJNߏRrNP~-vBt JFAFqf~{reZ@` dɜ\3'Vӱ= ʴk\:xwm`J$JoGlJt/U3bjNdOKOB/NmM&o>!BMf(EIeٽѓR(3#K2.ŅRXrgB @ CXٲ_ke?.'L/(r> I2ZY H(ۣrzl&?ƨ5 D`y@֢,Ͻe;.v_DEEpfF_HC)>AƄ_=kv-I`K5Q'ft^^n/T(dFl"11t[l@ @ ! j,,=dŅJQ L=44ڧp4 Fx@Ay]m/4P (3Q8ɜ> ɒ;˅ Y4?R5Nr .Qo1P@F/33DX·.ww/uOF  Rhb6$%%5_,c4)Y$. B$ @ @ dq=>CrnnQQF((︝6^qcnVdm[÷%J@ˁ,>Ǯ'IߣyiHFTudq6rQϿɮ!;O#Gsow`B?2t w-!^@$'ZFC=ޡc\w8vk|ZQF|y*ǾiBk=Dq_5/@6wlG+xINJ)4=#$ q/eYl6N͛QBۓ1x~@ @o/-*:$ 'h ) gw_m#3V`Y9͞ҵ_ړ9+2?Է/(0yq`8 Tnݟ(Ko(Ց=Ȩgض2E?imZEaωvvϟK*ޅo'L+7S\׮r"_(5=[118\. l۾j`>\Y@ @ E@@DfWQV+V]zQb%Ć,@ _I-C SBO]yi]"\q,ԩ]@fG;C$j֬A5w@ @>蓤9ll>+f>?m@ K@ xh4֞@oDDs#v:VocϩX<3cαwVYGHt 2!!!hޔ޽m^,%[11\JrP,ի4-v8m;ϽݎF2_s[ithԂM~V4i4#O7&QIKz./eX:YO^*}G ZOTvJ$^}[ ⸰=F2oԜz{BPN|.C-oX;?~fJoyǎ8r-`=1+#K1e?Sf2wY+'Jg|v, =eE{i cNnv[ QH~;l4mᲑ26抵u ?}o/N\T8+52 Lw U%{SXo aRd#F? ⡑| wrb8_}aLjgއٗ~e)bS@7`O-r$ƤP]ΈԾC0Ӭ2s`$M%1v?OGVAPZ5W $Y V (ՖJ}iVoҸ~&e)Qߎ Pq{0tDqޝ B7'ެ`Oԯc`ʯNk=d7?Ƅ/J?`oytkU!Zm2ڼY^\LòF,~Mc`'4$TΒ{GqbMN*0Pg )Ł5%+ޘ^9BFJ".~&]~]N2NdljWvѨ 2RILe4㭑  .mfdѠ~$s(tRRl4y'd>5$7v)O_~FQ7EJN5&5rbWHrAZR2j_|r?x&/9]v,ɩ8tF "uyʖE_vV-0?.[*<*4*֤$*|s ?Vd,F_BŁ5% F:O.lIX:|zw.N=G)d$xg*Yqlť7bҩ<ϼ %)΄Y_Ea̦]XHEůrP2DŽK{-֒wΣ>!5}3 ~W1L×Tg3ޢ_xԝ4W+{Yd/K7pWvnbCOeq@'_󏯰j{4hqȲeT!(  \"龔X 5^{zN}0%DZHnx[e.Syl+'jʞA:zrJj/zQG~ 3wrX(sSTn0v5"!SP΀'Z=ZQuRʤt%.J=xeVNü$i m1#2-|3v_PS^?>$4Ǐc=X'u2aiiHe:R \L*mx磗hW=ep=͎$W]+i}7IdM~/P|A+J WLgi4|˜pW^k&dUS*,ֿ:xcȊopRW#8aZv+RΌ psG<6t*8xU|o' Go7˄'2G$ |L!|,S1Q0_ _2_;d8/0@~'&2\P(TNͦτ]D9d8|hFu)p\'9ZApbj8úQAd\cըO) N%̤O90y _WP^S0 K`Yjvހ  mJQkoLFf*^n3rLiLf&_-d\f٧1y * /0YUsEќc$dr :A-SvsK0>Ϯ%W\dH2[#i/e'߱7=>tucj>PѠO#.J啅:5ǧ]87oLclWsġi|ӫ~ob>rЮGH?8?U( z ck1p}0(ղYKdl4!`ҠU9ԣz 9?~)Ģ/OOF0i2Q!Չ]*'`$8\5y#:RJggC? -4C/^\rpZ%>NżPI/PN H/g|!{]gvs08vMU%T| dprk4嬏¯ћLх0 `ꑃh0џT9/iNӆMUc#y=dԩo$nٱgl> WG=>̍`GtuIsct7 HviWye7:* 0&Jq%lYɱ 5cwF{sQXOnc9܏?c+jyKΞvhz~* ij4tMpP:^Y(*ݘx~ >k8,t>ҝr[ qKPJZ>fGU#|Lyk\Ues&~Cr|.z ߰^dkݔBy/FB˖y<}**OedY[uNŮ3 Ѳi-* ,wK4d;Ѩld 2q(8q#kobӮTJܑjT'Tx,S[2[4vqwHuh.l Y(SNk,'o\4. 8h0dqj]%]ŗ<*/Mgli(UNO`.m3f_nʵ;,ȓ½#LޞI_=Odr_0OKi'lټ(&KX=f* `lZ3+c0'%/-{֦K;?vxwo\kảkUܺoˑ,,'_έ1IX=r*:Ne˶ ld csbnJgf[϶MK ƍ '6LUZW ظan,4}:)eٵk:89+f&<̵ضi)_8̈́k4 юk׳iz/HyWzþgUl_ǕγdZ(m^xq/;H?>a i=j1Wbd=_sU#j#7gҚl,3t)nٸ5gq#Fo&*NeYnVM[QN6UVڳgfuULgkIQH=y[ Yˆ@o|s[-ᬛО3a_*ʹu{۶({t! Y't IDAT gF[훖3utXq [7eY5Wřս լ,~;Ǔ~mxm1eHU*;#3Gg$zZLfQ1’ k=omb=UHno1ufn{bH(NZ-ᄏky`"Rg܄'jz6 l _79|%M`ڎG-bS*6oˀ_X-Tdny\Jj6̭: sGocj{1|5C {s(La_=}OXѡ{|g0J#Vk:z\$'-z۲;N6l1{}N,|՝ިUwAp),aecxZC5 +/wg{hX$*&khq#~tVnSEkYˀB\vCkjߏa:$ٗGzv;ٓo [w^x%h|)U:(gxHkw*AU@ZtqrV\K#qU%Js[v'={_-Қ(ђC ˭HRSK%'fhQ/@eģ $$[R][JM@'Q=9 ޏɊ>Ȓ S.mSw3N_e w0%G]Q4Tz#uHh)]&%l1J>\.MF&nE\$"ƛ5zu ]z, YRZ KLC(Nx&[W&Z-IEfWZ)y5&| |k3mB.<,K".GFT.{'W/E$r VmWw Ova S]'{w`@J5HJO2#VgjIE/_^( k{ r Ew>r?pFvTA*Nt=JK"y'=WbEݶ@o/y;w.KZ ˭yŻ;*(H !i8lEh &b'?DF|RU8c@9NT. .뵠~ePfb>Ѹbm_rh{ QWpj,NS j6+C|مo˸̓i {j~2i̟x22>5'~B.O>axٵ|x{# I"j7]f~TT>=\T,QB- ;mYs?{M-oS*W@rJh4*>>,RsOAw~y4MI4~CcGNU)sU?eZҥO,tgz'~G?).g[u豜zW=qTH)ٟ$Y~ۘC#c٣ ]3I-<w!VyS
l8b\?srCX/{ԂoH1B!kH(o9g$SOx.$v?ky_EwdS5ԭ3㧗p9֏){IX?4XX~r1+"pKΌZOMsYK~ ccQ'+w!oB r4 [λAjoN}yua/~ d^č)+Cravdg_bLA,@o GŮĮs) 7.(Q|}̄ld͞i@@"/dl=L `uU!UJ*63oSHNbprIT 7.^ƒe+vP^=ɛ.KQQU5BƧ8z?NY ɡ5ִmJ/e[ hn'*Np' w $e=w[s>ƔhqlDp^o 2_^2v@~:dHwBC o [uZ/zMpo}c~-o$nݗZ 56k+b٧nW|:,Ⱥ/oExH$>U* &8ptBi=r*χ)輈 9Ewrb5 nwFX3Cf>LkM)ŏ{<{a4U{#Z-F_tiqqSڄ.u0w^JŜƷ je$5> p{6;wc,(4F4|8+"EaTd̙eI"Og*{SyE*cj3F?r^F: eb;opB'4K8/ @\Y;)9, *>gN?8p âp.#%$W27.*OP8}(!G<{W6A_-N1,zd3g3}P]?fFKθ* 4v24یqД1na z:; d,yv`'/eR.JƪH]GЅf8v-]wŸki8}RV?s=ɤ,Dv~N0$JO`"@Ji67c$ dT|J:هD6ְ=1>Ԕ5\ï{Ud1HnRZއpě47A?bj?;da~?m:BMxyR|)mGՙO]$53˔YP#\,4}Ts]1[>ڏby~o0y#U x}ҽXy7]ew=ǼLQA62(+k#ڣ9vߏ_>N.),#SC8hg6:"fr _ԠxH1e8#dY1;Cѭ?][&`"4}K+2[W̡՟t8m[@\ɺTRRт!Ba'+ BM,dB \VmR3;i36n4o3w{>^TjRۂãqv ڛFAI919j''5 #P/{^Yb_yx)V+_kkUEzlf'qUԠlv g|PQ)ݻWؿ6 GZ)ڽ.׬1Zn}h;P}Egq,k2q awy_q:;R ADޱ[ +}q$^-v<$sΞ6͆4RTΞ/* . Um O mtErx">^ХjjIfr.q@Cw#H|t RVvsjj $ԈoJ!PynZ 1tۃ$}{z$`<^0 𘺌wTyBSu+RoYyLa5΍/ΰ'|p`T=A+Lt@'zvdoY4槹rɇ:/} w:[o_͓]BM /K;ɋ3neVF~n M O3/"X!d2\~[NqkظGw>]Pzs#{F9Ƃ֭?Bg7:IYMq]=˹g=D#WJ|_5&Pw !0E<6e_3t(+^f m^ה^b h$v=ĭ⡋F^C@m-*5S7ssO1K\עz-ŏScC:d!|Cy꽻+[R0(2`ƍ҉]cf^w܍Op3#֏iەO8tsҋ 2C{1Ƀ؝?FDŽߦMΟrN/{HaR^ޟXZw@߸SߠwԢQԠU<}Sg,@'q(zj3\R9(ua͏qE Pz>[35:YYz0q|$SMdUjnQUASp~yx'giM#=zuMޫp\HÑz]BH6޿!OzW.L.nI2^i<0\;Z|>+})}Cq֤ŕpxKpg0VB.'OzHjٟk)wF<ۦj336.d漛h^yP E˘zʅ3^۟eHˢ֋;&7Y~E77OちO3g#z}׶͒V6lDNАSUK äswS_52e;λֵ=(}À%w&jLԙo`%xv.҆aWx pDDXx#&0M[^Snk[k')"IBGq~e0&bxDžTPT я7hXv8:0B U+) Tn/_k0u:ƪ@ @o =xlAEELDXu} zKq:qkC p>RTp|n/\7*pl,ֆ^Q?Nxyƻm[sYREsY8>3Ǚ_E R nw IDATBьS_H &v=8‰ xQF@QT N'0EbTD_ZHAp;*u.sSwyUnqЙ;T|1 j נ/sPPaäz˯~\B56Œ[_ $p|:/.?X[D&W߃[c;K5U7^ UV*B.0ӱkj0rt>#nEDZ4<~U1ӻ~"" (х]y 1UpjAOyF{$ac>7e8A^C0ʊpAT֠XyFLGT#,†zފ2髧-ΧLf'tZRTcj@kӯy>ԣOh1j eklDMs:{@}˥',"CЃG5rގv{ lظ~}NzΡ˝xn)9L2W@5$S̔Mr;(%t;e'j/mmaclU)\@ob40g*Ƣ/oH~DYX9R0oGwēbTϧylvD*8O5;7$9@L9{_g XG`iGy닞DRj=|8_<ܧbl,X>yN]΃paSe^f飩TgZ+P0f^d \Dɾ1C C s64`"j&_Sެ%_wɯן11`ւIu T9n3֘#FSeyuU|0wunFtG)zBbKod *: 1U?EtF_4zL52l>7 gU0{ESeҤj1T^cL{4FlwԭB)bsm~~ {2yTR̀FFg!2OyEo%2ZyE1DgR3=S4  };AgC^(j_BbOzq-Qtë[5f:'{UV3ۉajپ{S\,}ZEmתք=؛zZF覬5pmZcSIn-/3ƭAAo #roa)1ެ`"(V\Ǯ3Eol_xiџ(0ytڽJyN|hX"b9rj-Mz._0Wy' &4D` gӵ`Ugwdsk!8EUUm 폻OlJ..qU%GJ'`CiOj:vp1>*ƛv}]}=JkU}WCCx+pƸ{REF2xs{zИo'0cuv:uHaLhZ1fԁVe_}?!9SKz„?gؓ0?w= ]feSW zN(\|.;*2s?܇|h'sߛD6:%'vǝ]C84ʩ熱ʇ71g6oLL>Ō2~22?֝^r/| x/` /isn[g{cƟ؇&P%t`g7v~>Rwh3gӪUczjEKk +bUǬ{4j| ]oo%՗(+`׊wkx ڞH%8 F Cis^[EG%Xzo|I{' !B!Kڽg/v7,*BUUmđzΡ>Tn]{櫯9c9<ƃ44byL* HCCrX[K<0v,71v#LćϔOh !D'ә;+1UCcyi%P0i, !D[-jB3G#+߯:yכ(SEdO^- ^ ?n@ KQW>@뻶mpy!B!јק.3!۪5T^ p^`_eG3>)Kaa!%%%:qh`Ob@ 2|젉7:PzC!B!B39""B c`뉎lج !B!B!ZX@ze[H8wx˅B!B!=gxg!B!B!,B!B1cƐACӱ{OB= Bl6B|^:%̅d&44HTU%*NU~M$$qp:Q* 1]L!Di(B!B?$+0A|zwl6p$=̌LJdgeh2,*"77r@ @5(RRR(..%,, K(JB!B!C\.j6a/@Qb1SXX` $$׋%pN't:4Z ["??F Pj(B< !B!QVKrR"NVk('C(@NnEnr8|8 łjh0CLl,Z. i(B!B?DhDGG@ ';#wI1χFbXP*>{ GQ@OX CjAla~;23q]D!DPB!B!*hP޽^oN]Bb|yٴ'6GaeRAz[ M j%2"VEg0^EBT!]B!B|>)-a!fهSy=. h:3aCCq܄X-h `P=FARbb}SQAZ( !B! GDCC9z?,Cu,+U)A-aX"BB,D1QXX#''mڶUAő{v 9k<IJMo\8gw>&-B!BhH"c"?eƄuJfNBFA.EQ1xn<vܜl q8& !:*$X0iiDxBsO޽ahv6n5nueG/mx[*S]ﶭu9Ƙ򭣯%`"[ߙ9;-~X%P:IS%33Rug%i!B!B[P\bp.qˁU0YD6=F'+3m[wV q-Ѥg߾} zMFi ?GbBR]s>$gˡ8/}׾ lpG{CV6fۗkSs%bxx x-KbSlZ݊;Y_<:u('muf~t+7gQhSyOyEegQ=O ǐ|wYϼr(AX`q#k/S%:>,OKsPZU6Y/åc:p\^K.}f[{oO~6_-Y>lsG<5O *~wM2ggl]y7˻<ޏ.ç )Q=]uD2|\wz˼CYG){._x+ %X#K*t ?;l \qMߪWK/Τ9Kp?,ק} TծuJʩ-Yӓy-)/}5Wny^>Ч ̙:/&3s,>}: ]G׏W86r|ޤ,ښʖu*X0i ga 8b.9m-:B!B!z֭'qq tzztƵ\5H,6 py\8v8ڴ""2׋jjơQJ)**"*&0NCLtb|fDz22r괧߲<nYЏhE?RRL¥}-h`jo6ix= e|2"ķjLDvSzhRxk7|s> G辗0*| 7l~7ϻP4tt4ͷdJW/ ֡ -Vnh;1;dbB uoc:Ԭ]3hqf'Wdd(޵?y>PӼ:)'7-6KN.@cwZtSߚTMLaa`3f~t^aȿfXNrIi Z\f砦m UuhpT[R Wh\5!^L7( ְWzՠذUF4h(BB083Ptx36k=".IHZy]Fí\`1 aI<:GφA=a_i߽K@E+K[^|?Vgrf%3/@&qSr^ 8|J[J4vy֌B!B!^Eg#Uĉި'<4NMwnРA|ExKPtz"#")(%O(,,uvde}EkM|yP}Fa KCzQh*sfeQX@L/i!XHYWh+pGk_rojBEPTh#xDXWVbĵ~on^cGTjwc(lcB9(-mzZ[-^cggj]>s̞3̍7'fQElNZd=a_z*xj+]%_Gxwޛ𛓘[7y}} Kf‚Ķ?%_szB!B!~Ņݽ6K(,qAǀ^Hlن8~?!6EKNf.Wa0rs2q=puسeZ1~}opRoCG=p݉F #2BC}xQ UlG3(k.9HYPŝW>A1k LNƺo3+moNx(طԊd[LUْOM%a%s1 OޏWuݞW e!>ŏ+~{UXI||Ճ)`**-%E]=".{XV\R;`7zw“^Imtk4JftmL% { `:v X:G8,"cʧ}d-OTB!B!_BRr`Kt`O-'_@Z4/]w5oׇYy}[c>BWNˑ`o-LUf5nۍWuJVhҏ^)WW)UMD5Z|{g[Q`qxmClQcx,v3#t5cE鉓{< 蛹zfN巵t׹b&mQWkByE Qpr֭tҙJY>>f\rхF{5d㚋qҗ~G&^{@p' e7۠x3j([|?uky|Kļ1Vܘs++@u) *(vh#k`i!E{|a&:vp&B!9ذq|IhiV,_Lپr114ILN֠#=+<k _%4Fvv:P y%Ɇuk{wAv%SwC-ՉL<ҩIz}r]9L!N_ժ5T^r( p^`_es:)K\\iO)kp]Os3iD$ ^|p u4[ه^LP-K/6J$B!B)Վ#' _R#LV;3rH;bBUb61X(Qdeg/ BbbC~m%]uc ]Ŀ9 !׿̻r{ڧ9ؼIbfDJ.aL=j&_S[ϖP|wUiAc`3:\cNԗ~ /m;54mM˦hv>{Bt1DO$3\!B!`shJ}Ee8KJt Q6+fAǞ)vѠygz-;o]p!ARRp!`J}҉: o <> &[].~{e3@7Ss>Qg-;Oe ?%3~}郹y9D&vcOy[L6& u"Hs6 IDAT!B! GDLQ*A(qyu&9h i{PU4voұC۷p/wהKyK;w9kE G&N73ᥟpFLxj~Qo'n~c7ײ ˘gY7;=x􇏏[ſ簢J@xg T]aSE!B!R4PXTBX\ ֭MٌC ( aB8THb1)dCNg p&x A]D!Dg-0R#p~Y!B!ԣew&hѱf= |R FǴ,JJksѨ>l\^Ɉ^g&??']%BTuVP9"B!Bs,҂RG7&ٮDѠj@àa4 Uv;ّZFӄ˚ɛ ~Z%7bɦ"껈B*$'B!B?đsVON~v;&ǀhc68WSNgTk$UgC/B}mP(xi$|!ğɮHB!B!YGvw琄gg׮UHY!B?Fut"Bԍ-0i(p4ىvMM:B!Bq99ܽwV2p#k7`B!R11ѨAM$;i(?|w'B!BQknnc6ΊB!/jWo.30j Vr>:E[/g:7)9hӑ?{I*-Ո065) E!B!B!/E8g%1fk}:9B![5 ,lK/%G Y%muaVm+i C1@d;ʼnIM9B0KFLs2=^G*tDE~h %mam}QQPB eӢE32.h[bwI'77vm[wVUU׵|3.;r0ܼ3?!B?Nr#a67 i ߦ-}t*Dȧ0A3c7iC'ki͛Edf-2rlê+'5i5f4&r߱~BQQ/\2M4`c0iҸQ.VltzڷMVbfB\.</:U|>Ch4thV{¼lݺ]{z1 Ճ jw~c4/vm[cXض}>=Tr 6x_ބxXj 9a6F ddMχlo$&t:YZ PU FSlhh((ZjyҼT}NڴnUߥ˾'>>֊3geQDGE|Aoā M7ghZϡCiF$&зO/E[)*.j0j04-YJ>X4Z 5`İ!\~#Փ_-]J;!&:}ziY2Xh1Z'=fGo()-!*2{e:͛snwº'BwѰY2y^+•e_J^v1{%/n һo,$ΕGآ`>]qbt(::o|atDȰo߬.3Lg#ەHZ[ g1B ( !f#:*?WnǟV`q))-e᢯ HL,@޽g/? rW4LNl6af^r!:5?a^hּ);wz\vŵ{0cF>`4kڄ ,^]бC;Yosv{koǟV0~h؅(\~%(B^~>fLp08NL&f/q ͛5Pa6oƘ#@ ?XEttIRU $#3ݻ<زu;YY\8a<~`-tCi>EJqddfzͯ>El6JJJ)--eӖ7j8&'~N˅lFUU8@= u qc|r֮[O9b(> `ZOy\,G OF /%ߒt,O+VqB!r $@̶Q|r;#'uz6n?@3v׾7w΃l? }GuwS0(H XMEbhEec-N;^{}ʖכWGT %b@{ pI>3w{{ <`o")df03qҢT g\IfS+%kuM;yWn~(BbZn Mhȳ mIKM_^aZ[X|a@qQMM닊 s-8XV]9sKjX,İlےf /?iMLL$'; DAyy& 0T]e8ɘL&$::hl:O("=m,w02t]>X,ř0 ,qqdee244s(/[@9֦R힩-\3}Nłlf .| `6H3TEackn_=Gqq$$8͡  4 ŋ8{agΟoLDZZ [gǃw y@F=EYT.aaM)ٹ$C+'>5l?;hc1jɤ(9 o)iƜAnA=kţ6oO~<Q>|i>mZoO)/<?ϳc}lgԷ=_ ;4MCCqf3nb ȱxݽ,[$&&p:|Q^VGV0 :8z8nD?%g#NȴT[&2 Qbcc1fi'y\.. @00. ڬSЇäFZYQ,e &=KgeYzugnGD8E$n7 ܬ:َ56/74%0Jnr"U;ol~.V\H)^@qw{ w,"#tҟ5ݛwȁG׿_AQ7NoOxLw?ʟ}Qr!gSNROXG|ջ{׎ؓ_|9ȍ@Ewu MS^VdGFgj"fc&%el;G[6bX?53wxXbYB ⥝DNv)lX+#,_;ְ[yfrO?2Rmg s( PBL/x6rxݎ嚶|~w/=lTrHLj`E3YWW 0\UEDDDwn,- e2rx#ũ ]Qfi6phT}tXKKG-Hgȁ/77M7yR>ӕj~ӱb/Jxl@y^?`Gk"ܶb|Q˚3?og"72 yy?@KK+^@ @{{pē͞ 3<<}`)RqQ! g:|ts=lv>8~<@EY)'OP(D ^<0ecxExf#1!χ⺻{Ca,8YWWfDoo߬p`}$'%>(/ó^/=vbNs00 Vg>Iq:'~>Jxpl6KwP(4cǹFB}} j]ȍ8'.*eOėUkEzdV-Ǒf#KfU %9V4<߱9AMnمjjq)N=t;2Ȍ@bIOcbNBMOdyz? xǾ __+~4<*GVs2}8agޑDn6)VMy>Wil>Vػ= C$&$j׭exq;W؍DͰb2yw?`KjYiSU-^k7[6V.+YYܱ6~]0 Ƞ^>H  &&R eox0 ̌|Y^~0Iup`Qa (/+Z /2a>+,/&3U t]^әg>P|kSDDDDnDWsG#A;ǎw}r? XlfdooS ij!hSjnZLWy/%Ye$N/CƟno)%o~y>w^O<ىdxz&~ULqSϩ Ĝ"7y9Dnv/_1CGG'`P(s ~䓞zE_+`}PQQ6 0Eeܬ^9^(>Gd<53LwYPKQN6{ood H[(=‘WD^R"g^K2gZl*O~:(mʶ/o; uc#i۷pז?J20nlֲ*Vߟ$?`AI6Cm$Y α ˂(-Tc'qatQL~EY |gvı/no_\{w_bb|}߱&hf+՟z'>Y օ3bw"#\<<-kc'\A  ݾլZ|PH iHȇ2KIg߶ %+AժZvy94pTn_+m^xA$S ``j&uC~z ' biH4Xqf/=ZEnV㋲*:}V 3a7t=L3dߵw r1nh ׉iiibqxɬ^xۥqxo俿"w>]0Ev-L!""""""r;`bSa\g0yKY َdfeҶers1:IL͡BH˴A+Jafwb5ȍFs(ȇdECڱwP>'Nc7Ok&3'a NccGh4G[Yv/8cd3~DuE3 ] ÅZd$&ف֬8CoJU)X-0ޡ!fAv?GjFn q%SiZMgzZ("Wʅ8y0 VV~:q&2nzGH)UN>MFݻ3|yғ~[PxZ]465p1("E䪋j!"""""WV1H I$dYHQ9d5 c+/>K !Q%sOU3[E$"""""""|;O~ JFD9O`1Ú@VXcL G']pCϑ͜3N;}s=W="rƘ]ṇ*@\b W(6z{zIIMTUu`"""""r E.,]o7uܢazA0<KDn"v%%W!uZDDDDDO ܘfޙ7F[8xaP^V6ƋȍK1(zPYS@QDDDDDDDDDfME5EDDDDDDDDdPYS@QDDDDDDDDDfMEk !(CQDDDDDDDDDfME5EDDDDDDDDdPYS@QDDDDDDDDDfME5EDDDDDDDDdPYS@QDDDDDDDDDfMEh&"""""""""7Pkme(Ȭ)("""""""""̚"0\IDAT""""""""2k3`j\;~k.Pu=3uFf5LyoBxJLLH6L+Z~^|r1T| 2M6 [""""rqJ7w껹S͝Q͝nn<b AsG (XBP1039h Gs)""7b,p8XvH`bp|TolLx%cQ\X_dqj 1qnԀbd&.'1\("""""""""rDH$x;HYO2H paE>\N@1Xob 2yĨ4Mٌ*"""""""""ׇ (N k2yE DT@02S ʼn-XT "^MQr<0H f/"""""""""k.+ۇُr |?fc3 oIENDB`