pax_global_header00006660000000000000000000000064122754077050014523gustar00rootroot0000000000000052 comment=c3c6ed525967fed7789201626d51d0f380700e89 glyr-1.0.5/000077500000000000000000000000001227540770500125035ustar00rootroot00000000000000glyr-1.0.5/.clang_complete000066400000000000000000000002011227540770500154510ustar00rootroot00000000000000-c -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -pthread -lsqlite3 -lcurl -lcheck -lgthread-2.0 -lrt -lglib-2.0 glyr-1.0.5/.gitignore000066400000000000000000000006231227540770500144740ustar00rootroot00000000000000# Ignore object files *.o *.a *.so __pycache__/ *.pyc *.patch *.cmake core *.gch libglyr.pc doc/doc doc/build spec/provider/results/ # Ignore documentation, local working directory child/ bin/ # Ignore CMake output CMakeCache.txt CMakeFiles/ cmake_install.cmake install_manifest.txt Makefile # testoutput test/out/* # swig *_wrap.c # vim swap files *.swp *.swo *.swn #rmlint rmlint.sh rmlint.log glyr-1.0.5/AUTHORS000066400000000000000000000010471227540770500135550ustar00rootroot00000000000000Christopher Pahl CONTRIBUTORS ------------ Sebastian Pahl - lyricsvip provider - various fixes (in stringlib.c) Christoph Piechula - jamendo provider Matias De lellis - 'make dist' target Etienne Millon - Copyright issues - md5_update from RSA to Glib checksum Qball Cow - Numerous bugreports and partly fixes - Being the first adaptor + People reporting bugs and using libglyr. Please tell me if I forgot somebody. glyr-1.0.5/CHANGELOG000066400000000000000000000070551227540770500137240ustar00rootroot00000000000000Hand written changelog of important changes. Use the github page to view the automated git generated brother. 2011/03/07 ---------- + Fixed lyrix.at parser (ctr was incremented always, not only on item found) + Speed up of cover and lyrics plugins (Up to 200%) + Fixed lyrics:magistrix plugin + Fixed lyrics:lyricswiki plugin + Fix of DynHelp + Fixed overall memory leaks + added finalize() call to cleanup plugins 2011/03/09 ---------- + Help text reacts now on "I DONT WANNA COLOR!" + added ability to stop searchengine by returning GLYRE_STOP_BY_CB in callback + Fixed a bug when using the google plugin and -D + Fixed google (and other) returning 404 Pages + Added 'tracklist' getter12 + Fixed all warnings occuring with highger warn level (Default now) 2011/03/13 ---------- + Added examplce.c + Removed alldcovers plugin (they have good image, but don't allow API usage for library and desktop applications it seems :-( ) + Added format check for image plugins. Almost 100% success (== valid images) with this check now + Added option (C API) to configure levenshtein fuzzyness + went to bed :-) 2011/03/14 ---------- + Fixed a bug that made the itemcounter to be negative. ("Got -21 images!" he happily replied) 2011/03/17 ---------- + Fixed very ugly stringop.c - Many functions should be faster and smoother now. + Fixed -w stdout and tracklist. (fwrite didn't recognize \0, as ->size was the duration here) + Fixed an ugly bug in photos.c that crashed libglyr if ignoring a URL + added provider photos:google + reformatted due to trying anjuta as IDE (instead of pure gVim) 2011/03/18 ---------- + Replaced ugly remove_html_tags with a more generic version that works completely in-place + Removed a few redundant strlen()s + added (non-working) albumlist getter which gets all official albums from a certain artist 2011/03/19 ---------- + made albumlist getter working. Wohoo. + Fixed dumb shortcut bug in glyrc + Made finalize() of ainfo,similiar,review,tracklist,albumlist generic, i.e. only call the same function 2011/03/24 ---------- + Fixed crash when libcurl put an error to stdout (ouch..) + Fixed google names when having spaces (ouch x 2) 2011/03/28 ---------- + Did a lot of fixing regarding the API + Fixed "broken" review getter. Still slow; needs more sources. + Extended src/example.c to use more functions. + Tested API (It works, biaatch!) 2011/03/29 ---------- + Made 'return GLYRE_STOP_BY_CB;' work. + removed Gly_infoat, it was only for devs.. 2011/05/15 ---------- Found some time to work a bit here :-) + Added support for google translator (new 'gtrans' getter), lyrics/text can bew translated directly now. It is a bit restricted atm. as only 100.000 chars are allowed per day per IP address. But I already requested more. (20x times as much), hopefully it will get through. Also language detecting works. + Glyr does now checksumming. This is useful for developers which want to make sure the data is unique. For normal users: Well, the duplicate check is now as fast as rmlint :-P + getopt_long is now getopt_long_only (no --arguments, just -argument or -a) + removed call_direct. It's of no use. Not even for devs. 2011/05/16 ---------- + removed wikipedia.c for ainfo - never worked. Better provide a link and (relation getter) and let the user render the site (too many information would get lost if glyr would need to parse it) 2011/06/14 ---------- + added support for proxy. (only basic libcurl support, should be suffiecient for 99% of all cases) + made API *much* slicker & nicer 2011/06/25 ---------- - CHANGELOG discontinued, use the git commit history instead glyr-1.0.5/CMakeLists.txt000066400000000000000000000162461227540770500152540ustar00rootroot00000000000000CMAKE_MINIMUM_REQUIRED(VERSION 2.6) # Write in C, write in Ceeee... :-) PROJECT(glyr C) # Include pkg-config INCLUDE(FindPkgConfig) # ------------------------------------------------ # You can configure the next few params on the cmd: # -DLIB_SUFFIX="64" for example # ------------------------------------------------ IF(NOT DEFINED INSTALL_BIN_DIR) SET(INSTALL_BIN_DIR bin) ELSE() MESSAGE("-- Install binaries to: \"${INSTALL_BIN_DIR}\"") ENDIF() IF(NOT DEFINED INSTALL_LIB_DIR) SET(INSTALL_LIB_DIR lib${LIB_SUFFIX}) ELSE() MESSAGE("-- Install library to: \"${INSTALL_LIB_DIR}\"") ENDIF() IF(NOT DEFINED INSTALL_INC_DIR) SET(INSTALL_INC_DIR include) ELSE() MESSAGE("-- Install headers to: \"${INSTALL_INC_DIR}\"") ENDIF() IF(DEFINED LIB_SUFFIX) MESSAGE("-- Library suffix is: \"${LIB_SUFFIX}\"") ENDIF() # ------------------------------------------------ # ------------------------------------------------ # Versioning # ------------------------------------------------ SET(GLYR_VERSION_MAJOR "1") SET(GLYR_VERSION_MINOR "0") SET(GLYR_VERSION_MICRO "2") SET(GLYR_VERSION_NAME "Raving Raven") # ------------------------------------------------ # ------------------------------------------------ # CFlags and warnlevel / build config # ------------------------------------------------ # Tell config.h.in IF(CMAKE_BUILD_TYPE STREQUAL "debug") SET(GLYR_DEBUG TRUE) ELSE() SET(CMAKE_BUILD_TYPE "release") SET(GLYR_DEBUG FALSE) ENDIF() MESSAGE("-- Building Target: ${CMAKE_BUILD_TYPE}") IF(CMAKE_COMPILER_IS_GNUCC) SET(GCC_ONLY_FLAGS "-std=c99") SET(GCC_ONLY_OPT "-s") ENDIF() SET(COMMON_FLAGS "${GCC_ONLY_FLAGS} -Wall -Wextra -Wstrict-prototypes -W -Wno-unused-parameter -Wno-strict-prototypes -fvisibility=hidden") SET(CMAKE_C_FLAGS_RELEASE "${COMMON_FLAGS} ${CMAKE_C_FLAGS} -Os ${GCC_ONLY_OPT}") SET(CMAKE_C_FLAGS_DEBUG "${COMMON_FLAGS} ${CMAKE_C_FLAGS} -g3") SET(CMAKE_C_FLAGS "${COMMON_FLAGS} ${CMAKE_C_FLAGS}") # ------------------------------------------------ # ------------------------------------------------ # Configuration & pkg-config # ------------------------------------------------ CONFIGURE_FILE( "libglyr.pc.in" "libglyr.pc" ) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libglyr.pc DESTINATION ${INSTALL_LIB_DIR}/pkgconfig) # ---------------------- # Find deps # ---------------------- FIND_PACKAGE(CURL REQUIRED) PKG_CHECK_MODULES(GLIBPKG glib-2.0>=2.10 gthread-2.0 REQUIRED) PKG_CHECK_MODULES(SQLITE3 sqlite3 REQUIRED) INCLUDE_DIRECTORIES(${GLIBPKG_INCLUDE_DIRS}) # -------------------------- # set directories # -------------------------- SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Single Directory for all Libraries") SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin CACHE PATH "Single Directory for all Executables.") SET(SUBDIR_LIB lib) SET(SUBDIR_SRC src) SET(SUBDIR_SWIG swig) SET(DIR_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR_LIB}) SET(DIR_INTERN ${DIR_ROOT}/intern ) SET(DIR_COVER ${DIR_INTERN}/cover ) SET(DIR_LYRICS ${DIR_INTERN}/lyrics ) SET(DIR_PHOTOS ${DIR_INTERN}/photos ) SET(DIR_AINFO ${DIR_INTERN}/ainfo ) SET(DIR_SIMILAR ${DIR_INTERN}/similar_artist ) SET(DIR_SIMILSO ${DIR_INTERN}/similar_song ) SET(DIR_REVIEW ${DIR_INTERN}/review ) SET(DIR_TRACKLIST ${DIR_INTERN}/tracklist ) SET(DIR_ALBUMLIST ${DIR_INTERN}/albumlist ) SET(DIR_TAGS ${DIR_INTERN}/tags ) SET(DIR_RELATIONS ${DIR_INTERN}/relations ) SET(DIR_GUITARTABS ${DIR_INTERN}/guitartabs ) SET(DIR_BACKDROPS ${DIR_INTERN}/backdrops ) SET(DIR_JSMN ${DIR_ROOT}/jsmn ) # ------------------------------------------------ # Set source locations # ------------------------------------------------ SET(LIB_SOURCE_LOCATIONS # core "${DIR_ROOT}/glyr.c" "${DIR_ROOT}/core.c" "${DIR_ROOT}/misc.c" "${DIR_ROOT}/cache_intern.c" "${DIR_ROOT}/cache.c" "${DIR_ROOT}/register_plugins.c" "${DIR_ROOT}/stringlib.c" "${DIR_ROOT}/blacklist.c" "${DIR_ROOT}/testing.c" # "Builtin" special providers "${DIR_INTERN}/cache/db_provider.c" "${DIR_INTERN}/musictree/musictree.c" # jsmn "${DIR_JSMN}/jsmn.c" # fetcher "${DIR_INTERN}/generic.c" "${DIR_INTERN}/ainfo.c" "${DIR_INTERN}/cover.c" "${DIR_INTERN}/similar_artist.c" "${DIR_INTERN}/similar_song.c" "${DIR_INTERN}/lyrics.c" "${DIR_INTERN}/photos.c" "${DIR_INTERN}/review.c" "${DIR_INTERN}/tracklist.c" "${DIR_INTERN}/tags.c" "${DIR_INTERN}/relations.c" "${DIR_INTERN}/albumlist.c" "${DIR_INTERN}/guitartabs.c" "${DIR_INTERN}/backdrops.c" # extensions "${DIR_INTERN}/common/mbid_lookup.c" "${DIR_INTERN}/common/google.c" "${DIR_INTERN}/common/amazon.c" "${DIR_INTERN}/common/picsearch.c" "${DIR_INTERN}/common/musicbrainz.c" "${DIR_AINFO}/lastfm.c" "${DIR_AINFO}/echonest.c" "${DIR_AINFO}/bbcmusic.c" "${DIR_AINFO}/lyricsreg.c" "${DIR_SIMILAR}/lastfm.c" "${DIR_SIMILSO}/lastfm.c" "${DIR_TRACKLIST}/musicbrainz.c" "${DIR_REVIEW}/amazon.c" "${DIR_REVIEW}/echonest.c" "${DIR_REVIEW}/metallum.c" "${DIR_ALBUMLIST}/musicbrainz.c" "${DIR_RELATIONS}/musicbrainz.c" "${DIR_RELATIONS}/generated.c" "${DIR_TAGS}/musicbrainz.c" "${DIR_COVER}/coverartarchive.c" "${DIR_COVER}/lastfm.c" "${DIR_COVER}/jamendo.c" "${DIR_COVER}/google.c" "${DIR_COVER}/coverhunt.c" "${DIR_COVER}/lyricswiki.c" "${DIR_COVER}/albumart.c" "${DIR_COVER}/discogs.c" "${DIR_COVER}/amazon.c" "${DIR_COVER}/rhapsody.c" "${DIR_COVER}/picsearch.c" "${DIR_COVER}/musicbrainz.c" "${DIR_COVER}/slothradio.c" "${DIR_LYRICS}/lyrdb.c" "${DIR_LYRICS}/metallum.c" "${DIR_LYRICS}/magistrix.c" "${DIR_LYRICS}/lyrix_at.c" "${DIR_LYRICS}/lyricsvip.c" "${DIR_LYRICS}/metrolyrics.c" "${DIR_LYRICS}/lyricswiki.c" "${DIR_LYRICS}/lyricstime.c" "${DIR_LYRICS}/lyricsreg.c" "${DIR_LYRICS}/lipwalk.c" "${DIR_LYRICS}/elyrics.c" "${DIR_LYRICS}/chartlyrics.c" "${DIR_LYRICS}/vagalume.c" "${DIR_PHOTOS}/flickr.c" "${DIR_PHOTOS}/lastfm.c" "${DIR_PHOTOS}/google.c" "${DIR_PHOTOS}/discogs.c" "${DIR_PHOTOS}/singerpictures.c" "${DIR_PHOTOS}/rhapsody.c" "${DIR_PHOTOS}/picsearch.c" "${DIR_PHOTOS}/bbcmusic.c" "${DIR_GUITARTABS}/guitaretab.c" "${DIR_GUITARTABS}/chordie_com.c" "${DIR_BACKDROPS}/htbackdrops.c" # Old plugins, removed due to bad quality # "${DIR_LYRICS}/songlyrics.c" # "${DIR_LYRICS}/directlyrics.c" # "${DIR_LYRICS}/darklyrics.c" ) # ------------------------------------------------ # go on with subdirs # ------------------------------------------------ ADD_SUBDIRECTORY( ${SUBDIR_LIB} ) ADD_SUBDIRECTORY( ${SUBDIR_SRC} ) IF(DEFINED TEST) MESSAGE("-- Building with tests: ${TEST}") ADD_SUBDIRECTORY( spec/capi ) ENDIF() # ------------------------------------------------ # uninstall target # ------------------------------------------------ configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY ) ADD_CUSTOM_TARGET(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) set(PROJECT_VERSION ${GLYR_VERSION_MAJOR}.${GLYR_VERSION_MINOR}.${GLYR_VERSION_MICRO}) set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${PROJECT_VERSION}) ADD_CUSTOM_TARGET(dist COMMAND git archive --prefix=${CMAKE_PROJECT_NAME}/ HEAD | bzip2 > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) glyr-1.0.5/COPYING000066400000000000000000001045131227540770500135420ustar00rootroot00000000000000 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 . glyr-1.0.5/README.textile000066400000000000000000000203541227540770500150440ustar00rootroot00000000000000h1. Glyr is a search engine for music related metadata The finest search you can buy for no money ^TM^ !https://github.com/sahib/glyr/blob/master/doc/screenshot.png([screenshot])! It comes both in a command-line interface tool and as a C library, both with an easy to use interface. The sort of metadata glyr is searching (and downloading) is usually the data you see in your musicplayer. And indeed, originally it was written to serve as internally library for a musicplayer, but has been extended to work as a standalone program which is able to download:

GetterDescription
coverCoverart (front images supported only)
lyricsSongtext
artistphotosPhotos of a certain band (press or live)
artistbioArtist biography from various sites
reviewalbum reviews from various sites
albumlistA list of albums from a specific artist.
tagsTags, either related to artist, album or title
relationslinks to wikipedia, myspace, musicbrainz ...
similarartistssimilar artists
similarsongssimilar songs
tracklisttracklists of an album
guitartabsguitartabs in textual form
backdrops Large artist photos, suitable for backgrounds

*Terminology*: To prevent disambiguation the following terms are used below: * _glyrc_ is the command-line interface to libglyr. * _libglyr_ is the library behind, which may be used by your program. * a _getter_ is a type of metadata to download, e.g. @cover@, sometimes also called _fetcher_ * a _provider_ is a source libglyr queries in order to find the data. * _glyros_ is the ruby wrapper for this lib. Currently it is not maintained. h2. FEATURES * Many built-in providers (46 at time of writing, ~30 distinct sites), high success-rate (the longer the search, the higher the risk :)) * Portable: Windows and Linux are supported (Developement on Linux) see ~[1]~ for Mac OSX, * Fuzzy matching: Search providers with Levenshtein algorithm to eliminate typos and enhance search results. * Decent Unicode support: All sort of valid UTF8 is taken, and UTf8 output can be forced. * Fast Download: libcurl is used internally, and sources are searched in parallel, unneeded data is not downloaded if possible. * Lightweight dependencies: libcurl, glib and sqlite (for caching) - typical linux systems have those installed. * Download of a user defined amount of items, @glyrc cover -a Foo -b Bar -n 30@ tries to load 30 covers of album 'Bar' by artist 'Foo'. * Grouped download: Query providers by descending Accuray / Speed; controllable by the user over the @qsratio@ * Optional download of images, URL is returned otherwise - so it can act a bit like a search-engine. * Free Software licensed under the terms of the GPLv3 * libglyr is portable, easy, threadsafe and lowlevel enough for everyone. * ...lots of other options like min/max size for images. * A built-in cache to store the metadata (using SQLite) h2. GETTING STARTED h3. Compiling See the "compile page":https://github.com/sahib/glyr/wiki/Compiling. h3. libglyr: See the "examples in src/examples":https://github.com/sahib/glyr/wiki for a quickstart. There's also a more "gentle (and brief) introduction.":https://github.com/sahib/glyr/wiki/Introduction-to-libglyr Also see the "API Reference":http://sahib.github.com/glyr/doc/html/index.html *Please note:* Since version 1.0.0 the API will be stable, and will only be open for extensions. h3. glyrc: Please refer to @glyrc -h@ which gives you a brief introduction to the arguments you can pass, See the "wiki":https://github.com/sahib/glyr/wiki/Commandline-arguments for more detailed information about the options. h2. FAQ h3. Anyone using it already? * "GMPC":http://gmpc.wikia.com/wiki/Gnome_Music_Player_Client * "Pragha":http://pragha.wikispaces.com/ * "Freya":https://github.com/studentkittens/Freya * "lyvi":http://ok100.github.com/lyvi/ h3. Glyr.. such a silly name! Why? Indeed. Should have named it 'Glyros' (too late, damnit). h3. Is it hard to write something with it? Some knowledge of C might be required, but the code is straight forward most of the time. Bash scripts are pretty straight-forward: @glyrc cover --artist Equilibrium --album Sagas --write '/tmp/:artist:_:album:.:format:' --callback 'sxiv ":path:"'@ Additionally there are bindings to Python and Ruby: * "plyr":https://github.com/sahib/python-glyr by me (complete API). * "ruby-glyr":https://github.com/meh/ruby-glyr by meh (complete API). h3. How..how am I supposed to use it? Well, as normal user you could use @glyrc@ to retrieve some metadata in a batchlike fashion. As developers you have lots of option, you could write glyr-plugins for musicplayers (gmpc!), set up a webserver with this, hack up little scripts showing covers on the desktop.. everything related to musicmetadat is possible here. You could also extend libglyr itself but that's a little harder. h3. Isn't there musicbrainz already? # The kind of metadata downloaded by glyr differs heavily from musicbrainz. i.e. glyr finds metadata for musicplayers while musicbrainz finds data for CD Rippers and taggers. # Musicbrainz runs remotely on some server and uses a large database which is searched through lucene. Glyr is a client program which hops over several sites and does not cache anything, unless you do it yourself. You could of course let glyr run on a (remote) server, and cache all results to do something similiar. # There is "coverarchive.org":www.coverartarchive.org , but it does not seem to fully work yet. But it will be accessible once it does. h2. AUTHOR See the AUTHORS file that comes in glyr's distribution. See also COPYING to know about your rights. h2. I CAN HAZ HELP? h3. BUGS If you found one: _Meh. Sorry for that._ If you file a bugreport: _Hey, thank you!_ Use the "Issue Tracker":https://github.com/sahib/glyr/issues to share your find. Alternatively you may drop me a mail at h3. PATCHES If you hacked one: Excellent! Send it to me via mail or see below. If you want to add new providers you should look at the existing provider plugins to get an idea how to write one. Starting with lib/cover/lastfm.c isn't a bad idea either, because it is one of the very simple ones. __Take the usual Git(Hub) approach:__ # Fork this project # Make your changes # Make a Pull request If you're not familiar with git, or just don't like it, you can also send me the patch via mail: Thanks for any help in advance! h3. WRITE SOFTWARE THAT USES GLYR May sound strange, but you're giving me a reason to maintain it, write new providers etc. Also bugreports (well, there are no bugs, just in case) are appreciated, or just questions. Those help to make the documentation more clear. h3. DONATE You also might consider a small (CS-Students are already motivated by 1 Cent ) donation if you use feel like it: (For now only possible via Flattr or "Paypal":http://sahib.github.com/donate.html , you gonna need an account there - Sorry) h2. DISCLAIMER As usual, no warranty is granted that this software works like expected. Refer to the GPLv3 copy you got with libglyr. It is "here.":https://github.com/sahib/glyr/blob/master/COPYING Glyr is just a way to find the data, it does not own any rights on the data it found. **All retrieved items are copyrighted by their respective copyright owners.** Refer to the provider's terms of use. Every item you get from libglyr contains the name and a url to the provider, so lookup there terms of use there.

h3. [1] Glyr has not been tested on Mac OSX yet. If you own a Mac, any help with 'porting' glyr is highly appreciated. My guess would be that no to almost no changes need to be done though. glyr-1.0.5/cmake_uninstall.cmake.in000066400000000000000000000020211227540770500172560ustar00rootroot00000000000000cmake_policy(SET CMP0007 OLD) if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") list(REVERSE files) foreach (file ${files}) message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") if (EXISTS "$ENV{DESTDIR}${file}") execute_process( COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" OUTPUT_VARIABLE rm_out RESULT_VARIABLE rm_retval ) if(NOT ${rm_retval} EQUAL 0) message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") endif (NOT ${rm_retval} EQUAL 0) else (EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") endif (EXISTS "$ENV{DESTDIR}${file}") endforeach(file) glyr-1.0.5/doc/000077500000000000000000000000001227540770500132505ustar00rootroot00000000000000glyr-1.0.5/doc/README.textile000066400000000000000000000002171227540770500156050ustar00rootroot00000000000000h3. THE DOCUMENTATION h6. Is not here. It can be found online at "www.sahib.github.com/glyr":http://sahib.github.com/glyr/doc/html/index.html glyr-1.0.5/doc/build_doc.rb000066400000000000000000000060021227540770500155170ustar00rootroot00000000000000################################################################# # This file is part of glyr # + a commnandline tool and library to download various sort of musicrelated metadata. # + Copyright (C) [2011-2012] [Christopher Pahl] # + Hosted at: https://github.com/sahib/glyr # # glyr is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # glyr is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with glyr. If not, see . ################################################################# #!/usr/bin/ruby # A simple ruby script wrapping around gtk-doc; # Normally gtk-doc requires autoconf, which I dont want to use. # It's a pain in the ass. MODULE="libglyr" DIR =File.expand_path("../lib") BUILD_HEADERS = [ "#{DIR}/glyr.h", "#{DIR}/types.h", "#{DIR}/cache.h", "#{DIR}/misc.h", "#{DIR}/config.h", "#{DIR}/testing.h", ] DOC_DIR = "#{File.expand_path(Dir.getwd)}/doc" BLD_DIR = "#{File.expand_path(Dir.getwd)}/build" INC_DIR = "#{File.expand_path(Dir.getwd)}/include" if Dir.exists? DOC_DIR puts "-- Cleaning up.." system("rm -rf DOC_DIR") system("rm -rf BLD_DIR") end def copy_doc_files begin Dir.mkdir "build" rescue;end BUILD_HEADERS.each do |file| unless system("cp #{file} build/") then puts "Unable to copy #{file}!" exit -1 end end end def copy_includes if Dir.exists? INC_DIR Dir.open(INC_DIR).each do |filename| inc_filename = File.expand_path("include/%s" % filename) if File.file? inc_filename then system("cp #{inc_filename} doc/html") puts " - copy: #{inc_filename}" end end end end def create_dir_and_cd dirname begin Dir.mkdir dirname rescue;end Dir.chdir dirname end def do_or_die is_cool puts is_cool exit unless system is_cool end ############################ copy_doc_files() puts "-- Processing file #{BLD_DIR}" create_dir_and_cd "doc" puts "-- Scanning directory" do_or_die("gtkdoc-scan --module='#{MODULE}' --source-dir '../build'") puts " - done" puts "-- Setting up DB" do_or_die("gtkdoc-mkdb --module=#{MODULE} --main-sgml-file=#{MODULE}.sgml --source-dir='../build' --xml-mode --output-format=xml") puts " - done" create_dir_and_cd "html" puts "-- Generating HTML" do_or_die("gtkdoc-mkhtml --path='../../build' libglyr ../#{MODULE}.sgml 2> /dev/null"); puts " - done" puts "-- Fixing crosslinks" Dir.chdir("..") do_or_die("gtkdoc-fixxref --module=#{MODULE} --module-dir=html --html-dir=html") puts " - done" Dir.chdir("..") puts "-- Copying include files." copy_includes() if Dir.exists? "../child/glyr/doc" puts "-- Copying to repo" system("cp -r doc/html ../child/glyr/doc") end glyr-1.0.5/doc/include/000077500000000000000000000000001227540770500146735ustar00rootroot00000000000000glyr-1.0.5/doc/include/index.html000066400000000000000000000043171227540770500166750ustar00rootroot00000000000000 libglyr Reference Manual
glyr-1.0.5/doc/screenshot.png000066400000000000000000006172411227540770500161460ustar00rootroot00000000000000‰PNG  IHDRűÄ|ƒÅsBITÛáOà IDATx^ì] |M×ö¾sæ ’ˆ˜çŠTÍT‚*J½¶êÑšZmUG´´tPÞSDñªªê¡ÚJ•#Ô3ÔD¨H I™çäÿoŸuïÉMr§ 4þöþÝžî³÷Úk­ýí#÷;뮳Կ¡Ÿ„ŽG€#Ààp8ŽG ZȪ5Šâp8ŽG€#ÀàpœOóë€#Ààp8ŽG€#P}lâÓRß©¿§wkT3ÊVyïí¿×¯…®:ƒmS÷=´y*BоõÄ-G~žÐÊ®¶Éý†,Þùã„Öµ®Ø„£¶Ú’ùÿoÄúš*Lèø;šT-Çýr$ìµ¶ö‡qn“#Ààp8ÚGÀ&>]³¥Wœ—ô<˜ µY‰Î­GÞÄ_SC/Ü=r÷µ·‹¼lZ-Áª{X-3uiPQÜ£ûŒYw¥¸v’yõžöªÏþE¿Æ3.»wÝèy킶ʶÐèøÖŽØ“ßlTûöjo%ñ_ìóü꿊jOeU4Ù5üÉæ³ñ—¯œú哆ªª 岎G€#Àà˜Dà¾ói“V-4:vÊ4??ÀS.wÓ9=‘óʇEnuÎM 3xd»ÛžÜþÊ¿ÄæÝLÚrhÒûɦvî…úÔeB}ÿѱ`¡~—©Ó{ÄÍêÛmø²‚ž/töæÿ²,€Å»8ŽG€#`å¿NÚæã3g¹½±á?î=Û[cÜíвà¥-)ËÏÝ™2®ÔÁ(Ü,kT0mgú“= ‡ÿŠË¶å4sŒ»–ŒÚÁT-?–Þ¥aEw\:åMüÉ/¿2ga¡Êdš¶/•”ž—•\sùzˆgÄ)åé%nq [‹{üíVœG-œ«dÎO+UˆÂ;Ê\+”6‡ å'¯ Lˆ¿œ±xXcýH©ëïì<³÷‹þÞ`•Ní&m:üÛ{]õ+æÖåãˆKlÈ™µ#ü–WÖpø\ÐÇS/'ó Yþë›m ªÙ°·g­ÿÏ‘»Z+C¤~O¯Ý¹zÌÈv_¸x0tÔãýgx(tx#%(µ!â¿c{ü`Ãñ+ñ‘»=߯¹â¦mÙ7îÑÇåʶ“EmC:˜æ‰*ÿ¡ó÷ý¹ñes½¹^!3<XâöÌììª÷_î8vñö˜øËñ‘aŸ=ÓØøg¹[û1 ÂN^òøûf ·•9£Ûñ±·¶Åò—ΖË?±ñv¾ÇzóºûÎèï¹ëO™†(“›º™Jžì(ÉØnŸ˜#±Sé$¹Š+I:?_úÚ¯VšJÍR§—&(> Ͻ{É*ÒGÓ&ìš l£}ï=Ô1°×˜¥‡3 w?ºœ¨Õ3VÞþdæÐ¶]&Î#Ý4wõ™}{öéùƒÚµž}¼Â¢ho^µ+¿Û?zø k®ðïýViÛ÷Ɖ«iÚ C«ÜwÀ[/¨¶¯ ORš|†¬9yåà¢ÞÍ{üëÀEF"ìeè¬ßcêXÙò7BïvûpÑí×S—ÞnñT 7C¯kЛ_Np {ùÉÁŸ_ì<}î¨æåò±MØbíº׿ùsا5í=f¸/(s[å7hΚÛz}è„_“4ÆÓq¹IN[^ ¿.Vœ¯¢áÐyK^÷Ø5¹O÷~3#ßýäÙ¦†;e£aóW¼Ó<êÓ½‚zOøî²mñø‚Ø#[´lÓªßÌ£wÍ usS¶à†Ü»ßG+f=vá‹aÝ;t~þ_Ñ™•”šhÈ9·i}bßUáÿu}ñ¬MñSÒ‰ ÇxG€#Ààp^Œø´[IÏg5‰+\DË‹ ei§T”Š3“I¯®tß}P‘vY•©Ö:UÈi–K“Ö¸oÛ©ÌJU^:ªÌ+fµ,;MâÚ±¸Y­öžòü» ʸUè”jYA¾Dî¢mþ\îã-µ. Ô ýtE…Ŭ š™PMš 4iëÆ;5 ÒÜú·Úu‘“W -ŒZwç®Ú3¨{çf®š´‹;Þ,#G…—þ|Ù_O|ùówcòÿû鯋ù6ø—»swfûú5m´o<ÊÿÆ–ƒ7Jl(‘H=z½>5àä~»RX&Ÿ>¥;ãŽWO|Ü<²EÏ·¤ºÕI‹Vï‹OÎQ§]þýþk):{¥x1Js£—¸pWü«Ç¶Ïóíäoc¸I[hWùw ö¸q&æ|øYmàÀvå µÒ7xÖwŸú䯥‰”_ï¼ öÛüw'åÂáñéÂÕ«jÚL—ܰ¥›"S²nžØ¾#­aÿöä SÛg_éøõG¡{ãÒór²rŠË‘s›«,dfÊÜP54éɼ óB÷ÄgæeeÛj–º´ülóÌè›:Ÿo'•ï ß|ѯOú¨¼ ¼…#Ààp8¶#PöM*uÔzØÉn'ÉL-g+/žS€8è4Ȥå÷ëÈVž?ÅÈwi¢Cø*‡»V£^ù¹ya§4ýVÞ]°3cØ@µ9¢–ª•’Ô­º)éã;ÚEDH‚Wgvˆw>þ#˜uÂCKÐÊêu~ë§3—.üyÁ¤m½]› ùtÑk)ûÅÒ@m|ñ­UZ—×UŠE)‘2¯7Bêƒå¢IÙ;ûÕ¹'LXýÇé}«?ÔÔј'Þv:ÓI—|<*ÙˆäZRY˜°ï·Dÿ‘ƒZ;º´þ´KÔæc·mcŠmFOé°fcT¶­»¸è²ÏÜÈÖétÚ{ñDz*ËN8uK µLD«•” ˜³¥ðëâ•u«ä^lxŒ¤ã€6õæªòí1b€OâîßNÜ1q¯—·ïxnèŠnìY¾bÏu.Çú=½ÛMßÍ"ë±;ç<áãæå"¬Š¬^³ ÷¬¨ØTÛî5,!nÔgfÊæÝ¸ùù^ˆ.û=ÈKvÍG¾?4ï›iÆ|¨õ¬•36÷sÖ©Mÿ“·Aáp8ŽG”m"¦+”e”hý´² òðýªËW\XSïÂ:­ßÀ¼—>Ì”¦yì8'“d+®•”¶W:¯êë,P(磟—-SðÐÒUãÞ¶¿ß©·úNKi2ð¥‰37Ïh*½ºý‹·¯äZ#ôI(½^–•ì)U·T5ì©ËýDS1„jR…6ÿúU3¬ù²õà© ç.•¦ÿ*ZoLîÝgÚ{OÜÙs®Áä¹"§¬ŠÉ«ÈYMh,¹q8ì¤×Gö¿åÐGrxÞ¹tưHî°éÏþüöÿR*³oN£•Èä–2Xt–Œ8úwjïº59Gï­Y[r¿ vÍzö ÿë MÐÊýÏYúq%I;>_×xîÂ%]ù³ý)&8uE8 3“Ó~3ñµmɦ%•ɤ2) âеWgë+\Q½ùóòS6ï†D*®zdU ;õmnÄ7§ÞµQg¯üsWÒ‹Ón-y{ÙW>MqhÆUJæFñvŽG€#Ààp,"`ÒÌRÜ-oòVN¯@J¡sm_Ø¥—Ɔ0©Eõf:…C§ç·jªµ“J³“ä¹j=eÈjå×Ûy¿›5¸¯ÚñòùB°6”ºà¡™ ÍÇ}ôõ‰ÔŒ'7/xu``›†¾–`5:l'÷Xèè]˜&õþ—feþÍÝZK$“\P5üî{/ölæá(-¸“˜œ^ªt¶3¤»+|¾?£û¥%ïÌš1w·Ë„/^ëânÓOúš”S›OÈž÷qßÜÝ;/ÙÄå¾ý¦sÞ½|×5SáZ]~ÆMÿ^­Üê· Ñ/À¶M—å*g'G¯ö£>úòeÇÃßGèÓNÌÛ’ûv ¸±t80GbI›YGTÝ‚[ŠùØ@L}ïhè;¡ O}ºtRGÀ(¾~pKBÀÔ·ŸëàéààæÛaÈ„IÁþBµ&ãÚ…lßAú6òé8öß‹Ç7’iTÊrû‰8NÛ|""t=`iéŠ)ë33eónHrnKué>¬WSïÖÏÌþjz'W‹w&d)/õb^£Ñÿ i]ßÉN’uóN¾ÄÑy¶¤Ù6 .Åàp8Gcf!MZWoC˜¤×wwŸM™¿.¯©RR9âX¼‹Çí5Ú÷ä&C‘éV8æ×Ô¯¢SnÌS„»î?«÷¤0ÆyÃU“Yi N¥Î[P¬N”…j넇ÕAÀâ™D}¬0ñ‹’â\]ÁÆ‚››46°i‰¤$ýzŠûÐ/w‹¹sfó$Õ®¥«£(Шlþâ¢Ïºœû꫈[EÈNþìí¸o¾Qqhï^K^2Þ΂ù¨Ë8·õÀmuì–ÿ]µš´y)ž+œÚ2rUØ%3Ï-fEáôZØ™˜ã¿¾ñ¸JcÛåþÄÇ;0"ìƒVQó§-:”&Œ²`KæÛyTë‚#'nн‹&%zÿuçýZ–Ø^ýí“Y¿;¾¹vÍ?[XáLiÒ¶Ù3’ÿéÄÙ g®ç›v=ƒnò.¬ÿlMò€oöý¶oÜÂw—Fºù¹ß(Hå …R©S»âÚK¥¸Ô·/ËdrÊjÞ¢ø­óÿÛi~ø± £s×~üí¹]©µ+§ðòÆÙ‹O¶ø`Ç©¨3;>h¼oæÔu’)«C‡7´á£â<ø9G€#Ààp8z¤þ Žè8(¿l·nͰS&o)¿ ÇßïY-y`ßfòÆe׌kŸa—Z˜²sÇ÷6Ì÷]öÊŒ#éµä&WÃàp8Ž€­𸔭Hq9Ž@Mð~¼ß“-Üíœú¾0ÂûΉ'-+›ŒøtÑ;ƒkàâX¯qï±oŒp¾´?ŽgB×d‰øXŽG€#ÀàT²ç«©€ãpl@@í4à‹°UþmÆù_æÏØzÕTº¹ jD‘Ò;gO¥ }ã‡ÃËêËÕw£·~ýþ’wlK§©Š.Ëàp8Ž€Ux¾‡Uˆ¸G€#Ààp8ŽGÀ,<ßÃ,4¼ƒ#Ààp8ŽG€#`Χ­BÄ8ŽG€#Ààp8f°‰OK} §þžÞ­‘Y-:”­òÞÛ¯_ ë*[Pbµ«î{hu µ( õ{z-^ÓˆûY;Âߦ%®Eë\•IdþÃÿ±þ…¦u÷‰l3²!bÝèŠ+šœMM¤-«ÿì[OÜräç ­¬o¢h<íêª)pUï=pù‰ø‹»g>sÆ‘ÛËþãÞ³½5ÆÝ- ^Ú’²üÜ)ãJŒÂͲFÓv¦?Ù£pø©¸l[N3ú}ѵdÔ¦jù±ô. +bæÒ)oâïL~ù…”9 ½„W9Kdš¶/•”ž—•\sùzˆgÄ)åé%nq [‹ïœùÛ=¬8Z8WÉœŸVª…w”¹V( [ôÊœ[Žúü——…ÔŽøÈõ£¬D§ýzhý‹Íõ6¤Þ‡ÿöVG'½5á®ÿŽí2óÇÐYîí‰ .¿Ú~êÚÿúsÇO5°‰+š%w|iÉ®³ÐvùϳŸn¬¿¢d ‡ÿðçÁ}<õ˜Ì'diø¯ovp4xè8vñö˜øËñ‘aŸ=ÓØø§ KÎÛ‚f%¹[û1 ÂNêá=öÍ@ïJ"¦ì÷èãreÛÉ¢¶!¼MÞªü‡Îß÷W䯔¥VXpH™rõ<4嵡Mjçßÿƒ ǯÄGî^ô|gÛV2­Ô‚óxã¥9[fG5Y³gÄçîŒN¸ü¿U/·5rPîÑyòÊðHáßBLÄâamù‡äÖåãvI›ÈŒ²`ËÂ(D̯—iŒ,´:´{ýÇŸfwv•ù ùöPøg=Ü%n]æ¬êgÓºè²o=t4ò–éð´ªÙ°·g­ÿÏ‘»fè¶èû!uçê1#?Ø}áâÁÐQ÷Ÿ¹'öâ¡ÐᄪþÒí9ÐÂecΖKÐô-‘– ¨°VþéYø—bHKëU­ËF°dÎy³nX%U9¹+ŠÒò+ï£iæO¥ Í$–׋ªîß S¶|±YƤj½f¿Sª?/ó˜ÿeCó ™ø 0ïë1¯¹«WêúÄ;;Ïìý¢¿7¾¦ÚMÚtø·÷:»êÿj˜ûç`íËׂ‡EI¬Y½?©¸ éÀ¶Ýq9²{M^6–ÿnT÷•9·~޾¾ÐÞ¥üŸI“n`R–7ƒ¼i0Œ¿ïu ÇeLxIrú3»ú,˜ãxO©+ãL.%gäýÇkþ»ö^/äµð,¯Î¹dЧùöÛ<¾˜ìœ,¾y:Gµu¸ß;O»_©œu`WúÄÛùêÍëî;£¿ç®?eš¹›º™Jžì(ÉØnŸ˜#±Sé$¹Š+I:?_ú“_<4 cZR§—&(> Ͻ{Élú²”Ƚû}´bÖc¾Ö½Cççÿiƒíü%!à…Q„;¹Oבm2wï‹3þÂu zóËIN[^ ¿.¶ì%âm_Y¶|œê÷7ƒƒ» ž¹#YagÃÏ‘fGÉ}|¼dŠÛï“{vì2è³ØnsBßì$¼\{ëðª]ùÝþÑÃO¸ôþ½ÿÑ*mûÞ8òDÑpè¼%¯{ìšÜ§{¿™‘ï~òlÓò_Ħ·˜Ê"ÊFÃæ¯x§yÔ§#zõžðÝe[cxv]ƒëßü9ìÇÓšvƒ3Ü”éWù š³æãv‡^:á×òo€4é¼…)W×ÃÊs-kqÅêOp {ùÉÁŸ_ì<}î¨æ5J¬µà\4EûõÔ¥·[<ÕÂÍÐkn)©ß„-Ã@V«AÑ•›Õ ÛÄ¿‹Î[X/³—E…ä¾IçÍ-¥Ønb”cà[[/^Ú§y÷…ûò‘ßl`7û§RTh ‰ÄÂz™…·fS¶p±YŤ f¿S$fçUíEÍ]Ø–l™÷P¯ÝüW@EóFç&á5{õêr¢VÏXy;ø“™CÛv™8oŒtÓÜÕg 4×Ü?Ë_¾|ÝÏ»vìxB޶ðúÞÍ;*ÝÀ›¸æuU†×Ú%êúøÔ9Ïd.{ßMÆLêZ¦šqÊó&‘7ƒ†ÑÓQn%=ŸÕ$®¨w$ZöZtÊ1ÍxŒLzu¥ûîƒ ­¯*S]àT!§Y.MZã¾m§BÒX}é¨$Ïê/UjYvšÄµcq³&Š˜KÊó{ –:%ºJ%rmóçro©=Ñ@­òÓ ³.xhÇš4hÒ>.vÞèÔ05ïÖ¿ÕÍ9•NÊ»cíSÕlФ'ó6¼º'¾@"wÍ*¶e\,M:´ñØÄ¹ÿìù㹈4ÿž#›ÞÙ±øZ¹l'yAì·.øýº´É…Ç%é´”n/Œnúц3ìË9ïÄ–D[&lv”Ü·Ûsó·½ýsÔ]åëV<Ýÿƒaí¾:‰÷ûeÇîܹò…~M"~¼*k<ÊÿÆ/oPÐFÕ´ÿ˜.¹a¯oŠL)À-׎´àþí=6_O)›¹Içmqµ’ŒSÛg_éøõÄн×J$Y9ŦHI¥Q‰Ê¿K°Ç­gbÎgœÕÎØÎó»ieK©ô žõݤ SŸ¼öÕ¡4‘ÈèÕ˜rÞ”«ë¡ §Ëš¤¹ÑË?\¸+©Troûñ¼ùü]7$”û;`qt…N Î3I3¶¬úzÎÒIj¿Ó©ºQõØï¾ê¼;wÕžAÝ;7‹Û{1bgU5' MÚ2'å·z‰škª'/5>ß¹y³öö nmª×©KÛã®îy±·l½¹3¥’µI=z½>5àäüO¯–‰¤†OéÞÊøßÜõêä-åïõ$꤈E«÷%u­N¿´üûý‰=ÿ¡ë¤£1f–RÐmÒ–Þjîù•Ï÷XYÁK붉)¯`ÀøÔìec]¡Iç-˜¢.S£ bVŒzl›Iä-ý©ÔÛ2þ9˜]/óðÞ¯)[Ť f¿S$æçUõEÍ\Ø–l™÷PPnñ+ ¢ykçf¯^ ,¼üóç˺®ûòçàÜè%¯l¼X‰äšPnáËׄ´ÍM¦®yap•áµv‰J³Ï,›z ß·5Ï×sDT®ì‹Û¬6OĪ`Y|Zê¨õ°“ÝN’™æeÙÊ‹çpM§‘@@&-O÷²•çO)@½JÂW9ÜµšŽ®‘Ÿ›çvJÓoåÝ;3† TÛ‘#j©Z)IÝê ›’>¾£]D„$xuf‡xçã1>]'<´„¨¬^ç·~ÂÆþ¼`ÒÀ¶Þ®M†|ºèµŽæŸ®7(ÓÆßZ¥uy]¥8Q”)ózSa=øëæäSx!ºìçKž•õéÒOoÞýÄ?7wmúÔ0ßÛŽ‚;—¬¸}Ç“ÿTtcÏò{® ß·R'FvÙ—3m$•¤Ïü(•›o=Ifb:}™ëòÓ’ ìºéŸh+LØ÷[¢ÿÈA­]ÚÚ%jó±Ûz³Žõ{z·›¾5šÏbwÎyÂÇÍË¥R¦œ·ˆ »ß2ØçJÄì.ú›¬^³ ÷¬¨ØÔÊ?¿ZÔ§ðëâ•u«ä^lxŒ¤ã€6õäU¾=F ðIÜýÛ‰;&n9M9o~ÊÕõPbnÊ‚ŸÙ ‡¢n ¾ét¸›×Wµ8eóæ·dËʨœ„CgoÃCF­‘Ê”rÃ_0MÊÞÙ¯Î=Ù`Âê?Nï[ýÁ ¦Ž&smÌ{k¢Çœ-¢ú&+ΛhnQ ï%ä;¶kÔDwöÏð›.=z´ó“¤§åWéßae£mFOé°fcT¶µ»vÃX]vâ™Ù울,!«â0 —M•mÙpa›ú—Ry–6µÜËÆ&Ã6 YüSI:L¡a~½l€×F×j*f^³]æ¿SîϼL_Ø–l™÷PÀËòW@U!µ|õ'Þv:ÓI—|<*Ùè¾Ù’ó_¾–FU»¯êðZ1…цo‰TnãOýV”V¡»,>­+”e”hý´² ,>}¿‹._qaM½ ë´~ó^ú0Sšæ±ãœL’­¸VRÚ^鼪¯³ð'ÛùèçeŽÔ -áâÞ¶¿ß©·úNKi2ð¥‰37Ïh*½ºý‹·¯äZ#ôI(½^–•ì)U·T5ì©ËýDS1vYY…”]-úëEÕ°SßæB¾„ ¥à¯]›.?7éåç|ZÔû>ò– ßÍxöf‰[ëÆîòóUø*7?ª$;%SR¯±‡ƒä&N^‹n‹—Ü8vaÒë#ûßrè#9<ï\ºáÛ»039=ñè7_Û–lƒÓ6@!‘°ûÝ&$¥2. ësèÚ«‰³õeD_PH»f={†ÿõ)MÐÊýÏ» ¥$iÇçëÏ]¸ä£ë/¶?Å§Ö Šÿ3?åjzh~ÊåM;úwjïº59§¢GU87ï¼%[¶Žb:h}ôÚ´ù׬šq`Í—­O]8w©4müWѶ,š3*gËܘª8o¬ÃÜu¨ÍM½VÔ¤ÿ€ôó_D¹ygòÁÎý~»f³R56ý™ÂŸßþŸ‰DN£•È,~•ÏͨDÅËÆ’-3VûÂÆ- UçMØ´pÙTO¡ Õo²ü§Ò½ÖË ¼pÊæ®yLÊl—ùï+ó²)K2å.lK¶Ì{(¨¯úW€%¯ iþžÜ»Ï´÷ž¸³ç\ƒÉs'DNY“Wñ6Ø„j³_¾&dk±Éfxaó^¢Už¡Q 'Kur·¼É[9½5*…ε}a—^ëaÒ*[d…C§ç·jªµ“®mñV IDATJ³“ä¹j=åijå×Ûy¿›5¸¯ÚñòùB°6”ºà¡¥ùf_ôÑ×'R3nœÜ¼àÕmZtú~X‚Õ;C;¹ÇBGçèÂÄ0©÷¿ì4+óoîÖZ¿òsnKué>¬WSïÖÏÌþjz'W‹ßsÆn«“m<ª9sœ[dØé»Ö-alÖ…-Ûï>þîûc‚¼ö^x²¡õ ÒÌŽÒ¤DnrùÖ‹¼œO˜Ö5ÿÀÎKÖ)ѤœÚ|Böì¼ûæîÞy©Œ<_?¸%!`êÛÏuðtppóí0d¤`[ž:³´h¦û4×.dûÖµ‘ODZÿ^<¾‘L£RZ}SîÛ1$àÆÒáXú–mZ´ ™uDÕ-¸¥˜e Sê{GCß MxêÓ¥“:ºØ@5?åêyhz¶e­r•³“ƒ£WûQ}ù²ãáï#ô™6Ö†™î7ï¼ oÆ–•Q¦MIT¿ûÞ‹=›y8J î$&§—*í¬®—]5h®žó æß½Räävçäµô;1‡3<;{¦äZ¿Û6¯QîÛoÚ8çÝËw!©rÑågÜÔù÷ïÕÊÝ¡~›ý¬ÿ+gJÌ,¥e[ç8mó‰ˆÐôd#¹Sý »Î[¾l,+4å¼ÑêuU^üZmùO¥©!–Û¬À[í)[¶Zk½æ¿SªõÛš_¦/l‹šõPo«ª_\´tõ*|¾?£û¥%ïÌš1w·Ë„/^ëânÃ÷ »àLùZpÃj—ÙÕ€|ºz£Lÿµ±ê{ÕŒ!–&­«·!LÒë»;‹Ï¦Ì_—×Ti”{R5µå¥½‹Çí5Ú÷¬"C‘éV8æ×Ô¯¢SnÌS„»î?«÷¤0ÆyÃU“Yi N¥Î[P¬N”}yÔ k‚„ɱ2‰úXaâ%Źº‚77il`ÓÈLjß:ÿ?±æ‡Û0:wíÇßžËÑ•VèÝkÉÁK ç6Žmn|g¤KþmW|ÖÕ½;/ˆÖ¤geù¾û½Ÿ¥cþûç…¿ÎØôZ'¥Ö†èªÙQšÛûç°6÷¹µ'bÎìÿ´CÔÂ÷WFEBuç¶¸í ŽÝò¿«Æ¹C¥IÛfÏüI>þ§g/œ9¸vœoÚõ S¬ÀÊdléλ°þ³5ɾÙôÛ¾q ß]YèægÈH17^æÛyTë‚#'nÐ-”&%zÿuçýZ–ÿå ðêoŸÌúÝñ͵kþÙÂúÓ~æ§\Íy.¶×âãgbއ}Ð*jþ´E‡Òlû ^ÐG»ÎQÎÌ_;¦‹ÛÅ [ßÒz™³ey”™)”¤_OqúåŽc1—bÎlž¤ÚµtuT¥‹Ûô?A£ÐUnC3†Ê5WU-ç-˜Òd§ÜH¿“ðçÕ IÉ­³Ç¯§¦^L©AxZŠçÔ¦¶Œ\v©ìYãrÖ³¢¿ pz- Á¯o<®ÒØv¸›ºl¬ÚÂï r…B©TÈËÅþ«a[u¾ÒzY¹l,*4éǾè]ÉÊèü}EnüGYÜÞ†r÷À±‹·ÇÄ_Ž ûì™ÆFêl°UÉ8oàp8ŽG€#À¨:µÀ§íº׿ùsا5í=æ)­à„KЛ_NrÚòJðøu±úwÜú YsòÊÁE½›÷ø×‹Œ\ÿ:ØË0,ûôüAíZÏ>~¯Òlìš l£}ï=Ô1°×˜¥‡35z÷-*¬¤¦vtZ­E§³Q²Ñ°ù+Þiõéˆ^A½'|w9¯Ò8•ß 9k>nwèõ¡~M*·•´ %Eáó–¼î±krŸîýfF¾ûɳM ÜÞº­JÆyG€#Ààp8Ž@µ¨ù3p*ÿ.Á·vž‰9ŸqV;g`;Ï?î¦sLyAì·.øýº´É…Ç%é¥p35|J÷VþÃø~ä®W«ò–ZuÞ»jÏ î›Å틽±SœquV 2”{~åó=VÚ®À©í³¯tHüzbèÞk%‡¬œâ ï^QúÏúnRЩO^ûêPšº‚^JTMûé’öú¦È”IÆöiÁýÛ{l¾ž‚—´X³e»×\’#Ààp8ŽGÀ ÆñiåRØçJÄì.nV³n…_ç¯Ôˆ¨[%÷bÃc$´©_~TVܾãIx®°èÆžå+ö\/´A§9MÊÞÙ¯Î=Ù`Âê?Nï[ýÁ ¦Žµ^7g¬vÛeõš¹gEŦ–˜Ö«òí1b€OâîßNÜawŠ) ë7öôn7}k4[¯ØsžðqórQ²ÖlUÔÎÏ9ŽG€#Ààpª€q|šEy[TQ•Ü/(¤]³ž=Ãÿú‚F&håþç‰,«jt:V"“Ë*¦‡X¨Í¿~`ÕŒk¾l=xê¹K¥i㿊Υ!ÕShÙ\íõJe2©LŠÂT:tíÕÄYï7Ù(IÚñùºÆs.ùèúËŸíO1Á©+úR˜™œžxô›‰¯mK®ê¶f«¢&~Îàp8ŽG€#P}jà•ûv ¸±tx`›-Û´h2눪[pK[âÚºüŒ›:ÿþ½Z¹;Ôo2¢_€½ÕI¨~÷½{6óp”ÜILN/U:Û•í'R …V-Zpœ¶ùDDèˆFBHØjÑd\»í;hX×F>Çþ{ñøF2JYn3õ½£¡ï„&<õéÒI]lX–âë·$L}û¹žn¾†L˜ì/$P[·eÕ].Ààp8ŽG€#`#67 šd¾Gµ.8râeqhR¢÷_wîѯ¥«…1†®¬èïB#œ^ ;sü×7Wi*Y%ï^K^2Þ¤$ýzŠûÐ/w‹¹sfó$Õ®¥«£ŒáVÚà”í"R¹B¡T*äq¶>.ïÂúÏÖ$øfÿÑoûÆ-|wid¡›Ÿ[…{ˆÂ«¿}2ëwÇ7×®ùg ëo²)MÚ6{æOòñ?8{áÌÁµã|Ó®gP6‰-¶¬{Ì%8ŽG€#Ààpl@@êßÐÏ1.Âàp8ŽG€#Àà˜@ fñi yG€#Ààp8ŽGàB€óéGh±ùT9ŽG€#ÀàpjΧkR®#Ààp8ŽGàB€óéGh±ùT9ŽG€#ÀàpjΧkR®#Ààp8ŽGàBà>òi©ßÓkÏo[<³v„9Cò€Q"Ö(·óÿoÔ- aaâ(«Ú·ž¸åÈÏZYßÊÏxFÕeÞÅàp8ŽG N!P;|Ú)ð­±'¿ÙȘ ënï™Ô¹MëàÙÇïÕ©)ÿ=ÎÔ}4¬zX÷Ãè>cÖ]ÁËã«Pª7ª ¸(G€#Ààp8¿ZáÓMz?ÙÔÎý±@ŸG(âü·®7Îàp8ŽG€#P7¨ >m߸G—+ÛNµ éàm»B©ÿ6¿¹{Ñómœ¥Ë:Ø£Ïaõp}Z«ï\=fä»/\<:êñþ3÷Ä^<:ÜÆ÷}×:Ú.AÓ·DX>2@xÅwM‹Ü=pìâí1ñ—ã#Ã>{¦±C9}¦‚ˆÙQ BÖìÙ0!äù…;£.ÿoÕËm è²A'¯ dy8ñ1‹‡5¶en]>ޏd2uGbÁ–…Qœ¯)–|ß#äÝÉ¥¦z«Ô¦jÚL—ܰ¥›"S²nžØ¾#­aÿöeÓ2”õQ_ÏYzàÚK§Su^õ ·9ê¼;wÕžAÝ;7sÕ¤]ŒØyôfQ•œ5% MÚ2%KmVœ7?÷p8ŽG€#À¨k(Œò²æ÷}Ý©E{mÃØçœÎ¶æ°Â¯sˆWjxÔ­’{á1’™ÚÔ?”–nmú³EÝȨN‡X¯Vb5ЫËNþ§g/œ9¸vœoÚõ ýÝFšÊò(3°”¤_OqúåŽc1—bÎlž¤ÚµtuT¥*{(jºâöÌìl=ÛÝȃʣªå¼™9ñfŽG€#Ààp8'Rÿ†~§}n›#Ààp8ŽG€#ð0#P³øôÃ]s ¹ŽG€#Ààp8Gãý=]øÌ9ŽG€#` ½Ÿk‹—áp GÛô` Y¶ÂãÓ–ñ὎G€#Ààp8Kðø´%txG€#Ààp*#ðûšP +xÛá_.—( 9þ'¼¢Œ^T†£P$ˆ]AL*™LF!looogg‡JIIIQQSªÓi´jŒ‚r|Pd2öxI‰ÄÕÕ®^½zPRXXXZZªT*ìJèÁÀÌÌ̬,¶k“££#ZP°““SAAÁ½{÷`§^^^9ihÄXôÂŒ…ÿ¨«Õjø:4cRhgo\Ó¨QG]škÞÇI4â”f  DÜËÍÍ… ´c‚äÏÝ»wU*N +ØECrrrÜÜÜPÉÎÎ.È̓Œ‹‹ Ä´j PAQ—”æååa 0¸!¬` ¡Ï™ŒZ:&U° | FMi ô«´@4M`… JP‡0ÆÂt~A1<‡!Ôј––U €ÆÄq„u eg§ÌÍÅB°•EQÚÙA‰RÉÖ4#+’%j ”`a±‚˜=ðÑiJXL@ b…`! a(D#- ¬¥+„V†„ë]3ìB1¼!O'Õ_cÔB¶ "nIFמx¤ËŒt†0mX[R[á(\Ñ& P5ÑzšfÍš•XXÃ×ÑÕ¦gœO×&š6ê’ùÿaísáS'm¾þà®<}ãbŽG€#`0°P’$^B-"/õ€)¡.Òhª ,­¸˜½ -DŒ´:öí@4Z8Ê@¶pttd4Q0 Œ -%…EЃ±8Ь‘Z L”‹˜X ˆµLb§ÂppP‰t™# g àìììêꊣ”±8 ºÀ’‰3ÿ£‘ÏA¬Àóâ¢"h ¯ hgTR§ƒa¨c8tB3Æ‚ÅB˜ €ÿŽö¤õ’¢bâÓ°t@‚QA;i€Rùùùp&hâ¨àÅʆdÎД1éV„iŽ™9àÌ …½ìö@X 8yûömá'p#ú[Zª-))ŤaŒBƒà?[VB§¨SÑO§wâý»ŠÐÍK~Âg´ž"¼hA;rI8‚œ‰ut¡` B¤ › žÅÅ VàÄ:0´(er4}$^NY\Œ`­Œ4Tü½F ÖÁ…w‰£“~;,…˜4ñ-PL¢°nÎN#6ŒÐ ýðLb¨'¾¾†SÈGÇø‰#ù@~ý…*´CL`:5s òP•rë6¦CÜü“4à4§ ¯°PEü®j4¸%`,œø(!€zi)Œ2YÏÅà d\ôBІ„9ºíJFmå ™v”Îpíyù¹|J¹DªC¯Bx¯†\‹3ÉðdÆã%a¾2Æqµ:=Á~s€vuмŒzÐGN2¥FFqƆ Ì^¼mñR!Èâ‚Vt ŠO«†>±-gÏpoºÝ Âdï£ÙXS>ýh¢ÆgÍàp8â7ÀAàI â=•‘1’,#( FH© J„£ÈöcCªƒá—}K¯Á´ OL¤ ©%àFh¡¨ª£KöÀ´ P] P,ŒQ”¼Aâ433½H»@ B­äž±(A”S´ø®N Ä© uT¨É(4“ÛHa!1ê"ªºX0â•8„1–Zˆ,’¤¦ˆ:‘û!@Ín! Cíl¶¿$)h 1È …”c¦99ùB™…ùÉ1²‚Y!ÒIs„LAQ1‘uXÁ1P#7RÜNèÁìä2æÍÎà¿ f§¸¬0Mæ?tŠÁiÖjôƒ†p!é¯òS Š D_P§YãˆÆ\™ÌÁ–8ªr¥|gEIÒVy”¾¥¢¸YÁG§ÃtLmÍ_îÖ~Ì‚°“—/'Äãsì›ÞzÍ BÖìÙ0!äù…;£.ÿoÕËm~j9·õù/'ô£"×jD÷MR¿§×îY;ŸùÌêáëF”ÝQ™µ…ŸÌÌ(„¹{àØÅÛcâ/ÇG†}öLc›gî4}Käå#Ê^ ne¬Ô©ÅˆO9ùÊÁE½=ËIWÛ +6y7G€#ÀàÜìí£déÅ O£’!28Šø16Ë(—P(ÔJGœŠ$UìE‹‰†Ê>¤Ä SWP€l`cä@ãÍHŧ  P ¶àÜ K?uqqòòr’¨USBhZÜÝ]Á ‰Lƒ‚)‚áᎈ ÒHF¡¬«éÀ¹QArsJJJròÍÔÔT–è\P€#"Ê$CJ òˆæR2(Á)Å¡‰nŠÂ˜8R«wgA_CÁ¬¡òh Q¨c2ÈoaG;{„ƒ‘f’MGD¯Ñ‚BÇÈqsq­ï^ÏËÃÓÛ³^/w•¦®OÒ©**P‹vX Ø…?ðDSª–KePµ0*J¹¶ðA/’OŠ ‹4¥Ì:>˜ô`RŒÁKµ‡Uæ?.#ÓÊË–•n  ðÁ* ÙƒFP[¸+A† } •îRØ)npa$™àCÈW¸êD¢\áR´B‘ ñoøfLåïÿžÿŸ*ï'ŸV66Å;Í£>Ñ+¨÷„ï.畃Ð5hêœaYËFœv¸ñ ã¯gè”{÷ûhŬÇ.|1¬{‡ÎÏÿ+:Ó&à-ز PÑpè¼%¯{ìšÜ§{¿™‘ï~òlS›é1ì"/ƒgÞW¹WŸ™+?ì·hx×Ç;=ûåiãiÕÄ óyG€#ÀàÜ?À‡ÒCß,@ *&ÄŒõcÓ¹bX,ERIŽD‰' lQgGG¤2ã99'wwÇzõ\ñèršA+ÁÑåâ’‰‡ðØcp¬†$©ÉCTª vÁñŒ··7B¿îP'ÐY(Ä‘ø=dЈÒgEBvq#9ƒvãÙGT “îè–€îàÜÕ¢N´XHîÐ0lLŸ¦L0B±[ GÁ\êìznTà¾'æGÀ±Q£åÐF8@†nè®ü‰CCå~À<'dp4AJnÍN›ÝW¡…f‡ î> z„‚Ÿ ØRQ@ÎŽhùôDß!oL¸ñ³ƒðbÞì¨Ïó°à8›.}ÄKH˜»þŒÌ™äÍh4^A†u°0VÕb¬áQ«ßÇ|§¶Ï¾Ò!ñ뉡{¯•H²rŠÙ¿º²"ÍþzÎÒIj¿Ó©ºQõpѱ+BÕlФ'ó6¼º'¾@"wÍ*¶)çÝ‚- UMûé’öú¦È”IÆöiÁýÛ{l¾žb‹ÉÜó+Ÿï±ÒæËEÙxÀ„~E?¿õÕ®¸<‰Ì)ÛŒš¸a³\#Ààpj Æ•XÜV¤JøþbçŒïJÍa Öì‹E`B¬uvÕ# ab€DÝh,Ñ/H6ÑÞFAÚPÇœ21!O€Æ¢÷ ¢`ÔŽ(!Æ,QèPuòèE]T+º´ã9<ÐJ°L°pè„fº  ‡õ3Ú´.ÁWš)Ž45ØÂ(ʺ¦ÙÁšÉÐDØel,)tqrFÓaÌ‘`aÛq¹ äTgÇX:Ë_fq]6;.ä X–Ò.ÕBL&Åö$h++¤ÚôÕšE lÁUww{µš%…£AgÜ ŒåcèðJÈCÑmô˜b5{B)Ìl¹eÂ"ð]œ'rĘ*¤„Ã)h (ÈaQ@ÑŸ ×›œA“¨†™64·d*š…5›³Ônx–±‚®y] IDATü£|j̧SçtoQk`à¯íÈ4:tíÕÄ9׬ò²k —1'HªvêÛÜU¤C¦’ RèTøõkå. ×÷Y²eAaafrzâÑo&¾¶-¹|ìܬŸÕï`÷Ûz#J¿N}[–9/ynT|$G€#Àà»"º¾‚žëÌ(‹Ï£o5‘0A˜ø+ØñWb“hÇ)¨)† †€«!Ò)H]l Çò{…ˆ0KpBtNà—%RTR„v™\RTÌvMfí¶·ô#d‹8.Z qg5KJ.e™ÖzŠIä’8ø($É+¸DÎ0£ Æ&i èE!šU¨C…0ÆBAhpvšõ¢yÒŒÂ)QyÔø¨H¯å wG ~#Âl(H&'à÷HPF3ò˜ 4ùÒq 6¶*ØâAT–ñ̘³pB>EF‡Q†©uCÊI¬ =nh‡Tv%Kç€*¥\«ÿÑE´Jà¿Be'W±ç¡-d_®Ä͉ ™ãøEÑtÁ+6èÚ¡G éGøSz‰C{­0|ÐŽå†0aŽ Äù2˜“ ­ *°NIØŽÎlߘ ÔÃa¯n… „ÃDÀË)Â].ê ?)GÉ—D8—ðÝ~^¹rÿò§5×.dûÖµ‘ODZÿ^<¾‘L£bDX)9·Î¥ºtÖ«©wëgf5½“«x?†;ÐÜW§6Mú¼¹pFúâOK¶,(,¾~pKBÀÔ·ŸëàéààæÛaÈ„IÁþ6&P;NÛ|""tD#a««%÷æÙT§îÃz7÷j9tÆâw;»•9/©‰V sŽG€#À¨u†aôw\0P¹E´+v1r&ÒÀBµªP²³ñ¼[)˜2tAž *"a4G"²Ð"2²…Ü_£‚v „$dÐyœ’Q0< oCZpŠ 2ö*¨¨'ãåˆQÆ.A˜ò§qD!=ÄÿH I§ÈDÅv±‹1]¡`8CÜðîâßd‘x8ƒº¨äi5I¢@?¹ŠFÈà.…²ÃYG|ƒfÔÝÝ]ÜÜaóBè_À˜ÝMayKpÑ‘®Ñ†c23óð `Ããл~mÒCÎà.‹tB 7€–½½»xce†×þ12 þŒËC` …v|°xù -™x¹Š^1×Ë_çÔBxÒcÅRAÃ#uZ|º^ÐG»Î ;x\þkÇôŽNzó.¬ÿlMò€oöý¶oÜÂw—Fºù¹±Û+‹¥(~ëüÿÄvš~lÃèܵ{.GWjØÿ0+fÓOW{, ßùQý_¬ˆ4ÊE±`Ë’ÂÒ¤m³gþ$ÿÓ‰³Î\;Î7íz†™ô”ŠNcSJüÅOH¶å•\Û¾pETûÏöùéÅâf¯Â3—4¼¸0íP‚BR;TAP¼’ ¤C–ºÈqî4}š5¡D¯VÈ{¦:Fô’‡Ð÷PG#Ã’J'„öQØ’ÝrÀyƱe6î>ØN~âö‚sZ6ˆ-"êlj‹Fá÷‰³³ðþ°€ Èá^¢Aƒxá¹§§'Žx62´Üpk½PðyüFñWÜì¾‚Í 33Y¦-Ôƒ@Ãsá—öޱ`ÅÐN¤ªÄØE<»LTp•¦üA¦Ü¯4ðßX^¬W3)SÕFñ}ãGÛTÕ±÷Cþ>îïQ-w•MFÌy£éÉ ?»VR¿ÓóoŒp¾ôe\VµTÑ ZWX_øPŽG€#Àø„Ñ ÌÉ$«6ž+ñ"H̃È(NÑnÐÆ8нTe'$=keLÆ>ÈØcY Ò‚¸©\Ê~½ei |àaHÞEfãÓ¨‹\ ´ ndápa¤@L)&Š.ò£`L¬ u0-"‚ˆÙB|£h ¤“&mèé2¸(8N¢Æ2Œa] ¾ìe„ âˆSr§EyK§˜»(‰ i [°‹£1-&‡I!‰‘WtD;4S;‰îcÁNq I6 âB§¨Ð”I’†  ¨ƒÑB _xO8ZØ*³‹%‹ƒuËìÚÀS‰W×ï[BÀŠjI9¢Àî’Ð ‘zƒ{0????¿-Z´mÛ¶S§NÍ›7¯_¿>îv ƒeÎä3œf†„¤ ´gdecK– B¹zõê­[·nÞ¼™“Ãvz€WH#Á(¬&cüjlK¢ MÐd=`h7îa„èÓѸ" °±F‰þ@?æç— dP4R86lØ­[·V­ZuìØÑÅÕábüÊ€QH‘†(Èy'Àñp"Ý üŽàèìÒ¸qã®]»"V}÷îÝøøøÓ§O_ºt)66[zggç /ýAÄš=C ^DRHGÜxîb Í5’¤1¤$o¬ÇjíÊ<,uOK “¿z5ü«ÚïÖÖžk\G€#Àà<¬“ ~fuÄJ1„¤(o²H·&¦H4 òmctœÚA¡\Š@EEjˆv’„0‰‰tY$¦Ät‰&R#Žƒ<ÑhT œêèù]C1önBŒ(„)ó¦&JÆž!C,™€‚Bœ’E Ð)qYêUHY˜¦F™a…EÖõQ•]™XÁ|I„>°},„ „‹Bn7¹J$ôÐŽ^š“¸5M„F1 ‚ ðiª“{˜2¥|ï½Ô‡ó¡ 2ÂÊ0®ÏÖR tS€ÀêÕìFƒ5Â)ÔÈ;8°”èFõêÕëÙgŸ}ê©§po1'IsrrÀ†xNLL¼víÞRI¯=‡mðo$øúú" õf-Zâý;¨  žÝ¶]»"äÿûß±cÇ8píÚõü|z𔥂 Ÿ…æ+ø©Oê€c˜2NÅ‚ò»k‹n£B£¨"êyÔ*uŽO?j ÀçËàp8 BÑD›Ìŧ‰0!Ž‚)S#Ñ—  Ò Jy¢}4§DÑЈ‚FFÙ„ Ú„m6@†BC“È„D^C‚}B3ÚE>að`Ú†BÝè…B‚ ºÈ+èG#zÁ&Ay‰}RÀuðN¢ÔÐɨ¦Á+êÅ)Œ \“Q1èÁX’aí½&Èbä»]p ä{ˆÓ{¤Š4@ ¹D¨’˜8/"ÖÆ”^Œýt“@CÐN3¥v•Ûë CÐŽ ´‘ŸÔŽº>»C3;¸¹‘~X`Y9ì’v©£kC¸NÀ×ìäT¡‚S„¢‡ 2jÔ¨Ç{ Ah,Zj*ÞýuñâÅóçÏ#%û· ê xá Æ¢‚íþ° X(, &âäâêïïää[Cg»víÀÑA¸ÇþóŸ ÖÏ<óÌÑ£G>ƒ¬(Á…h¦t¡¦ dŒ{ÙÛt„µ#·éIqŒ…‘:çÓÈBóir8Ž@­!€_dóâ½ÞÐ(l¥Æ~ÿbÌ¢¢úßÑå,´¨…$fbá ` .ra¿jìS!Eð”%6kdlk}hP](¡ «Uȇ¦×hãm&™B©RáÝ{:;lF‡.hWÚƒ\‚Ð89°‡¡A]¢Fbµò¯…}‹Ñÿðaæà08%¸ óMTIpŒ´9;8‚¶*ä G7w±JgöNr g<[ˆIcÒ bR¼š„¥¦ ÅÞŽ=\ˆvÆTóKAŠÁI. +lë!ÕaÇ ¶w†T‚d™Ž¥Và KÀûbäxýÄY\zÀ1íìuëOÕb7-ä´F‹JîÄÂáì)O¤“ës£1_4"™Í¤Œéa)d™VfÇîOŠ4ÅX:¥£= ‚ ^û 4à Óc×Θ ö$J‡ÁïëÕ«ë¸ÁÈÉX¯žöÏÃór˨ÎÉΟn®îÂýŒœqßR¼’Ùä+C3–OÒÍ4 îûôÓOO˜0qå>>º™˜xòäÉ}ûö!¢ŒhÁ.+‚Wú„{¶j,%ZOú1}´ }-áÚ¡ÿAöâÓMš4i×® 2@@¦Û´ióôÐAûž>=hÿþý{Âw!ÄÙh/?²BW ÑhÆØ‹Ø6#Ø]…~ ).-¬_ÏS}×J%™YyöÂ3šHÐawDúÈ=æ!=c g쌚SæžxD›ƒ ’Æ”ýáÛßšói,%/ŽG€#ÀøÀïì¹dÄé O·@| Ž‚ßP#ü#BIg4Bž(KV:è{• ¨*=˨o€bK*EÙë Hº „^h r‰('ýµ…6Ð5ÔÑHzPÇ(’‡r€ ás¨B¤VÏò…¬b‚]Ü5ði,‡$ fòS æÌN©…0ÇzA‡éÞŪvôÒXòœ¨'uxSœƒoÃ4Àr‰´‘c v{Õ NÑÎ8º ‰S"¬zB#܆dfV<”)Ù0„h(A2Ò-À¡ó Xö ÚÐN† bè%´7n܈# ïAjÇŸþùÃ? =9iò“¦OG¨"mÔe|Ädq¸õéÓÑ(دúÇDBv¿~OáØ½W/|zöê¾yóæ?v9Æìh½  ÜA!4pÛÍÍ S RÎÅìÍ2ð ?¤–èŸ1Ѭ¸;©ì sðX•{ÿß´ÔŒO;>öÖ¦ŸÞ~¬Ü+PJÿúæÅ1ËϳW ñÂàp8ÿ‘6‘Í0ŽgH“­Òl~(äö²()ûù-R&ÉÈ.Ž´q‡À‘ @äÌLâè€wæ1j™aß‹Ò"D‰ÁíXš‹ÁŠä[pŠñs'³‹Ð0ê ŽÐ#°F˜<ŽD‰× ^Ü6pJÒÀæjkx§7$‰Óƒ«k"œÉz uR%<W¶³5ÚIžè)‰A„!Æøœe–ØM‚ý]ÆŽÑ’²ô PV°ql‚ÿ´‡£0»p[X;!†ÍTa‚P'(‡-¹ªï¸ yˆéC½8Ò¢`\…°j´€=£ áñ¾=ìjA‹pCa†xFF6v½“FXºyË–ŒtÊdÛ·nýé§ŸN:•’rî°°PÈœx$?a…*ް‚.¸Dw,¸(°žpàÆäôô´cÇþD6HŸ§z#·$((Û†ìê²ç?þ8xð`vv6X>Fää°7e•à'{{;;á…%ì QâMœÅx“ n–ò‹Ø˜NEÎ,eW¦P°Ë Ŧ j}]Xbc™‡¯^3>]»bdà \g-ÇmünÈžW_YoãëP>¤¸ÇŽG€#ÀÐ# dk€ ˆ€€:Tƒ€ñ0R(pSXªNRŽ#ñ04¢|ލ•Øö†F¼ç„ÈÚ…ÝÙ„§á´Zâ¯H¤ÀXRK”Q<5¶…:†€ ’-:%sZÆhÚ‰/’M´C’¨3êÂ.rÄ;á†cÚ1„ ÏÅÑÅ>/½jw. Ì è0ߌn5É%=˜Fä_Ü!„MGBKÞ]y^u¹ÅDd¾–Üu œöë¡õ/6ׯ¥Þ‡ÿö½=Q0jCÄÇöøÁ†ãWâ#w/z¾³Ñ…ë8vñö˜øËñ‘aŸ=ÓØ¡–ª]5.AÓ·DX>2ÀÆ÷“3ë .¿Ú~ê{‘äŸ>|ªá÷6¹{àKKvEûå?7Î~º±!k8ü‡?.èãiø3è²4ü×7;8ê§‚aæ€Ò#Ü+dæ' 6nÏÌήµ ׯàp]À 1y$TÌD ­ãƒáÄ)Åp,RrQ /Ã6ÄNÂE od/ D¤–ÅgYÚ)”€9Û-WÊÈž†Œ>è‹,“ \œ1KÃG5¥ñ ‰aû» ÁváƒyBX%G‚²½ñêA¼tP‰ST¨‘%N`÷7¼%¤¤TüƒuP.ð0ñ‡˜&á£møÀüÄv¢žt$ ®F§p^ g ß,¹ô¡s|„Td'³Ýêð¶«C.ReX¾²JŽJ‰Œ )PCVËV—h‹‹ JKŠà:ö¼&Î0 šˆÅ#ĈIãN‚V‚+³$raóL Ñ\!ÏPò0eÐPäi ÑÃa]öfh†Ö ,ÙÙÙ ©Ì³gÏ?~<Ä£—gΜY¾|yhhhdd$4øøxÀ;wØËY„Íq™•}hî8VhOÙ{p„Ë@…—ÏÈe#?¯4ý^n6òRJÕõš6ñòñv¹•|{Ã×Ïš1óµ‰c³sÒ&O?åÕ—ûöëÙ1¨µ{=ÇäÛ©i‰›»}}w;Tòò3JÕù$û ·v¸‡r¯çj'¤Mã  ít.\ôÆ÷™Âz ­í†.l¢ÎöQg…ǩь¨ça:Þ?>]ð×Î_^ÕÝ´Iä>]G¶Éܽ/NÌq zóË Ža/?9øó‹§ÏÕÜŽpS4:oÉë»&÷éÞofdໟ<Û´ ”õÁaÏþØjÒ¡í+Ë–SýþfpP`·Á3w$ãÏ0Vî;àã%SÜ~ŸÜ³c—AŸÅv›úf'üjo^µ+¿Û?zø Ä[áßû­Ò¶ïc;²ãÔP.@x’Ó–W‚ǯ‹¥!Â8^8ŽG †¸qN}ì°Ú:)Ü(rk|µÝ"}ú"†$=Šq 8Z Cƒ‰ R ‰ª¢‹ô „AH!€^êM›«Àk)2 £ § (0 6Iûµ¡§àÍ`¢ä!±m²Bñfr bp€n-„ïW6}š&L@§4ÜØ+g ÂÂ}&1Ø M™Ä >³`»JZLS£I¡CˆFC $É:ù% Ð`ÛЃ;ȼwT±.FìÛsá<Èô“}žôôò Ã^×X;LK€=¿!ƒÁU#)Õº»³ý­±ñHq1Þ²Î.¼h–ÿW@ôºÉ‚è(B}ú€ôïÝ»{TÇÅÅÁ4zÁ­AïAÑ]\í0, )(ÔÐ È+`TƘR›!üå<†‡ÂŠ<ÜŘO§†OéÞ¢V§Sð×®M—Ÿ›ôòs>-êÇ}y«—dÖý;µwHÝšœ#˜.ÌLNO<úÍÄ×¶%›”®Uÿ 2]AÆÍ·ÖÝåçóËO¬$;%óÿØ;@»¦ëÿßy¾ožó2‹AD%æ¡¡†*Õ*¥´hý”¢Z­¶ZÚþZmiQC[þ:š)5D"bHDÈ$ÉËðæ÷î}wžþŸµ×}7ÉC*¼øí9Ùgk¯s^òÝë|÷Z¶Ê‘Õ~[ oµ=X;2\ßÛoÈO¿ýô?ùãZçÿŒíé¾ÒÙÿÊ}Zõ1>k*K–, l¥xaóS 8Ò°H5›i2@pfp¡‚³*e×ý ëf ¥AFuˆ×Y•¹H:#{Ý‚;é`ò0Ä_xÍæ¨"…|±èrÀgÏn^¨)Tƒ´híÈP^—lëXa F-ì–^@A¤DÃÆÅ5i³ùÜï*ÎÈ,™¬œÕƒ›ëó3†nÁëLj’ží¯Úf9ÈÃ"ƒY‰BòØNÜ…ªž IDAT)T°K¡šÃ¹W{§¤#pS{©Zƒ.@/a‹ N@=¼nY²ù8€±<‘ŒÁCp—ƒMM•ÖÎçÒ̈¿jÈN¦@\õ· Úl4d[R ÊXÜÆÐKw(ŠÑ06=ÙôCU NI p46äµk×6Ì‘¾D”6U§rñÜ<.çf̘qÖYgí±×^žBêÀüÆo0ìš5k±#§ýd-B|–- Y5·ŠûÑŸniT«œCE<ª(”%˜Äº¢Ý¨!—çyš뇖xÒûr*É\¸ç`'ÁŠ81Ic¿¦{]ggç³ÏÎY¶ìͱcÇ~þóŸßo¿é8ÀUã`›èŒœSIOœ´'¬Zµª­­ƒL(Ì žîž8Ök}ú¿rÈkcžšyôÖ©6ßRôË“…Øô=”–ÒÎü¾hFKJåZ84¯Ûï! ή}ꎹ_¿é’/¯¹óÌÛÞ±ûpzBA väßúéWO_òh‘ÆZ5û®å§~ý‚–_óàòLÅÓ˜š~üŽY-CÍoHhÒù·Þ4sý5g]rÿÚĤèYt×ým·\xÑ)k®¾{q4´óÓ+?:g]Ò–Û0ÿž—οô›'Ïýî_ßòí{ÆùSc³.X"¦“r^øÇ¼ó~÷Ãï§–ýþô%ÑþbÛö¢¨’ÀVÆÒ€¥KŸ> ×Jÿ䓸@½-Ú†T½·™–m¦%ŽßRèà ’‚J(“r€ötòTi^E)Â\/CŽš$BÊQÆ"#Yf°€Ë:>µšÁçÎH=ƒÞÌ(‡&͹=-¤»ˆ­ÂÛퟟ@X¤œ–tá¸YY(jÌ^44!žB9ys¯(·ˆaö $ZMÚäUlZ‚n‘‡[ÁÊÆ3´¡J‰ãp ™go”Ä“BBQat Âô/x´Ì/[•PÇã4Fx´j˜.Lͧ¦£ ¸Ì-²QE›ŠŠ ÊY%Œ@4Î;ï<Àtëúõr$ѸA`8Ê©TûÈ‘#ˆ}ØÛe·@-}±ü¢¿PH¢ÈXåa|S"I·%‚ŒÇk”,Û$c§7Š%+‰–ʲ #ê‡:c ºì7Œ3Èž å@g ÏX©¡V^` á›U@AáJÇuëÛW¬XñöÛoóQÁåÅK`6†GBÁì‚§&¤evÞ6•ƒªþç+ò¿£©©zoá»Ú ÙÛmŒ§m…Î…w?´ì°Cf?¸¨„U{~ÿß·åÚþãªóÿ÷©ö~£mfͽ—_üÁU÷c<{t½xûUßïj`Z^~‰ðì(»â˜b‹n¹àÛÙË.ÿóœ+ùû!±äÎÿ9ï!Ó5·þñ«.®ùÁÏnw™?ÛºàΫ/ºþ%5Ö›êB×+÷ÌZÜIîzrÅ&ú9¿ Û‡¢> v¬f–, XØî4 ÿü—@P@±ÂÀ+؇uC®”¨ÕZB^’úËÓ* ™Ð%š¡ AƒbX4vh…A#nù’Ì$þ Ñ™³žÍé/¸ÈbðQ+  „„Šð¤5¶o34.™1$»ðß •þ‡,.<ø§ëgÿÙb°# d‹Úa5FÏþ5£À‹¼nèC [‘¨ [“h@ÂŽZê®j´E8ÃdRh-C)>KI0,°" pš±Å)²ÙŒµXŒb…áöØs@LfÃ/·pµÝn¯Û™IaÖ3´=«Á( ?[Ô!ˆÔH3ª™ I 0W K¢ª0Ôb×…/a¸î@v¤N†‚ay i„˜Þûî»§ý¦ï¿?SÔ××3–Ž{î¹ç´i/¿òÊ+mmmñ¸<,8ä >fVDÆÙÕ•L`ŒîÀS«rú.;+¦æZ •Þ.´bòæë‰X÷i^ K |5VxžQP ÏŠã’HÅáBΦ’éé‰ÌûÜÊ•oc“fF4€0°Dx'à¨ôF²8>÷x}ØÔyið§—J³à}3SAR7W²ÂFRÎk&Éø­)%Zi5í‹í6Un9{ó°¦m*©³yæïn8îù ¿qÇòMh¼¹ýéæ™|í¬»Ö|ªHÛT“Öà–, X°4ð‰k`¿NE†»nþ5W¥C(òS»œ"-ãHº˜hC ƒJ® ¸‚“%ß’4OcWˆj“v4àSà‰ZevóMœ[ N6!aD¸¥ ØBZ l2ñê€1ŠQ6!•þø‚ B®¥éèÈP @ ŠÏȃqd³a é’Ò :3@–[m ‚Ú;™Ž_’™‘e¥ÆþŽÚ‹1Ph@/®ÌBK22ÚJ·.!“Š ®ì'“ø’˜¹h_R`ZEÈëÄ~ìpºÅÀlw÷×åEB›ÃÃt©´Uˆ³.k—óg:…x9vuu)’VOLÁ°”¨`¢vŸOˆÎ!Ã!u „ù6‹ãʶ®áÜsÏ=餓ñ…‡_< ÀcÆŒQl½qÝ: ½?ü0¬u*YGÔºFFÈéõ¿^¨6Sß Ô4×AKÌÕà`ªÂ~9„¥:4û ó°?I%d/½C>,˜Í”Il#X/#˜ãDl}ê O3VÄ+PV6 eåE'€ ›a¿•ôÌÄ%g¡—0Í:µ –ì$s~——…3ìsEˆ!}H2o™,­´@}Üz-6êÿãÒK/]_«¹wßù®ªOäv›Ù§½µ»íÖØ¹ÎyØ¿9bþ•W¬ÜÞÏ~"OÇšÔÒ€¥K–†¢%`ÏUd)×âWõÁ¤U”ð¬`ªéO IÚv2®\†¬µ46SËÔ$ s!?Ðæ/ðSÊõ$¢ .¨ìŒÎt¿¤~Ñd@pª™K¶T8 øÔÈÙ³ŠŒe-î‹?y{ž± P‚_ý8^fïÓ‚ ›‘±ñÈm” ŒÈc±.V„7èŸE™EÛá`+–¢}˜©øõëD¥dNNtfÌîšyÒ8aSâ(ئŒ‰1û`9;¼ì,-/¤8*ˆS 쿨Áض͖D€4£7¦@¿Š/å¼]<®ËÔ…¨žÈÒËcOôõQN<mÉÚ‘^—vŸ2e Šo|㯾ú*h•s‡'N¼øâ‹;ñDÎôwß}w`о÷Þ{{Ù²ej˜×ò²ÉGRü·ˆÕ[ã§3bF ózq-Ô:Hk[ìê6>=„Ø^(ôödxmØÅ9íáÆÐ— E(XbfçÀŒhD&‹ã¥¤ºªüÍž„‰øèávy*ÊÙz85„ìORI6nÀh˜&LÅŽ¯`6š¼À*¤<¹d.™©‹ßQ̪ÌG󱤸ñST-uÛOÚfxÚQ;ýÒ;.š”óž«/þÍó]¬úÛr,I- X°4`iÀÒÀf4 @¡dŸgÐa©©ÂC[йÕmªµŠ+äZ"8Ñ@H â°WÊ¥! «Y—AE© °(Ô:øª‰Ê¤ïΤ¥:"†Ö–TŒòB1#ƒéŠñèH!8•ð’Ñû“¶k¦S)pàTìÒ\:¯K3pí5qËŒ:¤`¸þDI© `’6à<ñžaP; 0ô_Ƥœ["¨”f ÆìBW1ŠX Ï”е A„5š© L£ G²^βRƇâ̰Lª£•LéX¶Ugt{ÅÛ]>£ÙFŒA‚⯼ò#WV†0m¿ð«¯¾º¶¶v¿HG£åUUpxýÚµO<ñÄ¢E‹ÀµˆÊ¼*?ÓÅE¾##­ª‘UÀëæÎ,…ÈqC“/²búwg¢71Ë–Fò,ÙÐ £é&Áéð€Œ‘Ÿ.;³=`U²¾u( ‘XøªÕmÍÍUÊ)§âPg]Ú3¦@cúrN¶ÿ‘™çEXx}‚Åß#ŒAÒònÊÈýv˜¶žN,¹á„ÝnØ‚Frkî9íð{¶Pi[°4`iÀÒ€¥!­Šا‘Rñ  ŒB…‰Z¢  \ÚíÎEä* øk®[bh£p?ˆ¡CSè[œ«Ÿ5KcÊù™dà ¸\¨dâTjµP@} [õ*ö@S¦àL`Kc_F:1‡ócèÈ´“uP ü62¯eaÌÉð7°çj¡ÏR…Ì Xÿ)tC™oÓz‹Ä mCqQ´~* ·V†*%]5å¡!þ'€éj(  =ÈÊ ŽÌÁN$$L7 ÇŽë YQ6•ÚgNã¤1‹b»•§&Êg éG-2o6Ë8$ÊÁè.„ÎAž,ÖÀMZ‚°Yx”ˆ—H-…ÔºÒªb}q;z̨Q£^_² Ǹq£ÖØ¡Ô$xÏ=÷xº¼¢"H0`zÞ¼yj¨ÆV­`k,–t¹aSä•Ì­/OÖ<‘¢ÎÐŒyÄ"ͰP÷7=zÀ+ ¢Ì…b™ÇÅJZ&ňìu²!³Ù9ðƒB”q\`ƒéÙRuvv3æðáÑ„+L•Ûo¿¡Ì~–6sùZBG>HÈ[ÅÿâK]’¨U}æ‚B^— ”#Ýð§.OY„——Í,‚ößâ¶Ÿ?¶žÞ~T`IjiÀÒ€¥K–>”.É´—Þ¾ èmñK·á1kR2h`pyÕq£QޱyåÊ•x”c4à¦.œkOWrüØžãØÌé‚Òé Ç$½à¥—»»¡RˆL¦JÐrjW¯^…Ûmõüâœ.µ{ÊèVYèéŽA÷h¨[cÕŠàEW]°/A\È«z]hÆíLqR°7ÚÃZòÞ|__4¯ØáÏÚä"$ì¤#ï&jImE¨ ÛjΑ“Sz¶\f‡ÑMeåa”à „Yx4Ù‡1Øã«BòÞ¾X:çj¬n„;U\|É%3?{ìE]ÔÞÚÖÜTBM%2¡€ñU—Ü©ÁÍአyúÆø­ì ÖÎ2ƒAñëÇPŒ\Q ”3/ ælÆVUW·víúDœ­BÑS ²º€¿Lß~LìiÞÑзÕÔTgí…Ê2! ?‡éÀļ¢p(™!ŒM*µ/ x—Ó…´¿ÌïðÊ;Àìú°ÚºÛ²öìÂE ;z;~rÍOʪˡzã¾»º®6ÑÒ†«l^2ÚËÛ-_N˜Bž£­õÜœÕtŠÜ’\*Í· Ê—ßô ¿6b£ÓvÑR-¿›öWÜmÉÂÓÛÅc²„´4`iÀÒ€¥!¤` Òì5IÀŸ„@,@aÀY«Á….ugð´Œi0ƒ)%Ê XŒËÔdôÓ?‹*5ÁaA0äUªõQ±öÁІÌâq@E‡V9iϤ€9 XIn\E­.ö]cW Í8tgvÆ7`2…ÄçÓ]—`ì¤RNR4¬k„ýËh$FP%6I&2,gºPÅŒ”Ä’œƒqáS@mµ/iooon¬ìêꦼª²’Æ™´€~,Ê`n,¯•˃¥§«“x+å•UF¥°G<œÝc ƒ°lp¾„ì;¥˜)uFÈÐ|zcÎÇb®Öé‚Îj¤ —ùAr„ú£K.KÄSKz–9²¹y„ µ¬ƒZ¸ÄUUeâι³½­eÍê²€˜HwtÅ>6l°¿; NÀ¢-›sÙ [ —s%t¨ovžT.ãÄß²/ÏÂU·,^U5 (\w>Ïà§v¡[ÈC˜V¼Kò¼@®e½Ñ>JHú EefË„T´7gûì`SÊ kyÒ)¦N ,^¼xq2Y¨©ŸÐñ8›(xW—m@8œÍ$ÚÛûpÑ‚§ '3¡>#Õ>ûìóàƒ¾ð ÊòIì4’­П‚Ý‘J÷ Ì.¢0 !ÅÍf†H ð€ú,œ}öÙk×®={6¯S£Æ¦¦Ú˳6Z¨ÉkFˆùšA Éàé"E•°½_-<½½?AK~K–, Xø¸5臡Eì+FicýQ H-×÷Ž^4或8{3èV½sP¡{i(J¬hpU€àÍŸÑE›)pØ]QWZšZ#¬™Ñ€(¡Js‹EX¦¹yŠ–c‘Óœz¤ F­ô4’èø¢§Ya$ÓRû–– íArº%Àãí•_ û„hI W¢³ÈùÃ{òٔ؆³¹$p0ŸÍ莳ß''ûzÅÃ]Y¸šUg6Nw%b! Ûs1£+á‡Êˆ”³><Íò39!*°,…•ˆÑ/ÿ¦‹ú½tƒ§¡O`F ¦8î¸ãÀšª¥†ææ]vÙ¥¡¡'Ótadø‚ÚVu±ŒKFµMUPë&÷ÇH‰@]éÙm·Ý¾öµ¯1†ê²2á…#J- Áz ªwS‰rZ‘¡`’ó#4Nú&L˜À ¸yôÑG.\ˆf€Âta¦&Ï»Ä- dRääV|u;ŒÉ>aÚ´i,3‹15Qipª0K–,Á£6Æ~Ý\•ÂÔ$½E6Ö®x}ëV §,ø«¦ÁO[Ø–~ð¶aK OoCåZC[°4`iÀÒÀ§R  ¨ŠÕ)*RH^’²¨uå€n) Ä䥫IÄv1Æ0ê žcp*¯[.Þ@9A¿8qÃ4˜NæÃaªðÒÙUÚ \kð¬\DTbƒYJpY@0ÑÍNq•MÚø­cHÀZ-" K0K–, X¢0nÚ0§Êˆ BDêë'+´$ëA’Á‰t‘^šÔ@ȕΠ"šŠE@½‚o Òu)&3¸Êg̱òI]»+²¡ µ;·$SzS™µ«ššI)QB›UøÞ{ïÝý3Ÿù ê&x ŠÆo¾þ:0¦ø÷¿ÿý––£F5cD§=²¡DÕLæu‰UW4)ãÃó=î?H% O©Ça ciÀÒ€¥KÛ€8 P²JÆ8a&”áªàY!Åà‹amÆš¸5ª0àQ 0’Å©2¸„ñƒ `¼c܃/Mcl®xˆSV®¸ˆ6ãJäQi¹n̵è7ƒ–¨ä[?§í&‹)…^§‡ÎìøTO#þÏå0ëUlÁR¦¾žÍæ ‰&I nÏy=˜Ì]©HD4N nÉʉÀ‡õÚ& ž1—+Ä·åÄ1v®;–‹@OçÓ„aɺ¢±\4ýþØáÈÐÑÑî øw7D¾â­e--}Q‹Øq.„' ¬\·nC0TV°² ™K¶CGkjâÒá[•BT0~©Oe‡ÛƒжqÎÖ ÊGuÝ=ñIÇÿøÇ?†Ý½–•’§ï ›ƒ=÷Þ›Ð-p-xàìÁh ó6°U9Ú²ÃLªh¡lÊŒ0ž=ôЩS§L˜8‘Ž]ííj§ u4Ãæ}ðÁv÷Ùwßî»oéÒ¥LꂼâtVU…abì¸ãŽ\ᜠ.OÀïG£¼«ÌõÙÏ~tíî†'ÃòÇì¸ãÓ³f¡%t…ü¸Ì?~GŒî ùÉ“'T½«­ÍpÇmsçνñÆ8âˆsÎ9‡¾×\s g.yõ£;óŽHâƒI«$Ä£IÚFߟOÁÕÂÓŸ‚‡h-ÁÒ€¥K–>V ((U”¦ˆ9-™Aå—˜¶Eæ±" ®ŠWK€Cœ±û’tb Ìà!à,W$Wa,är‚¥\.ò`#EEôûª!F—ð ihEÇô¥s/UÊ&Ãê´¥KHWMæ*©•Ùþî_»–p‹$*•šÒ)’(„hA-‰q®Ab –¦QÓ•£ ÀÓ$—KV§jaµ×²v ‚K¨?°#öZŽÐQèó][ŽbvZ3 ¡ ³ÐLQ ƒD"Ÿ7‰ù6™“oªfA z‹ ÌΊ"œr`Òn¯(÷ó›ßÜc=ˆuòôÓOSõË_þò;ßý®`t ær°¿ò•¯rÈ!Ôb~zÎ\s PÔ[JLA 8< †ž>}:8˜7jVa4œ´$|éb{"ãzÓuKK{mmO Ç»ªÉ?ÿùO=ž^­­ aŽÀßäaäæQ£d÷–ÍbDGQÀtˆpW–ñzØÈ‘`î¬1?7ñú«‹þøÇ?Κõ ƒ€³=öXpüwÞÉàH¨ï3W’¨ÈfKåRè\«x·Ñ˜¾`ëØ®óžÞ®Ÿ%¼¥K–, |Pô \P8ÀÀ S|‰ŽŠ*h@-FN•’B2r5@¤<ÊG$ ¢=HÈã̉C ì xg3„iíÈ­Ð!cOM$SqñÉ€ Œ¦˜IÁ…\ãÑ>šQ(ÀÓPPĶ |(œgâÙIü:„Ü*œdžZN#"§FúÏ´‚Ûª~â„h!GôÌbåk>q36àOœ¬!C¿©»è#Ó±&º˜z¬ÚpTÒAϬϘ`¡€@ªâJÐøEfÃ!Y IDAT¨GÜ8ý ‚6ðH4Jã@(èñ:òbýO‚Å(áÐ`yuy*é±÷õõvw%»óåûÒåË8xç÷á6JtçòÙ 7…ø.ôM¦ÓÛº† k=n' üÆ ­ÛÚb1$¶€Ï[[¬(+ÃŽêw Vî‹§X$öX#!U¸ß`C8 f០Â|Ôþ•Ó¿ˆw¼»ï¾ûïÿ;HÓòý÷ßýøÔSOªO‘è9zÜ8NÿûßÿV%©Ù0, £%XS>kÖ,ÿí=}:~ìA<„BW¤ n]Ù€ÝÃ;Œ. NÔAÎD2rcc•XÁcŽ9†Ù¡nÏ™3ŒŽ[ÌÌú°˜ïÑO<ñ€û÷°aê«kg̘ÁƃªÆÆa¸êëèè&.d<žÜÿ ÄllYßÐØ˜J²Ù>ñŸÇ~ý K^_ʧ†¥o¼uÃnºð pÅ•äq<âqûZ[ñëWÃÒÞ~{ ‚d‚¯å˃6¿à媿 †ò¤‰à:æÓ ÷Ò^w¥|±h(ýaáé¡ô4,Y, X°4`i`ûÑ€ù÷¾H& QÄP `!4a0N?Ù…U±‰.lPˆ$0 ³00ßÜûqWLKZú H[š_G.ÕjwF cN Æ!Ï…B±@m)Å––F (©‘MUAƒÒø*‹"u3¼øKæ–.4–ep¬¶s•‡jDµ¡·: 1…i`XÑ^o@<ÄÅ„2Nª«ý…\ÖA°Â¤ýrÏã’w:#§3ó©<@\ ®Ãû-Á…ÌöD†Bòܨ`d AÀ0_P/š‡ æuaZÛÝŒÓÑÙ‹ÌÜ…+'1NoذáÉ'ŸÄóÓ1B[[ÛwÜGuo¶ 8ß[ºx1fÝGy„>L­æytÊ,ÌËs2gïÕW—\{íµ€æ){ïeš½Û‘²ÊÊ ¼þúë£FbFÌÒE·ñúÄGÆÄ5Þ×Î: 7pùÅ_£ ažç! mnAá”0µôO³9úØcC9<¬{ÅŠU÷Ýw–õ“N: ­²G¤#ÖîÛn»mþüù4S»þ+¯¼_\pÁ•W^ »ººí­[ß º1rãE„§)*6Éì"%)˜Öü¼šwpˆ& OÑc‰eiÀÒ€¥KCV@ùÝÏë9 :Sb4ÚŸYˆÁÓ’à?sen¶ØèÄv§ƒcPæ¿ 9P6#Þœý>·Ÿãr°e±p+SÙ¡Æñä!º×îŒ/%bç+Æ—;á-#z$ËDŒÙGÇö ––ÿ ¼—Cš¤‹A½\=~9’ˆÌ C">ⶃr’‰¹Øß^vJÙpÀ»H‹i¼ S°îæsX’1'; b¼D0D%©ôTTŠ·8—×+9;Î0PÍÖi)·—£$‡/t{ñ0+éTªÖã°“OÆ{cÉ–}—Ýkw¤Awym6ÒçµwtwFâ9GP8™wxÄ?tL£=1¼éÅûZzºzíŽ$@?•–(†=ä½ xàÑDpÉaDÐ=X³.ÖÙšÚÚ¿ýío(x:tA3H ŸxÞ¼yàiQQ*…¡Gu=ö.ó v9PH³j9ɪ¹…kÁhK|òeË–[…µìóuuuÃe¯½öL# §<ð@`7-õS úL3& ,ÓЩAÀŒ[ƒ–O=õ³ß£‘ÐÐÇÛQ¥ìì„* õŸ„0Œ–H{Ü»|y š56éêB¶`z¦–—Ô¼ó ru$'":ˆÇtÉ%—Ó™¨®ÖØk‰žè²ñ)‚–æ…(]u¶-^å]}g¢`+ ø'ø¨+,<ýQkÔÏÒ€¥K–>íÈ5¡˜Ì!+ͨö  })€PlJX   …LT2èr *Rs/WõLŒÅ‘6‚S ³¶Ôž CQB#—’J®Ï§ThÄo Å\Â3ÑZ³PY§ÐŽ%iujªÈ(:Ô^nD6ÑÄê®B  ˜žEØ¿™XÚ°Ÿ(Âá 0Y–­Ž {X­?”³E$ ”¬®¨AV†Cˆ¿¸eéŒPYâ}B.¯¬ÆˆÛÓÛ×Ù ^ìÀÀͺ¼ÜW]Vˆ4ÁJ’ñå,Ø2ÜÚ<Á*!™›1™ÚH.8{äðáø§ã, öàÎŽ@$X“~-œ4ñevCnÑö‡ÔЉõuјðd”ìÁ¢dXcGHºû°ººóóî»ï.Âåºîºëzè¡™3g²Ùìºë®Õuu´Ó3¦bôƒC½Ë/¿|ôèÑûp–wèG‰h”ÈðFúú°VG{nËËýj€§f°>p,Íê ©`Tnmçs»Ú‚°eUUÈLR`MÔ cX·a“†º½çž{næg?ûÙ]wÝ…Åš˜þ}^Ó„û"gÞ€éâÞ|óe þr&‹ÚÍU^½þ–[ ­¼…§‡Ö󰤱4`iÀÒ€¥¡¯ x‚úIÒ¬¸Âw ÿ.úžZÅÞâÊC!íÅQ$¯Ýupú SV"Q‹§60 Èø¨¨ˆ©¶j†<½¸êd´„AȨÀýb« \Dƒ²Í€ ¦•*]Ä»8hè·IÓŒ)dù24\gôPÆ,zŽ£˜ÉYÑŠˆÁ€ÀBæÍå3ÒXÁ‘Y£YeÎiÎmbr7ÝŒßUÖ!û’‚ÿ\>¯ÍOì\*“*«‘󎘧=é‚ϯ Â’§Þ^³ ±q¿‘-ÄcÉ>¤i¸ìÍ^‘”•WÚœî`EmE®¯}ñLALÄÞ2¸Mbóà˜7Qß ]á€ç!5Õ•¡œp©1à:0HWÔ¡ö]vÝ­¹¹¹©¡ø8j‡±8×÷ ’æц  Ÿa ;Å©L óøøöÀ˜F D™×fw²dÍ_üâAÌX¦Y Ý9¥ˆê`’üë_ÿ¢;0Ò8(a:ÌíÃGÒ·nÄèѧ45]å¹9sÊÂ~`1à>\Y VVb432>“bbG$¼Nƒá§LÙU3óø ;ïŠÛ$‰Fb|äðû}Q}ò A~ø1šGÝ»]ÞÞH2à‡_ÜÂÁ;‚iûøôGΤdõjR[>ærÂÓ¨®*õ‚ùh_¼³·m” ÖMµwĘÿ!ÝÑ6”CeNPRð‚Èí@£B(àw¸ XrL™±„Q‰>üðÃ.ŽyŒøÜè”(ŒÜÒXO`+à8™Äƒµx6dˆMOD¢œ–”h›«QµK›Q®ë˜ ™ñð‚—i¸×Xv±Fã"º¦¶š˜,8{Rÿõ¯Å‹Èk¯½†õÕvÚiÆ5b^±O¯[·±§»ã”|„:dOƒªêjâñH«6L’3fÀ´¦Ž>þtÛpBpŸ‡ÝŲ¶T…B–UTÙ'áÙÐL„ÂXš€Û~C;bóld{㕠̼9s®¾úê'gÏ Ønø3©„¼c6›Å<$z}IÞue´÷”l¶á*´ðôz–(–, X°4°]hкëœÃ‚ Á-XÌ¡ )þùnxP\¥iÛ›b/Áئì-ÄàÚO §×8ïÒb’=“¤Ï€Äj›å”0Uà®ÆðG’?T,2: ´Nà¦Iº^š)¦¶Tn yQüGxŽÅ-å a¿Å]ÛS8 e1«òpC-ÎoÃVj‚ŒISÈ ×òP3¦³i0nE°œX}Ëß| LYSÀ®Ì)MŒ¦ewU…9݇k 1E÷öJ¦¶6È$‰F"¸szÄã¡ Ó,6àšŠ<6ÝœÃC÷ÌŽH`w—׆˜{ë­·|~Nà‰xápûÆ.Nûñðb`äæ ¥ iÉëS £› Ê5þ¢ª‚·‡.„º¹ôW®\ù /<úè£8Áuâ‡,Ù?‘硳X Îh8ÁN ;Þ?ÀÁŒYV,äarK(D¬Î Ë’‘­«³³ª®ûq]Sΰ)Y±b\çǼ«S‚&>÷ÜóX”?üpøÓê÷ƒ6ˆÄà¸,‘O†ä&ÉlÀo÷ye…s½|^’!+ÄZ_·zõo~ó›Ù³ŸvÅÜžÇU|µäxVÞÌÓ/¾›ûcs/ËæÚ}ežþ$´nÍiiÀÒ€¥KÛ³öt*“Ðà‚—…˜€ âÍeÔL-Fa¬­àÁ"‚4€Œ›«1ñ°˜ËR€8Ær¹ínÃ鄬˫Çǧö\W›||¯©ªu­}{}uµ·®¶’§øî¤)—‰x|œÕË'Iœí¹ñºìôûÞ¼S ]¾@‰¶p<g}I¼ —yÊ˼âqàc£ØG!Pe.¯&Æíu:©$-3©^õ¬ $D0äáŒ9˹B¡ÿ:ì ¬•¸ßZÙ=!f!C9ZbuNcá†"] Ít;Qp9ì8î 6 ÞeÈÖÜËÎDÜrãà:[[^]VÈ’Wµ®ÛÕ6Ô3쪾u Mͽm4ïêìéèˆ1ú­ukcÝ̯+W,¯ªê7º\ØÓÚÚÓ㨭÷­kíëé0c xÃ=Ù„Çæ=lÂ’¥Ë½îÚX:ÚÕ›‡ýò@k*²âµÇ6¯éj¯©åDã°O'®Tw:w:ríâXÌ ™Þ§fý{òÄq#FŽJǺÝ>‡?ä±9‰1™óø‰t_EuØé±Ù]yžIÐÑ}Anƒe¾DGxwXSmmM™Ó‘MÄ{ý6{fîœYx‰æÄ!FåU«ôç>öféU+—NÞ}r´«2tow?±hÇéYâ©§Òxd;gËdS‰$öôxžþØ-„m…t4’˜ýätΛæõñè÷QîJ&²pdWE„qxºS"Ö [n±£³y“=¢Fù1D&ž#hÙÙ ñ(;HÙA9!¥?ÒÆÛìò¸yž™;gγs)aëÃÇ"RJtc“脾4[P’žk„œM nйfYï.Àýn<Íp¨‘ßÜáâ¹C禖_*®C- E™¶ZG¾ñ_½ë™¿±£þÓã#×Àvº.{ÓQ·.ÀÇÿÒå n=¶yÛ¾ð[7×Öõúož¯§iÆwnŸ½,›ý««ÿ›¡¬¾–þoj@Ílú½ž« ECD‚BúÉ!šؘZmôÑÓlXX1722‘¢ëêê€tØëëƒ`Dè¤ÔêPôRa€A4Àz­Ì,šjÔ¤`T L'Q €¤Þ'ÀO6b.º3ˆ `ÃßÄБŒÂbÆ!Q‹µL¢BªJ‰*§Š¤bn•“ÍøÚLOìQ®³¨U[µ¡£Q.¦e32ïl"ž®‘8l‡rÆŽ‹á¢0¤‰_\5þzZ*ÈÃZÌy¸—_~[2fÚW_}DÛØè‡'ÃrèY™*Ås K†mmí$7‘U O/~ýíùó_„ ‚$Q«‘S„[xÒXp1“³±àø!ÏŽyõ()ŠaêÃ%Ï ¨š d]jeW•0¹…­þ§U|<(½,ŸB½’QEqU”Þ%-AµÚ‘PŽ$20³9Æý2ËDÏ(Ílo„zD qž­É‘CgïÐrn•Ä­fXï/æ|´ÝÖÖÍç 6‰ìÊTÆ@tQ Ù>zŒoˆ% ¦›‚AÞÀcqa‰x=ÂöI¥SC<˜â³Ovýæ½`W9PJ™7þpò)¿{56°lóùä›·ø™Û6_÷1–1>òoźÍÇÜvËq}Ö]kûgæ#uà€…õŸ9åaçˆãÿôÇ£·éD ¾usm]¯Á×2˜æ]Ãþá凬»ö˜)µÕî5¥ÌÉß»E¿£ƒjÕZ°4ðN ߦ ‡à±n³°4Ö«ü]ÑoŸV®ƒ(*âªX3ŸÍ…C|I‡WRSQÜÐÛ¸>b \–„UšQÞ³Ó"D.…SgðmÁ ˆqÀ`KÑ˸_ˆã™Ax¸ióû+ëˆHðú”—l؆ÒÞ) T.÷38HkùŠ7pµ|ÐÓicØØ¹:1&ƒrp«ÜÏñPÝPHÊÛ\¢3J‚V«¼ñHõ[ø³âz™nèÚ¹°§‹M\I:Q ŒÒt'ÃYJÉî«Ï·ôúðx^<tÅþ0mœ‹d4è ‹…Òƒ"P)Π2ZjwQ‘Æ­41äެ·´DÚ ­<Óöv8!F9c;ÂÃôX±²ÏÐf³#Nc ïYÞLºnKäÛtxÔ¼´ýÓ‰¥¹Ÿ:O‰x&ÇàØ¼éK!’3¬é(“Ñ+“ŠúÐ5 "§Í¶~ÃF— f A¾6q%Siù7ª,\&tù¡š†žŽ/¾î¸I×aÛ÷å;þxäÃgŸþ—eBÖ±’¥K™*Æì?¬óþß=þVoÒÖ;ç‰l\k Kÿ‡4P{dÉ€g™ æŒ.àˆÐ ƒs¦Úùäd!¨BØ·•8ƒÁ±ÂŒ°ùÑ+5–cÚØ‚8™‘ƜߣH™Á¹¥1W HFìåѾ„ÁaòAŸ.XXD-»‚g ÷ZºË•'VL&ƒ}šÑäÖ|åÇV C·Ô†‘S$’Š}ÁRÌäq5·Îl^¾Îr›/‚ש… "j’æ˜ÌUÌÛº!Ég + xh?rYp«4p)‰2 vzwA­[»{Úa3£/åŸRν®=,ª¡¡‚…Tæýe°ïºwaSS¨ºJ'?Ä=äk¿Ïc úåA_e8ö{8ß¼v¸`ÅB«özüÁXè æ¦Šá7†Y›Ó ê7a·½÷›QÓ0z]käÍ×[6¶ÄºÚâ.[(Ö“Ì%m;î°“Ûé- …ÂÁ`}}íøñãÆî0Ã3ð&Nm-Nâ‚Z»›šÇ\qå7ßvóòÝ^yÉO~úÝ]&ŽŽÅáHÀ$äÆÀ‡žq¢b?~ÇæáMëÖ¯…ÓÌS‹õ%Ò)ß±9qT”×TWÕÛý7¿û²ç¾óž×Ìz]0ús¿=¸ö2lV‡ƒh~ª÷[Üfë‡|ÿW_+¿ï¬é»íuøïý½kÏÛ£äòsKëâDÆð™W]÷?c_ºòØ}'ïwÆ—ömvð¦p¹¶ø¼Ñ|`Ò7ïyýé_fì´«—‡2ÿÆCëK‚nÝkóѬÓÅÒÀv¦ä‹|¿­®hÝÒ2ˆlöJ@W­%Ϙ˜QùKp†MŽ<6¿ÆÆFEl ÚJ(G-â<Îé¤1‡Éà¿vw'A<Âd *P ¾²`ˆ…õ‹×¾öcßUÈżÌN-mÀU\1Çbbl)šŒN§°LiÍʦóªä´!1”1\J*2­âÊt:½êÂ)Q)ÍZDЋY8á P± ‚‘è‚UuãFläb¬’Âg`9øå`Zé”1ÌLG~ñâÅtÔÙY -ñžñì³Ï2)n¤O=õT‚Æã9츴AÖaÈ™RU_/gƒ)ÚÚúÐãÓ‹¥QΘ‚tÍŽ±Õ\rÈp«ªPͨNè‚À\éN-h“ÇÁ#q³vD¥¶ô2èý~ÈÇâ{NйÎcûÁ«¾' ÄUÏjð'OKLØ¢K{„!éÈ´g4&bXĤDBVÍt˜‡!·¨¨äQL2µÙ0˜'^ü¡¯…$ÍSÁçú¤Ó¹`И©õKýß™DÕÎGºyo¡Jï±ûdb•OŸ>ú5¾öðâÇ¡/ZJg²~Ÿ¿¶æ]âÝ~²÷CŒïñA”áŒ/¾ñ²ŸÝ·Ê>jÑÓOÛ:ßøésø™û÷Ý~Þµ/‹Ûœe=)y½4 V5ú SöŠþówÎß·uÝÿ@ûÁíRýU6uþbÈŒöèÂß~ï׳Öd›^ÜX8¾Rl¡òwè b¨œÑW¯?iŸëKb¿&»æÑ_ÜôØši'f;—üî–Çûtþ IDATWOÿ|a÷ûn²}­mÙšÉÓ¦Œyó±Å¯?úàûÏ#-Ê'}áÄa¯]ûÝÛl`›Ù7ï®ÕÅ~ùÚ´çOoN‡ž-k~ª&ë»Z9÷>aJìÞ þöR³Yºî¨ƒ.ž9á–—žïl]¶àΟ;}âêß~õÚÿ¬LÛü=‘Ô6¤†6×Ÿ× š¿vÝñ»Þ»RûÖ½6[¥z«“¥í]º €t‚íÌxá½òcmﱤ•ЕY¸yÃF5;ð Y¨ÐàÆÍØñ©ì÷õõÄ@ræp‰L¤ gÆË´ðŽ3Ægs_—Ó_‰Çâõë6ð¥Þ•·BÎÚ*PtEÈïLf #MÀ.@Õõë»;;qFœ… …’aˆŠ×ÕʵAx6p*.Îèk-† „ˆÜ„ ”Trò¡0£Ø°qF6J¹ 7K爎–0lþµC°¸†ÕMà•"OxE‡è9R¹l7ñU"=m]‘êæ¦¾X ,›³ 8ëK¤º¢)Dgg8Ò•Zµ¬ÕáÎõövµmœä×Fp[âöº6´®ïê‚r¬¯7G òÎH´ë©gž}ãÍ×ÊNWþº?üêÜo|cÊÔ]¾qÞW±‰®y»Ý‡¥ÝhG{Gï„ £A̬: Œ3ê­·–·´tz=b-&^`& øÃÜÚRDuÄ%³Ù4oEÑg¸¾á¢‹xÔPtÐj2ÃD¢ó¾yäe2¯…¹ ;,nyjjFÑ2 !g³¹âJ¹¢sTH/Ž+3¢c?(D¥B0ʹ2¦¶!F:JÐóˆæ‘Ií˜1c9äüôeƒT‚—7‰¯‘ÍtC& ÄÓ˜µî»îÀ •-¿òöSOúÙ‹½z÷‘Wý èyó±çÖÈ;òöÿƒjý~©¼yrCbѵ%Sö¦ƒTªFÖÔMøÖ= ¿UlžXøhØmÛ ójúbH§Èò§^^/ø:ü½)®aäï AÄ(Íö¡2…ÞÕ ÞîÅWS¾cÙ³Ë{ Æ\üþ)·á?—Ÿ:íÜónzâ§±çoÿßkþðøªø¦ Äæ°«‡{{¯îÞP¹9¢ùAª6/Üû”zÊ+mÝ«;å1ÄÚ×Ä}»”ûÌÝ–×å¨3¹¢ç¥Å?fÿ smÕóD%[ùÚ 2¢UeiàÓ«0àDÁVóŠÂ?™ i¿±£Ã¸eèE€ºš _íË‚²êµjC½Ù`å·–­èîNÇbë€wá°DYµjÕÊ•­ñ8fQ[}ƒRó{Šà3ay°x9e@AMÂt€¹–Õ• $å6C'§Dì–†]ÍÙ<m‚“œBÚæßA@¡/¢FcLu<˜Øñ«Þi§&Œåë—®Äφà y#Ÿ²ƒ-›dÈ(³²2µïÞ{Á/íµÅÀÁÚ ‰'’'\ q¹+Ë(éj½ñÆòD,Û²v]umІœ¾íIø‘ô~ðƒn¸áÈ#DÕÿ~ðI”ÌS…“]S^ (¢mrMÓÉÊ•k››ëQåˆÊâÈãÉ>Æ HT!†l°zÀÊŒÖÞÃw ÏBˆÈalÃŒ¦µ#üsP´×+{Œ"žÆÙ…ñyÂUÁ4³ÑHÇ/Ù§é¾¥—¨×ôþe÷Åƒàœ©¤ «‹' ¤&…lÞ ŒÓp~Q€ìétvÔwÌbÔÖŽ­š8)«V¬|à¡ûÏ>ó¼óÎ;·»3þ·¿ýËïÎG{ºÓ8ŒÄ y³ Aù„‚!’ OÙãvBÿðzƒ-ë8øh‡Û  uz%d 4‰;@’( ËLC/©­o ˆÏÊiýÿ(-5X@væ  巷dz1ñÒ †æ¡Ö€]Î,â×Ï‹ÚiÀŒì‘Ø¢0Êd0ÞÊŠru A^ÊàQÆz{™Ž1×­k/ óD’Ð|½Ô—‘cÇRÅ\N³#"Ã-('Žöxœ¯LGwÞvÞ“ Z!^ÓRlê&r;yÝfð¿¡Œ`ʹȞl/¦gãDVK^vé%\pÁý÷ßýõò)^v é$¿=üа'âCÙ>ý¾$Yÿv"ë^Ùž6sßÑuã?{ù/¿µ{þþõ R•Z5û®å#¾~Á küþòƉGžqæÁÍä8àVèj1t´Ð¤óÿ1ïÑkÕ#…[1À.©è†Bí;õ™ó®þÎ>U›öŠ6ÏÈ#.üöÉÓÇTìñÖÕk;3î }ô>©gÑ]÷·í~áE§L®õ»|µ?vÿajâ¥c!ÖÕRh>hß+üU;v쌥š-Ž:ˆæ©ÚâpƒUä6Ì¿ç¥ÐqßkÁï|ç;\pÎ%ZÖmA2ˆŽò,yĈÌÖdX5UeábàI¡Ðtv²XŒ»uuUŒ Ø¥ Q„ Æí¸# D˜²ŠJöB,“[_/N¾QCÁ’³®‘ÙÔF“¸3¡‡}ÈÉã`µ38+E$^(5?£ jy aH2ZÍñ4ºQ“wk[³óþxó™Z á¦d ò˜íÙR`§Ç5 vk¢‘3)ãÓqß}÷å|!g$YTE1Ë«§NZ[[ÑÒÒŠ <_VŽ?žÍ ÎXxXìYÙÂQ"î:O è/äw!èC>’7v5Þ?xc/½ä"À4|ž¿üå/í8¢ÆÑ‡yWõ•¯9æG ôdh^?uxºnß_Í^²Éïñ—–ÝsÕïïqÕ#ÏÞ~bôÖïßøJDˆTæi Reˬ¹÷òKþê<í¯ó^^´`ö­_nl_Õõ!>ð¿GŒAÿ`b˜n8·ä¯j>|¯RÏkwþuÅ>¿yäÁïûÏO®›_äóÈ,éÎU*ŽþéϾ¶äµÿ8ÓóЯoz©ˆ-7 ¿™uÅÝrÁ·ÿf?åÏs½ñʼ;ÏÙÃm"eiêYøÇk žóϯ=÷¯sw÷˜“¼ï“Ñü Uï3¨©6Â/åŽSÇ0¹õ_uñ­Ñn÷ڂǯœøÒÕ]ÿR¤¤-®«oÑ_~tóÚCþðøÜ|óê =?QÞTd‰l’â=s}ß+á s½ÏóÚ Í ­F–, ˆ\ÄE$΄IÄ„Ãφ&ùPs/“äã(?&kHïÕ–k• ›@Wð À± ' €?(ó¼ÍÕÕ6Õ ^zëÕ×–¬YÓÚÒÒþÖòµ‹—¬Hųáਦ†úÊrŸ³à*d¼…,n}μ—=¿=ËññKFp ü‚´·¶â›yDó0¬ÙŒ­¼,T[Yî,äÂh¸ÙÈàçÃmËÜö Ïðº `x¼Ÿ‹2î’!8ˆ/j–åtá~Ãáõy`ûž@Ð˳ÍÀ¹‡züÈc'wÒö|* R#^ºsH‚g’d:ÑííìíîË9–¬j™ýÜ Ï.xyMk{·•¾ªÊ”£Ð‘ÃñÕ u·/қƣ .@N·?òú‰À—éŒtuôvvF:Ú{:»úzœø©«´y}™¸+è©j¨ó•…ÆìÜTQïÃ%KkgoO¬×öW”Wñu uc窕kï¾ûžüãŸX坸ÞåWüà²#Ž85ð>)^O8ô€ùÍìÄ'Q ^£÷ôt¡PyÀ˜§Æ>XÉ~dÌ%ÆgœtÒI|hLÄúô³]9âˆ#¦Oß D{Ì1ÇaÙÿ©e0(ãcç¦â h ¾@dÐ3u£o/ωyx@d…Úò¥À°nôs_J‚A¿\›|µ`¢.¥S·òq¿X[NGÀ9RuÖY0=hÉ›·ÇÔ©D#g'@úâ¿øùÏê ?ÌG‡Öõw¿û]N Â{©¬,Cf‚ ¦ÁëŒÉfÇ%ìjø½€½O !ßR::¢üJå‡o:ì°W\q=Ø3\sÍ5 ,@ÛÿK£¿:òkÑ­?ôÞßÁªÄÞ<¬é£k;'´Û·o¿ªñ7§ç™ÎwK;HÕ»›nËû!"ƶ\¢5¶¥K–¶_ ìw©?÷ÑÛù‡?›3 F¬}rL˜$\-ƒ”ëL9y|Ó)¢2WÉwÌÜ9L¼qŸX»=†ƒ;o½õÖúBLƒ*33#œR—߆¹zʤ ŒŠ¶Ë8¹¤|vÇÉ]¿eÚÆp$ð¯Ã‰án9¼èÕW^}Y0äÜu×]w7–Á‰;.³”!s€[Í93J²…6ò“źÌr%± ·GȰbÉ.šÛ™1š”y‘N® sE¢Ï x‚:ÁPñ{ƒö¶î>V—s–c¡Œ'c¬7PVÆ2)ÀYum¦údB´ÑÚÒÓÖÖ ›¼¶ºA蹎XSSc}³œìèj§¥×-†ü±#Fé’±.p¤Û%85™¬Á,½â È4v‡*Åé2@êFóÑÞö 'œ ®(¯Æ†ýìÓ=óÌ3Dþfd軺@$ïîîÁÈí°+vÝe7ø¾á²ê®ŽŽŠ†2@öoûÛ»ï¾›ÆØt¡\—,Y‚Wl¬°PÔ”2A.‰ÚøÛksöÙgÏœ9Å I4Àã`Æ_ýêW¬.{Wdñ¤ÁrpvqÀg•VÖÔÌ~≟üä'ŒxEm§Ÿþå_üâ(‡0ÃÛ9ÿüóŸþy ¶á²21ö³Ì/|á Ø€‡™$ÞÓÙy饗Þö§;ËË|°–á.#ª¼±(UÖÖ¾üâ‹×^{-F÷ /¼>ã3rfÏž´‡z¨Ûë{ì±Çn½õÖçž{qæÌ# ¡«’ñÿõ÷¿Ÿ{ݼ-ò.•Þ òápùĉ>úhü¸ñ;/Y´èŠ+~xÿú¼fìèìÂ|È[û³9A(ÞžM`Zã_rÉÅ«òRͽûNiñI§íпLJS™{Ô±ß;wôó·ÿíÙ•éª=N:÷ØÐ’Ÿ¾©f×Aª>Üÿ]ë!"Æ·«·¥K–þ/i¾á{C ù·ß,^(WÍ‚¡ÅØŒ“ ðÐ@ ß“J…‚b ¹ôF!¸§ª²ÌãscPL$SL'A­!žº]ãwÞiìŽû­77$’øö°C® ßUæsa™Ó²-ÄÁ³O°­šs`&šgg;^f€ß¹x|c&Ó9jT¨yX#P˜ÕYAY "Ly§‹åp ’˜&†­!®Ó¨kXïÈ‹-^ä7E#ZXpxap†¬ŽÈˆ6[*‡SmŠc8{Ü~pB¿ÅS¶ß_ÑÐ8ŒÁ#IÈÊi_Ð_?bx0®¨­Žv&àƒ.Gj*›8@Á}3”hoÈ[YWA¯D>ž.¤F€È9L®®hßh߀›‡XŽ=iûˆ1•vq(l$†KL¾¤½aX5ÕåàïY³'dáQG¾çÔ©'MúìQÇ-}ó ø$ _ž”ä9à`d <ͤ9E[³vU˺Õ;WV†Ëäˆ!t04+EåvÚ —|?üáé{òÉ'c®¦/*B×4¦b Œ®Ï ô¤I“¾ô¥/áËOB<Æ…* ªú8]&Ð#Î:ì0¶ÐBX#¬ݼ1[}ëèB^e(/7Ÿ 1{?œÐ‘gRÀ4¯.vëÚš²3Ï<ü͘ŒÆ‚аM¢Q6À}cºæfL®óçÏÿÃþÀ‹7oÞ¼Ÿ]óóƒ>˜Mœ8d ?™“‰8Ä ]GvMéB [2ž&ƒµ¡Äxàûì³/\m¤âxìýwßÃâ¹yóykP ³Ã÷ˆöÅøl¯‹þÒ诺ÌÊ”O=žÎ´¾üBûÑçÞöôoªœÙ¶…÷üö¢_ÍÂ뎤AªLýÇ”†ˆÓj­i, X°4ð)ÐHEÁ4F¼+#벸I»Zø SP\ô¦œ)â$->€£”0p'à’@ài°ƒ1¨ ÀÁiE!¡úñpgooƒ+Lø@‡a©%ZH‚D™—"•¡t3·îiœÍ0 hIÂ%V mWHD;7Gë@Ý´'Œt7¾)ˆ+ÀUç2d.†/‘éU¦Z¨d'kÔ̈́щ*¡‰È–sxdªíí V,÷c÷-¸sJÅÆZ œµ›é„_‚:—¶³:à5h¯¼Z(7X|±ÜcŠ–@$aÞø›Â? £µ·áÿm]8Xá¡¡aÜ «ÛT3Ñh*ês}8ÛÞ{ï½k×¼ý™7Þ8`Ÿè3*µ»ì:ž|oo7Ž/°¹"g¤Wœ^CSfjÐ'²ñ´cÑÈN&œsÎ9L V±/»ì2€ãÈ‘#«jjP >ßz{z @ɪyÐHË«‚Jat㮎…@PFNäá[}yèûâ‹/"ÀÂ… q1Ž5IØß0Ž(GÕËÒâqˆ"òB‚’õA<üðÃlB?üpð::A{ØË:è Hóôåµ£ƒ€yæòÄÄváÝ`]¢:ãî5æd¸(”ÐŒýŸ|ê©3fÌ@r–ÀC‘gípÈ^%‘ÐýÄkgìØÑ,a®vða«W®¼íç?¿û®{8Šôe:'Áw ˜§ÅmÒfö Z1ô®Ÿz™ŒÑ--Ñ'ƒ³=##ÏÎåB ˆ@$öYPxU]]mc#v⊚N²%hhnfWÀ òžá{qãFœ@ƒÝ™W‚cBç`Ð(ƒ¼›G!n93ÄÕäÄdó~RxüñÇÃ0A¦#1àÂ… 8ŠGußu®¾ê*" Âðimíª¯«†)˜æÈ i€y4“µ ¤†ÂÁ‡}2 \çqÀ4bet 9UG$aõŒôeÀ#0MÁ4ž‚Æö“€ nÂ_på,˜¿ii’ÀEòNµ #‘ˆ`y'é€d~ ÞA!µv‚©cnï÷*M_l§ ㌴BiÊ@vjª§@Á4WÕ3‘qq<…ðvñ¼q9b¸°‰QXÙÕ…dOe¥7mK‚½ 1—" ¦ùöXdìØf—øMËìXx²7 7£®º¸¹víìÄÞ°¸Rnié]½º­º<ÌŒ„¬‰F³¸¬}âÆ ØšM%á1¯\ÖÂ+àAcÉbÅâX‚!dÝÎf$L¥òþñ–¿^§M›ŠæFKKË /<‡¶½^ah46Ã:[®ñO˜°ëØqãâ}QpIXÐø,¼¶º†d0úzƒÁUË–AÅž5kkD~ÌÛX©Õ[ fuÔ „*¬×D‚dÀ§žzŠ%ˆÍ˜(‡°¡Õ«+ø»Ûn»ÁŒIãËU# 6oˆb-Žtu•¡h›í‘¼ýöÛá~rÄkÈÜyç4F ö¬ …ó8ØÒ Ù* O²ú·f·4`iÀÒ€¥íO‰ùg¬Ž±aKƒŒEX’ ¡‹-Ö¯gØ™!ÑÓ!K%!Öïñ®[×eŽ+èÌéÍ×è€ï ñÜ€iK1À5SÀlˆ½1èÀ}RÚe¹¯#ÉW8“FÕÒ ÓP6Ô" <ˇ¼ÐlžŠ46àÄÙ¶9õÚs)f! Ø<»3}8;r ¬²¦7Ê€¡x´ÎãHÔéÞEÆ™ëƒ;Ü' ÍeÏhåíåSÑd*å°õa( xÅ›r.DºaZƒÀbøð°Ùs‰óR0¸ÜÅ´,.›Çcv2–qÛp0ì\»1ÒÚÕXánôÖÊì){¸²*O·¼úº' åáêð®cw\±îíµk[=uð²s9o¢fD°ÖŠÇ{˃•Þ¼½»+Ùµ2årF…vûË£íÑ2W8ôÒÂ;Oõ&^›¿ ÏÖ©d8žÁ?v¡nÂó¹N·G6:;ã=éUk;#g,¸ú¼œX´e'î\»~ýòÿwçògŸûÏÔ©Ó€³ûì³àóÍ¥ËV®\Ù²~Ãó/¼é#rmڴ鬪©ä•Üãjzá‚ù7ßüGh €×ŽÜçÉëÍC¨oð7 «Å-ú øËšš›š¢±(ŸÖ´¬L¾÷>{ƒAÙG½ñæ=ñdóy¹T nž0~Ò”)Sƒ½Ág?ûÙÏ}îsXÍy"Ü2KSs3ž ׋/¾6s(ìÃç ­ë|è^¼gà<ï ½®¼òJŽ'¦b‘eË—=öøÃ=ÑηV¼±OßTQÞž9ôˆƒØ€’›ëÄM¡#Fz¢¶í¶çÍ™±ÅK¥£'—‡ë·˼ÉTdÎÜYßþö·ñKÝØXI›Ý‚î‚ v7úÆ›ÿ¸téR5ºó‚“%0 o¼¢EKì¹P•Óá$¼·nSÂX˜Ä¦K‚’ãó† ©ëÅÓGß÷‹ýÄȳ—{æ}Q¨gÓ‘?¿éÔ×/>óOon ?ø¡´ôŽð¶¾¾wü™ÿX%G¶:Ù›ŽºåÖÏ?rÎYw­ùh›(ðÖùúkð IDATóÿêÿ»ùПuúŸÞÚJ-|ðÅ~œs}p©>-?üoÊùö:‚c=ç’oq ïßg}þ²¹]ÛNïkóáÖåý…¿üë{ÍËøóo¯»óùÖèÚR~ÍøõüµÖûìEŸûÚý-Å¿¶·…·NÂm!‰5æG¢5Á*hÆË8Õ€i £¡,ó¿I¥¹àh` ¥8¼ª*oGgçX—ùüJÄ+ˆ‡v^ñ}d Mäå,¡ÐÌ ˜ ±‚ ÁÓÊšÐ^´6Aµ±J%ˆ¥ÿ¼#øž¼—ã„f1QçB´uû±þúBAø¯==ÄYtúƒ>Ö÷&zAx¯½ò*m²©8%µµal“5åÒ~ìèZù¢içò;°•⫝̸çñJ´»‰æq[Å „±¼$þÃíš5øº³…kÖ'lJpº\`X–fÇŸÏ·qc/æØÕ­°+{}ìpŒ­4Ó¿fÔmKb쬬¨ÀüP®{"Qq//ˆéhöìWö˜º8gq˜ÚáHR9Céó­pÛº7}½³:T…œ™xvôèÑ-­"±9SùÿÙ{8»Š2ýÿÜ}_{ï¬NHB€ D¶q\qPAÔaÁpAœ‘Mõ§ Ê ˆÈê ŠÃ @Bö¤“NïËíÛwß·ÿ÷­ên‚$ h>ÿ{>árúœ:Uo½U·û©ç<õ¾ÀPlp¹}øê¬3Ϧ•@(Ìõ±ñlq6›gÏâ?¿ç]ô ƒé#UÁ‹C´S†Õ–ŠyÇzƒ8â’ÞDŒÜõz$Â7êŠ56·`ÏùçŸÏ9CÃã@và8%!¡AÀk×vÿåÏÏxÜ¿B¶qÌ1Ǧ!˜ž§9„óy¢ë©ô1 uä —,1ª…õëÖÑùoûHº¿œŽèTªô8l=‘ïð®f÷äûŠïÇ“L¼Á ‡Í€b!%%ÄžJ¼¢¶ Td°ÔòûPaøÀë0â´N1<@×Pt bÁ«TÅãO<ñ„÷ª^¢d,–f Ë»•³ï‡¼«P§Ò‘]‰¢Ô×HîìôeRO̼ãïñ´½ó_tyóOÏÿ¥ýË?úô†ËÏ»{'Ì}沿šýË>~ÙU_>á€Pepå-W_ñƒ‡ût†9¾8»¿õ²'ÌMG}ñs­|ëÛ“`zº§¬á埼ìšKÿ)rå+,y9}£†­¯ÁÏ–À'œÉy'N¶–ô ??ç‹ßfüMQêä7ÿò¤c~ù,Eßȶþ3eo>áÏí³ÅÌ?`Ãëzd×ß”ÝUù:f/_±åŸùÏŸžéyäÚSþÓÚÈä7owMÉõé¾_Ó=Ç;¸ÝLÑÿƒñzÍý*wÿî´£_ñ‰ ¿ûŸ¿9ðê³/ýcïÞ¬Jkƒ:ûÐ?Yæ~ìW??nú¾¿þ»ÿ˜…¯¿Ýz ÿGÐäÕ{úd µ¦Ž©+`×"¢P˜RˆmÑŠÖˆÇ @Q‘õd†¹E¥$ãC«ë+Ø|&õ8Sæ¬n¢xXÜÛ#c]-Ÿ´Ø`~©¼RVj 3˜˜ÈbüÑŠÁDøØ|b`” DCRÁ‘EK>[ZõÒzÞÑGb `–Ýí³&R’ $•¯ærE»ÔPÏæ^ÚR)JŒáCß¶ÉAKS% å4öB…gó%$uZ$̉ôXGš¤ãE„&~WêîÑñVOC1_2 ¼d,“MUÌUÃ䆢ÝÛzmvI1ˆ&fÞí4ÁçRɆ€éB‰Váq¹ñ("Ýp XÌÀy•.+‰Ð¢u”h,•Kç˹|z±PBSžBÔ@Ï8ó³K—.†'ÚΛױt¿¥¿Yp.[ Zª“â:ç‰'žD_ «ú2úžÏK~A®´ŠWxà6yd¾"÷z!¡Y#!¢ÐÑ ÁÖlID‘òÒ‹xÀ^YÄ3˜• w4Í9.¢¿À_bã½ðì³´{ϽwÁoذ ìËû„ÎÎ6¶’GÅž òÖèš ‘v¬ß°‰ëi»R¹ç÷áV.˜¦…qÑ(óðê…+4Š’$“Îù¼EŸ7À@ŒGãÿü®÷´¶´£oùÕm@vÖ`L'zêp£¿'ÁN“(¯ ‰žÓßjV³…w;2mhG¹ä¶:¸=…ªw…½§ ¾9'‡§ís?Ò¾æç]Žå—.ŽÜû‹=r³æ†#/¼þüŽÿ¾èÝgn ýË?þî5㽟¹i“ ¹û[;õÕ½ÿIŸY¶å—7®“t”Ó?å=àœŸßôÉâcO÷¤öUÌl×Ò3n¼ùs¶ß_qÂùOޏ÷÷;]NfýÞü%~s†«ÞjÝ;yÀ<ô‹Wæºýܳ~º:¹wÔêÞ}+ßd/ÿýÂâjnð™[.9cø;¿¾ìÛé ¿Ù6ã¾Ç3ßÂ7yàßRÍ)øë.|Ý$3­Ð€ôCã}®~„¡T1¤!†5°ÔÈ7º&½wÁÌÐnZmp¤NXOp•á ü=öNÀë ð /ÀyÊj8AÞº$xš’d‘Lƒó K(ZAÒ N®PŒ£#1B@ôŒƒðŠ HBÇÅääÐw{‚¢÷PX_óŽ…lÉí.Þ{ïóïzWâè#T.—”ÄÅ,X6W ¸ÄÚãS¶EªFåSzÍÂ@ô⇠çð@o‹º”úA`¶lf“œ/nnoí«:‡ø$E¼/ǨôD¢PJ¤ý¥—ð[%_öÎ R€-nØ {pËÆ›È QŽñѨD2ñÍ‘]z][¶vw”sÖšè+d)~5k>ÆŒF"Œ§r—¤rAÒ(QcD¸`TÔM­- ZÆt Æ=o2ÂeЧ ç\Óxšáǵ$o£ˆ`ž?úØÒÖÆXdFüî»ï†îE  cÝÑÑA€¹÷¿ÿý”!ª Œ5d3ÊiIúØ;üÄÏÜ|óÍ„9çœsÐ%S„ûg?ûÙ#<2Åýä>¤ìá`Ùà DŽÓxG`l!æc±û￟±s{|ðî4Êz†˜$ o¸sFK°WpàœÃXá =Dmo±¤âq*$45¬6éÃY ð 3!&qúËÈ1R\]CÔDzr;IsdR¾ráÆÓrU}›4tÖŸL¢É¯˜zn&Sx:täUwÞú‰9ʶ÷¬>Oþ÷‘nÜqÚ/6NÇy™›W|ü˜Ú×ÝúD*ÐÖÖ/ùèG–þvÓ‹)cš[/;À¾àÃ_:6~ëùÿ;:¦{ÊmÛôãO·²üž_râ>ñ¡¹ùˆÏœ¶pý§ÿð‘n^ÇVÝw×+ê5{ŸxÍ¿þñEñ?ÿûùݲ>5I\[‚}òòï^rübWì¥ÿºò¢ï=Уg„òÐwno;ç;Ÿ{§u믽ðÊßošôÔîͰ4zÖw¾û¹còÖ¬¸íÞË>÷û{vÒ ø¾àW??~ðš³¾öÇÞ½”L׃}|Ï:çÝŸ~¿ñÀE¿Ù[0Í"w÷_ØiÛÍ´™ö¹¹KÏïi²MÓ¯=Œä×Ð#?þÁq·|á_ßöÀwW¾*½çí}E]¯JLcÆ4·tåûÒÂ×ÖŸzé}ê £§À´®[°£þ³¯ ¸ÅõJ Xp3äe¾'(±™=k6#xÚ®3¹¨¼p R>­v›Ãåô€•AÔàÀ °±f”DE¡ÄÖ(ÎÒDÅá7 t¦¸ º¶XÔÂË“*T‚ÄÍÖ•wµP†ÿ¶ÊºL¾Š´`ý&Ù¬æñÍö†Û|f¯ ¢lÁBÜáš´^1R劵PpO†=°dU4; ~1®Û²½X•{sf5¢7 žtɨš‰"ý–Cœ#ì8Zr °°W,HoË•‚€×t¶<6‹äFyÀæ°ƒ¤{zû kš[@–Û»ûI;gb8™4e,è\6¿yhÇ@>UËaA™ ga³ç²ÅT, 0sº««˜+V²†·ÁÑ1gí¯yiípßH< 5ˆmb«9ŒöyìÇ´.Ó³£7ÃmÍæT2Þ,6[=‡ßb¦æSYI^ȳ 0ÂÞrÕ$bÒ©ŒŽ R±pp4~Ç¿'å!Ú‰h4Bf@ Ôfe¤WEôšùlj’Ôågœu¶ØÑ3Ïâ–`\d$àf.k Í@/^¸ ÅÎ:ë,€WFíÚko Ìg?ûYÖÐÒwÜq{GFF—,íDðýîw¿Yp\/6ˆ‚41 ƒ‹oÙ°i}Á >š=§ƒØ™K§ßûÞ÷S3pÖ“O> æDÖWêÐx! ¨ä ýàƒÀD/</éŸìÏdá„3‰$38ã- ‹ \ËòŒùDb‰Xàzvè *3F_øk…‡'¿>ºÌÔ-ùqê‹&?ÌŒc OÇž¼ü} ¯?êßnøÐŸ¿vY×17~gÞ/ο~õi¼[[ÝmËæ;Ü·4ÿó×.?bãOo·}jYGÈòbª2Í­Éê,mï=ÿö{/ýïÞ)­ótO¾øÎ<{·Ö¼ÖþGhÛüÓ'w•üo;ç2ÓÝß=ñ}¦ÓzñÙ‡=ðÕG#ªë¬ã¾uÝ‚w~æ˜3æGW\ñÑõçÞ!€œÃµôÌxÊøÏÏ{Ï)ë³ ¿ï(·ƒEôN4¿½ý—Ütùþ}á¸ÿx,2q=ñÜUØÿšÝ½tö,f\yÒûL§ýø«§¿íþK×Y\~é.Yúøw>|Î_Gçžòóï½7ýŸ¦­ð;Ï9eÛ¿{çÿýëÿÑzçµç\Æ%ÿ´0p_fls>|Õ¾ÜüзŽÿÂñýνùÛó§ÚšÆŒéµ;[_õèúïQ*òÐçÿ’ò|vãý¿í:ñÔøà÷ŸO–ÖÃNX{ð¦Í²!DþƒÏ»Úþ?×qôw_xÓ׿ù±κ­K(ÊiÌp,øÈ…§Ìyø«GŸô\³ðèw„ÈjûŠƒ¿†ò—dò/ä+o¾É?YZ>vAüÏ?Ù°SÒø=™4Ý÷kºgw;m¦¯i=?Íd›¦_{/úPzæžµ_úê{÷ ¬|ö5xæU½ÿǦÍiá«L®_x#=ÈØ1Óôpœ4( w€À(6` ‘j@ ‚†d¬à¯W…£Siä@*œh.À/}]Qz„’–]}‹‡’š¥S'’f‘›P†´Ì#p~ä?§$×À@$?WqaâÐRR³Œ ¨ÞÞQÈѾÁt#fÓ\© bÌ–J†€P¦š5C¸d·ªT"4›ò¡Pðè#ça¶Ã&±ð8Ä-JmBúq±§¦ ¾Êu£`õÄ¡™õ’Ù%ZŽt}íP*'쯷Ä~ëBTÓÖàÐD©Õ"Š”hŒüÞ÷š+@ÉÁAdá;Ê%”:háÏRrppHòB ñ/nþ»˜‘:K>ÑNphW§Ó«CTά …´Ô8V+0ma.CÊæLyÉ â® ÇÁâ Íw¥’O&ó­­ ‘Hôž{îæŽmß>À³ÈF@B  #žÁ·ƒÃ©ßçóòÉÆA8rtD—CÕÍ9p\k$Ø·¶¦6¨ßßþö¾¥ûu^)ôÑGC„³%‘?þ8°›Qf€ZfÍbè±½†È0NúøGi„êƒb:Z&±ì=CWÃ[ÓæABÓboß ?>ö裄±ƒVGd‚¨™þâO™~ê… õã>¡´i”µ5P¦·w„ÊC!’´K,B<‡?ÊDB³ÉDÜ=¡™wþSª¤O†Ê41;õJ’Ê9ð“ÌC¦ Z‘êF¹ÎE>'¦Ñ ûß+ôÞ¹+Ús/æz°oO`Z\á XKÉl­í}—|eÁ_¾uÁ#‹oüäR’4ñýžæ–ö©áÈ/œ3wåUßÞò2¹;]…ûÞsvO£³‰’ót—‡)±êÆËnx´¯ÜþÜ`åäìË–’öŽwjEêÎ/ÜþìPÖ¿÷¾È{Þ½¬áwÝC2æƒ>qÒ¬—n¸ô¶UCM?}WÏ+j¶µ½ç’ŸŸ}ð3W|þûEöv¿¤)õÂ.»þÑ^Ì®},äb&ɂξàg¾í¼þ´5kXüñÂÞ½ïßeOõÅrïCÿñ³‡{?©ÝðÛé9âãµCTÈóô£gØóƒOßð?Û‹†+žT ·ô1Ó9j·fˆ˜x¿Ýè§K½ýúÉOóÔ#~³ú¡Èì#Nè¹ïÚí/¿>ÁQ?üú5ô–Œ±{ŸJ_uÈlÿm]àðéÌ(§GFË~è‚ͯ[ÿÐýoVjÍžüÎÿüû«3ägwó’6c讑©Å^صÇoå^ÔñŠ"Ó×îznÐòlb7_í½èå¯Ù4fLsëåF÷…{щz‘ÿCÐ4‚äï=Ê >ùqª=~äЈè €Ä‘d³à/Ó©@±× á  î @d0Š"ˆ@PítˆØ,+ØÂ!Cÿèt)ü ÍLêÚ#H4i< ”HH DÜ€6±7’Øy"ê°ÈËz³‰OÂÞ…štv Vjž¾øÆ®±HœŒå­Á¦V®€:‰\mؽmøR©¹|A";Û†_b¦Ùü0¯mÍ>¢|¸]‚éQƒƒM†Äq¹l.Ð?F˜kcÈ÷FK_ÉÕ-œy…è “Íëô¹­îX¾JTl#™Ï¦“‚†á©­vgµbÍ窳Z;¨?2öU m6nì(däf»É(ZxH^H´àô­6À5OÎH›Ûc/Ê›×mËé!Å=‰(ŸÍÚ$AKFKc}†Ûg´46ömózÍ áv´ ÉlNäVÖ ™áiœš©±¡‘¾Äããô´+‰ŸìÖÈu4Ь=™H­~q 'n·,i"¶rfez¼<bšÙ?ñÄê¶6Á쀤ìäƒi†„ÖQðN8ñÄN{`×Mç>ŸØi–íñ©}ê³bf,oŸßPŽîêïn¢ë±eÉÏwŸ_Z»P wx^cóþÜýÂÆä^xÈg3† BMž†9ŽÄºžØ®ªãk×öÎãçµöÜú‡§G”†bïŽd×c/Nša2Û$:£T˜}pkní }Ówïêš®T-ѳjG‚_ÌÕ±­Ovʼn¶4y˜C ÆŸ_7¼ ÉÃ4fLã(Öí¼éž½+¨›¨n¿í”“ÿí¹=²‰µès¿{0ñãSí|ú‰Ã?ܶã®'ÏSãõü€úYÿšdMgFeè¾ñ¹Âéçž÷³?_YyÛµßûÉ#ÝÙ×½0™ÎËûð/{ùÃ1Iè•ïν{úVîCóŒÝ~S˜F»Ÿl‚vÛ¯½/È"% áõôæœ6o …¯§wõg_¿@ºúºà¿‰Øò·LB|Mü.K;õ ƒE"ë/@ðÎ…B•yN¦j+³ñ°\a;]*¯¡¢ùÄžXØíÐj¥(¿Ú(É•)û©¶ëÈ6&Û%†ä>ä°o>'ñ§~+DÂu}+ŸÏ ÍˆÆó±]]Qð–/8›[ãIš¨òx±$!8x\’tTZ¼¤¬y9¯•SX›IªlL—KijpØÕ,Òyoœ¿ZT¢IH‡Él:ž–^[ÜEžUˉ"R Ð0—+°«/&Ñ#N°DÇúaÍ‘ä2‚É@VÈwaÊY°±ž;•ÊxCá •ÄÆ·x}®æRæ¶ö&„ƒƒ}åò0Ú*ŽD(æp‰ ÀMÎÙÑi&Uä×mm N—브›ª$Ž/ãÖQP³¢–±Î0Rœg²q~éø¼.äà<Õ×?¹%Ò^)¡œ¦wzdÙŠ‡ƒI³îó![Cãî’±×Q!²l”ìz^¯X±NúŒSÏfó"ehi>y-5*í“O>Ybª˜ÍÐûÆó:;{¶m#”õon¿…1Á JÀ4(ûÁå0ÖtáHNÁO/Ýÿ`ôÙÈT„•Y*C&ûb™™òÞƒù '˜žö Þññ$…™¸ˆÎÿƒ¼4<¨–Uƒ‰®Æ(ÃÖ4êQ5ðŸqþ±Ì`®\Ý)¾‡®_¦ÐÄþyØÃªÎ)ýôëú ¯ÝÇÇ«õÓ\ušjã/ë¯\ýý“÷ ŸÎ¯ïu|þ«Ÿ~ê{§Ýº.c¿ÿ¡áôú NNs‹»öŽ_ð¡Ü_ú‹ð¸;Ó?õŠ¢¯ÿ‡äö§×ýÈQó¸Þuo\¬/ÚóÄO>ýù?¾*^`-;Þ_ ,ž´¬ÉìR{ï»òWó¾yÍu—vŸñG†^¦ž²M-ÓÔÁ/F~Gêí³yW§ÄÍÙGÇÎ iiJ~«ï‡kîaGÎ÷¦&[šÆŒie/µxµÍM-`v.ÝøÀí›N<ûŒ[†7ßüì®7̺g²Ì5|w;A8¦5èfºýéEÞtõâcϹæ›×›"§ÿ…©Î½Ú´™t%;¶-j>¤£Ái¼:®ÇîÜûòýÚÝxíÎó¯ü-øw“ßÓôk¯ÆËÓØ(’ÛaoßírPwg¼.<Í´™æÖTCûÄÂ]š]¿ø†yÐ4Éç| €È`áž%?·PÇœsâr™1À£ÁžèØØÌd´^ct4Îk."²ÈÎ=ƒøedDtš&˜ÐÒ@.žr)ä‚ÙhbO€¯úÍg:O‡F¥v»àrÛÀSbCWKÕJV¸pH@èF²¸¸ —Å:œ­CÃ7l„ó:\áÁH–%Ò &l¢Çn0'(.š[¸H:ÒÖ¸$üF­±ZJF!ÕäbÌ×Ê9ÆÃ$,Ã`Ö¬.– D§c5 45t£ÅÎÞÖGâ©ç×f.ë ´£–Mn07>4o^0O£«v:ÜÁom™ “šL£(.‘‰¦ °&ÊçòÇ qÑ3ì uÈÏ3=ìíÛÊ»£9ÝðÐ ãì»'Ë”£IF _±Þ†¹b„À¶&{k¸™uBïömè…­FÅðá|¾ Á[èlŒiršgq¾ä±Š˜Äí²¤r«t"™¡˜—l“*è!ù_ÀÇ ‘Z* ~P.*äb6™,ƒƒ1eƒã|•ÀÍîId,rØhªF}ìû>tÊ)§|ò“Ÿ ÿö·¿…QfÓ!»Zf\rÉ% öÛ/‰ ½xþ™g®»îº‡~8‘Ìï·ß,hì~ðƒÀnŒÁ øÃx¦13èÖÒ¤5»QõSÊ ''DoÄBú«áµÜP 3>ý~7 æ#W¨ T­°µ€i láÿ@áràlÔR97™"’¨¨¬‚xˆD3Ä# ˜ó³:•…™U§*&‹Cý)Ö̘c OÇžü¯ß4çÌmßüÚSüÛ÷½ë‚ï<½uuä¹?<ºãð·oíËØB‹?ø…Ï-üÝ¿oTxdš[†¥íŸ¿xš÷ÁKxŒî©}î´êèS7ýfË-_¾ò‚È7o–øï9½êþǧ Pèþë]]§œó¥»¾wW)¸ðˆc+>òëGû‘Ç×ÞuïèÍ_¹ðS½×üa]Ê»ôŸŽ®{èñ)MBy쉾|Ãì[¾}ýÙ£ŸûùšÔë B“«‡}Ÿúð‘]]Ëνò‚Cüµ-ûÜAVÆ·¯M´}àÇÝ32~Ì7®:}Ž¹Ò…ôOÓ˜1£¦5µ–ï¯Í~÷‘û=42ÜzôÑm›úkï¤ Ë}ýú‰s~vñi½·Ÿýܨ|«¦‹ÝK¤¦yÇ^põî¿]üнFšÆ û¼cÏ;1øÌ=¬îKôôEKGyýÒµzúâ/~öáÁï}æâ{õ¶ÌiíÞ‹›û²ÂòðêÇFÎýÀ¿Ù4í¦áÍú?ù~ín¼vçù=,$w߯=Ž—tÕÔpÀ±‡X7ܸe/~M3b»3žI5ÓÜz¹­}dá4Æ×o½ÔjÆ‘¿ëĸ“?ûJ0ü"•*‚ÈØ¾©p€¨vlÒVQ2æÓºœ IDATðÛ§¢pð@œA=º}E²NÜQwåžÃ)1@¸#°‚T„NõE™K†?Ñð >žž5#:_DZ¸L=ófÏeGZÿ(’‚€¡dj"Ì0ȯæ#%4tlGGDzeó(f³‹¾™F©A·Ê¥WWh6É&Y¯'^âë¬.ˆ"X¬Û¼ž.«"±”áèéék× o DÑ6„šQ’4uÈ3+_¤È _I¤=c »RqÂ,Tn¨b0:]6,„šÅLœßÔ¢-ë©4¨,!ŠÀK±HÒ$C¤…¾5WjØ@I<ã‹ÞW‚8y~ocvÀ/Bà)-2êÚ äQa $å—Ê"óåž |Œ…pÁ ãg5&³èé»ÂåeãânQ •SŒÇy{€¸|ü_¿¾`M¬ꑯ"ùÞ{ïE iÍÛ¢|szëÆ×_=[ñáÉŸøœôQGEU”„ÌFËèœj±GŒWÓ–)ÁÓqT.ØÔ§¿¬ô›zBïèc³®D¸hõÊÆM÷¬Ì-}>9yåÿò Òÿ¨ä žÑÁEZó-RÙÀ‡NŠTËHþsÉð4¸38xm·ÌüWüí׿ùŸj¢ßÂwíŸ}ü…‘æw×°ùOë÷òQuì‰k¿zúC¯zôù§ïýJÛŸ¿ýõ[7LÈ¡w{ËÄ^¤s=ûÓ;7ìB«°Û§ #|äUmÝ´å¯ÿqÔ‚w\ý𺮭¾æÈðësavã-_ùìu[¹üžU/=ÿ¿7ª³XØ3Q]êýã7.þ/Ëéÿõô‹kWýõ§µEºÇ'ŸÊ¬½ùK_½Ãô©[_»qõÓ·þ²Y½ÒÄܶ?\qÉ=îó~qÓ© e¿ÆÎGó‘×ýuÃæ?]|è^pÍù­w_õãu‡\õßOÞvRê—ÿ¿ÕIIäº÷îx-m¥×Þú›úÞû“GžøïÚ|ÍW®6hHØzjNcÆtŽšÖÐø ?¿á!Ïçï\õÒS¿?÷mD[Ý©t-úÂØßö?÷¯ý»9|ûå÷ñÄ_Ûïù«¾øònOc÷f£ÝCÁ㮾ïÉ—6¼´êwgÛ¸þgÏ¿¢R¤|åË´öîýÍ}Za¾ë¡ÛW7z޿̕Ц{wLóýÚ« v9mv7^»÷ü´mí¶_{/þù–â‚wºý™‘×´XUýêZýëS:'ߤïÞøi̘æÖd—ÿQ §uYýæï D·Ë‰ì¸NÔŽŽŽvHAt±¨#@¼IO\N`ÈcN€5`ô-jàqpÕhàâÑðeêYr¯(´Côdy IhR«Z‰R5#ã•-ÛÆ7l]»qxÍúAâulÝëÚÉGµáq£g(¿¹;¾aKdëöèÿ>µñῼ¸ê¥ž±¤)]°Gó£ÑxD!t¶\Ц’›·ï4¶…[f÷ Ƕî+×ì.oˆä{›³½¹ %´Ûánil) øa™?w^gÇò{CÛkÊWà{°Ç‰<;™K§£ùjÞé·†[ýùjšfgɢ̓&{üÙÕOuõn*VÓWË,? ëèx,•÷y³æ†“ãÙ ×æsZc£ƒ£ý]¦RÊï4•³±lbht`8ŸÊÜFÈc¸­e"v¼þUËyÔv¨Ê¬(q`p¡x½î2@K%…ÿX]p,+¤ôˆÅ£ñÄxd,.ÐÏèóIDxz‚ª™ài`73ÉJŒEsá @ù /D!,„DßW]uÕÅ_Ì¢3‰Í‹ðÖ0Í7ÜpÃ÷¾÷=‚ßýæ7¿ùâ¿xÅWüñ¤(i¦(µbÎî´…]][úf0©!ø¹O/Ô‹P/&Q*Ïã¹it°¹ŽX8ù €Hf‘CX=)¯_³ÈêGr{Ê-®» ºÂ„Å $ôÁý£ÂÖ"&áSôØN‘o“žÿR›ëÜÀcz¹¢¾Dú 1³>M³gµïE{Lï·7•¼eÞ*vîcWx—õ¶«Ún<ó¢ÿîãš_Suoˆ–ÙþáOOXù•/üZEïÐ‡Š—÷áû>ûæ§€y=3ðµ?k›ý¡«nûöÏÿ¢«ïZß…Æè5ßÌ)üõËdo^qúU×~¦ùþ κîÙØkÂÓoL×g¾…oŒÞâ­uâ)ôàþßþ`CK^CþÀkÎ ŽŠ8Çû-\çY»ÿ’%úDÏÀÁTÉDZ“Óë–v­Š§7ʬ ê ãŒ3>þ©OÝxíµljü×ýWÚ¾ó÷ÿ¼†Û¦0Õb¦ò,ŽR^ãc¨qišÝ“d›Wk9Â2 ÞåS/9ç:³C/fpˆBÌßaÍ+ÂZ®ªI2A ë‹t[ÞpPüŒIRMÈ‹06­`“. ­›å €î2èÂâyûÄþH®\øµ‹{rò‹þ‰?Ü>aЛú¿÷#îÉa…¯V¥öi¾ñ=µ»çûŸ±ù¿÷üÈ[½„mþñ—Û±ò¶;žÜ^ rò¹Ç{7\½y/_*ìþ¿f8š–/o‹XÞÿ­óç>ûí+¶O¯ÊÙ‡}|íU½¶oÊ뙽¥þ¿ufñ¼+¿ñÛUWöýêÔO^ýœ¿v›gÖ¯¹_–ö~ÿw7|ijåþœûéÛ_˜`zæ[8³¦ÀŒ·F£Ìb;„¡ßé;íöù x’†Ì{G¤ È:¡Þ@Q€~XØT%¸FQ*û®xÍCÓY³W@9:b´Š“ÐnsóY­Ž„¼#'• YíÏ$ò¼¾wxCM`”\àTpX`ÓlN$sȇ¡%‹ Cœ¡ ïOɯåmn@(4zûºÑ8ðF¹%äZ¾´cns éw;ËJ‚2Â8d²™ÑCs‰½ä<‡B[ÖšJù¡¢õçEÑmÀÜgË™]Aj¼Hž?œH+Ù=iŸ?k^1#$¼~[Kk„ÑPû왢ø%±ŒÉ¢õâ‰d2e!ý (Óªt¾JntÉt¹Í§%]6¹šÚýÅ¢=ÔèeûÓU‚!™Cm&—?DOîLÕ46w¾§jØr±’É ùœD&Éap©¹©¹ÁYÏdRè¶Û›Œ–¶YxžzvMµ,N“5 C"[ø«$Ð)•È`CGÀ¦P¯9͘(qK,odùa°9}Nºb"\Vÿˆ '1Äé;Å@½¬£@½ II–Ž«Sóç´ó#]fÍ|göƒü€ð|ÐÏ_þò—Ù³ÈD<ñÄÑFÓãw¿ûÝKk_H¥ 줼F´ŠvÀ‚+òÿæ¾¢m`Ïb¥=ŽèL)ðûe)ß釮|ºkÆ’ô3ß™2ôo;@ò}—?ù‚‡Á§ÁVl/ƒÍ’jм…NÀ@ÍT2а¿&6ñåòlÙ¢%j«ZU>꤆Zm^HZÀ Â- iA6ð¨f¶€±#C„ I´æöö6A™a"!ü8¨Š§ 'Ë(‡Ùf®‘æœ`ñ‚ d$<«ÕAåúA¥e;g·ƒÆ¸cís ¡¨aFKŸñˆGwXð#fó‰ÅBpV%:µ6£¿3xÝåóò‡Ikž€>7Ãåó8(S†Ôjd$2Ο¿¶µ·gPeA¶²ùž¶rW×µ¬ð¿Ã%ŽJ5ßÑÑáõ9úN+Édšöàž”)J¨o»‰å…ÔÒ±ò uæ8çà]@ÿHÝ_>u…ºŒîçjŠÈÁ£¯®G0†ÂòVFoÐï}¦f×äãz;¶v†|î­Þc†˜[7£îºê¨{ î7ÑZïñà?â/;ˆ }XI€‹ œL—e<,¨‹OÞr[«”I¥À8D¶<ërÊÆ,¨iø?Ä Aוª¥ë |à$»YR‹û\¢?¥rÙuçt6òŪ éáQv’%j9ÑÚGÀdÂA*H $DvAB—ÙÌ<8ÎfeÇ$ØI¥,4 eчX”îÂO`8°L1ÖyÿÑ©ÍaÎp^°IÄe°¯”4É;w›Uêݪ±l$ º‚„ÜfI:†š’™ 1×,y‰ ·¡›ˆoé’„ܶ-šLæ.ÖΕ-‚n -8~ó–žpØÛØØ¼qãv"?s@γ%Ñ ½m³¥sÙ$ÁˆÉiRû#«N—l(œ3·ß&SQÐy,>ÂÖ:Þà´ƒƒ#K|Üu8< LlL2•ø~J6zý¤MÞ^;à÷œ†6#¶6†%性ۻûЙ4¶Ì¢žp’¹X=x;š*­Á¹d0qºeÇa,šd¬[Z•Î'®a1ɺ ›9ð 8[xl ¬A¾u#‚>)#®S¢9§Ëz94‰kåBä­¬Ó)Ùé…»üñx’€-äM<î¸ãn¿ýv2ÓoH\nÙ B»ôwhh ]‡×+O©ú9©Ê9á% cÄ¡ïò©Á.Ñ%¹¥{¡ S]›(¯& }¦‡þñï>‹Y‰¥(ÏiKíÁ%Æ8…©’¬JøäÆÓ"£CøsŠqwÊNÜCðÿ”Ù_»è’·¬Þc—Nª_¬{ îºê¨{àÿgð—ÁÿÁ:H8&‹C ü³œÏË«|HÁbºæ°;éÂ.oÜ´œàr Â%“8ÁDä! J톥Z0ïÏ5ôQE  ؋Рªãu?x1‘Ê!y-–D€k ù4’æ.pDcj€X¥$ð8Ä.?€úW®\¹fõF’¹€AÕØ)8é*?aˆñYLóçÏgg-&¢ƒô‹®Ó]á¿Í¢…Eù 4„K¥ÎIñåI€T«üc)àNž”¼ƒ(àJ[œ`»ÞÞ'©¢y^3>É ÷€J!’ÓéüA-¡¿¤1Ú/’o‘@ű˜d„â­p Y»ÏŽ6:òŠ%Õ8çºÂèR«¾Hú)U§Z§Y$¦ 'Ø™ÈÉ@è5Æ$¸—q”¶smáÌùÜõJbæØW·¤îºê¨{ î™æ‡ ðÉF84ì$ ±ƒÍjØFú‡á>¨–ETK|7ÂÙUjôFÙp¤2cãG8c£XàU>;ÛÐ HÌøœF ª¸Z)W-6§Åîã΄®³ÅÇËÉäx:•2‚2ÙFh!œ†ËæSÊŠB¾Lê ¢ù–ªfôÔ€uËÁSÍ´Înhhjq–"ý mg!é«™2d8< Àyhj^Ó#̶eR¹9@é¹ÃÃÃYµqÅ Â6º=­žâ ɸ~§¥f‰G‡g²¢¤ì†DÙ«Te)@ú‰Ç`ˆn¸Ps˜pü= ADƒk˜ eÚ>§óCïiDœ=Ý©L.ÛØ¼v9àÇSñ`cûÐH®fбð°ÚU~œ\ÅHçl‹mNGkÚ4€ÍÙR1±Ó^^º¼3`¯€>S±‚¹Z¬*ѱ„Ƕ5›&†ˆyþw¹«øÒqå n{bÿ…‘asOLŒ\Ã12’všòF{{íøcßÇjêOC»™éŽJ¥ÀaeT̲U1[ÊWV£9è€ÃfŸ¡…Ààå’¹’7™+N›ÓmG…Rv8MÄ·N§P_ˆÃecŠ 46ÊE#è•×x²T–5O©TŽŒŒ³š‡É9·ný&ˆ]»ÃK N6<2ŒöùE­Q¯É\v¹9•}<ÎKôÔÌõͪήV.ñ±“-–6Y$à%¤úåR‘·üHažåœÈ lyEîO&yºÇEÇ,ù,NKб:b%D{2?Ù¦Jü;“-q¹<Ô&ËHžR"'š(OÔ¼j¥È³ÂVÖwòåâYùòÈVI1^ù7a¸²~†u<=C¢nFÝuÔ=P÷À[Æ ö²?Š·öMüÕÅÀdš{Ó‘¡A šEãn0èXªP C7d§¡R“rWr†+ò„¡u¥Ò•ˆÐVÙBIô¼£€“)(Z¹]’þ›G0Æb–Ô}¹lšO«© *Õ(?àgœ½R«HíLöÆqþüìÆ!Ƀ-Z“)ž¤"\l#j‡lVú‹ô '9ü°å<Æ¡FCæ›FÃÇÓW(É!èvryЧj r…†å匆ËÔÀA~ÄÉ\§~ÔÍñÉ]:N…º*â ¯hø´ÚEùÃË™BU‰nN \§°ž›*HŒÛhþ¹œnîN}³d fÌQÇÓ3f(ê†Ô=P÷@Ýu¼E<€˜•7Û>×ë€T ™\x /0E1vàz£‰4†Â (›¥‡KÁ4¡UðEÞøë7á<.‘iHeUüfX'P+»\€‰@è(kU¶+Jˆr2š£™!¤©R„Fu;ÌOµ©É6wnÜÞg•Pv‚{S¯[³V$T^UÉeáû€Uà Ã&þ¥²9²c%cÉ®­Ýófµû<¡·u:QK KNg2->¿ÍaOgòVº8‘¥WV±óaV{.õ&EbÈ!Ÿ€2.´Ïï÷šª`’·»˜µL"AÆ ßGoTÀ8ù‘d(†Im©4Y]N6#’hˆ"z©qv6SŠ'ãù\96ÎÂc ¯¯_¿¹¥¥Ád«R¹l|A¹ þhLö_–kà¶ ²î1 3jH§ÉÒR]³m¤Vù—£ß~ÈŠY›V¯5Ø!éoÀó Þä ‚ùY08©¬‘;DšPÖ¨+­Ý`×Öž—Öld$ý-U$8¸’™À=ln €Ÿ×k#Zµ¸D€#Φ;Dëæ3Äí–Lã¨hØwÏ"jøEÉ?K/81•Èsiµáw’5ZÊ¥l1•-•k9“…˜vµT.Îs[L-~YP'SHÇĈÐùßï˩Ԭ¸_‚k<-BS?R‚°¢þæ„[\J^í:Õw©D?ÅuÝs…&d™—Ëé‹ú¦,'¤uYÄñIÅH¸ÿ­ªåÛÀƒŸÔrÊä{D[âºIň>Ÿ9Ÿu<=sÆ¢nIÝuÔ=P÷À[Ã0dä¨CøTØ\Ð1áLËRálbïeÀˆt ($à 7@eDé!E‡ÈZŽÂàÒRƒ·¨þ“è¿2&•¦ë„ „›s€[8'Èh’U.{ ©?è-0Žz}ÂX+ˆ‰K—ŽÅVЊûä(É~=ÀШ&úúºQ° Ÿ¦f„$µN,o$3_c“ÄC»àT ƒ¢@>2`dEä¨hàh9'e¤\VˆME9Çá´˾ak7ZŽh4{jvb JTÔľ£~ (òU &¾vVÁMÍ\*ê=°vÝZÄèŠa—€k¯D"ƒü¢œ1¨8žŽ9Z}Š££ƒ`ÓD:Mß)Éã>ŸðÜ‘È8Ÿ~I÷Ðæ®5k†¡·÷Ûo?á„mSÂ’WLWoˆ²ÍEúîóy“Ѿ+;ÅÏ<ÕÕ=8<q;œâöZEÚ Ê¾:³©(¸™,*€4~óúªJ,B#½ 1˜Ü‡4Mqr&¤.gC§Œï”¾Aû ‡0u¨¨|†‘aðþ¡&+4ÆÐ:2‹8d\®•ñ1›eÑ¥n1èã“úØ| nU%5˜æŠ~Š9§#j åÀú®þQ?ÈqêqNÄr%Ë×[!©GlRbLo”e&xZê/ã^I3©žÒ:iz Ð2`˜ ÊNé„)3æb•Ïcê†Ô=P÷@ÝuÔ=0£=0wÿƒ°/=.ˆÓns 9KÀñYU– É‹"|¯âÕTò ûÙç¦zs­°‚ˆ‚%p¯ Œ øixC8ä5ºê9-oó…@¬ yôÊy ÇÖFÁKœ ~ šH¥\ ú‹óç6w.himñ7„íÁ 2‚b©˜0USÕršÇNÐ3S«fPžt.ho†Î#Æ2°®P*äÑzÛL9·½šÉŒ÷ìèàÐX>#åߨè0Ú[ˆ[imCØNeÓЊn¿WÇl!Ô_ ÍZO„µÐÌÒU0Œ­n«˜îqͰØÑf<±òù§Ÿ~¶gPb!*F<^bù¼n>YGÃ`0YÐ5ž ¯MM¿FP ×ÐàÀ¸¥y¶Íê øZ›ç*B²ªUÆorÅ2‚oÒwÃæÝŽFÖ#±8  ÉÜàqû5Íô†‡¢ÅlÉb­lZ;–Î$æÏ[¸yëŽh$f6;Ò2M”y?€Ø\ûÙÑÞ ]&û ¦òQ3r<·³É7;* {\Ž‹æx<àÔb0@øD$ f§ÝE/õ!•è~9Ï4‘Ì8„è6‘FÞÙÖÖÞѱ “ÉwumïÚºƒ ¢nw¹3’ØÛV‡„ä-“8Š“%Œ"y'Á ¦r­’%ÞˆÀYÃË:Ên"a<îVOL2ÍÌŠË2NÁ\¹+³N^qð¶…«²¶’OèpT%ÌeRFä%„4ªbS[ÌD1w¹ÝLS%c–¸éü£É&¬Ò*2êê:W,\‘ÈS ? îeÞ D€®s0Jbá¤'T%´£×-j%)ø{ùâÀ†c;–+ÃÍïxç;²‘Àèݸv&üʨóÓ3aê6Ô=P÷@Ýu¼•<9 Õ7:œ®Vj¢@(‹z•?üònZþäëh† Å5²é 4S%› C ·:('pE@oÀ aòA[ òÐoÛ˼ԟYC—JêrÈZTáPå‰Ç¥³Ù)M Z€l–ðbBœ»]èË{h¬é IDAT© üðÙ@_¶÷Ñ<«bU%±¶NПº«º;ä%í èRï솫ªXÚÒtÁˆÆ`p _Èg±dS €'nyT†mÔ„*I&óMMØPZ­ávj~ñÅÛgI¤ŽÑ‘qú°&:. ñÀ`Äã±74Úyj™t0Á5@ÿ¶5àø~³% âf0XÃ";îí j}a4!Ω‡ízØP«I*Áþþ,쯓݉v{ÛìÊ{+.ºŒ§þ¾Á(Þ ïÚ(³q5bnÞHćGæ0IBsMâ®Ô…òª;âFÑO+5·˜Q›7oåYºÑ«{̓”á]‚v¯bgåP$®P¿BíË{I_ÏSHq¤_Jå,-¿rt4¯ÌS\Ÿª‡s½xÓuršy–¬š:dø”lšƒ]X7¤Ëk?èjEâ-aX IÌ»BYxeñ{Å0op—úY&Èu5—¸¥¦pÛtQK¡œðõרÄ)ÇD÷UÉ™rÔñôL‰ºuÔ=P÷@Ýoð—>•Ê$) Ä¡¦ÝPÈAzÀÔà@a áãÀ ÚVoªÕ-ý^{¦¶ ® æT lÌ^ÀEÌ­'€¯Õ\…‘„¿¡0J‚vb´UªT‹æ(µ‚ÝRmj Î,¦b)Ÿ°Ú$b4_¥”Íd7ðTK¨ynKÃÒÅ¡Dbn,)dqCc+[äÙì„,•6oÞ¸jÕÀ¢EØìñ{R™ŒÓ‘ìH K*ì¤úg‘­c˜8\ÊéWŒ'׉ ßÚÖܹ°%»u„+¤ÎnßÖùm-è7D €ßX„»E ! Šb<ž÷x$Œ4[1·¬ïãÒ@_‚Ú ÍÛ@œ4/yK²jàÕÞ.§ó£C£4ˆ'û†ûÄ“ðß•òÀH$Ï„|¢X˜?«å‡z­¢P75†ׯohmµ–LcÑ(¾²ÛýéL|ŸL$™,&bZ¶ Š”TïCáæÔY%å£:;¡£Ùáê”è%L×ã¨ñ7×Å|õ¢§É8*)3Ÿzá'w2°4w9×Ë?Êè î¡ËÈ#†T°ÜŒÞC̘ýLS†ñçœË|¨‹²ŒÔ6ëωoÚΗÞìóñô+òW·ßvÊÉÿö\B¸Ïo½Ùý®·_÷@ÝuÔ=P÷À?êXL¸L(HŽ?íÂL—d/™ §˜i &á…n ohq¨aWç+h„¡yCp L0^ÊdMÐÞ8•Ì…ð¯ a #(ø  ` ûy„¤Ù ô`vI‚››(–λ¹cÊ]¿‡DƒˆXáB…¶yÂÔ‹§¸l<£ÞúSfñâEÏ£÷Üóøé§wÀòPW“Q…ÌvR„x3Ŭî&ŽÔLj¼%"_q‡Boª{ðÆdlAMË®»Ã@GºãY÷zàx¨Yj梤ÃÉ»Pk\¶!vïØ±uëp8,ûùÆKv"FT5"ãš±û$oÎüŽ&p-¸œŽ“<•Ïõa Ä€…ރ͜n¢²„ƒ^v%FP‡£®FLýä±Lb‰RË–Épé° Ü/• ²!: å¹H±Tξ©m®dsÄ¥ÔO<În"=7/YB¨YlÄWD†æ³²TÈçDþ[’%KáÐáVP½S 3jݺuàX¹aÕ{MÀ*ZBS›•ÜZÏVOªL„4Mk:Èu=O$_EñâŠc¦9>§.ê1âqJ) B up‘O®ëƒ[SÈXߥE ä.õpŽ…ÔF1’‹úÊÔd  (|„ª8t£Ô©¾&â{ðˆ¨G¤SòZFÏ– ©Ë¬¡˜,ªâI.R‰^‘joÌœÏñô4y÷ù­™ãº%uÔ=P÷@Ýu¼6üÁD< s $Ù¨œn„ #’l:Tï©A‚ Ù„Ÿ†uÓÍ€!À”ÐïÄA Üdpâ4ˆ6â{Pm­\)±9¯Dô^B» æ5>CA¿Ü•ç³å¢ %P ˆ¤˜/ÙM;l¡ŽMF—s’cÃA€”!zŸ;'ÈZI´Cì‘‚èYá/Mµ¤ËN$¶1ªâŠßå8åä÷¬}>0Ðßã ÅphÈfÉ•MÕ‚i,‘GV¡š257…ÛÛÛy TEs,øœDà#«ì„B†Ž?ßMìgÅÜWûû{GF†v,t¾ØŽnÚÊÎBÀ4vå3FÀge‹æz‘˜Ìje¯¥sÇŽˆÇ¯Rë™fGŒ6Þ à%ôm)?wN»?@o %ªÔƒÈ.Yt^¼hþ'F;:æzœÖÖ–p9K12Ÿ®Œü,&n ´+²Štj¼V– Ønƒ<ˆ¡´ÎØ»àv ÿʤñ^P…2ÄJ""™Þ1é€Èdcpဥfã"gIp“ÉX«¢c®ØV8”28`ႎvŒG"±lÙ²æ–17|aɲXªZð¸ÖäЋp8€ ¥é…/œç–Ó%S¶Jü8=dÑqò#ŽÑ}¸ù–‘Y76…y <ð@že±±fõzFÿ¦lS5àAœ‘1DP”?%3‚Î1•’ÂnÃW$¢]£ržåSi‡ž«¦û‚ÕSœÈ`©C_ÑUÑÊÔA+Tº<ç¦~ä 'úœb”ᮬ/ÕÊŠ»œ€‘š¹E[úA3ç¢Pa÷­’ˆØ\)¶9—îOðèT0qhƒ§lxùÆÌ8«ãé™1u+ê¨{ îºÞ:`c›ˆ­V P€»UïÐ’.4 ÐøCXXz&˜@i¦Ed­läŒpÎŽ¼’‰|uJ®* ÀÓpœÖJ9ŸË¢V9\L€šÄ ƒº¬‚BŠ`á8dÛŸ¹µ Bp’ÊÊP¡Õq˜ÉˆnGÐý†E½ɶ¸u¦0Öjª¹eTÚÄí#8‡¥V 56çr¤P· ÉcW1Ƴ¥þ‘ñšÕ‘Ì“‚€[Œ¦#ѬÝjì;«oHöG9d-! èÆDŒ¹³–.]’©8ûÑ7»<ëÖ-ëšé+2ÝÛ‡ÎÊŠÃ;A“b°MbÀ™k¹J1JH¸Î\²:{^cSs˜$Ù\ª¡1Øæ"™°:ì¨8âQ‘R;C ¯Jdktm-¹LšØɘKwÎ‡è  Ðð8iß!‚«¡‘¸‘(gsÅL® Æ¦–Íæ éK!—O SÁŒ²Ì¾Üã,¥-nO`îÜßÚ=åuUv78;“«…ƒlÞ3½aӺё‘p“cÑ¢–yí y& `Ëèœ6ßìV/‹´Î¹M˜N¼>‰Ù%¡ €²,Ü<’Mš6š6©Ø¤Çd„‹…4£i­ª,ƒ²ÁÑλ «5•Ê’É^5´±]¯>â©€[eöé)¡¤8jÑE=jÆ ÞåZ{4A' žÖ@|rn‹1œ«!žÐRS¿T®…±¥Õš%@‡@gÎaÙ¹Ž¥üH¼®‹“Õ¡ ÐfËSêÐ@\7Ͳ‡6Œl¶~dæ|ÖñôÌ‹º%uÔ=P÷@Ýo ð'¸EA+“zJ#ö(£ º:>á: ô(¬L7¨—äp~&Cp0ÛÐ4:÷H%𶉿æü(á÷ÔÁu@‹Â$RgUY¥Ë rrœ¶ø³©+‰ïóZÊÀv 6ˆae¼0á©L^’#FÇE>îuû¨†8RC…:í²Q’ÜäÒ¬ŽK­Xj1Ìbñ»}< U >öt/GLV/Ôì`oè ú–†ÐýGy t*X“€l²² VïïˆÅrè@@_ÁçÁ ¿jÕªb…8ÖÁóvw÷:Åá0óƒË•Ëe¥/zDøÄo‰Ø8 Sq*6|®Ab /·ØPÉKm6“OÑ”’í¥\áé-Zom Á©3D>ÑŠs†ƒÉ»BúȰ¯^ƒ.ºË“ÒX™Q³Z½º_+W®ÜÖéìl8øàƒæÍ›²{©Šˆÿ­ç‰D`l•H&³gçð|"žÁ€TRb’ŒÈvG9dÔ˜^‚5©Øêöøetòdê1\ÚÈ–BI ` e±¤TþjŒT„ Q²Œ>CCmO«é'‡ÆÁœ0âz.é  Ú( 1·žfÚ~}γÚÛTNJóTY¯LôöD–wÂs æAÜÈKŠÜE_Ñô¶;F*Å”…¢)Q»1ÅNmØÌù¬ãé™3uKê¨{ îºÞéÂÖ©ÔPìv'(–ªêO€ …$XÁ/@!DcT«ÂšôV£Nêq;º°¦³‰'¡äÖ‚)œ¡]6‰Å‹RÜÚàå9Ÿ€ !Í öz®óåYR@_T*& SNÿºR €)/*›ƒ¬•¼èU6B³InQ*{íÀcÁÞ å<‰ QD¸¢¹L÷޾¡¤h|Ëéj"Cýl˃2´;o¸cþÂr1ѵ±‡T“‡{Áì0ø8Í%G³¯Ý^ùvûÜMq»lÐdQú …]ó;æ‚nâ~°Ý” t,Pdò²§Ónv|#_)R¿Ãj¸XAÃ¥B||,ÚØ,ÎBºì¶…|þ…¨Džj}_WÄ2–/ÛË;©Ê’Ìåy#@È`'縋ëÉäºÂVBƒ×ªÁR©YeÃ,ö“‘&P™#3éçÙ<«Èù¬ ]%¸`^0"¡š7¹Å²Ø"ö9óR  ù?vj¬ÌC\aBP@°­Ò@óƒ¼JP,µx›´2„I„Cª$SLæ=5HÛ¼D|¬ÄTl ˆ<®jVÁÓeW£Ô©ð4ÙÅ9¡à>›Å Ù§ku:Ü|jÃ(Fy¬å“ÖôÚ€G¨3XK(œ=³Ž:žžYãQ·¦îºê¨{`æ{lÂãu>Ö傆#½ŠðÄJÝ!‡À!á4®[*…Àëšd9™¸>A³íTXA úYjPºVè^;HŽ TAü]u}¢ ŸQ›Šrc‚áhM!mƒ m(~Z™'W1Ù“&`=9½J©Ø8ˆ-èõ!qVóUI‰‡aÄôp¤ËàÑX¢ áG¬²¯‘v@–FMDºØ >®ø%2 ý›+J5¡r@Æ"‰îîîçÖv÷õEÌnÜs,™Ý²e°s~€àÖ@¸£#c«W¯¦ßôøØÕÕe·»Øé8þümÛºY ª…Ø@—±¡¥¥IøãÖÖƒ:3žyæýÅè{§åå¹ÉØÕ2å&ç›T8©¡6áé•ÞC×À°ÊT‚'Œ—zØ)À›ÅOSF?Ë Uɉp×Ú*>¹DµêÖ :êxz FÝ”ºê¨{ î·„rY6É Ú oC‚j²ÿ Íúï½þœ¾D9 жCè!!Æ€·`2•zšCmdÔ°P¤€ˆà—D½àDþÕ*erÀ îBÒŒ„DÆMDa€Œb•x•„¸ÃJ°ø(Š-¤õ]#L;s!»=ˆpc`(e˜Óèàb¡ýÊ%ËØX,›Hà]o!GäáA ¬ÏfÓ5šÎò¥ª«ÈÆ[&Ÿ„@®Öì9ÜŠu¿Fÿ* ¬2‡¼Bò:ìŠCŠ`xmÂË&ä.1òù, @F£c==ÑTÂhi-ƒÿx:‘È{½5tn—tt¬µ¥íз¯(äã¡€g,nE¿‘HŒÇbyøx×±}{W¡óšE›Qqä³…X4×µ¹»½­¡¥a.Ô. “aû¸oQC£¿<êÉñ"8°¥©0gŽÇjx¬5‘ÝÊÅÚèØpÓf-£»hnvƒ€G†ÒÄÜ[¼ŽÉ'‘8­U;émOO.iÄÆ“¡`Ǭöà මCpúÏ>µáÅç¶æ³Æ²¥ïX~ÐÁ@S¹9èMcƒpÉ21 RÛ”Oâi¤ŒÆÊzfjͳúD˜z–}]W2uåשG±Ûº-™µå»£”*,W˜tZÎÍ#Ú$NÄHµà¡CÌe}Ez2cŽ:žž1CQ7¤îºê¨{à-âþœ > Šo§­°YO~c¾S_¸nz 6©—Ú%: ¡ÎðªX{àÞŠ×.¬¡¼¯’IQP5ª)ÜÀ89$±Q–½_ k@ââirœ§h… ׂG«‚WDã¡ð´Æ.|‚g¹›O“ݺ«PʓΘÃuÀú‡¹ŒÆyÛ¶m¹dš{ä‹fµŽD i‡ã%h¢oc­9‘“ð}¡6@‘NtÇl†0Ær@¦Ö 8…O`ƒÁï–­1Sÿ韎IƆ)‰Z˜zpgc3‰QZÀXÕJÎëU¢«5NplrÓX,¸ÖKRÇHL°éüŽ6·{‚×äq7‰k`Á·wE)°+fwÛ¶ììÙ…t’|ãU‡ý¾tZÀ4Å!¿ÙC™K#º@¸"¯ž{aðå-8a``œâ þpX€ [EÕ]¨Ò›#šG‡2>n4ø%1;›¥] °›=ˆ?þ8’–Y³Û;;;é2ãH%ÜbÓ(îBìÀXh2ÀÀ‘³ÒùÀöB¥'ƇðÈX‡¸’Ë©»5Ù?ŠÒ‡ªrù*ãÈ1 ù¢D}I&Ò|öEHÅbÌ ÓgðžVPP¡–bS™ÆÓ.7¢ý:EmyœÜM¨g ?ÊŒUü7ƒˆ1^¬Tå¹Ë-®S?×)3Êuy ‡>‚†Ò2ÿé1•ƒÕ©’˜GØqj`š‰Èå>'Dòù¨:êû$_>µÙêÊL9,~¿o¦ØR·£îºê¨{ î™í¹û„kžý_ÞW»Ü¶@0à”Í^Bqð·âˆÌOÄàr°¯NBžC"YÂ0 6Qè€ 5¨.@Ôh›  ­XrÔˆIÜ51æl5²!†Cä^‘wã`¨LM›Ð{ {&ª ŽJÙT©Ùm¤ìv£@¡ö. d"›¢D^SúZÃT²•ÍÎ Jë¦Öp&•{öÙá—-XòªõoS8ܞϛH¦¾òÙ5%‹5šÊYÝÍݽck7õ?÷üÆ5›³y#S´ÆãåL¶È–¿ÑÈ„}¸!èpºŠ¯T,iv|.·Åæ’dÙ"iC´{ÆŠH{‡Æ‹‘hš0nÃC#n³qÔa‡:Ëuм–Ãèhõ˜2ãCöŠá÷d½öb º;Sµ”3[Écu&"#È×>¿ªks_,’ zÂæŠÍc÷Ý éhö„ùx{Ül¼0Ò3ê2¹‚Nb4VHV8ÍÁT´NÌÆÝ2a¡íì®DœÍá{k*] É ÛÍ©MF2_ÄŠ5«'löøgØ|jØ«&ê6€Œ!‚¯ÂsÄÐ fF 4sRÿN Wø?®hr11´ëK/m…× …ø‘m‚Ä© e5qš3ùÄj±f? ¡ƒHÆrXe„4û»û!GAMÛ4Ê!ˆ]µ‹XËÒ’ÐâÜÁÆãYÚZ»~;­·Ïžè9›JnܸÑÒ"4gËìöŋ۽^Ô V·Öj÷mß¾}°?FOÙ,86f”Š±ÆÆsVx}hò±±š–Ã?<þä'?!‚5Ì+¤/|g>Wa÷$ 7 ‚D*#0I„i§ÚÉF…d= ø…IU9_Èø-ä7nd¹Âþ@êÉ*]M©d×4-cÁ.IéQM:ÈÞÁh4U«¸ÑgÓë‘‘ÒG?²n56ž€#ÿ ðÕc³‰c}Àû/À$ ÉÑ×Ñ]ÄŽÉCfLõDbÖÅ´?{ÆšŸb¿Šd'ÊÕEŽIšV|Ž:…^q¹r‡ð¿×BÉ3Í0 ™¬´„ÿyJ«)Ï«C®;½¢w/©D-Äar2i ðÍ YŒ1'wÊc3ÔþBÉl(d¶ªS2 1ÄüXÓ{m'Ó´ÁKõ©´%lQ…êVFhII$yœ‹òjG}ˆaByr%Iµ%‰uÕ+v—Èâi”©+åfÒQÇÓ3i4ê¶Ô=P÷@Ýu¼<z˜ñ8À!ÁŠÄG“ˆÔàeD°‚ÔŽ.€W4<´¡ŽIÔ-;'ªÕktÒÍÜ …Ój­*P›+ sL`)À0 lÁës*1™UÜ1³E 9Žp$ȲТ¤(D¥L->›ü‚,¬ ÐÌıæy?ÁÚ+DãK$\Ù´ÔK8ðm <{6y…¢â‚7Šñ IDATó/—fp˜[²J”™Æ;¬6‹7ÙÈ(À½¬S‰áå¼h&tùëú»È¬ËähE¶HÍDQaBäŸÕY[$9³QxLEÚ/ëþ’€†X8òîÄl—w)µb7!ë<@ !)ÉÉÉa­ˆüŸX‰3ì˜qÍ0ÿÔÍ©{ îºê¨{àï=àõJ¾=p†0g-M–/‚u*ÄzV Ô)< TV8IJRV`± øl¥l–Cn¨÷ã*ó\Å U‰ö—&ÆmK¸U­Q†Ä¤~­Xåu½p{E…›­Bpê ùTN(LµÅkBçª9MHD^å‹ m9´}0Êó8•¢(UT¹(¥a7k(ÁµÑ¨‹Ö)IJ>‹%!?ÕÆ6 ÔÀƒ8‡&ÊTed¾$‘ü|lUÄr².ÂjKÐhŽPM69Q[]‚ö€K<žýÿØ{8ÍÒ²ÌûÍ9UÎÝÃäÄ0d`TĈ]P×ʪ»Ô]Aø>WE¢aa‘à0ƒ“S÷tšîê®üæœ÷ÝOuMOèžù9LoñóËwN÷9O¸ÏÓÔõ\çz®»Ýƒ_)žÝ²å|‹Žë¯¢~ºªâÛÕüÒw쟀Cõ-h×`4‹hg^Mý´íà¼f$L0å³ÖÆ ƒT9Úu‡¿D ^±màCàþ[_ŠÐ ´= ä^òÖxû Ôäø(ßözv¡QC‡MdX”J+ŸøÄ'}\02;+[v{R É )¹Låä§ó„ËV8ZêNy4ØŠ‘íiÅ´pëÍ({;Á)©²ƒk±´V‰žµ#½ýZÑ‘žƒ·Œ7Žñ9Õ`™Fo+e9 ’*œ’dcT(|iÊ“(Fü}Ì|ö|=>˜gŒšÛ9ï·µ"2£<ò³Øû–ý_ÇÓÕzƒ~*a:zz-÷p±]ìheBÚfĨ)è u6Ù4)6š*.º—5´Hϰoµº½®ö„Âz(ŸÚèœÖ±ìððô{ ^w¼xð"àE`ÃG`$›9ÑÍ.à¡Ç¶6‰,ÀC»wè‚#\Fñ) èµܰ†Ÿí¿Z1ãðìX#H-®(Fõ!ÿxÌÃÀÆ °CP[èÊËióŸIåMz<1Ù¨5˜@0uÉ~äƒN[ïÛÉ؉`+P›Åº] ÕÀH"5¿¼Œ¥v}>€ÝA¨\ož«ô:¾r±4:½u×®]™IyH¯ÖÛô3OTÙå–oݺ÷Pc2òÎâ±T*ujÂj)º¢’aT[Û·LOnšeëÞh*ŠôÆ&“ÓÙP»\ºº‡Î¥ßé/-­°[±7Œ,/ßY*¶Íݹݨ±]²Hq ™˜ÏVçæ„NãÉ”Ä3©ô˜V‘h Ü ÇÂȘüõ®v3$)Ü&¾õ{·ÖÕR¡ˆdPÎÄp÷—"¶Q²s#PÉnŒqO=r?Ð¥åJ=o “عgŒ§Ó»íæÑ‘Ñ+žu%!û؇?öoß}`ëÖ«‘³Î: „г" 9Ž–YL…‰e³a Õ0«-­l¿¦’T"öÓG|v+ŸôÚálÃ…ë=E$’pÈ[“ ÎV¦ä0º~KiÌQõ«bØàp—@TÂ<à¸/—fè•«œÙk ¤mFP÷„tCÀ€…°9Û²Ú:ýn•´½_‰†•·’ësEÈYX{ÄM`VkõV›u $FÝjʲZŠN±4!ðÏ…ÃÖŠÄ‚S¢L»Ã´þ “ ƒÇÉÈ£ôŠ„È[ɬ°ÜÇâfm°*Ù‡‡§7ÆsðzáEÀ‹€/?8$LÊ'”4ݸ1ÒNXÉ ¦ºñ«ÓTƒp Ii´€;m® I‹„ÓÆAác½l—RVPFèPV݈—/„O¾i¡ˆ¸pš%Q^½¡Ëžˆ5šûÒº±ÖCËüâô¸ oÌ”Aä€4ÍÔ îA ŒgwÑâá‡â³Ñ¬Ú5ßý̓ã(•'·æ¯ÔVa‘qÆ@i á.f‘¬×f^Ðç &$`äJ2!—~hfÒ¡øXÖ!98xp6™¾ù–!h‘+Ûv¡@xÓ¹1$¹D›òsG”O€5:ê[,¨:’È@ƒB«K]0¡ÎÀ¦4~u<«o9 ü‘E¸ÚïCŽQ4Jñû¸WȯN=XY£ÜFŸÍc´u¡3ŒØatÈ(Éè¸NR?J{î,!ÜKƒK.¹õö'?ùɯ|å_FGñ0g}Â`Õ®ꤶ ><±³kcKGï˜f5wBÒüä‰ÚžtدöÃæÆÚ7–£^–Öm®óI§WF[!ÌjžgM:×HL¬-y†ÃÞ$ÔëÊpɪÌÕF²ùP››B°Ûv£êaÙà®»žPƒ¶r„Ö^ÐÏ éìInIzÝM7Œé7Bœ¡™fšÆÀâŽç†À热+ Ï5ŸîÑ`$¬˜S }sÿî˜MÌ Ú:<<½†×/^¼xøˆø 1.X?ù Û_Æ×4pF„(–Üð&Þ·–oã“ÃÓwùáOGƒ¤1’æå¼èÚ!©#ÎÂÜÂb®˜ÃLvÎ;ý˜G‰çÊFŽˆ°žÉ¬!£]< Ä[¦¥Ž{d  M#ùB}~~Él0«Ö»åj{9¿B{µV'…ÅÆÀ?µyêÜsbû÷ÁÙ¡R.ø@ž.ÈÎÊ!¥|a8l‚zÓÉ4¬:r•®/Ti‚”:¹(ÙRÒP›hÃÁ(ÿ×c³_½í\ì6~¤è$rþ®T:µmïj¡º´´Ú~hUˆ<•i4ÛË«+£ãh3öp½‹Ó2ae¦Œ«ëÕR¹>³MGW=ª"†ÑX‚’þ`?tÚ¢U.Ðm)|‘#sËó‹Åa?(ž˜P¢Þ z­j«Ž'ž‰ lúüHØ!ˆx·Ýéç £ü¸»ƒØœ)uðý«,Š¢`ôLæ–½é3Ÿú4ðsóôÌÎm3¬=¦§&ÙÓˆ¡ Áéƒ@X\oÔ0¢{o¡—6е[»ýTÝŽr1òXù–ydû<Ñr ñ¡¹c„ƒ˜ª›¨‹%¬†Ì–.Ÿ…JÄý̹e\çýƒ¾ñ1û U˜»°¡ëáÎAÕrôhø4è\}Wo„§›Ý.Œ(ÆCC‚‰9‰x|¿¯°9/bß?ŒàæMCшù_gZ­H«i·f×UršN›•L½ËC€ŸÆ[—©Mä(ú(Dˆ—_ˆßbªØ¾R¨íhG6Ôááé õ8¼Îxð"àEÀ‹À@€DàHÀ®P„[OÐÄŒCGFZ^Q¸¶1ѱžº(›<1…ï}} 9™JD;ÍtØc¬MÔj‚Gòº\-¡E…4í7ô~<ÍÃ?†iÈÔloüÝ¡ûU¹Þ³CûQ¾Ù$—J’ÜÕ°†0ã¶qûí·£²È—JSSãзð¸ì½Wϲ‚»0o4šŠIÑ`ìì&ô'’izØí5‰©_ààO&æ)†Ísq>Dþ^€4ã“lgR½Û۞͆X~LNMÏnÞºoßq†‹#x©T‡¡½ã{w!¿ÆŒoûÖMÏ{Þóf¦'H`‰Õúy9®ôH€B‡C¨‚yLfAŽ¡ˆäý„ °æŒˆi )DW’NG¹¸¹—'Á-…RÄãsâÉâíÑ%ùL‹¼•,f´²ÕhRRL¦òK ÿ`"”‰‡‰¨jdàªm¢µvG{+3ñ-6ê­R©† ÷FááC~\®Cx¬]DËìsdÂIPã46yf0bïc¾ÌÊàzæ~,ìY~PÛl)ÚÛ ¹–}‘pîº3lÑ6<²À@ˆ]¯÷&'rFd¥)•|ù*ûA›õ&kúÐ6Šj½«Á5E/_ô¥ÖÒªUÄ;àìðò¹l°âuÇ‹€/^6p\>—ãî Ñhxȶg)ë„8` ¯Àôš–c±3x!X ŽÍIJù0%´½fô ÔÄèBÙ “z±†É|Æ$ù±ÝLPY@ExEžÿ’ÀE_‹9E,*ÞWP͹Ys\ § ÃGë t Â^‘$ t±ÒÚ¿®Zor0}à^’ÔÐË#GiG`¯ – ú;H;ØGO<·T@©\¬¶^¨)ïz7 Áಘ€-Vñ¶C ‚Ȧ‘ëlLkxEºQ®TAŠmË )ÿ4·æO希K4<åj±D»ó Ë À+®ºŠ¶7Ñ>ztŽšq‰é6:k*aÊÀlr/R†"£°®©ÛýAzƒÏø²¥ëÊ!¢„ Ñζm['ÆäÖ×pjó(ð~Èv;zEרT&¬ð"dŒdp¿ôÒKYÔÑ‘©ãÇçJeTH)|ÑˆÌæ&&R—=óbÊà”G{ \{Ö'(oЬ5O»¥¾ÑÁi{« ô?jνk×¹BØz+E 7¨6„ê¦i¶sÍfelùÆ |µ›ƒž{b¯0`ýJI†§ì M³Š(Ë(ÎÛ‚©äàTm‹ Ñl+=´Þk™Ï©ÇM8W›ª2šœOZ°1ÚÔ\û\›ÿîÑ0÷Öƒ©Sõ°|o¶-¼¸ŠÂáVÎŽäÕCe­ÇJÛ´ã š_[ÛX¬v: ^uåU^>{¶ÞáEÀ‹€/^~0#Ï€ QjH=-~‘¿ø‚LÊ0ÇÎ6§Ù6¼ÁA û±wöjD¤»`åMf ç»hH¹EÐÉÒº¹Ìn½I™/8Wvl)n àœG¹Ð$Ç8>Mé@ ²Á+£¨IœÉá"Ýì7A¡äèKgGǧ¶„¢V›ýp»_©µh¥Œty©Ù®ûÆFqª^Et‘Lø¶oOtûÕ;ï^.ç2ñpÐÖÇVëµN¹X†Wã–k:H&"Rµ»9”Ú¼uÉxØ9×C]_³Ã¾Ív‚€¢Pòœwüå|+•FE¾Ò(àA× Ô;~,¤§b#c›²ÁRéÐÜâÜ}{+ ÏËDêrîÓì6.ìeëaBÙrkíÁðuÔ%ð)q¦¼;hõÛN &‹ ¯¨€±;â³×ÃQz8=¾•õ@~q±Ój“ÞB}ç¹{¦'§:xˆw£ÛGGbµj+•ôwë<ßĸïâ v=ëYlÛ6…Gj‹h\y³}¤´áN¦Üòf“Ю€£‘kJL„׋,W#~¨—®ûq$罃eÿ1EÍð¦xk½Ëæí×^@,[¤¯h¿¬6_ÚŠNò}¹§ éGÜÏÄ‹²rhÔ;Åb3_â"š"O%%m5¨{˜Q’¡ÀƒËh„Lö´!ù7ñµ‡fÏÁLæ>hh¶›a‰º£z\M†öù*ìï1µÉ;DòO&¼?¤ñº()è#‘>–…Ñ`2ŒøZåPc~E‹áò‰œŸúWB…hQLCubk=Ø0‡§÷Ø0Âëˆ/^¼ü€DjÍ€œ Ê®ãÐ¥†§…•¹â@'ˆJøtìKGaJÂr¢eFõq _¥$¿ NRÑ»zù0„à PHr éjlëêÒQqØ1e×#Á´Ù# GíŸ}ÎYœ×$F»rJ¥JðÄÓ£Ò³ç‘zøUNv¤™Ôdi©T«Ð´oËfßæÍ¼Ûã²§NNÏÕή]pjòæ›ïJË@:DZ'¯hÞãÃvd“Ô¶XY¡E(mà´ÓòKyꢊ_0×B@ú/“ ÛÆðßàiÂË\§i©S|#GŽ;–ÇÜc$×£æ‹/»•6 –PÚý®/•6€àP³|#LµL[ ¾6“¶á ¤+°ÒÚ!Øš‡D%­¦ò;r¯^`4²œ ÁxX Äãz]{éP:oZ‡ ÇØä¡¹Žx«+ µú0™]táy×]wݹçžKë­f‹çÁBžÙãõèÍ„ÈùšM†Ù# ðºXh¿©LcôX宂cs¹èž;÷j.Øå" hb(`®Ù¨xJEO¶3ǰUŸÒRn¬-äÜ<¤ âæ¢Ç¤õµÕC¢¢¸9”̺gþÐê¼[jV«Wíú‰kB=oi‰¢‰6±ùteT•ôúRÚ$bÒ,±: ]NÜÐ(F´‰g(JNŸ¦/Üâ@…iAr$‘ÒööÇÆ¡ í×F;<<½Ñžˆ×/^¼xØèH™¾ÓÉRÍ$ØÔ (5þÖž†¸FÓ`0FŸa±k€•´cMî°¶/M)ZÜiXn (b°¶÷ㆩ BM*¯¼sÃL{ ¤BÉíNƒ¾Ñe ¤Õªrk7Ë¥ºØßœz¾sì›Ä3}fÊj½‡"šø²iÒ‡=óÌdŠ’éØpöòKW*÷ÃK.>燞sÅ­÷ÌÝy×Ñ~¹xøð²üç@\z‡Â-x8¨C¼j€‘¹¸èÔJåfs&CÏ»u¡‚B>òjãßÐßo¼›}©Ñ•÷ì¯Ý´܉À˜O$hºa:fÈjꉌ¨QöLÂ7Va¬# n`oøQøšsŸèLP`£ã[X.Ñ¥p4CIg8oõ|[®ËÁzfË,*êÑlŽ‘¶äðÁW*ÝhD9S ¹ED=»ÛÃ`LF\¡ÛŒzjÓTw¿é“i/óÉ„ÅvÜ¿SÇîƒ.Î/Ñófƒ¸IŽáøb÷ ‚ h8ªžéƒqÿÔ§>uäÈ2,5‰ gg}ˆ¥ÑLcA-®½\dzÐ4OÁÈ¡9à¨Ó`h¯)‡qÌ'ôÓ6¤ÈÐE‡†mþ(V\sÓ‰óõªˆ9cä:xš~âœÍ•°åiwíR’w¨jqáZY±Ú¾RÑ>Ú0ª"2Î k‹êÍŠCÇz`Öl)h|ºMdÃÓ|ªf9â"øc½QWØMZ&0C#?#I½q!rûÈÕB+ÚÊ;"¾§Ÿd’gb²Vâ™ÛVQŸÔ-'\#-\èððôz^W¼xð"àEà"8¯ƒ@ @LÈú¨œ~š?û\>ì}7ˆ(…ÌÚ€…`†ƒ;nC"°ÊpŒƒkÅÊp±ÏÞ,mÏ2䳋ˆxÁ†ÅðŠj%€P˜å)Ú5æ‘=png›œ5­‚`)O»À”ÑQåó›;D"ýÐÑãìë@Ô&’™¬|,$Y8£[XXM‡;”¯vzÕRqö¡Á°}÷=ÿ`šÞù¬‹.>ÿ¾ƒ«ÑX1_VrXEzâëh%€ À$„š£16À‘uhkˆ%‡‚Eì-7ÎñÀiÀÖ¡ù%äciÒR­Yæz×_,–ÉxÎ×År-To¡C ët4‰[HôÒg^^^*®æó]!^_4J¥•nî—G#öÇáT:ÎO/\ŸÝ–Iç¤i©…ÀǾ;'·l›ˆtû#™\0ŸÏ/ͯ9:†Û³i6‚Òf4MÊAðl·šˆÝÍz­ÝhÌÏ-B™òk½ZŽG#g=cëØx²?lÔ¥V» ³ƒ“±#þ:g—#2h÷ÔzùÄ[S«ÃÍôé‡> Ów”>ÒÛKšïÖl1¸y[w±N#û÷‰åûQ. k 1Í¤ÐÆ¸$S/j(¶X;-•èq€‡`¥T–e`µjÛ7U«]^¨¬Q¿<05ÿ‰f#D³ak§O‘$¢é¿¶»µÌQôè ü?¥Ùx©Kî…K?ʉ’ê`âg:öÉbÔ{ ùdë?ÚdåÞN¯ík÷ÁN&™žI%Bå ™íëý¦„Û¡¸j^.l¼c#öiãEÉë‘/^¼xx8à‘ ˆ‰Vzÿ.z¯04£°{ .o/À”(?KÔúˆ€m(Å_M‡ðyž#p¸ÔihSòheKÁi Ô"pIKÛ‰È=€#®„£bg¹ÈÑlÖí]ùnX0û^qÀ]¹æáÇuv<òÕyç‡Uóþƒ‹°¶Ë¥yÊÑõ\ê³WM¢pÔÙLbDFÄ|~ay¹c‰„;2–$†2åYAè6ØåÑ.´:$ýž[é0…GB«Û·oß±c;ý¡-Ê0vú_†Ëe³£"æ;øRÇPsàìVÇ?njj„n>|xמ]SS£‹K…$ã¤Z¼òÊ]D[nê$<µf¿kt¾`¦“¹Ùâܲ»Í:}æó­{Rk»÷Œîµ @ uÍCßâq­Uåzâv¸ë4a0]Ü?—{áà™ JÑâhv0J›ÈhUÖ×·< Ž&]DÁRýÁ¸tØ,â¨mj,‚"AuúæʰJ¤=—´“‹T3 “ÞH£ËÍš´‰;Äe?ý$Pv¡£×&¶jàÓ¥Ù>r£Å*qlLùwA­¸4‰Ùãkòiݾñ$ž^{6Þ¼xð"àEÀ‹À“ŒÚOt˰vhL!êÈé6¬*#Ø®nˆí°ˆíož`—eÆ Æ7€:xÇo.äm¶|+Øúò­l@¨ Á4eC(ÒÉõ” {½X=4­6PvàRA[Ч°¦ƒv#ÇY£Ý­Ëu×ÙC—Kf…»ˆ,Û; -(¥µO1ÌZcÕ|]|}!ïn@ÞÕ´ìùÒáýL<JfrtÐ=î/æó"§AÔl@Ìô$ÿ©ž±b§ÂÓ¡Áyï®^~wê#ïg`<ÎäWg,§¡3ÞÓ´µqâõÄ‹€/.`AÃIÎÁ@äˆ=Ës!dìp†í4” ØqmŽ9&dÁuàŸp‹ÜÆoÃ^  a žà¼«O°JS^sÔ*At`éÚíÇB£r]VÃ! ,N/†cb¯…²Ð`´õçÜå”ÁƒÚr9õôÂBž˜Œ+»víJ§'@Ÿ•»î;xðÐüâ27–«°Ñ¾f«L=­þp|¼–‰›VV } ÷pRëõ›ƒ&ÈÏç;ŽžACh 2zZtÒ[šã.ø]άbbCp'+- ÒHž"ÆSf.¢oB%÷"+rZIâÆ·tC›,ëdŠÑªĬÁF"›Ó¨¡ïºÿî]»|Ñ´ò’5~}ó¶-”9tà>L9¸‘.Õø[׋Œº¿sv„¶ô˜à;e×íƒ'ÚS™B:?_bìô0Mêu7»@)éBJÀi—O±ìuT" ^ ±“6êù»¦—à]£C2Ï€L>ÙËÇM;ÜüæºAkg>í^hpMMSF4-5·¸b(‰r-› 4gj¼28Q"ÁÌ4Ë ÏǨ^5!­…M6=›½ö4ä}b³Q\5m¹ ݧ›H|Rƒë×¹]‡[ø2ëážàª9G»DÍZ^Ê>DP˜‰o=×ðyÖäPºVˆô3œÊðPâé,ö…ôžaŽ ‡óÅ:lº¯3‡º5¸ŽSàéÔsšÏž‰|þmÓäP:ƒ_=*P¯ªüò÷$±£ó½Äû_[îø"5_óÙæÌ#+ ïÎüퟆȠôÈ»ü‡3óá™HÙ­¾áÃo¾,}Ë>›¡þ%¬ÜL¼ïç¢E·-àDC÷ßáÄ«ê/žŠ}â}¾ç} µð–ÔGÖJ%/i½øÝÍ=ˉ÷ÿt4ÿèµÈãÕôÈkg2¼§ië‰;ê•ð"àEÀ‹ÀÜðgž¿ÿ2!³]\†BQ{ÐSèàdœapwîA™¨VP—ôÏhŽ@‘x”B˜Ðñ‰<—šQñ‚ðx!Ï9u‚-Èîá*§<'†„“p`¢0fëa«Ñî¶{ "¸ñF£‰°; =Òh'á¢ÅÀH6=6š›?¾Úi/^rá’ùÊVB­ÙÈqDÃmu•Í…uÔ­n£-”ŸÉ$É1cŽ'/µN—=>"] w¡0¨5ê $ ¤®¤$„ŽÁò+ç“ÈpP˜_ûˆQé`8·¨ FóU§Ý‘ž$™&ØŒ0‡ý û-füø±%ps©’¿ïÞ½•r#Iò,Å”‘p8¶ŠÓßHnl|l’$’¸R[9SošJL¡’N$ú ±³Ýj9‘À øà;Φ’¥X{$Û›«G£¬‚×I«ƒ- Zg´ÜQ˹ƒ…E¥TìõSn+ØÅ°O\«ë?Ÿ½¾ò‡»Ãž6*f¹à10aG;l²p^·Ú |:xfÜ"Û9Vc†•)u³ˆÌ&î°É¤9ÃìsUp_y¾XÌ¡Áî„ï1Ð?ó a1¹0?é~诺ÁAÊ{ÀªÂ[WÌ=Fÿ¥#n­ýЏZ=†YV˜Ö\Rx |Ò¶ý‹0€­âª--ÒdËîWÎQeÜybŒ¦¾Ÿáãqñt²wé¯ô—þ*>_}LoÎäWi|åC™?úÐpòµÕŸ{i䣆¤Ýѹ+þW;ÐÒ?ÎW®@ó¶Ä^[Òòî‡?Õ¿è%ýÛö…¨)´«{éåCÿm.óø¿G;~hxì½ÁÐ¥MK‘›ç\©áÌ›ª?÷ þo ´6?þ}OpõL†÷4m=A/½¯½xð"ð<àà B‚GsÜáJOÃÐŽ0“©T#öfßÎÁ.àƒ.îà嵡“5Rˆ„WçàN° À¢ÚV²¸NC¹§&Fh(êR¾X~ru‘Sä4Ù  C¯RžFQ È@:Ħ:‰hƒip3S#Ü…T´ } ͼ¼Ü…ÏîôÊÔC²Ù˜žqjÁTEª“AsiŽQGÀõ2JE("AI‘$#G<&Åv*’¤°ªœ ›' ½€r—Bg„&é†@•ñµ^ÛAÛÙ(Faá-E.;Š¢}õÒÂ’ëùÉ"Ư„Ë+ùE\AH™ÍŠ¢Ûê‡;vp½Z«¢·n7KijÉNDzk =›ù1ô<}n•K´NrZÌ¥’\'b\a7'Þ KK÷ÀÇã=j t”§çÝ0õðÉEîâÆH§é>˜•_m$k ! »BÖ6´vrÈ’s¥ ûÂÄîF—ŒŒžR'Ž*.€*¯í€ _áis‘‰’j…‚NxÑõIªÜ"}íAäWÚå>7E)v„Ö&¥²uj» W´€³'¥oùÿ«DnÑÁqÍc=S›òVDxš„ƒ‡K ÊØ¢ù§Qó½úl{Rm‰Azs ‹)§ù– K ó ´»b>LibÍz’„ÀÆ“O+Gæ£áøÍóJÑOü‹³Í>ùë3ùÕ£»õtüήàÑ—t¦ÿ&t¤2œ|IgÂe):}K£Ý—}¡zÙ6+tCñ¹úOç÷ÿº?þ7Ï n¨n}åékyÜoÏdxOÓÖãöÍ»èEÀ‹€/ëàÝ5ù•™Ú®;¡ôvž¡åê3gôÑ=Ùnð.˜áŠð£±tœ¢Œ˜6J/(ØE.kA´`@Çj9°ñs‘»€¿à9½p ú]`+ ¿‘dµQ/—jI7ه蓟ž?ÚmUÕV')ž¡ œbBêH™ÁS£ÓSÙüj¹XXA?½º²Òér™d&ñd²2¤[*/˜[Ý*`ºA²87–aI2‘è ¡Ù™ Eé5X³­Üväˆi‘¶šSlx“Wƒi˜ø¨à*¾Å<:nJxSmhBuzì)„…„ÎöÃÑàh" ^Æ!GkÈTzŒè!"…ÀËt -ËäRhi5_¬”–G2‘~gдÊåJ£†lJ H¶@§™_«eãÁ\6EâöžäÝò»`Ý2³ijrâèÜ\™Ç‰P{Ñp° Ÿ Dè‚ê;Ð6Éây¿‡«§®G«ô(8 Mªr!5FK'È –¸×™G¢Þ0Þ„Å–N4?l9=Œ¡ÛpLyO8T{;O¨‡;½ïètL‰¤–qÓ¶Ú½F $Ým4ûxN·š–q=DÂJZB2¤¢Ý€eâm¨ú„埞ï¬w* ‰¬¹ÍHa¹…ƒ¡ùa?€²À:H™q1WmêöA›Š„ÍpSûðv‡õR§®ou0GÜ*ËÊ·úÊšTFž”ò& Ho“NGA?>0冂·ÑŽÇàéÀæîu?ï»ë×#…ÇhÎäWg&Nõû"ù±îE—ŽÜÝ¿ìßá/7Éúþ´G!ü¹«G¿öÜúOÞùôÿÜó?ëc•úçÛì‹/0÷Ïš#§­àT_žÉ𞦭SuÏ»îEÀ‹€/'" ¿ÿ'èF~P€I%'3‡Ñnf± «<. Rйt¥J=¨ò–ñ‡*.±Çd‘Ã錪8@x‰˜Ü-pÜ›ŠÉaš«f—£ÿÇ 7; ánW yÊTeúiUêxt dÑf>*›R3 ⦲SSS‡—!e——+ÀTà„4Zx:£šûÇûÐØ¤aá®Õj‘Fiš2´ãÛïHdÌê‚+è%\48§£Ó0ÖuÍQ’G®s8øECŠ˜ùZ8âÖUÖTÍ€'¿Òz¶mÛ–ð‡`¬e~âÀâÞf[tx˜Tê8F‡µZ¨w[¸_C`S&•E3î…’_].2 ñ£|q~ža†FSœW‹re>ÿüË Q·Û f.<½¦Ù%«z”tÒqÉɨŸ{Ý@~×Z‚A¡^ÖPˆ­»oØ”1TmÈÔ¦·ˆ†wX•+:ÜBÌ 3«ÜÔâ²ãÂI/Éa7 Trâr.:—sW3a¤KÚEhúi­a”–Z~‹î8OJF,û7~ë•*§Vn\ÇÓº`:ÃÓ:¸Q·HΡƒŠð‹ Pìp…¦5Þ¶¶Ÿ:b W Ö×g£*±¸P§«Yô?}.KïÁ¶W~å@Ÿîù˜½Õb£±ÑõÓþÁ®75GoJ~a¯ˆkaÓÎäW'5û}9?³ñ«e1ï«„ÿáEéu­óp)tǽúÉÞæXgs5|ӾŸLƒÃÑ+ýí™À½G«'SǣʜÉ𞦭GϽ[¼xð"ð.Ap‚…ŬA%šB´²·ü0Ž¡¡;PzØõ:ÞÞßs‚u±PEßð%Ü¥¨G½"7èÓ¢JjpØ­».”NBV¬Ù¨<ÏÝÑÜX»Ù[n®´ÝÐìu@œ[·†„c‘˜øñþ€ëˆ2q“(„€¼=¬ù6MŒNEÚõJ¶ß·Z‹Ì€µp‰¦V–šõÒàÕ|‘4`,¿Zï´r#`èn*êÈáf")F¬‹²ƒþQ(DÙ';5ÀªY°ƒ ÂŒ˜ÇŸ‹!'0¿i '‰­?–béÌ¢ Š ‡Xn̵‰ÄÂélª²Z}Ç’)Ú²T‚C616ÛÃZ£M’jR®Dʾ92Aâ$çIÎÍ-½Éñ©ÛwõšÊi“«W˜ŸT;8Ç5Ú絚uÖ'íF5 µ“qˆä\:Å0$Hô³LŒ5ÊËõ‰Ï*†ü QÜ €–8<›Í2{µõÎv"ÚD@$Ü…a¢’°É ‡«…AÕv=†ÊUYÏ™Ï3„Àñé*¡V¥À-³õNPëP®f‚ñÙN‹< Ä©±×·Üéí!QD¨Oaðç‚¿ ( _,9y;µ¼!‡‹4"†k-ѧôšbº¢ÞrØsƒóÖu­ Y,èùj]Èà}!ÆÍÒHl;l jÞøÛ?Q aÌMýÝ}ƒ¦Ö"Jú ÉŠ8,Õ/—eÖ$]',Àû=V~›ÆG ÕF¯Åz†,ðkoœÿ<²G‘ó:×^¼éCMÐÉÇ™üêÑm?åßO¥Ÿf:ût¸ó—ÍëvûꉯF-kÒav‡¯ü¯ðŽv¶Z->á O\àL†÷4m=qG½^¼xð"°Æ2‚"„Ö²k›‰¨IŸz°TjU‰5€–kû´$,uxY.E\ƒüøË…£±5É)W€Ô†0à­AØâó2)íD„T¦$¾jœ‡Iqbiç€à°¿ˆÆ*m_q;ôžö+â³£ÎSIð5¢±QôÐPÔx?oÙ²œ}èÈñC‡ ðˉDò•o-ß@– W*lUl„#uºÁ0©‡]yjWëlÝØþب÷ëœ x™^\Ì(U:é¸F¾5p¶Æq‚ ¦lùá¶ šå˜t49$t2•Æ}+ôáDxûÐÏåBØFZ@0_nTyàå8׆O–0!™ÅÆ$×ijÕA%|Kઓ1¹FPé$ca˜Ò^gr¾öØl´XoÂÝNžp¢Ê†NzÎ? Š»TädýäÜV +ÍG¹V£<;0y‡ çhV*\éX'»›{jwÃ'ãéHÿ‚·´;Ní›L÷ÎäWiüi½Ð¾?zßJûù›ÃŸúF Óhj]?ýÒâVü?m̽=cúéïq&Ã{š¶þ½Ý÷îó"àEÀ‹À°ÀI„à÷À  ºBüÅw 0•[©Ôº‚Ä>L¨ )Ç‹ …Áø9Ê¢"¡g¶½{EK£÷ X­R5â—‡ð€´èe2•œzØä-/.¦²™‘Ùé™ö(æ‹»wŸ!\2Àõ8K´ªõVOwjr3ufrbv«•V"›ö;d·Û³s[quiaþÈE]tÖ®m½v X–4Ûs‡¬ÖVÁ‘õfouÖ—†»Åæÿ@Ò‘P€}{è¦Ëåt¢Ó¥°  ¢Á¯Œ…s¢ÄÅÈî碛ÁÊ~[º[N@qÉXrÅ;MW›>»-u€æáwÛæïÑm “O¨0ŠÌù1L [ËfNܶµÙtf׎Åüå©éuff6-W}ÖžsQç:Ú.¼¤‚dl™‚í>xàp"ž®–KÓ3»AØ3Óä, 퉉P½\ð÷;[6ÏÐÞÊñ…6.*0ÁÝŠŽN£î+õ â Š-úcàÒhå^O9€`€µxžÐqœ[ÂÁx;Òüé¡9ï‚5ÝH3¤ô'†#Oî¶I›ãÖBºƒ¡´ÔT覢×_Ëk¨©ãv:ú¢°àèàA }(àP”(·Q{`ÇôÐÅ1š÷ R:Cm¨*b­|@‰µÁúƒxLކX³mbÞjé­HntRO£Þ#`²Í8P10ÑRÚ°6‚²æQ ƒv/–ÊT‚íø]k*[„ „r#ëÀ<›lEAý0P©×ÊÅ’ZÝót‡¾ji•ó‘LlþïÍIx:û‚æ©Èg?ó8ygò«3¤F𻿔ÙóçûFŸLÛ…ðW~=6òËÁÏÿjxæ]õmOýÓMö?’Oá8“á=M[OaÞ­^¼xø` Áß~Ûz%À'l.×5²þfáØdþá×ìè‡5p ›ÔˆP‘’à »Q…CWµtÀ"`0"jJ6 Jçêð(‚êRó+8›Â€Bœ. ›É€XªA´@[Ú„˜Î‚néˆM/,,DƒœFéH=îkÐ ¸ÀD˜Ô-ÉfC,{25É:azz;‘<ôÐþ;R<_F=–KCn'>éhŽ˜sn=íl*ØŒgQMh¨kÝs°Z &º§Ë'†Ì9–{ùŠs@Q¹6X®¸RÞÝÂ'_ñI@>²{² #‹ù\«Š¬;´hžàp÷ªcŽJ·ªx ¼ÌàÛP8Îõõ \á["Éð¸.$Ì:÷Dë*Ýã B÷(ICyèkY]\[ôŠ\‹ˆÌmb‹™F0C¯XWP-K+ÝkSbàb¦]¾åmå[}9“¸L–(@¸B u¬ãé±î³ßÜè퉽Fyäq&¿ztÛøý$'éÞ7Öý§O{“¾|X?íó­ûR¯ßÕž.é—Çh\¿ÞáäóûÝoD«›ºŒo¹çd0=Øõg•Wý´Fuß|¤î;ýÐ$æ¿¢µ«g2¼§ië´}ô¾ô"àEÀ‹€“"À^>àJåp jÙr› °€¿úx$ãÍŒW¨Æí>@±9ù¡˜aKþæ@߉ Å[LÐ$$6ã`‡ ¡1R‰b`AðNm"W5`> z{>èçóàr&‘„Í[Y\J'’‰t¢Ò®´š54㣖cØûÝa7ŽÐúÑ­! Í{û¶éB¾”Âý."³ù‘Äõ ™HVúÝ=gïŒV ] ÓÔŒd]µûÙ˜ÒGçFÑ{mù{ìIƒ‰T ia:xZ9(³ZÅÉÜoí™/ý7ì%d,Wä²ü‰Y!8¼Èr…õ‡€šá³f Hߤád„LdÕäíC+ko ÄŽgb©´u/ئŸxÖê¥x´ŸÍùV–æ=V<î %}“ÙF,kÕ»rm' MÖÚdê>™+ ‹‹«­F­Ý¬Ã«_xî¹ܳzlt>XyLŽM‘Zeô|¹$å'Zgº&© ðÚÜ÷0gÑZÈž)xR°!±„‡ŠNQôn/¯ ¨&ÚÕÇ÷ ŒMüÚúIÍÜ@%DfýàŠC®´L,ÐNÌ+¤ÍòáG¯C”“qà—l۟ɦBá@;¬ 9.É´‰’Bñ0«¯Iè¾²|bÅ"5ºx,±¥µ ®‹¨tÕÏëúª©ˆs¸™‡é6†×8FºW1Ûô›-º}f×$±É ÈFŽVˆµ‚5¾ZS[Þx¶Ñú'ÕïïuÄo³C²…cÓ­ ôņ9ü³›g6Lg¼Žxð"àEÀ‹€ kügéßâ¾oAѵê ÐØ@hXMôâ^ ãRµV㵿"Ç2¿/‘–Ô˜ÃÀ 5‹39¦‰¤4¿ÞtÒæÊ Æu.lÜ{§Ýr>èÃfܘWÎÝuг|Û;µ’TËpVqp«¥²l§¯~öÕ{÷îm4Ëð͉t¿‹TZž¡˜”*-T¤¦®ªÉÌÅb‹þƒ\µ®$á  9R§Ôn­î§Dµ1¸2¢™™™Á° žŽÆÅ,v[röD‚6[ÚIƉáH“õÖd t^+*5c)á‚#ÈÀ„ª4¡19gè + ªB#Q«5‘ 4!°æøL«ª¾XÒˆr¸àÔÝÂÛ$;š Îz¯Â]lŠd»wN@-‡4+‹e"ö‰õG›KŸc~eïËFúh¦ÇG”ãgy×]wÉ‹/¾x|T¿ùͯ?øàƒW]}õl™ž †ûîy€Øf#çœsι¦ O“–œš«+27žV Is™’k¼2xÚ(j®÷ Û»]Â+xÛy˜¨f Œo —f‰cx¾Ž½–} ·Û¾Cxdjf!£nõÓ”ïôôDÚgà-ÆácG«£ØÚNGd&”A¯Š‚ÂîéLŒ÷ɸ{‹¢ÞR•â,Ȭƒ+lhÔX +‡¥ÜÑ#V!åŽéòèÜ-ëÀ?PdÔyÔ F‡x§¡Ùe¾×ðçÜŽ”šìÝäÊ|Áþ-ØLÐb‹•IùµVSæšû¿û¹ñvHþ߇׺/^¼xx¢ !ܳTuF¬Ù«ê^76á솲"„làf*#ËŠèêvÒ_T³Fó)k‡`Š0Š*æÃaÊcÒzHDLmSLZƒ/”1 ®É0{É„rz³ÅlNg ù•ãsGŠù•-[7mžž::¿¿\ZÛðwÀ@ƒ^«Ó»3¨ `ÏVA–óÇQ±¤|»ö<¼~øðán§êFFsÙD:ÀË÷f;ào'BÑXž³†“³ìÐ ÌÏblã¶]oP„&x fS¿+űjœb ß2ø`„_ÅT ¼‰«vj7¦¤Kdƒ!½#Î{f­7ì°ˆ!>6ò¢êï | ï 1ÝìêÍ81‰7jÊf3;vÎŽlºóÎ;W—ó$saD×€ºTðw{]WY“#çŸóŒï|wßÂñc©Ä†à»vï(–òKóÇWº9“IV;ü@PQ×*"oÙLJ”—嶸æn$Z4qeêa9S4JaY|ª¨6^!1ámP·®Ë…›çKúEzÅA¨ëA£=ï€Uù¡›úˆv™Xâq òvÎÅêjÚé§VÖŽ@Þ«=<½qž…×/^¼xøÁˆøœ³ðî@tc­.Û5d208¡í‘Ä#¢”:Mô²„À½ÎßÀÞþ‹œ[¼C0Üž  ½¯Ð•íz¤ «Š3K‡¶U}_R IDATðÊ2xÓJ¥fÊåÆàqï¸c/®É”d @mm|'ðºP”a\ºJ(LZá–ÈH»ô“úÏ:ë,îÍç•wpÛ¶Mœ×Úpðµ©Í rqÝZÎUä.ŽÖ Ò'p¸±óÉx©™†(̉ L¶¬HÑ„œ4ÀVÂyÂo¬9`¹),†žždߨŸÃb£,×j cG¹ô( ×Q|bmYCœS&57÷šKœC´8p ^¬¬äK`áfYrèU§Z‡ËN®ññô‹^ô¢N÷cßþö½Í¦Ÿ¦ ¡Ë/¦f¼F,Â9Úm·Ä¶ºç¢JÐhËRÐ(Ù;õ;Þ7bã› ܶ)jP6ô”]þy*¿k4v›*nt¶ÑdswYeªÓŒõd~G1ô &W熤Éêâºç¢¤¶\E®ò|E[îÑ‹ã–-úé »ùd¤òý xWÀuzËá:iË<×OtÉ5iŸÜh¨¶Ñé†ÎÝ(x1áªÕÓ$õŒ|²u´;š\¤¤sõÖ@ðqohÆÊí¤ê7ÊéFìÓF‰×/^¼xð"ðxà:ïE™)¥60 Û¬ó^È€Iæ8¦m‚±°tÍŽÛ›dÅe%”Ó¦;û+lgTA#p€>¸†RHVj$%õ8,â°¦½” ÙÛv{˜JÄšmÜ?Âãcc@çÅE²pW–|]°ilŒìâíX‚%FU®pÝÝÄt:m“x‡˜š#}wÀ™™Þ”NÆ›õ*ïåI–Ø®kcbÈŸˆGâ¥r—úûÁ)Ç}ý’Ê<¬þwýJ¡P+ Ã…âÚö§žLg¼ðÚ³ºkL§ÎáN9| ¾ƒ2 YÆB™„Wª T<¦­rôÞ—\ˆh6´ÏÍVh‘[Hºû=b.åq¯ŠR©‘dc ÿy|¼RîÊ”¤Ùͤ*Ë͹#Ç'29Ê'âÖ yÈÛz{8NŒOŒ(ù+_ñŠÂêêÁCæÎ=÷ìF­ª·½^µJÉêö][réÌr5O¥fïÝGNÏõ¶åuGô@ÿÇ''è¼/C@ÊmOS 0úÀxÝåѲ¿Æ™ò¨¯Ûm“a@ÈZL8ç¹ùf ¾Z ˜F‚OšPð»j…¯¤‹ð¥¸ì¦>#mfç)[[y¨,(iAeQÇO—XyÉœEXÛ½|­LàA²9æ¶%C°C\ºSy¸w,”2HvÉÄ8µcOm44³« ƒÍ(žŒšúžN"ÒüÐ05-”^”vÐÜùá7õ‚÷¼¿E¹™æAÛt"߆°Oo ‡áuÅ‹€/^~ "‘)üÔh"6†8@;?]:Fvà3³fC¸ó4ÑCÎàEÎõD(˜Á!@‰ °pÃp …4Š ü Z"wyEo@Gïë;`M$¦4DÆÏniE»âf7Oã_q×Ý÷,.öñÓƒm¥jþbaG‹J¸T’ï‡s@ž"c˜²¨pû­L®å Cø•@ R?†!Ë+ZŒÇGø¬Á!âôÜ­PO¬-ÜT/v‘4,‡9ü°Ó|R‰cX›âa¿rv[ÎÂÓ]8æÉJEæßdç[ ùÔ–šR[.æVFóÊJN“ÞŵàÓs†aFóFŸ’îQòIm`e÷ø¨ÄéI(Àš×•&]ÙUұΠ{æ[4ÎpÚJµÞe£#Uq‹ú÷Ï€Þò®ƒ¾i°ævBmZPȸ®¾nŒ«v‰Ö½Ã‹€/^¼xxÂl=÷BÊ|çk߬ר!]‰é1?‚ÓüÄl_W:›˜M$Q3cÄV…}a7 LM¼Vg‹ð‡×öáhpmÊYœÃbHƒÆý0[¸ ø0uN¢D‡ƒv³QG3à•ÞêwÛ Y¸åFê}ñL š"ß_ŒMg’#™#óGëMßìöäöí[Á*Ы‡Ú<¾)—Ì‘7Jº–/–ó…PÏñCú†Ùä·ïÌ[^-ùÆ&rS#9hÞp·êï4ÇÇwÖKÍr>`84̰ãΨ—Šý^¤Qé•ÊÃv32B^'ñù9±$8M‚^Ëk„b'%3“‰¤’‘4¥b 9TÂ(Oj=@y(‰DIóZÍV½„ËtpÐ% d4 û²| ‘;’ü{Ø<«%ØÄª8ªéP¨ëóc¡VצÆ`/Œ&Jdâë´͆¿Ýð–ƒj,Ј÷Êf¡ëoÓ!²DFÓè!Të…D8¸sóÄÄHfØ«·ê•p²\k¬,-½ìòs¯¸â’…Ń÷ïÏfâ z»ŸLÅÏ¿àbÒ.æ—{áNcÐ(U ¡Xr$7Ñ›ŒDg¦6ÍŒŽ‘7ðµ0ˆV°°cöËд Ì>‹9Ÿ`a&¹Nøó/âýÝn¶]À> ¦d(úZ=fV… oгÜ6¢AÑóá¡Häx(ˆ@"l6¸|¤klµ¡s§xÐÐh•ìˆ"¸Ùˆï BHò#Ø£(Á¡¯ÉãŠD¨“˜À‚èÂøê-ðŠ,3ˆtÀ2¯8çù²¡–‡Z&tùä_ü7zj žÇÀáé :C2ðhÀå}ÙZ ðYÅ|l à­ d¶áÍ~ÅF³S¤6?4÷¿ë|;/¾Ó™ÏÆøç ÷”A|úe“_}àž'üg{ xxÚ7ù‚÷üó—ÿìå±[>óâ)òÁg^ü§ÿ½Í·ÿÓùµ$Oߣy²mf_öÁOý—è·¿p_im#íÓ×§'SsdÏÏ쳿3öÏß¶úôºB>‰çõdúë•ñ"àEÀ‹À¿'OßÛwE¿é­·$£TdÄ!VnÊç—ÉÈCÛ¶´_PÔùûŒm5ë_îäí¶ábä"Þ°¨¿èVã´ñÜLmìÜPä1òd®g°ðÈåÒi¥È†ÀƒRݹ-CIòwpàÚ§WVŽíßך™ ¶"ÿ†ƒ‡ø‚rîÈ?é5$b)‘¾}ÉÇ—±ÍÈ'Óâ,óK 0²Ø<€ØWJMX[“¹y$)ÙlKê žl %ò]Ã`âYÁ…/roÛƒIy„Œ¿6úÉ®AøÝMÓ8ÎO^nÒRX•‚J™ú‚úˆOÄ\®YxÈzÐj¶]t<1CTÎxS.1´2ž´¬‡MT ä€42ª ®€‰©3 êl7jðÙ™”ØôD4Hd°±€^)>„Ç…¹ht¶nÙµcÇŽN{p÷Ýw§RP¼(ðñ”Ï9ç,‚ßýÎÎNŸwÎÎÍ›7OŽO0®É‰qúÀR‚ú¡d™á9ÀœœëåB§“I§7¬i#±òš›ð(ÉG«@*z Èä B=` …ïÄ.»lä€Z±¼í.#­›ŽßÔþWÛá§Í…œs«t ¾¶EQÞŽŠ§+:;s©Ÿ×°¤èñ¨òq®= |;¤M¨†þXOtn´‹z4jĨtæ¼~i Ÿ»µ P ¬(¨MÕqâÜνўP£¯w®B>y:Qû·@üh‹,7ú×1±{Cái£õ9¢g½úï?ÿÞçO·ÞøwßþÒ»"뛸îÝŸ|÷ &õ%Péwí=°ß~îøò_¿ùÚÉ:‘ð®Ÿùø'¾âÛ»>þª=š=¾Äù¿ö™»×nq7îßûÀçÞt‘þúu×ý©ONxˆü»ÿýÁŸØúýÔÍÔ\n×–ö-?Öy[}…9˜¸ö¿¼é«ïøÔ¾µý¬¾§£§j‹ëÉ ís÷~ç7nù~Ûµ÷ýûììÿÈ+ŸóŠ÷= w—Oëñ„Ïëimݫ܋€/D»0|wÉhˆ±Ÿ6àöâ 0)©±ûä Ù;¥TÕÀ …80åš‹0°LÀ§á°‹v_Ægƒ0úf:ô—ü)-ì,Zm”%mѱÜtlÓÔèæYð[6öuZÕFsÀO2521¹9J´ÚC^’78o¼.–æ—Ž=^*”Íh#XGqÀ À²òžK&Žd4§@C@ÌÒòXÎ=îJuµÛ« ‡íZ­”Ï/ŠËµz½‹µ›`"ø ØNâ>Û g˦îDâûá1›'¦6Mnš¦iÆ ôDÙ¼cë–Í )GìÂ8;à9 æfY’Ia‡ìjZFÄð¨„%e#™FÉþ8'Ùp:Hd#ÉéÜÄx<“eOæ î Âín Ñ ÕÛá»2jƒäÞ“nBêm¶ê±$ â®ÂÀ}K$’€f ýáƒGˆ;ùùî»÷ö‰ñÌ7¾èª«.ž›#We7fKb¡\*Œä2¸¼5jÙÙ!¸¸ð“Ë‘s'ˆP½t.r&ÀI†éBMÌ58›2€u’‰Üõsã|ž€±íò|Ñÿ‚M™Ñʹ3“‘Ýã‰å©Ds.ß<ÑÕÂíø¯þè\bÇs_ÿ®ß{Ë/|óÎ?»³Æw݃ÿ™‹?àþÈû_üÅ_þÅí?Áð6î}ï¾×°ø£¿rUïü“ŸúÅ¿Ù÷´Ã¯'ŒusåÁùåå¹ùê)hÞĹ?ñºóüÛwß«ñ>ÍÇã¶ß~í³wDs“/¼pÓçæŽ?íùÓ<ħ\ý=¯§Ü€W/^ž(™Æ«‰-3´IKÅ»ÝW@Ž¥£(B±w€5;T± µðZD1|€åA`jšWôÓ\EÇûy‘ÃRƒÆ¨ä× ¨¡?®TŽSfrB-MÔ2>r¤1:êælôèQ6†Q'D5ÕÌ‘Mîe0»©ò.]@ Rvqq‘bŒ.•Í’Ð×,ÁRƒ°I=X,AR׺¦Á¥ hbzæ$Ný„•W¨–ž#/pÊ&‘I¿_nˆ_WŽ•lÀb‹@ÐBdúZÐ —jÅõ792RÖ”!nTë¬1xýïV#tØÈˆì5À¯@>õ”¤9Ή4%©J%“¦ÅõgA4h—![ ðàÈñNžÈb½·ÿ~£ä$›ä󒋯xÍk^ÓnÿÕwÞGst˜óyÎ9Ï £$1£§ç +ãΩËeó±“üjq;Ky7 \÷àÕ4åt†+²Ý–—3·jÝŶ繩EI¶grQ쮸g·€QܨPѰÃÍ+^èz[6É\nש“b|!~¥Kë·h ¢EŒëšv§Si»À†QÛØ¡>[ºa•¬‰ÅÝèøV] ¢KLÍ-ô›f9·ð+ßò•ÝîÞÜh¤Ñ€òMR!ßò•ʘç4®ØÔLY×Û õy‚Ÿö5 Ç[±Ùñém[B+ý±‹6oÛoÍÖñ´zMZšâûöyÖRjt&˜»ðgÞù…;`Ä÷þëGþËK¶ÅŸt‡å‡núÆM·|z:²ó¥o~QéCÿß·–O·×áŸyÉß|þ}?}ã[þéžû¾þ®—_ò¼·~ñÞû¾ñ®—mÑ® _pëË?üå¿ûÙ«_ð–ßüàþ[ÿé¯8;õè.>~[±mW='ýàg¾Ó:ç…L®?¯“ã™ýá·å[?ò“óökÍ]ó·~ôb²ï‹o½,³v ‘úÙ?ûÇ»÷ïÝë'ÿG¶­å°/ƒÙó~ú?ù½î…÷ÿÒ½ž8¹©ÇžŸü"âŽýÔŽ‡_4œ~ȧéF µçåðÿß²Ö[?ôòGó§^í wÅ‹€/ß÷$’a~Èz16–ŸÈŽeÆÆrãã##£Y2ZTkE<î`¡ùÛnå,ZαÑê°€_¡±á( p1?8@H"¾4¨e?›´º¡à CãÉ%RIDÖÍ|ñØÜñæ¬Væ‡Ã*kÃPjaµ¶ïÀÜÑã«­6Äetè‹ô¾±ÑàHn"Kf³£2š „ñïSž¹ºÕA½Þ,¢ Îç†0Í@ÿg4®0FÚÕþ=³¿påÝÁX(OÇ(éúãÄ ^"Lè`¯ñ¨& Äð®»î¢õ—½ìeÏ|æù”! n±A'Y(ÆKoé ·3.®»±ÓßCF*áWªu,qp}æFBJ»î)JÒ=G¯ÂÍ¥õqqâÆå®S¡›K\¤uî¥!÷”×ç˜{^î.·–[ŸÔæîZ¯–bîÜuu½BŠqðµQ³{@îóä2ë1§°ë W\W¾?yλ.2Ôéf—«ÁuÞݸÑ>×ÙÄNe¾à›|Æ¹ÑÆ­Ÿ¾åš+®»àœaãpþaÎvôÒßýâÝ¿ëó•nþ¯yãßïê2‘‹ßö…;ߦxT¾ý›?þš˜{<<{r¸¿ôKWž5û²¿ýÀ_øå×}úÐ18}Å_VÿÌ›ÿþ¶e€ã×>øÞ—<ï-/=÷·}§ô”âí»æ ¯ßú·ÿÞƒ'Ñô§é/0Ž~ùïûÊÑ+¢—¿ÿ=øê‘«rxix}Íâ¯Þþžßú“/íúVÿñæÚÛ/Í|øÀÊZ·-¾‹Ì>ëú±ãŸÿ·»ï*Ü1øíœ;þÏË+ÿÏrxúúß|ÿk/þîïþ§?ýÆÊ£ß÷þÕoýñgû·ßóÍoúòz!ã‹ìxÞO?«úÉ7|ìÖ…†¯ðŸ[¹þyç}âðÿ’çüØ/^pä/^ó®ÿ}¨ã‹—*í'z O&¶§òiºÙyÃkŸ]ûð¯¾ë‹ûÉŒš)Áx‡/^6XØ¥?ð8 Ù;¨=^ðo>¿ì v¦OüáÇÖñhÇ7Ô¦B?»…{LØj\µÃ1±¨~sXTg䑜w7ù»e³Ñl6L8]D0› ÷Z—4©æ ¡ l ¡áD2‹gZÍþÐ+«EñyÉL£Õ­U[h’Û-ÄlFÄ™zÐ|â¤IîCWƒ‡Ø ÆÌ:ÞÌs ‹ˆ,¸þN$œ{é$Þv.6;A]¯ ¨u|`e­É¦3m©¶2ýU ' QÙÊ~BOô…Œº5`D‰TŽsÌ(Š…*ºâd*¼kËuæKÅJq¹Þ(FG&ÆDQ¶% Øû‹8|ãñÁ€d ƒèÙ‹'‚>3á •r¥¯õŒT¸¤Sð”!i •Êy®á8,¥ [‘%„ð¼|';ašçÛe—^ ~çíßë¶ë;wn;|ðþ•¥cW^yå+_qã§?ýén«™K§âáD·ÕŽD°Þ.4£Qž €AP^¥ §)"ÈIwˆ;x"˜H‘[‘LJd8Øh3]lÑ¡OºMd0ÙȰ²ÎB¨Z«6«õzt€ØH %ßµ¥ jžJ©‘˜Àfó×%8—m×£¢m‹a™u´í%ˆªÁyí)> 1[øqè.ª²îv¦kÒÌTní9UBP'6*¨+b˜¥v²Õ´Ò~ª õéŠÎiÂÌïÍê~Ãý¨zÔ7D@¬ ›¥Ÿ~ÃwŸýÞ¿úâ¹Þ]}Ê`ëû©ŸŽd§G|Å#kjïa}åh#v^ö©ŠÕãgÿÄ/]pà¯å¶ò£y…Sýû°|äß*órc°ºÿÛJCSz<|”|ã¶ãkÝt²ÝËî8U[¡™Ë^8±ø¥ÛŽwV_ºÛ÷ÖçŸ=ú•ü‰»"ÓWýè¶MG>ô¿nY²jy”ö}忣ÚBùÐ߃’ÝŽÄè¶ñÉsßô·¿iíBóö/§Ã¾…¶/0²óâ\é¶{OåqòȺŸìo§ò©»áËÎ^¼©yÏísëŒú“mÊ+çEÀ‹€3HDåkx€Œ„H.• p¥‰¸üž\Äá Äòé/’C*k'wœÌ#LÖ9;¸Â rZWŠE€x¼æ·I3ß:|&Ù4Ûd¯†üÄ–W”•‹hú°ij+غQG¡‹Y²è ~u·°ó¨ «Ý‹Kœ­æx•o”×ÑÔæONP¾…¢ö܃2¤|Õj.ÚUp£Óß)SoÕ¸×TÏ’ða:ƒ­ÂabèÁÓô„­„DŒ]e\‰G †¬|Ñž]Q8̽åBl]ªIü¬+®`ó‹‹„.à«*tùOû»©Ó˜uÃÖÜ «P…j;ŸA<}J»¬†Âj[è 8ýQ¯¬zèsBi‹AÂåÓIâÙÙ)z˜/,1¨s^ðëÍ7ß|ñEÏÚ³gÏ÷¾{/O§F—Gã<úš^uŒÑ‡À§%Çâ,ð$}‰ÅØþÈYzЄ0öP6r\·ìåp¼JÙÍj‡+t‰±©”’(mè?u>)`ƒ0í²mL+ðò]TÌ©¦e×) :j ³{G-äTÁ‰CÓ’·àZ +_ºYò œá ZfKƒ+@xXŽ\çùFúi™Ïu£ ñ‰9O1wѪSÇè†Í@NG‘c£ÇÂÞLjt·Þ*òÞS>39“•··ÚÆù|O· sÍôž³Š_.¬Ìß“O¼ú<ßÞ¢%¬|øhîûÔ;?úÃïÓ믽å¿~}ù)#êG´õ•}Õn±ûðýòBÑ7²m,î;£ÎÿlK´æËOCìxé›~¤ù÷oþ—Ç‚œ¢'è1ïöNþ21{éyñŘ«¬] »»ÄøÄ&VmHz:ƒ^P/?|=ú±îSeµÒ»?šb‚y ÊtØç= :öd2¸.&Ñ¥—Ç_µ&¾Å }ÀQš2§¸ 2=áIÒ+‚¤0ò4µû“+üj«æ²êQnxI}´­0‹K£_Wb HNù€P ñûƒˆÛ1ó`¹ÈÍ4îXØðl"¯„ p´líüë dZÑû v¬k|ÝÚâjkß{DZZù¡{–{ýÒ¡Ç8È «÷|ôÏ?×»á7^÷¬œCöñÄÄy/Û½*ñÍ|ù!W÷©Û N_ô­ýùË.<òî³_ø›ßŠ\qýžu=6µ÷Vozׯ¿ëÀýÞŸ¿ö¢ôÃó”=iþú§l}ý›ü‚ñx<;}Á‹_ýÚëgM@Ý/º§<}ÃK/ÿ?ì€]EÙþoïm÷nMv6=@BAŠTštý”^¤¦ Ò«"" €¡òQ -$!Nz6Éfûí½üïÌî¦î’ð±ø¿ÇëáÜsæÌ¼óžÙ›gžóÌûÖ×ìrâ-·Ÿ\oÊóþgýŠdCc“( ñºÕÆÝ;ibéÒ¥Ï-¸”ÀÚVr –à¾r‰3èM&ciyÕÀW…%´‚b^[Ë-x ôyš˜ÇB6Z×›v)CÛ8Ca6=„¨„óÚWú]£ºÏ]ºžž?ýt°™F1©gýÍëÇ̸ùÒûgt“¿_^é&%Œ¬+<{ø´?=3¯ÕA/flRц'»ýæ% æ²3n<ïÖwZÃßG[¦Ú GL¼÷ár-ßÎ7Í|s™g¯ý‡oÈØ&—DøåC- eØ_î&¡Çå-d>—­*H|/ÂáXÈ×™É |È À/£ÉL{$Š“z¯hrx¹Na.UCŠ')è\næCd :a“·íÛ N"…bÑ’Må (=?"l¡zÄ/s—€µå dƒÞÌhøÇ@¨N¨y`3œÂˆeRù™I¿bEpK$ ¡"O†:ÃKÎþbî§MK ´1…\*â#jomnZFfÂ/æ†:[Ê|öáCŽlØ0°²Ìmv[ókÎ…²Nˆ@(V3Ѫaï õA’É‚ÕTÄ²í ‹‘°f*]%Ó•($$%4äR™D‘œÖ&"Ò'OÆ@æ¾´n´˜éuFã@Ú4 »-h4xã1C4bêhϯ^[³¦ƒxwN·‹SÙäèáH²TìvOV²Å£cÀÏŸ§Êï­v:ʬ¯Ñ@ʇÅä7=…œ3´Ä¢†ŽöLÓÚÈÊÆö5«:››"¡T„Q¯$„¸¡2Óc%ùvÿ£ÞÆ ulc¥Û·Ä{ôáÃ_:c£•”[rë·£ŒcÔéOܽËÃ'ŸÿFw”íÐeÏ.—<~cíÝ¿¸ü½Íø·Ã%+K(yà¿Õûs"]›÷Ñ3‚D«ŠPbÒdv»5» Y§;ð(1‰ÙÅ£YÞâKº?³9±6b8Ô#k°ÉóIÀc*¡6›EòÖú„&Ù5“]YanAê†bH(pCeRRØG"‚ŸÒYƒPžñµ-\°|öìÄ.c}н^ÝG¤pvØÁ”&XïJ‚¥ÐÅrÕ" ÒÎÚf̘ñùÜe±˜a§¡eÞöB ›äÖÜÛNFbA9Êà\CÑ ¼iÑ$Ôo[8k‹B”FµÔIÒE=8V ‘9`³×åæLJ©Mx_«¼„gœµÖ8ÝòêZÚ2Úè’®XA_è¾¢§öCSdÓjãŸwüøñ"ÃhkYÃðÎ6‰ÝVYPR™[vñ7`r% !BÌ`PyA©JQ²ÉIÎD”Y-E!™S¦0³ÔÕÖ¢2¸¼ 3pJp* íN¡8£1âá ‹w2¨®¬ä—-PC2‡©è=d hRä…6'¥qÈs ¢Ltêp(–-B޲EQ ˆ@šÔÓyáéa…Q½Ú0Mb;žæw›`,(jpU ڳؔ˜äeõ¹¬‡¹ºÂúÏšmù\ª-€_ösÛåʤ’ø§½yÍÂS—û|¬Æ4V’E154¸”ã”<Ô¬Î#CÔj”»`A³9“M‚YYƒ(o `K¬lA±sÉtÜ–„“G„¼ëàN_¹[¨Q››!‘˜1–0G¢{6Ü™ÅrfkÜénÜ d0k|U´£=¦°)T¹9φC ä¿N‡'•5’÷Žž ¼Éˆk‰+|O<¤/B˜ƒ˜YŽ ù33vÉRƒ‘Œù»[ð¦È?Î2M¦uVÎÂO3”ÖŸ¶žîOOã[hKÎýýß=ó§:C¡ã³§o¼|Ò’ÍÉÍ·¦[ÙæO?n=ôÜ¿¾{w¹9×2sÒ=—ÞñVs¿{­³5=*•-y äÿNhl¼ÐˆàV€éݸTÒj¥RF~j…oƒ6æ.@˜Í&êaÖ5«WqcsScKK+Ñï÷@OÂÛ‘~8 ]GýŠ.Oâo‚2¼(œ ¦’cu E+àFŽ«ªuu¢Õ挛ăäÛK †Ž’¦Zm`è¢]˜uà2ÕÆ ¹g±»ƒÊ€ò„[€²î<ÁM…hLþÃ%ºÓܦÞò*ð´”Ép/Ua4#­3ÃÛº£Xq¦8L… T|¦ò5À?²ÜÓb$#}§uÊ£Ÿ@!í°YñpÞ×çM9>ä| &a¡E‰¤a£„(zEÔ«ñ´–œc-RkéœàZâÅ4ååBÖïz à¢LYŠ,AaÏZh{«¹OÄå2 ¡FúÌyrSªøÓ}œ¯ô”j9ÎUT0ÁHNzý#œ^à±|L…š–Œ'²ÜžóF‹ØLsܨóVr ­ —w©4Œ¬ÑЉUŒÎS‰öᆵŸZ,ï-7¬+¤Nd5´…1tÊ%œÉUT9ìÉô-­¨ø-@r9ƒËº´:ü‡þ£•džÕ³âAqR 3ìOK_Œ’¨H‘„ªÕ]Êí@|Ns‰hŒ¡b—Yš´ÈäBŽUÄFZÐõsÌ%6& jäȺFÞÉp•?jà e6Xà¥ÍýF÷%<ýäþüÊI'2éÿ¨±ÿÃf:¦^=qøÕ›mð«u9¹ròmgN¾m³5–N–ĨR'”d1O¾DD³fœd¦Ã&ó hŠ„Ö?Z0"WvؼƒêjÁàisK„òþ@9„ C ,3I8¯Ã„ ¹”5 © Õ‚Áë­ˆD‰‹†ì †„­S&c§Cì2äÍ‘H8K^@l>e3I°…‚Eä!ÁI¤'›¼ûWK`ŠÄ§ lÊÍž¦E9 ÃYäð:íÍF'2gµ@æTíKÈDq“®Úb*dÒ-Ík Huåô»<Ð^Ì·ÄòÄ‘ËZ8rq¹Âgšy˜ð"¹ÅÐ=f·½("b1€/‰-Q­8© Ù ÅÌ6£7à&à ªRñ±.Ñ÷UÖ4TVÕcE(Büì‚ÝMˆÀb(uÄÝE‹¡¼:ˆB4ˆv8•Lg’Ð /µQRÍP¤!³QZ‡Û›9ô{k!b“I‰á ØtfôHp£@dãÃ0•Š)äd£f$tGÃ,šàv@>uÚûB€”°ÅJ‰«Ðy".zbÜ%¾R)$ùJµõõþYÃ/O⩵CM'ØOm˜$žÉça%¯ wÍt§ÂæáÒšˆ‹SYÉHmâ+E—JèiÕ«?iÎîrá„("‚G"èž ]ÛÓiÉþpSÄL—Ù¼ÔÀ%qsÖcÍ-ЧÄ>!·Ý™c6B°iÅC›% e(M(X8B[4ŠoCV©<ŠOPÐS…1LVìåó,EeîDRqy¦*6!]`ã M{ÇBñööN”B0àåUeØ€=” G„#§›ÜE–qñ$)¹,ÕJœçjÏWí†'¸‹½<RZ: ÆVüº>)ÞSL°¾‹‡‹·eq  G­倅±œ‘¡®ÞNày§uô=íCJDÆ(U 6h”[¸‘¾ªÑ!‰9y§!—ÔÐuê†ä~6(]w¿²YJJ½ýi33MíOö”l)y ä’J(y ÿz`ÐŽc1®}Í@ Á ,Üb‰l5¯ôAÍè!¢i‰{sºl¾€3_LW ÜÁêpš­NVj €EôP‚ÇaAlÌ"É0ÑÛ­‡ÕC:pbgXÀGXL ¨I°0T4Bú”(l$ÈË% Å´5mNER6£Õïòd¡lâ~$Œl! !E•ÅŽ©¬ƒX"¯……GCÇSÙöh~Ô˜ÝSKãªöHgtÉ«Z› µÃÎ#êýn{±ÀŠ1)ú„V6YæôûY‡FŒe·ßcr9RùL8 °×ËÀI(a d³,u#ü6T¥hø/ŠoèTÜ€(— Æ`ÐSU]^LÆ}e•PãEC€ÒÑP¢£ÙO·'D×6úƒDK“ùP´"hÕV{=.›!'G.7’pbU"íèÅd5¸3Eì“9šO[\E‡ÛP=0X70K´µ6/…|7e“ñp›½hª V ~‰‡“†4ü°7àgbùžpÚ©³9[=}ögÍ­ÙXÞÀãÉ\ɼ­2P,¯w¡ëÍ]Ä/!6b,U]PYÙ§Û›;mv/ê Ô.`…YÓŒþÚ\$„I$™Û­&·ÛÎB‹±ÀÞ#—¬ªòÕÖ–Y­Œ”lÂdi G:â£ÝesU䎌ÁU0»V_¶èHç‰1B.C$н„7 „¼fžÅd –W(`‹ 2É™d€}3Ì×XÀÉâD"0Z˜,Yx•"<´¨5ÇÑ%yÊJfGòÕ'˜ ‡‡Éš×|2“•˜=€NPmF%#.G ¦cP×Û¢À–l•2$ä‡Å©ækyú—UÏL®›®’’aŒKˆ^M¨r2¢$ÏlÄV‰PcðÍ[‹•WÉ,¹Ã×à¬FÌb0¬œ?»?ü^èU®ýÁ’m²Á8àGL~ôØAýJNcðÃÛ_þû)#7Ä®KÛä‡ÿî›MuGümÊc'4lÝKÓHdÆéY÷ xÛ€ý/üí³èí;&·òyõÿaÓÿ-ÜJ—wÿoí×V{Ã6ü¤§ß{æ¬ÑÛš|v«î7@9Ã> Ak³¬1¾M¶Ó 9×Ù)ä0Çš‡ƒdÕ¼)—@Ùš…Õäœæ Éõ¦Éiê¡$ur/”—ÈŠ$Öd§¾]S€4J1ö”Ç$6X^?ÍR·ë©JS™ÔÆ]œÑ²Z:Bµ”gOI·ÍPYéÇìžÚ S¹‘[(5 ÿ-"E±£‡ŽÕ­À¿c,Ç8&#C)|ƞʩ.p•¯TÅFaj !Msr ÍТÝl¦*êá¼v ÇÔ@uTlη֙:±„¯:(5wuvòŒDv3x°Ĉ!õõõô—¯ì•Š]úKUW-t²·Ð)êဆشaØ@Ä=ÜÂ%n!È7Á=hGõÄFC¢‚Ù˜¡=ÆÀ€Mç ÷R!­°ì’ ÎoóUyB\lÖ˜cÊs¨¯wq2Mµ´t¬^½ZÇ´F‹O£ÄÌæÙa6s̾g`›B\åX8Ýî Ô4ÇÅÚÍUãRFìF›. -gµTB=æ•[dRcXFúÈcÕC”}÷ØànQ˜`ÝÄÛlÚ½ÚÏrY‰UØs Ô¦3èå^ÝYý‡ƒ ýg[/¬CÿçÉY vèÏÛ7í#ú.Ùø ýçgÝç?òð…ûT­ƒ4&ßN'üaÒ_,Z0ÿÝ¿]qp½þ¡óÉŒ§~1¼LZóÐôiß  öúæÑv—¶ñ!™*÷9ïÌš7oý×ÂM¡öqi-ݾ©Šk^;m¨‘^õAÛ¦¿â™¯8l,õ‡^wÕ÷WßuÄ„q~xíäˆzͶÅ[ÿ6[è}Ö_>ìŠ1ÿÞWÿ¨+ý’ê±ünÜòü‡ýn|Ù¥Þõu¶µq¿ìµß;ãÖIz’6㵇Îÿîz¿‡kõ>üåßódþöòÝ?X7ÇÿJ]öçú7æ¯ûY^ðò»u¿Qìà “wô±7üëý¹‹ÍŸþÒ­?ëï±B†®¶¼û§~ÖÇoù5³è‰ŸìwüCó·-ùlïñ[t¥h‚!@E 'Û © T²{Ól´ AÌq>“E ËG–³ Í`„«D˧M‡;Ú"áÎ|Ž)·µGŠ0.Ö¶eà@Yä U.1­³HÊó©\¤=Làbd¬Íìr;¼>b›Ûæð:”‘+¢SΠ÷öU8U>B5›,v´ÕMkÛ–¯\Md´»ÃC®>—„ÜñŒ²¹–ŽÎù‹Ïüt΋–·¶„HChF}msó¢…4HI.÷H8ÞÖZ½ªyUcÓšÕÍ‚ûp7ë&ó9 5è¼½³#!“H‚Ë–-C©B¯½n•Ì2H`Y]Uãq{©YÁ3lV/ˆJ”Ô™ '$™ty*+ªëëW×ôøÜº¡h®¹=²¶-¼ªµmy¹ÚCí±x”éB8‘!¾8ûh*Íâ9S"oŠe ÑT–Oê‘·¨¢ Œ-Èka–Õ¦R×—îù>¯Ç!Ç€Ú  Ë „˜ jºF#pð©,ïBºÖºE=sã ³:F'#‚ © :›Ç‹ ‘§³¤I'ðIRiïiWÒ%³xÕdfˆf ò!Xc*o舦ֶoCŽ‘¯ç‡fCº®sÖ͇“T||ö¿zjÇzmvÌüÝv9f¯\ùNÍO/;ygl¦àÞ—ÞyÑNŸýöнöÿŸ¿DýÝ-'÷PF÷Ø#!yC‰µØ°ÿ±ß09¸^w¾öC׎Ǟ¾Ó}zNl“¦ú¸´IÙÒ‰ÿ&†ì;°ýÅ¿¿ùE8ZüŸÏlÙš\OýØll¡Õån|öœ‰ãw=vß“ŸÈzÉÙ»wOÑÕïÆù ï^~À„}Ž0|èïn>iTåÙÇ¥>ÆÂ×ÙÖ&ý búàæcö³ó‡\7m‡Ÿ]ö“Ñúgƒ{]üëµÞ}ø„=¼úãQ§]òÃA]“¦>úÕÇ%érbÎÃ?Ù½ëgyÔá·Ìˆj?X{5ÃT±ïewœ|íâƒ'L8ðüWËθåÒý*»~| «^úÅõ Ïgä>g>·håüeýnaOº¿\[j53 ãÂÏ™V®lò"Ò@@BåòN*‘ ̆zÇ5«Ùbö0‘àon„‚Õô]ÕRZ¢°f9Ð2h›¥ ™ IDAT°5L[S-œœ%X &O³ƒÀ}ŒîSjvü­ùEöI ÓàIQ›$¦6p •k2•ˆàBò, ÑþrK ;K…ܨéIM²öì5³Ü×ä´@$ÎBæò¬ÂŒ£dÑ ü.^¢›¨Ør¬5ÄšÂÔÖŠt8ÆBjÀÐÀ¸oP˜V´»p •S†óC‡=zô!Cðžöª†qÔ ›Ðnç1Q!5pú³³3µdIËRµ­Zµ ÒAúE¤ÌÂUÙðö‚ >þøc=Æà íÒ'Ðe*äÆs;¶ñ ¸Ê“¢ïÔ ¿êLJÍ8M—a¯9c0’œ‹ÄÃfÖ†çÀô,æDOâE €µÕ\µ"|å _Ùs̃¦×T‹ `›~ ú‰Ð('õ8YÿX£j]’[è;îbϱ~šì¹‘[(¹Q…ú+ôøÇx6œ¯+Ñ=¢ý@Ùëv{Èl]-{Ý~X”á«ö ®À †ýjÛ*„ËŒ°sñô÷ç·ç$Zl¦ªÝÛ·ðêïïy}Q[Ó§OÝvÏìš#­ù“otØŽò:Ã5âàC‡óÂï¸ žöÖ½G Rù®·z3ÆuÒ! ò¡7“gä17¿½·Õ—£6±g‹Nmî€%Õß ¦ <ñ—úéQ—½:{îÛw½ë¿zmÎÜwî:b£¬î›òöÛü(7µ0Û2ýµ×g­ŠæÌ®`íbÙgkâÚQò»±_ñ»›º*šup­|—¡7ú¸dôívÑËÓ_ÿÝU°­îOûÇ»Ï]2Á§‡ÞönkÝÝL¿Ö¼÷èC/|²¢3™Ž,ÿlÖê(LL÷ß¹Ñâpãk›#‘¦ÅËZIý…dR¶>úÕÇ¥¾ÆU¶W3|á™ù¾NøNÍ&b8sÅ>g]8fÞΔ}o®Ïþó.šüÓ 4W}ÿTš<ÃþíÓvý-O{ìèz1ÃZ»÷ONØ{ A ¾Åé/<`3ÛP«òï=𥭭¥¹¹)à‡&–3`Òð9«H~²ÀAQƒMˆ‚¬ˆ0ÄŸÈflQ&aÛ=O&7ðÉ!9i‘Kf@&ZŸ*Bd‰~ ¹ÄXóAüƲiÔ íÑp„wé°á©x4!<5ñ|ÊRÆ\ÊMšò)K1/°6CB;Ø?«ƒÕ|9ƒ^=œneM0XUK^•TÁÈåC‰äâ¥k[:£‰\2cH$³|²7Úé!P³·Œ0w”“PPIJX’˜Â@Kœ5ÔÓäÐcI"l´ÉL*?ˆqcú8“‰'É2'½M(’ÏÆvczmV¦©LÁŠ*£É""Û‰:AVCÑZ8¶oM6ÓS¬ª©©ËB äSDn6$‹¶‚ÝgóWºùØ=„Égòæ\OZ.‹ÝM¤×Â.CrF,¶sû’¯ÝgÒøéÆ•k›[#dÆf+ú–A‡$F!rùL¶µ&ª€ÉB÷B¡J;µÀpɺ= U´>æ$ÌCÀÖ +Û˜ò«–Ï8FL~äļ6ࣆ÷KFè_›Ãæô:Ü^ô럃ˆ' Žh¶5”hꈵ„“‰lg2×I¯îˆ¯j±_Nµ'òÉB[,ÛMò‰%Å&"¡xàÊ},'å׉õ„„ˆ‘|;ƒ&>¶Éj³H tö(°9É1g8Ï1Åx¯AŽ k-oxÍ ‘°‘D‹ÄZB$"Æ$o!È´uáªÎ§Ø—e^—É!Åæ•±I„pÏŒ=^†°'ƒgœ¯Æ¸\Å‚!žÍÇ2¹öx¦5šjŽ$׆û] Ý­ÂÓ£cÀ§Ÿ7~í /Î×´««v§A†Ÿ,ӿǹօ3;<;5”é_îŽù“ç:'9¶ÜX¶ëñÚ>z닸Z‰fȦæ•[³™œ÷>å–çßxè§X~Ü}§o׳¯>¬óîc:ïÝ~zÚú|Íþè‹·oÝgè^x‹·Ÿ pÏ•_zIðûåM§¸žùù¾?øíÜ \{ôÐ „Ð}o®ýþù'Ø^¼òÊMhŸ>.mÖö!G\zbý—ì;n—±{ÿôÎw;ó=OÌ2ðÐëî8'øÊéûí¹ÿ¯¦½øš7l81ñbÿiîgqàÉÎéÉ›¾}+,¬~÷O¯Ä¿sÜ^Ô#·Ôís܈Ö__¨›ûR 7Ûekýá7ÞwÑÐ×¹÷¸}Nùó‚M ~Û€C®~ø7;¾sΡ§ükå6ýIõÑV¯ŽêcDm¶?ú¤kìù“æ¾{ç~C÷¼ùM‡Ó<¨º§8éíO4Ý{î]-ßùõ­gî9ûÎ5þ7Ì¿^m›6½ZȃØú±±r³ ÞÝ.mÁÜ9½pÛ~Kºí•e]Ú'õ»±üã¥!sÕÄË~óÝùúÇ’îß>.#3ºüþ5^ó«CGï~êu?5þãÚ‡¦Gz~=¶k[ÝÎï¥_]—íƒ|ÙÁ÷|aQ·þ¡ØòÁC“â?y௸ò¶Û~~âŽ7WëÚG¿ú¸¤Úqí|ÆÓŸ,žÿÞ‹÷_üÃa$yÞdÛØŒTÇÊXp¯ƒ÷ìuøw8è¤_Œ+óÔï\+¬Îz›µþ°ë®ÿñM·¼Ù´C‰9÷5J{Äþ¿šÚu]e½ýTš«ö¿ò¾+vžý»Ã÷3áø?Ìììº%Û¹&=öªÞüûÕ?Ü*ÑÓ&}ÿæNÀ“–4¿È?c°eˆn1µ+¼ t D©¤SP[³°Ptà_6(©¹7?P"Øk"“óš:…¦¥0_9Ũ):¨>ÍíË9à*fh¾¦“»ØkRÛ1f” \J 0£º_©l§Y^èUZÁT FÜ CIp/D ]ãFÈcôǃ†(Uqý\Úfmžb„…Ç$zÇàI›ÇWÅHʆ©Ì%œ€ÚB4Á`MZWܰ¤¢Á Jò•[zØPl ]îâvŠi>^?#žÆ¥;”ç)@èR€B¢c?ñ=V¬=5c'Í¡~^¾|…&¼µ…ø„'%â‰ò!b¼­_P­IéÂyŒW6ñ N®Dž œÇÌÖn×o¨°ç‰ã½a0ÝÁX…=œä«<Ú“}b0ÕêÇ×󈱇ZeÍŸÕ–2ÔÀž»è‡ÃYbƒàIÍUÓMŽi…:ˆÛµH ›©'c§ÞøªßœP³×‚tôÆ-t¶gÛèW9ƒ1z˜õtG[¨TÝbýîº@šÛÖΡÔÀ0ÖoføÊðàá.Y²„¿5FŠÒƒô¯mÃç²qW¾2K“ÿ¾aÏÀú¦–¿æµÏÍþß[GO¾ä¢§ºÿù°8üÖ|4™íú7-ŸŒ¤ 2oRwZgLú°¸çQ{ì¼ÛÑcc¯OYÔêtÅÑÏî?~¯ƒ/~©qËßzíU»ýä†gÞ~‹ï8îû?¹ejKÏ¿Æðô»¯¾ë­eËç}²&_^æÒ ~íä3ö”–|øëw’Wœß½ð­VÝ~—Tct潿¾ù•EÍKÞñƒXíøº.†W]ìÝxcpïsÎôÑŸû"©ÛY·ïãÒÆE»¾çbÍ-¹Šq{NâË·ÎòòÔUÝÿpÛøéîÑgîüÇ´¦Ðª_|©uà;7xœæÄœýû67Í~÷Ý9íÚËÛ»Âðœ—_íÜé„ýwË;†xtÝògß^®ç8_náæ:íýã_ŒYqÏ•w½¾°= E˜÷o°Yk¼âÏ×ûøšso{§u“ùÊæjìý\_mõê¨/6›o.ñù}Gï¼Þ8Üãì7åß^½åVN¹õ¡75FríSïýË›K›E‡ ª·^†M¯¾Üó›Ûð({±?“·ýhDZ»îwì¥o ¸ôÏ7Õõz…ß +·‹µ]qñÿýý=o.Œ»~7ú¸„7’ žúíÝów»é©?ÿ4þ·ëŸ˜ÛÅw+?mﶨ²×~I{ÖÚC®¼óÔâß.¹íu¿B†brÕ¬ç†xüDÿüwg¬í^=ÑG¿ú¸Ä{ͯ?xÇ‘c¿³ßÑ×½ZøÁ-»ùèõ_Qmތ̒go¸}Úèk^ÿdÎôgÎr½zÏK+ûü´}èqמSýêïîÿ°c дòo[/?•¶!‡œ¶oìñëîzmQ( …ˆoܵ¥–=õ‘õÏì¡÷L~åÏ2rÀ»fú×%…:$±ÿÒ‡;;ùò9·Ë òAhZQ¨­&1u‘WñÀi0-;xíPXbï"?ξ¡Îù}¯ÇÞš€ÓÅ|ÆPÈúÌvb{ ~–xˆv Ó+ÿÊ8hUÁqv$°¤>LÄQÃ"ç@ð¬¾ò iÊáDÁ» %BŸåXQŠ;¬Æ2Ÿ+àÆš`% u2×Ùmïˆð!&Ôì¹Âš¶ŽÅË×4·Ç·f²e•5Þ² ‡Ç¿k´:à!RKÒ¾”È^É~±*?`: „¯ ¼°ÄÇFSQ)³i/——´xf ´½| Æ5L¶¢‘àÓ*Ñ $[ŽÚP›aæíޱ$„¶4a*[!,Mh£ ‰Ѽ PþHÁm°½VQžO{Ê\|¼•>FG1š­e )—ÛgµA;ÒYc$†Z·`±Ù‘•DÉŽ0ùyDT&܉±«·ž\«çŒ Òc¯ŽUêyV 2S%#Y–… R¦h*v Ó0ø}yvšÍE¯c²;yO`´¹²ôÎ`c_°ò1% æH¦È':gŠ$³Ñ$¯øDégja=*£OTÝ2¨ô‡ÖiÒšùÍñáyðU…Åc 2»4ÍD×ÐBjôÍÉ͜ᘕc1T¨ ÀUóAÉ ß¬?‰4£(‡1Ñd ùÄ’é(áD²¹T.ŸÌù0:cÉ–plmgduG´5–æ ™­ Lðñ뱡Eè§OøÅ# 7·Öýô±ç|¼ï}Ÿ2®!ð÷Ïél¹T$k©rReA2;}N1{º`N±ã³ßJÞyÞ æö§ÿ²Ì>q›zdª;òÁݲŸgÅs×ýüàF6þg ¼ø™k4ÊJ Q±oSkÜL…3V+Ê|LÆÐñèÎQÇž1fñÃçÎoR¼K½Ùšozýª3Ó'Ÿûˇþ}Sü£ÇoÿÃo.K¨•\åƒ+ªv¼`ÒÌ ºîMΜⵚ֭~ -|フòuùk÷Þ×ÝÀv¯0¹øçVœpì!#'=a;âGÞ÷¾¿¦ëÉôi!,ï ÷Mìš²–>~âñ¿ÿDÞr˜Ê†Œ „fÌYÛK¢E[í^G®YñØs6où4¬ïöÙVïŽê¥¶¯~º^1}y˜%D…¶Eï/7"ìz6½[ا畛_ñQòÏNïcž¶ ™hÓœWþxËÈ}î>ršVðJßœµ~ô1WZýêÕ×~šº·ÛØõ»ÑÇ%eyºñÝç?9ï ï7}0£q“ ëvn«~¦sßyž'Îûõ ËÖÿ½tŽ8ùžÛXqã¡çÌtê]w>r«õ—<¹„}ô«KzPóÉðšùoÿùÚDõ?ï8ú»u/®XÚ5ø{1£˜XòâoöâoÕíæú£>=?;¾Þß‹mèQWœêùÒ¿~¶ŽÞ×M}µ}/?•þºq5ÉÙ37"RºÚÈ…æ¿të™Sþ¶ûÏoºãů}ÿ¹§ÜÿÙ¦o£¾šEÿwA¹AâÒÜ'ÂbP5Øš¯œ‡e$ÜÿfÀ¥Ár&R¥j–•8«ÅÕÕU0Ž`&θµ,yì´0•°†,5Oå•N ¸H&Áqœ'O5dž†kpœ¡X`0ŽäI9ZÕ&4¶ZßFîn‰½  lrr 5,{ºf^) K ­Ktjj«ª"t\—¦½6¤ ‡Y—˜Éøý©_—,7Ô4*µu1—*(2JHGõ>Ú”Å0¸ø*)¤;%_Np¬(Ë ¸=c•ØÏðЊCuqOb¿Ý-yLè>ì/ÒaªÙiÖZa"f؃Õ“ëXàJÂN¿$t´—¼é…l&ÍIÅâ.—ÜæXji¥žŒ#MÍ j&£û ¿øë%4^6Ë-úá¢ÝÍÄ»gP¤Ó;n‡÷^çÁ¤|Zs:)šélF^A°¾$̓¡)̃á^ºÉWÍL{<®aÆñÑjWUUr•ÀÝCE‚¥Ð¡öv‰ WO?S”àÓüsIë,Ó¤]íR'çÉÁ¢Ÿ;–“L†óòDw#ö ÒT¸kv0º”‹XÜI¥<Χ$·³q‰“\¢föúªŒ1«Å¥JëÌ&+ʆ®¥2*d¡¢8„&˜}©ÖH†J9ä8ÃeΓXž’ØOÓYBÒ•¨Æ`’,m•—Ä?emˆ¿ÝÊQãËbs—wö@Ýè‚W_kýù¥ß»xêòÌÛÖùª—/8¶å„‹}ú¥7Ü·ßÿ¯iM©-s¨H¦Í"ì>.­³ÖU7~'çÚI[°šÔÖpø‡%Ÿºð7}‡Úë¥"ùQ%g½üúÕŽÛDÀ0y=OâËÞúÓåo=|ÓÈœ}óµw[O¾m¦,HJv6¶¯˜úÀ©g=߸ñÌ¢o?oï 3Ëß}föiçuÀjç~†w¯›ÕÞýPú´PXÞa›1”¿d•øK͆œƒöØ{O×ò+]8³ò¥ß>:øÚ›ï¸rÙÏox³i›0õ—´Õ›£0d‹†Ífz÷¥§6ý‰èuØPWoöéù>løj²/ ×oL˜'+TÿnØÏºäÔþpÒcsâ–vœPÞý»!?)½\’;ÍUûwÉnͯͪ>ýÚS¦ñ§Ï §º™m{´Õ{¿L¾Ýιí¢àÓç^úB·‚¥ËÏÈ=hñƒW½µ&QXóçßþiï‡9 áù%ó“ê§²—~õqiîá?Þ7÷½›±þmÖº=‘ûتu\¾oÌñ'ž÷ÇëælÞy›ñç–žÚð§’Çå¯YÝl8~âÐõßðqÎìò½_\zÉφ-züÊ;|e3k··´Ýo¢òOÞŸñÿÒÅK;ÚSúA¼E“ÁÚ°Ã ´¬—*ƒe²´‡:UÒËe³`5ŠŠ€`8Ø(rÐ'8O|gèkRÄ8ÐV[á Ó¼Ïñ a…£DŽ þ3˜ˆ2Õd"o3H X2)¬nOío(1 È.ÊjB–¥£!DÉ}èuKrl O¢Hf/EãlëL444(ÌšŒPÞæ€%CMý@~‹³dïC…B7’"¶[Y-š¼¢­E‹kÓ*jƒ‘-ä„ Ñ˜„‰ÐV3êXe6 %¯ øPVt´&ƒA¹Ð«‚ ;F´¹<ÍíU•òb[l„ªÈÐΊ‚jc)ƒOÊý¾tG#/jêëpuÞãµ»ìÑT¤¹µ9i•pE£ nãé]$[¼xieÙ`Ât„ã’ï=cÚ“ ú%¸^:ÅÊK«ƒÖ£¡(Çéà›L…^fGÕU"&©)~ð‚_›Å¡¤*}v/`2Iô7R¤GÌ6„K.æ,V2.¢1HÎv™œÈ¬¬ þXDÂÛZËËY*j_±b™ÕlBNƒ®˜GSð©g'6·3©ˆ‡dA!Ïœ7M ØuA·€r’ª D5êôö*;7aLDBúva“EP«ˆV„°+¼,àW$[@BŸéŒÆ±Œ@¿—L:pÇ 8Р, B°I4âË¿ÉÐϲñÖÁH„ÆÀwIp(18¨_fɹ¨ ‹þ› å*–£¼dᚉ¼ž "Og£î,ƒ›J‹F^‚˜’’û“û*a QahELæ Â1IÖbÊhWiH•=ýhÛ:ƒŠÑÙ¿ó¥Ü!—œ¾{@ýJš?ynªéð«.üÁ°`͸Ÿ\vÁ˜æ—_™¿J.|â£;ñšÍiô.±*Ããvº*w:úÊ›~îz÷/Sºd Ú¾Ío®Ýÿ¼“<¯ÞûÊÒMØÕ>.ÒѦbåøQƒvØï—7_¾WùzÁ6ø_ò“ï ºŒ‰æíY¢ýw½¶M/{ûÙŃξð˜1,÷׎ùá)§X÷¥+;·{…x#ßôñ??4ýøºßLŒ¾úò¼uÿ+Y˜ïX:;\{Èá{Ô×ìrâ-·Ÿ\oÊÃͬ?&rmSïºè®Åß»þÎÓvñn8~7ûPzO}µÕ‡£¨°¯ac0l¥½âè}DõaáWò¼˜ñeºGsÁ™®t9ý;p毎óΚ4MÏ3åwã­å‘–EqkÙÈÃÏ9säš—º~7ú¸$ó̓.½|Ïyw\tÅå×¾ê=åwgíÞ3h»·ÕG¿Ì&žu˜yÒý=rðuO0k ;FvÈn5Oí®ßû^]qmSXýôѯ>.ƒ:åä‰#‚N‡¿áÀÓ/þ±oî‹ê—f†>̰V稣÷jð;<÷:íÚ w^öôcŸôÌs ÖŠ‘c+ðúuW<6oƒ·°ùxÓ¢…ËÛÓ›a‘$1+ï)díòÖlùØÒ·<ÿ°ƒOy*{ð™GÚh•Ífk Íüó]SÜg=3ýóþuî®6õËÕµõq)°Ûo^âŽg.1ãÆón}§uƒ}6c¼‘eegŸö§gæmò~³KØúüO.ÙëîÉ/_9ðõßÝ7m½Åö™öeMCozéýÏç}>ýŸ§Ù^¹ó¡¼P[våóWýêIóÉO~øéìéo?rRm벎M`|w7»ÿ»Ý+”Š‹³&½µÆ™›óìÿÊ›íží+Y›ýØ 7~ÿ7§>8qáÍß9-éàß({DrÉs×\ñ‚ë—<ü³aë/ÝÌCYßU{ßñö¼Å³ž8qh—¢¢¶úruö1l˜jµ½¾©ú¸ÏaÓ—…_ÉóÒæÖ>Ê>-ÌÆ¢e^÷Â3gOù† ï8÷†×VwIÁäwã’»æL¸ñ­¾xqí¿¯ÿuÏïFï—¬Crë »Ïºí¶)«SÍoxºpÒ÷©#¼lç¶úì—Í[¬ÝõŠ—»–š,^Ô¶ºeÉó×ßòoß©Nýtú<Þøüooz£KÿÔ{¿Ô¯h/Þ ŒBÅ÷¯{á£OçàÃï,½÷Ü+Ÿí¦Äû0ƒ\5GÞ6eú¬YoÝ~HÇÃç]ôÄüõ~“,v·ÝOÛtÄq¦ïÑ«8*hÖ Ï{ù©L-štã猿qòû}ä7ΊHÄZi50íºôîcö?áÊ|²vsÿ:lÖ¶~u– êwéâ¦L jYÞ¤û½n>d#‰Å"­Í-„ÙШz Q!ŽêPPy„þð¸Ðçˆ 1Ip;—ÍBx ¢˜ è%x‡‡qTaÀqt"6I+ÑHÒP´8ìžPg,C^?9«ÓæwÙ¼ù´!Ômo ŽX7Hv8œ`1 gkG{5–°ÍDÌvqEBd'aq^'±œùH4<¨Ut2()47m—…yco"aᆠH!¬%9ï`mÁÂ¥ÍFùƒà¹WC4„ IDATlÔ @'Ì|^/A»…Õv¹’9K”>,8±†Þ¬n uÄ º¨Â‹&‡ÕâDŒT:‹ç“i êac±-ÜÙ¸vÕʦÆÕíkÃéX‘¬ØNK°ºÊD蜄» « Z[H—¤€|Ü3¸nð؆ï:vÄІ!C*ÕNÆSÉ(4Ä¿–Ø)ÃÚæöË—.Y=sæ§ÿùÏÔóò¦€ ¾‹Ò/À|ðö,8gR6·\L@â{ _·:ìèˆý•ËH…DeÁ´ƒ»ð'Sh´“šð³Ëí,–ùý^Èi$#‰'3ÙdkÛÚ•ËÈ ïó¹ë*ýn ·†dÔ€ÖÅq!â_2¥³&vuÞV/í˜Òì-ɲ©Rs ¤†0æ]ˆÑ„Úˆh+PÅÃUšº-œˆ$’Z(j™l‹’pù2a¿QH“ÅFÅWAÅ·(+ì“)ž5ƒKB+a¼È$칊×Áß¹Š6NrýÁ_’[q3ƒYô@ùŽ(•7ñI挑t!*Êof$e¢¾1#ò\Þv¨æýêA~<ëèo6õ{õèÇ¿tÆéÏn[‰þЗ’ %”?)£Ý; µH´ždEVb9â“‚K-¼¾æ^Ð*—ÀÊB@vs{0ëE9(¢-økŽQšÃm*`[k‡ô‚ucÜK¨ÆBŠÄ€ê)ÆÄ=ô°&¢ÛŒha‰›}«uW8YvˆÂ8.“Ê€OxÜ€õp6¹ ¢t¯]Æ ™¶9ìô—p$·Ýæ´Ë2;æÀAW™ ¨ç ÈZR¸tC$N8ر¤3W„-åù²´’ÈÌ&"‡ó!×6Ëú¼/¿H¦BÖªœÕ p3Ï| òåÝEeU¹ÇëD ât±Pïñò!Ïgä¨J™·Äx±ñx]•A@‚¼‰ð`Ÿy ^G8ˆå!@¬ªbØÉÃR³(ŽÕð8®8àä¹ò‘2¼ Pz íQÕ`³.0Í]J°Á&²á—òU†y÷Y†ÔßE?¯«A c ü8sS‘‚o­¼BWð5îÿðô×ñë¼¥¤Ë×øhJU—Ú¼YÚ%l\(çՃȞZ‡ªv…»UÄtׯI@jÃH6:Ãø¡rJhS¹…¯8G°p÷FRXm몓èçÎW‚vô\Ò:ùMp3ÎëªTƃԶî«!Ý—»Noð è»8‹I[%³‚~¶ý7àé¯Ã¥ù•“N>dÒ×Qs©Î’J(yàÛ厩WO~õfmîã§2¹ròmgN¾m³·}ûO"Fü z ÊíVI_HˆÅ¢ày÷-É ÁA 3èXHÌ¥¦ ÐXÊã´ŠXC.˜i‰X 890$ŸÁ ¬‘¸Bò‰Ø\TbaAÀÉDì²[h7ʸ]‹!íL‹˜U}Ä F'IgŠn4§&¯ÇpYBTcyfªkªïi–K,°‘‰¬hNvk¨3ÏIä8ð4IÈj'Iù,dflIÄ«pÈ)z$ýe)¤ä-(TF$­Â4°»Å`#áЄ¹Vp•³š8kòÊ^! U:–H§P ÛáòáŠ4Á5â9ÂÒ¡0Ædb$œ}Hk®#Ñ ä/·›Ê<¾d¼±¹µ¥àvbgkLÖÒÅŠ¢Z‡2>{ù²µå®rB6rV¯¬£µ ðítXÑ‹n°`2ÜJˆº ßG,‡Ùâu¹ äˆÌçK-N?6$ð]’¢÷m¤åkéJ¶¡ ›PwV‡5–Œ‘û½~_4.YÄÙâÉDsK³ÇéCÍ‚aÂ:'âÔ‚°×4­`0O’â–šÆ?=þ\ê –jj«¢QI`ŽxGp0³2£ÙȤÌkuÊ´ÄI&êlª=š†¿ePäKX#F/ð2_Å~%´A#!ãJ.J¨3Ê0 b(ê(1È>˜—&ÄÖ]<1e"3»PQõ&gº7*eæ‡HºçOYÒrÏ 7KK0Ù› _™5Â[‹$…ë,.·R›:ÏØPÇ]29T\b3Ê1ù@ûÝzÄžî ¥ƒ’J(y ä’¶È°cà!àô¤Í"l.i1`2%˜‚¼[—ÿ ¤ÙËÄcÄSR Çv0ÌL=†Có¸Â¶€@@@¹b®PWÕ{sH…}Ê(gœ2žï'ŸÍç9òžBP²ÌÅÄë2Nº¢ŠK­"OËÌŒ'!¸[ö³v–z8'3À‚Ò»w+:ÄçŠõ§0{*aÍ=g˜#Q€F9Ã]ì5…Ý ‰Uœ<¡´Yˆ«.voT%f êØ“Vƒ]Zé>P_»¶œW–  g ׫µ_š}>æ8¥­ä’J(y ä’¾ÜƒvK¡5‹> BnY™‡dƒ ŠA"âI’c @FC’¬oÉL2M& á¡0‰Ø‘HB&P£¶- xý§*¤m–$É ¶ç! Ö:í§Ík.Xòib(Yç°ÈK|¨èd"é@ra6Ò"úãBÞè÷—2ñ€ÏÕÜÖJ¤"0DP#‹¶Ùç/Y*áLE0 |¢7àóøÜÂ%’Dw @…ɘs› ÙXØryuà!9££qùêUÍ‘\º¸ruk{[çšUíuî8r8ÉÅG khk]ãsÛyS ¥’±p¤3šJd*` ’9Ayy¥Ó¦%eµåËʽ6ïˆl6å…‚yØÈ]Á_,kjé 'c>Œç±œ¶ô°!~ÛðÓ)óŽÃ†TUT* J¿yóggRñ±c ª¯hkkLEÛÜ£ÕΧ¶BÊç@Ý‘ó8II ¬Ça©­,#èx¨½…¥ª8­¢¼,X@íMs GôÖ͸̣ÉwÃ$à®®ðË<ÕA2<Ú ‚s$‘î–œ<‘E³•œ’Ì™àŸMVÖ%*öÛá`ä0óžSªAÈ2B$ Z˜Ë)áËýá Êp><>wyó€hĬ"uà(fOšÜæÍƒÉà ‚^K¨h'ÎË›F‰ÀcÜ-"{iHE á¿ç¬€Vgন?,5   ni“Û×ýaª &§-»ï±gXå4X9ö—ÿÝ~ý%¾Mü´qÀþòÒßó“¹ðýK|Æ‹«6œõ| β ØÿÂ?\{Ú^µCÓ‹g{é;ßú•é_ƒ“JU–7'šV¯n¶èŠ3‹f—È'кôZ\š!|]R¸ÿd³pç~" J$êqTTˆ.%™ä¼7c@ ÝÞ…ŸO¥Du³lÙ2¼” £:ðA¯Â(KÉ-Ž˜¼e%¨­ºª\èê I¿;2éˆèpÜjÝ^†%ŒµV§ÿ‹/¾X²¼ýL(C훩½þè±:†íFUZê½îªï¯¾ëˆ ã&üðÚÉó&úŸícC©–’J(y äo—xõ ö*+ z½~PÿÌCÀY-výï=pA#þÕ'3ËùØ(f³Iôe•‚¦áWa‚Á'àlIˆU«¨2ܨkcú¡ªX4ÑÖÚAˆÔÛ(U³£3’4[Étg‰'Ȩ`Åã†úúÕÕ•AŸßçdùÉÍN+áùHC,6Ä'ØI… OÈØ,²løtR$O˜O&W!›XÛ„ðWO4²¡Sz’ èMç !+ ‰xyJ ÎF ¢SãHrAìd…¨Î˜ i«!Kts.aHE†ì€ öúb,tXF×׎QSWðYLƒ««Æ F( ô)‘þ¢ä2ÌlÛë«ðxƒ±t²#JúóñFHÊHxÜ‚sÈ ãrÈ#I8Á¹s—Ë8_YiO¦ N·¿zà ÊÚ:‹Í:ÂIøæH,ɧ3”XÛܹ²1½ju'í¨€v`n8Y¸à‹… utÄðÌÎcFŽ= !!AØR‰±=|ÞT+Bp›Ó‰F[Z[ÁòúC´†bà*=ÚM¸nÄéа˜j"O¡h0p¾„Ý`Ï ÁE¢üVù,9 $N2[[»¶e‡† <y 3„+/Z<¯©yi<Ùæt*«<^?Ï=ˉô‘ËÛlvýdØ©u„lÌã£_ ^=¢ôpâ«hiÔÆ,LßSê’=•ôTȽŒWîeOͺ~ «VdêBNêq¢‡Fó=#¹ç@¦¿öë†zö=çµIº*yýiÛŸîœuó §<Öè¶ß)7ÝpÓåKO¼êí¶®ÙMÇÌß{Êß] ϾëúËN~wÖí³btÄÜûÒ;/Úéƒ=ó3ϯºçw·t6žúçù)C¡iú¤ÏMç4ªì?ïwR°|ôÁ;f§ÿvñäìî/þ Ùw`û‹÷¾ùE8eÿçßýŬ’%”¿“[¨õˆ©|˜^Ù0a„—þóö¼yó,XS]í ”WpÞª²ïÑ"Vñ ´°·»¤§HaÿÊăj‚UUÂfÛ#Ø<¤¡V é´’OÈJA‚”ÐkX|lF‹­" Ls.#‘É”B[¬¾tœ’~€¨ÕsàFV)ržàÜNØâêÊJ˜òtüs_ç2ø€ö¨ ÚÑm/œ7Ÿ»&ì¶¼û'önîPU£1½0ß.I'‰>›&ȃøŠ?µ70ô¼…N1®¸QîòxvØa:ÿÍ~éÒ¥k;x|A‡Äú ˜Œ=#ñ:ò"À‘üðB-Óü£ß„È£éf£Å§êt9¯ÇžøªpëÂì9ÉíT¥ÿÒôîbã$qµ{ªâ@×Ï%ÅYËǬVTsµÒ±[™­þ"ºHh¸·ç«¾¤¿jh®›ÐëV4’¦ ½Ö†õŸý¦üйDë‚)O<ú¹eçñuH}ÝV̧:O~;2õYSÕîÇí[xõ÷÷¼¾¨­éÓ§n»gv͇VŠì|Ó¬7¾pL8h$ú ^ðŒåöÃoY{F›;`IµÆ7È9ˆæä‘—úéQ—½:{îÛw½ë¿zmÎÜwî:b‹s¦÷ÞÒ•’J(y äo‰`ôàÁ=¬EÑj¸ÃÀHÒ §Ûff²4¨@ñööNöàTŸ;9*D;¼)Êl>CкJˆldÈZ%„„ƒc!«(b×$}&gqæ,ö¼ÑÊG#$ a¹‰9j³åR>s>`-†{m™=è6²ç.»¨¯t ádûò/«–Ú²Ig!SˆÅ „ùËÜV§Ûá·¨¬W¯jÂ%xHàf”"6‡Õë÷À§2ùP˜‹"Ž@eg²†PùvŽ¥Œ‰ ³·„öVZìþ‚ÑI‡{ ˜Æ5µ6h`ŸÇ†ÇNƪk*= z|ÇOjy§Ó=bÔÈ@y¬ùÚöÖD&íôz|åeÌ/‘D,’ˆÚêt0g §ñ¨Çç·`ª’Kh ã(¹ÈyVoF ˜"˜J%Q8ãRgGdÍêæÕ«IÈXQé1²¡~pÐã3¹ÜyŸß%„‡qÂÖ;ÜV3ŠgÙ?=³~Fjâ$$ R5Œføi”¬¥5Íw͑ԓÕÐ\WÈW}‰[–Z˜¡9·÷à]Š©Mæ“2¾7ÜzLW!õWß}‹ºmíX÷¯áõFžٯ½è§ºrS¤%¶Qþj£cÀþ§Ÿ7~í çÌrš µ; 2¬xu™N‘k]8³Ãó†2ó§Q”óMŸNYâ:íÀþ>1Ž8`WÓì[ S½ncŽ$¿8Ý’œmñ„µþðﻨjÊuGž354âÜ¿\¿COmö!G\zbý—ì{ì'a÷°}¿SÆK(µÕüðáî›àh·¥uÊYG^øV+'\cÏÿûÓìðÞï͹7 oøÙo6ëûH+~â’ߟ{ש·üúÖšgn?ûΟ_ñ½aþ—·Ÿ ¥ÇöÒAÉ%”¿ïèŸßì%úµrÊ­½±rÏcsíóîýË›+¾{\q¼uS¢»t¬TIÉ%”ŸË‹mñ|ÚåpyË};T–<˜‰ÊÊ–Ø;DɈó£h…¡µ:ˆBA¾'óo0œéüüÓY,0då¥ÕéZ¼xqS(IÓ¡PBFæŠõêÑG³¬ e¶S@{ÂàöÈZ@¢rú¯!®¶çíîœ;]°Ù‹6#憭¯­®i §ÝNWÎ`沂7._æqvÝḛ! ,y$Èó ºAÍ--D×À4!,ÂDïSVÄ3ä?tû}m²P²=SÌ}nÉñÎl‹éžTáêÈ×Î^í *6'“IÐ9*_z˜¼|¥"XS^)3¥L6ÖÒ¶8e¥©Ñ!s¿×ð™Û:sfSÜkκTCžî¿ÃÜÎ^q×”v³¯})À]ºp×ðUÿÑg¨AnÏɬÁ£Ð³]5”ozýª3Ó'Ÿûˇþ}Sü£ÇoÿÃo.Kt©Â¿Š%ÅðŠéËÃü6Ú½¿8Äzi+y ä’JøÿÊ`kñ$èGë Ó|Åsh( é:ýo$—øÊÚE@ +å(FÐ ]LƒÎËŒ-’lØÈCôГˆÇØ»]^©Ü€Ã?¨zwÈü¹ æÍkzãwÇß îú“h`k*„ þ¹;zq1'2’2‚¼ý?öÎN®ª|ÿÓ{ÛšÝì¦7’€é ‚€ôE•® ½ƒÒQ¤("z H1Rƒ)$!ôí;;½—ÿ÷=gv²Iv7AýAü;—ù\îœ{ê{ÏfžóÞç<¯ÛÍŠ¤C*S g{W?hÁ@ìTÒœ$gòê¹;P¸Kâog‰¥Ž#S‘X y$ˆ‡°ÅK_º®üÓ(UPªÈâÁHØtI±D_™&ðò+Ånù<>ãT,Iž ÊL¥ñ¼âz$?Ìï}÷Ý·óÍ÷¨š]1›’´N ,fì*Þ • 3V'OHJ)n1L…‡8†Ç’'H /ÐݦuâÍX#¼ˆÅH…åŒuc6‰· A¤Ÿ&«Tçzè¡Õ cÇV³‘QÜÞk×tt$&ïTƒo˜½š°n&M÷ÝÝ«ä¹ÔIÕ’xS3và+™éÞ(Å&'Ãa¤4‡ûY`·Çƒ)àF3À]vÙ…lòìrÿ’ |ô<ñLÁØÖÖOvw]<´Às¢ °æ.B LJaIBŸËH2.\¾‚×9Ӳі65&¥œ¹%OMú«.Þ;‡K®nŠ“NN59Q#‘·(\‹…•šµ®Vw@懨ŽH£º?å³X¼7Q_—ÏL]°|ÖȆ®dïß×E>÷¯›ãiÙøí‡–•œÏ[u.¹ìÉ;~wä3ÎÝoÎ5ot¢N´-^g8ø‹£ý¯¶ÁŒ¶Ôí´[Ulñšž^ïpfÃÜ¿l<ëßüfÁ¹òžE½[·ª÷ßN`É%²†zñã¾Ç¾#=Ñ>•â«gÿòâÙ¿¾qÂWϽéš;§Ýö~é¾PÕXø*ú×§?þL•Oßj¥DÅ T,P±Àçk ë[ôûzð„ú}—ˆ  <€²K!BlpÚıëÂ-¬†“Т_‹h¼vºiâ½™LV>]ü~eÀ(P±‰}Ø ›Z¨Ê"Î Q¢IÛ̪ F5jtsó°×ç-õ/‹6Ãèñ 55ÕK–,mj¨r9l¿àH³¤ËlòÉ.®Œáh0%ñDx?ŸæˆÙšÍCÑ.bA0`f|¼Ev}Ù0*Åé•E¥36D¯eÀ6»ÛjIÆSìOÌ&„¸éT¤jÞë3v8*èù™3⤴ ü±uáB¾kúzŸÇ<Ä•ŒFˆ¤MSÔƒ•pÇŠ·ÕšïììÀãKÑPw­ß3º±KÊdnRë´ ïmÌMÆ–î1ç½õMÝ£Y#¸ÖäðcUÈÀøH”(Æ9[E pˆc[Í© ‘h .£-x÷=„©„Eã p¯à{—sÚ´²ÑXÄÍ% êj“&îÔÚÞµ~ýúî®dYíB¿øâætw‡Ôî±tñÒ`@í”)S0ïûï¿ïUÁ/ =Ï&HD¤{oU5K¨ÍÍÆe em¨2Ü^°;“KÇ“B©%¶<Ê(Ò” (Æl*/س N…2‘1q³ûÐê5û}ž}÷ÙËh^9þr“1nÃÐ*ôÆ×°XÍÒ’ )zrÁ9ñUh&$Xœk½àÑ`ZÍÆ,Þ}*‘'›“˜Ž¨žë?@e=¥êaÂèʹkRܸ³(×èü¨Ñ1ý•R\häMCåeuËùc‘ÅéÔÃW5pé-}Ð5ì8ç­øƒv­ýèww¾pä]œùâ7½âMNû¼§ß1ÝzÅçÿèž…žÃ/š1¥ýñ;—l²©usf·Í¼ø Ô›—þ³½Cµâ™zþC÷Ýró™—<¿¾¤48hëßÌ?ù(ÜxØÑ{<×<àŠNfʯ´–ž–mÄW¿?=ðç^_¸> -«;»ŸÇ^ºE…ÅxpC±ù }Ç¿ÚÞÖ°ÿþK_}cÝ@ˉۯܩX bŠ*ø_²€Ÿy=bíç#“J¥ù½']Á >’…[šçê´ â„¨Ì]A ú ` 6Š“B< ÎM¾.Èïrùìl[¤‘úé„lnܱl\¤’‘#GÆb‹zºEt9—Œÿ+dž «ñeVù”šê0H]ð šqÑh( ⌢Ê@ÓEâÅ|¥þ¬BÀ@LRÔ¥!‘8%ÜÕ^<®¨T*ŒñC—¼¥ÔŠ‚!RÅÇ!ºÑ LAUŒÛ•¾nÁ$þWå$ø ã%þø8œY¹ M`^XS^" jÀçYÅÃÂnèŠ,YҚȥpÑÖ7:© s7%ÈÚÚ²žA P¡¤Ngðì†Ô©©jÂÏ(¼H\‘è&¥yÔ(гˆ:ç EøÆàô“ªð/#,½nÝ:ÞÀîà N¦CôÎP„‚àrð´~¸x å«×+o%»6véV’šßÊž²5ÕZ±šKNgI|XfH¯D4E잀¸œ­>Z'Ô<ê"]A6ÅZxÜÊê u’Þzô"PO?º§17_Õs,ÉÛ•Q¸~ÖÜ¥KÑêÎè'Ë]}¨õdéAS?wËp™üt†Cüä :sî-%×¤è £mÅWÝ ýÚ‡þ“®ûCÉfÝ¥¨L¹ÿ+ƒ¶Õ¿pþtxš‘ß{èŽÙÝrÙ)/rï‡qC¡ëÛ/úù•?¹öÏïUåÛæþöÚKýX 3–ŽÔš¿¿¹*5²ç•Z·„Óö´òG ¥ìS;‡ë÷½ãïˆÏ»vúw_%P<öÑ£?þõøÛï{ýÛ¡¿ýì™9íæo õ; ­@ãL÷êÖÀU7¾pÝ0ÞÂe[ÞýÍ ÷/è£2zÿŸ½zóUO̿Β\üÇ‹¾ÿò¿`ÄJ‘Š*¨X bÿ) ð£Î=CVÌW9ø=6ˆëNüuJ \*Á·AÞ6¨Ã¸]U„¸"¿zv›Åí°‚®LFQjC5½=t‰—(5jx€-HÖ€Z"™“Bx? 5Äãk!Þ [è šX ùXÐárV×Ö¤í­­qK‘myöjŸ¢E}à°D"ÆöD~ÁV œé(XS?PØíöä `P’€â¹"ÁFÄ_­@ü›À®Å‰«ð´‚Nò¨s™íB²`€xÁW¿ç’§…ê´J,=Aü ^ ÇMôF§ÝÄF4Ž`³hÞvœó‹$Y°¤¡b>NÀ&.Ø‘ô0~VB·§bÑbFÖ .4·½óáîêë†6ðkO$íòZ¼VMGC‚zé; ƒx ãübX‚b ãõ@ á‘ ªdÀή6bÁ$}^t² ™Áb—Óå°/_¾á‚ ŽhvÃÒÖ#XW[m·‰üB]Mu¸'¾Êç_¹ò“ööÎ# õC÷'+WjAÏ`níÊ…¡æ–ÇèqÇSÉb2ÁöJ§q÷2…螬"T•aÆ&rÚìð’e;§~âXÞlqdsl•Ñ!ÉMP Äðhƒ¥â‡Ç@èÄ¡5ÚëÛ:Ö[­¡f³>46¥~ ‹yR|e"©¹$;huŠNÔ ›Ž‘Ÿ3‰ú±ê¯T+|ÿ^&‰r‚ žV)j†¨­‡½·‰+©2®}­êÞ¬r%|(­¨£·fíD—ÒzñV®j¹067 ÝAºRéFÅ T,P±@Å;¸ö›~ =œ?ë~é5Ü)¤"èˆ)ýWüc³q¼ŠæƒŸÐË8>­FÀS•ÏŠcÕ犈Õ$(Ùa2 n–èÏ€ÙéerÚÁ…lFÀ‘¶“ÉTB<Ó€xÍ,›M…dÏ+ó¼UÜ…Œ|_S½07yÜ0îºâø,äD¤™ÿÑO‡ÑQÍ]³EÈßá˜ÄAD,Dàð0„°l_„\-)dòðž:…o-’ÈDF,H%É„lž£?2.ÑC˨Á¥yÕ®«(k†Z›l“ÇÊtZ#0›½.Qɨª®g,No•¼Ø3º¬p©!§ŸÛè@Ëâ•·ÞÚ]œ»–b’vÙG¹Ë+¼‚—­"~aKW˜R^=NÖDR$œé;+ói ‚ÝФ¼é`H‰ ¦(äqøóºÚÂ~¿¹ºJ¸…l‚g@üf^¼6)/€Þyúñ~+ÿŒ?­ú3î^¥¹Š*¨X bŠvD ðÏO¾Â%@iô=„cŠÊ0}¨30£¤œ¢#'^]ÁÚ =(hšR-䃪 Rªåƒç ¸!* ˆ(C•N%äÝ/’ú@jÄC¤mpg1/½½µE¢4 I%£^§mh}MUÀ,Cus†ZéŒÝ&¨Ê’)šHÐ["$&‘ïHÐû$þGOH8Ù á˜õð,daݺ†7›òtŽî®xÁlܬ†f€´Âz-ÕÙpxQ-)XM8â;K ¢¤e,̨w»29‡Oè±fúº9› ?s:ÆÊÁRHY=~Äúˆƒ›™ÚüVs]5Uª@®Un{1`zy«V·Ì8¬ ×t‡0UŠF[>gâÌGÐå жX4ÓÞº ”ÿØ‘£jUŒ¥³µíä ªö¤"š-8éý"Ægí lÎ!p“€’&h7¸Ì¼€%Î5*ßU£ÉX"eÂâ+âäŒ.ͦº$ ;*k¬O f™{~‹«:àõz <3azhèŒy@[ë'Õ;?e–jœ*WM<¦,G9ƒ@ÛÞC÷DŸyÏ¡Ëbs-T¢q00—yËÁ]‰ôÙ«l=A÷°„¡û4Ä_‚nz볆ìÿð=ʆ­\T,P±@Å T,ð?j94”ÔCàݳØK»»HÔXAC0@yšqÁÙj J=& ZOW<|` ¢d¡Ý„œ FÑ·p’k„á²»¨¡'Å‹ÙÝÙ£0¹WäA èMªv¨ ø+ˆÊ&TZª•†b‚ÆâIÙÔeµJJ&š†æg)hqˆšÁ±h+l„† úGï*BïŒÌKÅx/…¹AXJ‘™<”¢¨°(4üÞ¶T•·‰Ï•n€*C†0:§·žü‘\†þÛ² p¡1‰N41Î¥j%n`øÁŸ³Ù,{æz ¨Ë‰ 5ìkr¢¹'#× Š%ìÝy|¾g¿_ÖQÁwN~ÁëÅ"o @£Œ‹jùÊS W„xä\¨‹bYí¨§ÃW=‘ôWÚ¥Q±˜â?èÉàu‰Pt&]ÄØïá0-âY·Êj Ö×MMþX,MmâèSœÚ¨œgDåz8º~=)«=ÍôAž»Z QJßå‚tm.Ò9èƒUPÄÿ-3V §«²”Óy¸ÖÅÉC£\èk¾rè¯Ô /ôYÿÕÐ\9s‹}0Ë@ÒzV”w‹Šzy•nT,P±@Å ü×X€_t …ÅS«ßeZÔö;„âÉ!T½.º¶œ.—Û!dY`„Ã&oá) :Œ ø 0žT+‚Ux%egžÆ+ø–]N·É%µ²H7, 6ªv"¹æ¨‚¿ §3É|¼˜ŒE‰"ŠËÖDhÅŽŸ6à7Z\«OaPžCñž‘ð€F’(fÒÍÉ¿ð/)jý—=s‚íÔþ0º*cWªÃ\È8UŒt2p—ñ“h5åM34 H€DhF¥2×ðÒ+¾@=8ÞUÕ„}Œy±€#—­ôqÆLT,õõµcr U8ÓÄ’-¤SÉØúž v(šlDw$Ì!¢Á–ΠþÍÒP-øº7)R_¹' ,Χbé´ˆ,ZMæîŽÎ Qb¯`dm¥š@Þlž;ÃÄ>즔Œ&y¬&ÇGà2½¥yȬ–$%Ý:<Ë<+yfžžu‚•ý†˜Óå4' 'ɺ cééŽP0 c“ FšÍ+ç-v““æ¨ËsM=úk êª[jºÊÎEyŽjÆj謇 {¥o‘ Ýa½“Rç§}èl´¥KéšI¤9}kë3µéDŠ”KQ®‡NWxZ>˜Gtjýɳo]Û盲Ãuèó5G¥õŠ*¨X bжiý£®Á¼ ÀU.5Ð…tr h0À:à*phw bÈø)Ó¢>—O ÁÁ+@AiœIØnñ_*O§8tIèàÕ%]‹Hà„u€ªƒÅÒ¾1*›ì¸GD™@â‘BVb7ZÔD—×#¨]Õ€»j8,|Ù¼ O'´L„¯Üf["0TÔ<ˆþœ‚]ÐL&"LjÀइ>»‹ñ­BÏâ6­àmÜðb ¶ò1^í…Îx)ÎÅÉ mEy¬u·~¾vD4Dž÷<¾óxsiµfÀ+×V“8•ã™8»©›þP!,ŽöŽ0¼aª5º‘łꭄ®$h·vÇR ZûÆ=WV 4hzœjCÝ]ôPûòá¨s¦nfhÐ=ј¸bad¼Þêñci·Îh°ƒ82´‹é¼^Þbº V¦8ùã³j±È`µxßÕ‰»d‹e"žRœtÎÔÒì¦W&¤PP[/•Ý ÒÅbÉ8¦TU•ÈíõDd—d1ÆîR÷ˆ#¨déÚE<y4½2Ð2ÐÒ9tôªôœ'QÏXª%›žÏ¤“k]Š[ 3¥T%¥†ª-uHwU…\Ô¥tgtmd£¬¾fÂrÉ×rŠ”Ä\‚àT¥ Ó€iòÐU¾–kÓ}ÞAÎffÈÒ•J7*¨X bŠ*ØÁ-0|ÒTzؾjè$•ÁhXÑú`K üm¸ý“áõ¶´¿sÑïcÎ_A£…|*—Ïš,«Ãê°=RqÁlåÕy.žŒgÒ)ÑÙ³î@‹´^ ¾4Ü ³ òp0‰ÅRíáHÄp Ù„´E2õ»McFÔ’AæÚŽÈŽ® ];ql,•²»mÞ€9 ©ÂßNåŠ.·Éî ³è|¤“‚O 49 êz|ºÁ0ê¢È+ˆ"M¦ÀšÙ ™ tŠÈÏq Öd °ŽAÂΦ Hdû<0»SŶýÚ†Z7òU޼ɚ6ä‚ES†ÍnÊ]éL1–qÖÖ wù›YD¢ÄG „⩪úakZZ|¼< a Wï³×x›Ùã÷âd^øÉ*_4¾ïNãk„Ÿ‘ª©ö;ño .§%YÈùª<09zÂ=ø§ñ¡Øq¶çã†Ú@¹`KÅòV£-—.&£q³Á:¼±!—ÎFº»ó霹•¢ 7L_µ¥'ÔšJá°Ï²XHÅ‚¦D¸Úiþ¸a¡–Õ¡öÕ>[±±Úî…V]ˆæÓáõ¢‘L ¼ïvä¼ÑÁËl…"úˆnÖM¹ŠU"±$µ»š—%ûì»_8'(Ý’v„4*þéá)TúP±@Å T,ðßd ;p°*W™âv(çvã 4(ùó$7X„2“Oû)•ÜŽO MÇKtÒÙ®ÇÎé@VíÍ¥ˆÆ1@<¦l€C,Âå´Mš4Éãµã…Ü»×^{uuõP?ñÉ««áX;µðxGÓIüˆx©K`מNÖ CÀEÈ7ކ`J«÷þymâiP”T‘ âH-¡Ð/Œ9è‰:ËpØHºr ³;QùYµOT± øÊÙívÁœ”œÚ󪫢¼È&W ƒX]âºÆ‰ËÎB:SÙ]HRVç@Ç6¨Å‹"ñ…äyåäý 2iQÁcÙAK:…Yt:·(¢ûÃÓäÁ«lò"ëüòœä9ÂmÍz’ÅT&)œ¥êt%¾¨Ëé²Õ9zÏå²®$îžúƒ>îskłߟ3_Õ¶àåû°OýV nýôúyÉÛ_t`Ãv#75óÈ+mx¹g[×]I©X bŠ*ØQ, è@};ÄW*¸Ðn6¢ûA?ºG·õ†ðñ^ƒlÒ5ŒÆÕët¸_¤ÚÙCèpRDÕ.í5fõ¾;¢Ÿ„É“NÉFÐ9‚«†ª†¢@…”´—ÎEÂ1*Y;Z»Û[báŽFàôŠö®ö ­Ú;;ðzÆ’‰(~ÎH¤‡€/‰ûþp2òÑŽw$©!uðA€u²e3“éì;\¾@ G$ž5Z\V‡?ÅæX&×O†¼´(æ –t¾Keº;#|º:Ãm­Ým;±z¨;šˆ¦Ó)ÑsY¼¶VCQ>PÉì¥YÁ°NÛç퇲xØ=^—ÃíâµØ”¹VËFy^xؑҀ[Ì>TÖ6Цc1›95jxÍè‘Cy‘`&µ…»¾höEüè¤êB IDATÜ|âé Ÿd.ŸESKo]Õ Íáu=o¹Å:‡#0·^‰$öÁµzòK•Y9’5¤´Ó2ú¯FŸ58ÖHºïuùÏJá«Î¯[dÞsì(ÿôö£HôL>ãÆ»|ðÓ£ÏüËzÓð½÷¬K—–†ìªßs×ßÛÆ}ë±ùìo?ºbS˜Çø?ï>fÒݪ6óC®ÿýõÃÿúAë¦`‡Û`þé¬á™|î¿>)óæœµÑ­4³Í5\|ïµ;¿õãc/þ[‹eÄÞ»W‰Lºæ××ì=ó²#:~ôîoçöšqÿ•þöYX-}´ºÜëŸ:ïÀ™KÚs¾]O½õ® Î}û½+þ†æ=·jÆ6ýý¦é7-jË=ä‚û®¾è¤7OýÅG"B¹£çýŸ|ý»¿ÛXµ×ÙwÝ:cú«sïÝžBÛ¨³r»bŠ*¨X`G²ðWDQ:åÇ^ùïJû¥”ƒN¾–ÁHŠ(­Ää+×ù¢D³c Ñ¡òØS¨‚_Bµj‹ª-åÆÅ8jÔ(À £)‹o’ 7nDX`:ZÕPc 6 ÌAq€`:Ãã‹Î-B!á ‚v²« ?+oé‰ð·n}'žlôŒéPˆ+üÒÓ¬Ó-± éžFKjP‘å <奿MŸQ…ãè]dèpÜ$ô\ƬûC)2бêÚZRëÔ‰çñÉrÂí«;vì†%’‚ ˆv¢*m汩Pe³SDdUÄD*„LÃ5šÎô“åõ˜³b±œUú`±æo!Çušã²Ì0Kì·è…S«öˆÓ"r×êiŠ"б`ÁÚ<rVªà¬ó0•ýsXÏP0š7¹h…<Ô ç†F¥œe6È>Ó^Ahâ¢s _žt2H6ôEڙ鰀œœáªp(’yŽ%žœé6)pÑñµ[¡òØlt˜CE ‡¾!»' V!—“¡¡¡#ÝÂÛˆ~Ê*°[Úê7C,)ëÙ§HOʈV¡:Hç,U;ÑÕŠ‘kÂÐk,M–^YPªPš`Á"õIª£>Ê):½üU7]îƒ.¬ó”‹—¿Òò(ʉŸûE 7½Ó.þÓãgŒ7òëf]uÞ¬Õ‚Æ7?ì#Ž»è¬š·o{n…Šzµ]‡ÉÙtà·Ï™Òò܃ËJæH,yñ+§Ÿz”—n[5˜ö8~§ž—~½LÀtÃá¿~îîeËö~³ßÌÿ:_=çØÎîT-YšŽ¼öŽóOœyÀé-μûê«[ü½?¬V¨Ù>ú˜ OöÚûm^Ø=vÿ=«ˆf[9*¨X bŠ> (”#H‰x­¿«ÄÇJ@A»èømÃë§®vs†å>箸åŸlü|Cs­KøÈ¢B» ï2Á§ÁÓâr~qC DŠÁÛêñHë­-íÝÝá¡Ã©ª;(úÄ&³(f¸6\§6«›2ivË%ѯhR}"îÑ«¡CE‰yéªõ»è>S?Ža«•L§!Ú cÖ²e uQ­ô\»ç‰ èu8ðÚZ š|"믒†n¢Æ&qïX&€¡Y€×ó ÁštŒÚ’AùÙlŒ[øV‰,èó{)‹ó•³`ý"áec\:§žDAÌÊ»*æ:`ß­Ù┃ÑU0x0˜ÄU Ö§-ìF:KqáËCqÒ¢¬B·ipʾ!õ3PúC,Jd,H‹ÓŒ •X3Iùj5a`–+Œ†¨ßžÄW@™¯z6ª9o úò<¤‡}óHäò´4¥ŸºRßÇ®Óut¶òY.¶B˽w¥Z™ë;4ž.F>¸÷¬“?þÎeW=õZë37ýø¾WVi@ªG=ØÙµó7.ùšãÕK3?´96®ÚõòY /—¢‘w/þÝgÖoB²CôÃ{NÜûžÁêÝÞ{ÄGòVOþæ%Ù'¯=aÏ9©Ï¼ë¦ÛÎ]sêí e‚ŠÉ ÿ¾2wÎÁ'N¿~¶¾˜9ºà¶#&Ýå2þK§]qÕ7N¿èé¾>^kãa—ßùÝâ#3n{³£o×éXÕnW¿¼ðj”&=2söú²¯>»îÍÇÞýî5§îó»…¯v6ïsü¨önÿD!ô¶?Ÿµ×øæc~óàñ³Î>ó©u›5cuÐÉ_Œ>qÞãs[†àó/t|ÐÎ5ZÝ* …\¬½#W»ë^»^öڢů¾8HŸ*·*¨X bŠþ“Ü¢Ž-* ¥‘('ú ‘ ¢«€É4RTF´m Ú òD°Œ`)¥£gõxĈ +‹t5@HÀÆÐEæÚåvúýUÀ2@-z çP8Š‚D$s{¼n¯ ¼È>BÐ6R!ä1›³²…%ãl }åB<)žïü[ÈÜH0ƒVQê Š¡zŸŽ:¾BÑPLIA””R1zF6úL5ªš z[JÖØ­µ^wµ1ë·ÝÅ"ðßm1 [#‘3Ùñ™ WØë«v¹ýøœ³ 3#êoP8À”f¸Ø¦‡ õÆác×·ã) ›>Áà D=Ä/pÎį'¬rC2p1O$LÅP,•Dâ/ ;Í„Gn‡²µÈ{×Ö5€\ùŽYŸx=~Ø.ŒÊöÅ–õña×yÜhKÄÒ6‹µT[QƒeÓp¯ ]™7$‘L £Ÿ=8š*òÝâz4%Lg‹)çÈÁŸ`}ba{¡„£‘my¨h`'Ñà˜Y”n­FÌL×²Ô ÿD¬˜-8ÅqŒ"ˆI(!Z³M´5Ò6žÀ‡f¹sé<*Ú©|‰‡…øŽìj“ ˜´ÄSsX E“76³œcG4‹=„0·ØÄ}œ±³°‘Ç‹´¸ZõåňmÙ`*ë#.dNŠ Yc[a4‘½(ÓMõÌÅ -+"¦/úëàl®Õ!9ôHß }ÍYctÕ®@vi¾ZÔw{oÉ 1ãŽwlîÒ,ÄWϾçœ#¾ð1—?rÇ)c7mϬçޱ_»è[uïüü¾¿um‰9áOµëØq;·Ç雃éÁ*üÔ÷x”2š‚¯ÿâ×W‡c­ï=õØr×´ÉCôžIçøÓîºý˜µ7yÀWÎy¶aæC·nÚh©*d¢­‹fÝ{Ë“Ñ)ÇîѰ‰â˜¾êîó½Ù“«¶—Ãb0ô¼ÃQÓ¦îsÜesw»þþ ÷®ê]d»çýé¥ð´S¿:Æ7êKG7®yöu›xæØU=¢¶~ÒŒgÞ—m‘‹^¼rZƒ¿Î[Úã˜o}劳¯yoÈwîÿ˼×î¿è°Q®Šz ;VÒ+¨X bÿ¨U(+Ì!ÿÎ RpKƒfΤ“‡"\s¡3𕲠$¡Ïª0(Ô¬Ó jq£Úí8Má$Œ5 ¶ô°aÃÀÓˆ`€N]³fÍ'Ÿ|‚`ÊVW»©šÑ!Æ7Iqš ¬… ½³\Ó=å•P‚”Ãy ›ÀEÀ–dCODz‡IšÂ{ÂBé Æ¤ë?‚sSWÈh¯-ž]í˧8­ð•‚8SÉÀ@¸¥‡©– f¶ZªU‡l ¤ÿ0žqŸ“‡ƒ‚À_]„ÌTÅð©„R–iO9-vtt+ÙÑë RøJ6F'nþ¢8›×¯_Ï5õ“„ÍM,Ã5¨Û 7Æl¦8gÝ"ÍÑ1:À!QqµÅª\P×$ŠgЪ7R‡~¬ÚÂÔ&+(§G¸VÔæ+9©¶<:ŠÂX2FÖ S£1(}‹ iˆ²ä¡fjÐ;M¹Ð\p%µ± BëcôèÑH`ËÃS˜T?Mý(õW}M£¡uÎTB[zªëÙËãÆº•èê3ÝèsÈä×Ý ß"º çrÊdÓ YÙúÌ]à4 ˜­o}¾)ý‰Vd:çþöÎG¾ò«£÷öÄÊ[3 6ï±mÄ‘3ÏýáϮݲ%šþ̆V ­[´12,S²¯Åpbè÷ž Gœ0|寮˜Ý’(´Pr£ªm‘Ñü8A¨†½-J~f ˆKXA=³Óaò8%1  ŸSüÜ^‹±Úi«¯§©¾¶ìHôð|&ë øu(mÈÛÏWåöW‡Šxv³ù”X2'¦Œ!–IÈ®ACÁí·Aò¨©oZ²j-@°£¥-8Èȸ4ÙQ˜Ä¸aÈ˘ÛjG±™ÈKäšڪõ:p‚WU{{ñH(R´;â±p®ÝBOð cgüÜÁ`<FÏ”OD€¤áÎô®»Ži¨ æö»ê±yÑdHÄ’²+ff‚‰a5Zó» zI1S€&˜‘h“gŽ´ÓéF(+À0áÙQˆ50$ÛMùmǼUÀþÁ`õÛ=ÎXŸñâÙMsN›Ñá÷¦°RÏ`‘$É —b’}“f«ú4a2ÑŸæ‚GÄ:»±0á±g;;42ᩇ ‰m.xA$Âm{rh•1?dùÚvˆ¼¢ÈäÐ 7B,ž&,%-”é3C`•D÷¨9]”­±¤¨Ù®ÜØLg.'„C†ŽÆ´Ðx7#Oµ[9¹…‹BNfo!ß ®Ùž[R°7Z·¢ÓýæZ$] ‘šx¥C×°ãœû°µFzÖ™GìÒ\åvUÙçðCš3«V·¹½Í2ôàçOYùÀÏ_Z»moëÃöL=ÿOs^ýٱöSTn«%V¼úìÇ£Î;iÏF_íäã¾Zýò´©‰u†ã:lZƒÇÓø…/}©¹ØÖÖãrO˜>ãìC&Ö¹œþ‘}É×½ Ÿ™Ûªæ¡žs”ù™{úcTÒÒ-£É^³Ë!GO²l\ÞÙG$·þÍÇޱɷüsŸ˜×±ir1¥âÁ ÅæƒöpVïtè±_îîK¯~ã©•ÃÏýáô)µN§¿qÊáß9ãàfív·øêÌ NÚgt˘h_»¾;kõØw8ù˜m›ª’£bŠ*ø/´È”z.”»¯€¸ÍHÔ‡NQé v¨a )\ãå¢ì‰äš 05kO-ˆGÐZŽ"´ÑÃñŒÄÙ8‘8 uÍ4§ˆÔ ÔÆi v¡i²!…¯— tŒÚÒžN2p—FÉÚp¦@Rµ__“¨‡Ã™CZ׃‚3_ñ£CËü)N¶ð¶…H­nÑIú¦kæÈU#-,IEˆûHÍÚmÌÐûÓúš]­ ¥]žÀbZŠK(D·uô¨ÇŒ ×N_úC%P”ñÓUíÁeø<´žžÂ’%«Z[;C¡p²Ðµ1ƒ¥c\kuBÒõx)…eôsaDt›åAùЈ~’Nñ²‰È©_2P-5`l³#_õã ·¸ÉYÑœž9<Æ…¹ànù¡`@™(;¿u»zFéü´Î]=Cà£c ®é›yh‚kzHßô¬ 8×t˜Á’Y§ëɦg¯®\O=+ôx9ëy¨m¨ÛÒg=úV¥+ÔéL= *J22IÔO»é¹T.¸#\lòOg£=ö/Þðø¥wBòÈw~ôü//¹õoÝú/YåGŸ¾f·txÚËÿ¼:ñþO¾VRÍ Œ?xÏæú†kg-ºV'³ø§œ|w¯FÜ&þ´!»ä¾“NþE_9 Vº¬ù,ÂöÙ®£zßžyäkz;â~¯-ºÑ°áÉoŸxù»Jß.µâW\[㕼}5¹ò¥;.½æåj×1ÊÏ^wËè.zøË-†ØÚ·»þÆ×Jžôl,ZuðµÏ]\k6d[ç=yÇ÷~Þ[È`ó©iüÂ¥/.¼´Ôµ~øßýwZøÓ^ÍŒoŸ÷ØWÎZ«{¡ó»ßzÖŠC¿òÆ‹…6/zÿŸ½zóUO̿Β\üÇ‹¾ÿrévvݳW\â¾æ†ßϹމXæ¼ßÞpUi‘“é^Ý¸êÆ®ÆÛ¼lË»¿¹áþ[TÚ+© T,P±@Åÿ¦4tÐ(ÿ¬Æsüä÷£4A:)œ7p< ÄkÐkP‡¶(’—–ïTßPV„Ðoq>BEHç2²@Cp¨¶éŒ=•„vl‡.žf‡3—ÌÆ“©hûDcsÓÐϾÕÿÙÍÍGÿâ—Ç¿7ó¼ÇVn‹Gó?k£ÊÀ+¨X bØûM?…Þ½ñ‡{Ç' Š3éà]ÎZ34Ád6ñ4»-¶6²¨ 8å-¿„±K»T:D`À16¶–˜,¡4Ã(*/²ð•@Z’egÍ‹'¸Ž—Ñ_݈³¶£½û“OZ|>Û®»îêñ©7–DZ„1¢ÐLK8+œc§G˜¸lœl삱b©".äöq™çÁnÜ^‘lÊZ ⪄I³Õ7B˜{lÙ8M4ùÝx^v =o ˜¸ÆÕ ·8›5Œ¢N1e²í¾ûî–šzÌîÆf<¯„Q'Ëd£žÖîNÒ›š›!R•ÐÆš~ôᇺŒ9zh´HÀ,lpº›”4²Eш-VêYÛÑÞÖÖSW_%²Œð˜Ã=°µ‹.—)š‘„ág“caSë³à´ÎÄB¤ì2qÔĉCmx»Ý.‡ØÓíÜ|çP4ƒxB„®Ív-‹°ÒÙIOXÿœÎ‰Þ³Àn{^ø9ÄZ”Qç²ðy²yársšé@þž8}K™[@´R›OSC*-ïvÙ¸ È3Â=M o))õK[êE‰kRÔ,IpBÇÈŸ/H|M‹MlÎsN,q¼ÁX²dÉÂ¥«y5"‚ˆfsNq–$x/Ø•"ÊI¯/JŠÕ5Ÿ^Ívý*_&B v«)Æü´(¬¯ÔÊ[—üÜ”Uy%³¾Ðg²q¡Ïú®\ôC6½!é“.—rÓ_xÑ%k•Ý;O?Þ·ÎÏëº?þôçÕ—ÿÛµ×í²Kc÷Fó¡×þ`øÜë®V"Ù•£bŠ*¨Xà¿Ôbz† P‚öÏ©|9`VðÃ# °dÍfâ‚0Š&ðtb®Ä I»%‚4¸M•-}Ftß@$ ¥q‘:†ÕšÏ8l p¸òÖ;•$-%X_Ý4wU·ÄK…”J¤dG  ºLÒæŽ†Ó ­ŒÑ/AÕÞÈp¼MðOL4($4 U#Ý€wš´¬R2±J q.9ã"Ö¤,0Q€—VÇsÙj«}C|¢Ýpá-íw2Ý쉄#©0é)ƒ#‘Îü&L ’!0«¾nˆ›1‡#v{Àãótvwvtw:ÜNBZ‹4³ÕBÀAÚÌÒc^øÈÊI Í[ð´U¢áìEC&‡óO; Íbö]fÓqøì¦KESá¢ÎI^ øQ„`Î9½†Q£›á'B]„72©$Ô‘6lðÖ7 `Hk ±Im:-é,{=ñÝ vÊ™•K˜Wâ–5‰(ûµGœþÄ—HîÅtR‚Îä²i£Ëj¶ "QoÀÊN—¹`Õ;VA®ÂÀ‘t‹¥½£š7«Ÿ_ÂèXm&Px"’J$bÙ‚p38 ·3 X} u™Cm%$}ãM æœ`“ÛG&gšÇf2dí2ë­ÁpÕêTg(ž3Û «_YUpMYÆÂË|£Ç”Aï|Užô¾ïÞqÊK¢jKÁa™!|ÔŸ…JS¥äØ@—Ó·¸ÐˉºZ5’¦]Ï@Å?—ô žþLÌnªÛçÒÇ.œZXöÌMýü½`ùßÛϤñJ# T,P±@ÅÿY IÅA¨ÜÄâTP˜ƒŸ|MaT‰›¶^“_VÌ¥~Àa@"ê¿pWa²‚Ì\‚• —BPè<™)KAÒ†€*\~”åžÝLNöÉQwI!› ΂’ ]û¹¸â•– J/¹`ö6®\²Á¦ÀYd×a¡‘ÂJ}ˆ™úš‚®Ì&0h!Ÿ|t‰!H=éhÙœ&‘ÞÂÙ…P€¶4 Ißè8iÒ¤¨’Â@£D  Ã4g øeÉ‘Ú^4BžFÒ„¨+=×Ss^ܸle'Þr²uIW¡!-¸´Áë‹(]µR¾Z$®a1ÅÜœ2ú0;c!§Ë•«®RùJÓXn1gúIl%õôúMÉOÐwyŸ`•7Ý=!DÑ !uL#öA'Ž¥C6FN†Ì5ÔzÎzJäs‚zé(·hK=#y"ç«Ý)ìg4]øš#^K6«YìÌ+ig¼lˆo4]b\òœ¨¥NJq¶”võS¦çºi1VAØ þ–¤Bÿc°ã žQh÷‚Ñ&<"§K¼Ñ\ÈèzQ°j…-†òâ¥<"}ø¯ÛU¥J3„[¤ .¢›È÷ò…®MçÐÅi\µ¯Ï’Ö{õØãå IDAT·oM;âuO&O%ùñ/§ïòËϤ©J# T,P±@Åÿ×^òXÜ,Ъz ¢P€€4¨ˆø# Çà¤ÄÁUèvpx„6 :æ ‘–:qYJ%W‹?X>V#¡Bl´• GºÓ‡Ùä¤NÜšø®ín¿ˆrðR_öpÎâX5¦³)‹ ügöô$b&Ô! ÀtBÓ]dèÐTÎ+4ÂÏè‹ð°„Gä ÉÃJ]£ˆd2“ ÓBÅ(žrËj™mL‹l\(ÔCΔMvLzY—Óe³[‚«ÏÖí°%Š^ŸhsóúQ’p¸Üx}Óén 3¾X§ËëÜêóyÂP+`eñQWß0´iXË'+,6k!+$˜Ù(–ø,NÈ6 y3£SÑ?¼.wM ŠÀÜìt³÷Î\ {Þm3­?ZÕe;&%Ì”š¡g'ÓÁàºùD™”a#j,€ðu¢+ˆât(“ß0fž¯¶z. o‡A.…Ì#$á<N ¼Âé„â0ãÅÝÙ«JqžNÒù]ŒEÀ±ÕaÊÙ¹)aV"Á(Hš ­B`V*"¥ÚÁJ¸œì…ªA=Àf^>Øêu„ÑVÌ#1™K¹¢¨"²‚ ëÃdFž[Ë$úY€ŽÏV>4ÄybY¨ïì3cª2Xÿjª¼cF5g qÖ9‘¨02Aü‘s!ÏW­—˜oj†o:ô_–ˆ“EKQ±B$MþTÎòµ¾`:)*”¤Sg)·®Eu ·ú¤É”Óùˉ:EÕmõÍ¿#\WðôŽð*}¨X bŠ*øo²@@«ŸvñÞñ&ZLM•7ø€iÐh‰SùÙV„ Eâ¾r âÄ3Jy¼Á>®bŠoS"‹æƒT¢|®áž05TW5ˆ—4›WiLü‚×6¥Îx² v‡Ñœ„Í]`k,bLuøOf¸†S‚‹RÜÒê€>`à%h:…FŸËÖDqRB& ËY#§D^‡Sâñ r"â9®¯Âêõš`'éiÿ7n×H$‰¿‚ò¼yóêÇL Nä)r4›Å'mL‰Fv —n†¯œÐŒÎ3" §˜YX à»pÁÙ ^–+`l›pŽ{¢rú=°0S*Ô;Ä­Xhp×m3ãö†ÈŒÔ4øzäÈ‘ãÆC^ƒ2^à/íj-”|AP&!ÒIa»$½E²l@m<®-ìCTnoýŒôc’Rú-„ ÏWžy­08à¾ÌtëÐðK áX‘íeô°X ¾{ÐÐ#ÜkØ;ÑÒz¦¥2Â,g¤Q»´«þtô#Óï ØÏ(¶2éŽ ÒSS4yFé´g4Ù9Šj×®‹Ñ”2ë8ž‹`é}‹ ï>_ův¯ YÚ”zKÞè-/´Iu ª[ºà–©½nrõ'Sr~kóÊTTÎò n]Õg–RÁÓŸ™©+ U,P±@Å üb\…Ð-ø±L\ÒÓwŠO(k *ÞfñgZ 9cÍ& šmƒÐa%™6îuÚ²É\8Óà³»!Kq…Jµ ¥áÄ‹ë"æˆlA+d‹ÉLÑfqôtt uT'ÃDÕ&ØŠÛ˜µÇR]P‡ád½æ4qüBâ¼p-Þbd8šLÕ²[.K¡CÝ•6iðŠÀ¾|‘F u•acTä%>òDüƒ`‡è+D„Ëè›9'ÊÄ8̯M 0,†DÎБ2|žö¼/¼1±Ó!9sm2_¾|9>z'!â™ü‹>èèé¯,¦Ò9 U‰ÇR­ë7ލ«©õW…{"DÍöÂsˆÅ†5%ñœ±`«õFM ¤hÊ~¶»£ÊéO uìrsŽQé,ž2ºrÁT. Zµ5…%’-X@ÉAE_Û0¼àñãö[C=¯÷Ô&³É`(íINÖÐJÖÖ5›¼Ë[o½ðzꚆ[mšM!Ìéd6~Å!MÍÑxŒñÂåÆtp’¹ ¢·ä,ÅtèéF¿Ãqðš…éý<›,‘ýUŒIÂX2iØhê*²õЃ=î{De'„¸XÕãµ$!·ÇgwxÛÚƒ¼1ðù}¼ àµábK6Z5™½¼ÌâÈ„&^D®ÄVÌ›Y{Ç Ù=á5P7¥bPÊ32ºØuÈ[Ü"A1s5ž¬w„±ÚUììÌ-XóÛÀ+Ö1ù¢YÖ*¦–#‰ÃŸ‡§p-³›àJ€­¨÷ì8,ŠRˆÙ%j»ú B ÿ“5ƒ}ÞÈŒƒŠÔýJÖêN)¹tÑ»±Œ›õú ‘oÓôŠ€õ^DåØn ˜‡Ÿð藘ߞõqx³×Û]Á§ÈøY¶õ)ºUÉú¯ZÀ6ôËÜûðon½üG3¦øhÖkk¶+´½UÿûsÃÔ|ÌÃO^awÖâP…Ñ¿½f¯ä«X`ø¤©¡må‡Ê린…8óÄ͇ýú[ Uú‰PÞ¾ŒD-! ~J¯[8fPY¡` £Ös°+É4TdÁ^~¿@ (Qì[ÁÈ?P6w2@/f&%"Ó@=RL6ñ‡ƒàÅ)i4ütq¯ H ¢žh<‰×¶‡‰È6'!RK>ÅUxH+Ú-•Ò~O5sôpu¬ ¾1R4 £„‡ *¤÷”¡.B#ÒJwwíÖÖÕ€)#Q<ÑÙ‚Y¤³EÓ´iÓª‡4€Gò6åãÏæÅ? „œm$–9ý\¹t õ8Td> ¡p¦ÙX‡ÏU·¥Îˆ˜`.]!¹Uˆ8 d  5·¬Ý u ]ñ±R’}‚vù¥qÙ3N"wô?ꡬÅ(îdQôß¼xyÈsðfAÅ’!=qË]ÎÔVÈŠž†GÉ„# M°/}f™„ŸÞçñ’‡j© Šz¼^¥ryЂ/Êr`Y­9ΦJàFYÒ¬ÕL©–BQAUÂïX­©4‘×KÜúÞ™'OŠ·ꑉmˆEñCabE"FEcQìj§C"ÒÇs6¶_ÆâXæÈ¦7ª ¿¼€Qgi‡ˆ.\ëC£[ÝR9q‹‹ÒÖÍSuÁ~‹ t‹t™&Ó^{ïV1øÖ-ù¨ßJ>ãÄ’EŒCxhÞ‚?|{œÌ9,#¦ß?îCÇ6ë fÿ”“n~úeD½^±ô÷oŠØíœ|Þ³ûýéãtŒƒmÜ·þôº”ÚV…ÿÊ0ùùd¾t üYøØ‰£z=ìÖ!ûÍxð/swþ‹??}j@)©ÃäÛù·<;gùŠ¥KÞzäÒC‡õ¢n©ÞåÔ;^^<ÿÑo”+úWº¶]m ØCÏÄsœ£µäíÇ®<¢7šËà=1y'~íÇO¾»xåŠ%ó_¸õÔ©þM#´àÀCÌPƒUévÈÌþH=—wvLSù¥ÇÀ:ä{8X/º7Ø´Ù¶ ]Ohþ¼Í§‡½ñKgÝúŒžŠ ^¾ÿûÔoùš§¿RôÏ2ìÈk¯øÊÆŸ³û®»~ÍŸ#æmG2ÔP Ùàßóº×–lúKYúâ¥Ó*Ëæ­U¹Q±À¿`ÎP¿ë T•P£ ²Èô!O¦s)BÒ ÅCT~iÏ&!A q(Á4'P}bd}[À yÅC6·~€†‚ž“ PœHÂÊìa3Pý@ÚÄÞ9—°Í•h!]g(ÎEÔ˜»‚¡Ž®`0&÷¡8žÆ¢ëÒŒàøMïúo©C÷¤ü•"üí耨­‹ÀJŠC Ö¬î¢!J'ºã‘ ]í]‘dªÉ\>œLÙþf2#{Ád/â@vðO 0ÀF ¸ðÇ@3.@™ÀÓººšX,BOô†<ŒHçÕZ@ ¢À Ç›ƒœl@¯¹»»§¥¥­µµÑ¦ÄÅj±¢» ÑÁ”b>ÚìnoCÛyxc#þõO–¯ˆEBÜ}^÷¤‰L†\wg«F®ŒZ]°Z€¨ìTÐ ŽOÛ¬p·!y£Ò-xš›‰Ë”PàRéx ÉšOg°Ê~ŒŒð:Œ#ÊùqfsHÄ‚j#ÕÃær{n·—G #pÂ`yXL “Ì>RLéPb2BŸ6 ÿ%ŸCµ‰Äld•‚—šFaÅd“ø«QÈSlÈé9»3ÇnRëµÉÚÁ¦F Ä g²6äxQ.!iݾ,²6­³¤óòz5ð~ŽáOl "bõG7P†Ï+}Ó Ã`tO=öÐñòJŠ…ð¨/m÷@ù¦gò7ÎØeÑÍGï±ë”½Ž¹üùõè’oû¤Âmî'Gaà ßÞ}§±ãÔgÂ~g?½bÝ’ÕÁ’fKÍÞ3/;¢óçGï¾ÇÁWþc§3.8|x «˜jö½ðÎŒzëâƒvßïÄ_…üÉMßÚ©„¨=“ÏýíKw}%óáÚÿP”îAÚ2ì¡Õå^ÿÔyî¶ËÄ©ûŸöXîÈ Îýbu?Ãß<ÉT»ÿEwœ[óòÌCwßýà¼TuÖ-P×çiPÁ C´óTG²¹æ€‹ï½vÏe7»çä)ûyÕ+…Ò,¤ÂA†ÃáÀ:~¤ž â}WSEÏjc% % ³æ ט‹viE§P§žE×íÕóÕÏT?VΤˆ—º´ŠI— jé¯wcB–„šlcLýp9Ë#ï}M¡'CyJèt³ï­í¹¦Z]s9³þ ¼ìEÏü™ÝÝ„ÀXTæFrÔ$m»ÆzäXc¾üko÷uFΞ³œ8GÝËÿúò»¶ã5õ`ªñywñÔÜÙ¿8~xɹý)m®ÝïœNùø¾‡ßëRF Zœñ–õí‘HëÊÕ1¶Rkdªÿâ×(¾öóGßÙÍ:‡ú«w9ÚYç².½÷ä#ϸwNGqÕÍþOþéï-Õîðwï;¤¾Oöæƒ.úíß—¯˜ûÒ­'îäÑË‹ÁÚ2 ØCC¶cþ˯,ÜÍ™]5t0±úѯ)ý¶å½ÿ”Ì>3wc(Ü2ç¹'–øúÆž åõÚ@xȃvØ<€5l#;ë€ðƒWßóú'ü{ѽìWßkÕêÚƒU8Èî¡Ä˜zÊíÏÿsÅÒsŸøñQ#$†Xï1È­r–ͧÍ6lhm>âÚ«§Í¿ý¾¹›Ç̶¼ýðýÏÍ[Û“LGÖ|¸pc”—®›÷@¥èƒÑæXRñ~fÛ@æÄPjPýÎM6éïÊè{ìu|›wMË߸u¿Úþ²TÒ*¨X`[ÐC£òYþ&å(ái¹*ìðCš¤’΢‚É4á)MP2З&|!á\(æŠfü­ÑX¢' ‡¢ˆLãÐv¸Et‚4 ÀR}&ŸÃ㜀œ"<z üáh,žÌ%$aÐo²‘Êí.<ØEt=/jl ãL®û»Å¸ø*âÃò®\)Hº|€Ûä×%Š›c”BŒÝÉxW"Î¥z2‰¡`Gª¯ÝSWÛÒÞN,Fܧ=A5ûݮڀ°¨1(FcYØ£oÀM† 2êh‘âî-æ­Sã· W!z| C›ìÆßœ…'"$aàˆ”‡„¼´ HxB‘‰êb¶8m6§Ùl3À­¶‹ÙX¹ l@”%ÝXëÙiLÓ¨f—嘱*Ö‹úÃ;íçŠòÙ4þWåÕ÷/¦ßŠË3³¼Æë7Ûç’ØÇ£\òçÅÎZm¬ú‰ÛÞ›½\h÷ê.|ü…à—¯ÿéù_jfOòöƒT¨«`,믾›ÛU·uØQ×^¹Û?n¼åõÖÒD4;þ~ÿ3ñ“îûÍÍ—ßvÛIáÇîx}£¾åjÜy¸aÍ?> ™ë¼èª}–üòñUžGU©:>xóÝ5ñ>ÿ2ôiÝ:ìèîþј×»ï®û}ç¥e[¨<¾]¿ãw\Oœ¾ÿW¯_¼ûŒkN£x2ƒµ5p¥¤wÚÅ//]¼è½çn;à“ûo›µºo¼—þÛJ×Åjö>t¯^‡ä!ßúö®Uža“UHxV÷v~à!Úù+ ŒÙ»>ô~è‹W>ÿ ùÏÝpÜxÂ~É1h…yàòf±éÈkï8¯fÖ™ìõåKæNyõq£z×bƒÜÒ6«l1mµ¡sÂ)?>ÇÿÔuw"nqÜEgÕ¼ý«çVƒMŽK¹¦þà™ÅoÝyÀ˜½nzŠÎÒ¹¿:dHoÇy^dùôsCÕëš|Öç­\òöó÷Ì<|lé‘l®;à’{.Û}Ù­Çìñ…ÝŽ»qžìh¯ T,ð©- Ý~+ñ3¦°ŸpOµç¬ïYWÍ]rú‘]Œ8ñ\jT¤Ñ¤vm*Úq÷Úµk‘ËÀ7I½º €Éü%‘JD¸'µ§“» lœßÔÉyH¡rÕ19øª±×Úu­ÝŸºZý3 šÑMñ÷j*¶þ®|œzy †ÀGB JLlåæ+Õj|Ïx¹ÆJý¤Ð(ðLÓ[Úå@Ỹ„ém mѾdm.2S³®ˆRN=øb2µ©FK½ÒöÔžceDT¢MÍYšDjã.6Ñœf:wé*¾a¶-Ò2ßñÔ*U ¡RP ®§omz¼Ø™vfçšü M{‹¹ ÈÓš Ù]'ç)S9Ë.s†OWéw©ŠþAOú@ýš(O'‹®‡áè•wõs×wõ#ÐË$…±ä ˆ®œâÜ*×£HXÔxon®¯GJ\ ºè§!oZ¸â¬g‹¶°¾§{ÂYÏ.ú=Jmõ?ý¢£oò6ýÓånlUÙçœÐ:<3§¸×ñ{LžvÂÔØ+¯®H”ûVŒ|pïY'ÿä£)W=õÚ#—1fÓÏó`ݤBU,úá='î}èÌÖoó­÷f­ØÇ|ýšó†¼ô“{æ{Ñ4÷‹É ÿ¾27îàô/ykA[/"µ8ü–l$Ql<äÒ™£ÿúÓ»^_Æ*ÙçØ’ðºå8Üûö”µw]þ³W–uìb•¸Ycôý_\vÓ¬í«Þ}þï±ÆÝšÅ«o¼­z¨L±à¶#&MýÂ_»ðµ¡>pÓñ#ú¸ìûo+³ê©ß>wâÕ¯Ì[4ÿ‰s\/ÝõÂ:£Ç®ýÓÛèü–cÕßëüÀš]oõäo^rTìžöÜõ€oŽŸyÛ¹S•û° ·1äþ{h°:èä/FŸ¸óñ¹­¡ sž¡³é kô äV©²~¦ÍÀ64Uíyþõ'żæ±%‰þ×[ÀóÆÃ.¿ó»ÅG.¸íÍ=;+•øçÝ'Lþò%﬚sÙÁ;CÃØãÜ×Û{‡9°y%ǧŸCø×:iÂÔ=8áÚ— _½å‘›N(Í(눯|çË©?\yÛ¬e=ÉX8¼Å¼Àð•äŠ*ØÒü¨÷Âh`;(ssÆdä̾Ëh6·ºµ­`±;ýÕN·eö –°µ8ƒ¿@ü?Q—†š](€DI¡ŸßãpÚêêk›š‡Ò¡x¢%0 ¹Xư´€–žI'’ ©0žÁÿO C`<oÈèÊâ(˜ˆ núL’aÜqK× óÌB›½Î`§#ÁÞELš€2GSCƒÉŠã&x”3C4c|\Êø¼1k¹fQ.QÏ^[Œ5Hi £Ìu/O<üäl„¿‘Á›O¼C<ÖÂ7Šv5OÀ+Ë Þ',™t1âí>deÈpB -›=î;Y¹Ð‡8¯ßÕT‰‹™«ÆÇ`zEÑÆ5.?Zù¢5“3¡âÍ ÎAÂLʘJÓ¢ø°$ö%9Z&«1m*$ì¦t­ß6vÄIãj‡7ºnQçƒYÔ¦Z,$ê|JEý¯w ÉÿûÓ$öÍÿï\ë…Ÿž“ÿN=ÿeûz›‹ÁŸŸÜíüß›Ô=ëÍÕ›S: ñÕ³ï9çÈ£/|gÌåÜqÊØò¦>yrec [»• È þ‹£±9þÒïú_¼ñ7FúçøÓîºý˜µ7yÀWÎy¶aæC·ön™Ì¥"9kÝÄéWÁozðƒ¤»ËHªo¤Ì~zbª½k ´`Q[?¯æ%{xå› 6ªe€L1þõT}´­{ØÛ|!m]4ëÞ[žŒN9vMÌÚ2«ž¿þÔý&Â&ßãk7þ-UïÉwÇU—¶ÕùÞ7ÿÿ ¤ÂB&ž2š‚¯ÿâ×W‡c­ï=õØr×´ÉCd90H…Ûrÿ=4¸ªGÔÖOšñÌû²ÓnÑ‹WNkð×yõk§An©ÊúŸ6ÚÐ;þðC¦Ž=üæ¿~¬H£÷¼ñµEÿüÃ)cÊËÀôUwŸï}ìüËž\UþCÙf©þÇ5ˆy·e¨þç¡.UÌ'Ã-KÞxàškžŒá„}š•¡|Í_hL¼`ýæ¯[úïW%µbжî=ÁÑ Kk$ BâÒØšþ¾È%nb?àB|–`# p’DÅu Föˆø‰üÌ€TÈŒ³‚/ÊÁ8hI×®G 1q©Ò½âàX™¾Ó9=¾R¥8¨ GŠF?dP?c[Qõ¼tèß6ýE;}Ë †‚×íÒœpòC¨¶'r¢íCA‹ÓW0]¢89A„äáZ[†““üº?$’B"#êõxð"“A[œ‚å'£œ.¥µ—tót: »JbÙM ˆ¥Nz‚3’7Â#8ªÑº¦ ¶¸K)ÅÊ+L"ÓŹÐÔ~heUÙFIfí´æL zW%ÓUéçKp3( ¥GÄ]rb(ÜöÚY®íI·é$-–¢?ªzè0,<è†6iùÑœN¡zN6íÞæ¬MG]œäÑOPgcŒ¼ =z4/¼^¦YÙÒr¡›Ð}ëµ¶äØÂÚÚæ}Ï›Õòï}á/«üÐÿ½šþÃ¥7goD—¾ôrçȇ¬~æ5ý"ÉLçÜßÞùHëø£÷¦•@ò29Î’¿×æ­wÂø*q—ñ­m«ÂO;ß”OññožYÛÌmè™pÄ ÃWþêþÙ-‰î÷¸þ—&N?h”"×&Ú¯³ïwÁw½ÏÞøè¢¸¥~ÒîÕ±Åkz6w7oÕ õ>Kž˜Üqßcß‘ž­ò¨Wón;;ÛÞ_‘/ƒµ5p·¬˜ÙðCl™ºe[›Ý·6ïqäøìâ÷7(Þõvw~³:éü CëmŒàÐb‹#à(Ä"Wn-F7à7Ï—ìYß½ö‹ÿ®ú|áć—ëƒÜ’:˜6}«ß̆âߨ[Sù“\yèä©'?¾JÿQ˜|ÓλíG5œqÅs«{‰RÕॶ󦯃˜wË2j³y¸y)fÔÆÞBêý÷Ñ:t·Ç¶l¢ò½bжÇ#PŽ‚•|€hòƒÁ/=, ¬Ë¯­5)Í?“ÈLØN"TN%‘"Ì8n^Ú¼©L1™.ÄY>Hƹ܇Ӄœ¾d—ÛWS]çqûÁÏ JÌì&ä XdKÄÑœ(¡:áðB|ÍdñÔòa,`hbzœHY»DÉx‚²õ? )¹@uÜÑ!hĬ175pKþ)äØ'Ȱ¹Ë hZào!‹dpuzÝÐ'Šèv@€à×9‡Ûƒ@3˜H<µ±-OeÍ6'»/CRRI¸Çè¾ñ/¿xø`ékMm5h¤ˆ×ç.¦i¨/ôŸµÄäÉ“‘¡'º¢E ' };å³9hÇGÛBI²- ¤3ø„Å-LˆH¤UT4GÍs€¢Ž´b dCý2»ßësØìÀYöéÇòÇ IDAT)¶uv²¾¡Êå±mn¸Î·l‘¤x [çòØ*vÀçem‚—i>œÇ8™{zJ †€WòkD‹ Ù4èñòb‚!À˜[ÚÛé p³Z³ƒŽ°ža³%ÒˆhqÐN$ïêîA‹ƒ·¼ÌÀ Ï.DÀkwÈ®GYŠ˜ .Aï5ú@ouˆÃ9ž€{…M\„C‰x toÎA§.Úò9s"™#Ïä²¼ÉtC nzåt wÈ‚ n3†5TO8fü¨zèÔÄn$î"×yÜHk«}·ò£¢ç€†×z¡Âµ>è‡^-èN’®{ùïk‹¯ýþÝÉßUïÒH-´Úá®ï!CI.{ì‡ÇuÊÕ›ˆÉ’êyèYg±Ks•ÛU=fŸÃiάZÔÐ"Ó±tqlØ1ßøÉGáÆÃŽÞcXÃ.§ÜrûiÃL„aêó‚Ãlc¿‚«nç.¿ñt×[¾ªWƒµ5p î Ógœ}ÈÄ:—Ó?ò ³/ùºwá3sËÄp^´ôÛ–Á:dÏãOØ{”ßáiÚûŒk~8yõ×­`ø¶:¯­¿åyÎVabÅ«Ï~8꼓ölôÕN>îû§Õ/aA›<žA*ÜÖ·ì[é{zõO­~î§O©u:ýSÿÎ7k—ñ ·(<д؆ô@%›‡xÎQægîÙœæ>X‰Áï fÞmn8FòÓ_ãtøG|æÌã|‹ŸŸ£_§D7|ÐæÞëèýÆÔ;òâÛgîîïoá6xw+w+¨X@[ ïϼ†ƒ[FA+qyòfԨѨ Ç$‡CfPù5šw« ÄL éÒˆŠ²š-ë—š5øùAqj°Æ1Ú£¬3° 4D‡–„÷` €T­¢á²^ ¨aJrù–†Aº*úãv›'ÿ½7´¬ªÎu×Þk÷ûôÕ@ Qc‹Š‰÷)J&Š=Ï\ðb`ƒ bƒbò½€¢DŸ‚Áˆ‰$ z‘iŠª‚jN·ûµ»ûýc¬½ëe užkzصö\³sÏ?Çúç?Æ0ŽOš•r׿+/>ÀŸÜb¦ ™Ñâfä €bŒÙ‘¨Îõ`§\3/êr$q÷Ýw‡àK/nÜ€6ÆC- 3k.¼šuHÇèwèÓuHM¦ç;æ£ `L>Eœ ~`.Gx‘™%6éwئs¦)Iï ›|zd:>ßk‘ïØ×í0,ÿ”ô֨趢5HóÄÇ> †º”¤)ã«L1ÿJ]îR† fÍÜÅ*Žv¾r×*oŠÁSWˆÔ-û*ûæfñ)øúÒ2ýòÞcåÊåË–BþÖÓ¯bš>kA;+Ÿ&ø¯€·°õ_‡Gwן ÿ|t-üáj=”GÜ­­½ã6u·Ps£]™É¿àøsŽ<’Gwý¯/:ýˆ¾Ü¡>¹kN9ü¤âqüî/>;/9å#Ç]r?¿“ƒ!o±A¿ÉÓÔÒfM†øQATœAÚ%ºëÂOüÓnÇþõ+ŽÊÕ{zö§>ó£5޹{®8ñCŸ?úÓÇ_zÍd÷_žõ‰žysü†~êÅÇ_ð×ïl­ìó£›>Üÿo¾ñ¨+§ùZýõ™Ÿü—gœø¥8{ùç?üÁÿüÇϽmåx!X»#§žwÌ÷®>&è®»ö¼ã9ñ¿ÖÇð~+}me„íjerßã¾û‘¥„¦Zû«;é½_øÁê|”Gè‹®;þý—øOKÓÝ¿¾øË‡|î[· ï[üV¦¼•Áo¥Á yÇ·>vÜòÏýŸ}(Û¸óßO:òãƒÑo¥Á­Ly+# Ú÷]ø±#Ê?þÜ«>Ŏé_uü1ñ¾nk·ø¿€Gxl¶bÃá£õð‹ÜèKVü_G^|ý‘ñ½ù+Üÿí¬úï<ÞÐ g+æÝŠ¡Tû‘žzcéË?ýÝcWä‚Î×^xÊ{OþN|Ä5úíE'œºç?ò?~ÖùùWþØioýÄ«y\ÉĉÑCL 4ñ×àö)W.É?íB’ ú$Ô5Î`ü¹è9“êâÁ媔בAô“†ûÅ8&ì¤:¹n`ȯBÉÀ/± % 𔀑y†'mêlô‚ue^§ÙÐNCL"“î#xAk€ž2¡bøK‹ÿœ°ÛÝ4”årV¶Õˆ]Ô4e®[þèpñPÐlãW"4¶&Š/™/ºV¬D˜Óˆ[;y@“GN"äk€W§15£¶È¹‰u{pè ‘äF½·nÃF|®xù{ý(_q+›áäÂdØê1LB%è–ÁºZU &Ú Cìq^@ÌÆ™ßî¢a!J²Y»˜×›¡=ýp;Q‹a×Ót6í!NA ŸàéAبÏl…8Ñ(7…qI™l.(ö–ŽŽ•ënõA•™`‹R™•®ŸyZy÷GŒnéŒ ÒÆ0xÁbñ˜¤t â6Gšà&6˜G (Z{UFgºwXþtÚh„Î´×ÆÉö0åÅF;“…;Þ'˜ «ÙrtÝ<ݧd"Ëôñ‚—ØjAc<˜'ÖÐk0Óëf:møô†.§%Ö¢åK7×h*j=Y˜Ž {ØI¬ÊX!]ZJhöÌÚµÙ*Ñx˜{$QÍh>vá«Æ#Ñ“`ixá_ݧleÐau=ƒÛ_Jí¼ÓÊíoTɈ $H,X ±Àöh}ö?€a]yþ醫@- ^÷›Š†Æk‹•hBsúf”I÷p<yOËÅœN×íp¶b‰ŒŽfaHˈ¾e²a]\g÷ /êØ”L>»Šq.j2xlgwÃúY°GbzàoÎ+â°ÌG@f’Y#–^/\»v-@–œù~F˜Ì´)`3·5¯ÓiÁ“ôñL\èæÖ4¦G z1Ju´ Häšó| 7ôä?^qú} V¥°ãiDIÍvw)´hÚ¬Všãã…£üÈž{îIðÝmH±$â¬&øÒøßà=Ò˜–4½¯íýwÝÆg§n¿kò:Iœ)T;bÏê²Éƒ0®{œÈK£'ðX*/–9ÎY.ãHõâM¤ÇZe; Ózj™bR"Ggºj.híáGpõfD´Z#ºÁ;#šw„û©Bˆj’¬á¢ÃÉévZ´`§*ÛѤ KoOŒv#ͶØí4À:í«ÍCMŠÅ._·=EZâÆÐpŠI0rÈ-ÌŽÈçr¨·êγ§.þgž@9OTpr€ÑÔ ³R2qárah]Š`mÁãéNÔpšÒ O“A¾¯Ñ“CñJ½»Ž4øw+bäÀ~¡ñ¸1r|Àö¯>øá,†ø{XxPì!ï[@Ì4N³>ÆvØ>toC†ºâüs©•'2ÿ¡þé'²ï¤¯Ä‰ $H,ðÿ3 Ä`ÚfeˆHú1èÚÜ¢Šxˆ÷ îáGmEA½)@„莀êù#T9Üfä9Ä‘EW¨‡Ç˜Ç™<®+ EKY:9Êu—B)\á:r”éâ§uÎ8j0RŸÎ‹ÂÌm¯ß`(hÔ#‚ÿµòÝ "S •IFÛ>÷CB¹c“| ™æb'S/f8·r'I_ªž^¿~ã²%Š‘NTCµ/nˆ7@—’R;¬`‹ †¶,CavY¼[pÏ:³Ðˉ›£œ,ÑO³ «Ô iœ•ÍAzg ºµXôr Ä#ñb™½0ƹnŸ ¢¨ì,8œGÍŒ8™ìH£I-C›ú m¢*Úñ–s]18Aí: €W =tXú<f}£¡g';±Œ2£¸µ7<²ž ÉååLbR e>>AZâ'à6Wªö‰<|>lù$Eˆ£q zwâ2íàq»Ëa\•sZX ÇžÁFVÆT|ÅŸ ˆ‡Âa×J­¦‰{¤å…¹û0ø|píL×ShÈÊHp)g-mâBVôõvÇ.}Q )ÙÙ¸"v.? ß-Áµ)éa§8£gÄnÚ´bÈÀAjÐÈÈáX%i4]ä+áåîOcmœŠ £Ø„õª´Yºl|0–µîåÚ¢vº¼O3*ÁkK”-FI%¬Œ-èh¥Ø0*6l¸CûŽ'*i¦Še®W² »®m™à£Ç~qLrÄ2$t¢ž@b®s Vf-ü=Fìíî4S¥$­ˆ­LåK'‘i¨ÜòùR’‡‰1ð•L¢ç¢.{¼Z«j8b‚›»Ñ·\;–v«êÞ¾‡Þ‚»ÙKýîOØ Íøßß]í /‘àé'ÜäI‡‰ $H,°È-฿ôà˜!qHá`TŸÆ÷pDs: )€¨ã°QÊ€&Ñ‘_0jrÊ ™ðÉû{ ÁL[ …¦BÍöô _µVëÐÈ ¾e¬Xgù)#n¹<2°‘‹l.òF/%Æ-9lò@^p’ÃÁ(…Àc¸ ®fäÞxmC‹‘k®AéÃâm–1?ÒƒŒ£­¢+‚ËRбŸ­4+D ¤#à.°¼ÌPéºJ±”Ž=œ¾à³¢Åƒ`xÂÓÆ„—ÍWüÖÀ5qPen¦A·ã…Q¼õEÛ䀒؆èÛC¦Cd m$ÖKœ‘1Áåò$Û‘Çl *3'.‘ÇGÌ©O¦Ö4{vSB«¼* g„-FqtdBd˜é¹uBÌ©e–ï°d秬¸ç®ûY4R´W‘g!xõóExæL˜¦Ìžþ´dÆáJ# ¨È— &¦P? EXQLJ‰— øvp%÷àlk„˜. e™MZŒž (¼«“‘êWœJ²ò­–t¶z sÊï¥*ÔÂUÏŠÚ4 Du|帿}uõئµj ‹ŒÄ"¾ïµþ⦠CóÃΦ• Ó]”fÄÅOí¼/uŸÌóŠUniÓË jüV>FÃÇ)¾ñ{þ3xü~ÏjOFñO?VOúL,X ±@bEnþÒ —ú“ù˜çO¤`êN8öEu\}Å"oó¥µlÊn¢gàw0á­äSžNd[ñ\¦ ñ˜¤´B“àÙ CãIKD‚¦å§4%5šÒ€ÌýL|´~î2ù¾   ]ÎÅqË™ˆ¨ü€éŽÆM3ÎΫäËmE¸Š¹»=úš[²dI;§¹Ùéâ+ ÑqC„ÍXàDYgøFiF.~ÙtJ2ÌŽ§ñã’/°h^m’»ŸùêôI»ð¤¡y˜ 5mf9Ý9(<6¾S`'FEe¢¾´P8äI/ìhl vêÎ|ª«}K ò$Y•ä·‘ 2é1Õ•û—]vÁ’×o0,,#SŒ24¢¦Ývd 2ã'Ò´{7Ú<ͬ3ni'MSK»{kÁPùj<ôÀÐ,±`tWü U§A¤kúÂý°§Ejhûã¾,o 0^ã‹P®–óYÛ! '¶îPJŠ¡mŠym“ÒÒD'r½?3øéË££°ðgLC$;Ϻåô»~-¶\k+¹Ø~”¶RìI¹•àé'ÅìI§‰ $H,°ˆ-5Á¬B*Äáà€`—$µ¡IÈÚ;Éûr`?¤|·1}å T¦F‹ˆ~`¦ ¢à!2ŒHD&]@Aqbq­Eˆ ïv*ËID MçÂ"ÊaQ`¸­…ùÙ  ¢jU¢“SKÁXˆ®5{™V­•-wè„M·9σfû­ øÅæ‘LØN§ð㸄ǀ”5H>3ŸhCkâþõtÞôQ7/•Îg E½AÂ/ÂÓMa‘ÞSý\±Ôì™øL&OsffšG}§Sp§Ù­]'yèãpp“'Ê=ûðQl[æš-bLJð½=PÃ$@ —iAŽöQ^†#œƒü‡âfat{ó³½¥Ooo+’Œ'±@bĉµØ«x.qØîÖW•‡ïÛà$”C&øÆB~ˆJ Þâ D¾t<ú:›È90¾{rW¥÷*%‡Pü]œÄäÐ ‰Ñ RUÌ]M®Çò£´Y#˜PZj!Òœp➦®chŠ ½€R°0ðp†|UÞÍåò¥èV c cµÓ°ž"®ƒVÛp$"‹Æ¡¦`q#©ÍW“ÂM^ƒ• é@•2àbIÛ NP)¡¼p÷î»îׂye¸Ñ"¶B“YÌÌÌÓB/ã=•ìŸ%êÒíp³¶“ŽÙÌTE!Ž|g³QWkб%ž1…éñ®»2ôEÀq¹ÞA›hƒä¤”ˆ6íë1ÌAÆì„ÑÍ=mˆ¼±ÒsZ»0gÞâºèó齘ÙQÌ“¿YÓ6Kj0‹0wQS!'èÚªA÷€ŒÞ”[š6¼®žk†G;,-wÖ“1›Íš2¤qòÝçMƒ¢Î[È-1¾j5÷aSŒLÛìA‘ÑÓ(Έ)¥Ðz–â ÍÔáYÔR¸3Si6@ËÄ—)µ–!]» ž/Q²¯C²mPÚf6ÀÓ¥ç¾ÿœs{îBÕé }Ë—Þü–Sn¨=ÿ#giï¿óm§]LMv—ýOùê÷ýÿüó¯æúAv÷·žyþÇ÷2îWoö¶ÿøò§?yæÕMßpá-¾VqÜë<ï·v+I‰ $H,X`Q[@XÇx¢Î?–×ÌÝY§^ö7ÿÀk.y×¹w½øàwìvÃ>u-`:N3ןð¦ƒÎ\5ò'/9è3ŸüÌG~{ÀÇ.Û`Vá•·üÚmϾdû°X2ŠÄ‰ $øc·pŒó ` `ÿŽdå…«´4? èYœ« ä]¸¥K—’C”C~(“7°$thqò@LPâ-)湃58ÂfIغ¯ˆ*ÅÒŸà!îRë|]\µÓÃ?«£…ÆÙµI©ºÏ‡ÁR˧ hòñãc°â­~N¡iœò-‹¦ôv(éÞÍ\^üH£} ¬ñ›Î#ÞsÏ=Ù?Ù Gu·ÕŒ`>ro“ꌆhÙ  .Ç>/›‹¶Sò[é ß2óâ,'e8yIk>lfáׂ«&GaÚg2‘iÒqá`ÑJø š‚JäÐ_nZ·lL2·®‚dR,öŒ ¨\P7~9 "ö¢7<;™l_/ÙÐ,ºixØAEaI‹ÁN"!«`jß^åZ‹¨ŒI¢ù³c].ËO>s'ñ$°l¬)ÁÝV|j‰”/¯yü²Bªá´¬Šåô޼G_;šµ1é¡2£©IÊúƒDÍ•ϖ ì‹6ÎÎñNŸd©DŸ–¶7ð»±-¿3ŒilÛ)žÞôîfÁ€zÙ}ðgg|õ¶g¼ãÝ/}úŸ¿ù¯?ç+—-ˆ‡m¥ûúú[xö×oÌ<÷/vÖvoÒ螇~ç——žòÚ]6óŠo½bfÉ Þþÿ^ô‹›ï¼ãÖ[.?ë£ÿc‡ÁYÒpb·žôýëÈ¿õò³?öÊ]9U«”Þé5ÿßå—}ö%Kã­NzÇýN¾äßÞ÷gƒ!Rí€/ºñŽ[ïøå·?ùw»š¬NœÂ]^wÖ¿qÀ‹÷;â›WÑìm?8âùc n'—‰ $H,ðÇjQËMžf9Ÿ3¸‘„WyŽfžüà y{a©B¹Fšq°Á;@!hÖq»ƒÎDÔˆÚ¼ïosª-Ìàe&ÞGÖÀ_ »§(1ä5ÀªF!ˆ2Í&±sÕ DBŠzQ­;ºrìî@“¾˜1˜¿Ž+N5îGc÷ù +­îú¹ÚªuÓüÜ»~ã=ë6¬šž{ RGü9êp| Ÿ 'dŒ†q̰KຌÆ?73·æþÕ ¬ÙmFð±4?}Ö)êaº˜Aƒ¯{ûÍ·\÷ËkgÖMcºfB6/ÊS#SËJKFÆ'Ëcìry¹ÀåµõDH•>t^,ÀË€ KXAÈ EÂOŽòS(”0’t>ºý&Â#Àfþ#¨ «T.•ùɧºA1ê[Ë© :óˆSÏVˆ Ói1ëf´vÃôƒ³³¨îÁM©êÜ‚ÍÄâ–‚K&èBSÉã«fMÚdDó»Ÿc½àÛwZm(í äÌí^­Õ©5Z ö" dò# iè…²R™©Õø:G{ÜÓAŠ6[˜±—Ê„¹Rqd|lrtt¬ˆ®ŠñŠEbÉáÝÂyÝíóìðÕCÒfÇaj ðtÌ!¡Lª[å'¶&Æ2»®˜|ú®;üÉ®+v{ÊØX‘€7D®d¬€êV>Ý•w¬A~K?ÈÖlúØ>øyø£¸0gý·^ì ¾»üé讋Oû×7~åøÓÿ²Û¸øýÝE4Ñ-¤ÂÄÎSéùuÕ¡g{ e63‰ŸSÝöíIñY~ᔦÏxß¾ü¦¾dÏWìSÊó;Áʇ+^~ÌIï?ïà½Ï½½¸÷{Oùäçß÷à'^3ôVÿôôï¿ósoxÑÊ+/^ÏÎû¼áë/úâmš;³Ó«Ž;é=ß>ø%ÿsÍ3>õØcÿá7ïýÖÝ †?ºçû>SüñÜ÷‹ÿpò‡Çl’Û‰ $H,ðGbwgÁÜaÆŸ±-ÁÑÍŒ¡?uNšvÿ´9©uQ8F~b ÜY¢M8ÐÒ”°&žQÒ*wÁ¦HQ4ƒ¨¹@Ú 4I#¸NqCâõ$Q ô %wbr å)€—Z0 ­WX‚›s®RÅ£ìsq°NVZ]L…cQrµ‰^P\E( @oÙ™EУ9dÅ—ðýÀ«ÎaÁl›ÉF2¶ö›Q³Ïº»ïÞ:#’¹s¡eâ›T©8J¨tâ–ŠŒsÍ=÷p—éÈ5fvØa‡RI\Ž1Rrzf×l*ÿ ÔœŸ§kFB›B ¹:ÙV‰¯ÃO!7³!wÙßÏW ,¡)iγ X—ŠCùä-¢fƒò¨ÖÑ>¾a<ë0±ƒ@@X ÂÖa Êæ“A²^RGÄÃ]ÓŠp Z0i IDAT•òÍ®¢Hb|ÙŸØê:x*˸çá<3wì‹ÕúšŠ‹2õ†Á´ÌCi²%×Ù€/Õ3»—Mí˜7_)Ïô:ÉX™£¯;¨Ë*ÛW1×%˜§$·=C%‡2²¤}bZÏ÷B4†­YÙÅJ–Æ6à«^?]©VEÊgK£m¦*ma·F¿¿cj%&YÅÒðâ!žÄ¯Ûˆ§¡?ßô¯_üÉëNyѵ>ûšMTÁÈáõ‡ß¼+½û¾¯Ûùž½,aîi/{Ë *ß~Ï9¿\[¦/úÞú}_öœ%çݽV°§°~Ó—?úÙïÞzê¯úÓ`£~ƒ’”X ±@bÄì0š+(Ò†Ûà…>ê—N …M¥´\¼x‚„NønTaùªL¤‚ô—ñN šË5 Ç |Aü/ù$¯ ‚_$¢xA<`_”›‚À$–7ZDù–OšêtAkD8­ž­ÈΧ"hÞ]úÌñ¨¯±‘èƒBl “Hr(mhOZÑ8ÐÑ^6.…±í Ó‚†DòCk®¥šH( pKœÙYlÝ«?¸ní5×\sóÍ7?{×§1©%|n\·.eðñÎ+WàqUl½0jõÂB°déòsóÕV¿#]ä>æz“½G*ÛÃqŸÆ+M®–$Ì‚‘RA/#Ì…¬õä Äz µ õŒl«Ùî!Ì2ƒÆ«­Ózpj§'66Æát­ÜHÈÑk¬Iqq£û¹&žt`gŸø—b}[ èH÷áX¢2è¤@Õ#å2”JlÖÁ»`k®7Öúóµv-" oÄõ@nËÒ=Lzª¸m à3§`–x³ÇóíTÀ.FŽPÌø0ÛF \ä½z£´£Ññ%ÌÑÞqèUÞz†±ñ æjÑŒeÍÖŒY¶Y,æˆmè]j–¸Ërð´iè@¬O]:$‚:C`»Ò&—:ˆª÷+ËêKÊË'(ÉLÏ6 ä0 Ùœ烴à×b˜·à‘¡CÚRí"o›ñtйû¦5îö›ßÎ,ÄÄš ùâk Z÷]yî ïúâ%«9|\ùÓ©ò’§äçnº÷arã+&ƒ™{7J¹…G ¶þ¾zá9ãÒì!5îüÑù÷¾éõýÌ Îν散לråšx¥©]—.ö¡\{¨— ×þp4¬Ýä}Ÿ½íGÿ}Ÿ¾ÞóƒS`—')±@bĉ &à æhŽÍ!¤´å¿÷žK%÷ñ9vX²Óo~ôÐYË|Áà³Æ3 hÒ@r4m˜F-Ñ—pICê—å •üåa#7^áÖmìv%!Ÿ¨yXæÜZ·nš‹ZƒX®R,1þlÚ7v´zñé1GwŽâÉdx>aFkxKÑdmÚH¶7H«1Ý –,Ä¢zgTýZŽX>ÉÁM>Ây»N5LèÛ®½žœ§í¶+c[ÿÀƒ¨Fp`郧áOi½_\Ã|ì$mô‚$FŽ‚(¼\ÒÉÈ¡ç•kö t·ll©å ;bDù\E'Î7¹vö³#KTOæçk]!Imi„J­’ߌÒ~eð4žlŸH¿%‚rGÜ= Ú™·Qly¸!œhQ ›Fd«NÁÏÏs®QðZ67n1wi(ϧb¸˜^!Ÿ1¢µ3”ñr³HrňÙá覶n n±¸4£FŒÿCyde{† Üã«fßÁu½QÃþ¸ü¹fÁ)CbœŠóØé0e_22í‘W·ä¤)θeDJ'§(æ)žº|~œÁdr3©[#`»W|>äãÐʦ‰mÇÓÜÿã š¹› _Ÿ¾?æ®á µÍ1}4·v&˜ÜuI1¸YTyÙ®¥æš¹Á)È螟~û×ÿë=¯}ÙêâK‚ŸwýÆÁÒ6fVm¼÷Š/½ý]næ7ßÊ’[‰ $H,X Ø»o³„.pÚ-ôœ‰þ!—µ>A§¥×&°w°ÑvuxIg‚>wúð£ å7V.ÀÀ3 RWÐ+—ÒAAÇô.@ÓBd„Œ"N€0øÄ÷™ÿ1àm{µ&LVTï¾û _õh8¦»Õê´ÁHÄÀbå¬޳;„Ã<µ"82rŠ´Èl)("!ý ÝàgÏŠÏ=ȸ+)Î-g*ˆs¥ÑŒ©g€\™?kfo¸Õ¨AhDúÃ43;=;7=³q=çÛr¹ä«Qk.^}Ï}೩Éqü¤hú!?‡¶ÜwßÇ!¾u3•z³þó9<§Šuê(e‡HC—˜EÔFþ-W(±ÉÐhe+ÇôèÝÝZ‹Y5æ+œ%–!z òjزpˆƒ×?Cl*æ˜Ê¬^½žk<Æý™jÔíª¶f³]±FÊòC7ê ‚©ýOkÇ'ÀÍÓÕ9ò»=bb¦*uØÒ¹FºRmq’ÌiMí ,š:O…VVNj\ Ú~µ¡Ò2Bò|¡Ù·ÀÈhèÑ'Üñj½Î"AnãÖZÍù™u}®Ù…•ߓ޹£·{…¢È'ìz„ì ËI<‹ Änn|BÎlzgÌ(_ОüÌ]!Š |‹TmoTlOÅÑS=¾¨†³M¨È—‰Éžž'Qd,î´réØš6pðtžW &œ÷„FL‹D~mß_²ŸÑcà¿A\ò´û‹8|Ú/Ôvš<ýh§6²Ç!_ûÊ«×|îà#.ZµMLŠÙ_ç¢u_ýà‡ßrß çßTyÖÿØ{â¦^¾ºt×þò‚k9òýo¾â¨so/¼ø Cöª]zØÍ=¹«ó°5}ns‹ý -dóeµs-Þ'ÌÌÏqÜÑŸ—7¢gÇÁôÂ{^bñ|þñô&þôPÍz“môÊBo¹¶}»QûõWûPç£ûÆåŸ@ñºqó9xß÷­½îšøÒökW}´ØyðêsNøðiF¦þôõ\ºæµo\ûŸÜµP»¯}ß…;¢üñãϽêS({Lÿê¬ã™NÀôâyz“‘&H,Xàɱ8@;Ú¼ó\0S!T#‰p!Ÿ}Fry‡ùZÜÎ"\ËK– ™ò„o¬¶ÚðšûÀÎRéþ ³ÓÐ%úèÝáÕÍtGø0'‹¥Úò¹"Ã3F4(.Õgò)˜wµíp÷ N¦Òu¨/HsèD „¾PM–íŒQ£é bònÃöf #Ix¥Aü‰Êɱ†N¸n ¸Òá¿‹A]©²©à x•ètîs+¨5zóM¤E8ÍÊHS%½7CP¸#üJ¢kÙÞA=;ƒ¡–-ønk-ó­nCÏ‘LÇ5Ì.`rJEaYª€æ+ÕùVƒÕgjlêÔ…f®âNK0š½ˆ‰s+É>†¶1 _‡{¬Êô5u;®è„jˆ! kè$¦íš²(4„‘|Ùã Kn,ÛÏgÊÅÞHIt£jÝ…~2б©ß¡øQC÷†ùÆìímò²êÑÛnRjçVn7ƒI’X ±@bĉ¶k ì³ÿŒï{§Ÿ(Èén5;±§HÚrßÚ§q<†I˜ÃNeùé"ƒ q"¨³X¹9á¶±|¹lbDÜÓþ,<ŠB®Ìk¸5axH§»ÈqìÅ@–-Y*d>ð¾UŠË½â)»€¥Z¦ÒD”­Vƒ¾¢"ØhC=+Íà™YtŠíQÎf¤‘{|D9r%ïgŸœ@~e4 Î Ng$(x„Fï4ãØ„úfœ&B¬—÷ÒÙÍ ±WxÅ â~3¯:Ûe‚žhÌ&ç·dj =“bNŒFÔ¢.¸ç4`šk¦‰jÒfØð1ˆÆÂ p0'¸>¼^Üuòy»WÉ6ÂBà Om\Ì? [žì”tBÌ´œÏêø]ËâjØ òŽ”1è—ºÜV;³Þ<Ü]q!–R¸ü'§50ŸSxKäó¸™ÎHkE6Ù¯ô3´3;‹^aõÞ9È ‰Nïå<3-I%Zû[Ú4« 9øÞ¹£‚SéZnrÛ™4,¦cdû.LÌðÑó ¯b¶äkͺÏͳÊ5¶9ä0mMŒ%z,䄼GFˆ,¡ÕAëN—Ÿð'Íø!²¢{Ì®ßnÐ#[>Ɔߛ–ytè7›/ª—nÜ\A\ ¤r´YÕœb5×>¸nãÆyQœÂ€m=8ÝC:’zÔìä«)¨l=qÄ÷6´ë¸âüs¶^ò‰¹ûöO?1“HzI,X ±@bÄO ìgAz$gµ¨®q8‹só…„Q¤Å;|T¨SB–Àò¸R‹vİÙ!†‹pî^ø!à!ê“Ɍ娈wé ÁS ï2LélN<(*Ì+JìŘ£B±rCÊmÌ]à˜ÐÒ6A%Ÿ㳉âè§ñº›Òx¥–mŒJÞ2 ‹S‰ÏJÅP5ð/ŒH5Ü™8Jå7Už "ÙÔ¦÷ÒÐoŽÀÞÅlg3Dˆì(¦çf?¦‚WMÆlq~tܹ¹T¦ kôê-©6/)LË@U£Â¯NeQoá~±78Š¡åc×°ËÖb%j|âº@7‰·8Á!›È-–#†òPóóÀ]MTKº”é/(¹ÞnŒˆUñ˜ôl{\›”Éåá–Æ0Q?lFa­â§ÑÅŒ uOy¡…hG'ƒ‰¼¹ÂÊÀbªÕŒ+ÂpæÝˆ¬]£.v½Ö„p/Ül±lduÉ[ó ¬É£zÍVÊTI­æå@…m¤¶};àqmô‡"4Š9³ˆ…&÷yŠÈguÈdºÎlÁPºŠåA…gØö‘ƒË.9ÈM˜é@󓃛›õ «‹*yj|™Œ™YÔ‰û¨­˜˜õjNìû¸^ð‹µH.<½H*fbĉ l70£´9¤Þl|ƒ2›îA-ËqB̘Ó|ƒ) 2«ÕL¼9¬‰ƒ›UôAw!w–J4"\(Sùv‚ àºåÓ=¸äS€’€QQoƒ´é-äðISØ„6°ÏÞàglˆ—ùŒ€CŽãi÷Uó©2î+5ï8·I>rg·|Dú>5N}eShh€\¥""?>嬨oÀÖ´ÃdAo@>ÆIDÆ–Ïáa€ò¾ëry¦REK›b€ÈZ”æ®vQë”Çb´oŒq†,|OóÔÊÙ[ÒÆàî[*’ÏH8j¿)R:9Ž#¹ €µ©Q@-säNÔ˜Ä7 ÆJÐ#½0k9$' ˜vQ£~–é°@, 2jη•xíæÜ/+/2£ò–UD|˜.¤ r8"H›tAkòHÛ·$F·I©P—Œ™m™ Ã=ÍBÃ`_E·±çÕÇéTd.n˜Eê1[i&™G Ó²ç gkrµáðøºˆR‚§Ñb%CM,X ±@bíÂŽ<¶„”é!ˆ¼†ö©R-)á%¥3çZ Ö^!\_Ð*–ð,6Ma#àžá$à©”«…’t’¯“Ëó\P¢xÈ`¢$*Χú€ÞèÓcBŠ&Ù†š~Oè¼äÇï÷S:=fÇí„>5ZCÏ@p’ÑbÝ”gœvÂÈJ2*Mµ?§—¶(3vHˆ_8-ùcGŒQŸ5É °&žYjQ’.ÈÆ! €£.ZzÙ|©4:’ƒ#Ã8€²é Ôä?î^sÿš5óÄL\¾<_›®ÉBtî˜w|Ì€…óvvSQrèÈVÁS ÷•ƒya–3í7 ‰R„!ÁÖ€$LR¿S8Kãak«¼¡^Ü› Û„öûa¾Ù†ü-Uff-»Áˆó€ [-1^ Tjü(Gx”!ôÞ>°“(ÀþƒYo0…áuPr6ˆDü@ð Æ¶Õb0BØÒÚrðÅHáÐ$ŒÄ!ÃBØZ lñÚõFC.d6.z=Á ˆH¾Ä>l²ÔèÛ3æÕýéUw$·›V6Þ0n·ÐÍ¶Š¬ŸFäïWkY=“ÂúD]´ÆØ4Áß™,¤޺б\ûÐxÐÜë÷š72ä±Å#bL´`ÑCãgLëºxR‚§ÏZ%#M,X ±@bÅl÷Ã=d`¸ ~@QîbD8¤HI@@ìÆC£+~€T P˜|ð±´Ôèæ(Qm[Ï×x£i„|P)ÀšÔ´Fa"~P@ð(ÌêÓ 6>QŠ &ÛäÅNB°&IͨçlšÎ`Ó@ Œ¹pXPˆÌˆÒ¦ý\VØÝ9\©ÑƒBŒ Àn®9ºšÑ2"Ü0nç«Ì.fk É6ÓŸáÃûÞ‹˜u¦T”?Û­6£s÷F-ÙN3U(Àg< "Ä€ûCÔä…±P„%aC³òñÄu Ƀ|Ð2×ÀD `B¦ˆåh§×•o»@ Z3»ð•겯±±í_6DvÏ’]±wxEÁ­lA;™E¼dí‘ØK°jþ^Âmˆ¿Ú€®<ñŒë‘hмÊ+2%ë"¾°yÅ6l¦1/ŸÛÍV“¾ ùÅm‡ãlw]ûWåukU½Á-μS×>JoTÜb< Ì, ¿¨ÎˆvÉ]1>ùº|ùò™™Uú¥ˆ·onp³Ë"L ž^„‹– 9±@bĉžT tŬÝ,™¬Eì¥3‡¨|¢ö°QÇ$RBYözÛä3ðE‰HÌü ãL”<^’§û­.G¾rùt.[O £m/Wxpz¼E(nøÄ`˜œCËçÇ #E†aתËJ+€ÈVgåŽ;mØ0Ãy¹Rq,WÎohL·ëÕ\§0¶R“%0D_@!Žk5ŸF68ÍÙ´^(1 ‘‘>€uRssY`ƒHv–v›Ã‘ŒÙ¸"¾cÖ‡¾æÛ°4óœ¸ìõ "8¾8HÓHFtû ÒœíÓI5¯^*Œ]ÇgIëcrbÉØä$Q]zéT‹‹í6Á˹B75ÚU4} Ô\Õ³%zĈ™¼‚­pü—ÂÚŽÄE.¥™R­Zdž$ð""˸j=0àÌL ¢ØÕÙú\Ÿ7ÊÙâÊ™r¡„˜4ü…§ÁælChvù²1Zh5ªygÓ§»½ÖÜ\›kÜÐ’õòŒ¤…PxS ‘µXdŽ>Öšœ§ìÔÄ% Ú©¬H5¼¼­tPïg& ¢­w0[@¢PÞ£º4U¨›…a§™f‹ð8®µb@4Ï ,j}IħÙ!KnsíUX“÷÷¥ûüú¬{£‰† o òÑøxY œ)´Ûl=„ƒ‘q‰Z…›4XI¸—CúÀ¿M“ìЩÖ^¾‚7š?ÛøHé^¶ßîdGÓùtƒøínç_Q,ˆç ´1HºuÂr 9ø~ŠŽlóê * ‰–í¸ß·\µš[B6H4 œˆ£0hÒ¨ ò;R’xñRwÚó`5®…’»RA „òM§÷·\Ê裀ô_ý:³Ù}ð€iߪHV™ÄWœßpH|vjÇb7zÒ[K|õOÊ“h\C¸0…á,A=À…)·®%HÞ\S˜Ž¸ëâb'Q—ES8öäVr¾‡»®Éá%Ý…L€?>}$Q__¨( ?/I`o›  ƒ8É'S‚šÓFBœi‰õ¸(—Y‚ªw6NM5çgjdR–(M]ïPJ]$X£!j¶zåÚúª ¾Ò#ëÆ|Ç qpoîúh¦¨›¶öLf‚ÃYczŽzä¿A¿ Cù.¡â¦·H=Døñ'Çæ«§=®½"³§¯"¿-Ñz±l´AûšT|lQOBܧ)|{,zíÇðÇ ¿ÇŽs±~(×–_Ü{Ñ9Pö>òÝgFGeíf—wjZÄžy÷ië¹XL)~”mÈáøŸ½ùsç_qÛ·ÞyÇ­¿øÊ›wvÇó)ïñþïÝôó¯¾ö)FUŠSv÷·ž{½ÊÇ?—}fŸ©-ߺþ›oÚí±¡÷ÜÓßvÞ¯.;éoVøôõGgüÝJûµORbĉ $x¢,à: Õ†9Ô~È'(} à‡ôŽãGœUÔzúÑ;n 5-¢ÞaŽv8hHB.;:À†6š¶DaAš $ÎDAØàPÂ@]º†¬1Ê™‚܄Ʊ ½™™éX3?? ¼”d_ §¦t.`kçÒú S—;™ ÇŒ°‘®‘¹¬~òT7ä­tg§p•b.rë.jŸ+° Ö´Ðô%LÌf³ž2ê8Ÿ×þülºf ä6ZžPhµFs®Rç#]úÊa ”*¡±‘4éYEðcøœÕÓö@¯Pïnw[H:Kï³îFèU×›u‚q×›â0Ø1D 9楣Â,°j ½n팃n±²Å3©ÌMÏN¯ŸŸÝÐjTp7•^ÔÊ¥S¥B¶\Ì–Kc££#%¤¦áÖLŒ­\±lÇ–,[ŠfÞ8`aè=;b¹4Zíz3ª4š•F«Þ è šì€û)Ç""赤÷" ”tHàL8\ÃânKgÛÎìñà˜x"µ|ocpuŸ¿zZ~bù~{ìø½U«ãƒÅ6á­ÄßÊ­Gg«ÜŠ¿ûàAçÿâ„ÿžY”æ~t“Nj%H,X ±Àve€Å¦ñlþçˆ[Îñ €ˆwºCRù * ¢dÎGùDA0"CWàùhüÁ¦Lè€~„Ÿ:òù¹JùÀ#ïÈ`bMþ×®ë&l`˜!ÜU}­žE䦊à‘éÖÙG|æÌ¶IOŸì,Ÿš£}äx¾O'ž“MD}ôc°e(9ž£R†ÆiÄ? °l‘2Ì»ÌÎ R äçmbnyÅc·F|Þ>×\ØØåvóŽÈ¨M£KT‚î, 9[š8‘O-:Â2Þ©œ¨>0à)ÈÈ:7¨!Ç&‘)xG42V#D`·ÖÈG0E먤ݕ;°5fÙÊ!5WË_kòb¡HÈšp[;¢‹˜Ã£®µ°} ›h³<:¢ÉXr­J1íkü– ªžCj1BvGd›Ð³žLš¥–òc¦¸† ä'Ó„jù½]kÔ¢õ« ˆÙlÎ'Ï,ãô|‘KŒŽBƒìu˜v¾l¡+Ýò6P[=Ô"ñ”BÀ¦1ÝrQ/ä˜k˜‹ -ÀÓùñ•Åùë/½êöb,Ýþ“ܾÙð »¾è%£·_øó%{í÷gË/Y½ÖýÓ G÷<ôëgüýš:üÂû¶5*auúî‘ý}ý…×ýË- !=¿A{¼éØÏ~äïŸYì<ð«³N8æó—ÜÛH ÷cZŸ¤rbĉ lÙø¹áªÒþ§†·Ôäà´ €AK梋ËàN0İ”'§ãóL IDAT¿Ò³[2Írç!Z‡„ýdbÌ‚Wò½9&2È7(r-¸ ½T/ÓD*¡3Íš¿S‘>€ Æô§JškªÌÍEˆ× ´gsÝb®Øš1ÝåXsšòBo¨ÀÉ«¬‘– ŠKÒn^[½fñ¶#÷ÑŽ\MOã·)“ñ\„#}„>_cð*ù[ÊDý‡bðF`Hƒ¸sV# ?º3/¸CRály‰½H¨¤E(Ä.„aps 긜‘ Ø ±!)"vÚc`·jcSÈdæ/“X¬gÚǤì\à_ÐãäHžO¢¸@/V°Eö+A¯Ù¨FÍ9zd´9R*@Ü`ˆtZ€dÍÈ`>(®e«Ó‚ÿl1V¾_È­né°“‚O³ÉL.ãšxuPé®5 0ñ`Úõ†Â­Ã%†ÁM{ •iÚVN>{NB*¬ó”¡bCYX)~ÐdK O6h¾*\û-Çß<|Å2Œ™W%ÀbžX3¦´el_(`m« –»ý+Ó•B¾˜Nˆõ¨ÇB¹ioÓ xùÜi¶êz‹ÂÆE[MʉSn¾ybg¦Qÿ& Ó®‘´è>èEõ¹OO_Î÷¦OÿÔg9îÓ_»ü~ :³)åwÙkß©û¿uây/|Þ‘ýÜ¥?\»îq«z¤IƒÕÞÃÕn9ïÌ5o>øWþè/(®xù1'½cü¼ƒ÷>÷öâÞï=哟߃ž¸0äø¶4ž”I,X ±@bÄÛbûõù_¯ø¯"™æz‹¿Æ¸fЦE ´d¸!Š•›Oë…{!+TGEkš£^–øšË†:WgŒg  5Ý™, 3ð/šïSŽ)¯EkàHªÀ»–®BÁ”ãLú×=‘`;%š,œ>[:•HŒ9A=ü5„[®ÁÇ|B„ º¢“i›ª ØmØÜ"ñéɯû.‘g.UÙÂÐ…Õ%a5çpEü‘zÄØh,áñQ—î¼o ´çcç“*T—MNÖa_4B™7Ÿ¯ áAò7Æó¦–J¿ôgɇ—+ˆªQ %5Íè G-Mñ/^NåÉ3"®{5_ kØ1¥ìï>ZÁGs–sA޵£œa_q—di0±—ÕBæR©èœ(ô’³/`ù`†gœÚ'ÔuÎ’Æ5h.ÆÍð¹Ø„‡Ï¤?’è£Ç|çGk/8á“_ú»ªPÛùû.Y}ñÕ7Þ0}]ïèW<{é®[?Ô“{õýë²ùßsî¯?îç³C[lº5å‘û¿ý‚U íT¹á´7¾è´ßÓnÝõWüËW^üõw¿sŸ_œ5¬®xáþϯ]xØ·®YÇ’]úõS_ù²Ã_ýì¯^³`$¿g7Iñĉ $H,ðÈ0F©©v¸gZAóÌG§Oa]ó‰d Šè1«3^ñ nÕ€m3€!°• á @|;¤îf#‚†šæW6ÐfêiD¡ Ãih´¥ ‚Ç™Hà-ôƒ”˜¬ ´¤%¡ÐçkÐ`„t¬ðcÆ˨ … 9m…ñ1‹L±€Úœ[æ’±¸‰†FEšsYƉ”‡"r6t§³•ž¬aÝ4B¤n)¼¶÷hÈÏ‹©qAdw#ЈßUŸæ%%¡åx Ou–L˜MŒo8ž–Ð/!G®SyïÈÆx‰T¥ Pe­±läɆAõF ˜a%­“ ããlH°3µ Lƒ+‚ÀžV„· Ì„ 6Äú›ÂüïäÈõN“F»×ì¦"tG$3Ž}7ÅÓÖàŒõA"¬"­E pD@8ƒköuÒ½9K)/6Ý”W—øz»¢¹0E·Nç)°›Žkßä‘Ã]«G·²³oÄZgÏ–VF« £<#-B+ïUx Õšé¦{¬¼ÎºÕÆ¥Oó ¦ÐTÃöô‹?xCLÖxØþIÀCkm,"ø6] {>â¥ö—/-‡Ó{_Ÿ ð4ãíÕî¾ô´w]~Þ^Ò7NZrÐagß ÷ƒ•Yùüý–=pÉ5«£ õKn ŽxùŸNý×úƒ n…$½•[Ú<íU—œzîÏ8äm7þdð+œ_1ÌÜ»QñAYÛÚúûê…çŒo~œòQ÷—TL,X ±@bÄÛdð†yV`ÁWÿ-óNÆFÔHⳓ÷i͵ 3‘B'"} üæ«Ç‰t P°†”êáBÆ)My€´µ Ô6Ù><¹ÚñD¦Ð‚h"Ò‡ ïA²Qˆ×Ì'æá+ƒ1«iF>qrXAÎ127Ñp^äì°Ã¾nd·§_Ó ~m‹£õå1PÛ0¡L‚%ùJ; ›ÇŒ¯t— õàE龞7c]/°v*|UsÖùÌô5G6$¾6kmt| ÈÄ€ÙP{ϧ-HD†hÉnÞ­É›o¦XŒis<í3ˆÖÿò¬“¿ñò/¿ú¯žòí;ïà¼C¸rÏýž½ÛÞ{_r˧½Ä½/ÆÄåWmrC?Á3oÜzþ.yÍÉïziL[×ÑÜÚ™`r×%Åàþ+S^¶k©¹fζIJ,X ±@bij ƒ!ð* âátî´¥5gkA>‹>q8:RN¬Xš7¸`oÌu²0ÊK7_‹ÀÀT¼½ r¯×'Ñ·ÀjðÃÏÑ>_…ÿz  ¡Ê€ÕVî°3F…¾™| ï´p"nÀFèi¨Ç´PæøØR:…x=;;‹ôác¸Ñ¬UsÅ®F¹té…×üÄ—]¦‰¨B¬n;ƒ 5¡¿h¡ÝÆÅëbÒô.³ÀQ!¨aç£öÑ2à .%¡<Á“à”abÈl Ï{±”g´TêesR÷+-fuÚâaO‚´$ÜfQSC÷|Ç5ûvtGX HP˜ …çjµf©¤»˜¡ŸD¶ÃqÁÜ|k¡.á#‡á{›%%ÕbHt]«Í·`ÛžŽ% ûúK@¡ŽlE‡G™&Ê*P€ƒ;'qBæ"œà!*%xØ€N™ikÃÀW¡SÐ-ìjËâ¢U›Þ|lKƒýÙ_}ýôŸÿÍ^Sú™ï®ýå×räûß|ÅQçÞ^xñA‡ìU»ô°›Ÿ4¼¿-SHÊ$H,X ±À¢µ€{æ@P2çÂÌï›A\'&k¹”#¼xÐ0V´s`Æ”psÅ‹{ÊãôT®‰QèˆÖ—¤ä”=SÆ™à`ÚÉeÍ ¤Œõ"$%a8I§¹E¿‚°F8V/ù²0D…‘"x€“¸Ë¨/-P˜||½TçP·@Tö®%lfÉ[P¨”Ngjjœx"ÂIuqq “‰Ø –°×Õt"Å·)Ç|.èÎ'K1OžIݾo*„ð¼ 2F2Ìqh¨Iå9âÁ<Ä’Oßp¡C^@žú¡)0Öº0ôÌ®&(y@JáõnOü™ñ±‰©©© 1ëCeš |h.SyúãÖR F”›™#ƒ¡¤Q[DdYl$±h4(¬vè#;` Rªu‰—£ÑÛ>$WÔšºI‡óõQñ©‡ÇÆp‹ñäx#ä057‚Wd´4õõ"‡G’*îÅ—J¢Àl<ýc¸ûË]±›¾dOiÛžk¥#NaÚ©…öÁˆKÄ{‰´ž+*jB¦Ùb.rQ±SÈ÷ähÙ÷Þû"úÜ„§Û•™ü Ž?çÈ“¡It×ÿú¢ÓøçË7ʪéÏÝ3ë?;ýgSt×^ûã»GÞöÒ§ýêêMçeaÊ ¨Õí[¾ôæ·œrƒ6*qÒö¾,ß#ÔÞJvwíe_üò/94.Ò]óãã_úñÏ~íª;^}Î >-9Œ¸ó%· $H,Xà1X ßmˆôªÿE†’øÐ84ù$ÜÇHàùÑralŒàßpF˜Q1Éѧs À8ïo`ž¶t†iqè^&ÛÏf²~ŽÌ^…FhSäc%‘¡ GÉQMó½¾”72„Wäž4+ð‘"Ü rÓ[xê‚WÀxæX•"ø‰D&X iLYÅ. +tˆÜcôÇO8{A×È-S¸H4qšuX·y ÁíÞY†Mw‚Mp@tôR茓‹’»6ºËB“kJ£8åÅØ¦ÌJ)ÉV÷PÅ&2# µ7º3éb¼ÄR`îá®–£‡:É[Ã#ßÌ‹ö(ãpËÝg“£—’Ås¦ˆjÞ¢†ö'8ÝeIY ·¯b7ö …]Ø1 ì.ôÝ—:J£VÒ¾ï¶bÈðα`Ÿxí!d‰Y+xš‰ùˆ.‡û³}¾’ÙOÑ„šmƒ0ÙˆŽŒ*¸ØËÎÎWÜf"AsýRžâ¢†7/'?³`á`q¼4 Oßâ¨ã‡f½°éåeø®=9H²ôÓØˆí£¬DðD´Ã»AÔîñ^& ·qú‚.¢ÏÔÎ;­\DÃM†šX ±@bĉžD ì³ÿô~á—Oâµ9ø8sŠÈ’æøŸ¸Ñy½:OƒÔˆý!†€EäÎdk†H4p^ö«¢Isx‰/…yìx Hé=x¶¬óa"{ôšu¨æö˶ÔÂÙJ>Ü`jqz)¤ lâk>_´»HˆO9µ³Y‰ñIÄDô7H ÓÓ1·ÀÓ”4é9  ¸¿œ‹Nµw÷óõìêRRxÚ<â¼Ë££Ì×»»[”[€&a2ónÒ}Q—ö¹ °;./À×¶»b-ØŠLd^m®1ýÂ`!çú Þj¹÷7Ó )o“ºŠæ¯•¡ìpžîÜ=l¾¯¦Øá§'Â6qZŒ¹.ä³_>.ãÓ­qîÐÛÇzéæÚG>t«ÒE«§R ¨›`NV‡|>+Q?wµc P‡'ŠÏT.duxÁSD>½ð5*‹%Îò.¹ÈIOHNºŠ( m £”gcE#ÂÁ'¸ßf®ç!k1A½ŒÉFR…Ä^€!±"ŸçÙžOõÈ6†§‚*Ø™'ŠuŒô~ ìgÊXlͺù™™™9X<€uUUôJYi«éÈ#¼×¤è®8ÿœ­|‚nn‰?ýut“X ±@bĉ¥PÜ‘1Š¢2–tpp¬l¨Z°2P<Ö¦e&v‡8¤ÐN†ÉM'ß©•¹ñôV|Þ¤£‚«Yˆ$Y3²p€ïXLáï7+Ά.‡ö²jŸs„°EÄҘРJÌa®TDc­ ÕÁym!KpTã’å¡€iEmDóè‚þ„“„¤E&üd§ØÀØ áƒ¯Ì 8¿™[ì™ûÉUŸîqú, àŽù¸Æ@Ø¢ }I>B ÐŸôRÔÙ8yåö–ðŸÃîüúæ<Ø0Ÿé±@c9 ±x ¦â†miYÍóøÌ WX³p„°¦/›:š4‚§áŨY»ÅMOKÒ¸`Ç2==î—ñŒ\ÄdÓÊ 9L¬›”ÇóoIÆ´§*y¥Õ処p&ã÷c³§`Ûå‘ <Õœ)ÃEóªkŒÐ9ÇòæËörikÝ}ÏŽKG!é‘+zl4=Uæð#™†Âµd\ ²#æ-ùdÉÁžd¢ÝÁÃÅ­Â]ßhÑ©ËñX4…©›¶éÝîñ4õ ˆÛ3ÌKõºv•=™¡—Íí­ƒFH lÆtxü5aöz9ƒ]`,hïláàœ7ší'¬CèŒælkT™bûH žÞ>Ö!Ebĉ , €W ]=:'‘`”"ðkŽŽ˜ž.òsà•ÆðÀõŒ7ÎߌHšÇÓpäÿ³P„!F]q5ŒDKâ‚|Áä(*Kª; ;T"ÀdèGýz¢Aà bk×®¥ýeË–fðËRR¨±Ó?£›¯Í¶ÞéÏ0 uAµLW„ZêZ€1­ñ#2|´ /jQeùòåÄÓV-;ôɃL3Eðï™T$ĦæJ§eGù|¥eá4á31˜IdR‘O2} ²s¦m‚Ü6MhÊðé»oœ>n‘Oaoøfc¦6cP4t<ÓÆ-î ‚BdW„m >Þ\Æ,†´d,6‹9˵†Œ‡mÆ€²ìËDpnÖ‚L™>*úJ¶ˆñµæ»Õ„¨:Ö¨Ø~¡ôR4¸ Æü÷jÍüÓ€PYcàò7#ˤˆ‹¨dO`š ¿³™Y“Ï,HܹÑÃÑø ÃÑpcª_Çþ¾Â<ÜHäÉ2Y½°©© Ÿj|ðj÷Áö¢ m‚äÎ¥¦A­´ñË¡Ó`m ËÆCÈ|i«æÙNo&xz;]˜dX‰ $H,°ÝZìªÂ£ZÈgÊy¹÷ÆJ"LD}NgÁbväú• 3òÀT²ˆrÂC‚—›èÌà^J^UX³òã‰xZÌbðå€Ò dx‡L ¯îa;Ÿ›vA>|‚òå»$ä¬Ð½AÉv­VÇë,e´¼tâð †Hϵ¢j­†P¶vz±Ü,³pŠJ b€:›2<:7˜Ò’^ÿk;Á¥g]­Àë0hà<+‰»\s xG]ýiÇä·éqk¿ØIµC‡6ŒÝÑU=²)½n!Ç[b«eO¹þ`Zƒð(ÚdC}6X.û˜Ô·Í…=$S08®ƒžp! ü©5°£"¼£«¢ˆ-ÁÄÄx„QpÓBg¨}ñ%0#! —N-£eÿ!jáÐ)N!Û’˜u&WášÁ혩9ÈÙÙp!6I  5&bkÙ‡fdð§ª35{i=œ ‘ûê¨Mïäò­Ÿþü˜”¹‰ÕЂ©•óÞšÁ«ãOS^§Ô8ÙÝvKQÐíT­4Ø#`㌗Qõ… NÒ.²ƒ7±â_Ê]-6QŠÝÛ|½Qm4Ô+tzù› ƶ}¦OoŸë’Œ*±@bĉ¶_ x…ƒŸ4x_æø¸A¯!@jÑC|ô‚5N3nŽ1b‚ ‰> „á%ƒµ1)‚X׆läÁuP B'GÄ‹‰`mD°s¢ªð™4"g*…G”fžl¹™s`å0]¡¼*Â9‹ßBÈää$.GÚjR@I2i P2­‰iÝëÑ&ã†óªé˜ª1wi¦D¿©`Š` õJ”¡M.èTêsäÓ쀬Ì]ïk8~æÈð|"Œ„4B&×Ù´ÆÉ-oÜá _YoÄì'(Ê-÷R;“˜êÞNè”§¿(MpH縹XþÉÜÜ:Ú§:ØZø–€´9Áø‘Nèˆñت¦qM{/ uó²^$ãSƧ©Ñ ൭ÿïH‚— Š -|jræöÂÃXÌdIôB2|€N3[È,ÝaI§Ÿ«GÑdi|ÂÀfÜ‘&òò~¦*½ôôLI.0e½V”‡R*Èß,¶KõF ĉévffÊK'G ¢¦€Ÿšµ†£:xáS%Å©–ž02¦KÝ©W¡Ïfó9xÇ##c4†@ˆ|||Jìãœp<¯ˆß¿ƒ“•Ëÿß+ËgŒª4^Ì圎Z"˜ìVž³su 9ª™J#Êö:#øÝÑ~nsæ/%ÖkÓ숊æ5 æ ¦{½ÉühªEøË.Ó¤¥,vÈ!+’‡ôB›VÛ÷€Oø=Ì'ª·9 ù¹Óo‹d“+à#f™?Ö©”ÎvÄ7ŽP-¡°!Fy™¹–ƒß`ªÅŒÄÓ¤©G%j®Oã4;„çiB|öÞ°ŠQ­Ì㇗[ø:èó õP å1ž=Svx‘ *B‰8ãóYmW²Äì…µHÊ)æ·.TÚ\*]Îö Ì”‘B·¨¹‘QIÍìôØÆÆð:xcâ ÉÜÌœîì`HîÚØ4«ì/{A¶@À ‚bLÎÌ5gfæØX¡x5¦ÞÓæÐ¨R©ßOCÙ&ý¤§O?éK ±@bĉ™ É çã0'´óàd˜Ã#JP >ÝêNM*RRü‹_Í]«Ën×À…8)6ÈT—~íoÌ…\Ìyì‰vRA“$õþÐ{aÝ ,?k .ˆb®~!‡ˆë ÷s¥.•zmµªËe)Þ³F%ºG/Œ$®zfš:cÖ…!õªS’·þ´ì¾d:™>;šÒ c©"Ú#:Ø(W%ÉOÔÉŠ^KóÅ>´ƒ™®}"î/ ï‚䤓 Œ¦ßfÖt-,IOI-»ÃžùÎ×AYHÛp¤bÔèüŸZ Y2©Å]ØÀ> > ¦½=l„kÊP<­IÙ2µu1Jz6;ÅàiœD1Ÿ¾xêïÐd]5… oÙʪ[-¢ÃkÏ|ø'š0ª}ª°<ù“†s\·b;éaã)#á "dkÏfÃ6÷±ˆO°»¾X”§;êú8qFóU¬íXÔ4ÎeõbªêtHƒäRWXÞv|’©OcŒ°—¢5{a-êác_¬9›ðtîéo;û;G?OûÉ ¨Þ{Ù7>}ô¯Xg#Oå=Þÿ­sXwìÞuáªø=Vé¹ï?çÜÞ«ÍÙ0 u¦³»¿õÌó?¾W9¾SýÅq¯;ð¼ß.hpa­m»N=ç Gÿ×>w²»æçßøÌ±ÿûG«’ ˆÛfº¤Tbĉ 1À¤ZE!Ì žæ³(·TW”Ct9ðw7‘()é:wñ}‰ài€Hsð½³x|QøCÙBØ”¶h–4b j„ï#‘|&‡À{P&Z¤³ÃL@é™Ä…ûeúm\âÄá ‰{‡bÞCCþ.³sÆ­\±}0˜)ß ÅºÐ&Ÿ`õ^ÐÃ.ôo †H Jî:ÕGЃ†JX÷ AYŸžØ)Œb|ª ¸ƒÝ8sÉÂqÐN3 Nø!rÈh0›_ÚÙÐDt.µfÀ9­BšññÒ‚vjÆšp ͧ‘¢7¥x•ä×&îCjÕSbõÙÙèZÌm¶g šàœë°9úÆØÒuÙ¿ˆÃîN„8¸ÈŒúŽÐ"ª¢2jëBOê{j¿‹[Å Öê qÝ`¢<øFk×['>‰ðÅ"âðG4•ÕNÊO`éj¾iý,L¶·Øi ¶ÛÇçåù|r‹ömf1·ØO¿‘éNbú娥g®%'"•·BÌÈH©Ì×zJ# q³‹¬‚mȧë×òcvµ|¨>} –Äö0T§eµb¤4)ÓgÓŽOÜÎbª¢—×øÍÛ-é©Ô©K.èŽ3œä7šÚ²ˆøÂ^HŽoX2ZP2)F+/¯9žw­— ¸{wóXx›”_˜<“ÚîŸljÙbŽ çe5˜…(°Ï-ûaä*ã»»j5âX&‹jÓ’3Rº  ¹ÅtxPÝ[¶k¿dAÔ‡íÍ Ø™ /çÓaÓÓ£D¶õÖ¬\¯_^§gÏ À[Qu'xÞdœáÕÃùýnsæÎ«¯¼eãó6{PØõE/½ýŸ/Ùk¿?[~Éêµ›¶>[huÛ²F÷<ôëgüýš:üÂû¶Ai0½üoxIÿGGŸyÅý•ñ+VŽOýé?¼æYÿzëu•më.)•X ±@bĉ (VpK`É\‹ AT €…ÁEá <™ð¡ |}€xÍ{ªO«£8ˆ  ‚×:(¦èö#è txåå­,5b‚ù•J hž-ã!åä-Ó;Çèré¦ÎGzà5Ý.¥`8¨®  ÑtÑ*)³¹ìÑýè¾ÞPÔæÈ, {sҬПHefºýÌcÍlYDÚ¨5HáCEe`÷ £ÅÓTZ“ÃÇs]Rt4c’H¿ ‰EgdÆÂ(ÀÞDúƒ£eꊈ܇€ÞKs˜²Ð‡œï²‹‰À­€:`-CÅòð/ Ìeqf±A’èbŒŒèÙLG^g(2ë¼xì}Œ÷¤V©^Bô$CC‚ûpi €NI[4ú,µ[Bô=TÀ樵¶±šÀX.uÔ’j6Žx‰uHNPdô±ÝŒªPˆt¢uðöùô˜)NèPäDåˆaÀXp—‡Á|¿¶²Ÿ.–yÞJh‰8¼(ç³ÖÑ}áò°æÇ€ÆÏFŠ9¶;¢M,êª@uÞOhzÂå…m"l·¡¹gõV„mÛÚo ˆÑÄü0 vUébp4ï3X˜÷µF«RmÌW›óUCô›ïÜ[oÙ‹,=O©ÂÊ—|È_<ðÝ÷Ü2tNù]öÚwêþoxÞ Ÿwä_?wé×®³•|l‰uÑŽf7'¥ÏÙ%¸çß;.éáÇì}Ëéçdßòœ§M†×UböÉcLR;±@bĉ l›ìO±9D-7P‰ °ù~ͧÀ"¨T¨¬“/lòL;d4Ï\ŒN ²æðI €Ö DÐ\˜Îò­–êzG>€åXƒüaU—&ÍáãñÆ¥ÆlºÔ"-<ÈB{û¹‚t-Êôç^F®ÛÔK§`q0/dï\zûÏù¤':êEBTEãZxèŸ[ê¢æ¬Ö„H™©†)À¥$@–Í nË«nNeŸš¬g¼ .Ø-€èh‡[p¾Íp‚ ž’]M°K`r³¤•—û¼Û×¹@r(!•mƒÂÜ%ö z¾ bÑYÎ…ÙQ…cŸwìñÕÀ|¸Õ)Òí9FC%`Ÿš¡¸"z$D™±-Ž&oþ\LÁg[½m¦sW™8Å ­o Š ôÒ”?ü³©¸]i·Ò 6J?¢*ÞÅVÐ<ÍÆÚ×ðtúPۜȼã‰çƒÀÉæ»#š*TGâŽ2sbCÂðéiŠ ëɱercúšÂ8ò¾ôpY‹­ÇØ•e6M¡ÿpF‹åbs<=õÇþàÆcƒ`ö¿ÿéí‡|ëŽMLŠÜÎ/ØwÉꋯ¾ñ†éëzG¿âÙKÿsÝúmÔ“{õýë’1æ¯,²à…ôƒqùgÎNh¹VsÖbùE Q £ÞÐWÃ+âH““Ñ¡å“j*f*f/¤P e©EWÀZâÒá§Ø‘O nñ/Å «iŠBæVR‡ia„èrFÇÇÅ­³d‚fCk¡.¨±1ÕlKÄ%Ç2>î6³¤åÇĈM*’€ƒ­N»È”«ØúÖ§ß4gøš­:}o ïñÊ2jzf»­™¸«R‰£Û XœEÂCí5‰0—. E¡Š|ûÃËÊ›ü¤Å,¾ê° ÐÓ(ŵZfꡘâŠÄ¤‰^Iïx‹µ½×°Ä6¡ïn£š×¿dG2sY·$ƒ§k”KœÕÁ1rd¥µXILd k¾`{Sâ¨Wðm6}♓Xiuˆãš]GQ.™Jw¹vG±wÙ×?:=Ê3½(kY¥øa¹òâŠ^M9kÚ>ìÒ½Ôhêñ.mËGm`>ÄQ¯…מJ%höÄõŒô= çS8Yñ$é É×dÿE’Òz6ÁÛ~£}Â#QnO<݆X¯5ÙMq?4‹eû:¢qÂVç÷¢ q®Úš­p¨”ì¡´¤ÁiÀÛ‚,ã*ÛÛ?›ãiñ§ßó‹¿:õ¬ƒö|ÚÄ7o:~3+Ÿ¿ß².¹fu´¡~ÉÁ/ÿÓ©ÿZ¿qæòxò§;ÍùNö)ÏÚÿc¯ÚáßþøuÝ_\N5çye’¤Ä‰ $H,ðDZÀI½®æŠäÓåý¾@…‘€B01@‘ãgˆ„¥ ùº –:ÒRް’X$Ú¤èÓ|á†ác”,h˜BÍ- ¤Cc˜Aœ£á`$fµ¬—ý–Ô:qŠ…®òý#³šoŸÕ;æÐxú29”GºŒ>ƒØ梶¹ô[7û…(Ììú‘¾ÑjŸôèŠäóôB×ÌNTb3UqX‚P]„®PÊÓ/Å¨î€ ‰8®©B&Œî:Ùš»êvà3¦k¾¨wùnµÞ)…‹#dÇ ú ùœØcjÆwœœ¨¥Q {K'[>]Aê§N}:”t®6Üî"”ÈÈÁ“6Ó¸ªn¦°×övèï\ÛÔ±Z»ì#tW,?2Õ æ¶®)Ù쬢›wKåð§Ë2ñp¯ŽM™½Ï@\ß¹†ØU¤{ö 6xözVM6ô±ñLkJôJ²¹(â”¶E—WxLÒ€õD>ðŸOøE²§É–WkÍÙÙÙ¹ qß=tè¬äâ…Ôç{4nû·“¾ùª3}÷>W}ü²uæú Wî¹ß³wÛ{ïKnù´OþÞ—?câò«fj‰?ì÷ú¿¹/ÿ®½ý¿?÷¶3oªežúìçOUsÏLâœþÚ=i=±@bĉjä¾ÀR8ë(¸y­È¡X 2Ó9.)ÁɈ?›±ýúÄ‹6v8ŽYQgõêZ®ü…û æp¬Y© Ÿ^¸/uia;¹× &ÙMÃ:–ªÕºxÉÅ<¢Êt]ÞòãÓÍçj•ù±±1D”…•ÏP¤Ýt¢%xl1;Ì…¸ÍçK­vd¤"¸¡}}©qwÃ̺éõø£ù{[G—ZÜÜÓò㬎WÇ,Éf"J ¢§Ã‚à-$ƒŒµÂJGmÅyÁéÌ­r¹tÙgst*žT\ ;ÃF냊ÔŸeœè{/}§§ìL Å‘²p­µ¢É\)j¶ðŽ”À¨-Þí48[ ¯K¾€@0T°ŒsDúˆ¼d—H6±!³9zïšþw³nšâ`C“6©;XÝ~3‚ï¬%|_’–ßí GÅÁÉæõÃÃ:„£`0E_[ €Ûî‚ ZµP,¹ -Ö"¾]dœ!°äˆaÎéQ9›9Ëî´ŒóÀR$úî8fÒ;/ÿ-°•Ö|D¶+³MŽ kDÉôø”¡Ù™/›MñvÌ"xlX´SËðHèQWXIyøƒl»—éu`ig¨h`pøë¼RÐÖ€ë c*̲âývÄg>SÒŽÈl5iL%ì–>Vgeu.¡% dÕ"‹Ë2»uëÖµkWј’Yˆ\käq.¤±mÆ1£[U›S²"3Žé<csŠNl(k›Ôè²aNL(¤2w¹ Bðþ´#ÔÐD{7dÁ%;b,ìÜ~„¬r¡ì,4f37QýÍ6?¢ ÊM±ÁåÒMoL\æ–‘•⦑«í»Â{+|@«ß¾ç–Güág§?ú]E{M˜<<òú_Kæ&P_õþË‹Bg>´øÝ÷ê;‚`½Ú‘K¿#˜›äi¹S%³næÍ—ßvõu×ϘÓ%½zö”_ÿì!øZE@PmŠ€-vʲD\Cþæ$¹ê 6Ž„ ø`ù´‘ ¡«ò#?4‹HÎB½5C8šá1Fu4TUjLDD© 78Wz:Â6@‰ƒ–£Iƌ‰Y$ —¾…”‚" ós½4t9 =d¸ƒ»A3áÎ0]Q+éYRhG¢…;=°¨”Ã䡪!þåòªÆ˜ßÄ1n cM| ˆ ¥¤¼ùÇ\ÜÉLZÆòû‚te¹¯!fè¿ò¼ÁGšù°1_"Ʀ4˜hÚç…»Ò~leŠ>áÓi>oMm#PW×6ò*”ì‰셋Ųe]¼ðtá¯n̽1³Æd6޵@ò²,¼»Ö|BßMücX_8,Ä…™€±\k­6è­ÀC4j_Ð cIœÀB¾…/[†²Ì‘d¸ÌH¾qzÁ{¼VÁ¢YX ŒüÌU~z¹„¿vk¤zch1bÓ"I€•lÛêàQŽDœ5 ¤{ÞÊ×Áìu¤œHÂæ3ÌËD6´|Ù0{&kNp…X™i(±d 'JÅyy7mãB% 륽©g ¨4ÍQZáÊ1QŸùµAî’߇:-»UK2&Î4?fÈU’i’øã^¦o’Ÿó[D,žmŒg¹|© ØqÌÔ<-Xû¾åÓòÕâWPœâÖçÔ4;Y…ûnwÂâ,ïÓ{'œ¶NYPE@Ø|Ò錺ä¥!ðiUI®„›Ü¨IÄ#ð*H•ðÎf¾ÞT:ÂYH'1à°%~)ª6]Á® »WŽDÆNFŠD&4/d ©> #¥™\Qk"µpá”ÉÞBBnbë¨öy¥=ìSøtZRÓA}-ù’6†O'¬œ(¤*-“r`_.]¾xqu]DlµVK–LÒœâ/M:dBבRȰ‰ä*ö3¼³ÌiZæì‘³~²Ã¶Éã÷Nï8 Y1L£ÆËÌ=²±’ LaÕêµôÏB™aß~ð®¡Rê—QÀ“öðiÃËÅd‚u\fž÷y4œ2¾y¬ÉºÅ?ƒsߨ‚ä—"#X`r­R¤’ é™ÐxÒ%?@à2OH?G£ú ŸÆ¯N‡lðcèôôŸ”¹y2s«£ ›–ûE½åÓQè>Å<’œ×Õ6¹/7 ʇƒÛ}¨&½ÏS‘|6O/b1júE‚¥ÆÜ¾\|4–fvOv%r –™ömÞ®&à _ûb×!+**ø'–OSÃê¸q@Ä÷™³$—ï*¢4~‡œÆüC·øCä«+¿?Øíš²KÞl¥`S7ŸÌ‡f|Ú|n¢ú渭rÕUW-‰ 3Ÿ|¸­6Û²¾U}z[N@ÇRE@Pv2"BË2&3IÂcTUâ9 X&ú"z¯=Mx  †Õ±?sl‚.‹½XhUÆFù¾EÃó„»Pž…óU‚³Ô¥“Å "%NŸð3.—y›Ù­çLN"O‹@Î&@!µ~Äæ¸ø„„ O–~Ð&ÎP0$[3BL±ˆ¯]Û¸¶본… ‰ïÖ\‘%Û¤-gÏæI@ÔXã²µ; Å ÌšeÅìe3¡?ŒnM{q‘ŘO° Bu [Í=cÑB¡‹}þÂ=z”uëÎåÞuÕge¬n5- ÍG^ 9G2 ™ú¥ñY„£1ü*pbƒµ  ~v&ÊY&@ ;¿?ÈUœÎï5O™L8f×£ñ»‚1¨sHø ðc]À€°-c‰m½¼$HH^~ àIÇí1ÏpìLdå+§4ãŽãp6[äã–‰ë`Lȶ•"¿»¦^Œ5áŠ/…ìŠN-ÙèĹbx©ÍÅÓŒyæ"ïY~lÇ ìŸ4”*Ìïô¥çؤ!—{i)5luyd¾Ò5OE¦ul½fŒ¹ÚKŽL`%dB¼1üæxîùjˆaÐ2ç”D d›¥@ÑfÑ4e Xvdâ !c›>KŸM}«–ñ(ŸÞïšÎYPE`{"€° ·ƒ;ÁQ…ç#Á5ì´` 0Ã!EN¶2 mh{|´L—÷&rirq7éÓ¦R¨']ÁÀ,ŸC_æcžq DÏè~\KJ´>C¼¤õp;Ž<’’#‰OCÚ'%ưÕíXÂñ,m•R4l³ ’F3hhUUUM á8Ä9@SñaOA7§gã"f7ŸÝ)"§×¨òP£cÌ”æ¦Ni,¤[È7 ®y`r'– ªñ× "½Ðv;á>åå£G^W]³råÊššôé³jÓ• mαåë|4°Ë)ë“.(’N‰7ÇÄ]—Ž× Vbÿ5cÙ9åÃDM=–Û-í9c[ w'ÔìÛ+||d2†7“uFа}šGóø#™M¨Å "Ï02¹Ã2%r†p?Æ4±ÿð‘CÖ Þ–É†£ÉHŒ`'7o_Hò 6Šy7…´ Ĥ¼†öŠœÍå›äA ·ÏÝA¹×&R‡À(Qµå˜èÔ¡â"›š‘uÑ3fñ&›ÜŠ<ÔÈ 7Oèår „Å’%ÅôLÉk‹ùšˆ^‹ƒÜÀ”N€B0àˆ|uá8úw„@†’ËÞª¹vÛ Ù§˜+FñͱdÓÆ7=õ˜h3¦­qY˽ÉKÑíG ø²Z»^™´L‘Y ¹›Äc…+I ù‰ÌÃQþÌÞJðÆñÂ1–:”3ùˆÚæRëH1~p^Í”éõÓÙé”Oïô·P (Š€"°0”5'R1“†kH ¥\ÌšFK+S&Û‹Íêg§j½–ÁHcSì)|&lœHË&šµa¢†µ›ÂÔ7½ËY«„çŒfO$¡%ÄÞà^ë&á‹Ø˜-+D±ýÈжڸ±Y ½A“êêêÖ­«‹Fs¾]†4ÔÉÉ™…‰D( 55ÑB\&³ pBvqž„^3. `®ð]f’ŒÇàÓ…ÆímÚ ·4QÍŠŒ[ÆpV)%TÚ­²²{1WÑ•(¸l"`#+i/H¼;jwå^ˆ‰WRñQÉèSV„Yƒ¼„XNøS1¶…ë£/ ˜&†Vä¶ý[ déFwç#í“ÆUR*ìÝ»7þizk¨ssäÝZ£ÍG¿1® Ÿ6 ®Üe³828F¨6ÝBF ý„‰;g%19wTïx.äFa-·Óéì»é²ž>[=Ûòl³áäöaÆv*Ó´Eü üÏðoCÍ]2 iOwü‰›]²pdù.ñÀÂÉ9¤Í¸M£¯Ÿmn±9Ü i þMÄ¿³ ÛÛ)ŸÞoŽNMPE`‡D` Ì,“jpˆ¬Hf|0L¿4è÷KH;O‚÷ +þ ”Iqm˜-‹²×Œ´xhœIö㡤 óʯ$‡¸:|Qc’ßDBI@N0$˜-q&„‚ðÓ¡;èÛò?<dž ÿáÕô/;†1x°EY¤È8(t<@º”€?• C¸eŠ&¢3ºj’lâ.b /$Ña}8¹®.\Ž uá …p‰kÁ4Œ‚EÞ2“„ãäBâYK  ·'-ø‘8½Ùx¡'U€]™øˆá…8<îx× IY4V Fl727âЉ×9,-)søK@é ¯¹`Á‚µ5ëvìXZ.^4—³E›9¬[·ŽJ.ärÆí?`íß›µ˜ÎKº”RL¾È$«c2ÑxŒk-÷e2¬uŸ —¬W9Ù( Èæ—„6øh7j WÛo×ît'ï®ù†»dÌw~ÿäÌùóVÌ{çïß,aÎŽ‚Ñ—<ý15Í_s§]ºW¡ÃÙû˜{ÞóèYCsû/žþ'ýý½Ù÷œP.Ýz÷‘sW-xwêçNèúUÙ»«xÔ©xzÖ‚Šys_»ÿª‰}í;ºí\µƒœêhz^PE`GB&#lp,§HÃMf#‰ÚúH„@b©t4™ålœhb/:Ò.™:È/KeÂq¢7Ä#ÄG@æ4¡ä…Õ@rfˆÍ%xáìÀ{„æ…ãÑH’Xo6A‰¡ÅŒù˜­u˜:„ÂZÝÚx^7x™¨X ¸©”mŽlq‹b#†0ÇLøg¡r–nc9&ˆ²7ÀŠªªëªkêãÊBdÇ\4³Öð‡ð™"ªyÀë+ ‹ ‹C!¸ ÔœÀ¼Caa–ö¥pAþØqE3òGb®&Fm]õ²åK~±àÙg§54Ô÷/ïKœïâÂî‡ââÒž={y|AâhƒjÆ%³LF IDATÂNLß–œ‰þ#oHºr]uq—²!ÃGð¤Á ygðÇ3 ›-£QªØB(ÐnˆS‡-»¦¾ï5òzc8ºjõ‰_u…#ñ•«×¬^[IšlÙèòp›BÅ%…EŽz÷1rÏ’Ò.>b¡dœ¼œ8G0¿åå fœžêºF^ëªkùñzì íÕwÀåýÓ€áòdE`i"°Õ’xU5Õ !T5CzK!?B¯B¿·[qa ±=ò³€(Ì]¶Véüm!‰¸yµ¥ü¶vÿ6·Î<¶R6·¿]áºf|:4úÜ.ÝëÓ߷߸1ÿó©ËâVÛ|úçIc‡ ±ç17ÌYþþuÇÈñÈãïøH‚ñˆW8ö„‰ÃØjKñ<üä ¥Í)z͇7~{ï{rüµoö¹à†ŸÒm£_6 BW׃~rë%_ûé>åouÇ^wã#:fÔí\µƒœÚ$´±" (ŠÀvG+<ol }bÊ;¤L,”Aè4ÆÁT!I":š¼[&Ç;T·¹ÎgÏæ¯â£páDÂvÈ1§èÍ6³=óÑê»ùþóõ–Â2+z°×ÚSˆ²²i±fmŠmcgÅ14°,××ËÎ@X@ÞéÚ*æÐbêmÿ̄ƔäÝÛ€¡áÐ mgK{ Çy’jN lšøÜ\‚ýöÛo?óÌ3P‰PÍ*脹q×2²®<•Ìä9… ÌG¤bºBÖÝsÏ=Ì…XLp2çy?|J-‚´ñº0†°pæÃX]ºtA™¦OfÂBh@RqÆâ–2252„-öÎ2´] ¥PuS˜€$—ðPÁ1€Óÿ„czcÕÎ2[¦Çèt•‡ÅhŸF˜¥¨ˆp×rÇqÕðÞêÙ6•öÛÕò}ÛŒ¾cŽÒŒßúKzë?œ1kAM,ZµàÓß\Þºfƒ…x>Õÿ¨oïYLmÁ°‰Çq¦7NžME*ç½øà}{F/·ÄÛvQ4îÒ'fϸcR?I[ÔqqõØ÷ÿš}éöf.oHzõ.)ÛëÄãGupa;Wí §:X€žVE@ØÑ Æ0dD$ž ÇÓ¼âéÆD¦!šmŒ9H—p„SîhÆuøyÅS„ŸÀ À¾‹é:nõ$3îÉY‰ã›åXöy¡Yf‰Ê!æâ€Ëé—— A—{ÔrAˆmŒŽ‘S±y"’ "°¤@!œ…l–“ÐÆS˜˸!ÁB8àÝ𕄈ýL`|ÂI²»°Y’¾È¿˜q44ÆjëµõâJ&-¶Iøg˜µìD³›ó·#…n‹FÂlÈ« 7"iGØe˜N%`¢Zªm-à^TÚzK@a¥4°Z5áOdÿ&~ ·»¨(Ô¥KiIQ(è÷ 6¤´´˜N ¡â=öʺtë×w@AI×:4iZ2.b6×5Æž@Ÿ~ƒXÅšªšºp¬´[Ï¡#FC%ÈÃþß„ àµHº>±šéÏv¾×^{ 4°¶¾"ãñú‚¡®Ýzp5QAÆî½×å˜ÈñL‚&N?ù»öìÓµg¯ŒËÓˆá:ÉO ‰Õëª*kjQy*(.îÑ«œüŠ$¿‰^Æå%¼†ÛwÀPjÈ,XPTŠO€=§¯(–öÔ0m_á€!Ã=ÂeË–óÀ%aHÇÃþQg&èq}ÝJ ÷èZRVäêYæïU*+tóK?Èòƒ©ÆHÔ¼¨°uœöòÚÑþ¾ìóiƧ«?|xZõá¿ýÝÅ_/ÇôÔÙR=÷…Ï‚‡0¶ÌÙeïSŽô½=cAck—JËË\õkù/L³bþòˆ­«µ+ZÔôÕϱø/kÝ=»âš¯ÍýëÃ_„F ìb3ì´hÝTÑÎU;È©6§®'E@PvLŒ2'Sƒb̰²4§U­G4/Ã)¡\}´WZ%Ò*V´Îëšy±™þi«¯Iãg{°T•f\buî¼hÚü€–­¢ér¡Ñö‰öI‡Öza§ÄY®µrµI#|Z¬†õ¶U±¾K3«˜ÚÕÙ>©´kɽѠvV4£Þ^È”k‘Ÿ‘cyGôµz3Ú-§h†¸ŽqÀY8¹–ƒnݺ3æ°Ãëg ®eò¿0X8¼yß}÷=óÌ3<òÈÞ½{¨={–ÐøŒ3Θ}ú `Sì BD///GզИN˜Õˆ#è_5]Ñ 5Loøðá,™`¹f\¢=ë¢OfËòiÉYÖÈ;Ç ÁYNÑ °—ÆÞû lëÖlÕzphµlÕAwðΛçlýwÚuŸŒ¹æ‰—î¿ò˜Á¡N‘êL圧fe˜´ßè}&müÏ‹¹6ùu;]þ.ƒ¿qѵgvyïáÿ-nΧ>ºó”'þxÚ²íÖ1óJ<ÉúH¶×QWýxÐÿ~÷§—ç7dÅ<Ùí\µƒœj}µZ«(Š€"°Ã"K’ཙL…¢+#C6Ƴ ±Ìº†¯ÊÆ4¯uæUuðâ,¯0¢&NkôìD&’rÄ2.òHóBìŒÄSáXCcó.!‡ëj# õ8œ%ôYåe¶8æÔ\íѲM¼ç¤ ±)–’Zf,Ž öö‘ØrbÛŠï—¾ ÷l΃Èz‰!çÅ‹L¼ „vÌ߬Èhâ ñЀjÕŠp•WD½.wÐï-*  )‡ÈÁ2=;œŒb&Ƭ¬VmÉw¾ÞbÎB±ƒKÈ9– ™Ä‘mÀïM̹Â`€àt¢ §²á†Øê••õ‘t$!’c4å„ ÕwàP6/Žßg^={•c°° ¼¼_‚|(Ÿ†%3.¨Á°÷Ûÿü,#GŽ:þø^ZÖ- <ìÄÉ'ÙkÜšªºAÃö=n|°¨„p)#Çì5~¿ýÖаACG‹ŠñIóò‚¥Ýºƒ¾q|ÛÉ´Ã(ô”„Jº 2bß2b4xöî;hÐÐ=1¦×Ö“±㎳†¸Ò©Ì˜½÷)0(P:à ƒ;âC†àî…‡œ‰ŽŒ+“È$"ÙDØ‘Œ‰']rwïèÙ5Ô¥PòæHFò\1?H pn ¬¨b”¿l³¸k­–Íîp¸pCΜ /šqçŽ=î'3ÿüþ[NÒ±;ïVõGSgDÇ_|éE{V=÷ê¢ ="]ÆýüÙ÷?›ýÔ/Æ|tã~óŠMŒ ¸À©X}ÊÛ}äI¿¸°çó7ÞýA´°[¡3VÏžvK;Wí §Ú¾žTE@ØñÀÚ Kµ¤Ùal&j±¤í{s} K¡ÆXW4¤Ä²LÎæ¯å'.º,v[Ž­_ÂÊÀŒï„­òα€ýHeÏ–OÓ³%g–X[ÂJê­¸ËYfÎ%Tr`y­5þæ4¶A‹‰‰ÜÖ€å3+#¬Zç4ÚBçÌÍNÏòi”{–ÉŠø˜çÙ m[Zé×NÉ*²hÀ(ÓÈÌ A3`D\Û!Sb!x Ý—žß|óMNÚ¼yó.\È(hº„ïxúééÏ>û,Âó€YÙïsm‘«xàY³fáÆþ裸öÿûßÇŒ®LÈŽ»ï¾{Ù²e,nÉÿbÛO›6 RŽu„k—/_ÎkÖ¬±è1Vuu57 ៃO?ý”ãýöÛïóÏ?gè+V¾ƒÙ27¦Í%¬ˆe¢U3Öÿû_k¼~ë­·BÆI¦Ê»Uôí☺ÂH)¼s¿í·uë´~ #К¨œ=åÖûW ;î¾M;ÚµaÞóÓ+ÖsÑS37П¹Hö#Ž2t¯#ÎúÃ´ŠÆö~4jws2²ú³¥þƒ/?§èéø4ìé±ç„²ÆÏ×t2¦«vS¯\[(Š€" ìXd™Øx¤ñ@à Iˆ¾ƒ©±6‚D¯‰¤ª£™Õu±åë–UÖ¯¨¬¯¬‹q6–ñÄÒî0îêXZ^Æ{ÈŠ¿Í[^)Š&lÒRm¸猫D#ìr$e^ ÝpÌíò¢“äDBìá~Ná–&h²d.Ä:-îi<µLÒI ' xqÀGbM¨Ñéð*ÛíÁÒMNAO,…>íY¾¦º>j‚YK‚@ôNÂ9CµÉöglºÍ2€ÈnE'‘° ƒ˜*éý|’rg ž'üjÎ-ƒàÚ…p ƒ‡)¤9 ÐŠÉY8(¹Ð jAª·¤Çæ ‘IÅ²éøºªÕoÌ|†J?<Š,Z´“q¿~ý}Eš×V54DR}û êÕ»ß3ßZ±rõÚuÕ~üicCD~8p¸Ãõa„z¾ðüsŸ|ôa÷îÝûöí‹tN ¾%K–Ì;·º¶þÍYïÔÔÕ/[±ûy¨¸4K.]±Úï+L%K¯H&²%Å]ú‘CR؈Ňž…Â*˜¿ÝYé!áL @€uxü¾¢TÒ‹fâ±l0Z¹b×àÛR ±S9¼¬[Ò.]+~¹léŠåËVÚ°zÄHñ{LÄ éÈ0!)ŒÏ* 8CAWßQRèïÙµ¤´¤€ %òó7™l—üTb~Á»b“l‘~šùB¿ÕÒÖ_®VSÙVûݹ~=Ÿ ˜xþyÇìUÞ¥° lð׎>ª<ñÅ¢ê ìÎmâÿàe“¾}úµ/¯ê€ÜnØChìÅÍzñ¶úvÎ9ŸYóî“3ׯ­Xöv~Ü… _9í¹¹ ëûtuÿú¯¦¿÷Òm“û5{ hçªäT›°ê E@P ˆ/ìW3*,BcÞN q¤P™—¨íYëW†“åÕkøhå[+îBŒ,+²¼[M&J±-ó´)O€¨¡¥§!¯¶¥­ärûŽn§dç†ÖkÌb›¦Xf%jËÒÄPÐD΄ɹÀ¡!™ Û a‹]Bþ£U ©´lÏÞ\K©9fáví¶=mqQ2„!l$ +[ݚŲ4¼È½ûï¿?NeÚ ÅÒStkZb¯® ¿óÎ;¬Žž±/C¬y?æ˜c˜-rEÅ Äu‚ ~Ó?mšžY6LŒJ¤qº={6ìùÔSO…U£|3F—8ÙFng’PmF>‚*gm4‹]QQA¥õµ[¾9†y0™’ý€nMüq¹Yö¦¯ÿ›²Õë'±Û­7Ù$jüû^ÿðU·òÝIW~2õ¯WÞôFU'ŸAÒáUó»ÎEêÈ¡ìä©aƒ=³næÍ—ßvõu×ϘÓ%½zö”_ÿìÏ7 A’uûòí½º?³ty“ÞÎU;ȩέ^[)Š€" ì8È¿1XŠ(Sö0†ib"äÅlÌe'x4fp §Y‘ªÈq¹,HÖÄd¬·„Ô@F1¦Ö0N¢¼‰@l¥Q¡ªbÙ–Ñ`½‰8ýgƒ:~þ§UŽ7K•)¢#T‹¡Bbs ^Â¥tORÌd¸~S(ÖNO<¯#Aw’@âË¥¹Éu ¹6ùñaù–ît ç6%û8/ò³ðòº“nWÆEç4N˜imù·¨·2¨©Éõ" ROw–¿Bvã$;“ñe@Dng¦g÷îPæÊ5«à‘^—§G×î{të]V\V\Z¼lÙŠHcý>‰C«W®™=û=ža0=‡ ˆ"¯Â‚DD´>Bï%Sñ5kW ê?€AüÁ¯'ž|Š0w¾€(ú‹–­¬®÷XT\ÖÝ¿®†-·æ9*Ï1¬wÆÿ^GŽ?þøî=º._±ØçwE£uõUäuçåÈò+OSR¼_·®Ýý¾ïÜPn±;$e*îö8%î]&ƒy{ɬ™¯`P¾çŸ…ø™Aî]Zd~.”$Ð ¿¸Ð¾ƒO“v_'/#|:e¾Qb›n&Q›-Ûõ|:]õî?øæm¨xðÔÃl~>»rúù“¦7¯‘6GåÚ$¿x仇?Òvކn?iÂíí4hq*]÷É£Wžøè•-N˜ŠLåk7]ñça×÷Y·¡³¤«vS­¯GkE@PvPŒ„»áïÞ9Ú)õFâ…•:… ‰ŒD$r\*m¬ÏNÙ&˜öˆÿÁ‘I‰‚k9´‰C?ÙAh¤‘cKC!´ð?‰¤—ßY(¦\BÖ!gðÑtSK[-9Öè÷ C5Eø¶q*Ó×!. >É Ó3b*L”8y8ÃÍdäKä[ÌÞ8ÃY±S4éÜBøŒUš”Úˆ»rQŽ= oÆ"-’(ý˜‚9› åÁtbGä˜JfHŒn”fÜÆ„ÂÀB ï$å"R´•ÕéI1˜k•Fý…¼RÉå´Ç¸,ª6sÀ…&m-éÖ…ìõ–ÐmUUm<áèÛ‡ Ö¢HO|h˜.= HÓ!æ¢j€$ÚóÚÊÕ8­<ð@¤eFäNa€¦Ð’ QÄ0éS¬‘«…®@šNXkdþT‚è»g·.ŒÈFLAIòõðè$HfõÃëö)ñ=É›®È}ãñèÚö´þöWéç­ÀVߺõ—ÁÓí€s¯<¶î©Ë?¨Ý†£êPŠ€" (»Ú6–,ŒÐz$à0›, ¬ÓN¤°¤lVÂixqKdìÇdB”ßuÑuyGî–ö^ÂQ;]äÏæÅÕÂ_%SŸ)¦KQ𡯆êr@øjdp…4w‡$”d%Äafv3ñT<“Nf’NDî,DÆk×ÕUV5ÄI“3q¦ÄÏÌBmÔ<ËÈsš¡„òz\¼$d2/·¸¥}n Ò‡N.—}Úreû<`%}æc¾¬EàõD\†uz%N\Ì!,3 ’ô*¬Ì~? Š\ZZF¬ì ²¬ª†5ø7ˆB=Ù#ñƒ2hÙÒŰXF/ Éæ¿L’T“’Û\¦"ã¼ýæ[$Ÿ„1ÀÇ7zôX²‹/X° oŸrv+²¿pé²åÕ5µË–¯Ü¿¿¸ËÍêÆŒÕ¥¤„[vÄa‡6ÔUa¼n¨«vN:o¬¯IÄ“õà¥^;ÃP¨k—2&Ü@?‹¯^¾¢{—2nlA È:ÃõõëV¯$ßa2). ÊqaáAM§j«ÖôêÙ}]åj&Ëò.¶|=„PgœäÏ’ÑG`#œ‹#µ¯¸° ¾1‰)>÷U`/\(¿;¤[Ûgn¤–­…À®Ä§½¡¢Uÿúñ/.´9R·dÚ¯" (ŠÀnŽ€pæÖJËú| :b r,â´(»öjÈ"Z#!çh'¶á”SÞ¥pÀGthC—…ÞÒ̰gaZöc:#Z5\‹Sbœ0…tPê…©šb/äÝ6Q>È€Lª~Y]]A3m¦læ—(>¿X.f¦Y‚̪)¨C3œœK‹GÙíñ Y‹‰Ì”«íT¹ÂÌAº³¶¸CØðŸ–ç ©”}—²óÒI‡,£…< d³ƒ BEfƒ ¤a˜ ÎÐhÚ`ù @ǘѣ‘™\¶¾!B¼„ÆC$Îx<(Áï¿ÿ~4æÀ0M¤äjÚãýÆMšrdcäy&É4›ÑŒYœû‹/¾`7äŒ3Š‹Ctö fBè aÃøªÙ%¹vu%홳ePfE'´DbgægzñÒÅ\ÅÒ¼ióÁ°Ú£>Ú ùô£9öY¬5ç €8oÌ£MSa,B ÷×¢ Ç’)¹oœü› Îß1=Ø6ìJ|:ºøå§oØtE@PÝf´3‡Â†ü: šs0X.ôÅ—|Šx¡ÝØ, .ˆ !Œ}X˜1 ¯(ÊYg*“õ‰ÂKfA~ñÏ@‡¡KHÌP1Zy7r5q: ]\BIH Ä\j(²µð 7M&i «s€5/hÆJf%øFm4UU ‰¤ŒMÚØ"y G‹ì™ôÆÝbš™ÎÂcÚÒØi7’­+íò Ž².©·ôO–nŠ­1ï2„½Ð®ˆ4‘°q“R§ˆ¬3K" ‚ô<˜ ¡+ã²èݳ¯¨éµ+¿vÀ‰XGÇÛoaÁxš¬(#G {ï½÷–/Ãy±”hÄ ÙkÜ„ /¸à“ù >üðCH¶Ïë€Rña½eøð‘Ÿ~úùgŸÍEœ… ö=*“~__W³vÍ*ˆ/ã.˜7·bþúèÊU•'œp¥ /Í2Yñ§×¬­Ÿ>}:Â3*5õ‹/†d­:‰"N=nbH3‚x a㊮ª®|÷Ýwûö-g (†ž°y>Ò“7›Í‘~ི²ò³Ï>³^¹iÏôP QÍé‡@Daƒ#Á§{öè†ÎMc¹Gl@…I7)ú¬Ë@Hhó¸è÷„Æã«Ù dÆ a£ÎÝ5ýc#à,ïÓ{©Ã)Š€" (;)Ÿt:3ÿ×Ü´ù¹( ðÃã32c_vÝù}r=rflø?ÂòGS¡=tÊ0W å& ÞivìYSǺzq>XešK[-a¥g 33ÔÌÐ䔯”6y%;Ï¿Û\”Q”m<¤ç@À]Í»,ägsˆÔ†¾€7Í;qK(ø‰¥½ÙI)N–¦}“X[¨á aAv-Ô¸Md:—D”˸é9žtÀP‹K{07—W¢…Ô!¡Çbñd zŒ 7Å”,ü5ÜH}Q‘Ä­[¼l¼<åôÃ_—­­‡Ôz CDÁ›óÉRFAcg&É„˜B»•±¿0ˆÂ˜kj$ÍJïžÒ ÐÜHŠ*+.›Œ2Ïâ  ¹Ð =*2õÓcíØÈ™KLr­›b5æh,‘¿e<@QÏ„©‰6Ô l õ¢1ûè?-’çÀ¯TˆÊ÷C7ˆÜ÷•ºÓ‹E@P­€¡Siò” ×$ö™|L%SÞD:`\˜}©IºM(2B”<ØI‡!&?ƒ(Ën¿&†ç8… GÑ>-§äÆF?ëiœ9Î/ÎÒ¸p:l˜Ÿ³!. ÛÆžm‰?Ï¡9“å•g>ŸßÐg¨¢#%‰³~‡Ùhm“.mÕÄ&¨‡,÷·¼³´d”?$å¤D‹KËÑCØÑµ´H(¬ÙÝñd<>jÜñˆ£Ææ™8Ì^@p•§R6[d"šˆÄçõú}á†xC}ØãÒšÙÓð1ˆB©eL¬ˆB"¢@¾ejhç¸ÀÅÀÎEì-( px"£<ù 1.ÓU4O²×ÐOÈ?Bq‹–, ;w@ž—(’>Òø¡ˆ#B¦M„ræið‘b.I‹Iž¤›R²#¤}Ð/+:[¦n& ±4……¾w{޶›#-Û õiÒƒŸzÖ=ó[}«ß¿îä³ZV0ð°Þöë+¾ÿÚ‡7Ø(uŽ=aâ°Ç+>‰8þ‡Ÿ<¡Ôõ¡ÔG>ý󤱶\üGO¿à¬*:—lq[®^ÇRE@P¶¢HZ1#†'¼Tb9 e‚÷ZºðÓx9®iŠ a©E‹Ç‘‡#qôfieãÚÑ<ÍP5¹ªŸ @\ IDATœ‚$Þ¼[Kì¤Þš¤¥I›ÅŒ"…Æ&¶Û›TbîâlÂ&7ñiŽ`’,àuòä` Íä‰]!îoÞ]ÆìÂhÕ.âåù=N¿\å}ÚëS¸$T'¹šwü(µY#îIZtzLÌ©”DôóxŸsÏ´§¨/óq¥*,{+Í\’IŽe!q3Ü>ñÛß™Ÿè²^É$ÍþN©!ž¡¨ãpàÀ3Äúß°}ÈJå§ ö“6Wñå„K 2ò¼a2» §—¹™b‡“u‚}H=o‚)5°vÁ¡IÛ¶—èûvD`“v€fÓ±š…ï½9·Ê„f±÷;Kõ?êÛ{ó©`ØÄc‡8ÓÉÎ.§hÜ¥OÌžqǤ~ͪX0ú’§?^X1O^æó1iKך´º4\I¿'œß¸MäAšLÖÄQ\à IHb^NÄYGBlâ¨6”T$x“æO^p}´ödJrH"$ÇÉ™5.[Ðé‘t1Á¤cáj^ÉHm:VŸ‰×9Sžtƒ/:SE^G‘×DÆ%¥c2 ‡F,K$ÅcMœéÆ(”{QÍ!˦Ø'qÅÈC©:šp`ú iJb9ó,âx}… /X0ìÕœ˜’êëÈúÝ.r[òBwóH€’ÝôÊm%›"´;ËÞGôx·}q¾y èHû’ºaÙÈü¼Päyñ´@¦Fû²5¹JÆ—(xB©2ÍX¯©ËÝ1¡ë9§ÈzþÓêÝÔÊ­À&ñi‡3Ðûˆó.¿ú™©s8M©žûÂgÁÃN[æì²÷)GúÞž± éLÇÓåë!?P٧厛[Í{ÈÐÿræÚí‹Çý膳 ?óoýö³ —þrò`¿mâésì¯n¹°ësçzÀáWÎûãkOØDàÝ=ÿùŸ¯ýÉuÇ0fÂ)¿¿¦E§Z¡(Š€" l-,ñd^b¥6Nb¼¼(¬y‰_ œÔpÅÍYþ¤Â&ú€K'æ],VàÌ¿7ÿ(’gSi~ÜÎ:%|„)<p©üëmÄl.gÂÐYŠðT3n^¯µr{^sµ4°—0uÄØÜdZ’¹ˆ“®ˆ›a“Ú¨'î2û¹ŠfTÚEÐ­ÈØI"H§¶)¦·¦e!ñš…›%K¥¸DŒ`PMà9 —€©†½ÌÁ%L)¯U ÖF.æ,óâ´½„ú<Í×N¥E›f»|KŽíýeþ¶]ˆÅ“!lËæö”YŽ ›¿Avú¾ØÐïÑeÜÏŸûðçf ‹9ëä_½½>Ñ`Ùøk§|­ÃQûÖιøÑм%$S9ç©ùã.š´ßèÀQcÿóÏŠÃFìßÉ54|tç)¶“༓Ý45s6¼ÇÏn|niÒ±nê[×//ž²°ÃÉÀ#NÛ·áñ ž½*⨞:­òÈ#Fu}lÑ*þ*ù}óÜC§üè¶é‡»¸–'=-Š€" (ŠÀ–G uõ Wä ‰§6e2““:œ“hzüiˆ’©°=IȯýPVK%a¡¨Ú\ÖüjlÞ†J/-ý¶{‰¢Ãbúqào–Ð^‰Ÿo7Ǭ’ [EÀ—*(pøÉ&NüЬĽ¶f¤h®5ÛóØAhþ0öë§1:íÁ<‘ˆHàòå8ƒ)Ñ—ñ´¤³ Txòáx$.·‰ÓœÉœÍ¾`'d:‘$•wY:%A2ˆybl&ÜÕ4rÿÐËË©ÍÄ–ÆíaSÄãôŽGÉ;è ÿ Îj–’UJ3”cy’_xna2ž,nY’qB›ôíxW2Ü.žd¹†³#$˵é$|þÏ]ä”LŠì˜òü#¼\Ò¯ Bú ÛÌW½Øíùž$äc¥!‚¡ÛãM³¯©ÛluÍ‘uãd·ß›oª6Ø‚l’úÂwùó”³Ç ,}èãó7^J¶ú£©3¢·^|é@wÕ¿î^ä?l În“ºª[øêœæ¿-ö«˜ûïPAYÿn=ö¼ô©÷/Íõ}ÿE~&ZÅÊ’òq{D?yÖo-Š€" (ŠÀv@€±•ÿfx'Ô--ZX“1A R¸…¤'4CÀÍÓAÚÐ^®mA£`¡ÔÓ‡¥Ô4°m,÷²›R8È÷)Si»0;+ú¥ÙmvÔ9…ú²ƒxa®cÓíŸf24„\Ö““ueþf³ uÂ)s„Q6)¢ÁóŽe„«Ð†í Ôؘ&¥º˜¸)á¤ø="Û7Š«œ„”èø8XƒMžL³X‘¨}niÃÃ]eõ.¿Äþ£W˜}Ìì¤ ¸%i Ô\Öhd}Ì+Ò—‘áñ²Ø¥É‚Ìo ˜F8+áán/Í,æÂ§˜Mn ©ÏÊÄË6Tæ{“U™+SÆNVv±ÏèÄkÉÂìWEò~\©Ö²íØOw0ntþ¿oyèØ\úÃgýò•µyFÝ0ïùé•gþ¤Ïë?ž¹8qd}lƒÓåãGW?µ¬ÞŒ­YVµdæ_ÎùÁÓËò3ÎMBöÆ"˜O¾>ã,.p-Š€" (ŠÀ–FÀþSc ïz­ׂP Ãl-Ž%аá~–]É»|´ÌLì ˜­ád–;ÅQ(¹BZË[˨멶i-kÞ,OÝZ^kkšvQ26 Š@Šž½#qŸYAÙȸqf¡Ó±0|´vÔ[›ýQÂT¤3ˆÑN¹ÞÌÕ#b±pÄ$ÜñÛãÅá‚ÈF£1!Ý"W‹ÎM è)‡ãïX}$§‰]H¡ÚÊNCÄ^£Io¼^».2VÚ[ù–X*g*ë Ç’Èã$®$ÆiÙ&†?Úé“0y‚$Sæiì]®8óKe¨g2XWÄÐ,|W˜.÷Sf²òüÀr™¿ ù!ži6 "FSrηˆބòÍÙ„CžFœÀÁ† ó3ì®ä‘…G‰”B‡ò<@W"žorÎy…c £eÛ"Ðú/PmÍ!ÛðÉC·NK}óòóö-mö×6:ÿÁË&}ûôk_^µ1cm«#S{ñc³^¼í„¾xæ«·/DH›î£&ÿü†3 ^»ûÅÅ6žH|Ñ+O,ì÷ÃËNÓ-,é5æè³Ï=²Ü¨ëW|¸ºè€ãØcø·ñÇKÇ·|¶ÿêÓÒE@P]K¾E)54Âg-ÝØ Þgßñà ¡ŒpM´dØ!‘f)Â, ›ç,:+ÔÓ†Ùæý@¦é_x¡‘{-j›±¬"'ÕÛ®!ÙØÍ) •Q„ÂÚK:ÿO»]šÎöo;±Óæ8?œ¥ÎLfŒÈ¸¶íÁŽË»}â€6[vÕFfÎѰüm?½ÛEÙ‘ÆydòÇùš]ç«¶S­d“ôiùæT¿}Ï-3ŽøÃÏNþô»>nZj:¼ªb¾|èl¤s¡“Ÿ,ØökT7©ðHÊÓÏz\UºÏ5Ó޻Ƒ^ûþc×_|ó«•MÜ>¹ôé_\YøËë™õ["{T¿;åúkª-ÕŽUÝY#$š`Ò •Ax7]Á–…‡ˆÛÇÌ‹½¦ öä!—\>è“<$¨Ô¹• *\³©”JFÑòÕØ)óFœ÷àí{ýóû—¼Ôåƒxy÷ýó¸içŸ÷ÄÒÍýoJh¯Ë§\ßëö³~úzÕW‡U{PE@Ø%ØÌ|ãfç\SÙÀ{ÐJ9>mí°Væ¤åFbdþZ`ëý´Ê%¥£Ö›·]»þ×lË׬vŒÔ½’ˆ®â|(0yÈKpƒM~ònÒÊžAi¦?²ÔuÎxLÌi·„øÈëÖRcôiÃJe²B3›6ðq6ö!¶ 뤃((kë0O7§qnDs”­\'”º…Y!<’žm)õ%d-~’ýî,Ç¡€ø=BáÁÐhêYž½\(¾ÉÀhÈ®ðiS/¦g>S]fždŽA†*óìAZ».9+Ñ·e—"íqî¶+ˆúqRþà)OÆéGˆàæ—,è˜PPå/]‰ÄFHˆAù¶DÀnãûÐ;cµæßü»ÖcïÇ7|0{uña§žÐcÍ£_¬>²y}zœpõEßžòè›_&ÊÆŸrÑ ¡Ïo˜ÿU;ݼ©èUŠ€" (»0D@fu²ºöý–MœÛRÂõ¿ã¶Å ·2xM›%ó«ÀîË1NbÑNÓ_þ'*Â25ð"ûIxHL ³Yqÿº[¹L¬ÄNÙÛÇ•@˜bÀ/{ûL¬ #åìÙEž$.ùML~A^fçŸ!¼"U;Òq¼:ŸnLºÃ)g4ãŽW|ËÍöå x¶–Ø1\î^0/I"—Šl«äB‹‘Å ¨'1£3qÉ=îó`¼ŽD%1´åß™¸X;Ì1aOäÞ!Ms¡¤éa¶Ý&]‹K¶7J¨iän®—‹­E$Ìaá<4È'¦o´g‚tÃÅqg'aÒÇåÄ+μê$hLðÃÀúUYy µY“–m‹À¦ú=¶íì6-Uøëÿk9ž“þuýOŸúâ«æ[L®ùàÊc/º÷µÛËÜ©µï?õ§ŸÜ2cÍæÊÛÛ[PE`·F@ˆfk¥‰/¶vnKÔÁà$Á8ä½ZTa x‰E%&P´×Sh(¦°Fë&›‰°F+´›vC 9PDz5q‘»&‹?CV‘IJÔŽ,éȱM§$¢˜‘œeá2OZ f]†+›(èÊöïÂΩ”ÝF‹¶¶¸¸8hд…ÛzXµèÖ¦ø Ž!IŽcG´¦mÃÅeÉ-Ÿä„–m…ÀÎħ«g^}ØÐ«[E&½ô©ïó©VOµS]úÂ/xáí´ÐSŠ€" (ŠÀVAÀò ÓµÉJ+†‹LjХɭ“å¦+äÏ6ÈT[væ—vê¸Ù r”œ j™.ÄQÌÎÏDÇvÅ“‰d¢@È­3˜Êâ†fŸQ–³>/ô߃Û9c=†ƒÂ“IOJ<DŒ–(ÍÉ41:HÇ"4Õ¸b ýä2ɇŸ'$ÚtM$‰&#ñŒä˜ÄÛ-£™9Zªš²­U6CÞ6¿´#Fhkï27‡À$"´KhWÊãE;Ïéy­ño ‡‹//‰•'N¢WËÀœòˆ«ÅLB"s»xø`!PlK¥™£pvy7óµÛà ¡æIƒØ{‚C"åó‰SFlÓ✖€'±D<q‹[ÜÁ‚ÛBë¿";ŸþŠKÕËE@PEà« `½"ª/ä`~B %-·D ­TbÀAkÈ5( º=žBŸ®œŽÇPXñ‚H1f X(ïèÒVÀæ,›…m›ÀiÃãm4@¢Ö™þ¥$b—JÁ¡MT4Nb£‰ +•|M+´ì{3Ökù¡" ƒ—Ä­3Êz2å8•]¬Õ~? ˜‰[!Ef+)*áÓæqgƒ¦x&¶*,\Ù¨Ê6¥‹Ø:l-ÓÅnÛøª)¢ÄËÒ%þž\•¬¶¾>& ´ãtüÈ%×jÙz(ŸÞzØjÏŠ€" (Š€ `8Ok%w¢™¦hjòísêc›×7õÙaƒÖß„º¦ šù£‡0G†AJ>×t ©Ízc œ.OÂðIþ‚U»bŽ Ï…ôJro<å¦#qVxÜDÎð³ÇÏ÷@Z‰ãa²±˜~ò.YÓ¸™%á¡ ßð'“®XœÄìr"¦Òâ6sJTiQ† »ÄµLàg{œ5ÙÞZ)-Ô\óËs‚Rcè †­TÚ‰vâì}ÌÝÓnýz‰ÃQ÷æON<êòÿ)ÙJsÒnE@Pv–kÙ-$¥ dÒã‡q,œ„[GÉ-ŽåÃÆø3~¯GêáÓhØd81¬TY1K1^dç áLdz†G¦c Ü’¼pkk)2,]bšÝq+gå9ÎÌücÙ«3ÙqI:Ñä9ÞZ Ö~7 õÎ!ßÐ3ûhÞ y}6ãŸ?9²Ã Ç^2íÓ·ïžÔ×~»ådÁèKžþØ^’Ÿ;íÒ½ ×_ÙÊU›5Ñ­t‘«üøûÿsßÉýÖ¯i+ d»Í¿÷äCOÛ$2½eg˜]9ýÜ #†ù‹·ÖmÕ…j犀" (»/¸à¾H2Þ6Ä"‘hC8ÒMÔGâuáhmc¤.oˆ&ñ ‚+Ù Í+ÕKòâ ’HE“iÛ²¶1ÊUTòjˆÆ¹–ØiÒÇD"Òƒ•i·†ålâ^cê Ua6sÄ¢ép4ÝI‘Û<NÆ¢RŽÅ"ñ8›"ãØTLDjè= ¨ã¼ á‰t&‘IÅR ûâ©À¼lêãèˆKVH›‡‡òÅØ³âÄÆzîñ‘î‘N£1‚†ÃÑX†Ùø;[‡‡ÑÏ-ØPŸ®~ÿº“ÏyhEɸ“¯¾õúß×,?ÿÞù±¦K‚>d ¿´Çı{L[¶Â>F>ýó¤±fŸÁÐ3üÇÑÓ/8늂n´vU‹Ih…" (Š€" ìt4©ªmN\üH»¢¿"Dzù6Íöæ×&-Š€" (Š@‡ð£¯y¹_a7â¤3Ì ãÊ«!æ¨f¢^õyÕ6&yU7Äkö½.’âE~ûjŒgyÉqܼ¢ø<’ Ø­‘caºâx6âNòÖê:œ¿i &ñ¬¤Zä%vê´¼ˆ;D¨Ž»#Qw8êÄ|õ±dÒ{,i_ ñ”=hL$âÔÇí‹cûB†Û—I².9Ûż‚|mBâë€RöyŽ€LûA×g²-ŠKFVš‹¢rtçîåÖoÕ3NUU|ÒØelß’&åï·ß‘eË}ü¡wÓ{~st·NR«®Êù£r¦¡Î/ÖìsÐÙxú¥¿ŸÖ;Ìß®\)÷뫽ýä£.~­ÿ©ßß»K®ÚÝë×Ür~É3ç}m¯}¿ù›O÷¿ú¶· w£ÿùö‚Wn:xð¿Ÿñ™0Ý·þtd÷ÎÍ¢xÜn8»àñ3ùÖo?›pé/'ÞÀSÄÙs Ÿ8ëÈïß÷i¤©Ãºw¯ÿæžm-ZŸ|»3ôö=îú?ÿßà9¿>á qŸýyL½ý¶ºJOŸcuË…]Ÿ;ïпröØ_{â@󤓬Yû‹g^~èêÇv5)Rµ(Š€" (M^a+¦nøž#|&ØE³—Ýç'Þ "k,–ŽFãÆäÀ»‰ÕÁQÓ„ÈÕ¶C+ÜRI3É€(¦étïF¢ö”oj Ï–çÙýØâÑa«,^;ímíGL' g0ä‡o‹µÃW¾ï‘]W<ûÞÇU¹ú¨=»ýwmeÇ7²ƒ«>ºó”ïìÜùöfX8òijÆ,ùÓ9·ýçË„#X[·œ¦NÛŸak ûqÚ¾ _øðìUGõÔi•G1ªëc‹Ve±EO_}Â+#¹àò?½paÅ#·Þrßç×m8\kj" (ŠÀý§˜|‡Ð+{öˆ¼!ºªÄ’–í|&5ÿ'Òçà%nҚ̂ÖlÖMNAÙ„H0hüâ‘Nòÿú·ù¯‘ám _ù6Øál2BBo“ËÑA0j’ˤeaxWÈñí¦+²–\‘,‰ÚP!n³]‹€%f"+ÏàèdŒø-ÍÄ»bò–³MS”é¡DÜþÂV'ÄëAþq¬ú+¯H;ز´Å§="6Ò·ß Oï »¯~aÎŠÄºÈ ;®üƈ²W+«:šÉæ]Õf¯®òþöï?Zòä¯Îœ8u~ýÆ…ê¾úÁJá®ü•sº¼’N‰&¾’^]5Kª¬%)®\ Œ* ´9JçNÔ-|uΠÓù‹#S6øf×Îé­¥²wwñô;p—w¦´>ùv®tu4®´vΧ«ÛÈÙþ [븠¬·{^úÔû—æÎFß±ÈëXe‘¤jçN»é‚ïß÷Ìn™úÎ/?¹ó¢³ïühCI¼µNµNPE`wFÀ(©kFt¶©ùÙPjŠIùB+úŠ3Øðiɹ-'r›s 4mÝn!®y·´ísèµV62ÙÒå9Àre§øÂs%Wc(µð~)²jÈ´¬E–ëÀ m›qL'£>c¡–³V“¦=²tAA™& %B½‘Ãeg$%Ç::é+´l]ÚàÓÞnÃFV½µ¤ÖÜ1wïq÷ôµ¯½0÷:;›%ßVúƬÚö§¶yWµÝgfù³—ž¼öÔÿ켟\ï(¼ùÎÏ^kó-ÿ6Q·ªÆÑ¥× cy˜¯ma÷þ±•uù]–üxBžT·ù«¼9¥ |ü¨àê§–ÕoÎÅm]“Ÿ¼4hc†üEå ÖþÊì·ßAB ­ö×éFk–U-™ù—s~ðô²ULÇîР¯Ÿõ“Ë¿7¤bÊÏoýÛsŸ*™no­TÝOž6YRe(‘[£˜åî¾5“š£í?ÔMb1i­ý-ד·,»D𦅡¢¾Ê¿‚"Y­ÿ7^¸r–Ä*üaô`„î¦"gÖ7´çO2Þ‰bÿ5Íý›*±µ¥G“È%_¤gIÎKÞ›zµãyͿۼÉ?˹œHéì6ä{áòÈÎK¡×&Ù -H éöø>¼äÇ‚æí °]Óæº‘d1………¡PÈç›e&Hg°dK¼>ZÊzEæ+û°"³±<ÆÎ§ÕÅ›/F·8-¾yì¢-ìµïWü°ß¼G^XhT]w¯½&ö[|ëñcG :bȈ‰W½îÛÿÈ¡„0n·t|UhìÅÍzñ¶úvÖ“›‰­˜õÀ“>ãoËöûõ3¯>ríIûyÓ«f?5'4é’ïŒï õ=òì‹÷ Ïxöóü£@6\½<[~ÄAÃJƒe#&žpx¿Î)×n_¨0XÐ}ÔäŸßpfÁkw¿¸¸ •¸]„:w²¦«¿ü¤®×7Û¯ï{þ‡›¿ßו&ëú.7}†ñE¯<±°ß/;iL·`°¤×˜£Ï>÷Èrc vË¿vÎÍO¼òè…}Þú͉ß:÷wOZÝKþʃ9IDAT稭E@Øé€m4g+Nît Ñ o°¥˜áG0UË;Û m4<»¹Pö6+b^‘XÚ/bw2«Lcð@™æ¶M%gëêê°YC»m˜maï(o[dÚÉWB`Ãÿ"”¿vú‡ó>|åÞS3\õË©K irõš0yxäõY‹­e"½êý—…<|¨ÝÔ×Ö踊4ôDo÷ð«M[´ZŸnürÆß.ùöijMN¼`òˆf±®[o¾òå미§á¤{f}üÞË¿3çÆŸÜ9§™š\ûþ?n{±ð¿÷ñ[ÿ¾ho_'#—îsÍ4®xüŠas®¿ø¦W+7åQ°ÇA·¼òùú¸­Nºye3lüäßüsÙ7þòòÌ¿6ÿÆß:;ZÒ»™¥¬£ši,üðÁÓ7=Î$—>ý‹+qÿ‘Y|òÞ+÷œÑ«rQµyN(wÆ÷öþòö“?õç¿»šMÚZE@ؽ€è´¤Ôù_ðwolÌꎛ+"¨¶úï<ªj^<¶AP¬yÑÞ•ëÁö#©„\йZüÕd`lzÅ:ÿÚBØË4ÒíËŽ%3BÞè•"Í£IOÈ Ñ<™v$Òô"06¯X‚W†Ä3dE'yO¦Èé(ü[ÂNKÔ?âu×µX`š éLŠ€Ô0骪ª5UÕÕõ 6Áë!Nt·±ÑÈ«I—ÞBëÖn6gyŸÞ›}ñîya;ÙwO@tÕŠ€" ì>|Òé,öÙ{þbÃP˜ß÷s&ÚÝ„ŽWÚìçÒæd±½ÖGc\°ºž%ܰfþ—ÒfT›+ÈÑÑvkÔlŠŒ%Cvàú0#ŠÃN/“m¾€®• %K®Ø>ì;þË{Ŏ׃Œf¹´ ä&“¹õMgØ•èD“Æ5Nt<òDsˆx¯mÌ“†˜+!U¢\ë2ûÅ;.˜Ø ¿‡y€±hn*:råÎV®ºêª%QYøÌ'ÞæÞ†zG˜šÎAPE@Ø!¸øâ‹wÈyé¤E`û  |zûண*Š€" ì¼Xalç¿Î\P¶,ʧ7ÏôÒ§¾ÿͧ6ù2½@PE@PE`WD@ýÓ»â]Õ5)Š€" (Š€" l+6Œï±­FÕqE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]åÓ»Æ}ÔU(Š€" (Š€" l”OoÜuTE@PE@P]¶ø´'3êκ³/H{Z.SO5Çd7D£åWBkE@PE@Ø}hƒO‡ÒÛ÷Ò£îT hôTsHvC4Z|#´BPE@PÝVùtajüEé5ó¯lhžjÉnˆF‹o„V(Š€" (Š€"°{#Ð ŸÎv›Uëí®ìÆØè©æˆì†hlü…ÐÏŠ€" (Š€" ìö´ðG»ú$?ÃñÑÿùª[X=ôTó¯ËnˆÆnÿ·EPE@PE %éÓÎÌàK£e3ƒÌsnÜVO5Gd7Dcã/„~VE@PE@ õiߨÄÁ{»gžå‰¶°zè©æß—Ý ýë¢(Š€" (Š€"ÐÍõi_zÌñÄ”àü•-Zê©æì†h´øFh…" (Š€" (Š€A Ÿ.9*ºÈ÷ÊÓ­ÄÈÓSÍ¿.»!ú·EPE@PE  ò|ºkòËÒ‹ï叟h©§šC²¢Ñ⡊€" (Š€" (M8ËûôV4E@PE@PE`óh%þôæu¤W)Š€" (Š€" (»!ʧwÛ®KVE@PE@Øb(ŸÞbPjGŠ€" (Š€" (»!ʧwÛ®KVE@PE@Øb(ŸÞbPjGŠ€" (Š€" (»!»Ÿ .}òÉòsµÈ•¾moì2M]´³gèÞç‡|ùÆ/§÷>±×¦^­íE@PE@ØMؘOûú—üã–®{ºö¿´Ïßöº·,žÒÀ×ö›;½Ïwún3Ž}Q{ÒIËïýrãdé®^E<Ôûä>Ûh1mMcó†ß¼ÉoÆUÙ5ç»pèwÖ¾U½y3Õ«E@PE@Ø؈O;û/ð}®ðNœš:'™Þ昄†wyð=ŽJÆ—4nó±u@E@PE@PE`Èói÷ÁWöÿòÁ/]^xèYåOëýñEüméHÿ&ö—oîõ|BÉÁ{87Mav8 ¼‰»~´ôì"k’›2tQðÚ‡6Ç«à. |ïÚ¾Ÿ¼1ä‹çÊû oÐŒ)·ûz÷[]_øïàWU<þ nÿ™1äõ_õóv4¥v¦Ñ=tÏ”>gZü‡û}ùꀿý?hS¡i1xéÈ’[„CcÁS}®9Â[йÝEþï^U>û5×ÿzˆ§EÇZ¡(Š€" (Š€"ÐYò|:=ó¦%ƒŽ[ùØœ†óOøâ°_pùþ?¬ïlG·K¦WÄýWßÝÿáKŠÆvéÑ3]¬ý4¢ðŠ£üw­q´wUᢳG$n¿¢ê…%YG SŸØöw¤ÃUkE@PE@Pv&6àÓÅ{x]k"5~ßi=2ï.ëŒwÚ¨Ú7µ¹àT]|Ú_W¾øïàYWö|ö¹îß·ê¬ûc émv¸eO”z»uó_öÏA—åúÍÌyÕÅÃA‚õÉw—§³NGº:ñæ’tv‹x"¯~šKÆ‘q:|_i³§«¸‡ËQ›¬Ž™©g3•+3aîí9eý¥õ±OÖ*Þ²_%íMPE@Pv_ò<1¯4‡æœdàxlÈu9¥¹tÚѧsW…úž}~×3$¦ÜXõ—ñíB¦³Y¬Ó#^î xd´.Yµ"r×OV>µrƒ5ndOپܳÉgêÑÔK½eDzŽoW÷>®ØštÞžÓÆU4t¸œëj/è<¨ÜÕÐÎíÕSŠ€" (Š€" (!çÓé™Yó^]¾¸yõ›#zÞ4¶î’ÛptXÚÓ§ zœv^׋ö˾|oåñ¿®Õwû”l4µ<ë9b_ßÖ¥öØ¿ ×ÂÆWVIŽ/ ?¾¸äÂs‹+îj\˜t ™Ú?ž23¹I;!·ö’ÚšüÊëß?«ÛeÇG®z&œPzÉÞ™¿ŒçoY[WU/×õ?®aMmÁÕ?-éër|Ñá&˦†F–Ý÷û¢•w­¼â¥ ¢­} ´E@PE@PÚA`½#¸h@á¨XxÎ:ÏGºçýo=3kçâvO¹÷:©dï%U“NYþ³§7L—íÛãµ7†ÈÂ~Áß=2øË7úÿ~ßM1Ft-¸õñ!SºM5›]]ìw‡ ¿WþþËŸø~À—w²$“Oÿ~ÍîÒG§úlú€ûNòT.KoÚßê4Úū͓mL>½&üÛëkŽéýÎ˃þ{¹ÿ½;×ÜùI³Í…m\Õ8¯öW$º¡ÿ[7οkÍ­fŠ{º76r›ÉùbŸïõß@©wºÓãvlÂöÒ6W¥'E@PE@ØEp–÷齋,E—¡(Š€" (Š€" ls¾bÄŠm>_PPE@PE@Ø‘P>½#Ý ‹" (Š€" (ŠÀΆ€òéíŽé|E@PE@Pv$”OïHwCç¢(Š€" (Š€"°³! |zg»c:_E@PE@P Nñig¯èŸ©Ú¿ïæLÜ;¬ñò—×>dë&EÙñg¸9ØmµkÃÏyâõGÏÖa:ÅM»÷Ñ7?ûÐÙ÷xÇ­L¤³c¹Ê¿ÿÅN¸ER\¶2M­ò =ã_¯?þƒ‘G)ÜÔ~´½" (Š€" ì tŠO•¹&„n=ªÛ+ ;³8[r`ã9ÿ^}Û'+o{}í.‹u~•ñ;¾vÓgØqŸ;x‹Øü{O>ô´ûäÓ)n™ùºº|ñ{¼|Ó¿ç7u,\ö?÷ÜoS"ˆwn.-ÇâºÂ±—Lûôí»'õÝòãunVi•¨xð;‡žò÷¹6S|g®Ø¢mü}¿uícTÌ[ðο®ØÇ·EûÖÎE@PݭΧ7Ö‚ñ ç^î×- w—d ÷©?ëg±’nš›º¬Ý¡}Áž'Ÿ7jÁ½ÿút$•ou¬à€ƒè/=qì;2¡Þ®ß…²}xéó¯:lÿão|íÔ =ôoÖv½:¸" (ŠÀ®À†ÿœz2ƒ¿_óÓ×WÞ6üßu'œn~:84òÝ'VÝñášóÏH›ÉÍ®¾‘‹Ÿ­:äÀèñ÷®æÂÛŸ®TdÀ)NLž&]ÝñfÕ¾}6†«h|ã9ÏHû;>YuõÑîV(s¥G~7‘üÈ•ø²èOGw{ñï»·”ÌïžÏ9³Ýg¸ñ:¶ÀgŸ+tŒ×‡ _à*þ–ÇÛiÉÐÝuÂyw¾0{aż…¿xóqýsW:‹÷ù¿gßûÏuGô€Uîyîï=yù„âÜ+Ù÷š?—KÞ»ç„òf·×Õçø{ßxåw‡v˵sí1ñÖþý£1] oÐq—}«ö»^_Û,Kc«;{sϳ?mÒÏòÙ+·MÞûˆ+§úÙ«·ß×d>w÷›<åÅûOÿÚQWLykAÅìço:eDhã7Z+ÐÿÀC‹<ývläÄ1­óD_ù±×¿4wöƒÿo½`žî ‰W>4 XæO¿rBqnÖîÒ±§ß<õãŠy³ÿÍ·û7ÿ™Ä]2ê´ß=þö<çõæ_ŽêÑêJ7¨,}ÉÓ›öó~°ÿ¤ý%·3 WhèäßþkVn³˜Ü±0ŸŠ5ÄÓ™¤³Ûžû¯xýóuݬŽ×¥-E@PÝæ„9ÛçŒê³¿ëx÷ÿz^¹ß¿»º`7»^æ+JüÿöÎ<®©c‹ã÷&7 a‘%@dSPd©¢EÑdm)¢¶}ÖZ±©¸¯€ZÄÜi­>kEÅŠ"‚"AÙªBX  Hr{!„5 ÷i?¯¾Ï›ü3sfÎùÎå“ßœœ .A]¼Úá[•´—ñLµF’£÷¸…ò•®h†­¦×wI»:ÈÉ‹t·|¨þôåÌ”ÞY›ùš™Bì˜ µ®ÿNI$“šÐ˜L¬§A­W•X…ŒBÈÓ:T—)yÛ <Ê›7 °ò*ª‚è Z»h {Âhù({ Šñ¢í+&el[`cme¿<&»MzúA; ãŽ?wÚè1möW!ËásÁñìíÂݦ›9íε)âÆì¸ëüw?«Û¿çˆþüO§r®Þ|2¸›²¶™Î—‘¯O«J›t>H¸÷4+r¾ÉÜo3ËûDdî'mi§Æ\ÿ„£ëb_¼»3ÒO|Ä?æ¹éû¦jÒ^U›õ|hI«¸ï/·Ý¼ÔdD=¶Œµú )sœ4Î'ýëhºÛ é¹`Èm²®Û7 {¦ß^ëás±nð_Î÷õ«`Ëù*_úÒÉ;±l0^DÏ#$z­æõÕïÙ9Þ·Úºw±‘ô¤Cšä~l‹Ia¨—½Í|ŸÓñåã»ÊŽ-±2b>Õ10çÅ[?É YD†ã®cA3JÃ<í,mÿñmQÛ˜Ie4tŸû‰å—öãÒšCAç*ÿ¦¢Ž&@@à—À0=­Ö3o±ˆuLõNñ•€Àɧåd!½ƒ‘àêãê©Yç1¹M(VUÓL„ëÔ¯\#q›H9$Þ™2BB;Rµî66‹_’Ý ´J*n”$$tñ!¢ŠØäãÎw¦ˆU& õtÑW‚~‰ù6x(' 7iîqöt£ÞÊz6¢Æï„ª‘ÊÚVxµ×üB¨ecgk¬*â”§_ËiG‚Çç÷þcÖó§—ó =[ÎÇá_{ÙµÔ6‹eކ˜lT2qZª_{)«¶‡!Ášöký î¸üT04¾)ÍÏ®O;Vçít²Àt¤é¼Í™i·°.=2>£²¾CØ’sôû[ÏØ]¨iða„;‹ŽîÂ×eCÕðƒÐÈ5Ö’êE†âÊîÆ8±ÊZ2’÷Š}Ÿ ½é/}Pü±oîþ:øÞDŸø?ȈßáfD.‹ºë³¯¬ONÈòÝ€Ôômt¥ECŸáX‰b²d»ïäï=·Í‚Žº[™èÒQ¡ì?yó!€ € €ºD Z{ĺbB)ñ¿ðþŠò‘Ò„ ¥‰b]Þç;Û`ŽfJ1jGžõôZèqô~ EÏÙ?´Mo…‡Šžõi uó7:l`º|þUà…#¸újØæ§Šlúûà‰$íU„ž½Â)d½yhç^ÑèªÌ)ÄüšÌ¸€Ì„fîþƒc`ŽwTÑÀbDÆ{¶Íj¾Qþž^þï#C–ïÃײd½™&Ã’øò¦Wd«Í/~ÚÒÍiŒÞ|8êÌþ5Èí€j)%yV @–Òä’ï¥ 7vØ[‰Èªj!˜m/‘&U8½œNÄ@౉?ÕHLáö:b§U’TÈŠ‰å?Q[¹îB:–/ŸËwvÅÖÒ×Û࡜ˆú›[s#wÉkj­½w!âk+sSKíIUãf‡)D̓4z‘€•3¾¥ˆŽóRÅŠD¦Äòd÷­Û>›g¬Iƒ»šYõ-½$:EZîŽ0]¶ØUDo NUñ [3[×Gú"vþ…<Ââ=©×*p©D"ÓqÃJzêÑëÏd¥kQ~kª¿Ð~ª:UÃÜÕËÑߥËD2]™JÓ¶XºëÀ*Zö÷ée'ò×"2­] jca̱Âs× ;äw¦ ÖccÄ„/sb·ÄV½ãk­‚FwMÖ¥*ÿÍ[jQ©jLË||ôû ¨E­ÏJÛ™nžs&éX¯øî÷$‚ˆLqŸÝjÃ…¼ôX/É,=1C}rB–ïÔÑXܤbçioÄ0ûhwÔ¦™ª O&’•xMå¼IŸ|áj¦¡L¸ Í|ˆ¦…Õ}à)/€ ü?®,àºÄ g’ ûÓ͇²ÃyF$hlÆñu 1ºWÞvï&nZ‘65Áò‹MQEìƒgyHšê­‡žJèg¢É†Aœˆü¦ˆn!‹8,UûVxø:Ú á]+¬§»í:ÛÕpN„CMCPOK [Ýã@ÊÝ’Š’‚ ¾äë1ñ…’D#Éä³È}³‹£¢Ò_aÕÉû~¯§ Ë.ýV=nÑ6ƾWè?å~\R…œï-r‹NǦ+¯I*(ɽ¸î²ß¥>kO f‘´cjaø†ÈÛœ~+k˜¶KͺîäÕJÎ."vÑ­ú\Ç)#3¶‚êË{ƒ~¥­ÿ!á ÓñÿáLoÝ•Ý?½Î{XZõÃJ&§¦Urdà•þ´/¡Þùä­œSOn¹/PÓU~P€‰B"!DI {ôÞÃ0ö¨cyû‘G&™!c¦òÝxU™~¢lfxÚÝ3Ÿtþ°çTqÚ;Þ“#x|v÷¡{¦;Rò RvLÎôO„üâcéá8aŒŽü€ `}½Á»è@àï'€]—˜à™â·úÒÈK8þ~Ïþ"”ÌWŸ=là½1CzËÇ_2ÝzÛ™pæá/î´üEn‚i@@/—ÂK ŒÞ„ãǦêºÃ2/FsÞ-“ ½B#·¸Ï˜¨B›0yþŠu^ôŠ[O@%ô›l°@^“ÀÐ÷_s`8•Ã’âô!që£_Â’«e•›ã˜fpHoóÃ|ŽÇºfÖ _%ÙÙŒ¯œæ?YŒ@q €zq€ € €€\—u-Æ¡'ƒIEND®B`‚glyr-1.0.5/lib/000077500000000000000000000000001227540770500132515ustar00rootroot00000000000000glyr-1.0.5/lib/CMakeLists.txt000066400000000000000000000023261227540770500160140ustar00rootroot00000000000000# Configuration for Version / versionname configure_file ( "config.h.in" "config.h" ) SET(GENERIC_LIB_VERSION ${GLYR_VERSION_MAJOR}.${GLYR_VERSION_MINOR}) SET(GLYR_API_SOVERSION 1) # Link libglyr as shared library ADD_LIBRARY(glyr SHARED ${LIB_SOURCE_LOCATIONS}) # Win32 needs that socket library for libcurl IF(WIN32) TARGET_LINK_LIBRARIES(glyr ${CURL_LIBRARY} ${GLIBPKG_LIBRARIES} ${SQLITE3_LIBRARIES} ws2_32) SET_TARGET_PROPERTIES(glyr PROPERTIES OUTPUT_NAME "glyr-${GLYR_API_SOVERSION}" VERSION ${GENERIC_LIB_VERSION} ) ELSE(WIN32) TARGET_LINK_LIBRARIES(glyr ${CURL_LIBRARY} ${GLIBPKG_LIBRARIES} ${SQLITE3_LIBRARIES} ) SET_TARGET_PROPERTIES(glyr PROPERTIES VERSION ${GLYR_API_SOVERSION}.${GENERIC_LIB_VERSION} SOVERSION ${GLYR_API_SOVERSION}) ENDIF(WIN32) # Install Files INSTALL(FILES glyr.h DESTINATION ${INSTALL_INC_DIR}/glyr) INSTALL(FILES types.h DESTINATION ${INSTALL_INC_DIR}/glyr) INSTALL(FILES misc.h DESTINATION ${INSTALL_INC_DIR}/glyr) INSTALL(FILES cache.h DESTINATION ${INSTALL_INC_DIR}/glyr) INSTALL(FILES config.h DESTINATION ${INSTALL_INC_DIR}/glyr) INSTALL(FILES testing.h DESTINATION ${INSTALL_INC_DIR}/glyr) INSTALL(TARGETS glyr LIBRARY DESTINATION ${INSTALL_LIB_DIR}) glyr-1.0.5/lib/README000066400000000000000000000005151227540770500141320ustar00rootroot00000000000000This folder contains the implemantation of libglyr. All subfolders implement a getter: cover,lyrics,ainfo (..) A corrsponding .c file (cover.c, lyrics.c, ainfo.c... ) implement the getter itself. All other files implement the general webscraping abilities of glyr. Start reading src/main.c:main() to get through it.. Good luck! :-) glyr-1.0.5/lib/apikeys.h000066400000000000000000000026121227540770500150700ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a command-line tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011-2012] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef APIKEYS_H #define APIKEYS_H /* * Please register your own keys if you fork parts of this code! * */ #define API_KEY_AMAZON "AKIAJ6NEA642OU3FM24Q" #define API_KEY_LASTFM "7199021d9c8fbae507bf77d0a88533d7" #define API_KEY_FLICKR "b5af0c3230fb478d53b20835223d57a4" #define API_KEY_GTRANS "AIzaSyDzfBNb-W5G9pvZY6KGbEoRK4JvOIhUsjI" #define API_KEY_HTBACK "b3085ed18168f083aa69179b3364c9d8" #define API_KEY_ECHONEST "ZSIUEIVVZGJVJVWIS" #endif glyr-1.0.5/lib/blacklist.c000066400000000000000000000040211227540770500153620ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ /* The blacklist consists of two links at the moment :-P */ #include "blacklist.h" ///////////////////////////////// GHashTable * lookup_table = NULL; gchar * blacklist_array[] = { "http://ecx.images-amazon.com/images/I/11J2DMYABHL.jpg", /* blank image */ "http://cdn.recordshopx.com/cover/normal/5/53/53138.jpg%3Fcd" /* blank image */ }; ///////////////////////////////// void blacklist_build (void) { lookup_table = g_hash_table_new (g_str_hash,g_str_equal); gint b_size = sizeof (blacklist_array) / sizeof (gchar *); for (gint it = 0; it < b_size; it++) { if (blacklist_array[it] != NULL) { g_hash_table_insert (lookup_table,blacklist_array[it],blacklist_array[it]); } } } ///////////////////////////////// void blacklist_destroy (void) { g_hash_table_destroy (lookup_table); } ///////////////////////////////// gboolean is_blacklisted (gchar * URL) { if (lookup_table == NULL || URL == NULL) return FALSE; return ! (g_hash_table_lookup (lookup_table,URL) == NULL); } ///////////////////////////////// glyr-1.0.5/lib/blacklist.h000066400000000000000000000021561227540770500153760ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef GLYR_BLACKLIST_H #define GLYR_BLACKLIST_H #include gboolean is_blacklisted (gchar * URL); void blacklist_build (void); void blacklist_destroy (void); #endif glyr-1.0.5/lib/cache.c000066400000000000000000001141241227540770500144630ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "cache_intern.h" #include "cache.h" #include "core.h" #include "glyr.h" #include "register_plugins.h" /////////////////////////////// enum { SQL_TABLE_DEF, SQL_FOREACH, SQL_DELETE_SELECT, SQL_ACTUAL_DELETE, SQL_LOOKUP, SQL_INSERT_CACHE }; static const char * sqlcode[] = { [SQL_TABLE_DEF] = "PRAGMA synchronous = 1; \n" "PRAGMA temp_store = 2; \n" "BEGIN IMMEDIATE; \n" "-- Provider \n" "CREATE TABLE IF NOT EXISTS providers (provider_name VARCHAR(20) UNIQUE); \n" " \n" "-- Artist \n" "CREATE TABLE IF NOT EXISTS artists (artist_name VARCHAR(128) UNIQUE); \n" "CREATE TABLE IF NOT EXISTS albums (album_name VARCHAR(128) UNIQUE); \n" "CREATE TABLE IF NOT EXISTS titles (title_name VARCHAR(128) UNIQUE); \n" " \n" "-- Enum \n" "CREATE TABLE IF NOT EXISTS image_types(image_type_name VARCHAR(16) UNIQUE); \n" "CREATE TABLE IF NOT EXISTS db_version(version INTEGER UNIQUE); \n" " \n" "-- MetaData \n" "CREATE TABLE IF NOT EXISTS metadata( \n" " artist_id INTEGER, \n" " album_id INTEGER, \n" " title_id INTEGER, \n" " provider_id INTEGER, \n" " source_url VARCHAR(512), \n" " image_type_id INTEGER, \n" " track_duration INTEGER, \n" " get_type INTEGER, \n" " data_type INTEGER, \n" " data_size INTEGER, \n" " data_is_image INTEGER, \n" " data_checksum BLOB, \n" " data BLOB, \n" " rating INTEGER, \n" " timestamp FLOAT \n" "); \n" "CREATE INDEX IF NOT EXISTS index_artist_id ON metadata(artist_id); \n" "CREATE INDEX IF NOT EXISTS index_album_id ON metadata(album_id); \n" "CREATE INDEX IF NOT EXISTS index_title_id ON metadata(title_id); \n" "CREATE INDEX IF NOT EXISTS index_provider_id ON metadata(provider_id); \n" "CREATE UNIQUE INDEX IF NOT EXISTS index_unique \n" " ON metadata(get_type,data_type,data_checksum,source_url); \n" "-- Insert imageformats \n" "INSERT OR IGNORE INTO image_types VALUES('jpeg'); \n" "INSERT OR IGNORE INTO image_types VALUES('jpg'); \n" "INSERT OR IGNORE INTO image_types VALUES('png'); \n" "INSERT OR IGNORE INTO image_types VALUES('gif'); \n" "INSERT OR IGNORE INTO image_types VALUES('tiff'); \n" "INSERT OR IGNORE INTO db_version VALUES(2); \n" "COMMIT; \n", [SQL_FOREACH] = "SELECT artist_name, \n" " album_name, \n" " title_name, \n" " provider_name, \n" " source_url, \n" " image_type_name, \n" " track_duration, \n" " get_type, \n" " data_type, \n" " data_size, \n" " data_is_image, \n" " data_checksum, \n" " data, \n" " rating, \n" " timestamp \n" "FROM metadata as m \n" "LEFT JOIN artists AS a ON m.artist_id = a.rowid \n" "LEFT JOIN albums AS b ON m.album_id = b.rowid \n" "LEFT JOIN titles AS t ON m.title_id = t.rowid \n" "LEFT JOIN image_types AS i ON m.image_type_id = i.rowid \n" "JOIN providers AS p on m.provider_id = p.rowid \n", [SQL_DELETE_SELECT] = "SELECT get_type, \n" " artist_id, \n" " album_id, \n" " title_id, \n" " provider_id \n" " FROM metadata AS m \n" "LEFT JOIN artists AS a ON a.rowid = m.artist_id \n" "LEFT JOIN albums AS b ON b.rowid = m.album_id \n" "LEFT JOIN titles AS t ON t.rowid = m.title_id \n" "INNER JOIN providers AS p ON p.rowid = m.provider_id \n" "WHERE \n" " m.get_type = %d \n" " %s -- Title Contraint \n" " %s -- Album Constraint \n" " %s -- Artist Constraint \n" " AND p.provider_name IN(%s) \n" " %s -- 'IsALink' Constraint \n" "LIMIT %d; \n", [SQL_ACTUAL_DELETE] = "DELETE FROM metadata WHERE \n" "get_type %s %s AND \n" "artist_id %s %s AND \n" "album_id %s %s AND \n" "title_id %s %s AND \n" "provider_id %s %s; \n", [SQL_LOOKUP] = "SELECT artist_name, \n" " album_name, \n" " title_name, \n" " provider_name, \n" " source_url, \n" " image_type_name, \n" " track_duration, \n" " get_type, \n" " data_type, \n" " data_size, \n" " data_is_image, \n" " data_checksum, \n" " data, \n" " rating, \n" " timestamp \n" "FROM metadata as m \n" "LEFT JOIN artists AS a ON m.artist_id = a.rowid \n" "LEFT JOIN albums AS b ON m.album_id = b.rowid \n" "LEFT JOIN titles AS t ON m.title_id = t.rowid \n" "JOIN providers as p on m.provider_id = p.rowid \n" "LEFT JOIN image_types as i on m.image_type_id = i.rowid \n" "WHERE m.get_type = %d \n" " %s -- Title constr. \n" " %s -- Album constr. \n" " %s -- Artist constr. \n" " %s \n" " AND provider_name IN(%s) \n" "LIMIT %d; \n", [SQL_INSERT_CACHE] = "INSERT OR IGNORE INTO metadata VALUES( \n" " (SELECT rowid FROM artists WHERE artist_name = LOWER('%q')), \n" " (SELECT rowid FROM albums WHERE album_name = LOWER('%q')), \n" " (SELECT rowid FROM titles WHERE title_name = LOWER('%q')), \n" " (SELECT rowid FROM providers WHERE provider_name = LOWER('%q')), \n" " ?, \n" " (SELECT rowid FROM image_types WHERE image_type_name = LOWER('%q')),\n" " ?,?,?,?,?,?,?,?,? \n" "); \n" }; //////////////////////////////////////////////////////// ////////////////////// Prototypes ////////////////////// //////////////////////////////////////////////////////// static void insert_cache_data (GlyrDatabase * db, GlyrQuery * query, GlyrMemCache * cache); static void execute (GlyrDatabase * db, const gchar * sql_statement); static gchar * convert_from_option_to_sql (GlyrQuery * q); static double get_current_time (void); static void add_to_cache_list (GlyrMemCache ** list, GlyrMemCache * to_add); static int delete_callback (void * result, int argc, char ** argv, char ** azColName); static int select_callback (void * result, int argc, char ** argv, char ** azColName); //////////////////////////////////////////////////////// ////////////////// Useful Defines ////////////////////// //////////////////////////////////////////////////////// #define INSERT_STRING(SQL,ARG) { \ if(SQL && ARG) { \ /* We have to use _ascii_ here, */\ /* since there seems to be some encoding problems */\ /* in SQLite, which are triggered by comparing */\ /* lower and highercase umlauts for example */\ /* Simple encoding-indepent lowercase prevents it */\ gchar * lower_str = g_ascii_strdown(ARG,-1); \ gchar * sql = sqlite3_mprintf(SQL,lower_str); \ execute(db,sql); \ sqlite3_free(sql); \ g_free(lower_str); \ } \ } //////////////////////////////////////////////////////// /* Ensure no invalid data comes in */ #define ABORT_ON_FAILED_REQS(REQS,OPT_ARG,ARG) { \ if((REQS & OPT_ARG) == 0 && ARG == NULL) { \ glyr_message(-1,NULL,"Warning: %s != NULL failed",#ARG); \ goto rollback; \ } \ } //////////////////////////////////////////////////////// #define ADD_CONSTRAINT(TO_CONSTR, FIELDNAME, VARNAME) \ { \ /* We have to use _ascii_ here, */ \ /* since there seems to be some encoding problems */ \ /* in SQLite, which are triggered by comparing */ \ /* lower and highercase umlauts for example */ \ /* Simple encoding-indepent lowercase prevents it */ \ \ gchar * lower = g_ascii_strdown(VARNAME,-1); \ if(lower != NULL) \ { \ TO_CONSTR = sqlite3_mprintf("AND %s = '%q'\n",FIELDNAME,lower); \ g_free(lower); \ } \ } //////////////////////////////////////////////////////// #define CACHE_GET_PROVIDER(cache) (((cache)&&(cache->prov)) ? ((cache)->prov) : "none") //////////////////////////////////////////////////////// #define SQL_BIND_TEXT(stmt,text,pos) { \ int cpPos = pos; \ if(stmt && text) { \ int rc = sqlite3_bind_text(stmt,cpPos,text,strlen(text) + 1, SQLITE_STATIC); \ if(rc != SQLITE_OK) { \ printf("Could not bind value: %d\n",rc); \ } \ } \ } \ //////////////////////////////////////////////////////// /* How long to wait till returning SQLITE_BUSY */ #define DB_BUSY_WAIT 5000 #define DO_PROFILE false #if DO_PROFILE static GTimer * select_callback_timer = NULL; static float select_callback_spent = 0; #endif //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// typedef struct { GlyrDatabase * con; gint deleted; gint max_delete; } delete_callback_data; typedef struct { GlyrMemCache ** result; GlyrQuery * query; gint counter; glyr_foreach_callback cb; void * userptr; } select_callback_data; //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// //////////////////////////////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrDatabase * glyr_db_init (const char * root_path) { GlyrDatabase * to_return = NULL; #if DO_PROFILE GTimer * open_db = g_timer_new(); select_callback_timer = g_timer_new(); #endif if (sqlite3_threadsafe() == FALSE) { glyr_message (-1,NULL,"WARNING: Your SQLite version seems not to be threadsafe? \n" " Expect corrupted data and other weird behaviour!\n"); } if (root_path != NULL && g_file_test (root_path,G_FILE_TEST_EXISTS) ) { sqlite3 * db_connection = NULL; if (g_file_test (root_path,G_FILE_TEST_IS_DIR) ) { gchar * db_file_path = g_strdup_printf ("%s%s%s",root_path, (g_str_has_suffix (root_path,G_DIR_SEPARATOR_S) ? "" : G_DIR_SEPARATOR_S), GLYR_DB_FILENAME); gint db_open_err = sqlite3_open_v2 (db_file_path,&db_connection, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL); if (db_open_err == SQLITE_OK) { to_return = g_malloc0 (sizeof (GlyrDatabase) ); to_return->root_path = g_strdup (root_path); to_return->db_handle = db_connection; sqlite3_busy_timeout (db_connection,DB_BUSY_WAIT); /* Now create the Tables via sql */ execute (to_return, (char*) sqlcode[SQL_TABLE_DEF]); } else { glyr_message (-1,NULL,"Connecting to database failed: %s\n",sqlite3_errmsg (db_connection) ); sqlite3_close (db_connection); } g_free (db_file_path); } else { glyr_message (-1,NULL,"Warning: %s is not a directory; Creating DB Structure failed.\n",root_path); } } else { glyr_message (-1,NULL,"Warning: %s does not exist; Creating DB Structure failed.\n",root_path); } #if DO_PROFILE g_message ("Time to open DB: %lf\n",g_timer_elapsed (open_db,NULL) ); g_timer_destroy (open_db); #endif return to_return; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_db_destroy (GlyrDatabase * db_object) { if (db_object != NULL) { int db_err = sqlite3_close (db_object->db_handle); if (db_err == SQLITE_OK) { g_free ( (gchar*) db_object->root_path); g_free (db_object); } else { glyr_message (-1,NULL,"Disconnecting database failed: %s\n",sqlite3_errmsg (db_object->db_handle) ); } } } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) int glyr_db_edit (GlyrDatabase * db, GlyrQuery * query, GlyrMemCache * edited) { int result = 0; if (db && query) { result = glyr_db_delete (db,query); if (result != 0) { for (GlyrMemCache * elem = edited; elem; elem = elem->next) { glyr_db_insert (db,query,edited); } } } return result; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_db_replace (GlyrDatabase * db, unsigned char * md5sum, GlyrQuery * query, GlyrMemCache * data) { if (db != NULL && md5sum != NULL) { gchar * sql = "DELETE FROM metadata WHERE data_checksum = ? ;\n"; sqlite3_stmt *stmt = NULL; sqlite3_prepare_v2 (db->db_handle, sql, strlen (sql) + 1, &stmt, NULL); sqlite3_bind_blob (stmt, 1, md5sum, 16, SQLITE_STATIC); if (sqlite3_step (stmt) != SQLITE_DONE) { glyr_message (1,query,"Error message: %s\n", sqlite3_errmsg (db->db_handle) ); } sqlite3_finalize (stmt); if (data != NULL) { glyr_db_insert (db,query,data); } } } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) gint glyr_db_delete (GlyrDatabase * db, GlyrQuery * query) { gint result = 0; if (db && query) { /* Find out which fields are required for this getter */ GLYR_FIELD_REQUIREMENT reqs = glyr_get_requirements (query->type); /* Spaces in SQL statements just for pretty debug printing */ gchar * artist_constr = ""; if ( (reqs & GLYR_REQUIRES_ARTIST) != 0 && query->artist) { ADD_CONSTRAINT (artist_constr,"a.artist_name",query->artist); } gchar * album_constr = ""; if ( (reqs & GLYR_REQUIRES_ALBUM ) != 0 && query->album) { ADD_CONSTRAINT (album_constr,"b.album_name",query->album); } gchar * title_constr = ""; if ( (reqs & GLYR_REQUIRES_TITLE ) != 0 && query->title) { ADD_CONSTRAINT (title_constr,"t.title_name",query->title); } /* Get a SQL formatted list of enabled providers: IN('lastfm','...') */ gchar * from_argument_list = convert_from_option_to_sql (query); /* Check if links should be deleted */ gchar * img_url_constr = ""; if (TYPE_IS_IMAGE (query->type) ) { if (query->download == FALSE) { img_url_constr = sqlite3_mprintf ("AND data_type = %d ", GLYR_TYPE_IMG_URL); } else { img_url_constr = sqlite3_mprintf ("AND NOT data_type = %d ", GLYR_TYPE_IMG_URL); } } gchar * sql = sqlite3_mprintf (sqlcode[SQL_DELETE_SELECT], query->type, /* Limit to */ title_constr, /* Title Constr, may be empty */ album_constr, /* Album Constr, may be empty */ artist_constr, /* Artist Constr, may be empty */ from_argument_list, /* Provider contraint */ img_url_constr, /* Search for links? */ query->number /* LIMIT to */ ); if (sql != NULL) { delete_callback_data cb_data; cb_data.con = db; cb_data.deleted = 0; cb_data.max_delete = query->number; gchar * err_msg = NULL; sqlite3_exec (db->db_handle,sql,delete_callback,&cb_data,&err_msg); if (err_msg != NULL) { glyr_message (-1,NULL,"SQL Delete error: %s\n",err_msg); sqlite3_free (err_msg); } sqlite3_free (sql); result = cb_data.deleted; } /** * Free ressources with according free calls, */ if (*artist_constr) sqlite3_free (artist_constr); if (*album_constr) sqlite3_free (album_constr); if (*title_constr) sqlite3_free (title_constr); if (*img_url_constr) sqlite3_free (img_url_constr); g_free (from_argument_list); } return result; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_db_foreach (GlyrDatabase * db, glyr_foreach_callback cb, void * userptr) { if (db != NULL && cb != NULL) { select_callback_data scb_data; scb_data.cb = cb; scb_data.userptr = userptr; GlyrQuery dummy; dummy.number = G_MAXINT; scb_data.query = &dummy; scb_data.counter = 0; scb_data.result = NULL; int rc = SQLITE_OK; char * err_msg = NULL; if ( (rc = sqlite3_exec (db->db_handle,sqlcode[SQL_FOREACH],select_callback,&scb_data,&err_msg) ) != SQLITE_OK) { if (rc != SQLITE_ABORT) { glyr_message (-1,NULL,"SQL Foreach error: %s\n",err_msg); } sqlite3_free (err_msg); } } } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrMemCache * glyr_db_lookup (GlyrDatabase * db, GlyrQuery * query) { GlyrMemCache * result = NULL; if (db != NULL && query != NULL) { GLYR_FIELD_REQUIREMENT reqs = glyr_get_requirements (query->type); gchar * artist_constr = ""; if ( (reqs & GLYR_REQUIRES_ARTIST) != 0) { ADD_CONSTRAINT (artist_constr,"artist_name",query->artist); } gchar * album_constr = ""; if ( (reqs & GLYR_REQUIRES_ALBUM ) != 0) { ADD_CONSTRAINT (album_constr,"album_name",query->album); } gchar * title_constr = ""; if ( (reqs & GLYR_REQUIRES_TITLE ) != 0) { ADD_CONSTRAINT (title_constr,"title_name",query->title); } gchar * from_argument_list = convert_from_option_to_sql (query); gchar * img_url_constr = ""; if (TYPE_IS_IMAGE (query->type) ) { if (query->download == FALSE) { img_url_constr = sqlite3_mprintf ("AND data_type = %d ", GLYR_TYPE_IMG_URL); } else { img_url_constr = sqlite3_mprintf ("AND NOT data_type = %d ", GLYR_TYPE_IMG_URL); } } gchar * sql = sqlite3_mprintf (sqlcode[SQL_LOOKUP], query->type, title_constr, album_constr, artist_constr, img_url_constr, from_argument_list, query->number ); if (sql != NULL) { select_callback_data data; data.result = &result; data.query = query; data.counter = 0; data.cb = NULL; data.userptr = NULL; gchar * err_msg = NULL; sqlite3_exec (db->db_handle,sql,select_callback,&data,&err_msg); if (err_msg != NULL) { glyr_message (-1,NULL,"glyr_db_lookup: %s\n",err_msg); sqlite3_free (err_msg); } sqlite3_free (sql); } #if DO_PROFILE g_message ("Spent %.5f Seconds in Selectcallback.\n",select_callback_spent); select_callback_spent = 0; #endif if (*artist_constr) { sqlite3_free (artist_constr); } if (*album_constr) { sqlite3_free (album_constr); } if (*title_constr) { sqlite3_free (title_constr); } g_free (from_argument_list); if (*img_url_constr != '\0') { sqlite3_free (img_url_constr); } } return result; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_db_insert (GlyrDatabase * db, GlyrQuery * q, GlyrMemCache * cache) { if (db && q && cache) { GLYR_FIELD_REQUIREMENT reqs = glyr_get_requirements (q->type); execute (db,"BEGIN IMMEDIATE;"); if ( (reqs & GLYR_REQUIRES_ARTIST) || (reqs & GLYR_OPTIONAL_ARTIST) ) { ABORT_ON_FAILED_REQS (reqs,GLYR_OPTIONAL_ARTIST,q->artist); INSERT_STRING ("INSERT OR IGNORE INTO artists VALUES('%q');",q->artist); } if ( (reqs & GLYR_REQUIRES_ALBUM) || (reqs & GLYR_OPTIONAL_ALBUM) ) { ABORT_ON_FAILED_REQS (reqs,GLYR_OPTIONAL_ALBUM,q->album); INSERT_STRING ("INSERT OR IGNORE INTO albums VALUES('%q');",q->album); } if ( (reqs & GLYR_REQUIRES_TITLE) || (reqs & GLYR_OPTIONAL_TITLE) ) { ABORT_ON_FAILED_REQS (reqs,GLYR_OPTIONAL_TITLE,q->title); INSERT_STRING ("INSERT OR IGNORE INTO titles VALUES('%q');",q->title); } gchar * provider = CACHE_GET_PROVIDER (cache); INSERT_STRING ("INSERT OR IGNORE INTO providers VALUES('%q');",provider); insert_cache_data (db,q,cache); rollback: execute (db,"COMMIT;"); } } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrMemCache * glyr_db_make_dummy (void) { GlyrMemCache * c = glyr_cache_new(); glyr_cache_set_data (c,g_strdup ("[dummy]"),-1); c->rating = -1; return c; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// // --------- INTERNALS ------------ // static void execute (GlyrDatabase * db, const gchar * sql_statement) { if (db && sql_statement) { char * err_msg = NULL; sqlite3_exec (db->db_handle,sql_statement,NULL,NULL,&err_msg); if (err_msg != NULL) { glyr_message (-1,NULL,"glyr_db_execute: SQL error: %s\n", err_msg); sqlite3_free (err_msg); } } } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// /** * Return the current time as double: * . */ static double get_current_time (void) { struct timeval tim; gettimeofday (&tim, NULL); return (double) tim.tv_sec + ( (double) tim.tv_usec/1e6); } //////////////////////////////////// static void insert_cache_data (GlyrDatabase * db, GlyrQuery * query, GlyrMemCache * cache) { if (db && query && cache) { int pos = 1; char * sql = sqlite3_mprintf (sqlcode[SQL_INSERT_CACHE], query->artist, query->album, query->title, CACHE_GET_PROVIDER (cache), cache->img_format ); sqlite3_stmt *stmt = NULL; sqlite3_prepare_v2 (db->db_handle, sql, strlen (sql) + 1, &stmt, NULL); SQL_BIND_TEXT (stmt,cache->dsrc,pos++); sqlite3_bind_int (stmt, pos++, cache->duration); sqlite3_bind_int (stmt, pos++, query->type); sqlite3_bind_int (stmt, pos++, cache->type); sqlite3_bind_int (stmt, pos++, cache->size); sqlite3_bind_int (stmt, pos++, cache->is_image); sqlite3_bind_blob (stmt,pos++, cache->md5sum, sizeof cache->md5sum, SQLITE_STATIC); if (cache->data != NULL) { sqlite3_bind_blob (stmt, pos++, cache->data, cache->size, SQLITE_STATIC); } else { glyr_message (1,query,"glyr: Warning: Attempting to insert cache with missing data!\n"); } sqlite3_bind_int (stmt, pos++, cache->rating); sqlite3_bind_double (stmt,pos++, get_current_time() ); if (sqlite3_step (stmt) != SQLITE_DONE) { glyr_message (1,query,"glyr_db_insert: SQL failure: %s\n", sqlite3_errmsg (db->db_handle) ); } sqlite3_finalize (stmt); sqlite3_free (sql); } } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// #define DEBUG_LIST false static void add_to_cache_list (GlyrMemCache ** list, GlyrMemCache * to_add) { if (to_add && list) { GlyrMemCache * head = *list; if (head == NULL) { /* Initialize list */ *list = to_add; } else { /* Find rating in list * head will store the first non-matchin item, * tail = head->prev * */ GlyrMemCache * tail = head; while (head && head->rating > to_add->rating) { tail = head; head = head->next; } /* Now see what timestamp we have, * and sort it accordingly, younger * caches (== higher timestamp), are sorted * at the start */ if (head != NULL) { int last_rating = head->rating; while (head && head->rating == last_rating && head->timestamp > to_add->timestamp) { GlyrMemCache * p = head->next; if (p && p->rating == last_rating) { tail = head; head = p; } else if (p == NULL) { tail = head; head = p; } else break; } } /* Check if we're at the end of the list, * If so just append it, * else we insert to_add before head */ g_assert (tail); if (head != NULL) { GlyrMemCache * prev = head->prev; if (prev != NULL) prev->next = to_add; to_add->prev = prev; to_add->next = head; head->prev = to_add; if (prev == NULL) *list = to_add; } else /* We're at the end */ { tail->next = to_add; to_add->prev = tail; } } } #if DEBUG_LIST GlyrMemCache * p = *list; while (p != NULL) { char * surr = (to_add == p) ? "*" : "|"; g_printerr ("%s(%d|%2.10f)%s %c ",surr,p->rating,p->timestamp,surr, (p->next) ? '-' : ' '); p = p->next; } puts (""); #endif } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// /* Convert a single result from the DB to an actual Cache */ static int select_callback (void * result, int argc, char ** argv, char ** azColName) { #if DO_PROFILE g_timer_start (select_callback_timer); #endif int rc = 0; select_callback_data * data = result; GlyrMemCache ** list = data->result; if (argc >= 15 && data->counter < data->query->number) { GlyrMemCache * cache = DL_init(); if (cache != NULL) { cache->prov = g_strdup (argv[3]); cache->dsrc = g_strdup (argv[4]); cache->img_format = g_strdup (argv[5]); cache->duration = (argv[6] ? strtol (argv[6],NULL,10) : 0); cache->type = (argv[8] ? strtol (argv[8],NULL,10) : 0); cache->size = (argv[9] ? strtol (argv[9],NULL,10) : 0); cache->is_image = (argv[10] ? strtol (argv[10],NULL,10) : 0); if (argv[11] != NULL) { memcpy (cache->md5sum,argv[11],16); } if (argv[12] != NULL && cache->size > 0) { cache->data = g_malloc0 (cache->size + 1); memcpy (cache->data,argv[12],cache->size); cache->data[cache->size] = 0; } cache->rating = (argv[13] ? strtol (argv[13],NULL,10) : 0); /* Timestamp */ if (argv[14] != NULL) { /* Normal strtod() cuts off part behin the comma.. */ cache->timestamp = (argv[14] ? g_ascii_strtod (argv[14],NULL) : 0); } /* We're in the cache, so this one was cached.. :) */ cache->cached = TRUE; if (list != NULL) { add_to_cache_list (list,cache); } else if (data->cb != NULL && cache) { GlyrQuery q; glyr_query_init (&q); if (argv[7] != NULL) { GLYR_GET_TYPE type = strtol (argv[7],NULL,10); glyr_opt_type (&q,type); } glyr_opt_artist (&q,argv[0]); glyr_opt_album (&q, argv[1]); glyr_opt_title (&q, argv[2]); rc = data->cb (&q,cache,data->userptr); glyr_query_destroy (&q); DL_free (cache); } } } data->counter++; #if DO_PROFILE g_timer_stop (select_callback_timer); select_callback_spent += g_timer_elapsed (select_callback_timer,NULL); #endif return rc; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// static gchar * convert_from_option_to_sql (GlyrQuery * q) { gchar * result = g_strdup ("'none'"); for (GList * elem = r_getSList(); elem; elem = elem->next) { MetaDataSource * item = elem->data; if (item && (q->type == item->type || item->type == GLYR_GET_ANY) ) { if (provider_is_enabled (q,item) == TRUE) { gchar * old_mem = result; result = g_strdup_printf ("%s%s'%s'",result, (*result) ? "," : "",item->name); g_free (old_mem); } } } return result; } //////////////////////////////////// //////////////////////////////////// //////////////////////////////////// static int delete_callback (void * result, int argc, char ** argv, char ** azColName) { delete_callback_data * data = result; if (argc >= 4 && result && data->max_delete > data->deleted) { /* God, this is so silly.. SQL, why you don't like " = null" * I can't think of any easier way to do this, tell me if you found one */ gchar * sql_delete = sqlite3_mprintf (sqlcode[SQL_ACTUAL_DELETE], argv[0] ? "=" : " IS ", argv[0] ? argv[0] : "NULL", argv[1] ? "=" : " IS ", argv[1] ? argv[1] : "NULL", argv[2] ? "=" : " IS ", argv[2] ? argv[2] : "NULL", argv[3] ? "=" : " IS ", argv[3] ? argv[3] : "NULL", argv[4] ? "=" : " IS ", argv[4] ? argv[4] : "NULL"); if (sql_delete != NULL) { execute (data->con,sql_delete); sqlite3_free (sql_delete); data->deleted++; } } return 0; } glyr-1.0.5/lib/cache.h000066400000000000000000000221551227540770500144720ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef GLYR_CACHE_H #define GLYR_CACHE_H /** * SECTION:cache * @short_description: A fast SQLite cache for glyr's results * @title: Cache * @section_id: * @stability: Stable * @include: glyr/cache.h * * The Cache offers application authors to store the items found * by glyr persistently in a DB-Cache and get them again once needed. * Before usage it is necessary to open the DB via glyr_db_init(), * which expects a folder where the DB will be stored, after this * there are 4 operations you can use on the query: * * * * Lookup by a Query (glyr_db_lookup()) * * * * * Delete by a Query (glyr_db_delete()) * * * * * Insert (glyr_db_insert()) * * * * * Iterate (glyr_db_foreach()) * * * * * * If you want to insert "own" caches, e.g. to indicate that some artist wasn't found you could use * the following piece of code: * * // Create a new "dummy" cache GlyrMemCache * ct = glyr_db_make_dummy(); // Query with filled in artist, album, title, type, // and opened db glyr_db_insert(db,&q,ct); glyr_cache_free(ct); * * */ #include "types.h" #ifdef __cplusplus extern "C" { #endif typedef int (*glyr_foreach_callback) (GlyrQuery * q, GlyrMemCache * item, void * userptr); /* The Name of the SQL File */ #define GLYR_DB_FILENAME "metadata.db" /** * glyr_db_init: * @root_path: Folder to create DB in * * Allocates a new database object, and create a SQLite database * at the given path. The filename is in #GLYR_DB_FILENAME * You can now use insert,delete, edit and lookup on it. * * Returns: A newly allocated GlyrDatabase, free with glyr_db_destroy */ GlyrDatabase * glyr_db_init (const char * root_path); /** * glyr_db_destroy: * @db_object: A database connection * * Close the connection and free all associated memory. * You may not use it anymore. */ void glyr_db_destroy (GlyrDatabase * db_object); /** * glyr_db_lookup: * @db: A database connection * @query: Define what to search for * * The artist,album,title and type field are used to query * the database. * * If you used glyr_opt_lookup_db() to bind the DB to a query, * You may use glyr_get() as an alternative for this method. * If your specify "local" in glyr_opt_from() only the DB is searched. * * Other query-fields honored by glyr_db_lookup(): * * * * glyr_opt_download() - If false URLs to images are searched, true for real images. * * * * * glyr_opt_from() - What provider the item came from. * * * * * glyr_opt_number() - How many items to return at max. * * * * * Returns: A newly allocated #GlyrMemCache or NULL if nothing found */ GlyrMemCache * glyr_db_lookup (GlyrDatabase * db, GlyrQuery * query); /** * glyr_db_insert: * @db: A database connection * @q: The query that was used to retrieve the @cache * @cache: The cache to insert. * * The cache wil be inserted to the db @db, @q is used to determine the artist, album, title and type. */ void glyr_db_insert (GlyrDatabase * db, GlyrQuery * q, GlyrMemCache * cache); /** * glyr_db_delete: * @db: The Database * @query: Define what item shall be deleted. * * The database is searched for the artist, album, title and type specified in @query. * If items in the DB match they will deleted. * * Other query-fields honored by glyr_db_delete(): * * * * glyr_opt_download() - If false URLs to images are searched, true for real images. * * * * * glyr_opt_from() - What provider the item came from. * * * * * glyr_opt_number() - How many items to delete at a max. * * * * Returns: The number of deleted items. */ int glyr_db_delete (GlyrDatabase * db, GlyrQuery * query); /** * glyr_db_edit: * @db: The Database * @query: The query with set artist,album, type etc. * @edited: The edited cache. * * A simple convenience function to delete caches according to the settings specified in @query, * (Same rules as in glyr_db_delete() apply here). * After deleting the cache @edited in inserted. If @edited is a doubly linked list (next pointer is not NULL), * then all items in the list are inserted. * * You could have written it yourself like this: * * * int glyr_db_edit(GlyrDatabase * db, GlyrQuery * query, GlyrMemCache * edited) * { * int result = 0; * if(db && query) * { * result = glyr_db_delete(db,query); * if(result != 0) * { * for(GlyrMemCache * elem = edited; elem; elem = elem->next) * { * glyr_db_insert(db,query,edited); * } * } * } * return result; * } * * * * Returns: The number of replaced caches */ int glyr_db_edit (GlyrDatabase * db, GlyrQuery * query, GlyrMemCache * edited); /** * glyr_db_replace: * @db: The Database * @md5sum: The md5sum of the cache you want to edit. * @query: The query with set artist,album, type etc. * @data: The edited cache. * * Simple convenience function to edit caches in the Database. * Best understood by example: * * * // If you have a cache called 'c', that's already * // In the Database: * // Save the old checksum, edit it, update the database. * unsigned char old_md5sum[16] = {0}; * memcpy(old_md5sum,c->md5sum,16); * glyr_cache_set_data(c,g_strdup("Changed the data - muahahah"),-1); * c->rating = 4200; * glyr_db_replace(s->local_db, old_md5sum, s, c); * * * * Some caveats: * * * * You may insert a cache several times, if the source url (cache->dsrc) is different, * but with the same checksum. If you call glyr_db_replace() once more, the caches * with the double md5sum get deleted and replaced by the new one. * * * */ void glyr_db_replace (GlyrDatabase * db, unsigned char * md5sum, GlyrQuery * query, GlyrMemCache * data); /** * glyr_db_foreach: * @db: A database connection * @cb: The callback to call on each item. * @userptr: A pointer to pass as second argument to the callback. * * Iterate over all items in the database. * Callback may not be null. If callback returns a number != 0, * iteration aborts. * * Callback parameters: * * 1) The artist / album / title / type that was used to get this cache is stored in 'query', other fields are not filled. * * 2) The actual cache completely filled. * * 3) The userpointer you passed as 3rd argument to glyr_db_foreach() * * This is useful if you want to have statistics or such. * */ void glyr_db_foreach (GlyrDatabase * db, glyr_foreach_callback cb, void * userptr); /** * glyr_db_make_dummy: * * The idea behind this function is to create a dummy entry for the cache, e.g. to indicate a certain item * was not found. In this case you create a dummy with a 'rating' of -1 and push it into the DB. * If one does a lookup (via glyr_get() or glyr_db_lookup()) then this cache will be returned, one is able * to check if the item was not found before. * * Returns: A newly allocated cache, use glyr_cache_free() to free it. */ GlyrMemCache * glyr_db_make_dummy (void); #ifdef __cplusplus } #endif #endif glyr-1.0.5/lib/cache_intern.c000066400000000000000000000052571227540770500160500ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "core.h" #include "glyr.h" #include "cache.h" #include "cache_intern.h" #include ///////////////////////////////// ///////////////////////////////// ///////////////////////////////// /* Check if a cache is already in the db, by cheskum or source_url */ gboolean db_contains (GlyrDatabase * db, GlyrMemCache * cache) { gboolean result = FALSE; if (db && cache) { gchar * sql = sqlite3_mprintf ( "SELECT source_url,data_checksum,data_size,data_type FROM metadata AS m " "WHERE (m.data_type = %d AND m.data_size = %d AND m.data_checksum = '?') " "OR (m.source_url LIKE '%q' AND m.source_url IS NOT NULL AND data_type = %d) " "LIMIT 1; ", cache->type, cache->size, cache->dsrc, cache->type); if (sql != NULL) { sqlite3_stmt * stmt = NULL; sqlite3_prepare_v2 (db->db_handle, sql, strlen (sql) + 1, &stmt, NULL); sqlite3_bind_blob (stmt, 1, cache->md5sum, sizeof cache->md5sum, SQLITE_TRANSIENT); int err = sqlite3_step (stmt); if (err == SQLITE_ROW) { result = TRUE; } else if (err != SQLITE_DONE) { glyr_message (-1,NULL,"db_contains: error message: %s\n", sqlite3_errmsg (db->db_handle) ); } sqlite3_finalize (stmt); sqlite3_free (sql); } } return result; } ///////////////////////////////// ///////////////////////////////// ///////////////////////////////// glyr-1.0.5/lib/cache_intern.h000066400000000000000000000022121227540770500160410ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . ******************************************************/ #ifndef GLYR_CACHE_INTERN_H #define GLYR_CACHE_INTERN_H #include "types.h" #include "core.h" #include /* Check if a file is contained in the db */ gboolean db_contains (GlyrDatabase * db, GlyrMemCache * cache); #endif glyr-1.0.5/lib/config.h000066400000000000000000000017551227540770500146770ustar00rootroot00000000000000/** * SECTION:config * @short_description: Compiletime Information * @title: Config * @section_id: * @stability: Stable * @include: glyr/config.h * * Misc. version checking macros and other defines * that may vary between builds. */ #define GLYR_VERSION_MAJOR "1" #define GLYR_VERSION_MINOR "0" #define GLYR_VERSION_MICRO "2" #define GLYR_VERSION_MAJOR_INT 1 #define GLYR_VERSION_MINOR_INT 0 #define GLYR_VERSION_MICRO_INT 2 /** * GLYR_CHECK_VERSION: * @X: Macro version. * @Y: Mino version. * @Z: Micro version, * * Version to check glyr's version. * Example: * * * #if GLYR_CHECK_VERSION(0,8,7) * puts("Version is at least 0.87!"); * #endif * * */ #define GLYR_CHECK_VERSION(X,Y,Z) (X <= GLYR_VERSION_MAJOR_INT || Y <= GLYR_VERSION_MINOR_INT || Z <= GLYR_VERSION_MICRO_INT) #define GLYR_VERSION_NAME "Raving Raven" #define GLYR_DEBUG TRUE /* Message output */ #define GLYR_OUTPUT stderr glyr-1.0.5/lib/config.h.in000066400000000000000000000021561227540770500153000ustar00rootroot00000000000000/** * SECTION:config * @short_description: Compiletime Information * @title: Config * @section_id: * @stability: Stable * @include: glyr/config.h * * Misc. version checking macros and other defines * that may vary between builds. */ #define GLYR_VERSION_MAJOR "@GLYR_VERSION_MAJOR@" #define GLYR_VERSION_MINOR "@GLYR_VERSION_MINOR@" #define GLYR_VERSION_MICRO "@GLYR_VERSION_MICRO@" #define GLYR_VERSION_MAJOR_INT @GLYR_VERSION_MAJOR@ #define GLYR_VERSION_MINOR_INT @GLYR_VERSION_MINOR@ #define GLYR_VERSION_MICRO_INT @GLYR_VERSION_MICRO@ /** * GLYR_CHECK_VERSION: * @X: Macro version. * @Y: Mino version. * @Z: Micro version, * * Version to check glyr's version. * Example: * * * #if GLYR_CHECK_VERSION(0,8,7) * puts("Version is at least 0.87!"); * #endif * * */ #define GLYR_CHECK_VERSION(X,Y,Z) (X <= GLYR_VERSION_MAJOR_INT || Y <= GLYR_VERSION_MINOR_INT || Z <= GLYR_VERSION_MICRO_INT) #define GLYR_VERSION_NAME "@GLYR_VERSION_NAME@" #define GLYR_DEBUG @GLYR_DEBUG@ /* Message output */ #define GLYR_OUTPUT stderr glyr-1.0.5/lib/core.c000066400000000000000000001567061227540770500143640ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include #include #include "stringlib.h" #include "core.h" /* Get user agent string */ #include "config.h" /* Get access to the db */ #include "cache_intern.h" /* Mini blacklist */ #include "blacklist.h" /* Somehow needed to prevent some compiler warning.. */ #include ////////////////////////////////////// static int _msg (const char * fmt, va_list params) { gchar * tmp_buf = NULL; /* Silly, but needs a way to get length */ gint written = g_vasprintf (&tmp_buf,fmt,params); if (written != -1 && tmp_buf != NULL) { g_log (G_LOG_DOMAIN,G_LOG_LEVEL_INFO,"%s",tmp_buf); g_free (tmp_buf); tmp_buf = NULL; } return written; } ////////////////////////////////////// int glyr_message (int verbosity, GlyrQuery * s, const char * fmt, ...) { gint written = 0; if (s != NULL || verbosity == -1) { if (verbosity == -1 || verbosity <= s->verbosity) { va_list params; if (fmt != NULL) { va_start (params,fmt); written = _msg (fmt,params); va_end (params); } } } return written; } ////////////////////////////////////// /** * Check if the size of a cover fits the specs */ gboolean size_is_okay (int sZ, int min, int max) { if ( (min == -1 && max == -1) || (min == -1 && max >= sZ) || (min <= sZ && max == -1) || (min <= sZ && max >= sZ) ) return TRUE; return FALSE; } ////////////////////////////////////// /* cache incoming data in a GlyrMemCache * libglyr is spending quite some time here */ static size_t DL_buffer (void *puffer, size_t size, size_t nmemb, void * buff_data) { size_t realsize = size * nmemb; DLBufferContainer * data = (DLBufferContainer *) buff_data; if (data != NULL) { GlyrMemCache * mem = data->cache; mem->data = realloc (mem->data, mem->size + realsize + 1); if (mem->data) { memcpy (& (mem->data[mem->size]), puffer, realsize); mem->size += realsize; mem->data[mem->size] = 0; GlyrQuery * query = data->query; if (query && GET_ATOMIC_SIGNAL_EXIT (query) ) { return 0; } /* Test if a endmarker is in this buffer */ const gchar * endmarker = data->endmarker; if (endmarker && strstr (mem->data,endmarker) ) return 0; } else { glyr_message (-1,NULL,"Caching failed: Out of memory.\n"); glyr_message (-1,NULL,"Did you perhaps try to load a 4,7GB .iso into your RAM?\n"); } } return realsize; } ////////////////////////////////////// void DL_set_data (GlyrMemCache * cache, const gchar * data, gint len) { if (cache != NULL) { g_free (cache->data); cache->data = (gchar*) data; if (data != NULL) { cache->size = (len >= 0) ? (gsize) len : strlen (data); update_md5sum (cache); } else { cache->size = 0; memset (cache->md5sum,0,16); } } } ////////////////////////////////////// GlyrMemCache * DL_copy (GlyrMemCache * cache) { GlyrMemCache * result = NULL; if (cache != NULL) { result = g_malloc0 (sizeof (GlyrMemCache) ); memcpy (result,cache,sizeof (GlyrMemCache) ); if (cache->size > 0) { /* Remember NUL for strings */ result->data = g_malloc (cache->size + 1); result->data[cache->size] = 0; memcpy (result->data,cache->data,cache->size); } result->dsrc = g_strdup (cache->dsrc); result->prov = g_strdup (cache->prov); result->img_format = g_strdup (cache->img_format); memcpy (result->md5sum,cache->md5sum,16); result->next = NULL; result->prev = NULL; } return result; } ////////////////////////////////////// // cleanup internal buffer if no longer used void DL_free (GlyrMemCache *cache) { if (cache) { if (cache->size && cache->data) { g_free (cache->data); cache->data = NULL; } if (cache->dsrc) { g_free (cache->dsrc); cache->dsrc = NULL; } if (cache->prov) { g_free (cache->prov); cache->prov = NULL; } cache->size = 0; cache->type = GLYR_TYPE_UNKNOWN; g_free (cache->img_format); g_free (cache); cache = NULL; } } ////////////////////////////////////// // Use this to init the internal buffer GlyrMemCache* DL_init (void) { GlyrMemCache * cache = g_malloc0 (sizeof (GlyrMemCache) ); memset (cache,0,sizeof (GlyrMemCache) ); cache->type = GLYR_TYPE_UNKNOWN; cache->cached = FALSE; cache->duration = 0; cache->rating = 0; cache->timestamp = 0.0; return cache; } ////////////////////////////////////// // Splits http_proxy to libcurl conform represantation static gboolean proxy_to_curl (gchar * proxystring, char ** userpwd, char ** server) { if (proxystring && userpwd && server) { if (proxystring != NULL) { gchar * ddot = strchr (proxystring,':'); gchar * asgn = strchr (proxystring,'@'); if (ddot == NULL || asgn < ddot) { *server = g_strdup (proxystring); *userpwd = NULL; return TRUE; } else { gsize len = strlen (proxystring); char * protocol = strstr (proxystring,"://"); if (protocol == NULL) { protocol = (gchar*) proxystring; } else { protocol += 3; } *userpwd = g_strndup (protocol,asgn-protocol); *server = g_strndup (asgn+1,protocol+len-asgn); return TRUE; } } } return FALSE; } ////////////////////////////////////// struct header_data { gchar * type; gchar * format; gchar * extra; }; ////////////////////////////////////// /* Parse header file. Get Contenttype from it and save it in the header_data struct */ gsize header_cb (void *ptr, gsize size, gsize nmemb, void *userdata) { gsize bytes = size * nmemb; if (ptr != NULL && userdata != NULL) { /* Transform safely into string */ gchar nulbuf[bytes + 1]; memcpy (nulbuf,ptr,bytes); nulbuf[bytes] = '\0'; /* We're only interested in the content type */ gchar * cttp = "Content-Type: "; gsize ctt_len = strlen (cttp); if (ctt_len < bytes && g_ascii_strncasecmp (cttp,nulbuf,ctt_len) == 0) { gchar ** content_type = g_strsplit_set (nulbuf + ctt_len," /;",0); if (content_type != NULL) { gsize set_at = 0; gchar ** elem = content_type; struct header_data * info = userdata; /* Set fields.. */ while (elem[0] != NULL) { if (elem[0][0] != '\0') { switch (set_at) { case 0: g_free (info->type); info->type = g_strdup (elem[0]); break; case 1: g_free (info->format); /* * Specialcase: * htbackdrops uses application/octet-stream as format * for their images. This is annoying, but needs to be * handled nevertheless. Shame on you, htbackdrops. * */ if (g_ascii_strncasecmp (elem[0],"octet-stream",12) == 0) { g_free (info->type); info->type = g_strdup ("image"); info->format = g_strdup ("jpeg"); } else { info->format = g_strdup (elem[0]); } break; case 2: g_free (info->extra); info->extra = g_strdup (elem[0]); break; } set_at++; } elem++; } g_strfreev (content_type); } } } return bytes; } ////////////////////////////////////// /* empty callback just prevent writing header to stdout */ gsize nearly_empty_callback (void * p, gsize size, gsize numb, void * pp_Query) { GlyrQuery * query = (GlyrQuery *) pp_Query; return (query && GET_ATOMIC_SIGNAL_EXIT (query) ) ? 0 : (size * numb); } ////////////////////////////////////// static void DL_setproxy (CURL *eh, gchar * proxystring) { if (proxystring != NULL) { gchar * userpwd; gchar * server; proxy_to_curl (proxystring,&userpwd,&server); if (server != NULL) { curl_easy_setopt (eh, CURLOPT_PROXY,server); g_free (server); } else { glyr_message (-1,NULL,"Warning: Invalid proxy string.\n"); } if (userpwd != NULL) { curl_easy_setopt (eh,CURLOPT_PROXYUSERPWD,userpwd); g_free (userpwd); } } } ////////////////////////////////////// static struct header_data * retrieve_content_info (gchar * url, gchar * proxystring, gchar * useragent, GlyrQuery * query) { struct header_data * info = NULL; if (url != NULL) { CURL * eh = curl_easy_init(); CURLcode rc = CURLE_OK; info = g_malloc0 (sizeof (struct header_data) ); gchar * link_user_agent = g_strdup_printf ("%s / linkvalidator",useragent); curl_easy_setopt (eh, CURLOPT_TIMEOUT, 10); curl_easy_setopt (eh, CURLOPT_NOSIGNAL, 1L); curl_easy_setopt (eh, CURLOPT_USERAGENT, link_user_agent); curl_easy_setopt (eh, CURLOPT_URL,url); curl_easy_setopt (eh, CURLOPT_FOLLOWLOCATION, TRUE); curl_easy_setopt (eh, CURLOPT_MAXREDIRS, 5L); curl_easy_setopt (eh, CURLOPT_HEADER,TRUE); curl_easy_setopt (eh, CURLOPT_SSL_VERIFYPEER, FALSE); /* Dirty hack here: Amazon bitches at me when setting NOBODY to true * * But otherwise large images won't pass with other providers * * Check domain therefore.. */ if (strstr (url,"amazon") != NULL) { curl_easy_setopt (eh, CURLOPT_NOBODY,FALSE); } else { curl_easy_setopt (eh, CURLOPT_NOBODY,TRUE); } curl_easy_setopt (eh, CURLOPT_HEADERFUNCTION, header_cb); curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, nearly_empty_callback); curl_easy_setopt (eh, CURLOPT_WRITEDATA, query); curl_easy_setopt (eh, CURLOPT_WRITEHEADER, info); /* Set proxy, if any */ DL_setproxy (eh, proxystring); /* This seemed to prevent some valid urls from passing. Strange. */ //curl_easy_setopt(eh, CURLOPT_FAILONERROR,TRUE); rc = curl_easy_perform (eh); curl_easy_cleanup (eh); if (rc != CURLE_OK) { if (GET_ATOMIC_SIGNAL_EXIT (query) == FALSE) { glyr_message (1,query,"- DLError: %s [%d]\n",curl_easy_strerror (rc),rc); } g_free (info); info = NULL; } else { /* Remove trailing newlines,carriage returns */ chomp_breakline (info->type); chomp_breakline (info->format); chomp_breakline (info->extra); } g_free (link_user_agent); } return info; } ////////////////////////////////////// // Init an easyhandler with all relevant options static DLBufferContainer * DL_setopt (CURL *eh, GlyrMemCache * cache, const char * url, GlyrQuery * s, void * magic_private_ptr, long timeout, gchar * endmarker) { // Set options (see 'man curl_easy_setopt') curl_easy_setopt (eh, CURLOPT_TIMEOUT, timeout); curl_easy_setopt (eh, CURLOPT_NOSIGNAL, 1L); // last.fm and discogs require an useragent (wokrs without too) curl_easy_setopt (eh, CURLOPT_USERAGENT, (s && s->useragent) ? s->useragent : GLYR_DEFAULT_USERAGENT); curl_easy_setopt (eh, CURLOPT_HEADER, 0L); // Pass vars to curl curl_easy_setopt (eh, CURLOPT_URL, url); curl_easy_setopt (eh, CURLOPT_PRIVATE, magic_private_ptr); curl_easy_setopt (eh, CURLOPT_VERBOSE, (s && s->verbosity >= 4) ); curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, DL_buffer); curl_easy_setopt (eh, CURLOPT_SSL_VERIFYPEER, FALSE); DLBufferContainer * dlbuffer = g_malloc0 (sizeof (DLBufferContainer) ); curl_easy_setopt (eh, CURLOPT_WRITEDATA, (void *) dlbuffer); dlbuffer->cache = cache; dlbuffer->endmarker = endmarker; dlbuffer->query = s; // amazon plugin requires redirects curl_easy_setopt (eh, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt (eh, CURLOPT_MAXREDIRS, (s) ? s->redirects : 2); // Do not download 404 pages curl_easy_setopt (eh, CURLOPT_FAILONERROR, 1L); // Set proxy to use DL_setproxy (eh, (gchar*) (s) ? s->proxy : NULL); // Discogs requires gzip compression curl_easy_setopt (eh, CURLOPT_ENCODING,"gzip"); // Don't save cookies - I had some quite embarassing moments // when amazon's startpage showed me "Hooray for Boobies", // because I searched for the Bloodhoundgang album... // (because I have it already of course! ;-)) curl_easy_setopt (eh, CURLOPT_COOKIEJAR ,""); return dlbuffer; } ////////////////////////////////////// gboolean continue_search (gint current, GlyrQuery * s) { gboolean decision = FALSE; if (s != NULL && GET_ATOMIC_SIGNAL_EXIT (s) == FALSE) { /* Take an educated guess, let the provider get more, because URLs might be wrong, * as we check this later, it's good to have some more ULRs waiting for us, * * alternatively we might hit the maximum for one plugin (off by one!) */ gint buffering = (s->imagejob) ? s->number / 3 : 0; /* If we use caching we should consider getting a lot more items, * since many of the *may* be already in the Database */ gint pre_cache = (s->local_db) ? s->number : 0; decision = (current + s->itemctr) < (s->number + buffering + pre_cache) && (current < s->plugmax || (s->plugmax == -1) ); } return decision; } ////////////////////////////////////// // Bad data checker mehods: ////////////////////////////////////// /* Check for dupes. This does not affect the HEAD of the list, therefore no GList return */ gsize delete_dupes (GList * result, GlyrQuery * s) { if (!result || g_list_length (result) < 1) return 0; /* Build new hashes, the data might have changed */ for (GList * elem = result; elem; elem = elem->next) { update_md5sum (elem->data); } gint double_items = 0; for (GList * inode = result; inode; inode = inode->next) { GlyrMemCache * lval = inode->data; GList * jnode = result; while (jnode != NULL) { bool is_duplicate = false; GlyrMemCache * rval = jnode->data; if (lval && rval && rval != lval && lval->size == rval->size) { /* Compare via checkums */ if (CALC_MD5SUMS == false) { if (!memcmp (lval->data,rval->data,rval->size) ) { is_duplicate = true; } } else { if (!memcmp (lval->md5sum,rval->md5sum,16) ) { is_duplicate = true; } } /* Delete this element.. */ if (is_duplicate == true) { DL_free (rval); /* Delete this ref from the list */ GList * to_free = jnode; jnode = jnode->next; result = g_list_delete_link (result,to_free); /* Remember him.. */ double_items++; continue; } } jnode = jnode->next; } } return double_items; } ////////////////////////////////////// // Download a singe file NOT in parallel GlyrMemCache * download_single (const char* url, GlyrQuery * s, const char * end) { if (url != NULL && is_blacklisted ( (gchar*) url) == false) { CURL *curl = NULL; CURLcode res = 0; /* Init handles */ curl = curl_easy_init(); GlyrMemCache * dldata = DL_init(); /* DL_buffer needs the 'end' mark. * As I didnt want to introduce a new struct just for this * I save it in->dsrc */ if (end != NULL) { dldata->dsrc = g_strdup (end); } if (curl != NULL) { /* Configure curl */ DLBufferContainer * dlbuffer = DL_setopt (curl,dldata,url,s,NULL, (s) ? s->timeout : 5, NULL); /* Perform transaction */ res = curl_easy_perform (curl); /* Free the pointer buff */ g_free (dlbuffer); /* Better check again */ if (res != CURLE_OK && res != CURLE_WRITE_ERROR) { glyr_message (3,s,"glyr: E: singledownload: %s [E:%d]\n", curl_easy_strerror (res),res); DL_free (dldata); dldata = NULL; } else { /* Set the source URL */ if (dldata->dsrc != NULL) { g_free (dldata->dsrc); } dldata->dsrc = g_strdup (url); } curl_easy_cleanup (curl); update_md5sum (dldata); return dldata; } DL_free (dldata); } return NULL; } ////////////////////////////////////// // Init a callback object and a curl_easy_handle static GlyrMemCache * init_async_cache (CURLM * cm, cb_object * capo, GlyrQuery *s, long timeout, gchar * endmark) { GlyrMemCache * dlcache = NULL; if (capo && capo->url) { /* Init handle */ CURL *eh = curl_easy_init(); /* Init cache */ dlcache = DL_init(); /* Remind this handle */ capo->handle = eh; /* Make sure this is null at start */ capo->dlbuffer = NULL; /* Configure this handle */ capo->dlbuffer = DL_setopt (eh, dlcache, capo->url, s, (void*) capo,timeout, endmark); /* Add handle to multihandle */ curl_multi_add_handle (cm, eh); /* This is set to true once DL_buffer is reached */ capo->was_buffered = FALSE; } return dlcache; } ////////////////////////////////////// static GList * init_async_download (GList * url_list, GList * endmark_list, CURLM * cmHandle, GlyrQuery * s, int abs_timeout) { GList * cb_list = NULL; for (GList * elem = url_list; elem; elem = elem->next) { if (is_blacklisted ( (gchar*) elem->data) == false) { cb_object * obj = g_malloc0 (sizeof (cb_object) ); obj->s = s; obj->url = g_strdup ( (gchar*) (elem->data) ); cb_list = g_list_prepend (cb_list,obj); obj->consumed = FALSE; /* Get the endmark from the endmark list */ gint endmark_pos = g_list_position (url_list,elem); GList * glist_m = g_list_nth (endmark_list,endmark_pos); gchar * endmark = (glist_m==NULL) ? NULL : glist_m->data; obj->cache = init_async_cache (cmHandle,obj,s,abs_timeout,endmark); } } return cb_list; } ////////////////////////////////////// static void destroy_async_download (GList * cb_list, CURLM * cmHandle, gboolean free_caches) { /* Free ressources */ curl_multi_cleanup (cmHandle); if (cb_list != NULL) { for (GList * elem = cb_list; elem; elem = elem->next) { cb_object * item = elem->data; if (item->handle != NULL) { curl_easy_cleanup (item->handle); } /* Also free unbuffered items, that don't appear in the queue, * even if free_caches was set to FALSE */ if ( (free_caches == TRUE || item->was_buffered == FALSE) && item->consumed == FALSE) { DL_free (item->cache); item->cache = NULL; } g_free (item->dlbuffer); g_free (item->url); } glist_free_full (cb_list,g_free); } } ////////////////////////////////////// /* ----------------- THE HEART OF GOLD ------------------ */ ////////////////////////////////////// GList * async_download (GList * url_list, GList * endmark_list, GlyrQuery * s, long parallel_fac, long timeout_fac, AsyncDLCB asdl_callback, void * userptr, gboolean free_caches) { /* Storage for result items */ GList * item_list = NULL; if (url_list != NULL && s != NULL) { /* total timeout and parallel tries */ long abs_timeout = ABS (timeout_fac * s->timeout); long abs_parallel = ABS (parallel_fac * s->parallel); /* select() control */ int max_fd, queue_msg, running_handles = -1; long wait_time; fd_set ReadFDS, WriteFDS, ErrorFDS; /* Curl Multi Handles (~ container for easy handlers) */ CURLM * cmHandle = curl_multi_init(); curl_multi_setopt (cmHandle, CURLMOPT_MAXCONNECTS,abs_parallel); curl_multi_setopt (cmHandle, CURLMOPT_PIPELINING, 1L); /* Once set to true this will terminate the download */ gboolean terminate = FALSE; /* Now create cb_objects */ GList * cb_list = init_async_download (url_list,endmark_list,cmHandle,s,abs_timeout); while (GET_ATOMIC_SIGNAL_EXIT (s) == FALSE && running_handles != 0 && terminate == FALSE) { CURLMcode merr = CURLM_CALL_MULTI_PERFORM; while (merr == CURLM_CALL_MULTI_PERFORM) { merr = curl_multi_perform (cmHandle, &running_handles); } if (merr != CURLM_OK) { glyr_message (1,s,"Error: curl_multi_perform() failed!"); return NULL; } if (running_handles != 0) { /* Set up fds */ FD_ZERO (&ReadFDS); FD_ZERO (&WriteFDS); FD_ZERO (&ErrorFDS); if (curl_multi_fdset (cmHandle, &ReadFDS, &WriteFDS, &ErrorFDS, &max_fd) || curl_multi_timeout (cmHandle, &wait_time) ) { glyr_message (1,s,"Error while selecting stream. Might be a bug.\n"); return NULL; } if (wait_time == -1) wait_time = 100; /* Nothing happens.. */ if (max_fd == -1) { g_usleep (wait_time * 100); } else { struct timeval Tmax; Tmax.tv_sec = (wait_time/1000); Tmax.tv_usec = (wait_time%1000) *1000; /* Now block till something interesting happens with the download */ if (select (max_fd+1, &ReadFDS, &WriteFDS, &ErrorFDS, &Tmax) == -1) { glyr_message (1,s,"Error: select(%i <=> %li): %i: %s\n",max_fd+1, wait_time, errno, strerror (errno) ); return NULL; } } } /* select() returned. There might be some fresh flesh! - Check. */ CURLMsg * msg; while (GET_ATOMIC_SIGNAL_EXIT (s) == FALSE && terminate == FALSE && (msg = curl_multi_info_read (cmHandle, &queue_msg) ) ) { /* That download is ready to be viewed */ if (msg->msg == CURLMSG_DONE) { /* Easy handle of this particular DL */ CURL *easy_handle = msg->easy_handle; /* Get the callback object associated with the curl handle * for some odd reason curl requires a char * pointer */ cb_object * capo = NULL; curl_easy_getinfo (msg->easy_handle, CURLINFO_PRIVATE, ( ( (char**) &capo) ) ); /* It's useless if it's empty */ if (capo && capo->cache && capo->cache->data == NULL) { capo->consumed = TRUE; DL_free (capo->cache); capo->cache = NULL; } /* Mark this cb_object as */ capo->was_buffered = TRUE; /* capo contains now the downloaded cache, ready to parse */ if (msg->data.result == CURLE_OK && capo && capo->cache) { /* How many items from the callback will actually be added */ gint to_add = 0; /* Stop download after this came in */ bool stop_download = false; GList * cb_results = NULL; /* Set origin */ if (capo->cache->dsrc != NULL) { g_free (capo->cache->dsrc); } capo->cache->dsrc = g_strdup (capo->url); /* Call it if present */ if (asdl_callback != NULL) { /* Add parsed results or nothing if parsed result is empty */ cb_results = asdl_callback (capo,userptr,&stop_download,&to_add); } if (cb_results != NULL) { /* Fill in the source filed (dsrc) if not already done */ for (GList * elem = cb_results; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item && item->dsrc == NULL) { /* Plugin didn't do any special download */ item->dsrc = g_strdup (capo->url); } item_list = g_list_prepend (item_list,item); } g_list_free (cb_results); } else if (to_add != 0) { /* Add it as raw data */ item_list = g_list_prepend (item_list,capo->cache); } else { capo->consumed = TRUE; DL_free (capo->cache); capo->cache = NULL; } /* So, shall we stop? */ terminate = stop_download; } else { /* Something in this download was wrong. Tell us what. */ char * errstring = (char*) curl_easy_strerror (msg->data.result); glyr_message (3,capo->s,"- glyr: Downloaderror: %s [errno:%d]\n", errstring ? errstring : "Unknown Error", msg->data.result); glyr_message (3,capo->s," On URL: "); glyr_message (3,capo->s,"%s\n",capo->url); DL_free (capo->cache); capo->cache = NULL; capo->consumed = TRUE; } /* We're done with this one.. bybebye */ curl_multi_remove_handle (cmHandle,easy_handle); curl_easy_cleanup (easy_handle); capo->handle = NULL; } else { /* Something in the multidownloading gone wrong */ glyr_message (1,s,"Error: multiDownload-errorcode: %d\n",msg->msg); } } } destroy_async_download (cb_list,cmHandle,free_caches); } return item_list; } ////////////////////////////////////// struct wrap_retrieve_pass_data { gchar * url; GlyrQuery * query; }; static void * wrap_retrieve_content (gpointer data) { struct header_data * head = NULL; if (data != NULL) { struct wrap_retrieve_pass_data * passed = data; GlyrQuery * query = passed->query; head = retrieve_content_info (passed->url, (gchar*) query->proxy, (gchar*) query->useragent,query); g_free (passed); passed = NULL; } return head; } ////////////////////////////////////// static void check_all_types_in_url_list (GList * cache_list, GlyrQuery * s) { if (cache_list != NULL) { GHashTable * thread_id_table = g_hash_table_new (g_direct_hash,g_direct_equal); GList * thread_list = NULL; glyr_message (2,s,"#[%02d/%02d] Checking image-types: [",s->itemctr,s->number); for (GList * elem = cache_list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL) { struct wrap_retrieve_pass_data * passer = g_malloc0 (sizeof (struct wrap_retrieve_pass_data) ); passer->url = item->data; passer->query = s; GThread * thread = g_thread_new("content_retriever", (GThreadFunc) wrap_retrieve_content, passer); if (thread != NULL) { thread_list = g_list_prepend (thread_list,thread); } g_hash_table_insert (thread_id_table,thread,item); } } for (GList * thread = thread_list; thread; thread = thread->next) { gboolean success = FALSE; struct header_data * info = g_thread_join (thread->data); if (info != NULL) { GlyrMemCache * linked_cache = g_hash_table_lookup (thread_id_table,thread->data); if (linked_cache != NULL) { if (g_strcmp0 (info->type,"image") == 0) { linked_cache->img_format = g_strdup (info->format); success = TRUE; } } else { glyr_message (1,s,"glyr: Uh oh.. empty link in hashtable..\n"); } g_free (info->format); g_free (info->type); g_free (info->extra); g_free (info); } glyr_message (2,s,"%c", (success) ? '.' : '!'); } g_list_free (thread_list); g_hash_table_destroy (thread_id_table); glyr_message (2,s,"]"); } } ////////////////////////////////////// static gboolean format_is_allowed (gchar * format, gchar * allowed) { /* Let everything pass */ if (allowed == NULL) { return TRUE; } gboolean result = FALSE; if (format != NULL && allowed != NULL) { gchar * token; gsize offset = 0; gsize len = strlen (allowed); while (!result && (token = get_next_word (allowed,GLYR_DEFAULT_FROM_ARGUMENT_DELIM,&offset,len) ) != NULL) { result = (g_strcmp0 (token,format) == 0); g_free (token); } } return result; } ////////////////////////////////////// static gint delete_wrong_formats (GList ** list, GlyrQuery * s) { /* Now compare it agains the format. */ gsize invalid_format_counter = 0; GList * new_head = *list; GList * elem = new_head; gchar * allowed_formats = s->allowed_formats; if (allowed_formats == NULL) { allowed_formats = GLYR_DEFAULT_ALLOWED_FORMATS; } while (elem != NULL) { GlyrMemCache * item = elem->data; if (item != NULL) { if (format_is_allowed (item->img_format,allowed_formats) == FALSE) { GList * to_delete = elem; elem = elem->next; invalid_format_counter++; new_head = g_list_delete_link (new_head,to_delete); DL_free (item); item = NULL; continue; } } elem = elem->next; } *list = new_head; return invalid_format_counter; } ////////////////////////////////////// static GList * kick_out_wrong_formats (GList * data_list, GlyrQuery * s) { GList * new_head = data_list; /* Parallely check if the format is what we wanted */ check_all_types_in_url_list (new_head,s); /* Kick the wrong ones */ gint invalid_format_counter = delete_wrong_formats (&new_head,s); glyr_message (2,s," (-%d item(s) less)\n",invalid_format_counter); return new_head; } ////////////////////////////////////// static void do_charset_conversion (MetaDataSource * source, GList * text_list) { if (source != NULL && text_list != NULL) { for (GList * elem = text_list; elem; elem = elem->next) { GlyrMemCache * cache = elem->data; /* We might need to unescape the HTML Utf8 encoded strings first, this is done later anyway. */ gchar * utf8_string = unescape_html_UTF8 (cache->data); if (utf8_string != NULL) { gsize new_len; gchar * conv = convert_charset (utf8_string,"UTF-8",source->encoding,&new_len); if (conv != NULL) { cache->size = new_len; g_free (cache->data); cache->data = conv; } g_free (utf8_string); } } } } ////////////////////////////////////// static GList * check_for_forced_utf8 (GlyrQuery * query, GList * text_list) { gint deleted = 0; GList * new_head = text_list; if (query != NULL && text_list != NULL && query->force_utf8 == TRUE) { glyr_message (2,query,"#[%02d/%02d] Checking encoding [",g_list_length (text_list),query->number); GList * elem = text_list; while (elem != NULL) { GlyrMemCache * cache = elem->data; const gchar * end_of_valid_utf8 = NULL; if (cache && g_utf8_validate (cache->data,cache->size,&end_of_valid_utf8) == FALSE) { /* UTF8 was forced, and this cache didn't pass -> deletre */ glyr_message (2,query,"!"); DL_free (cache); deleted++; GList * to_delete = elem; elem = elem->next; new_head = g_list_delete_link (new_head,to_delete); continue; } else { glyr_message (2,query,"."); elem = elem->next; } } glyr_message (2,query,"] (-%d item(s) less)\n",deleted); } return new_head; } ////////////////////////////////////// static void normalize_utf8 (GList * text_list) { for (GList * elem = text_list; elem; elem = elem->next) { GlyrMemCache * cache = elem->data; if (cache != NULL && cache->data) { if (g_utf8_validate (cache->data,-1,NULL) != FALSE) { gchar * normalized_utf8 = g_utf8_normalize (cache->data,-1,G_NORMALIZE_NFKC); if (normalized_utf8 != NULL) { /* Swap cache contents */ g_free (cache->data); cache->data = normalized_utf8; cache->size = strlen (normalized_utf8); } } } } } ////////////////////////////////////// static gint delete_already_cached_items (cb_object * capo, GList ** list) { if (capo->s->db_autoread == FALSE) { return 0; } gint deleted = 0; if (capo && capo->s->local_db) { GList * elem = *list; while (elem != NULL) { GlyrMemCache * item = elem->data; if (item != NULL && item->dsrc == NULL && capo->s->imagejob) { item->dsrc = g_strdup (item->data); } if (item && db_contains (capo->s->local_db,item) ) { GList * to_delete = elem; elem = elem->next; *list= g_list_delete_link (*list,to_delete); DL_free (item); deleted++; continue; } elem = elem->next; } } return deleted; } ////////////////////////////////////// static void fix_data_types (GList * list, MetaDataSource * src, GlyrQuery * query) { for (GList * elem = list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL && item->type == GLYR_TYPE_UNKNOWN) { if (TYPE_IS_IMAGE (query->type) && query->download == FALSE) { item->type = GLYR_TYPE_IMG_URL; } else { item->type = src->data_type; } } } } ////////////////////////////////////// /* The actual call to the metadata provider here, coming from the downloader, triggered by start_engine() */ static GList * call_provider_callback (cb_object * capo, void * userptr, bool * stop_download, gint * to_add) { GList * parsed = NULL; if (userptr != NULL) { /* Get MetaDataSource correlated to this URL */ GHashTable * assoc = (GHashTable*) userptr; MetaDataSource * plugin = g_hash_table_lookup (assoc,capo->url); if (plugin != NULL) { if (capo->s->itemctr < capo->s->number) { /* Call the provider's parser */ GList * raw_parsed_data = plugin->parser (capo); /* Set the default type if not known otherwise */ fix_data_types (raw_parsed_data,plugin,capo->s); /* Also do some duplicate check already */ gsize less = delete_dupes (raw_parsed_data,capo->s); if (less > 0) { gsize items_now = g_list_length (raw_parsed_data) + capo->s->itemctr - less; glyr_message (2,capo->s,"#[%02d/%02d] Inner check found %ld dupes\n",items_now,capo->s->number,less); } /* Look up if items already in cache */ less = delete_already_cached_items (capo,&raw_parsed_data); if (less > 0) { gsize items_now = g_list_length (raw_parsed_data) + capo->s->itemctr - less; glyr_message (2,capo->s,"#[%02d/%02d] DB lookup found %ld dupes\n",items_now,capo->s->number,less); } /* Any items left to kill? */ if (g_list_length (raw_parsed_data) != 0) { /* We shouldn't check (e.g) lyrics if they are a valid URL ;-) */ if (capo->s->imagejob == TRUE) { raw_parsed_data = kick_out_wrong_formats (raw_parsed_data,capo->s); } else /* We should look if charset conversion is requested */ { normalize_utf8 (raw_parsed_data); if (plugin->encoding != NULL) { glyr_message (2,capo->s,"#[%02d/%02d] Attempting to convert charsets\n",g_list_length (raw_parsed_data),capo->s->number); do_charset_conversion (plugin, raw_parsed_data); } raw_parsed_data = check_for_forced_utf8 (capo->s,raw_parsed_data); } if (g_list_length (raw_parsed_data) != 0) { for (GList * elem = raw_parsed_data; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL) { if (capo->s->itemctr < capo->s->number) { /* Only reference to the plugin -> copy providername */ item->prov = g_strdup (plugin->name); parsed = g_list_prepend (parsed,item); capo->s->itemctr++; } else /* Not needed anymore. Forget this item */ { DL_free (item); item = NULL; /* Also skip other downloads */ *stop_download = TRUE; } } } /* Forget those pointers */ g_list_free (raw_parsed_data); } } } } else { glyr_message (1,capo->s,"glyr: hashmap lookup failed. Cannot call plugin => Bug.\n"); } } /* We replace the cache with a new one -> free the old one */ if (capo->cache != NULL) { DL_free (capo->cache); capo->cache = NULL; } /* Do not add raw data */ if (parsed == NULL) { *to_add = 0; } return parsed; } ////////////////////////////////////// gboolean provider_is_enabled (GlyrQuery * q, MetaDataSource * f) { if (q->lang_aware_only && f->lang_aware == false && q->imagejob == false && g_strcmp0 (f->name,"local") != 0) { return FALSE; } /* Assume 'all we have' */ if (q->from == NULL) { return TRUE; } /* You need to take a little break to read this through at once */ gboolean is_found = FALSE; gboolean is_excluded = FALSE; gboolean all_occured = FALSE; /* split string */ if (f->name != NULL) { gsize name_len = strlen (f->name); gsize len = strlen (q->from); gsize offset = 0; gchar * token = NULL; while ( (token = get_next_word (q->from,GLYR_DEFAULT_FROM_ARGUMENT_DELIM,&offset,len) ) ) { if (token != NULL) { gsize token_len = strlen (token); gchar * back = token; gboolean minus; if ( (minus = token[0] == '-') || token[0] == '+') token++; if (!g_ascii_strncasecmp (token,"all",token_len) ) all_occured = TRUE; if ( (token[0] == f->key && token_len == 1) || !g_ascii_strncasecmp (token,f->name,name_len) ) { is_excluded = minus; is_found = !minus; } g_free (back); } } } return (all_occured) ? (is_excluded == FALSE) : is_found; } ////////////////////////////////////// /* GnuPlot: plot3d(1/X*Y + (100-Y)*1/(1-X) + 1000,[X,0.1,0.9],[Y,0,100]); */ static gfloat calc_rating (gfloat qsratio, gint quality, gint speed) { gfloat cratio = CLAMP (qsratio,0.1,0.9); return 1000.0f + ( (1.0/ (1-cratio) *quality) + (1.0/cratio*speed) ); } ////////////////////////////////////// static GList * get_queued (GlyrQuery * s, MetaDataFetcher * fetcher, gint * fired) { GList * source_list = NULL; for (gint it = 0; it < s->parallel; it++) { gint pos = 0; gint max_pos = -1; gfloat max = G_MINFLOAT; for (GList * elem = fetcher->provider; elem; elem = elem->next, ++pos) { MetaDataSource * src = elem->data; if (provider_is_enabled (s,src) == TRUE) { if (fired[pos] == 0) { gfloat rating = calc_rating (s->qsratio,src->quality,src->speed); if (rating > max) { max = rating; max_pos = pos; } } } } if (max_pos != -1) { GList * wanted = g_list_nth (fetcher->provider,max_pos); if (wanted != NULL) { MetaDataSource * src = wanted->data; source_list = g_list_prepend (source_list,src); } fired[max_pos]++; } } if (source_list != NULL) { source_list = g_list_reverse (source_list); } return source_list; } ////////////////////////////////////// gboolean is_in_result_list (GlyrMemCache * cache, GList * result_list) { gboolean result = FALSE; if (cache != NULL) { for (GList * elem = result_list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (memcmp (cache->md5sum, item->md5sum, 16) == 0) { result = TRUE; } } } return result; } ////////////////////////////////////// static void execute_query (GlyrQuery * query, MetaDataFetcher * fetcher, GList * source_list, gboolean * stop_me, GList ** result_list) { GList * url_list = NULL; GList * endmarks = NULL; GList * offline_provider = NULL; GHashTable * url_table = g_hash_table_new (g_str_hash,g_str_equal); /* Iterate over all sources for this fetcher */ for (GList * source = source_list; source != NULL; source = source->next) { MetaDataSource * item = source->data; if (item != NULL) { /* get the url of this MetaDataSource */ const gchar * lookup_url = item->get_url (query); /* Add this to the list */ if (lookup_url != NULL) { if (g_ascii_strncasecmp (lookup_url,OFFLINE_PROVIDER, (sizeof OFFLINE_PROVIDER) - 1) != 0) { /* make a sane URL out of it */ const gchar * prepared = prepare_url (lookup_url,query,TRUE); /* add it to the hash table and relate it to the MetaDataSource */ g_hash_table_insert (url_table, (gpointer) prepared, (gpointer) item); url_list = g_list_prepend (url_list, (gpointer) prepared); endmarks = g_list_prepend (endmarks, (gpointer) item->endmarker); /* If the URL was dyn. allocated, we should go and free it */ if (item->free_url == TRUE) { g_free ( (gchar*) lookup_url); } } else { /* This providers offers some autogenerated content */ offline_provider = g_list_prepend (offline_provider,item); } } } } GList * sub_result_list = NULL; gsize url_list_length = g_list_length (url_list); if (url_list_length != 0 || g_list_length (offline_provider) != 0) { gboolean proceed = TRUE; GList * cached_items = NULL; GList * raw_parsed = NULL; GList * ready_caches = NULL; /* Handle offline provider, that don't need to download something */ for (GList * off_source = offline_provider; proceed && off_source && query->itemctr < query->number; off_source = off_source->next) { MetaDataSource * source = off_source->data; if (source != NULL && source->parser != NULL) { cb_object pseudo_capo; memset (&pseudo_capo, 0, sizeof pseudo_capo); pseudo_capo.s = query; GList * offline_list = source->parser (&pseudo_capo); if (query->imagejob) { delete_wrong_formats (&offline_list,query); } else { offline_list = check_for_forced_utf8 (query,offline_list); } for (GList * off_elem = offline_list; off_elem && query->itemctr < query->number; off_elem = off_elem->next) { GLYR_ERROR result = GLYRE_OK; if (query->callback.download != NULL) { result = query->callback.download (off_elem->data,query); } if (result != GLYRE_STOP_PRE && result != GLYRE_SKIP) { cached_items = g_list_prepend (cached_items,off_elem->data); query->itemctr++; } if (result == GLYRE_STOP_PRE || result == GLYRE_STOP_POST) { proceed = FALSE; break; } } g_list_free (offline_list); } } /* Now start the downloadmanager - and call the specified callback with the URL table when an item is ready */ if (proceed == TRUE && url_list_length != 0 && query->itemctr < query->number) { raw_parsed = async_download (url_list, endmarks, query, url_list_length / query->timeout + 1, MIN ( (gint) (url_list_length / query->parallel + 3), query->number + 2), call_provider_callback, url_table, TRUE); } /* Now finalize our retrieved items */ if (g_list_length (raw_parsed) != 0) { /* Kill duplicates before finalizing */ int pre_less = delete_dupes (raw_parsed,query); if (pre_less > 0) { glyr_message (2,query,"- Prefiltering double data: (-%d item(s) less)\n",pre_less); query->itemctr -= pre_less; } glyr_message (2,query,"---- \n"); if (g_list_length (raw_parsed) != 0) { /* Call finalize to sanitize data, or download given URLs */ ready_caches = fetcher->finalize (query, raw_parsed,stop_me, result_list); /* Raw data not needed anymore */ g_list_free (raw_parsed); raw_parsed = NULL; } } if (cached_items && ready_caches) { sub_result_list = g_list_concat (cached_items, ready_caches); } else { sub_result_list = (cached_items) ? cached_items : ready_caches; } } /* Free ressources */ glist_free_full (url_list,g_free); g_list_free (endmarks); g_list_free (offline_provider); g_hash_table_destroy (url_table); for (GList * result = sub_result_list; result; result = result->next) { GlyrMemCache * result_cache = result->data; if (result_cache != NULL) { *result_list = g_list_prepend (*result_list,result->data); } } g_list_free (sub_result_list); } ////////////////////////////////////// static void print_trigger (GlyrQuery * query, GList * src_list) { glyr_message (2,query,"---- Triggering: "); for (GList * elem = src_list; elem; elem = elem->next) { MetaDataSource * info = elem->data; glyr_message (2,query,"%s ",info->name); } glyr_message (2,query,"\n"); } ////////////////////////////////////// GList * start_engine (GlyrQuery * query, MetaDataFetcher * fetcher, GLYR_ERROR * err) { gsize list_len = g_list_length (fetcher->provider); gint fired[list_len]; memset (fired,0,list_len * sizeof (gint) ); gboolean something_was_searched = FALSE; gboolean stop_now = FALSE; GList * src_list = NULL, * result_list = NULL; while ( (stop_now == FALSE) && (g_list_length (result_list) < (gsize) query->number) && (src_list = get_queued (query, fetcher, fired) ) != NULL) { /* Print what provider were triggered */ print_trigger (query,src_list); /* Send this list of sources to the download manager */ execute_query (query,fetcher,src_list, &stop_now, &result_list); /* Do not report errors */ something_was_searched = TRUE; /* Next list please */ g_list_free (src_list); /* Check is exit was signaled */ stop_now = (GET_ATOMIC_SIGNAL_EXIT (query) ) ? TRUE : stop_now; } if (something_was_searched == FALSE) { if (err != NULL) { *err = GLYRE_NO_PROVIDER; } if (query != NULL) { query->q_errno = GLYRE_NO_PROVIDER; } } return result_list; } ////////////////////////////////////// /* New glib implementation, thanks to Etienne Millon */ void update_md5sum (GlyrMemCache * c) { if (c && c->data && c->size > 0) { gsize bufsize = 16; GChecksum *checksum = g_checksum_new (G_CHECKSUM_MD5); g_checksum_update (checksum, (const guchar*) c->data, c->size); g_checksum_get_digest (checksum, c->md5sum, &bufsize); g_checksum_free (checksum); } } ////////////////////////////////////// void glist_free_full (GList * List, void (* free_func) (void * ptr) ) { #if GLIB_CHECK_VERSION(2,28,0) /* Use official version */ g_list_free_full (List,free_func); #else /* Fallback to simple own implementation */ for (GList * elem = List; elem; elem = elem->next) { if (free_func != NULL) { free_func (elem->data); } } g_list_free (List); #endif } ////////////////////////////////////// glyr-1.0.5/lib/core.h000066400000000000000000000150241227540770500143540ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef CORE_H #define CORE_H #include "types.h" #include "apikeys.h" #include "config.h" /* Global */ #include #include #include /* * Logdomain. * Use --log-filter="Glyr" for gmpc to * just see glyrs debug output */ #ifdef G_LOG_DOMAIN #undef G_LOG_DOMAIN #endif #define G_LOG_DOMAIN "Glyr" /* libglyr uses checksums to filter double items * Also you can use those as easy comparasion method * There is no valid reason to diasable this actually */ #define CALC_MD5SUMS true /* Returned by get_url() in case of offline provider */ #define OFFLINE_PROVIDER "autogenerated_content" /* This needs to be updated in case of new image getters.. this is a bit silly */ #define TYPE_IS_IMAGE(TYPE) (TYPE == GLYR_GET_COVERART || TYPE == GLYR_GET_ARTIST_PHOTOS || TYPE == GLYR_GET_BACKDROPS) /* Get signal_exit with atomic operations */ #define GET_ATOMIC_SIGNAL_EXIT(QUERY) (g_atomic_int_get(&((QUERY)->signal_exit))) #define SET_ATOMIC_SIGNAL_EXIT(QUERY,V) (g_atomic_int_set(&((QUERY)->signal_exit),V)) /* Feels a little hackish - but works with extremely high probability :-) */ #define QUERY_INITIALIZER 0xDEADBEEF #define QUERY_IS_INITALIZED(Q) (Q && Q->is_initalized == QUERY_INITIALIZER) /*------------------------------------------------------*/ /* ----------------- Messages ------------------------- */ /*------------------------------------------------------*/ int glyr_message (int v, GlyrQuery * s, const char * fmt, ...); /*------------------------------------------------------*/ /* Used to pass arguments to DL_buffer() */ typedef struct { GlyrMemCache * cache; GlyrQuery * query; char * endmarker; } DLBufferContainer; /*------------------------------------------------------*/ // Internal calback object, used for cover, lyrics and other // This is only used inside the core and the plugins // Other parts of the program shall not use this struct // GlyrMemCache is what you're searching // It models the data that one plugin needs. typedef struct cb_object { // What url to download before the callback is called char *url; // What curl handle this is attached CURL *handle; // pointer to settings struct (artist,album,etc) GlyrQuery * s; // internal cache attached to this url GlyrMemCache *cache; // has this struct been consumed? gboolean consumed; // If this item reached DL_buff gboolean was_buffered; // DLBuffer data DLBufferContainer * dlbuffer; } cb_object; /*------------------------------------------------------*/ // Internal representation of one metadataprovider // PLEASE FILL _ALL_ FIELDS! typedef struct MetaDataFetcher { /* cover, lyrics, stuff */ const char * name; /* A List of MetaDataSources */ GList * provider; /* what this thing delievers; e.g. GLYR_GET_COVERART */ GLYR_GET_TYPE type; /* callbacks */ void (*init) (void); void (*destroy) (void); GList* (*finalize) (GlyrQuery*,GList*,gboolean*,GList**); /* Default value for ->parallel, if set to auto */ long default_parallel; /* Optionaly and required fields for this getter */ GLYR_FIELD_REQUIREMENT reqs; /* Wether this Fetcher delievers the full data (lyrics), or just URLs of the data. */ gboolean full_data; /* Default data type to assume for providers */ GLYR_DATA_TYPE default_data_type; } MetaDataFetcher; /*------------------------------------------------------*/ /* Internal representation of one provider */ typedef struct MetaDataSource { gchar * name; /* Name of this provider */ gchar key; /* A key that may be used in --from */ GList * (* parser) (struct cb_object *); /* called when parsing is needed */ const char * (* get_url) (GlyrQuery *); /* called when the url of this provider is needed */ GLYR_GET_TYPE type; /* For what fetcher this provider is working.. */ gboolean free_url; /* URL is dyn. allocated - set this always! */ gchar * encoding; /* Encoding, NULL defaults to UTF-8, this will only take place for textparser */ gchar * endmarker; /* Download stops if this mark is found */ gint quality; /* Measurement of how good the content usually is [0-100] */ gint speed; /* Measurement of how fast the provider usually is [0-100] */ gboolean lang_aware; /* Has language specific content? */ GLYR_DATA_TYPE data_type; /* Default datatype this provider delievers */ } MetaDataSource; /*------------------------------------------------------*/ typedef GList* (*AsyncDLCB) (cb_object*,void *,bool*,gint*); GList * async_download (GList * url_list, GList * endmark_list, GlyrQuery * s, long parallel_fac, long timeout_fac, AsyncDLCB callback, void * userptr, gboolean free_caches); GList * start_engine (GlyrQuery * query, MetaDataFetcher * fetcher, GLYR_ERROR * err); GlyrMemCache * download_single (const char* url, GlyrQuery * s, const char * end); /*------------------------------------------------------*/ GlyrMemCache * DL_init (void); GlyrMemCache * DL_copy (GlyrMemCache * cache); void DL_free (GlyrMemCache *cache); void DL_set_data (GlyrMemCache * cache, const gchar * data, gint len); /*------------------------------------------------------*/ void update_md5sum (GlyrMemCache * c); void glist_free_full (GList * List, void (* free_func) (void * ptr) ); /*------------------------------------------------------*/ gboolean size_is_okay (int sZ, int min, int max); gboolean is_in_result_list (GlyrMemCache * cache, GList * result_list); gboolean provider_is_enabled (GlyrQuery * q, MetaDataSource * f); gboolean continue_search (gint current, GlyrQuery * s); #endif glyr-1.0.5/lib/glyr.c000066400000000000000000001110271227540770500143740ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a command-line tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include #include #include "glyr.h" #include "core.h" #include "register_plugins.h" #include "blacklist.h" #include "cache.h" #include "stringlib.h" ////////////////////////////////// static volatile gboolean is_initalized = FALSE; ////////////////////////////////// static const char * err_strings[] = { [GLYRE_UNKNOWN] = "Unknown error", [GLYRE_OK] = "No error", [GLYRE_BAD_VALUE] ="Bad value for glyr_opt_[...]()", [GLYRE_BAD_OPTION] = "Bad option passed to gly_opt_[...]()", [GLYRE_NO_PROVIDER] = "No valid provider specified in glyr_opt_from()", [GLYRE_EMPTY_STRUCT] = "Empty Query structure (NULL)", [GLYRE_UNKNOWN_GET] = "Unknown GLYR_GET_TYPE in glyr_get(); Use glyr_opt_type()", [GLYRE_INSUFF_DATA] = "Insufficient data supplied for this getter", [GLYRE_SKIP] = "Item was skipped due to user", [GLYRE_STOP_POST] = "Stopped by callback (POST)", [GLYRE_STOP_PRE] = "Stopped by callback (PRE)", [GLYRE_NO_INIT] = "Library is not yet initialized, use glyr_init()", [GLYRE_WAS_STOPPED] = "Library was stopped by glyr_signal_exit()" }; static const char * type_strings[] = { [GLYR_TYPE_COVERART] = "cover", [GLYR_TYPE_LYRICS] = "songtext", [GLYR_TYPE_ARTIST_PHOTO] = "artistphoto", [GLYR_TYPE_ALBUM_REVIEW] = "albumreview", [GLYR_TYPE_ARTIST_BIO] = "artistbio", [GLYR_TYPE_SIMILAR_ARTIST] = "similar_artist", [GLYR_TYPE_SIMILAR_SONG] = "similar_song", [GLYR_TYPE_TRACK] = "trackname", [GLYR_TYPE_ALBUMLIST] = "albumname", [GLYR_TYPE_TAG] = "tag", [GLYR_TYPE_TAG_ARTIST] = "artisttag", [GLYR_TYPE_TAG_ALBUM] = "albumtag", [GLYR_TYPE_TAG_TITLE] = "titletag", [GLYR_TYPE_RELATION] = "relation", [GLYR_TYPE_IMG_URL] = "ImageURL", [GLYR_TYPE_TXT_URL] = "HTMLURL", [GLYR_TYPE_GUITARTABS] = "guitartabs", [GLYR_TYPE_BACKDROPS] = "backdrop", [GLYR_TYPE_UNKNOWN] = "unknown" }; ///////////////////////////////// const gchar * map_language[][2] = { {"en_US","us"}, {"en_CA","ca"}, {"en_UK","uk"} }; ///////////////////////////////// void glyr_internal_log (const gchar *log_domain,GLogLevelFlags log_level,const gchar *message, gpointer user_data) { if (message != NULL) fputs (message,GLYR_OUTPUT); } ///////////////////////////////// /* Local scopes are cool. */ #define END_STRING(STR,CHAR) \ { \ gchar * term = strchr(STR,CHAR); \ if(term) *term = 0; \ } /** * @brief Guesses the users language (in ISO639-1 codes like 'de') by the system locale * * @return a newly allocated language code. Free. */ gchar * guess_language (void) { /* Default to 'en' in any case */ gchar * result_lang = g_strdup ("en"); #if GLIB_CHECK_VERSION(2,28,0) gboolean break_out = FALSE; /* Please never ever free this */ const gchar * const * languages = g_get_language_names(); for (gint i = 0; languages[i] && break_out == FALSE; i++) { gchar ** variants = g_get_locale_variants (languages[i]); for (gint j = 0; variants[j] && !break_out; j++) { /* Look up if we need to map a language */ gchar * to_investigate = variants[j]; gint map_size = (sizeof (map_language) / (2 * sizeof (char*) ) ); for (gint map = 0; map < map_size; map++) { const gchar * to_map = map_language[map][0]; gsize map_len = strlen (to_map); if (g_ascii_strncasecmp (to_map,to_investigate,map_len) == 0) { to_investigate = (gchar*) map_language[map][1]; break; } } gboolean allowed_lang = TRUE; if (allowed_lang && g_ascii_strncasecmp ("en",to_investigate,2) != 0 && g_ascii_strncasecmp ("C", to_investigate,1) != 0 && !strchr (to_investigate,'@') && !strchr (to_investigate,'.') ) { g_free (result_lang); result_lang = g_strdup (to_investigate); break_out = TRUE; } } g_strfreev (variants); } #elif GLIB_CHECK_VERSION(2,26,0) /* Fallback to simpler version of the above, * g_get_locale_variants is not there in this version */ const gchar * const * possible_locales = g_get_language_names(); if (possible_locales != NULL) { /* might be a bit weird */ for (gint i = 0; possible_locales[i]; i++) { if (g_ascii_strncasecmp ("en",possible_locales[i],2) != 0 && g_ascii_strncasecmp ("C", possible_locales[i],1) != 0) { g_free (result_lang); result_lang = g_strdup (possible_locales[i]); break; } } } #else /* Fallback for version prior GLib 2.26: * Fallback to "en" always. * Gaaah... shame on you if this happens to you ;-) */ #endif /* Properly terminate string */ END_STRING (result_lang,'_'); END_STRING (result_lang,'@'); END_STRING (result_lang,'.'); /* We don't need it anymore */ #undef END_STRING return result_lang; } ///////////////////////////////// static int glyr_set_info (GlyrQuery * s, int at, const char * arg); static void set_query_on_defaults (GlyrQuery * glyrs); ///////////////////////////////// // OTHER ///////////////////////////////// // return a descriptive string on error ID __attribute__ ( (visibility ("default") ) ) const char * glyr_strerror (GLYR_ERROR ID) { if (ID < (sizeof (err_strings) /sizeof (const char *) ) ) { return err_strings[ID]; } return err_strings[GLYRE_UNKNOWN]; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_signal_exit (GlyrQuery * query) { SET_ATOMIC_SIGNAL_EXIT (query,1); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_update_md5sum (GlyrMemCache * cache) { update_md5sum (cache); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_set_data (GlyrMemCache * cache, const char * data, int len) { DL_set_data (cache,data,len); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrMemCache * glyr_cache_copy (GlyrMemCache * cache) { return DL_copy (cache); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) const char * glyr_version (void) { return "Version "GLYR_VERSION_MAJOR"."GLYR_VERSION_MINOR"."GLYR_VERSION_MICRO" ("GLYR_VERSION_NAME") of ["__DATE__"] compiled at ["__TIME__"]"; } ///////////////////////////////// // _opt_ ///////////////////////////////// // Seperate method because va_arg struggles with function pointers __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_dlcallback (GlyrQuery * settings, DL_callback dl_cb, void * userp) { if (settings) { settings->callback.download = dl_cb; settings->callback.user_pointer = userp; return GLYRE_OK; } return GLYRE_EMPTY_STRUCT; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_type (GlyrQuery * s, GLYR_GET_TYPE type) { if (s == NULL) return GLYRE_EMPTY_STRUCT; if (type != GLYR_GET_UNKNOWN) { s->type = type; return GLYRE_OK; } return GLYRE_BAD_VALUE; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_artist (GlyrQuery * s, const char * artist) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,0,artist); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_album (GlyrQuery * s, const char * album) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,1,album); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_title (GlyrQuery * s, const char * title) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,2,title); return GLYRE_OK; } ///////////////////////////////// static int size_set (int * ref, int size) { if (size < -1 && ref) { *ref = -1; return GLYRE_BAD_VALUE; } if (ref) { *ref = size; return GLYRE_OK; } return GLYRE_BAD_OPTION; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_img_maxsize (GlyrQuery * s, int size) { if (s == NULL) return GLYRE_EMPTY_STRUCT; return size_set (&s->img_max_size,size); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_img_minsize (GlyrQuery * s, int size) { if (s == NULL) return GLYRE_EMPTY_STRUCT; return size_set (&s->img_min_size,size); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_parallel (GlyrQuery * s, unsigned long val) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->parallel = (long) val; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_timeout (GlyrQuery * s, unsigned long val) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->timeout = (long) val; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_redirects (GlyrQuery * s, unsigned long val) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->redirects = (long) val; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_useragent (GlyrQuery * s, const char * useragent) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,6, (useragent) ? useragent : ""); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_lang (GlyrQuery * s, const char * langcode) { if (s == NULL) return GLYRE_EMPTY_STRUCT; if (langcode != NULL) { if (g_ascii_strncasecmp ("auto",langcode,4) == 0) { gchar * auto_lang = guess_language(); glyr_set_info (s,7,auto_lang); g_free (auto_lang); } else { glyr_set_info (s,7,langcode); } return GLYRE_OK; } return GLYRE_BAD_VALUE; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_lang_aware_only (GlyrQuery * s, bool lang_aware_only) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->lang_aware_only = lang_aware_only; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_number (GlyrQuery * s, unsigned int num) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->number = num == 0 ? INT_MAX : num; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_verbosity (GlyrQuery * s, unsigned int level) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->verbosity = level; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_from (GlyrQuery * s, const char * from) { if (s == NULL) return GLYRE_EMPTY_STRUCT; if (from != NULL) { glyr_set_info (s,4,from); return GLYRE_OK; } return GLYRE_BAD_VALUE; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_allowed_formats (GlyrQuery * s, const char * formats) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,5, (formats==NULL) ? GLYR_DEFAULT_ALLOWED_FORMATS : formats); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_musictree_path (GlyrQuery * s, const char * musictree_path) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,8, (musictree_path==NULL) ? GLYR_DEFAULT_MUISCTREE_PATH : musictree_path); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_plugmax (GlyrQuery * s, int plugmax) { if (s == NULL) return GLYRE_EMPTY_STRUCT; if (plugmax < 0) { return GLYRE_BAD_VALUE; } s->plugmax = plugmax; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_qsratio (GlyrQuery * s, float ratio) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->qsratio = MIN (MAX (ratio,0.0),1.0); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_proxy (GlyrQuery * s, const char * proxystring) { if (s == NULL) return GLYRE_EMPTY_STRUCT; glyr_set_info (s,3,proxystring); return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_fuzzyness (GlyrQuery * s, int fuzz) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->fuzzyness = fuzz; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_download (GlyrQuery * s, bool download) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->download = download; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_force_utf8 (GlyrQuery * s, bool force_utf8) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->force_utf8 = force_utf8; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_lookup_db (GlyrQuery * s, GlyrDatabase * db) { if (s == NULL) return GLYRE_EMPTY_STRUCT; if (db != NULL) { s->local_db = db; return GLYRE_OK; } return GLYRE_BAD_VALUE; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_db_autowrite (GlyrQuery * s, bool db_autowrite) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->db_autowrite = db_autowrite; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_db_autoread (GlyrQuery * s, bool db_autoread) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->db_autoread = db_autoread; return GLYRE_OK; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_ERROR glyr_opt_normalize (GlyrQuery * s, GLYR_NORMALIZATION norm) { if (s == NULL) return GLYRE_EMPTY_STRUCT; s->normalization = norm; return GLYRE_OK; } ///////////////////////////////// ///////////////////////////////// ///////////////////////////////// static void set_query_on_defaults (GlyrQuery * glyrs) { if (glyrs == NULL) { return; } /* Initialize free pointer pool */ memset (glyrs,0,sizeof (GlyrQuery) ); glyrs->type = GLYR_GET_UNKNOWN; glyrs->artist = NULL; glyrs->album = NULL; glyrs->title = NULL; glyrs->local_db = NULL; glyrs->callback.download = NULL; glyrs->callback.user_pointer = NULL; glyrs->musictree_path = NULL; glyrs->q_errno = GLYRE_OK; glyrs->db_autoread = GLYR_DEFAULT_DB_AUTOREAD; glyrs->db_autowrite = GLYR_DEFAULT_DB_AUTOWRITE; glyrs->from = GLYR_DEFAULT_FROM; glyrs->img_min_size = GLYR_DEFAULT_CMINSIZE; glyrs->img_max_size = GLYR_DEFAULT_CMAXSIZE; glyrs->number = GLYR_DEFAULT_NUMBER; glyrs->parallel = GLYR_DEFAULT_PARALLEL; glyrs->redirects = GLYR_DEFAULT_REDIRECTS; glyrs->timeout = GLYR_DEFAULT_TIMEOUT; glyrs->verbosity = GLYR_DEFAULT_VERBOSITY; glyrs->plugmax = GLYR_DEFAULT_PLUGMAX; glyrs->download = GLYR_DEFAULT_DOWNLOAD; glyrs->fuzzyness = GLYR_DEFAULT_FUZZYNESS; glyrs->proxy = GLYR_DEFAULT_PROXY; glyrs->qsratio = GLYR_DEFAULT_QSRATIO; glyrs->allowed_formats = GLYR_DEFAULT_ALLOWED_FORMATS; glyrs->useragent = GLYR_DEFAULT_USERAGENT; glyrs->force_utf8 = GLYR_DEFAULT_FORCE_UTF8; glyrs->lang = GLYR_DEFAULT_LANG; glyrs->lang_aware_only = GLYR_DEFAULT_LANG_AWARE_ONLY; glyrs->normalization = GLYR_NORMALIZE_AGGRESSIVE | GLYR_NORMALIZE_ALL; glyrs->signal_exit = FALSE; glyrs->itemctr = 0; /* Set on a very specific value, so we can pretty sure, we are not accessing bad memory - feels little hackish.. */ glyrs->is_initalized = QUERY_INITIALIZER; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_query_init (GlyrQuery * glyrs) { if (glyrs != NULL) { set_query_on_defaults (glyrs); } } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_query_destroy (GlyrQuery * sets) { if (sets != NULL && QUERY_IS_INITALIZED (sets) ) { for (gsize i = 0; i < 10; i++) { if (sets->info[i] != NULL) { g_free ( (char*) sets->info[i]); sets->info[i] = NULL; } } /* Reset query so it can be used again */ set_query_on_defaults (sets); } } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrMemCache * glyr_download (const char * url, GlyrQuery * s) { return download_single (url,s,NULL); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_free_list (GlyrMemCache * head) { if (head != NULL) { GlyrMemCache * next = head; GlyrMemCache * prev = head->prev; while (next != NULL) { GlyrMemCache * p = next; next = next->next; DL_free (p); } while (prev != NULL) { GlyrMemCache * p = prev; prev = prev->prev; DL_free (p); } } } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_free (GlyrMemCache * c) { DL_free (c); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrMemCache * glyr_cache_new (void) { return DL_init(); } ///////////////////////////////// // !! NOT THREADSAFE !! // __attribute__ ( (visibility ("default") ) ) void glyr_init (void) { /* Protect agains double initialization */ if (is_initalized == FALSE) { /* Set loghandler */ g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, glyr_internal_log, NULL); if (curl_global_init (CURL_GLOBAL_ALL) ) { glyr_message (-1,NULL,"Fatal: libcurl failed to init\n"); } /* Locale */ if (setlocale (LC_ALL, "") == NULL) { glyr_message (-1,NULL,"Cannot set locale!\n"); } /* Register plugins */ register_fetcher_plugins(); /* Init the smallest blacklist in the world :-) */ blacklist_build(); is_initalized = TRUE; } } ///////////////////////////////// // !! NOT THREADSAFE !! // __attribute__ ( (visibility ("default") ) ) void glyr_cleanup (void) { if (is_initalized == TRUE) { /* Curl no longer needed */ curl_global_cleanup(); /* Destroy all fetchers */ unregister_fetcher_plugins(); /* Kill it again */ blacklist_destroy(); is_initalized = FALSE; } } ///////////////////////////////// /* Sets parallel field depending on the get_type */ static void auto_detect_parallel (MetaDataFetcher * fetcher, GlyrQuery * query) { if (query->parallel <= 0) { if (fetcher->default_parallel <= 0) { gint div = (int) (1.0/ (CLAMP (query->qsratio,0.01,0.99) * 2) ); query->parallel = (div == 0) ? 3 : g_list_length (fetcher->provider) / div; } else { query->parallel = fetcher->default_parallel; } } } ///////////////////////////////// static gboolean check_if_valid (GlyrQuery * q, MetaDataFetcher * fetch) { gboolean isValid = TRUE; if (fetch->reqs & GLYR_REQUIRES_ARTIST && q->artist == NULL) { glyr_message (2,q,"Artist is required for this getter\n"); isValid = FALSE; } if (fetch->reqs & GLYR_REQUIRES_ALBUM && q->album == NULL) { glyr_message (2,q,"Albumname is required for this getter\n"); isValid = FALSE; } if (fetch->reqs & GLYR_REQUIRES_TITLE && q->title == NULL) { glyr_message (2,q,"Songname is required for this getter\n"); isValid = FALSE; } if (isValid == FALSE && fetch->reqs > GLYR_REQUIRES_TITLE) { char * f1 = "",* f2 = "", * f3 = ""; if (fetch->reqs & GLYR_OPTIONAL_ARTIST) f1 = "Artist "; if (fetch->reqs & GLYR_OPTIONAL_ALBUM) f2 = "Album "; if (fetch->reqs & GLYR_OPTIONAL_TITLE) f3 = "Songtitle "; if (*f1 || *f2 || *f3) { glyr_message (2,q,"\nFollowing fields are optional: %s%s%s\n",f1,f2,f3); } } return isValid; } ///////////////////////////////// static void set_error (GLYR_ERROR err_in, GlyrQuery * query, GLYR_ERROR * err_out) { if (query) query->q_errno = err_in; if (err_out) *err_out = err_in; } ///////////////////////////////// #define PRINT_NORMALIZED_ATTR(name, mode, var) \ if(var != NULL && query->verbosity >= 2) \ { \ char * prepared = prepare_string(var, mode, FALSE); \ if(prepared != NULL) \ { \ glyr_message(2, query, name); \ glyr_message(2, query, "%s\n", prepared); \ g_free(prepared); \ } \ } \ __attribute__ ( (visibility ("default") ) ) GlyrMemCache * glyr_get (GlyrQuery * query, GLYR_ERROR * e, int * length) { if (is_initalized == FALSE || QUERY_IS_INITALIZED (query) == FALSE) { glyr_message (-1,NULL,"Warning: Either query or library is not initialized.\n"); if (e != NULL) { set_error (GLYRE_NO_INIT, query, e); } return NULL; } set_error (GLYRE_OK, query, e); if (query != NULL) { if (g_ascii_strncasecmp (query->lang,"auto",4) == 0) { glyr_opt_lang (query,"auto"); } GList * result = NULL; set_error (GLYRE_UNKNOWN_GET, query, e); for (GList * elem = r_getFList(); elem; elem = elem->next) { MetaDataFetcher * item = elem->data; if (query->type == item->type) { if (check_if_valid (query,item) == TRUE) { /* Print some user info, always useful */ if (query->normalization & GLYR_NORMALIZE_ARTIST) { PRINT_NORMALIZED_ATTR("- Artist : ", query->normalization, query->artist); } else { PRINT_NORMALIZED_ATTR("- Artist : ", GLYR_NORMALIZE_NONE, query->artist); } if (query->normalization & GLYR_NORMALIZE_ALBUM) { PRINT_NORMALIZED_ATTR("- Album : ", query->normalization, query->album); } else { PRINT_NORMALIZED_ATTR("- Album : ", GLYR_NORMALIZE_NONE, query->album); } if (query->normalization & GLYR_NORMALIZE_TITLE) { PRINT_NORMALIZED_ATTR("- Title : ", query->normalization, query->title); } else { PRINT_NORMALIZED_ATTR("- Title : ", GLYR_NORMALIZE_NONE, query->title); } if (query->lang != NULL) { glyr_message (2,query,"- Language : "); glyr_message (2,query,"%s\n",query->lang); } set_error (GLYRE_OK, query, e); glyr_message (2,query,"- Type : %s\n\n",item->name); /* Lookup what we search for here: Images (url, or raw) or text */ query->imagejob = ! (item->full_data); /* If ->parallel is <= 0, it gets autodetected */ auto_detect_parallel (item, query); /* Now start your engines, gentlemen */ result = start_engine (query,item,e); break; } else { set_error (GLYRE_INSUFF_DATA, query, e); } } } /* Make this query reusable */ query->itemctr = 0; /* Start of the returned list */ GlyrMemCache * head = NULL; /* Librarby was stopped, just return NULL. */ if (result != NULL && GET_ATOMIC_SIGNAL_EXIT (query) ) { for (GList * elem = result; elem; elem = elem->next) DL_free (elem->data); g_list_free (result); result = NULL; set_error (GLYRE_WAS_STOPPED, query, e); } /* Set the length */ if (length != NULL) { *length = g_list_length (result); } /* free if empty */ if (result != NULL) { /* Count inserstions */ gint db_inserts = 0; /* link caches to each other */ for (GList * elem = result; elem; elem = elem->next) { GlyrMemCache * item = elem->data; item->next = (elem->next) ? elem->next->data : NULL; item->prev = (elem->prev) ? elem->prev->data : NULL; if (query->db_autowrite && query->local_db && item->cached == FALSE) { db_inserts++; glyr_db_insert (query->local_db,query,item); } } if (db_inserts > 0) { glyr_message (2,query,"--- Inserted %d item%s into db.\n",db_inserts, (db_inserts == 1) ? "" : "s"); } /* Finish. */ if (g_list_first (result) ) { head = g_list_first (result)->data; } g_list_free (result); result = NULL; } /* Done! */ SET_ATOMIC_SIGNAL_EXIT (query,0); return head; } set_error (GLYRE_EMPTY_STRUCT, query, e); SET_ATOMIC_SIGNAL_EXIT (query,0); return NULL; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) int glyr_cache_write (GlyrMemCache * data, const char * path) { int bytes = -1; if (path) { if (!g_ascii_strcasecmp (path,"null") ) { bytes = 0; } else if (!g_ascii_strcasecmp (path,"stdout") ) { bytes=fwrite (data->data,1,data->size,stdout); fputc ('\n',stdout); } else if (!g_ascii_strcasecmp (path,"stderr") ) { bytes=fwrite (data->data,1,data->size,stderr); fputc ('\n',stderr); } else { FILE * fp = fopen (path,"w"); if (fp) { if (data->data != NULL) { bytes=fwrite (data->data,1,data->size,fp); } fclose (fp); } else { glyr_message (-1,NULL,"glyr_cache_write: Unable to write to '%s'!\n",path); } } } return bytes; } ///////////////////////////////// static int glyr_set_info (GlyrQuery * s, int at, const char * arg) { gint result = GLYRE_OK; if (s && arg && at >= 0 && at < 10) { if (s->info[at] != NULL) { g_free ( (char*) s->info[at]); } s->info[at] = g_strdup (arg); switch (at) { case 0: s->artist = (gchar*) s->info[at]; break; case 1: s->album = (gchar*) s->info[at]; break; case 2: s->title = (gchar*) s->info[at]; break; case 3: s->proxy = s->info[at]; break; case 4: s->from = (gchar*) s->info[at]; break; case 5: s->allowed_formats = (gchar*) s->info[at]; break; case 6: s->useragent = (gchar*) s->info[at]; break; case 7: s->lang = (gchar*) s->info[at]; break; case 8: s->musictree_path = (gchar * ) s->info[at]; break; default: glyr_message (2,s,"Warning: wrong for glyr_info_at!\n"); } } else { result = GLYRE_BAD_VALUE; } return result; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) const char * glyr_get_type_to_string (GLYR_GET_TYPE type) { const gchar * result = "unknown"; GList * fetcher_list = r_getFList(); for (GList * elem = fetcher_list; elem != NULL; elem = elem->next) { MetaDataFetcher * fetch = elem->data; if (fetch->type == type) { result = fetch->name; break; } } return result; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_GET_TYPE glyr_string_to_get_type (const char * string) { if (string != NULL) { GList * fetcher_list = r_getFList(); for (GList * elem = fetcher_list; elem != NULL; elem = elem->next) { MetaDataFetcher * fetch = elem->data; if (g_ascii_strcasecmp (fetch->name,string) == 0) { return fetch->type; break; } } } return GLYR_GET_UNKNOWN; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) const char * glyr_data_type_to_string (GLYR_DATA_TYPE type) { if (type > 0 && type < (sizeof (type_strings) /sizeof (const char*) ) ) { return type_strings[type]; } else { return type_strings[GLYR_TYPE_UNKNOWN]; } } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_DATA_TYPE glyr_string_to_data_type (const char * string) { if (string != NULL) { gsize table_size = (sizeof (type_strings) /sizeof (const char*) ); for (gsize i = 0; i < table_size; i++) { if (g_ascii_strcasecmp (string,type_strings[i]) == 0) return i; } } return GLYR_TYPE_UNKNOWN; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_print (GlyrMemCache * cacheditem) { if (cacheditem != NULL) { glyr_message (-1,NULL,"FROM: <%s>\n",cacheditem->dsrc); glyr_message (-1,NULL,"PROV: %s\n",cacheditem->prov); glyr_message (-1,NULL,"SIZE: %d Bytes\n", (int) cacheditem->size); glyr_message (-1,NULL,"MSUM: "); /* Print md5sum */ for (int i = 0; i < 16; i++) { fprintf (stderr,"%02x", cacheditem->md5sum[i]); } // Each cache identified it's data by a constant glyr_message (-1,NULL,"\nTYPE: "); if (cacheditem->type == GLYR_TYPE_TRACK) { glyr_message (-1,NULL,"[%02d:%02d] ",cacheditem->duration/60, cacheditem->duration%60); } glyr_message (-1,NULL,"%s",glyr_data_type_to_string (cacheditem->type) ); glyr_message (-1,NULL,"\nSAFE: %s", (cacheditem->cached) ? "Yes" : "No"); glyr_message (-1,NULL,"\nRATE: %d",cacheditem->rating); glyr_message (-1,NULL,"\nSTMP: %f",cacheditem->timestamp); /* Print the actual data. * This might have funny results if using cover/photos */ if (cacheditem->is_image == FALSE) { glyr_message (-1,NULL,"\nDATA: \n%s",cacheditem->data); } else { glyr_message (-1,NULL,"\nFRMT: %s",cacheditem->img_format); glyr_message (-1,NULL,"\nDATA: "); } glyr_message (-1,NULL,"\n"); } } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GlyrFetcherInfo * glyr_info_get (void) { return get_plugin_info(); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_info_free (GlyrFetcherInfo * info) { free_plugin_info (info); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) char * glyr_md5sum_to_string (unsigned char * md5sum) { gchar * md5str = NULL; if (md5sum != NULL) { const gchar * hex = "0123456789abcdef"; md5str = g_malloc0 (33); for (int i = 0; i < 16; i++) { gint index = i * 2; md5str[index + 0] = hex[md5sum[i] / 16]; md5str[index + 1] = hex[md5sum[i] % 16]; } } return md5str; } ///////////////////////////////// #define CHAR_TO_NUM(c) (unsigned char)(g_ascii_isdigit(c) ? c - '0' : (c - 'a') + 10) __attribute__ ( (visibility ("default") ) ) void glyr_string_to_md5sum (const char * string, unsigned char * md5sum) { if (string != NULL && strlen (string) >= 32 && md5sum) { for (gint i = 0; i < 16; i++) { gint index = i * 2; md5sum[i] = (CHAR_TO_NUM (string[index]) << 4) + CHAR_TO_NUM (string[index+1]); } } } #undef CHAR_TO_NUM ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) GLYR_FIELD_REQUIREMENT glyr_get_requirements (GLYR_GET_TYPE type) { GLYR_FIELD_REQUIREMENT result = 0; GlyrFetcherInfo * info = glyr_info_get(); GlyrFetcherInfo * head = info; while (head != NULL) { if (type == head->type) { result = head->reqs; } head = head->next; } glyr_info_free (info); return result; } /* --------------------------------------------------------- * Setters for MemCache * There is not a setter for everything, just for things, * you might be interested in to set. * (No setter for is_image e.g.) * --------------------------------------------------------- */ #define SET_CACHE_STRING(Cache, Field, Value) \ if(Cache != NULL) { \ if(Field != NULL) { \ g_free(Field); \ } \ Field = g_strdup(Value); \ } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_set_dsrc (GlyrMemCache * cache, const char * download_source) { SET_CACHE_STRING (cache,cache->dsrc,download_source); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_set_prov (GlyrMemCache * cache, const char * provider) { SET_CACHE_STRING (cache,cache->prov,provider); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_set_img_format (GlyrMemCache * cache, const char * img_format) { SET_CACHE_STRING (cache,cache->img_format,img_format); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_set_type (GlyrMemCache * cache, GLYR_DATA_TYPE type) { if (cache != NULL) cache->type = MAX (type,GLYR_TYPE_UNKNOWN); } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) void glyr_cache_set_rating (GlyrMemCache * cache, int rating) { if (cache != NULL) cache->rating = rating; } ///////////////////////////////// __attribute__ ( (visibility ("default") ) ) bool glyr_type_is_image (GLYR_GET_TYPE type) { return TYPE_IS_IMAGE (type); } ///////////////////////////////// glyr-1.0.5/lib/glyr.h000066400000000000000000001023531227540770500144030ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef GLYR_H #define GLYR_GLYR_H /** * SECTION:glyr * @short_description: Main interface to search metadata * @title: Glyr * @section_id: * @stability: Stable * @include: glyr/glyr.h * * All functions used to search metadata and use the essential of libglyr * is located here. */ /* All structs used by glyr are here */ #include "types.h" #ifdef __cplusplus extern "C" { #endif /** * glyr_init: * * Init the library, this has to be called before any other calls from this library are made. * * You should call glyr_cleanup() once for every call of glyr_init() * * * This function is not threadsafe. * * **/ void glyr_init (void); /** * glyr_cleanup: * * Cleanup all parts of the library, you can use atexit(): * * * * * glyr_init(); * atexit(glyr_destroy); * * * * * * This function is not threadsafe. * * **/ void glyr_cleanup (void); /** * glyr_get: * @settings: The setting struct controlling glyr. (See the glyr_opt_* methods) * @error: An optional pointer to an int, which gets filled with an error message, or GLYRE_OK on success, or %NULL * @length: length An optional pointer storing the length of the returned list, or %NULL * * @settings is pointer to a #GlyrQuery struct filled to your needs via the glyr_opt_* methods, * * Once an item is found the callback (set via glyr_opt_dlcallback()) is called anytime a item is ready * * * Returns:: a doubly linked list of #GlyrMemCache, which should be freed by passing any element of the to glyr_free_list() * */ GlyrMemCache * glyr_get (GlyrQuery * settings, GLYR_ERROR * error, int * length); /** * glyr_query_init: * @query: The GlyrQuery to initialize to defaultsettings. * * This functions may allocate dynamic memory. It should be freed with glyr_query_init() after use. * */ void glyr_query_init (GlyrQuery * query); /** * glyr_query_destroy: * @query: The GlyrQuery to destroy. * * Deletes all modifications and frees dynamic memory. It can be reused, as fresh from glyr_query_init() * */ void glyr_query_destroy (GlyrQuery * query); /** * glyr_signal_exit: * @query: The currently running query you want to stop. * * Try to stop libglyr as soon as possible. * This is supposed to be called on another thread. * Calling this function twice on the same query will do nothing. * * * This function is threadsafe - but use with care anyway, * since it causes libglyr to do really a hard stop. * The returned data is NOT guaranteed to yield best results. * * */ void glyr_signal_exit (GlyrQuery * query); /** * glyr_free_list: * @head: The head of the doubly linked list that should be freed. * * Deletes all dynamic memory by calling glyr_cache_free() on each cache. * */ void glyr_free_list (GlyrMemCache * head); /** * glyr_cache_new: * * Initializes a new memcache. * * Normally you never need to do this. * * Don't forget to free the cache with glyr_cache_free() * * Returns:: A newly allocated and initialized memcache with no data. */ GlyrMemCache * glyr_cache_new (void); /** * glyr_cache_free: * @cache: Frees the (valid allocated) cache pointed to by @cache */ void glyr_cache_free (GlyrMemCache * cache); /** * glyr_cache_copy: * @cache: The cache to copy * * Allocate a new cache and * copy all contents (= deep copy) from the original @cache, * The pointers next and prev are set to NULL. * * Returns: A newly allocated cache. */ GlyrMemCache * glyr_cache_copy (GlyrMemCache * cache); /** * glyr_cache_set_dsrc: * @cache: The cache to change * @download_source: The string to be changed too * * Copies download_source to the dsrc field, clearing all previously allocated content safely. */ void glyr_cache_set_dsrc (GlyrMemCache * cache, const char * download_source); /** * glyr_cache_set_prov: * @cache: The cache to change * @provider: The string to be changed too * * Copies provider to the prov field, clearing all previously allocated content safely. */ void glyr_cache_set_prov (GlyrMemCache * cache, const char * provider); /** * glyr_cache_set_img_format: * @cache: The cache to change * @img_format: The string to be changed too * * Copies img_format to the img_format field, clearing all previously allocated content safely. */ void glyr_cache_set_img_format (GlyrMemCache * cache, const char * img_format); /** * glyr_cache_set_type: * @cache: The cache to change * @type: The new type */ void glyr_cache_set_type (GlyrMemCache * cache, GLYR_DATA_TYPE type); /** * glyr_cache_set_rating: * @cache: The cache to change * @rating: The new rating */ void glyr_cache_set_rating (GlyrMemCache * cache, int rating); /** * glyr_cache_set_data: * @cache: The cache where to set the data. * @data: The data * @len: Length of data * * Safely sets the data of the cache. It frees the old data first, updates * the checksum and adjusts the size fields accordingly to len. * If len is a negative number strlen() is used to determine the size. * * Attention: @data is set directly! It get's freed once you free the cache. Be sure it's safe to be free'd. * */ void glyr_cache_set_data (GlyrMemCache * cache, const char * data, int len); /** * glyr_cache_write: * @cache: The data to write. * @path: The path to write data at. * * Write @cache to the path specified by @path. * * There are three special files: * * * * "stdout" -> Outputs file to stdout * * * * * "stderr" -> Outputs file to stderr * * * * * "null" -> Outputs item nowhere * * * * * Returns: the number of written bytes. */ int glyr_cache_write (GlyrMemCache * cache, const char * path); /** * glyr_cache_update_md5sum: * @cache: a valid memcahe * * Updates the md5sum field of @cache. * */ void glyr_cache_update_md5sum (GlyrMemCache * cache); /** * glyr_cache_print: * @cache: The GlyrMemCache to be printed. * * A debug method to print all fields of @cache. * */ void glyr_cache_print (GlyrMemCache * cache); /******************************************************** * GlyOpt methods ahead - use them to control glyr_get() * ********************************************************/ /** * glyr_opt_dlcallback: * @settings: The GlyrQuery settings struct to store this option in. * @dl_cb: The callback to register, must have a prototype like this. * @userp: A pointer to a custom variable you can access inside the callback via s->callback.user_pointer * * The callback should have the following form: * * * GLYR_ERROR my_callback(GlyrMemCache * dl, struct GlyrQuery * s); * * * * Note that you can return certaing members of %GLYR_ERROR in the callback: * %GLYRE_SKIP: To not add this item to the results. * %GLYRE_OK: To add this item to the results and continue happily. * %GLYRE_STOP_POST: To stop right now and return the results. The current element will be added. * %GLYRE_STOP_PRE: To stop right now and return the results. The current element will NOT be added. * * Returns: an error ID */ GLYR_ERROR glyr_opt_dlcallback (GlyrQuery * settings, DL_callback dl_cb, void * userp); /** * glyr_opt_type: * @s: The GlyrQuery settings struct to store this option in. * @type: The type of metadata you want to get. * * Example: %GLYR_GET_COVERART * * Returns: an error ID */ GLYR_ERROR glyr_opt_type (GlyrQuery * s, GLYR_GET_TYPE type); /** * glyr_opt_artist: * @s: The GlyrQuery settings struct to store this option in. * @artist: The artist you want to search for, %NULL and "" is not valid. * * This is needed for all types of metadata. * Libglyr keeps a copy of this string internally. * * * * libglyr applies some basic normalization, like " artistX feat. artistY" -> "artistX" * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_artist (GlyrQuery * s, const char * artist); /** * glyr_opt_album: * @s: The GlyrQuery settings struct to store this option in. * @album: The album you want to search for, %NULL and "" is not valid. * * This field is required for the following types: * * * * %GLYR_GET_COVERART * * * * * %GLYR_GET_ALBUM_REVIEW * * * * * %GLYR_GET_TRACKLIST * * * * * Optional for the following types: * * * * %GLYR_GET_RELATIONS * * * * * %GLYR_GET_TAGS * * * * * Libglyr keeps a copy of this string internally. * * * * libglyr applies some basic normalization, like " CoOl_album CD01 (20.7)" -> "cool_album" * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_album (GlyrQuery * s, const char * album); /** * glyr_opt_title: * @s: The GlyrQuery settings struct to store this option in. * @title: The album you want to search for, %NULL and "" is not valid. * * This field is required for the following types: * * * * %GLYR_GET_LYRICS * * * * * %GLYR_GET_SIMILAR_SONGS * * * * * Optional for the following types: * * * * %GLYR_GET_RELATIONS * * * * * %GLYR_GET_TAGS * * * * * Libglyr keeps a copy of this string internally. * * * * libglyr applies some basic normalization, like "Songtitle (blahblah remix)" -> "Songtitle" * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_title (GlyrQuery * s, const char * title); /** * glyr_opt_img_minsize: * @s: The GlyrQuery settings struct to store this option in. * @size: The minimum size in pixels an image may have, assuming it to be quadratic * * * * This is only taken as a hint, returned images are not necessarily higher than this size, but should be around it. * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_img_minsize (GlyrQuery * s, int size); /** * glyr_opt_img_maxsize: * @s: The GlyrQuery settings struct to store this option in. * @size: The maxmimum size in pixels an image may have, assuming it to be quadratic * * * * This is only taken as a hint, returned images are not necessarily below this size, but should be around it. * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_img_maxsize (GlyrQuery * s, int size); /** * glyr_opt_parallel: * @s: The GlyrQuery settings struct to store this option in. * @parallel_jobs: The number of providers that are queried in parallel. * * A value of 0 lets libglyr chooses this value itself. This is the default. * * Returns: an error ID */ GLYR_ERROR glyr_opt_parallel (GlyrQuery * s, unsigned long parallel_jobs); /** * glyr_opt_timeout: * @s: The GlyrQuery settings struct to store this option in. * @timeout: Maximum number of seconds to wait before canceling a download. * * Default is 20 seconds * * Returns: an error ID */ GLYR_ERROR glyr_opt_timeout (GlyrQuery * s, unsigned long timeout); /** * glyr_opt_redirects: * @s: The GlyrQuery settings struct to store this option in. * @redirects: Maximum number of redirects before canceling a download. * * A value of 0 is allowed but may break some plugins. * * Returns: an error ID */ GLYR_ERROR glyr_opt_redirects (GlyrQuery * s, unsigned long redirects); /** * glyr_opt_useragent: * @s: The GlyrQuery settings struct to store this option in. * @useragent: A string that is used as useragent in HTTP requests. * * Some providers require an valid useragent, an empty string might break these therefore. * * Returns: an error ID */ GLYR_ERROR glyr_opt_useragent (GlyrQuery * s, const char * useragent); /** * glyr_opt_lang: * @s: The GlyrQuery settings struct to store this option in. * @langcode: An ISO 639-1 language code. * * Some providers offer localized content, or content only being available in certain countries. * Examples are: last.fm, amazon and google. * The language is given in ISO 639-1 codes like 'de' or 'en'. * Alternatively you can set it to 'auto', which will cause libglyr to guess your language by your locale. * "auto" is the default behavior. * * Returns: an error ID */ GLYR_ERROR glyr_opt_lang (GlyrQuery * s, const char * langcode); /** * glyr_opt_lang_aware_only: * @s: The GlyrQuery settings struct to store this option in. * @lang_aware_only: Boolean, set to true if you want language specific providers only. * * Note: Not for all types of metadata there may be localized content, and only fetchers, that provide text items are affected by this setting. * The special provider 'local' is an exception here, it is queried, but delievers only language specific content too. * * Returns: an error ID */ GLYR_ERROR glyr_opt_lang_aware_only (GlyrQuery * s, bool lang_aware_only); /** * glyr_opt_number: * @s: The GlyrQuery settings struct to store this option in. * @num: Maximum number of items to get or 0 * * The maximum number of items to get in a glyr_get(), resulting number of items may be below @num but not higher. * A value of 0 causes libglyr to search till infinity. * Default is 1. * * Returns: an error ID */ GLYR_ERROR glyr_opt_number (GlyrQuery * s, unsigned int num); /** * glyr_opt_verbosity: * @s: The GlyrQuery settings struct to store this option in. * @level: Define how verbose the library is. * * The verbosity level that is used by libglyr: * * * * 0: No output, but fatal errors. * * * * * 1: Basic warnings. * * * * * 2: Normal informal output * * * * * 3: Basic debug output * * * * * 4: Full debug output * * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_verbosity (GlyrQuery * s, unsigned int level); /** * glyr_opt_from: * @s: The GlyrQuery settings struct to store this option in. * @from: A comma separated list of provider names. * * * Tell libglyr where you want your metadata want from. * You can get a full list of providers for each getter by running @glyrc @-L * The string you can pass here looks like this example for _cover_: * * * "lastfm;google" * * * * This would query to everybody's surprise"lastfm" and "google" * Alternatively you may use the string "all" in it: * * * "all;-lastfm;" * * * * All providers except "lastfm" (therefore the '-') are used, a '+' is also allowed, which does plain nothing. * By default all built-in providers are used. * You can access the providernames by calling glyr_info_get() * * Returns: an error ID */ GLYR_ERROR glyr_opt_from (GlyrQuery * s, const char * from); /** * glyr_opt_plugmax: * @s: The GlyrQuery settings struct to store this option in. * @plugmax: Maximum number of items a single provider may retrieve. * * Restricts providers to retrieve at max. @plugmax items, you might use this to get results * over several providers when glyr_opt_number() is set to something higher than 1. * * May be removed in future releases. * * Returns: an error ID */ GLYR_ERROR glyr_opt_plugmax (GlyrQuery * s, int plugmax); /** * glyr_opt_allowed_formats: * @s: The GlyrQuery settings struct to store this option in. * @formats: A commaseparated list of allowed formats. * * Restricts providers to retrieve at max. @plugmax items, you might use this to get results * over several providers when glyr_opt_number() is set to something higher than 1. * * For the getters %GLYR_GET_COVERART and %GLYR_GET_ARTIST_PHOTOS only. * The allowed formats for images, in a comma separated list. * Examples: * * * * "png;jpeg" * * * * * "png;jpeg;tiff;jpg;" (default) * * * * * * * 'jpeg' *and* 'jpg' because some websites return strange mimetypes (should be 'jpeg' only) * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_allowed_formats (GlyrQuery * s, const char * formats); /** * glyr_opt_download: * @s: The GlyrQuery settings struct to store this option in. * @download: Wether to downlaod images or just to return the found URL. * * Imageproviders only return URLs, by default libglyr downloads these and * gives you the cache. By settings glyr_opt_download() to #FALSE you tell * libglyr that you want only the URLs (in a searchengine like fashion) * * An check for valid images is done however. * * Returns: an error ID */ GLYR_ERROR glyr_opt_download (GlyrQuery * s, bool download); /** * glyr_opt_fuzzyness: * @s: The GlyrQuery settings struct to store this option in. * @fuzz: Maximal Levenshtein-distance tolerance may have, see below. * * libglyr features fuzzy matching to enhance search results. * Look at the string "Equilibrium" and the accidentally mistyped version "Aquillibriu": * Those strings will be compares using the "Levenshtein distance" (http://en.wikipedia.org/wiki/Levenshtein_distance) which basically counts * the number of insert, substitute and delete operations to transform Equilibrium"" into "Aquillibriu". * The distance in this case is 3 since three edit-operations are needed (one insert, substitute and deletion) * * The fuzziness parameter is the maximum distance two strings may have to match. * A high distance (like about 10) matches even badly mistyped strings, but also introduces bad results. * Low settings however will omit some good results. * * The default values is currently 4. * To be more secure some correction is applied: * * Examples: * * * * artist:Adele - album:19 * * * * * artist:Adele - album:21 * * * * * lv-distance = 2 which is <= 4 * * * * * But since the lv-distance is the same as the length "21" it won't match. * * * * * The easiest way to prevent this though, is to properly tag your music. (http://musicbrainz.org/doc/MusicBrainz_Picard). * * Returns: an error ID */ GLYR_ERROR glyr_opt_fuzzyness (GlyrQuery * s, int fuzz); /** * glyr_opt_qsratio: * @s: The GlyrQuery settings struct to store this option in. * @ratio: A float, in the range [0.0..1.0] specifying the ratio between quality and speed. * * 0.00 means highest speed, querying fast providers first. * 1.00 Takes possibly longer, but should deliver best results. * 0.85 is the current default value. * * All other values, smaller 0.0, greater 1.0 are clamped to [0.0..1.0] * * Returns: an error ID */ GLYR_ERROR glyr_opt_qsratio (GlyrQuery * s, float ratio); /** * glyr_opt_proxy: * @s: The GlyrQuery settings struct to store this option in. * @proxystring: The proxy to use, see below for the notation. * * The proxy to use, if any. * It is passed in the form: [protocol://][user:pass@]yourproxy.domain[:port] * Example: * * * * Proxy.fh-hof.de:3128 * * * * * http://hman:rootroot @ godserve.com:666 * * * * * The environment variables http_proxy, ftp_proxy, all_proxy are respected, but are overwritten by this. * * Returns: an error ID */ GLYR_ERROR glyr_opt_proxy (GlyrQuery * s, const char * proxystring); /** * glyr_opt_force_utf8: * @s: The GlyrQuery settings struct to store this option in. * @force_utf8: To force, or not to force. * * For textitems only. * Some providers (like metrolyrics) might return text with strange encodings, * that can not be converted to regular UTF8, but might return a subset of UTF8. * This options forces libglyr to prohibit those. * * Returns: an error ID */ GLYR_ERROR glyr_opt_force_utf8 (GlyrQuery * s, bool force_utf8); /** * glyr_opt_lookup_db: * @s: The GlyrQuery settings struct to store this option in. * @db: a GlyrDatabase object. * * Bind the previosly created @db to the query @s. * By doing this you add a new 'local' provider, * that is queried before everything else and may speed up * things heavily. * * You can either query it exclusively or disable it completely: * * Enable exclusiv: * * * glyr_opt_from(s,"local"); * * Disable: * * * * glyr_opt_from(s,"all;-local"); * * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_lookup_db (GlyrQuery * s, GlyrDatabase * db); /** * glyr_opt_db_autowrite: * @s: The GlyrQuery settings struct to store this option in. * @write_to_db: true, to write this to the database automatically * * If a database is specified via glyr_opt_lookup_db you can choose * to automatically save newly found items to the database. * They will be looked up from there if you search for it again. * * Returns: an error ID */ GLYR_ERROR glyr_opt_db_autowrite (GlyrQuery * s, bool write_to_db); /** * glyr_opt_db_autoread: * @s: The GlyrQuery settings struct to store this option in. * @read_from_db: Boolean, true for DB lookup while searching * * If set to true libglyr will lookup the database previously given by glyr_opt_lookup_db() * during searching in the web. If there's item that already seems to be in the DB it gets not * mixed into the results. * * * This does not influence the usage of the DB as local provider! * Use glyr_opt_from() with "all;-local" to disable it. * * * * Returns: an error ID **/ GLYR_ERROR glyr_opt_db_autoread (GlyrQuery * s, bool read_from_db); /** * glyr_opt_musictree_path: * @s: The GlyrQuery settings struct to store this option in. * @musictree_path: The concrete path (relative or absolute) where a mediafile reisdes (see below) * * Set the path to a specific mediafile and glyr will try to fetch covers from directories around this, * since many people place things like 'folder.jpg' there. Instead of the actual file you can also pass the * containing directory (see the 'dirname' utility) - the path can be either absolute or relative. * * From there on it works by cascading upwards - i.e. checking all files in the dir (not recursing), go up, repeat. * This will be repeated $(recurse_depth) times or till it cannot go upwards. * How the file is checked depends on the metadata type to search, see below. * * For reference the actual C code is given (${artist} gets expanded): * * Used regexes and recurse_depth * case GLYR_GET_COVERART: search_regex = "^(folder|front|cover|.*${album}.*)\\.(jpg|png|jpeg|gif)"; recurse_depth = 2; break; case GLYR_GET_ARTIST_PHOTOS: search_regex = "^(${artist}|artist)\\.(jpg|png|jpeg|gif)$"; recurse_depth = 3; break; case GLYR_GET_ALBUM_REVIEW: search_regex = "^(${album})\\.(info|txt)$"; recurse_depth = 2; break; case GLYR_GET_ARTIST_BIO: search_regex = "^BIOGRAPHY(\\.txt)?$"; recurse_depth = 2; break; default: search_regex = NULL; recurse_depth = 0; break; * * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_musictree_path (GlyrQuery * s, const char * musictree_path); /** * glyr_opt_normalize: * @s: The GlyrQuery settings struct to store this option in. * @norm: Any members of GLYR_NORMALIZATION, which may be binary or'd * * Defines how much artist/album/title is normalized. * * * * * GLYR_NORMALIZE_NONE: Do no normalization, except strdown and utf-8-normalization. * * * * * GLYR_NORMALIZE_MODERATE: Remove stuff like feat., featuring. Track 01 etc. * * * * * GLYR_NORMALIZE_AGGRESSIVE: Also remove everything between (), [] and <>. Slightly destructive! * * * * * * * Even for None, utf-8 normalization and strdown() is done. * The default is GLYR_NORMALIZE_AGGRESSIVE | GLYR_NORMALIZE_ALL * * * * Returns: an error ID */ GLYR_ERROR glyr_opt_normalize (GlyrQuery * s, GLYR_NORMALIZATION norm); /** * glyr_download: * @url: A valid url, for example returned by libglyr * @s: A settings struct managing timeout, useragent and redirects. * * Downloads the data pointed to by @url and caches in it a GlyrMemCache, which is returned to you. * Use glyr_cache_free() to free it after use. * * Returns: A GlyrMemCache containing the data, or %NULL on failure, use verbose output to find out why. */ GlyrMemCache * glyr_download (const char * url, GlyrQuery * s); /** * glyr_strerror: * @ID: a member of the %GLYR_ERROR enum. * * Gets a descriptive message from an error ID. * * Returns: a descriptive nullterminated string, do NOT pass to free */ const char * glyr_strerror (GLYR_ERROR ID); /** * glyr_version: * * Returns: the current version string. Example below. * * Version 0.4 (Larcenous Locust [dev]) of [May 20 2011] compiled at [19:12:37] * * Retunrs a nullterminated string, do NOT pass it to free! */ const char * glyr_version (void); /** * glyr_info_get: * * get information about existing Fetcher and Source * A Doubly linked list of Fetcher is returned, each having a field 'head', * being a pointer to a doubly linked list of GlyrSourceInfos * * It is best understood by an example: * * Using GlyrFetcherInfo: * * static void visualize_from_options(void) * { * GlyrFetcherInfo * info = glyr_info_get(); * if(info != NULL) * { * for(GlyrFetcherInfo * elem0 = info; elem0; elem0 = elem0->next) * { * printf("%s\n",elem0->name); * for(GlyrSourceInfo * elem1 = elem0->head; elem1; elem1 = elem1->next) * { * printf(" [%c] %s\n",elem1->key,elem1->name); * } * printf("\n"); * } * } * glyr_info_free(info); * } * * * * Returns: A newly allocated GlyrFetcherInfo structure, you can iterate over. */ GlyrFetcherInfo * glyr_info_get (void); /** * glyr_info_free: * @info: The return value of glyr_info_get() * * Free the return value of glyr_info_get() pointed to by @info */ void glyr_info_free (GlyrFetcherInfo * info); /** * glyr_data_type_to_string: * @type: a member of the %GLYR_DATA_TYPE enum, %GLYR_TYPE_LYRICS for example * * Converts a type to a string. * * Returns: a statically allocated string, do not free */ const char * glyr_data_type_to_string (GLYR_DATA_TYPE type); /** * glyr_get_type_to_string: * @type: a member of the %GLYR_GET_TYPE enum, %GLYR_GET_COVERART for example * * Converts a get type to a string (GLYR_GET_COVERART => "cover") * You must not modify the string or daemons will come to you at night! * * Returns: a statically allocated string, do not free nor modify */ const char * glyr_get_type_to_string (GLYR_GET_TYPE type); /** * glyr_md5sum_to_string: * @md5sum: a md5sum (from a cache) * * Convert a md5sum (raw data) to a human readable representation. * String consists only of [0-9] and [a-f]. * * Returns: a newly allocated string, 32 chars long. */ char * glyr_md5sum_to_string (unsigned char * md5sum); /** * glyr_string_to_md5sum: * @string: The string containing a human readable checksum (lowercase) * @md5sum: A at lease 16 byte sized buffer of unsigned chars * * Convert a string to a raw-data md5sum. * Must be a 32 char long string only containing [0-9] and [a-f] * The new checksum is written to m5sum, which must be a buffer with * a size >= 16 bytes. */ void glyr_string_to_md5sum (const char * string, unsigned char * md5sum); /** * glyr_get_requirements: * @type: The type to get the requirements from * * Different getters need different fields set. You can use this * to check if the artist, album and title field of a specific getter * is required or optional. * * * * GLYR_FIELD_REQUIREMENT reqs = glyr_get_requirements(GLYR_GET_COVERART); * if(reqs & GLYR_REQUIRES_ALBUM) * { * // do something when artist is required * } * else * if(reqs & GLYR_OPTIONAL_TITLE) * { * // Title is optional * } * else * { * // None of both * } * * * * Returns: A bitmask out of members of GLYR_FIELD_REQUIREMENT */ GLYR_FIELD_REQUIREMENT glyr_get_requirements (GLYR_GET_TYPE type); bool glyr_type_is_image (GLYR_GET_TYPE type); GLYR_GET_TYPE glyr_string_to_get_type (const char * string); GLYR_DATA_TYPE glyr_string_to_data_type (const char * string); #ifdef __cplusplus } #endif #endif glyr-1.0.5/lib/intern/000077500000000000000000000000001227540770500145505ustar00rootroot00000000000000glyr-1.0.5/lib/intern/ainfo.c000066400000000000000000000036711227540770500160170ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../core.h" #include "../stringlib.h" #include "generic.h" ///////////////////////////////// static GList * factory (GlyrQuery * s, GList * list, gboolean * stop_me, GList ** result_list) { /* Fix up messy text, escape chars etc. */ for (GList * elem = list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL) { gchar * temp = beautify_string (item->data); g_free (item->data); item->data = temp; item->size = (item->data) ? strlen (item->data) : 0; } } return generic_txt_finalizer (s,list,stop_me,GLYR_TYPE_ARTIST_BIO,result_list); } ///////////////////////////////// /* PlugStruct */ MetaDataFetcher glyrFetcher_artistbio = { .name = "artistbio", .type = GLYR_GET_ARTIST_BIO, .default_data_type = GLYR_TYPE_ARTIST_BIO, .reqs = GLYR_REQUIRES_ARTIST, .full_data = TRUE, .init = NULL, .destroy = NULL, .finalize = factory, .default_parallel = 2 }; glyr-1.0.5/lib/intern/ainfo/000077500000000000000000000000001227540770500156445ustar00rootroot00000000000000glyr-1.0.5/lib/intern/ainfo/bbcmusic.c000066400000000000000000000056001227540770500176000ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../stringlib.h" #include "../../core.h" #include "../common/mbid_lookup.h" #define API_ROOT "http://www.bbc.co.uk/music/artists/%s.xml" ///////////////////////////////// #define CONTENT_BEGIN "" #define CONTENT_ENDIN "" static GlyrMemCache * parse_bbc_xml (GlyrMemCache * input) { GlyrMemCache * result = NULL; char * content = get_search_value (input->data, CONTENT_BEGIN, CONTENT_ENDIN); if (content != NULL) { result = DL_init(); result->data = content; result->dsrc = g_strdup (input->dsrc); result->size = strlen (content); } return result; } ///////////////////////////////// static const char * ainfo_bbcmusic_url (GlyrQuery * qry) { return "http://musicbrainz.org/ws/2/artist?query=artist:${artist}"; } ///////////////////////////////// static GList * ainfo_bbcmusic_parse (cb_object * capo) { GList * result_list = NULL; char * mbid = mbid_parse_data (capo->cache, "artist", "name", capo->s->artist, capo->s); if (mbid != NULL) { char * full_url = g_strdup_printf (API_ROOT, mbid); if (full_url != NULL) { GlyrMemCache * bbc_xml = download_single (full_url, capo->s, NULL); if (bbc_xml != NULL) { GlyrMemCache * item = parse_bbc_xml (bbc_xml); if (item != NULL) { result_list = g_list_prepend (result_list, item); } DL_free(bbc_xml); } g_free(full_url); } g_free(mbid); } return result_list; } ///////////////////////////////// MetaDataSource ainfo_bbcmusic_src = { .name = "bbcmusic", .key = 'b', .free_url = false, .type = GLYR_GET_ARTIST_BIO, .parser = ainfo_bbcmusic_parse, .get_url = ainfo_bbcmusic_url, .quality = 95, .speed = 85, .endmarker = NULL, .lang_aware = false }; glyr-1.0.5/lib/intern/ainfo/echonest.c000066400000000000000000000100731227540770500176210ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #include "../../apikeys.h" /* JSON Parsing */ #include "../../jsmn/jsmn.h" static const gchar * ainfo_echonest_url (GlyrQuery * s) { return "http://developer.echonest.com/api/v4/artist/biographies?api_key="API_KEY_ECHONEST"&results=${number}&format=json&name=${artist}"; } ///////////////////////////////// static char * echonest_strip_escapes(char * src, char * dest, int len) { int offset = 0; for (int i = 0; i < len; ++i) { if (src[i] == '\\') { ++i; if (src[i] == 'n') { dest[offset++] = '\n'; continue; } } dest[offset++] = src[i]; } return dest; } ///////////////////////////////// static bool echonest_check_if_text_is_valid(char * text, int len) { bool rc = false; if (len >= 125) { return true; } return rc; } ///////////////////////////////// static GList * ainfo_echonest_parse (cb_object * capo) { char * json = capo->cache->data; bool is_text = false; const int num_tokens = 512; GList * results = NULL; /* jasmin stuff */ jsmn_parser parser; jsmntok_t tokens[num_tokens]; jsmnerr_t error; /* make sure it terminates */ memset(tokens, 0, num_tokens * sizeof(jsmntok_t)); /* Init the parser */ jsmn_init(&parser); /* Parse the json text */ error = jsmn_parse(&parser, capo->cache->data, tokens, num_tokens); if (error == JSMN_SUCCESS) { for (int i = 0; i < num_tokens; ++i) { jsmntok_t * tok = &tokens[i]; size_t len = tok->end - tok->start; char * text_off = json + tok->start; /* End of tokens? */ if(tok->start == 0 && tok->end == 0) { break; } /* Check for the "text" field. */ if (tok->type == JSMN_STRING) { if (len == 4 && g_ascii_strncasecmp(text_off, "text", len) == 0) { is_text = true; continue; } } /* Interesting part! */ if (is_text == true && tok->type == JSMN_STRING) { if (echonest_check_if_text_is_valid(text_off, len)) { GlyrMemCache * cache = DL_init(); if (cache != NULL) { cache->data = g_strndup(text_off, len); cache->data = echonest_strip_escapes(cache->data, cache->data, len); cache->size = len; results = g_list_prepend(results, cache); } } is_text = false; continue; } } } else { /* No intelligent error handling yet. */ } return results; } ///////////////////////////////// MetaDataSource ainfo_echonest_src = { .name = "echonest", .key = 'e', .free_url = false, .type = GLYR_GET_ARTIST_BIO, .parser = ainfo_echonest_parse, .get_url = ainfo_echonest_url, .quality = 95, .speed = 85, .endmarker = NULL, .lang_aware = false }; glyr-1.0.5/lib/intern/ainfo/lastfm.c000066400000000000000000000065721227540770500173100ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define CONTENT_BEGIN "" #define CONTENT_ENDIN "User-contributed text" #define OTHER_ENDIN "" #define CDATA_BEGIN "artist," ","+"); if (right_artist != NULL) { gchar * lang = "en"; /* Check if this is an allowed language */ if (strstr (GLYR_DEFAULT_SUPPORTED_LANGS,s->lang) != NULL) { lang = (gchar*) s->lang; } /* Do we need to map a language to 'en'? */ if (strstr (locale_map_to_en,s->lang) != NULL) { lang = "en"; } url = g_strdup_printf ("http://ws.audioscrobbler.com/2.0/?method=artist.getinfo&autocorrect=1&artist=%s&lang=%s&api_key="API_KEY_LASTFM,right_artist,lang); g_free (right_artist); } return url; } ///////////////////////////////// static GList * ainfo_lastfm_parse (cb_object * capo) { GList * result_list = NULL; gchar * content_begin = strstr (capo->cache->data,CONTENT_BEGIN); if (content_begin != NULL) { gchar * content_endin = strstr (capo->cache->data,CONTENT_ENDIN); if (content_endin == NULL) { content_endin = strstr (capo->cache->data,OTHER_ENDIN); } if (content_endin != NULL) { content_begin += (sizeof CONTENT_BEGIN) - 1; char * skip_cdata = strstr(content_begin, CDATA_BEGIN); if (skip_cdata != NULL) { content_begin = skip_cdata + (sizeof CDATA_BEGIN) - 1; } gchar * content = copy_value (content_begin,content_endin); if (content != NULL) { GlyrMemCache * result = DL_init(); result->data = content; result->size = strlen (result->data); result_list = g_list_prepend (result_list,result); } } } return result_list; } ///////////////////////////////// MetaDataSource ainfo_lastfm_src = { .name = "lastfm", .key = 'l', .free_url = true, .type = GLYR_GET_ARTIST_BIO, .parser = ainfo_lastfm_parse, .get_url = ainfo_lastfm_url, .quality = 85, .speed = 85, .endmarker = NULL, .lang_aware = true }; glyr-1.0.5/lib/intern/ainfo/lyricsreg.c000066400000000000000000000052251227540770500200170ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define INFO_BEGIN "
" #define OPTN_BEGIN "Biography:
" #define INFO_ENDIN "
" ///////////////////////////////// static const gchar * ainfo_lyricsreg_url (GlyrQuery * s) { return "http://www.lyricsreg.com/biography/${artist}/"; } ///////////////////////////////// static GList * ainfo_lyricsreg_parse (cb_object * capo) { GList * result_list = NULL; gchar * point_to_start = strstr (capo->cache->data,INFO_BEGIN); if (point_to_start != NULL) { gchar * opt_begin = strstr (point_to_start,OPTN_BEGIN); gsize skip_len = (sizeof INFO_BEGIN) - 1; if (opt_begin != NULL) { point_to_start = opt_begin; skip_len = (sizeof OPTN_BEGIN) - 1; } point_to_start += skip_len; gchar * end = strstr (point_to_start, INFO_ENDIN); if (end != NULL) { gsize info_len = end - point_to_start; if (info_len > 200) { gchar * info = copy_value (point_to_start, end); if (info != NULL) { GlyrMemCache * result = DL_init(); result->data = info; result->size = info_len; result_list = g_list_prepend (result_list,result); } } } } return result_list; } ///////////////////////////////// MetaDataSource ainfo_lyricsreg_src = { .name = "lyricsreg", .key = 'r', .free_url = false, .type = GLYR_GET_ARTIST_BIO, .parser = ainfo_lyricsreg_parse, .get_url = ainfo_lyricsreg_url, .quality = 35, .speed = 50, .endmarker = NULL }; glyr-1.0.5/lib/intern/albumlist.c000066400000000000000000000030331227540770500167070ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../core.h" #include "../stringlib.h" #include "generic.h" //------------------------------------- static GList * factory (GlyrQuery * s, GList * list, gboolean * stop_me, GList ** result_list) { return generic_txt_finalizer (s,list,stop_me,GLYR_TYPE_ALBUMLIST,result_list); } //------------------------------------- /* PlugStruct */ MetaDataFetcher glyrFetcher_albumlist = { .name = "albumlist", .type = GLYR_GET_ALBUMLIST, .default_data_type = GLYR_TYPE_ALBUMLIST, .reqs = GLYR_REQUIRES_ARTIST, .full_data = TRUE, .init = NULL, .destroy = NULL, .finalize = factory }; glyr-1.0.5/lib/intern/albumlist/000077500000000000000000000000001227540770500165445ustar00rootroot00000000000000glyr-1.0.5/lib/intern/albumlist/musicbrainz.c000066400000000000000000000100521227540770500212340ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../stringlib.h" #include "../../core.h" static const gchar * albumlist_musicbrainz_url (GlyrQuery * sets) { return "http://musicbrainz.org/ws/1/release/?type=xml&artist=${artist}&limit=100"; } ///////////////////////////////////////////////////////////// //#define ALBUM_BEGIN "" #define ARTIST_ENDIN "" #define TITLE_BEGIN "" #define TITLE_ENDIN "" ///////////////////////////////////////////////////////////// static bool is_in_list (GList * list, const char * to_cmp) { bool rc = false; for (GList * elem = list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL) { if (g_ascii_strcasecmp (item->data,to_cmp) == 0) { rc = true; break; } } } return rc; } ///////////////////////////////////////////////////////////// static bool type_is_valid (const char * type) { bool result = FALSE; if (type == NULL) return result; static const char * valid_types[] = { "Single Official", "Album Official", NULL }; int check_idx = 0; while(valid_types[check_idx]) { if (g_strcmp0(valid_types[check_idx], type) == 0) { result = TRUE; break; } check_idx++; } return result; } ///////////////////////////////////////////////////////////// static GList * albumlist_musicbrainz_parse (cb_object * capo) { GList * result_list = NULL; gchar * node = capo->cache->data; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + 1, ALBUM_BEGIN) ) != NULL) { gchar * type = get_search_value (node, TYPE_BEGIN, TYPE_ENDIN); if (type_is_valid (type)) { gchar * artist = get_search_value (node,ARTIST_BEGIN, ARTIST_ENDIN); if (artist != NULL && levenshtein_strnormcmp (capo->s, capo->s->artist, artist) <= capo->s->fuzzyness) { gchar * name = get_search_value (node,TITLE_BEGIN,TITLE_ENDIN); if (name != NULL && is_in_list (result_list,name) == false) { GlyrMemCache * result = DL_init(); result->data = name; result->size = (result->data) ? strlen (result->data) : 0; result_list = g_list_prepend (result_list,result); } else { g_free (name); } } g_free (artist); } g_free (type); } return result_list; } ///////////////////////////////////////////////////////////// MetaDataSource albumlist_musicbrainz_src = { .name = "musicbrainz", .key = 'm', .free_url = false, .parser = albumlist_musicbrainz_parse, .get_url = albumlist_musicbrainz_url, .type = GLYR_GET_ALBUMLIST, .quality = 95, .speed = 95, .endmarker = NULL }; glyr-1.0.5/lib/intern/backdrops.c000066400000000000000000000027661227540770500166770ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../core.h" #include "generic.h" ///////////////////////////////// static GList * factory (GlyrQuery * s, GList * list, gboolean * stop_me, GList ** result_list) { return generic_img_finalizer (s,list,stop_me,GLYR_TYPE_BACKDROPS,result_list); } ///////////////////////////////// /* PlugStruct */ MetaDataFetcher glyrFetcher_backdrops = { .name = "backdrops", .type = GLYR_GET_BACKDROPS, .default_data_type = GLYR_TYPE_BACKDROPS, .reqs = GLYR_REQUIRES_ARTIST, .full_data = FALSE, .init = NULL, .destroy = NULL, .finalize = factory }; glyr-1.0.5/lib/intern/backdrops/000077500000000000000000000000001227540770500165205ustar00rootroot00000000000000glyr-1.0.5/lib/intern/backdrops/htbackdrops.c000066400000000000000000000077171227540770500212040ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../apikeys.h" #include "../../stringlib.h" #define HTBACKDROPS_URL "http://htbackdrops.org/api/%s" \ "/searchXML?keywords=${artist}&default_operator=and&" \ "fields=title&inc=mb_name&limit=%d&dmax_w=%d&dmin_h=%d" static const gchar * backdrops_htbackdrops_url (GlyrQuery * q) { gchar * result = g_strdup_printf (HTBACKDROPS_URL, API_KEY_HTBACK,q->number * 20, (q->img_max_size < 0) ? (gint) 1e10 : q->img_max_size, (q->img_min_size < 0) ? 0 : q->img_min_size); return result; } ///////////////////////////////// static gboolean check_size (GlyrQuery * query, const gchar * size_string) { gboolean result = FALSE; if (size_string != NULL && query != NULL) { /* "1024x1024" -> ["1024","1024"] */ gchar ** strv = g_strsplit (size_string,"x",0); if (strv && strv[0] && strv[1]) { gint width = strtol (strv[0],NULL,10); gint height = strtol (strv[1],NULL,10); gint img_size = (width + height) / 2; result = size_is_okay (img_size, query->img_min_size, query->img_max_size); } g_strfreev (strv); } return result; } ///////////////////////////////// #define NODE "" static GList * backdrops_htbackdrops_parse (cb_object * capo) { GList * result_list = NULL; gchar * img_list_start = strstr (capo->cache->data,""); if (img_list_start != NULL) { gchar * node = img_list_start; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node,NODE) ) ) { node += sizeof NODE; gchar * dimensions = get_search_value (node,"",""); if (check_size (capo->s,dimensions) == TRUE) { gchar * validate_artist = get_search_value (node,"",""); if (levenshtein_strnormcmp (capo->s,validate_artist,capo->s->artist) <= capo->s->fuzzyness) { gchar * id = get_search_value (node,"",""); if (id != NULL) { GlyrMemCache * result = DL_init(); result->data = g_strdup_printf ("http://htbackdrops.org/api/"API_KEY_HTBACK"/download/%s/fullsize",id); result->size = strlen (result->data); result_list = g_list_prepend (result_list,result); g_free (id); } } g_free (validate_artist); } g_free (dimensions); } } return result_list; } ///////////////////////////////// MetaDataSource backdrops_htbackdrops_src = { .name = "htbackdrops", .key = 'h', .parser = backdrops_htbackdrops_parse, .get_url = backdrops_htbackdrops_url, .type = GLYR_GET_BACKDROPS, .quality = 80, .speed = 80, .endmarker = NULL, .free_url = true }; glyr-1.0.5/lib/intern/cache/000077500000000000000000000000001227540770500156135ustar00rootroot00000000000000glyr-1.0.5/lib/intern/cache/db_provider.c000066400000000000000000000042541227540770500202630ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../cache.h" ///////////////////////////////// static GList * local_provider_parse (cb_object * capo) { GList * converter_list = NULL; if (capo->s && capo->s->local_db != NULL) { gint counter = 0; GlyrMemCache * head = glyr_db_lookup (capo->s->local_db,capo->s); while (head != NULL) { if (counter < capo->s->number) { converter_list = g_list_prepend (converter_list,head); head->cached = TRUE; head = head->next; counter++; } else { GlyrMemCache * to_delete = head; head = head->next; DL_free (to_delete); } } } return converter_list; } ///////////////////////////////// static const gchar * local_provider_url (GlyrQuery * sets) { return OFFLINE_PROVIDER; } ///////////////////////////////// MetaDataSource local_provider_src = { .name = "local", .key = 'l', .parser = local_provider_parse, .get_url = local_provider_url, .type = GLYR_GET_ANY, .quality = 4200, .speed = 4200, .endmarker = NULL, .free_url = false }; glyr-1.0.5/lib/intern/common/000077500000000000000000000000001227540770500160405ustar00rootroot00000000000000glyr-1.0.5/lib/intern/common/amazon.c000066400000000000000000000063341227540770500174770ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../apikeys.h" #include "../../core.h" #include "../../stringlib.h" #include "amazon.h" ///////////////////////////////// #define ACCESS_KEY API_KEY_AMAZON #define rg_markup "__RESPONSE_GROUP__" const gchar * generic_amazon_url (GlyrQuery * sets, const gchar * response_group) { const char * lang_link = NULL; if (sets->img_min_size <= 500 || sets->img_min_size) { if (!strcmp (sets->lang,"us") ) lang_link = "http://free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; else if (!strcmp (sets->lang,"ca") ) lang_link = "http://ca.free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; else if (!strcmp (sets->lang,"uk") ) lang_link = "http://co.uk.free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; else if (!strcmp (sets->lang,"fr") ) lang_link = "http://fr.free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; else if (!strcmp (sets->lang,"de") ) lang_link = "http://de.free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; else if (!strcmp (sets->lang,"jp") ) lang_link = "http://co.jp.free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; else lang_link = "http://free.apisigning.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId="ACCESS_KEY"&Operation=ItemSearch&SearchIndex=Music&ResponseGroup="rg_markup"&Keywords=${artist}+${album}\0"; } if (lang_link != NULL) { return strreplace (lang_link,rg_markup,response_group); } return NULL; } ///////////////////////////////// glyr-1.0.5/lib/intern/common/amazon.h000066400000000000000000000021331227540770500174750ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef GLYR_COMMON_AMAZON_H #define GLYR_COMMON_AMAZON_H #include "../../core.h" const gchar * generic_amazon_url (GlyrQuery * sets, const gchar * response_group); #endif glyr-1.0.5/lib/intern/common/google.c000066400000000000000000000110241227540770500174560ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "google.h" #include "../../stringlib.h" #include "../../core.h" ///////////////////////////////// /* Methods used by more than one provider go here */ const gchar * generic_google_url (GlyrQuery * sets, const gchar * searchterm) { const gchar * lang = NULL; if (!g_ascii_strncasecmp (sets->lang,"us",2) ) lang = "com" ; else if (!g_ascii_strncasecmp (sets->lang,"ca",2) ) lang = "ca" ; else if (!g_ascii_strncasecmp (sets->lang,"uk",2) ) lang = "co.uk"; else if (!g_ascii_strncasecmp (sets->lang,"fr",2) ) lang = "fr" ; else if (!g_ascii_strncasecmp (sets->lang,"de",2) ) lang = "de" ; else if (!g_ascii_strncasecmp (sets->lang,"jp",2) ) lang = "co.jp"; else lang = "com"; const gchar * back = NULL; if (sets->img_min_size == -1) { back = ""; } else if (sets->img_min_size < 75) { back = "&tbs=isz:i"; } else if (sets->img_min_size < 300) { back = "&tbs=isz:m"; } else if (sets->img_min_size < 450) { back = "&tbs=isz:lt,islt:qsvga"; } else if (sets->img_min_size < 550) { back = "&tbs=isz:lt,islt:vg/a"; } else if (sets->img_min_size < 700) { back = "&tbs=isz:lt,islt:svga"; } else /* High enough. */ { back = "&tbs=isz:lt,islt:xga"; } return g_strdup_printf ("http://www.google.%s/images?q=%s&safe=off%s%s",lang,searchterm, (back!=NULL) ? "" : "&", back); } ///////////////////////////////// #define IMG_SRC_START "&usg=" #define WIDTH_START "&w=" #define HEIGHT_START "&h=" #define MAX_NUM_BUF 16 static gint google_get_size_value (gchar * ref, gchar * name) { gint number = 0; gchar * start = g_strstr_len (ref,256,name); if (start != NULL) { start += strlen (name); gchar * end = strchr (start,' '); if (end != NULL) { gchar numbuf[MAX_NUM_BUF] = {}; gsize span = MIN (end - start,MAX_NUM_BUF-1); strncpy (numbuf,start,span); number = strtol (numbuf,NULL,10); } } return number; } ///////////////////////////////// static gboolean google_check_image_size (GlyrQuery * s, gchar * ref) { gboolean result = FALSE; gchar * img_src_after = strstr (ref,IMG_SRC_START); if (img_src_after != NULL) { gint width = google_get_size_value (img_src_after,WIDTH_START); gint height = google_get_size_value (img_src_after,HEIGHT_START); gint ratio = (width+height) /2; result = size_is_okay (ratio,s->img_min_size,s->img_max_size); } return result; } ///////////////////////////////// #define FIRST_RESULT ". **************************************************************/ #include "../../core.h" #include "../../stringlib.h" ////////////////////////////////// char * mbid_parse_data (GlyrMemCache * data, const char * lookup_entity, const char * find_entity, const char * compre_entity, GlyrQuery * qry) { char * key = g_strdup_printf ("<%s ", lookup_entity); size_t keylen = strlen (key); char * node = data->data; char * result = NULL; char * find_ent_start = g_strdup_printf ("<%s>", find_entity); char * find_ent_end = g_strdup_printf ("", find_entity); while ( (node = strstr (node + keylen, key) ) ) { char * name = get_search_value (node, find_ent_start, find_ent_end); if (name && levenshtein_strnormcmp (qry, name, compre_entity) <= qry->fuzzyness) { result = get_search_value (node, "id=\"", "\""); g_free (name); break; } g_free (name); } g_free (find_ent_start); g_free (find_ent_end); g_free (key); return result; } ////////////////////////////////// #define LOOKUP_QUERY "http://musicbrainz.org/ws/2/%s?query=%s:%s" ////////////////////////////////// char * mbid_lookup (const char * query, GLYR_DATA_TYPE type, GlyrQuery * qry) { char * result_mbid = NULL; if (query == NULL) return result_mbid; const char * lookup_entity = ""; const char * compre_entity = qry->artist; const char * find_entity = "name"; switch (type) { case GLYR_TYPE_TAG_ARTIST: lookup_entity = "artist"; compre_entity = qry->artist; break; case GLYR_TYPE_TAG_ALBUM: lookup_entity = "release"; compre_entity = qry->album; find_entity = "title"; break; case GLYR_TYPE_TAG_TITLE: lookup_entity = "work"; compre_entity = qry->title; break; default: lookup_entity = "artist"; compre_entity = qry->artist; find_entity = "name"; break; } char * lookup_url = g_strdup_printf (LOOKUP_QUERY, lookup_entity, lookup_entity, query); GlyrMemCache * parseable_data = download_single (lookup_url, qry, NULL); if (parseable_data != NULL) { result_mbid = mbid_parse_data (parseable_data, lookup_entity, find_entity, compre_entity, qry); DL_free (parseable_data); } g_free (lookup_url); return result_mbid; } ////////////////////////////////// glyr-1.0.5/lib/intern/common/mbid_lookup.h000066400000000000000000000022671227540770500205240ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" char * mbid_lookup (const char * query, GLYR_DATA_TYPE type, GlyrQuery * qry); char * mbid_parse_data (GlyrMemCache * data, const char * lookup_entity, const char * find_entity, const char * compre_entity, GlyrQuery * qry); glyr-1.0.5/lib/intern/common/musicbrainz.c000066400000000000000000000130561227540770500205370ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "musicbrainz.h" #include "../../stringlib.h" #include "../../core.h" ///////////////////////////////// /* 'please' is important. gcc won't compile without. */ gint please_what_type (GlyrQuery * s) { int result = -1; if (s->artist && !s->album && !s->title) result = GLYR_TYPE_TAG_ARTIST; else if (!s->artist && !s->album && s->title) result = GLYR_TYPE_TAG_TITLE; else if (!s->artist && s->album && !s->title) result = GLYR_TYPE_TAG_ALBUM; else if (s->artist && s->album && s->title) result = GLYR_TYPE_TAG_TITLE; else if (s->artist && !s->album && s->title) result = GLYR_TYPE_TAG_TITLE; else if (s->artist && s->album && !s->title) result = GLYR_TYPE_TAG_ALBUM; else result = -1; return result; } ///////////////////////////////// const gchar * generic_musicbrainz_url (GlyrQuery * sets) { const gchar * wrap_a = sets->artist ? "${artist}" : ""; const gchar * wrap_b = sets->album ? "${album}" : ""; const gchar * wrap_t = sets->title ? "${title}" : ""; switch (please_what_type (sets) ) { case GLYR_TYPE_TAG_TITLE : return g_strdup_printf ("http://musicbrainz.org/ws/1/track/?type=xml&title=%s&artist=%s&release=%s",wrap_t,wrap_a,wrap_b); case GLYR_TYPE_TAG_ALBUM : return g_strdup_printf ("http://musicbrainz.org/ws/1/release/?type=xml&title=%s&artist=%s",wrap_b,wrap_a); case GLYR_TYPE_TAG_ARTIST: return g_strdup_printf ("http://musicbrainz.org/ws/1/artist/?type=xml&name=%s",wrap_a); default: return NULL; } } ///////////////////////////////// #define ID_BEGIN "id=\"" const gchar * get_mbid_from_xml (GlyrQuery * s, GlyrMemCache * c, gint * offset) { if (c==NULL || s==NULL || offset==NULL) return NULL; const gchar * searchterm = NULL; const gchar * checkstring = NULL; const gchar * comparestr = NULL; switch (please_what_type (s) ) { case GLYR_TYPE_TAG_TITLE: checkstring = ""; searchterm = "<track "; comparestr = s->title; break; case GLYR_TYPE_TAG_ALBUM: checkstring = "<title>"; searchterm = "<release "; comparestr = s->album; break; case GLYR_TYPE_TAG_ARTIST: checkstring = "<name>"; searchterm = "<artist "; comparestr = s->artist; break; default: glyr_message (1,s,"Warning: (tags/musicbrainz.c) Unable to determine type.\n"); } const gchar * mbid = NULL; if (searchterm != NULL) { gchar * node = c->data + *offset; gchar * search_check = NULL; gsize nlen = (sizeof ID_BEGIN) - 1; gsize clen = strlen (checkstring); while (node && (node = strstr (node,searchterm) ) && mbid == NULL) { if (! (node = strstr (node,ID_BEGIN) ) ) break; if (! (search_check = strstr (node,checkstring) ) ) break; search_check += clen; gchar * to_compare = copy_value (search_check,strstr (search_check,"</") ); if (to_compare != NULL) { if (levenshtein_strnormcmp (s,to_compare,comparestr) <= s->fuzzyness) { mbid = (gchar*) copy_value (node+nlen,strchr (node+nlen,'"') ); } g_free (to_compare); } node += (sizeof ID_BEGIN) - 1; } *offset = node - c->data; } return mbid; } ///////////////////////////////// /* Returns only a parseable memcache */ GlyrMemCache * generic_musicbrainz_parse (cb_object * capo, gint * last_mbid, const gchar * include) { gsize offset = 0; const gchar * mbid = NULL; GlyrMemCache * info = NULL; while (offset < capo->cache->size && info==NULL && (mbid = get_mbid_from_xml (capo->s,capo->cache,last_mbid) ) ) { if (mbid != NULL) { const gchar * type = NULL; switch (please_what_type (capo->s) ) { case GLYR_TYPE_TAG_TITLE: type = "track"; break; case GLYR_TYPE_TAG_ALBUM: type = "release"; break; case GLYR_TYPE_TAG_ARTIST: type = "artist"; break; } gchar * info_page_url = g_strdup_printf ("http://musicbrainz.org/ws/1/%s/%s?type=xml&inc=%s",type,mbid,include); if (info_page_url) { info = download_single (info_page_url,capo->s,NULL); g_free (info_page_url); } g_free ( (gchar*) mbid); } } return info; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/common/musicbrainz.h����������������������������������������������������������0000664�0000000�0000000�00000002453�12275407705�0020543�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #ifndef GLYR_COMMON_MUSICBRAINZ_H #define GLYR_COMMON_MUSICBRAINZ_H #include "../../core.h" gint please_what_type (GlyrQuery * s); const gchar * generic_musicbrainz_url (GlyrQuery * sets); const gchar * get_mbid_from_xml (GlyrQuery * s, GlyrMemCache * c, gint * offset); GlyrMemCache * generic_musicbrainz_parse (cb_object * capo, gint * last_mbid, const gchar * include); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/common/picsearch.c������������������������������������������������������������0000664�0000000�0000000�00000007402�12275407705�0020150�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #include "picsearch.h" const gchar * generic_picsearch_url (GlyrQuery * s, const char * fmt) { /* picsearch offers a nice way to set img_min / img_max */ gchar * base_url = "http://www.picsearch.com/index.cgi?q=%s&face=both&orientation=square&size=%dt%d"; gint img_min_size = s->img_min_size; if (img_min_size == -1) { img_min_size = 0; } gint img_max_size = s->img_max_size; if (img_max_size == -1) { img_max_size = INT_MAX; } return g_strdup_printf (base_url, fmt, img_min_size, img_max_size); } ///////////////////////////////// #define IMG_HOOK "div class=\"thumbnailTop\"" #define IMG_HOOK_BEGIN "<a rel=\"nofollow\" href=\"" #define IMG_HOOK_ENDIN "\"><img src=\"" static GlyrMemCache * parse_details_page (GlyrMemCache * to_parse) { GlyrMemCache * result = NULL; if (to_parse != NULL) { char * start = strstr (to_parse->data,IMG_HOOK); if (start != NULL) { char * img_url = get_search_value (start,IMG_HOOK_BEGIN,IMG_HOOK_ENDIN); if (img_url != NULL) { result = DL_init(); result->data = img_url; result->size = strlen (img_url); result->dsrc = g_strdup (to_parse->dsrc); } } } return result; } ///////////////////////////////// #define NODE "<div class=\"imgContainer\">" #define NODE_NEEDS_TO_BEGIN "/imageDetail.cgi" GList * generic_picsearch_parse (cb_object * capo) { GList * result_list = NULL; gchar * node = capo->cache->data; gint nodelen = (sizeof NODE) - 1; node = strstr (node,"<div id=\"results_table\">"); int items = 0, tries = 0; const int MAX_TRIES = capo->s->number * 4; while (continue_search (items,capo->s) && (node = strstr (node, "<a href=\"") ) && tries++ < MAX_TRIES) { node += nodelen; gchar * details_url = get_search_value (node,"<a href=\"","\" "); if (details_url != NULL && strncmp (details_url,NODE_NEEDS_TO_BEGIN,sizeof (NODE_NEEDS_TO_BEGIN)-1) == 0) { gchar * full_url = g_strdup_printf ("www.picsearch.com%s",details_url); if (full_url != NULL) { GlyrMemCache * to_parse = download_single (full_url,capo->s,NULL); if (to_parse != NULL) { GlyrMemCache * result = parse_details_page (to_parse); if (result != NULL) { result_list = g_list_prepend (result_list,result); items++; } DL_free (to_parse); } g_free (full_url); } g_free (details_url); } } return result_list; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/common/picsearch.h������������������������������������������������������������0000664�0000000�0000000�00000002212�12275407705�0020147�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #ifndef GLYR_COMMON_PICSEARCH_H #define GLYR_COMMON_PICSEARCH_H #include "../../core.h" const gchar * generic_picsearch_url (GlyrQuery * s, const char * fmt); GList * generic_picsearch_parse (cb_object * capo); #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover.c�����������������������������������������������������������������������0000664�0000000�0000000�00000003153�12275407705�0016034�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../core.h" #include "../stringlib.h" #include "generic.h" ///////////////////////////////// static GList * factory (GlyrQuery * s, GList * list, gboolean * stop_me, GList ** result_list) { return generic_img_finalizer (s,list,stop_me,GLYR_TYPE_COVERART,result_list); } ///////////////////////////////// /* PlugStruct */ MetaDataFetcher glyrFetcher_cover = { .name = "cover", .type = GLYR_GET_COVERART, .default_data_type = GLYR_TYPE_COVERART, .reqs = GLYR_REQUIRES_ARTIST | GLYR_REQUIRES_ALBUM, .full_data = FALSE, .init = NULL, .destroy = NULL, .finalize = factory, .default_parallel = 3 }; ///////////////////////////////// ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/������������������������������������������������������������������������0000775�0000000�0000000�00000000000�12275407705�0015666�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/albumart.c��������������������������������������������������������������0000664�0000000�0000000�00000006777�12275407705�0017662�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" static const gchar * cover_albumart_url (GlyrQuery * sets) { gint i = sets->img_min_size; gint e = sets->img_max_size; if ( (e >= 50 || e == -1) && (i == -1 || i < 450) ) { return "http://www.albumart.org/index.php?searchkey=${artist}&itempage=1&newsearch=1&searchindex=Music"; } return NULL; } ///////////////////////////////// #define NODE_START "<div id=\"main\">" #define NODE_NEXT "<li><div style=\"" #define AMZ "http://ecx.images-amazon.com/images/" #define IMG_FORMAT ".jpg" static GList * cover_albumart_parse (cb_object * capo) { GList * result_list = NULL; gchar * node = strstr (capo->cache->data,NODE_START); if (node != NULL) { /* Decide what size we want */ gsize size_it = 2; if (capo->s->img_max_size < 450 && capo->s->img_max_size != -1 && capo->s->img_min_size < 160) { size_it = 1; } /* Go through all nodes */ while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + (sizeof NODE_NEXT) - 1,NODE_NEXT) ) ) { gchar * img_tag = node; gchar * img_end = NULL; gchar * album_name = get_search_value (node,"title=\"","\""); if (levenshtein_strnormcmp (capo->s,album_name,capo->s->album) <= capo->s->fuzzyness) { for (gsize it = 0; it < size_it; it++, img_tag += (sizeof AMZ) - 1) { if ( (img_tag = strstr (img_tag,AMZ) ) == NULL) { break; } } if ( (img_end = strstr (img_tag,IMG_FORMAT) ) != NULL) { gchar * img_url = copy_value (img_tag,img_end); if (img_url != NULL) { GlyrMemCache * result = DL_init(); result->data = g_strdup_printf (AMZ"%s"IMG_FORMAT, img_url); result->size = strlen (result->data); result_list = g_list_prepend (result_list,result); g_free (img_url); } } } g_free (album_name); } } return result_list; } ///////////////////////////////// MetaDataSource cover_albumart_src = { .name = "albumart", .key = 'b', .parser = cover_albumart_parse, .get_url = cover_albumart_url, .type = GLYR_GET_COVERART, .quality = 80, .speed = 65, .free_url = false }; �glyr-1.0.5/lib/intern/cover/amazon.c����������������������������������������������������������������0000664�0000000�0000000�00000007745�12275407705�0017334�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #include "../common/amazon.h" // Example snippet of what we parse: /*** <SmallImage> <URL> http://ecx.images-amazon.com/images/I/51rnlRwtsiL._SL75_.jpg </URL> <Height Units="pixels">75</Height> <Width Units="pixels">75</Width> </SmallImage> <MediumImage> <URL> http://ecx.images-amazon.com/images/I/51rnlRwtsiL._SL160_.jpg </URL> <Height Units="pixels">160</Height> <Width Units="pixels">160</Width> </MediumImage> <LargeImage> <URL> http://ecx.images-amazon.com/images/I/51rnlRwtsiL.jpg </URL> <Height Units="pixels">455</Height> <Width Units="pixels">455</Width> </LargeImage> ***/ // A short note: // Since some time amazon does not allow anonymous acces to their webservices. // So you have to register an (free) account and you'll get an Accesskey and a Secretkey, // sadly amazon does not allow you to publish the secretkey to the public, // therefore I had to use freeapisign.com to access the webservices, the bad thing is: // it is limited to 30K requests per month. If you have an own account: replace the Acceskey here, // as an fallback there is the albumart and coverhunt plugin which implement a search on amazon (on serverside) ///////////////////////////////// static const gchar * cover_amazon_url (GlyrQuery * sets) { return generic_amazon_url (sets,"Images"); } ///////////////////////////////// #define END_OF_URL "</URL>" #define C_MAX(X) (capo->s->img_max_size < X && capo->s->img_max_size != -1) #define C_MIN(X) (capo->s->img_min_size >= X && capo->s->img_min_size != -1) static GList * cover_amazon_parse (cb_object *capo) { const gchar *tag_ssize = (capo->s->img_max_size == -1 && capo->s->img_min_size == -1) ? "<LargeImage>" : (C_MAX ( 30) && C_MIN (-1) ) ? "<SwatchImage>" : (C_MAX ( 70) && C_MIN (30) ) ? "<SmallImage>" : (C_MAX (150) && C_MIN (70) ) ? "<MediumImage>" : "<LargeImage>" ; GList * result_list = NULL; gchar * find = capo->cache->data; while (continue_search (g_list_length (result_list),capo->s) && (find = strstr (find + strlen (tag_ssize), tag_ssize) ) != NULL) { /* Next two XML tags not relevant */ nextTag (find); nextTag (find); gchar * endTag = NULL; if ( (endTag = strstr (find, END_OF_URL) ) != NULL) { gchar * result_url = copy_value (find,endTag); if (result_url != NULL) { GlyrMemCache * result = DL_init(); result->data = result_url; result->size = endTag - find; result_list = g_list_prepend (result_list,result); } } } return result_list; } ///////////////////////////////// MetaDataSource cover_amazon_src = { .name = "amazon", .key = 'a', .parser = cover_amazon_parse, .get_url = cover_amazon_url, .type = GLYR_GET_COVERART, .quality = 90, .speed = 85, .endmarker = NULL, .free_url = true, .lang_aware = true }; ���������������������������glyr-1.0.5/lib/intern/cover/coverartarchive.c�������������������������������������������������������0000664�0000000�0000000�00000006306�12275407705�0021226�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../../core.h" #include "../common/mbid_lookup.h" ////////////////////////////////////////////////// static const char * cover_coverartarchive_url (GlyrQuery * qry) { /* Return a search for the mbid, later we'll search for the cover */ return "http://musicbrainz.org/ws/2/release?query=artist:${artist}%20AND%20release:${album}"; } ////////////////////////////////////////////////// #define IMAGE_NODE "\"image\":\"" /* This should work, but apparently there is no real data yet there... */ static GList * parse_archive_json (GlyrMemCache * input, GlyrQuery * qry) { GList * result_list = NULL; char * node = input->data; while ( (node = strstr (node + sizeof (IMAGE_NODE), IMAGE_NODE) ) ) { char * url = copy_value (node, strstr (node + sizeof (IMAGE_NODE), "\"") ); if (url != NULL) { GlyrMemCache * item = DL_init(); item->data = url; item->size = strlen (url); item->dsrc = g_strdup (input->dsrc); result_list = g_list_prepend (result_list, item); } } return result_list; } ////////////////////////////////////////////////// #define API_ROOT "http://coverartarchive.org/release/%s/" ////////////////////////////////////////////////// static GList * cover_coverartarchive_parse (cb_object * capo) { GList *result_list = NULL; char * mbid = mbid_parse_data (capo->cache, "release", "title", capo->s->album, capo->s); if (mbid != NULL) { char * full_url = g_strdup_printf (API_ROOT, mbid); if (full_url != NULL) { GlyrMemCache * json_data = download_single (full_url, capo->s, NULL); if (json_data != NULL) { result_list = parse_archive_json (json_data, capo->s); DL_free (json_data); } g_free (full_url); } } return result_list; } ////////////////////////////////////////////////// MetaDataSource cover_coverartarchive_src = { .name = "coverartarchive", .key = 'z', .parser = cover_coverartarchive_parse, .get_url = cover_coverartarchive_url, .type = GLYR_GET_COVERART, .quality = 90, .speed = 80, .endmarker = NULL, .free_url = false }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/coverhunt.c�������������������������������������������������������������0000664�0000000�0000000�00000012242�12275407705�0020050�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../../core.h" /* * Coverhunt seems to have some load problems at time of writing... */ static const gchar * cover_coverhunt_url (GlyrQuery * sets) { if (sets->img_min_size <= 500 || sets->img_min_size == -1) { return "http://www.coverhunt.com/index.php?query=${artist}+${album}&action=Find+my+CD+Covers"; } return NULL; } static gboolean check_size (const char * art_root, const char *hw, cb_object * capo) { gchar * begin = strstr (art_root,hw); if (begin != NULL) { gchar * end = strchr (begin,' '); gchar * buf = copy_value (begin+strlen (hw),end); if (buf != NULL) { gint atoid = strtol (buf,NULL,10); g_free (buf); if ( (atoid >= capo->s->img_min_size || capo->s->img_min_size == -1) && (atoid <= capo->s->img_max_size || capo->s->img_max_size == -1) ) return TRUE; } } return FALSE; } #define SEARCH_RESULT_BEGIN "<table><tr><td" #define IMG_START "<img src=\"" #define NODE_BEGIN "<a href=\"/go/" /* Take the first link we find. * coverhunt sadly offers no way to check if the * image is really related to the query we're searching for */ static GList * cover_coverhunt_parse (cb_object *capo) { GList * result_list = NULL; /* navigate to start of search results */ gchar * table_start; if ( (table_start = strstr (capo->cache->data,SEARCH_RESULT_BEGIN) ) == NULL) { /* Whoops, nothing to see here */ return NULL; } while (continue_search (g_list_length (result_list),capo->s) && (table_start = strstr (table_start + 1,NODE_BEGIN) ) ) { gchar * table_end = NULL; if ( (table_end = strstr (table_start,"\">") ) != NULL) { gchar * go_url = copy_value (table_start + strlen (NODE_BEGIN),table_end); if (go_url) { gchar * real_url = g_strdup_printf ("http://www.coverhunt.com/go/%s",go_url); if (real_url != NULL) { GlyrMemCache * search_buf = download_single (real_url,capo->s,"<div id=\"right\">"); if (search_buf != NULL) { gchar * artwork = strstr (search_buf->data, "<div class=\"artwork\">"); if (artwork != NULL) { if (check_size (artwork,"height=",capo) && check_size (artwork,"width=",capo) ) { gchar * img_start = strstr (artwork,IMG_START); if (img_start != NULL) { img_start += (sizeof IMG_START) - 1; gchar * img_end = strstr (img_start,"\" "); if (img_end != NULL) { gchar * url = copy_value (img_start,img_end); if (url != NULL) { GlyrMemCache * shell = DL_init(); shell->data = url; shell->size = img_end - img_start; shell->dsrc = g_strdup (real_url); result_list = g_list_prepend (result_list,shell); } } } } } DL_free (search_buf); } g_free (real_url); } g_free (go_url); } } } return result_list; } /* Queued last, as long coverhunt is down */ MetaDataSource cover_coverhunt_src = { .name = "coverhunt", .key = 'c', .parser = cover_coverhunt_parse, .get_url = cover_coverhunt_url, .type = GLYR_GET_COVERART, .endmarker = "<div id=\"footer\">", .quality = 0, /* ex. 70 */ .speed = 0, /* ex. 40 */ .free_url = false }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/discogs.c���������������������������������������������������������������0000664�0000000�0000000�00000011420�12275407705�0017463�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define API_ENTRY "http://api.discogs.com/database/search?type=release&q=${artist}" ///////////////////////////////// /* * # Example Snippet (for type = release) * { # Start of item * "style": ["Grunge"], * "thumb": "http://api.discogs.com/image/R-90-2845667-1303704896.jpeg", * "title": "Nirvana - Nirvana", * "country": "Russia", * "format": ["CD"], * "uri": "/Nirvana-Nirvana/release/2845667", * "label": "\u0414\u043e\u043c\u0430\u0448\u043d\u044f\u044f \u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f", * "catno": "none", * "year": "2001", * "genre": ["Rock"], * "resource_url": "http://api.discogs.com/releases/2845667", * "type": "release", * "id": 2845667 * }, # End of item * { * ..more data.. * } */ /* Note: "thumb": null is ignored! */ #define TITLE_SUBNODE "\"title\": \"" #define THUMB_SUBDNOE "\"thumb\": \"" #define FOLLR_SUBNODE "\"uri\": \"" #define NODE THUMB_SUBDNOE #define ENDOF_SUBNODE "\"," ///////////////////////////////////////////////////// static bool check_artist_album (GlyrQuery * q, const char * artist_album) { bool rc = false; char ** split = g_strsplit (artist_album," - ",2); if (split && split[0] && split[1]) { rc = levenshtein_strnormcmp (q,q->artist,split[0]) <= q->fuzzyness && levenshtein_strnormcmp (q,q->album, split[1]) <= q->fuzzyness; } g_strfreev (split); return rc; } ///////////////////////////////////////////////////// static GlyrMemCache * transform_url (cb_object * s, const char * url) { GlyrMemCache * rc = NULL; size_t rc_size = strlen (url); char * rc_url = g_strdup (url); if (rc_url != NULL) { char * slash = strrchr (rc_url,'/'); if (slash != NULL) { char * sp = strchr (slash,'-'); if (sp != NULL) { char * ep = strchr (sp + 1, '-'); if(ep != NULL) { size_t rest_len = rc_size - (ep - rc_url) + 1; memmove (sp,ep,rest_len); rc = DL_init(); rc->data = (char*) rc_url; rc->size = strlen (url); rc->dsrc = g_strdup (s->url); } } } } return rc; } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// static const char * cover_discogs_url (GlyrQuery * q) { return API_ENTRY; } ///////////////////////////////////////////////////// static GList * cover_discogs_parse (cb_object * capo) { GList * result_list = NULL; /* Jump to the very first node 'directly' */ gchar * node = capo->cache->data; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + (sizeof NODE) - 1,NODE) ) != NULL) { char * artist_album = get_search_value (node,TITLE_SUBNODE,ENDOF_SUBNODE); if (artist_album && check_artist_album (capo->s,artist_album) ) { char * thumb_url = get_search_value (node,THUMB_SUBDNOE,ENDOF_SUBNODE); if (thumb_url) { GlyrMemCache * p = transform_url (capo,thumb_url); if (p != NULL) { result_list = g_list_prepend (result_list,p); } g_free (thumb_url); } } g_free (artist_album); } return result_list; } ///////////////////////////////// MetaDataSource cover_discogs_src = { .name = "discogs", .key = 'd', .parser = cover_discogs_parse, .get_url = cover_discogs_url, .type = GLYR_GET_COVERART, .quality = 60, .speed = 70, .endmarker = NULL, .free_url = false }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/google.c����������������������������������������������������������������0000664�0000000�0000000�00000003417�12275407705�0017313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../common/google.h" ///////////////////////////////// static const gchar * cover_google_url (GlyrQuery * s) { const gchar * result = NULL; gchar * searchterm = g_strdup ("${artist}+${album}+album"); if (searchterm != NULL) { result = generic_google_url (s,searchterm); g_free (searchterm); } return result; } ///////////////////////////////// static GList * cover_google_parse (cb_object * capo) { return generic_google_parse (capo); } ///////////////////////////////// MetaDataSource cover_google_src = { .name = "google", .key = 'g', .parser = cover_google_parse, .get_url = cover_google_url, .type = GLYR_GET_COVERART, .quality = 10, .speed = 80, .endmarker = NULL, .free_url = true, .lang_aware = true }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/jamendo.c���������������������������������������������������������������0000664�0000000�0000000�00000007702�12275407705�0017455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * Jamendo provider written by: * Christoph Piechula (christoph@nullcat.de) * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../../core.h" #define RESULT_URL "http://www.jamendo.com/get/album/id/album/artworkurl/redirect/%s/?artwork_size=%d" #define SOURCE_URL "http://api.jamendo.com/get2/id+name+artist_name/album/plain/?order=searchweight_desc&n=100&searchquery=${album}" static int get_cover_size (GlyrQuery * query); static bool check_values (GlyrQuery * query, char * artist, char * album); ///////////////////////////////// static const char * cover_jamendo_url (GlyrQuery * sets) { return SOURCE_URL; } ///////////////////////////////// void do_line_split (char ** p_arr, char * line) { g_return_if_fail (p_arr && line); char * hop = line; *p_arr = line; while ( (hop = strchr (hop,'\t') ) != NULL) { p_arr++; *hop = 0; (*p_arr) = ++hop; } } ///////////////////////////////// static GList * cover_jamendo_parse (cb_object *capo) { // A nice parser with zero memory overhead.. GList * result_list = NULL; gchar * line = capo->cache->data; while (continue_search (g_list_length (result_list),capo->s) ) { char * line_end; if ( (line_end = strchr (line,'\n') ) != NULL) { *line_end = 0; char * line_split[3] = {0,0,0}; do_line_split (line_split,line); if (check_values (capo->s,line_split[2],line_split[1]) ) { char * url = g_strdup_printf (RESULT_URL,line_split[0],get_cover_size (capo->s) ); GlyrMemCache * result = DL_init(); result->data = url; result->size = strlen (url); result_list = g_list_prepend (result_list,result); } line = ++line_end; } else { break; } } return result_list; } ///////////////////////////////// static bool check_values (GlyrQuery * query, char * artist, char * album) { if (levenshtein_strnormcmp (query, query->artist, artist) <= query->fuzzyness && levenshtein_strnormcmp (query, query->album,album) <= query->fuzzyness) { return true; } return false; } ///////////////////////////////// static int get_cover_size (GlyrQuery * query) { int cover_size[] = {50,50,100,200,300,400,600,INT_MAX}; int array_len = (sizeof (cover_size) /sizeof (int) ); if (query->img_max_size == -1) { return 400; } else { for (int i=1; i<array_len; i++) { if (query->img_max_size <= cover_size[i]) { return cover_size[i-1]; } } } return 400; } ///////////////////////////////// MetaDataSource cover_jamendo_src = { .name = "jamendo", .key = 'j', .parser = cover_jamendo_parse, .get_url = cover_jamendo_url, .type = GLYR_GET_COVERART, .quality = 90, .speed = 75, .endmarker = NULL, .free_url = false }; ��������������������������������������������������������������glyr-1.0.5/lib/intern/cover/lastfm.c����������������������������������������������������������������0000664�0000000�0000000�00000007502�12275407705�0017324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../../core.h" ///////////////////////////////// static const char * cover_lastfm_url (GlyrQuery * sets) { return "http://ws.audioscrobbler.com/2.0/?method=album.search&autocorrect=1&album=${artist}+${album}&api_key="API_KEY_LASTFM; } ///////////////////////////////// #define ALBUM_NODE "<album>" #define BAD_DEFAULT_IMAGE "http://cdn.last.fm/flatness/catalogue/noimage/2/default_album_medium.png" static GList * cover_lastfm_parse (cb_object *capo) { /* Handle size requirements (Default to large) */ const gchar * tag_ssize = NULL ; const gchar * tag_esize = "</image>"; /* find desired size */ if ( size_is_okay (300,capo->s->img_min_size,capo->s->img_max_size) ) tag_ssize = "<image size=\"extralarge\">"; else if ( size_is_okay (125,capo->s->img_min_size,capo->s->img_max_size) ) tag_ssize = "<image size=\"large\">"; else if ( size_is_okay (64, capo->s->img_min_size,capo->s->img_max_size) ) tag_ssize = "<image size=\"middle\">"; else if ( size_is_okay (34, capo->s->img_min_size,capo->s->img_max_size) ) tag_ssize = "<image size=\"small\">"; else if ( true || false ) tag_ssize = "<image size=\"extralarge\">"; /* The result (perhaps) */ GList * result_list = NULL; gchar * find = capo->cache->data; while (continue_search (g_list_length (result_list),capo->s) && (find = strstr (find + sizeof(ALBUM_NODE), ALBUM_NODE) ) != NULL) { gchar * artist = get_search_value (find, "<artist>", "</artist>"); gchar * album = get_search_value (find, "<name>", "</name>"); if (levenshtein_strnormcmp (capo->s, artist, capo->s->artist) <= capo->s->fuzzyness && levenshtein_strnormcmp (capo->s, album, capo->s->album) <= capo->s->fuzzyness) { gchar * img_start = strstr(find, tag_ssize); if (img_start != NULL) { gchar * url = get_search_value (find, (gchar*) tag_ssize, (gchar*) tag_esize); if (url != NULL) { if (strcmp (url,BAD_DEFAULT_IMAGE) != 0) { GlyrMemCache * result = DL_init(); result->data = url; result->size = strlen (url); result_list = g_list_prepend (result_list,result); } else { g_free (url); } } } } g_free (artist); g_free (album); } return result_list; } ///////////////////////////////// MetaDataSource cover_lastfm_src = { .name = "lastfm", .key = 'l', .parser = cover_lastfm_parse, .get_url = cover_lastfm_url, .type = GLYR_GET_COVERART, .quality = 90, .speed = 75, .endmarker = NULL, .free_url = false }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/cover/lyricswiki.c������������������������������������������������������������0000664�0000000�0000000�00000010704�12275407705�0020225�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../../core.h" const gchar * cover_lyricswiki_url (GlyrQuery * sets) { const gchar * url = NULL; if (sets->img_min_size < 650) { url = "http://lyrics.wikia.com/api.php?format=xml&action=query&list=allimages&aiprefix=${artist}"; } return url; } ///////////////////////////////// static gboolean check_file_format (GlyrQuery * query, gchar * filename) { gboolean result = FALSE; gsize length = strlen (filename); gsize offset = 0; gchar *token = NULL; gchar ** token_list = g_strsplit (query->allowed_formats,GLYR_DEFAULT_FROM_ARGUMENT_DELIM,0); while ( (token = token_list[offset]) != NULL) { if (g_str_has_suffix (filename,token) == TRUE) { result = TRUE; gsize format_pos = length - strlen (token); filename[format_pos] = '\0'; if (format_pos != 0 && filename[format_pos-1] == '.') { filename[format_pos-1] = '\0'; } break; } offset++; } g_strfreev (token_list); return result; } /** -- Example snippet <img name="Axxis_-_Access_All_Areas.jpg" timestamp="2010-08-03T17:05:20Z" url="http://images.wikia.com/lyricwiki/images/f/f9/Axxis_-_Access_All_Areas.jpg" descriptionurl="http://lyrics.wikia.com/File:Axxis_-_Access_All_Areas.jpg" /> **/ #define IMG_TAG "_-_" #define END_TAG "\" timestamp=\"" #define URL_MARKER "url=\"" #define URL_END "\" descriptionurl=" #define NEXT_NAME "<img name=\"" GList * cover_lyricswiki_parse (cb_object * capo) { gchar * find = capo->cache->data; gchar * endTag = NULL; GList * result_list = NULL; gchar * escaped_album_name = strreplace (capo->s->album," ","_"); if (escaped_album_name != NULL) { /* Go through all names and compare them with Levenshtein */ while (continue_search (g_list_length (result_list),capo->s) && (find = strstr (find+ (sizeof IMG_TAG) - 1,IMG_TAG) ) != NULL) { /* Find end & start of the name */ find += (sizeof IMG_TAG) - 1; endTag = strstr (find,END_TAG); if (endTag == NULL || endTag <= find) continue; /* Copy the name of the current album */ gchar * name = copy_value (find,endTag); if (name != NULL) { if (check_file_format (capo->s,name) && levenshtein_strnormcmp (capo->s,escaped_album_name,name) <= capo->s->fuzzyness) { gchar * url = get_search_value (endTag, URL_MARKER, URL_END); if (url != NULL) { GlyrMemCache * result = DL_init(); result->data = url; result->size = strlen (url); result_list = g_list_prepend (result_list,result); } } /* Get next img tag */ find = strstr (endTag,NEXT_NAME); g_free (name); /* Whoops, right into nonexistence.. */ if (find == NULL) break; } } g_free (escaped_album_name); } return result_list; } ///////////////////////////////// MetaDataSource cover_lyricswiki_src = { .name = "lyricswiki", .key = 'w', .parser = cover_lyricswiki_parse, .get_url = cover_lyricswiki_url, .type = GLYR_GET_COVERART, .quality = 75, .speed = 85, .endmarker = NULL, .free_url = false }; ������������������������������������������������������������glyr-1.0.5/lib/intern/cover/musicbrainz.c�����������������������������������������������������������0000664�0000000�0000000�00000007410�12275407705�0020362�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../stringlib.h" #include "../../core.h" ///////////////////////////////// static const char * cover_musicbrainz_url (GlyrQuery * q) { return "http://musicbrainz.org/ws/2/release?query=${album}&limit=10&offset=0"; } ///////////////////////////////// #define COVERART "<div class=\"cover-art\">" #define AMZ_URL_START "\"http://ecx.images-amazon.com/" /* * This is silly overall, * but coverartarchive.org does not seem to work fully yet. */ static GlyrMemCache * parse_web_page (GlyrMemCache * page) { GlyrMemCache * retv = NULL; if (page && page->data) { char * begin = strstr (page->data,COVERART); if (begin != NULL) { char * amz_url = strstr (begin,AMZ_URL_START); if (amz_url != NULL) { char * img_url = get_search_value (amz_url,"\"","\""); if (img_url != NULL) { retv = DL_init(); retv->dsrc = g_strdup (page->dsrc); retv->data = img_url; retv->size = strlen (img_url); } } } DL_free (page); } return retv; } ///////////////////////////////// #define NODE "<release " #define DL_URL "http://musicbrainz.org/release/%s" ///////////////////////////////// static GList * cover_musicbrainz_parse (cb_object * capo) { GList * result_list = NULL; char * node = capo->cache->data; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + 1,NODE) ) ) { char * album = get_search_value (node,"<title>",""); char * artist = get_search_value (node,"" ,"" ); if (levenshtein_strnormcmp (capo->s,artist,capo->s->artist) <= capo->s->fuzzyness && levenshtein_strnormcmp (capo->s,album ,capo->s->album ) <= capo->s->fuzzyness) { char * ID = get_search_value (node,"id=\"","\" "); if (ID != NULL) { char * url = g_strdup_printf (DL_URL,ID); if (url != NULL) { GlyrMemCache * item = parse_web_page (download_single (url,capo->s,NULL) ); if (item != NULL) { result_list = g_list_prepend (result_list,item); } } g_free (url); } g_free (ID); } g_free (artist); g_free (album); } return result_list; } ///////////////////////////////// MetaDataSource cover_musicbrainz_src = { .name = "musicbrainz", .key = 'z', .parser = cover_musicbrainz_parse, .get_url = cover_musicbrainz_url, .type = GLYR_GET_COVERART, .quality = 85, .speed = 70, .endmarker = NULL, .free_url = false }; glyr-1.0.5/lib/intern/cover/picsearch.c000066400000000000000000000031741227540770500200000ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #include "../common/picsearch.h" ///////////////////////////////// static const gchar * cover_picsearch_url (GlyrQuery * s) { return generic_picsearch_url (s,"${artist}+${album}+coverart"); } ///////////////////////////////// static GList * cover_picsearch_parse (cb_object * capo) { return generic_picsearch_parse (capo); } ///////////////////////////////// MetaDataSource cover_picsearch_src = { .name = "picsearch", .key = 'p', .parser = cover_picsearch_parse, .get_url = cover_picsearch_url, .type = GLYR_GET_COVERART, .quality = 50, .speed = 60, .endmarker = NULL, .free_url = true }; glyr-1.0.5/lib/intern/cover/rhapsody.c000066400000000000000000000114251227540770500176660ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" ///////////////////////////////// static gchar * translate_string (gchar * string) { gchar * result = NULL; if (string != NULL) { gchar * beautiful = beautify_string (string); if (beautiful != NULL) { gchar * downcase = g_utf8_strdown (beautiful,-1); if (downcase != NULL) { result = translate_umlauts (downcase); g_free (downcase); } g_free (beautiful); } } return result; } ///////////////////////////////// static const gchar * cover_rhapsody_url (GlyrQuery * query) { gchar * result = NULL; gchar * corrected_artist = translate_string (query->artist); gchar * corrected_album = translate_string (query->album); if (corrected_artist && corrected_album) { result = g_strdup_printf ("http://feeds.rhapsody.com/%s/%s/data.xml",corrected_artist,corrected_album); } g_free (corrected_artist); g_free (corrected_album); return result; } ///////////////////////////////// static gboolean check_size (GlyrQuery * s, gchar * ref) { gboolean result = FALSE; if (ref != NULL) { gchar * width_str = get_search_value (ref,"width=\"","\""); gchar * height_str = get_search_value (ref,"height=\"","\""); if (width_str && height_str) { gint width = strtol (width_str, NULL,10); gint height = strtol (height_str,NULL,10); result = size_is_okay ( (width+height) /2,s->img_min_size,s->img_max_size); } g_free (width_str); g_free (height_str); } return result; } ///////////////////////////////// #define DELIM_BEG "" #define DELIM_END "" #define NODE "cache->data,DELIM_BEG); gchar * delim_end = strstr (capo->cache->data,DELIM_END); GlyrMemCache * special_size = NULL; if (delim_beg && delim_end) { gchar * node = delim_beg; gsize nd_len = (sizeof NODE) - 1; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + nd_len, NODE) ) && node < delim_end) { node += nd_len; if (check_size (capo->s,node) == TRUE) { gchar * url = get_search_value (node,"src=\"","\""); if (url != NULL) { GlyrMemCache * result = DL_init(); result->data = url; result->size = strlen (url); result_list = g_list_prepend (result_list,result); /* A very cool hack. Thanks Bansheeproject! */ if (strstr (result->data,HACK_SIZE) != NULL) { special_size = result; } } } } /* Awesome hack continues.. */ if (special_size != NULL) { /* Note: Prepend the large size at begin: * If only one item requested it will just * be thrown away (the small size) */ GlyrMemCache * result = DL_init(); result->data = strreplace (special_size->data,HACK_SIZE,HIGH_SIZE); result->size = strlen (result->data); result_list = g_list_prepend (result_list,result); } } return result_list; } ///////////////////////////////// MetaDataSource cover_rhapsody_src = { .name = "rhapsody", .key = 'r', .parser = cover_rhapsody_parse, .get_url = cover_rhapsody_url, .type = GLYR_GET_COVERART, .quality = 50, .speed = 80, .endmarker = NULL, .free_url = true }; glyr-1.0.5/lib/intern/cover/slothradio.c000066400000000000000000000100741227540770500202040ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../stringlib.h" #include "../../core.h" #define API_URL "http://www.slothradio.com/covers/?adv=1&artist=%s&album=%s&imgsize=%c&locale=%s&sort=salesrank" #define RESULT_LIST_START "" #define RESULT_ITEM_START "" #define RESULT_LIST_END "" #define RESULT_ITEM_END "" /////////////////////// #define STREQ(s1,s2) (g_ascii_strcasecmp(s1,s2) == 0) static const char * cover_slothradio_url (GlyrQuery * s) { const char * locale = "us"; if (STREQ (s->lang,"uk") || STREQ (s->lang,"de") ) locale = s->lang; /* * Possible image sizes: * x = largest available * l = large (300**2) * m = medium (130**2) * s = small (50 **2) **/ char image_size = 'x'; if (s->img_max_size != -1) { if (s->img_max_size < 75) image_size = 's'; else if (s->img_max_size < 150) image_size = 'm'; else if (s->img_max_size < 350) image_size = 'l'; } return g_strdup_printf (API_URL,s->artist,s->album,image_size,locale); } /////////////////////// static bool check_size (GlyrQuery * q, char * node) { bool rc = false; char * width = get_search_value (node,"width=\"", "\""); char * height = get_search_value (node,"height=\"","\""); if (width && height) { int w = strtol (width, NULL,10); int h = strtol (height,NULL,10); if (size_is_okay (w,q->img_min_size,q->img_max_size) && size_is_okay (h,q->img_min_size,q->img_max_size) ) rc = true; } g_free (width); g_free (height); return rc; } /////////////////////// static GList * cover_slothradio_parse (cb_object * capo) { GList * result_list = NULL; const char * bound_start = strstr (capo->cache->data,RESULT_LIST_START); if (bound_start == NULL) return NULL; const char * bound_end = strstr (bound_start,RESULT_LIST_END); if (bound_end == NULL) return NULL; char * node = (char*) bound_start; while ( (node = strstr (node + sizeof (RESULT_ITEM_START),RESULT_ITEM_START) ) != NULL) { if (node >= bound_end) break; char * url = get_search_value (node,"img src=\"","\""); if (url != NULL) { if (check_size (capo->s,node) ) { GlyrMemCache * result = DL_init(); result->dsrc = g_strdup (capo->url); result->data = url; result->size = strlen (url); result_list = g_list_prepend (result_list,result); } else { g_free (url); } } if (continue_search (g_list_length (result_list),capo->s) == false) break; } return result_list; } /////////////////////// MetaDataSource cover_slothradio_src = { .name = "slothradio", .key = 's', .parser = cover_slothradio_parse, .get_url = cover_slothradio_url, .type = GLYR_GET_COVERART, .quality = 80, .speed = 80, .endmarker = NULL, .free_url = true }; glyr-1.0.5/lib/intern/generic.c000066400000000000000000000154021227540770500163320ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "generic.h" #include "../core.h" #include "../stringlib.h" struct callback_save_struct { GHashTable * table; GLYR_DATA_TYPE type; GList * results; }; ///////////////////////////////// /* Simple finalizer template sufficient for most */ GList * generic_txt_finalizer (GlyrQuery * settings, GList * input_list, gboolean * stop_me, GLYR_DATA_TYPE type, GList ** result_list) { gboolean add_to_list = TRUE; GList * almost_copied = NULL; for (GList * elem = input_list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (is_in_result_list (item,result_list[0]) == FALSE && add_to_list == TRUE) { /* Set to some default type */ if (item->type == GLYR_TYPE_UNKNOWN) { item->type = type; } /* call user defined callback */ GLYR_ERROR response = GLYRE_OK; if (settings->callback.download) { /* Call the usercallback */ response = settings->callback.download (item,settings); } if (response != GLYRE_SKIP && response != GLYRE_STOP_PRE) { almost_copied = g_list_prepend (almost_copied,item); } else { DL_free (item); item = NULL; } if (response == GLYRE_STOP_POST || response == GLYRE_STOP_PRE) { add_to_list = FALSE; *stop_me = TRUE; } } else { settings->itemctr--; DL_free (item); item = NULL; } } return almost_copied; } ///////////////////////////////// static GList * async_dl_callback (cb_object * capo, void * userptr, bool * stop_download, gint * add_item) { if (capo->cache != NULL && userptr != NULL) { /* Sanitize this */ struct callback_save_struct * saver = userptr; GHashTable * prov_url_table = saver->table; capo->cache->is_image = true; if (prov_url_table != NULL) { GlyrMemCache * old_cache = g_hash_table_lookup (prov_url_table,capo->cache->dsrc); GLYR_ERROR response = GLYRE_OK; if (old_cache != NULL) { update_md5sum (capo->cache); if (is_in_result_list (capo->cache,saver->results) == FALSE) { capo->cache->prov = (old_cache->prov!=NULL) ? g_strdup (old_cache->prov) : NULL; capo->cache->img_format = (old_cache->img_format) ? g_strdup (old_cache->img_format) : NULL; if (capo->cache->type == GLYR_TYPE_UNKNOWN) { capo->cache->type = saver->type; } if (capo->s->callback.download != NULL) { response = capo->s->callback.download (capo->cache,capo->s); } *add_item = (response != GLYRE_SKIP && response != GLYRE_STOP_PRE); } else { capo->s->itemctr--; *add_item = FALSE; } } if (response == GLYRE_STOP_POST || response == GLYRE_STOP_PRE) { *stop_download = TRUE; } } else { glyr_message (-1,NULL,"glyr: Warn: Hashtable is empty im image_callback!\n"); } } return NULL; } ///////////////////////////////// GList * generic_img_finalizer (GlyrQuery * s, GList * list, gboolean * stop_me, GLYR_DATA_TYPE type, GList ** result_list) { /* Just return URLs */ if (s->download == false) { for (GList * elem = list; elem; elem = elem->next) { GlyrMemCache * img = elem->data; img->is_image = false; } return generic_txt_finalizer (s,list,stop_me,GLYR_TYPE_IMG_URL,result_list); } else { /* Convert to a list of URLs first */ GList * url_list = NULL; /* Hashtable to associate the provider name with the corresponding URL */ GHashTable * cache_url_table = g_hash_table_new_full (g_str_hash,g_str_equal, NULL, (GDestroyNotify) DL_free ); /* Iterate over all caches and turn them to GList */ for (GList * item = list; item; item = item->next) { GlyrMemCache * cache = item->data; /* Make a copy, since we free the cache */ gchar * url_double = g_strdup (cache->data); url_list = g_list_prepend (url_list,url_double); /* Fill in the URL */ g_hash_table_insert (cache_url_table, (gpointer) url_double, (gpointer) cache); } /* We need to pass this to the callback */ struct callback_save_struct userptr = { .table = cache_url_table, .type = type, .results = result_list ? result_list[0] : NULL }; /* Download images in parallel */ GList * dl_raw_images = async_download (url_list,NULL,s,1, (g_list_length (url_list) /2),async_dl_callback,&userptr,FALSE); /* Default to the given type */ for (GList * elem = dl_raw_images; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item && item->type == GLYR_TYPE_UNKNOWN) { item->type = type; } } /* Freeing Party */ g_hash_table_destroy (cache_url_table); glist_free_full (url_list,g_free); /* Ready to save images */ return dl_raw_images; } return NULL; } ///////////////////////////////// glyr-1.0.5/lib/intern/generic.h000066400000000000000000000024471227540770500163440ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a command-line tool and library to download various sort of musicrelated metadata. * + Copyright (C) [2011-2012] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #ifndef GLYR_GENERIC_H #define GLYR_GENERIC_H #include #include "../core.h" GList * generic_txt_finalizer (GlyrQuery * settings, GList * input_list, gboolean * stop_me, GLYR_DATA_TYPE type, GList ** result_list); GList * generic_img_finalizer (GlyrQuery * s, GList * list, gboolean * stop_me, GLYR_DATA_TYPE type, GList ** result_list); #endif glyr-1.0.5/lib/intern/guitartabs.c000066400000000000000000000040061227540770500170610ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../core.h" #include "../stringlib.h" #include "generic.h" ///////////////////////////////// static GList * factory (GlyrQuery * s, GList * list, gboolean * stop_me, GList ** result_list) { /* Fix up tabs, escape chars etc. */ for (GList * elem = list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL) { gchar * temp = beautify_string (item->data); g_free (item->data); item->data = temp; item->size = (item->data) ? strlen (item->data) : 0; } } /* Let the rest do by the norma generic finalizer */ return generic_txt_finalizer (s,list,stop_me,GLYR_TYPE_GUITARTABS,result_list); } ///////////////////////////////// /* PlugStruct */ MetaDataFetcher glyrFetcher_guitartabs = { .name = "guitartabs", .type = GLYR_GET_GUITARTABS, .default_data_type = GLYR_TYPE_GUITARTABS, .reqs = GLYR_REQUIRES_ARTIST | GLYR_REQUIRES_TITLE, .full_data = TRUE, .init = NULL, .destroy = NULL, .finalize = factory, }; ///////////////////////////////// glyr-1.0.5/lib/intern/guitartabs/000077500000000000000000000000001227540770500167155ustar00rootroot00000000000000glyr-1.0.5/lib/intern/guitartabs/chordie_com.c000066400000000000000000000107301227540770500213350ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define BASE_URL "http://www.chordie.com" #define SEARCH_URL BASE_URL"/?q=${artist}%20${title}&np=0&ps=10&wf=2221&s=RPD&wf=2221&wm=wrd&type=&sp=1&sy=1&cat=&ul=&np=0" #define RESULTS_BEGIN "" #define RESULTS_ENDIN "" #define NODE "artist) <= s->fuzzyness && levenshtein_strnormcmp (s,to_check,s->title) <= s->fuzzyness); } } return result; } ///////////////////////////////// static GlyrMemCache * parse_result_page (GlyrQuery * s, gchar * content_url) { GlyrMemCache * result = NULL; if (content_url != NULL) { GlyrMemCache * dl_cache = download_single (content_url,s,NULL); if (dl_cache != NULL) { gchar * content = get_search_value (dl_cache->data,"
","
"); if (content != NULL) { result = DL_init(); result->data = content; result->size = strlen (content); result->dsrc = g_strdup (content_url); } DL_free (dl_cache); } } return result; } ///////////////////////////////// static GList * guitartabs_chordie_parse (cb_object * capo) { GList * result_list = NULL; gchar * search_begin = strstr (capo->cache->data,RESULTS_BEGIN); if (search_begin != NULL) { gchar * search_ending = strstr (search_begin,RESULTS_ENDIN); if (search_ending != NULL) { gchar * node = search_begin; gsize nodelen = (sizeof NODE) - 1; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + nodelen, NODE) ) != NULL && node >= search_begin && node <= search_ending) { gchar * url = get_search_value (node,NODE,"\" "); if (url != NULL) { gchar * name_value = get_search_value (node,"\">","
"); if (check_title_value (capo->s, name_value) == TRUE) { gchar * content_url = g_strdup_printf ("%s%s",BASE_URL,url); GlyrMemCache * result = parse_result_page (capo->s,content_url); if (result != NULL) { result_list = g_list_prepend (result_list,result); } g_free (content_url); } g_free (name_value); g_free (url); } } } } return result_list; } ///////////////////////////////// MetaDataSource guitartabs_chordie_src = { .name = "chordie", .key = 'c', .parser = guitartabs_chordie_parse, .get_url = guitartabs_chordie_url, .type = GLYR_GET_GUITARTABS, .quality = 95, .speed = 75, .endmarker = NULL, .free_url = false }; glyr-1.0.5/lib/intern/guitartabs/guitaretab.c000066400000000000000000000115131227540770500212110ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define GT_BASE "http://www.guitaretab.com" #define GT_URL GT_BASE"/fetch/?type=tab&query=${title}" ///////////////////////////////// static const gchar * gt_guitaretabs_url (GlyrQuery * settings) { return GT_URL; } ///////////////////////////////// static GlyrMemCache * parse_single_page (GlyrQuery * s, const gchar * url) { GlyrMemCache * result = NULL; GlyrMemCache * tab_cache = download_single (url,s,NULL); if (tab_cache != NULL) { gchar * content = get_search_value (tab_cache->data,"
","
"); if (content != NULL) { result = DL_init(); result->data = content; result->size = strlen (content); result->dsrc = g_strdup (url); } DL_free (tab_cache); } return result; } ///////////////////////////////// #define SEARCH_RESULTS_BEGIN "
" #define SEARCH_RESULTS_ENDIN "" #define SEARCH_NODE "" #define ARTIST_END "" #define URL_END "\" " #define TITLE_BEGIN "\">" #define TITLE_ENDIN "" static GList * gt_guitaretabs_parse (cb_object * capo) { GList * result_list = NULL; gchar * begin_search = strstr (capo->cache->data,SEARCH_RESULTS_BEGIN); if (begin_search != NULL) { /* End need to assure we don't get over the search results */ gchar * endin_search = strstr (begin_search,SEARCH_RESULTS_ENDIN); if (endin_search != NULL) { /* Go through all search results */ gchar * node = begin_search; gsize nodelen = (sizeof SEARCH_NODE) - 1; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + nodelen, SEARCH_NODE) ) != NULL && node <= endin_search) { gchar * artist = get_search_value (node,ARTIST_BEGIN,ARTIST_END); node = strstr (node + nodelen, SEARCH_NODE); if (node != NULL) { gchar * url = get_search_value (node,SEARCH_NODE,URL_END); gchar * title = get_search_value (node,TITLE_BEGIN,TITLE_ENDIN); if (title != NULL) { gchar * delim = g_strrstr (title," chords"); if (delim == NULL) { delim = g_strrstr (title," tab"); } if (delim != NULL) { delim[0] = 0; } } /* Check if this is the item we actually search */ if (levenshtein_strnormcmp (capo->s,title, capo->s->title ) <= capo->s->fuzzyness && levenshtein_strnormcmp (capo->s,artist,capo->s->artist) <= capo->s->fuzzyness) { /* Build resulting url */ gchar * result_url = g_strdup_printf ("%s%s",GT_BASE,url); /* Go and parse it */ GlyrMemCache * result = parse_single_page (capo->s,result_url); if (result != NULL) { result_list = g_list_prepend (result_list,result); } g_free (result_url); } g_free (url); g_free (title); } g_free (artist); } } } return result_list; } ///////////////////////////////// MetaDataSource guitartabs_guitaretab_src = { .name = "guitaretab", .key = 'g', .parser = gt_guitaretabs_parse, .get_url = gt_guitaretabs_url, .type = GLYR_GET_GUITARTABS, .quality = 95, .speed = 75, .endmarker = NULL, .free_url = false }; glyr-1.0.5/lib/intern/lyrics.c000066400000000000000000000040161227540770500162220ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../core.h" #include "../stringlib.h" #include "generic.h" ///////////////////////////////// static GList * factory (GlyrQuery * s, GList * list, gboolean * stop_me, GList ** result_list) { /* Fix up lyrics, escape chars etc. */ for (GList * elem = list; elem; elem = elem->next) { GlyrMemCache * item = elem->data; if (item != NULL) { gchar * temp = beautify_string (item->data); g_free (item->data); item->data = temp; item->size = (item->data) ? strlen (item->data) : 0; } } /* Let the rest do by the norma generic finalizer */ return generic_txt_finalizer (s,list,stop_me,GLYR_TYPE_LYRICS,result_list); } ///////////////////////////////// /* PlugStruct */ MetaDataFetcher glyrFetcher_lyrics = { .name = "lyrics", .type = GLYR_GET_LYRICS, .default_data_type = GLYR_TYPE_LYRICS, .reqs = GLYR_REQUIRES_ARTIST | GLYR_REQUIRES_TITLE, .full_data = TRUE, .init = NULL, .destroy = NULL, .finalize = factory, .default_parallel = 1 }; ///////////////////////////////// glyr-1.0.5/lib/intern/lyrics/000077500000000000000000000000001227540770500160555ustar00rootroot00000000000000glyr-1.0.5/lib/intern/lyrics/chartlyrics.c000066400000000000000000000100351227540770500205470ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define CL_API_URL "http://api.chartlyrics.com/apiv1.asmx/SearchLyric?artist=${artist}&song=${title}" #define CL_API_GET "http://api.chartlyrics.com/apiv1.asmx/GetLyric?lyricId=%s&lyricCheckSum=%s" ///////////////////////////////// static const gchar * lyrics_chartlyrics_url (GlyrQuery * s) { return CL_API_URL; } ///////////////////////////////// #define LYRIC_TEXT_BEG "" #define LYRIC_TEXT_END "" static GlyrMemCache * get_lyrics_from_results (GlyrQuery * s, const gchar * url) { GlyrMemCache * result = NULL; GlyrMemCache * dl_cache = download_single (url,s,NULL); if (dl_cache != NULL) { gchar * text = get_search_value (dl_cache->data,LYRIC_TEXT_BEG,LYRIC_TEXT_END); if (text != NULL) { result = DL_init(); result->data = text; result->size = strlen (text); result->dsrc = g_strdup (url); } DL_free (dl_cache); } return result; } ///////////////////////////////// #define LYRIC_NODE "" #define LYRIC_CHECKSUM_BEG "" #define LYRIC_CHECKSUM_END "" #define ARTIST_BEG "" #define ARTIST_END "" #define SONG_BEG "" #define SONG_END "" #define LYRIC_ID_BEG "" #define LYRIC_ID_END "" static GList * lyrics_chartlyrics_parse (cb_object * capo) { GList * result_list = NULL; gchar * node = capo->cache->data; gint nodelen = (sizeof LYRIC_NODE) - 1; while (continue_search (g_list_length (result_list),capo->s) && (node = strstr (node + nodelen, LYRIC_NODE) ) != NULL) { node += nodelen; gchar * artist = get_search_value (node,ARTIST_BEG,ARTIST_END); gchar * title = get_search_value (node,SONG_BEG,SONG_END); if (levenshtein_strnormcmp (capo->s,artist,capo->s->artist) <= capo->s->fuzzyness && levenshtein_strnormcmp (capo->s,title,capo->s->title) <= capo->s->fuzzyness) { gchar * lyric_id = get_search_value (node,LYRIC_ID_BEG,LYRIC_ID_END); gchar * lyric_checksum = get_search_value (node,LYRIC_CHECKSUM_BEG,LYRIC_CHECKSUM_END); if (lyric_id && lyric_checksum && strcmp (lyric_id,"0") != 0) { gchar * content_url = g_strdup_printf (CL_API_GET,lyric_id,lyric_checksum); GlyrMemCache * result = get_lyrics_from_results (capo->s,content_url); if (result != NULL) { result_list = g_list_prepend (result_list,result); } g_free (content_url); } g_free (lyric_id); g_free (lyric_checksum); } g_free (artist); g_free (title); } return result_list; } ///////////////////////////////// MetaDataSource lyrics_chartlyrics_src = { .name = "chartlyrics", .key = 'c', .parser = lyrics_chartlyrics_parse, .get_url = lyrics_chartlyrics_url, .type = GLYR_GET_LYRICS, .quality = 75, .speed = 25, .endmarker = NULL, .free_url = false }; glyr-1.0.5/lib/intern/lyrics/elyrics.c000066400000000000000000000112631227540770500176760ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" /* Simple URL replace scheme - works pretty good here */ #define ELYRICS_BASE_URL "http://www.elyrics.net/read/%c/%s-lyrics/%s-lyrics.html" static const gchar * lyrics_elyrics_url (GlyrQuery * settings) { gchar * result_url = NULL; gchar * space_to_min_artist = strreplace (settings->artist," ","-"); gchar * space_to_min_title = strreplace (settings->title, " ","-"); if (space_to_min_artist && space_to_min_title) { gchar * prep_title = NULL, * prep_artist = NULL; if (settings->normalization & GLYR_NORMALIZE_ARTIST) prep_title = prepare_string (space_to_min_title, settings->normalization,TRUE); else prep_title = prepare_string (space_to_min_title, GLYR_NORMALIZE_NONE,TRUE); if (settings->normalization & GLYR_NORMALIZE_ARTIST) prep_artist = prepare_string (space_to_min_artist, settings->normalization,TRUE); else prep_artist = prepare_string (space_to_min_artist, GLYR_NORMALIZE_NONE,TRUE); if (prep_title && prep_artist) { result_url = g_strdup_printf (ELYRICS_BASE_URL,prep_artist[0],prep_artist,prep_title); g_free (prep_title); g_free (prep_artist); } g_free (space_to_min_artist); g_free (space_to_min_title); } return result_url; } ///////////////////////////////// /* Neat try elyrics to vary this string with every request :-) */ #define FROM_MIDDLE "http://www.elyrics.net" #define FROM_END "

" #define BAD_STRING "Lyrics removed for copyright protection!" /* This data is separated from the actual lyrics => remove it from here */ static void remove_from_from_string (gchar * string) { gchar * from_middle = strstr (string,FROM_MIDDLE); if (from_middle != NULL) { gchar * from_end = strstr (from_middle,FROM_END); if (from_end != NULL) { gchar * from_start = from_middle; while (from_start[0] && from_start[0] != '>') { from_start--; } if (from_start != NULL) { gsize memlen = from_end - from_start; memset (from_start,' ',memlen); } } } } ///////////////////////////////// #define LYRICS_BEGIN "
" #define LYRICS_ALT_END "these lyrics are submitted by" #define LYRICS_END "
" static GList * lyrics_elyrics_parse (cb_object * capo) { GList * results = NULL; gchar * lyrics_begin = strstr (capo->cache->data,LYRICS_BEGIN); if (lyrics_begin != NULL) { if (g_strstr_len (lyrics_begin,250,BAD_STRING) == NULL) { gchar * lyrics_end = strstr (lyrics_begin,LYRICS_ALT_END); if (lyrics_end == NULL) { lyrics_end = strstr (lyrics_begin,LYRICS_END); } if (lyrics_end != NULL) { /* Modifying original buffer is allowed * As long it's not saved in the result cache * */ lyrics_end[0] = '\0'; GlyrMemCache * item = DL_init(); remove_from_from_string (lyrics_begin); item->data = g_strdup (lyrics_begin); item->size = lyrics_end - lyrics_begin; results = g_list_prepend (results,item); } } } return results; } ///////////////////////////////// MetaDataSource lyrics_elyrics_src = { .name = "elyrics", .key = 'e', .encoding = "LATIN1", .parser = lyrics_elyrics_parse, .get_url = lyrics_elyrics_url, .type = GLYR_GET_LYRICS, .endmarker = NULL, .quality = 75, .speed = 75, .free_url = true }; glyr-1.0.5/lib/intern/lyrics/lipwalk.c000066400000000000000000000127441227540770500176740ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define TRACK_BEGIN "
  • " #define TRACK_DESCR "" #define LIPWALK_DOMAIN "http://www.lipwalklyrics.com" #define LIPWALK_URL LIPWALK_DOMAIN"/component/lyrics/search/index.php?search=${artist}%20${title}" #define START "
    " #define END "
    " #define IS_ON_SEARCH_PAGE "Search results for" static const gchar * lyrics_lipwalk_url (GlyrQuery * settings) { return LIPWALK_URL; } ///////////////////////////////// static GlyrMemCache * parse_lyrics_page (GlyrMemCache * cache) { gchar * start = NULL; gchar * end = NULL; gchar * content = NULL; GlyrMemCache * result_cache = NULL; if (cache && (start = strstr (cache->data,START) ) != NULL) { start += (sizeof START) - 1; if (start && (end = strstr (start + (sizeof START) ,END) ) != NULL) { if (ABS (end-start) > 35) { * (end) = 0; content = strreplace (start,"<br />",NULL); if (content != NULL) { result_cache = DL_init(); result_cache->data = content; result_cache->size = strlen (content); result_cache->dsrc = g_strdup (cache->dsrc); } } } } return result_cache; } ///////////////////////////////// static gboolean validate_track_description (GlyrQuery * query, gchar * description) { gboolean result = FALSE; if (description != NULL) { gchar ** splitv = g_strsplit (description," - ",0); if (splitv != NULL) { if (splitv[0] && splitv[1] != NULL) { if (levenshtein_strnormcmp (query,query->artist,splitv[0]) <= query->fuzzyness && levenshtein_strnormcmp (query,query->title, splitv[1]) <= query->fuzzyness) { result = TRUE; } } g_strfreev (splitv); } } return result; } ///////////////////////////////// static GList * lyrics_lipwalk_parse (cb_object *capo) { GList * result_list = NULL; if (strstr (capo->cache->data,IS_ON_SEARCH_PAGE) == NULL) { GlyrMemCache * result_cache = parse_lyrics_page (capo->cache); result_list = g_list_prepend (result_list,result_cache); } else /* Oops, we're on the search results page, things are complicated now */ { /* Happens with "In Flames" - "Trigger" e.g. */ gchar * search_node = capo->cache->data; gsize track_len = (sizeof TRACK_BEGIN) - 1; while (continue_search (g_list_length (result_list),capo->s) && (search_node = strstr (search_node + track_len,TRACK_BEGIN) ) ) { search_node += track_len; gchar * track_end = strstr (search_node,TRACK_ENDIN); if (track_end != NULL) { gchar * lyrics_url = copy_value (search_node,track_end); if (lyrics_url != NULL) { track_end += (sizeof TRACK_ENDIN) - 1; gchar * track_descr = copy_value (track_end,strstr (track_end,TRACK_DESCR) ); if (track_descr != NULL && validate_track_description (capo->s,track_descr) == TRUE) { gchar * full_url = g_strdup_printf ("%s%s",LIPWALK_DOMAIN,lyrics_url); GlyrMemCache * lyrics_page = download_single (full_url,capo->s,NULL); if (lyrics_page != NULL) { GlyrMemCache * result_cache = parse_lyrics_page (lyrics_page); if (result_cache != NULL) { result_list = g_list_prepend (result_list,result_cache); } DL_free (lyrics_page); } g_free (track_descr); g_free (full_url); } g_free (lyrics_url); } } } } return result_list; } ///////////////////////////////// MetaDataSource lyrics_lipwalk_src = { .name = "lipwalk", .key = 'z', .parser = lyrics_lipwalk_parse, .get_url = lyrics_lipwalk_url, .type = GLYR_GET_LYRICS, .quality = 80, .speed = 60, .endmarker = NULL, .free_url = false }; ����������������������������glyr-1.0.5/lib/intern/lyrics/lyrdb.c����������������������������������������������������������������0000664�0000000�0000000�00000006026�12275407705�0017341�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define LYRDB_URL "http://webservices.lyrdb.com/lookup.php?q=${artist}|${title}&for=match&agent=libglyr" ///////////////////////////////// static const char * lyrics_lyrdb_url (GlyrQuery * settings) { return LYRDB_URL; } ///////////////////////////////// static GList * lyrics_lyrdb_parse (cb_object * capo) { gchar *slash = NULL; GList * result_list = NULL; if ( (slash = strchr (capo->cache->data,'\\') ) != NULL) { gchar * uID = copy_value (capo->cache->data,slash); if (uID != NULL) { gchar * lyr_url = g_strdup_printf ("http://webservices.lyrdb.com/getlyr.php?q=%s",uID); if (lyr_url != NULL) { GlyrMemCache * new_cache = download_single (lyr_url,capo->s,NULL); if (new_cache != NULL) { gsize i = 0; gchar * buffer = g_malloc0 (new_cache->size + 1); for (i = 0; i < new_cache->size; i++) { buffer[i] = (new_cache->data[i] == '\r') ? ' ' : new_cache->data[i]; } buffer[i] = 0; if (i != 0) { GlyrMemCache * result = DL_init(); result->data = buffer; result->size = i; result->dsrc = g_strdup (lyr_url); result_list = g_list_prepend (result_list,result); } DL_free (new_cache); } g_free (lyr_url); } g_free (uID); } } return result_list; } ///////////////////////////////// MetaDataSource lyrics_lyrdb_src = { .name = "lyrdb", .key = 'd', .encoding = "LATIN1", .parser = lyrics_lyrdb_parse, .get_url = lyrics_lyrdb_url, .type = GLYR_GET_LYRICS, .endmarker = NULL, .quality = 75, .speed = 75, .free_url = false }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/lyrics/lyricsreg.c������������������������������������������������������������0000664�0000000�0000000�00000004557�12275407705�0020237�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define INFO_BEGIN "</div><div style=\"text-align:center;\">" #define INFO_ENDIN " <a href=\"" static const char * lyrics_lyricsreg_url (GlyrQuery * s) { return "http://www.lyricsreg.com/lyrics/${artist}/${title}/"; } static GList * lyrics_lyricsreg_parse (cb_object * capo) { GList * result_list = NULL; gchar * start = strstr (capo->cache->data, INFO_BEGIN); if (start != NULL) { start += (sizeof INFO_BEGIN) - 1; gchar * end = strstr (start,INFO_ENDIN); if (end != NULL) { * (end) = 0; gchar * no_br_tags = strreplace (start,"<br />",NULL); if (no_br_tags != NULL) { GlyrMemCache * tmp = DL_init(); tmp->data = beautify_string (no_br_tags); tmp->size = tmp->data ? strlen (tmp->data) : 0; g_free (no_br_tags); if (tmp->data != NULL) { result_list = g_list_prepend (result_list,tmp); } } } } return result_list; } ///////////////////////////////// MetaDataSource lyrics_lyricsreg_src = { .name = "lyricsreg", .key = 'r', .parser = lyrics_lyricsreg_parse, .get_url = lyrics_lyricsreg_url, .type = GLYR_GET_LYRICS, .quality = 42, .speed = 90, .endmarker = NULL, .free_url = false }; �������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/lyrics/lyricstime.c�����������������������������������������������������������0000664�0000000�0000000�00000012604�12275407705�0020410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define GLYR_GET_URL "http://www.lyricstime.com/search/?q=${artist}+${title}&t=default" ///////////////////////////////// static const char * lyrics_lyricstime_url (GlyrQuery * settings) { return GLYR_GET_URL; } ///////////////////////////////// #define LYR_BEGIN "<div id=\"songlyrics\" >" #define LYR_ENDIN "</div>" static GlyrMemCache * parse_page (GlyrMemCache * dl, cb_object * capo) { GlyrMemCache * result = NULL; if (dl != NULL) { gchar * begin = strstr (dl->data,LYR_BEGIN); if (begin != NULL) { begin += (sizeof LYR_BEGIN) - 1; gchar * end = strstr (begin,LYR_ENDIN); if (end != NULL) { * (end) = 0; gchar * no_br_tags = strreplace (begin,"<br />",NULL); if (no_br_tags != NULL) { result = DL_init(); result->data = beautify_string (no_br_tags); result->size = (result->data) ? strlen (result->data) : 0; result->dsrc = g_strdup (dl->dsrc); g_free (no_br_tags); } } } } return result; } ///////////////////////////////// #define START_SEARCH "<div id=\"searchresult\">" #define SEARCH_ENDIN "</div>" #define NODE_BEGIN "<li><a href=\"" #define NODE_ENDIN "\">" #define SPAN_BEGIN "<span class" #define ARTIST_BEG "<b>" #define ARTIST_END "</b>" static gboolean validate_artist (cb_object * capo, gchar * backpointer) { gboolean i_shall_continue = false; if (backpointer != NULL) { char * span = strstr (backpointer,SPAN_BEGIN); if (span != NULL) { gchar * artist_beg = strstr (span,ARTIST_BEG); if (artist_beg != NULL) { artist_beg += (sizeof ARTIST_BEG) - 1; gchar * artist_end = strstr (artist_beg,ARTIST_END); if (artist_end != NULL) { gchar * artist_val = copy_value (artist_beg,artist_end); if (artist_val != NULL) { if (levenshtein_strnormcmp (capo->s,artist_val,capo->s->artist) <= capo->s->fuzzyness) { i_shall_continue = true; } g_free (artist_val); } } } } } return i_shall_continue; } ///////////////////////////////// static GList * lyrics_lyricstime_parse (cb_object * capo) { GList * rList = NULL; char * start = capo->cache->data; if (start != NULL) { gchar * div_end = strstr (start,SEARCH_ENDIN); gchar * node = capo->cache->data; gchar * backpointer = node; gsize nlen = (sizeof NODE_BEGIN) - 1; while (continue_search (g_list_length (rList),capo->s) && (node = strstr (node+nlen,NODE_BEGIN) ) != NULL) { if (div_end >= node) break; if (validate_artist (capo,backpointer) == TRUE) { gchar * end_of_url = strstr (node+nlen,NODE_ENDIN); if (end_of_url != NULL) { gchar * url = copy_value (node+nlen,end_of_url); if (url != NULL) { gchar * full_url = g_strdup_printf ("http://www.lyricstime.com%s",url); GlyrMemCache * dl_cache = download_single (full_url,capo->s,NULL); if (dl_cache) { GlyrMemCache * parsed_cache = parse_page (dl_cache,capo); if (parsed_cache != NULL) { rList = g_list_prepend (rList,parsed_cache); } DL_free (dl_cache); g_free (full_url); } g_free (url); } } } backpointer = node; } } return rList; } ///////////////////////////////// MetaDataSource lyrics_lyricstime_src = { .name = "lyricstime", .key = 'y', .parser = lyrics_lyricstime_parse, .get_url = lyrics_lyricstime_url, .type = GLYR_GET_LYRICS, .quality = 70, .speed = 60, .endmarker = NULL, .free_url = false }; ����������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/lyrics/lyricsvip.c������������������������������������������������������������0000664�0000000�0000000�00000005745�12275407705�0020260�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define LV_URL "http://www.lyricsvip.com/%s/%s-Lyrics.html" ///////////////////////////////// static const gchar * lyrics_lyricsvip_url (GlyrQuery * settings) { gchar * result = NULL; gchar * artist_clean = strreplace (settings->artist, " ", "-"); if (artist_clean != NULL) { gchar * title_clean = strreplace (settings->title, " ", "-"); if (title_clean != NULL) { gchar * prep_artist = curl_easy_escape (NULL,artist_clean,0); gchar * prep_title = curl_easy_escape (NULL,title_clean,0); result = g_strdup_printf (LV_URL, prep_artist, prep_title); g_free (title_clean); curl_free (prep_artist); curl_free (prep_title); } g_free (artist_clean); } return result; } ///////////////////////////////// #define BEG "<img src=\"http://www.lyricsvip.com/images/phone2.gif\" alt=\"phone\" /></div>" #define END "<br />\n<div class=\"ad\">" static GList * lyrics_lyricsvip_parse (cb_object *capo) { gchar * start = NULL; gchar * end = NULL; gchar * content = NULL; GList * result_list = NULL; if ( (start = strstr (capo->cache->data,BEG) ) != NULL) { if ( (end = strstr (start,END) ) != NULL) { if (ABS (end-start) > 0) { * (end) = 0; content = strreplace (start,"<br />",""); if (content) { GlyrMemCache * result = DL_init(); result->data = content; result->size = strlen (content); result_list = g_list_prepend (result_list,result); } } } } return result_list; } ///////////////////////////////// MetaDataSource lyrics_lyricsvip_src = { .name = "lyricsvip", .key = 'v', .parser = lyrics_lyricsvip_parse, .get_url = lyrics_lyricsvip_url, .type = GLYR_GET_LYRICS, .quality = 60, .speed = 85, .free_url = true }; ���������������������������glyr-1.0.5/lib/intern/lyrics/lyricswiki.c�����������������������������������������������������������0000664�0000000�0000000�00000011546�12275407705�0020421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define BAD_STRING "Special:Random" /* This has been a running gag during developement: "I want to edit metadata!" */ #define EXTERNAL_LINKS "<span class=\"plainlinks\"" #define LW_URL "http://lyrics.wikia.com/api.php?action=lyrics&fmt=xml&func=getSong&artist=${artist}&song=${title}" #define NOT_FOUND "<lyrics>Not found</lyrics>" ///////////////////////////////// static const gchar * lyrics_lyricswiki_url (GlyrQuery * settings) { return LW_URL; } ///////////////////////////////// // Compare response, so lyricswiki's search did not fool us static gboolean lv_cmp_content (const gchar * to_artist, const gchar * to_title, cb_object * capo) { gboolean res = false; if (to_artist && to_title && capo) { gchar * tmp_artist = copy_value (to_artist,strstr (to_artist,"</artist>") ); if (tmp_artist != NULL) { gchar * tmp_title = copy_value (to_title, strstr (to_title ,"</song>" ) ); if (tmp_title != NULL) { /* levenshtein_strnormcmp takes care of those brackets */ if ( (levenshtein_strnormcmp (capo->s,capo->s->artist,tmp_artist) <= capo->s->fuzzyness && levenshtein_strnormcmp (capo->s,capo->s->title, tmp_title) <= capo->s->fuzzyness ) ) { res = true; } g_free (tmp_title); } g_free (tmp_artist); } } return res; } ///////////////////////////////// #define LYR_NODE "<div class='lyricbox'>" #define LYR_BEGIN "</div>" #define LYR_ENDIN "<!--" #define LYR_INSTRUMENTAL "/Category:Instrumental" GList * parse_result_page (GlyrQuery * query, GlyrMemCache * to_parse) { GList * result_list = NULL; gchar * node = to_parse->data; while (continue_search (g_list_length (result_list),query) && (node = strstr (node,LYR_NODE) ) ) { node += (sizeof LYR_NODE); bool is_instrumental = strstr(node, LYR_INSTRUMENTAL) != NULL; gchar * lyr = get_search_value (node,LYR_BEGIN,LYR_ENDIN); gchar * beautiness_test = beautify_string (lyr); if (is_instrumental || (beautiness_test != NULL && beautiness_test[0])) { if (is_instrumental || (lyr != NULL && strstr (lyr,BAD_STRING) == NULL && strstr (lyr,EXTERNAL_LINKS) == NULL)) { GlyrMemCache * result = DL_init(); if(is_instrumental) result->data = g_strdup("Instrumental"); else result->data = lyr; result->size = strlen (result->data); result->dsrc = g_strdup (to_parse->dsrc); result_list = g_list_prepend (result_list,result); } } else { g_free (lyr); } g_free (beautiness_test); } return result_list; } ///////////////////////////////// static GList * lyrics_lyricswiki_parse (cb_object * capo) { GList * result_list = NULL; if (strstr (capo->cache->data,NOT_FOUND) == NULL && lv_cmp_content (strstr (capo->cache->data,"<artist>"),strstr (capo->cache->data,"<song>"),capo) ) { gchar * wiki_page_url = get_search_value (capo->cache->data,"<url>","</url>"); if (wiki_page_url != NULL) { GlyrMemCache * new_cache = download_single (wiki_page_url,capo->s,NULL); if (new_cache != NULL) { result_list = parse_result_page (capo->s,new_cache); DL_free (new_cache); } g_free (wiki_page_url); } } return result_list; } ///////////////////////////////// MetaDataSource lyrics_lyricswiki_src = { .name = "lyricswiki", .key = 'w', .parser = lyrics_lyricswiki_parse, .get_url = lyrics_lyricswiki_url, .type = GLYR_GET_LYRICS, .quality = 95, .speed = 75, .endmarker = NULL, .free_url = false }; ����������������������������������������������������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/lyrics/lyrix_at.c�������������������������������������������������������������0000664�0000000�0000000�00000010624�12275407705�0020057�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define AT_URL "http://lyrix.at/lyrics-search/s-${artist},,${title},,any,1321,0.html" const char * lyrics_lyrixat_url (GlyrQuery * settings) { return AT_URL; } ///////////////////////////////// #define SEARCH_START_TAG "<!-- start of result item //-->" #define LYRIC_BEGIN "<div class='songtext' id='stextDIV'>" #define URL_TAG_BEGIN "<a href='/de" #define URL_TAG_ENDIN "'>" #define TITLE_END "<" #define MAX_TRIES 5 ///////////////////////////////// static void parse_lyrics_page (const gchar * url, GList ** result_list, cb_object * capo) { GlyrMemCache * lyrcache = download_single (url,capo->s,"<!-- eBay Relevance Ad -->"); if (lyrcache != NULL) { gchar * lyr_begin = strstr (lyrcache->data,LYRIC_BEGIN); if (lyr_begin != NULL) { gchar * lyr_endin = strstr (lyr_begin,"</div>"); if (lyr_endin != NULL) { gchar * lyrics = copy_value (lyr_begin,lyr_endin); if (lyrics != NULL) { GlyrMemCache * result = DL_init(); result->data = strreplace (lyrics,"<br />",""); result->size = strlen (result->data); result->dsrc = g_strdup (url); *result_list = g_list_prepend (*result_list,result); } g_free (lyrics); } } DL_free (lyrcache); } } ///////////////////////////////// GList * lyrics_lyrixat_parse (cb_object * capo) { /* lyrix.at does not offer any webservice -> use the searchfield to get some results */ GList * result_list = NULL; gchar * search_begin_tag = capo->cache->data; gint ctr = 0; while (continue_search (g_list_length (result_list),capo->s) && (search_begin_tag = strstr (search_begin_tag+1,SEARCH_START_TAG) ) && MAX_TRIES >= ctr++) { gchar * url_tag = search_begin_tag; url_tag = strstr (url_tag,URL_TAG_BEGIN); if (url_tag != NULL) { gchar * title_tag = strstr (url_tag,URL_TAG_ENDIN); if (title_tag) { gchar * title_end = strstr (title_tag,TITLE_END); if (title_end != NULL) { gsize tag_end_len = (sizeof URL_TAG_ENDIN) - 1; gchar * title = copy_value (title_tag + tag_end_len,title_end); if (title != NULL) { if (levenshtein_strnormcmp (capo->s,title,capo->s->title) <= capo->s->fuzzyness) { gchar * url_part = copy_value (url_tag+strlen (URL_TAG_BEGIN),title_tag); if (url_part != NULL) { gchar * url = g_strdup_printf ("http://lyrix.at/de%s",url_part); parse_lyrics_page (url,&result_list,capo); g_free (url); g_free (url_part); } } g_free (title); } } } } } return result_list; } ///////////////////////////////// MetaDataSource lyrics_lyrix_src = { .name = "lyrix", .key = 'a', .parser = lyrics_lyrixat_parse, .get_url = lyrics_lyrixat_url, .type = GLYR_GET_LYRICS, .quality = 70, .speed = 50, .free_url = false }; ������������������������������������������������������������������������������������������������������������glyr-1.0.5/lib/intern/lyrics/magistrix.c������������������������������������������������������������0000664�0000000�0000000�00000010516�12275407705�0020233�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see <http://www.gnu.org/licenses/>. **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define MG_URL "http://www.magistrix.de/lyrics/search?q=${artist}+${title}" static const char * lyrics_magistrix_url (GlyrQuery * settings) { return MG_URL; } /////////////////////////////////// static GlyrMemCache * parse_lyric_page (GlyrMemCache * cache) { GlyrMemCache * result = NULL; g_return_val_if_fail (cache,NULL); g_return_val_if_fail (cache->data,NULL); gchar * data = get_search_value (cache->data,"id='songtext'>","<div class='lyric-actions'>"); if (data != NULL) { result = DL_init(); result->data = data; result->size = strlen (data); result->dsrc = g_strdup (cache->dsrc); } return result; } /////////////////////////////////// #define SEARCH_FIRST_RESULT "<table class='searchresult'>" #define SEARCH_LAST_RESULT "</table>" #define SEARCH_NODE "<div class='title'>" #define SEARCH_LINK_START "–\n<a href=\"" #define SEARCH_LINK_END "\" class" static GList * parse_search_result_page (cb_object * capo) { GList * result_list = NULL; char * first_result = strstr (capo->cache->data, SEARCH_FIRST_RESULT); if (first_result != NULL) { char * end_of_results = strstr (first_result + sizeof (SEARCH_FIRST_RESULT), SEARCH_LAST_RESULT); if (end_of_results) { char * node = first_result; while ( (node = strstr (node + sizeof (SEARCH_NODE), SEARCH_NODE) ) && continue_search (g_list_length (result_list), capo->s) ) { char * new_url = get_search_value (node, SEARCH_LINK_START, SEARCH_LINK_END); if (new_url != NULL) { char * full_url = g_strdup_printf ("www.magistrix.de%s", new_url); GlyrMemCache * lyrics_page = download_single (full_url, capo->s, NULL); if (lyrics_page) { GlyrMemCache * item = parse_lyric_page (lyrics_page); if (item != NULL) { result_list = g_list_prepend (result_list, item); } DL_free (lyrics_page); } g_free (new_url); g_free (full_url); } } } } return result_list; } /////////////////////////////////// static GList * lyrics_magistrix_parse (cb_object * capo) { GList * result_list = NULL; if (strstr (capo->cache->data,"Es wurden keine Songtexte gefunden") == NULL) /* "No songtext" page? */ { if (strstr (capo->cache->data,"<title>Songtext-Suche") == NULL) /* Are we not on the search result page? */ { GlyrMemCache * result = parse_lyric_page (capo->cache); if (result != NULL) { result_list = g_list_prepend (result_list,result); } } else { /* Parse Searchresult page */ result_list = parse_search_result_page (capo); } } return result_list; } /////////////////////////////////// MetaDataSource lyrics_magistrix_src = { .name = "magistrix", .key = 'x', .parser = lyrics_magistrix_parse, .get_url = lyrics_magistrix_url, .type = GLYR_GET_LYRICS, .quality = 60, .speed = 75, .endmarker = NULL, .free_url = false }; glyr-1.0.5/lib/intern/lyrics/metallum.c000066400000000000000000000055271227540770500200520ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a command-line tool and library to download various sort of music related metadata. * + Copyright (C) [2011-2012] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" #define AJAX_URL "http://www.metal-archives.com/search/ajax-advanced/searching/songs/" \ "?songTitle=${title}&bandName=${artist}" \ "&_=1313668588182&sEcho=1&iColumns=5&sColumns=&iDisplayStart=0" \ "&iDisplayLength=100&sNames=%%2C%%2C%%2C%%2C" #define SUBST_URL "http://www.metal-archives.com/release/ajax-view-lyrics/id/%s" #define BAD_STRING "(lyrics not available)" ///////////////////////////////// static const gchar * lyrics_metallum_url (GlyrQuery * s) { return AJAX_URL; } ///////////////////////////////// #define ID_START "id=\\\"lyricsLink_" #define ID_END "\\\"" ///////////////////////////////// static GList * lyrics_metallum_parse (cb_object * capo) { GList * result_items = NULL; gchar * id_start = strstr (capo->cache->data,ID_START); if (id_start != NULL) { id_start += strlen (ID_START); gchar * ID_string = copy_value (id_start,strstr (id_start,ID_END) ); if (ID_string != NULL) { gchar * content_url = g_strdup_printf (SUBST_URL,ID_string); if (content_url != NULL) { GlyrMemCache * content_cache = download_single (content_url,capo->s,NULL); if (content_cache != NULL && strstr (content_cache->data,BAD_STRING) == NULL) { result_items = g_list_prepend (result_items, content_cache); } g_free (content_url); } g_free (ID_string); } } return result_items; } ///////////////////////////////// MetaDataSource lyrics_metallum_src = { .name = "metallum", .key = 'u', .parser = lyrics_metallum_parse, .get_url = lyrics_metallum_url, .endmarker = NULL, .quality = 55, .speed = 70, .free_url = false, .type = GLYR_GET_LYRICS }; glyr-1.0.5/lib/intern/lyrics/metrolyrics.c000066400000000000000000000127701227540770500206040ustar00rootroot00000000000000/*********************************************************** * This file is part of glyr * + a commnadline tool and library to download various sort of music related metadata. * + Copyright (C) [2011] [Christopher Pahl] * + Hosted at: https://github.com/sahib/glyr * * glyr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glyr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glyr. If not, see . **************************************************************/ #include "../../core.h" #include "../../stringlib.h" // Search URL #define ML_URL "http://www.metrolyrics.com/search.php?search=${artist}+${title}&category=artisttitle" #define MAX_TRIES 5 // Just return URL static const gchar * lyrics_metrolyrics_url (GlyrQuery * settings) { return ML_URL; } /////////////////////////////////// static void replace_from_message_inline (gchar * text) { if (text != NULL) { gchar * from_msg_start = strstr (text,"[ From: "); if (from_msg_start != NULL) { while (from_msg_start[0] != '\n' && from_msg_start[0]) { from_msg_start[0] = ' '; from_msg_start++; } if (from_msg_start[0] == '\n') { from_msg_start[0] = ' '; } } } } /////////////////////////////////// #define LYRICS_DIV "
    " #define LYRICS_END "
    " static GlyrMemCache * parse_lyrics_page (const gchar * buffer) { GlyrMemCache * result = NULL; if (buffer != NULL) { gchar * begin = strstr (buffer,LYRICS_DIV); if (begin != NULL) { gchar * end = strstr (begin,LYRICS_END); if (end != NULL) { gchar * lyr = copy_value (begin,end); if (lyr != NULL) { result = DL_init(); replace_from_message_inline (lyr); result->data = lyr; result->size = strlen (result->data); } } } } return result; } /////////////////////////////////// //#define ROOT_NODE "
    " #define ROOT_NODE "