pax_global_header00006660000000000000000000000064134167147150014523gustar00rootroot0000000000000052 comment=66f6ce0778bb2c3af4bd3901111bf26dbbb429f9 CPU-X-3.2.4/000077500000000000000000000000001341671471500123655ustar00rootroot00000000000000CPU-X-3.2.4/.github/000077500000000000000000000000001341671471500137255ustar00rootroot00000000000000CPU-X-3.2.4/.github/ISSUE_TEMPLATE.md000066400000000000000000000001411341671471500164260ustar00rootroot00000000000000 CPU-X-3.2.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001341671471500161105ustar00rootroot00000000000000CPU-X-3.2.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000011761341671471500206070ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us to improve CPU-X --- **Describe the bug/Expected behavior** **Additional information** * Operating system name and version: * CPU-X installation type: **CPU-X dump** ``` ``` CPU-X-3.2.4/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000005261341671471500216400ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for CPU-X --- **Is your feature request related to a problem? Please describe.** **Describe the solution you'd like** CPU-X-3.2.4/.github/ISSUE_TEMPLATE/libcpuid.md000066400000000000000000000004631341671471500202300ustar00rootroot00000000000000--- name: Wrong CPU Code Name about: Create a report to help us to improve libcpuid --- **libcpuid dump** CPU-X-3.2.4/.gitignore000066400000000000000000000000301341671471500143460ustar00rootroot00000000000000*~ build ebuild po/mo.h CPU-X-3.2.4/.travis.yml000066400000000000000000000015001341671471500144720ustar00rootroot00000000000000sudo: required dist: xenial language: c compiler: - clang - gcc cache: ccache env: - CPUX_BCLK=100 before_install: - curl http://download.opensuse.org/repositories/home:/X0rg/xUbuntu_16.04/Release.key | sudo apt-key add - - echo "deb http://download.opensuse.org/repositories/home:/X0rg/xUbuntu_16.04/ /" | sudo tee -a /etc/apt/sources.list - sudo apt-get update -qq install: - sudo apt-get install -y -qq nasm gettext libjson-c-dev libncursesw5-dev libcpuid-dev libpci-dev libprocps-dev libarchive-dev libncursesw5 libcpuid14 libpci3 libprocps4 before_script: - mkdir build - cd build - cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_GTK=0 -DCMAKE_INSTALL_PREFIX=/usr .. script: - make -j$(nproc) after_success: - sudo make -j$(nproc) install - sudo cpu-x --issue-fmt notifications: slack: on_success: change on_failure: always CPU-X-3.2.4/CMakeLists.txt000066400000000000000000000150761341671471500151360ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0048 NEW) project(cpu-x VERSION "3.2.4" LANGUAGES C ) ### DEFAULT CONFIG # Global variables if(PORTABLE_BINARY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) else(PORTABLE_BINARY) include(GNUInstallDirs) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/bin/) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/lib/) set(CMAKE_DATA_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/data/) set(CPU_X_DATA_DIRECTORY ${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME}/) endif(PORTABLE_BINARY) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86") set(BITNESS "32") else(${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86") set(BITNESS "64") endif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "i.86") set(CPU_X_FLAGS "-Wno-unused-parameter -Wno-unused-result -Wno-format-security") set(CPU_X_DEBUG_FLAGS "-Wall -Wextra -Wuninitialized -Wstrict-prototypes ${CPU_X_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations ${CPU_X_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CPU_X_DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CPU_X_DEBUG_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now") include(CheckCCompilerFlag) check_c_compiler_flag("-no-pie" HAS_NO_PIE) if(HAS_NO_PIE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie") endif(HAS_NO_PIE) # Options option(WITH_GTK "Build support for GUI in GTK3+" ON) option(WITH_NCURSES "Build support for TUI in NCurses" ON) option(WITH_GETTEXT "Build support for internationalization" ON) option(WITH_LIBCURL "Use Libcurl library" ON) option(WITH_LIBJSONC "Use Libjson-c library" ON) option(WITH_LIBCPUID "Use Libcpuid library" ON) option(WITH_LIBPCI "Use Libpci library" ON) option(WITH_LIBPROCPS "Use Libprocps library" ON) option(WITH_LIBSTATGRAB "Use Libstatgrab library" ON) option(WITH_DMIDECODE "Built-in Dmidecode" ON) option(WITH_BANDWIDTH "Built-in Bandwidth" ON) option(FORCE_LIBSTATGRAB "Force use of Libstatgrab instead of Libprocps (GNU/Linux system)" OFF) option(PORTABLE_BINARY "Build a all-in-one binary (portable version)" OFF) option(IGNORE_STATICLIBS "Build portable binary without static libraries" OFF) # Colours string(ASCII 27 Esc) set(ColourReset "${Esc}[m") set(ColourBold "${Esc}[1m") set(Red "${Esc}[31m") set(Green "${Esc}[32m") set(Yellow "${Esc}[33m") set(Blue "${Esc}[34m") set(Magenta "${Esc}[35m") set(Cyan "${Esc}[36m") set(White "${Esc}[37m") set(BoldRed "${Esc}[1;31m") set(BoldGreen "${Esc}[1;32m") set(BoldYellow "${Esc}[1;33m") set(BoldBlue "${Esc}[1;34m") set(BoldMagenta "${Esc}[1;35m") set(BoldCyan "${Esc}[1;36m") set(BoldWhite "${Esc}[1;37m") ### MACROS # Macro: print_config(libname foundstate withstate) # Print the state of CPU-X features: in bold green if enabled, else bold red. # @libname: library name (e.g. GTK) # @libver: library version (e.g. XXXXX_VERSION) # @foundstate: the result of pkg_check_modules(...) (e.g. XXXXX_FOUND) # @withstate: the CMake option which allows to disable this feature (e.g. WITH_XXXXX) macro(print_config libname libver foundstate withstate) if(${foundstate} AND ${withstate}) message("${BoldCyan}** ${libname}${ColourReset}\tsupport is ${BoldGreen}enabled${ColourReset}") add_definitions(-DHAS_${libname}=1 -D${libname}_VERSION="${libver}") else(${foundstate} AND ${withstate}) if(NOT ${withstate}) message("${BoldCyan}** ${libname}${ColourReset}\tsupport is ${BoldRed}disabled${ColourReset} (explicitly disabled)") elseif(NOT ${foundstate}) message("${BoldCyan}** ${libname}${ColourReset}\tsupport is ${BoldRed}disabled${ColourReset} (not found by pkg-config)") endif() add_definitions(-DHAS_${libname}=0 -D${libname}_VERSION=NULL) endif(${foundstate} AND ${withstate}) endmacro(print_config) # Macro: add_embedded_library(lib) # Include a library (satic or not) for building, needed for portable version. # @LIBRARIES: variable name where to put libraries name # @lib: library to add macro(add_embedded_library LIBRARIES lib) if(PORTABLE_BINARY AND NOT IGNORE_STATICLIBS) set(${LIBRARIES} ${lib}) endif(PORTABLE_BINARY AND NOT IGNORE_STATICLIBS) endmacro(add_embedded_library) # Macro: add_embedded_library_linux(linux_lib) # Same as add_embedded_library macro, but only if target is Linux # @LIBRARIES: variable name where to put libraries name # @linux_lib: Linux library to add macro(add_embedded_library_linux LIBRARIES linux_lib) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND PORTABLE_BINARY AND NOT IGNORE_STATICLIBS) set(${LIBRARIES} ${linux_lib}) endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND PORTABLE_BINARY AND NOT IGNORE_STATICLIBS) endmacro(add_embedded_library_linux) # Macro: add_embedded_library_others(others_lib) # Same as add_embedded_library macro, but only if target is NOT Linux # @LIBRARIES: variable name where to put libraries name # @others_lib: NON-Linux library name macro(add_embedded_library_others LIBRARIES others_lib) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND PORTABLE_BINARY AND NOT IGNORE_STATICLIBS) set(${LIBRARIES} ${others_lib}) endif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND PORTABLE_BINARY AND NOT IGNORE_STATICLIBS) endmacro(add_embedded_library_others) ### HELPERS / SUBDIRECTORIES find_package(PkgConfig REQUIRED) find_package(Threads REQUIRED) find_package(Backtrace REQUIRED) if(WITH_GETTEXT) find_package(Gettext) if(${CMAKE_VERSION} VERSION_GREATER "3.1") find_package(Intl) endif(${CMAKE_VERSION} VERSION_GREATER "3.1") endif(WITH_GETTEXT) include(CheckSymbolExists) add_subdirectory(po) add_subdirectory(src) add_subdirectory(data) ### 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 ) CPU-X-3.2.4/COPYING000066400000000000000000001045131341671471500134240ustar00rootroot00000000000000 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 . CPU-X-3.2.4/ChangeLog000066400000000000000000000253701341671471500141460ustar00rootroot00000000000000v3.2.4 (01.13.2019): - Changes: * Build portable binary without PIE * Improve AppImage experience * Use GitHub API to check new version (libjson-c) * Deprecate the portable version - Fixes: * Wrong GPU clocks with AMDGPU driver * Empty memory bank label * Build without gettext v3.2.3 (07.01.2018): - Removed feature: * Support for CMake < 3.0 - New features: * `TEXTDOMAINDIR`/`TERMINFO` support * Add AppData metainfo file * NVIDIA Bumblebee support - Changes: * Patch Dmidecode to v3.1.20180620 v3.2.2 (05.03.2018): - Changes: * Update CPU database - Fix: * Segfault when retrieving AMD GPU temperature v3.2.1 (03.24.2018): - Removed feature: * Drop 32-bit portable version for future releases - Changes: * Switch Cache and Swap colors in System tab - Fixes: * Swap bar in NCurses TUI * Bug in Bandwidth related to AVX instructions v3.2.0 (01.31.2018): - Translations: * Add Polish translation (thanks to eloaders) * Add Russian translation (thanks to TotalCaesar659) * Add Czech translation (thanks to pavelb) * Add Chinese translation (thanks to 高垚鑫) - Removed feature: * Support for libcpuid < 0.4.0 - New features: * Add ability to read CPUID raw file (CPUX_CPUID_RAW environment variable) * Add --issue-fmt argument * Allow to enforce BCLK (CPUX_BCLK environment variable) * New GTK theme for Dark themes * Retrive CPU frequency in fallback mode * Add GPU usage and GPU clocks in Graphics tab - Changes: * Update CPU database * Display influenceable environment variables in help * Display CPU family/model in hex only * Add a second line for Instructions label * Improve CPU temperature and voltage retrieval in fallback mode * Improve GPU temperature retrieval * Rework GPU detection and improve multi-GPU support * Patch Dmidecode to v3.1.20180131 * Patch Bandwidth to v1.5.1 - Fixes: * SSE3 feature detection * Cache labels format * --nocolor option * Set window icon in GTK GUI * cpu-x_polkit command on Wayland (used by cpu-x-root.desktop) * Buffer overflow in some cases when Dmidecode is called v3.1.3 (10.25.2016): - Translations: * Add Russian translation to shortcuts (thanks to TotalCaesar659) - Changes: * Add more AMD Kaveri CPUs in database * Print CPUID raw dumps when using --dump --verbose - Fixes: * Segfault in call_libcpuid_static() * GTK GUI theme v3.1.2 (10.23.2016): - New feature: * Allow to set Bclk through CPUX_BCLK environment variable - Changes: * Avoid to refresh Bclk and minimum/maximum CPU multipliers * Rework CPU multipliers calculation * Add AMD Tyler CPUs in database * Reorganize databases - Fixes: * Segfault caused by free_multi() * Socket detection in fallback mode * Kernel module load in fallback mode v3.1.1 (10.16.2016): - Fixes: * Bandwidth build on system without stropts.h * Segfault in cpu_multipliers_fallback() * Asking for update when already up-to-date in portable version * Dynamic allocation checking * Memory leaks v3.1.0 (09.24.2016): - Removed features: * Support for libcpuid < 0.3.0 * Support for GTK 3.8 & 3.10 - Changes: * Patch Dmidecode to 3.0.20160907 * Rebase Bandwidth on v1.3.1 * Decrease Dmidecode verbosity with --verbose * Merge Descriptor label in Size label in Caches tab * Hide absent cache levels in Caches tab in GTK GUI * Hide empty pages in GTK GUI * Refactor Memory tab * Various minor core enhancements - New features: * Libcurl support * Libarchive support in portable version * Add support for L4 cache in Caches tab * Add --tab option - Fixes: * Broken redirection with --dump * Memory leaks * Bandwidth build with -DWITH_LIBCPUID=0 * Set speed to 0 for unavailable Bandwidth tests v3.0.1 (08.23.2016): - Changes: * Add more CPU and sockets in database * Decrease verbosity in Dmidecode and Bandwidth * Improve fallback mode - Fixes: * Refresh in fallback mode * Detection of GPU temperature with NVIDIA proprietary driver * Check for a new version when network is unreachable * Various minor fixes v3.0.0 (06.15.2016): - Build: * More CMake improvements, allow to build with CMake 2.8 - Removed features: * Drop support for Darwin/Mac OS X * Report CPU BogoMIPS value - New features: * Report total CPU usage * Add a signal handler to provide backtrace on crash * Add --nocolor option * Add --cachetest option * Add --bandwidth option * Add --core option * Add a Bench tab - Changes: * Full core rewrite * Improve options parsing * Rewrite update module for portable version + add --update option * Rewrite NCurses UI + add color support + add help * CPU-X logo redesign * Patch dmidecode with latest source code (commit cff11af) * Rebase bandwidth on v1.1 * Recognize more CPUs for the "Technology" label in CPU tab * Print some values > 9 in hexadecimal in CPU tab * More fallback support * More strings in --verbose mode * A lot of GTK UI tweaks * Run bandwith in a separate thread to avoid UI slowdown v2.2.2 (12.02.2015): - Change: * Add technology report for some Clarksfield & Richland CPUs - Fixes: * Avoid to free dynamic labels in Caches tab * Free memory when possible in pcidev() function * Fix a buffer overflow on HT detection, causing bug in bandwidth v2.2.1 (11.27.2015): - Build: * Add debugs symbols in bandwidth source code when using CMAKE_BUILD_TYPE=Debug - Fixes: * Segfault on NULL pointer in bandwidth() * Buffer overflow when setting label name in Caches tab v2.2.0 (11.21.2015): - New features: * Add support for libcpuid 0.2.2 * Add new tab Caches * Add labels Technology, Voltage and Temp in CPU tab * Add lebel Temperature in Graphics tab - Changes: * Some changes in options parsing * Update to dmidecode 3.0 * In NCurses TUI, add tab names * Merge Architecture label in Instructions label in CPU tab * Merge GPU driver with GPU vendor in Graphics tab * Update GUI for GTK >= 3.8 and < 3.14 - Fixes: * Typo * L3 cache value * Some problems with libdmi_fallback() * .desktop files * Build with Clang * Stop update if curl is missing v2.1.1 (08.26.2015): - New features: * Add translations support in portable version * Add HyperThreading detection * Option --version informs if a new version is available * Add an auto-update module for portable version - Translations: * Add pt_BR translation (thanks to ShyPixie) * Improve translations support (rewrite target updatepo, add target newpo...) - Change: * Some text changes in --verbose mode - Fixes: * Segfault with strdup() on NULL pointer * Avoid multipliers "(0 - 0)" in CPU tab and "-nan" values in System tab * Fixes garbages after freeing * Some problems with build * Do changes to enable compilation with libpci.a in portable version v2.1.0 (08.08.2015): - New features: * Add libsystem * Add a button to change GTK GUI color * Add new chipset section in Motherboard tab * Add new tab Graphics * GTK 3.14 support / partial GTK 3.16 support - Changes: * Improve drawing bars in System tab in GTK GUI * Use dynamic arrays instead of static arrays * Use GResource instead of GdkPixbuf in GTK embedded GUI - Fixes: * Build * Options * Deprecated functions in GTK GUI code v2.0.3 (03.15.2015): - Build: * Remove RPATH * Add 'make' target uninstall to allow to properly uninstall CPU-X * Add 'make' target genpot to generate a pot file * Add 'make' target updatepo to update a po file from a newer pot file - New features: * Add verbose mode (for CPU-X, previously Dmidecode only) * Colorized messages * Add a 'Run as root' button in GTK GUI - Changes: * Better support for non-Linux OS * Improve displaying of memory usage in System tab - Fixes: * Stop spam errors (in Dmidecode) * Options when built without GTK * Incomplete possibility for translation * Output messages (verbose and error) v2.0.2 (02.08.2015): - New feature: * Add argument --dmidecode to run (internal) Dmidecode alone - Changes: * Rebase dmidecode code on 2.12 * Improve options parsing * Less (useless) function recalls on refresh loop * Display dashes for empty banks in RAM tab - Fix: * Empty RAM tab on certain machines v2.0.1 (11.23.2014): - Build: * Add more static libraries in portable binary - New feature: * Add possibility to resize terminal with NCurses TUI - Changes: * Better CPU multiplier calculation * Don't show non-existent banks in tab RAM * Better compiler detection * Improve option --help * Better translation support - Fixes : * NCurses TUI: correct refresh (when left key/button 3 on mouse are spammed) * NCurses TUI: segfault when spamming right key * GTK GUI/NCurses TUI: use timeout instead of new thread to refresh * Segfault when file '/etc/os-release' could not be open v2.0.0 (11.16.2014): - New features: * Add argument --dump (no start GUI) * Add fallback mode for Libdmi (but it not replaces Libdmi) * Add new tab System * Add new tab RAM * Add support for translations (only French available) * Add CPU-X launchers (depends of GTK); cpu-x.desktop and cpu-x-root.desktop * Add possibility to run CPU-X as root with pkexec * Add more CPU vendor logos - Changes: * Big changes in core * Full rewrite GTK GUI * Minor changes in NCurses TUI - Fixes: * Segfault when compiling with target Release * Memory leak (with function get_path) v1.2.2 (11.05.2014): - New feature: * Add argument --verbose (set Dmidecode verbose) - Change: * Print nothing on impossible values (Caches section) - Fixes: * Stop distort GTK GUI when label length is large * Stop spam errors (about CPU frequencies) * Typos (BogoMIPS, CPU Vendor, label Manufacturer) v1.2.1 (10.24.2014): - New features: * Add arguments support (--no-gui, --version, --help) * Add support for custom refresh time (--refresh) - Changes: * Rewrite error messages * Restructuration of files and functions in files - Fixes: * Segfault when compiling without GTK & embeded * Unwanted characters in NCurses * Compilation with CMake v1.2.0 (10.12.2014): - Build: * Add possibility to disable GTK/NCurses/Libcpuid/Libdmi before compiling - New feature: * Add NCurses mode - Fixes: * CPU multipliers calculation * Relative path of file on error * Segfault on unknown multiplier * Unwanted characters v1.1.0 (09.28.2014): - Build: * Change build system from Makefile to CMake * Add possibility to change install prefix - Changes: * Remove calls to external command 'dmidecode', use provided library instead of * Remove calls to external command 'lscpu' v1.0.0 (09.21.2014): * Initial release CPU-X-3.2.4/README.md000066400000000000000000000130711341671471500136460ustar00rootroot00000000000000 [![](https://github.com/X0rg/CPU-X/blob/master/data/icons/CPU-X_22x22.png?raw=true)](https://x0rg.github.io/CPU-X/) [![GitHub release](https://img.shields.io/github/release/X0rg/CPU-X.svg)](https://github.com/X0rg/CPU-X/tags) [![GitHub downloads](https://img.shields.io/github/downloads/X0rg/CPU-X/latest/total.svg)](https://github.com/X0rg/CPU-X/releases/latest) [![GitHub total downloads](https://img.shields.io/github/downloads/X0rg/CPU-X/total.svg)](https://github.com/X0rg/CPU-X/releases) [![GitHub issues](https://img.shields.io/github/issues/X0rg/CPU-X.svg)](https://github.com/X0rg/CPU-X/issues) [![Build Status](https://travis-ci.com/X0rg/CPU-X.svg?branch=master)](https://travis-ci.com/X0rg/CPU-X) CPU-X is a Free software that gathers information on CPU, motherboard and more. CPU-X is similar to [CPU-Z (Windows)](https://www.cpuid.com/softwares/cpu-z.html), but CPU-X is a Free and Open Source software designed for GNU/Linux; also, it works on *BSD. This software is written in C and built with [CMake](https://www.cmake.org/) tool. It can be used in graphical mode by using GTK or in text-based mode by using NCurses. A dump mode is present from command line. *** # Table of contents * [Dependencies](#dependencies) * [Build-only dependencies](#build-only-dependencies) * [Build and run dependencies](#build-and-run-dependencies) * [Download/Install](#downloadinstall) * [Download packages](#download-packages) * [Manual build](#manual-build) * [Portable version](#portable-version) * [Usage](#usage) * [Screenshots](#screenshots) * [Translate/Contributions](#translatecontributions) * [Troubleshooting](#troubleshooting) * [Bugs/Improvements/Request features](#bugsimprovementsrequest-features) * [Links](#links) *** ## Dependencies ### Build-only dependencies These dependencies are needed to **build** CPU-X: * A C compiler ([GCC](https://gcc.gnu.org/) or [Clang](https://clang.llvm.org/)) * [CMake](https://www.cmake.org/) * [Pkg-Config](https://www.freedesktop.org/wiki/Software/pkg-config/) / [Pkgconf](https://github.com/pkgconf/pkgconf) * [NASM](http://www.nasm.us/) ### Build and run dependencies These dependencies are needed to **build¹** and **run** CPU-X: * [GTK3+](https://www.gtk.org/) (version 3.12 or newer is needed) * [NCurses](https://www.gnu.org/software/ncurses/) * [Libcpuid](http://libcpuid.sourceforge.net/) (version 0.3.0 or newer is needed) * [Pciutils](https://mj.ucw.cz/sw/pciutils/) * [Procps-ng](https://sourceforge.net/projects/procps-ng/) (Linux) / [Libstatgrab](https://www.i-scream.org/libstatgrab/) (*BSD) * [Curl](https://curl.haxx.se/) * [JSON-C](https://github.com/json-c/json-c) **¹**On some GNU/Linux distributions, the appropriate **-dev** or **-devel** package is needed. ## Download/Install ### Download packages You can download binary packages to easily install CPU-X on your system. A lot of distributions are supported, see the [download section](https://github.com/X0rg/CPU-X/releases/latest) or the wiki page about [GNU/Linux packages](https://github.com/X0rg/CPU-X/wiki/GNU-Linux-Packages). ### Manual build For step-by-step guide, you can see this [wiki page](https://github.com/X0rg/CPU-X/wiki/Manual-build). If you need to disable some parts of CPU-X, you can read [this page](https://github.com/X0rg/CPU-X/wiki/Modular-components). To build and install CPU-X on your system, do (in CPU-X directory) : ``` $ mkdir build && cd build $ cmake .. $ make # make install ``` By default, CPU-X will be installed in */usr/local*. If you want to change it, add option `cmake -DCMAKE_INSTALL_PREFIX= ..` on CMake invocation. ### Portable version CPU-X is available in a portable version (Linux 32/64-bit, FreeBSD 32/64-bit), like CPU-Z. You can find the lastest release [**here**](https://github.com/X0rg/CPU-X/releases/latest). The CPU-X_vx.x.x_portable.tar.gz tarball requires GTK is installed on your system. The CPU-X_vx.x.x_portable_noGTK.tar.gz tarball requires to start CPU-X from a terminal. After downloading tarball, you need to extract his content to be able to run CPU-X portable. Check if binary has executable bit set. You can use this portable version on a lot of system, so you can leave a binary on a USB stick for instance. ## Usage Start program with **root privileges** allows CPU-X to access some special devices, minimizing empty labels count. Application is put in the desktop menus, in **System Tools** category: entry *CPU-X* run CPU-X as regular user, and entry *CPU-X (Root)* grant root privileges. Else, you can use command `cpu-x`, or double-click on `cpu-x` binary is also possible (if program won't start, check if file has executable bit set). If GTK and NCurses are supported, you can start CPU-X in NCurses mode by taping in a shell (as root) `cpu-x --ncurses`. Use `cpu-x --help` for other commands and help. ## Screenshots You can find screenshots in [gallery](https://github.com/X0rg/CPU-X/wiki/Screenshots). ## Translate/Contributions You want to have CPU-X in a foreign language but no translation exists? See this [wiki page](https://github.com/X0rg/CPU-X/wiki/Translate). Or you want to contribute to CPU-X? In the top-right corner of the page, click on the **Fork** button. ## Troubleshooting Refer to the dedicated [FAQ](https://github.com/X0rg/CPU-X/wiki/FAQ) page. ## Bugs/Improvements/Request features Please [open a new issue](https://github.com/X0rg/CPU-X/issues/new) and fill template. You can remove italic text. ## Links Official [webpage](https://x0rg.github.io/CPU-X/) made by GitHub Pages. Official [wiki](https://github.com/X0rg/CPU-X/wiki), still on GitHub. CPU-X-3.2.4/cmake_uninstall.cmake.in000066400000000000000000000021571341671471500171520ustar00rootroot00000000000000# See: http://www.cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 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}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) file(REMOVE_RECURSE @CPU_X_DATA_DIRECTORY@) CPU-X-3.2.4/data/000077500000000000000000000000001341671471500132765ustar00rootroot00000000000000CPU-X-3.2.4/data/CMakeLists.txt000066400000000000000000000031771341671471500160460ustar00rootroot00000000000000project(data LANGUAGES NONE ) # Files needed by GTK GUI if(WITH_GTK AND NOT PORTABLE_BINARY) # Set config file(MAKE_DIRECTORY ${CMAKE_DATA_OUTPUT_DIRECTORY}) set(EXEC ${CMAKE_INSTALL_FULL_BINDIR}/${CMAKE_PROJECT_NAME}) set(TRYEXEC ${EXEC}) configure_file(cpu-x.desktop.in ${CMAKE_DATA_OUTPUT_DIRECTORY}/cpu-x.desktop) configure_file(org.pkexec.cpu-x.policy.in ${CMAKE_DATA_OUTPUT_DIRECTORY}/org.pkexec.cpu-x.policy) configure_file(cpu-x_polkit.in ${CMAKE_DATA_OUTPUT_DIRECTORY}/cpu-x_polkit) set(EXEC ${EXEC}_polkit) configure_file(cpu-x-root.desktop.in ${CMAKE_DATA_OUTPUT_DIRECTORY}/cpu-x-root.desktop) # Install UIs install(FILES cpu-x-gtk-3.12.ui cpu-x-gtk-3.12.css cpu-x-gtk-3.12-dark.css cpu-x-gtk-3.20.css cpu-x-gtk-3.20-dark.css DESTINATION ${CPU_X_DATA_DIRECTORY}/ ) # AppData metainfo file install(FILES cpu-x.appdata.xml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/metainfo/ ) # Install launchers install(FILES ${CMAKE_DATA_OUTPUT_DIRECTORY}/cpu-x.desktop ${CMAKE_DATA_OUTPUT_DIRECTORY}/cpu-x-root.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/applications/ ) # Install policy rule install(FILES ${CMAKE_DATA_OUTPUT_DIRECTORY}/org.pkexec.cpu-x.policy DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/polkit-1/actions/ ) # Install binary which can run CPU-X as root via Polkit install(FILES ${CMAKE_DATA_OUTPUT_DIRECTORY}/cpu-x_polkit DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) add_subdirectory(icons) add_subdirectory(logos) endif(WITH_GTK AND NOT PORTABLE_BINARY) CPU-X-3.2.4/data/cpu-x-gtk-3.12-dark.css000066400000000000000000000001741341671471500171310ustar00rootroot00000000000000GtkBox#footer_box { background-color: rgb (76, 153, 230); } GtkLabel#value, GtkProgressBar { color: rgb (128, 128, 0); } CPU-X-3.2.4/data/cpu-x-gtk-3.12.css000066400000000000000000000001721341671471500162100ustar00rootroot00000000000000GtkBox#footer_box { background-color: rgb (76, 153, 230); } GtkLabel#value, GtkProgressBar { color: rgb (0, 0, 128); } CPU-X-3.2.4/data/cpu-x-gtk-3.12.ui000066400000000000000000013623511341671471500160500ustar00rootroot00000000000000 True False CPU-X False center True False vertical True True True True True False vertical True False 6 6 4 6 0 out True False 6 6 6 True False end True False vertical 2 True False end 4 1 1 True 1 False True 0 True False end 4 1 1 True 1 False True 1 True False end 4 1 1 True 1 False True 2 True False end 4 1 1 True 1 False True 3 True False end 4 1 1 True 1 False True 4 True False end 4 1 1 True 1 False True 5 True False end 4 1 1 True 1 False True 6 True False end 4 1 1 True 1 False True 7 False True 0 True False vertical True False True False vertical True False 1 1 0 in True False center True end 30 True 30 1 False False 0 True False 1 1 0 in True False center True end 30 True 30 0 False False 1 True False 1 1 0 in True False center True end 30 True 30 1 False False 2 True False True False 1 1 0 in True False center True end 9 True 9 1 False False 0 True False 1 1 0 in True False center True end 9 True 9 1 False True end 1 True False 1 1 True 1 False True 2 end 3 False True 3 False False 0 True False 4 2 0 True True 1 False False 0 True False 1 1 0 in True False True center True end 43 True 43 1 False False 1 True False True False 1 1 0 in True False center True end 7 True 7 1 0 0 True False 1 1 0 in True False center True end 7 True 7 1 0 1 True False 1 1 0 in True False center True end 7 True 7 1 2 0 True False 1 1 0 in True False center True end 7 True 7 1 2 1 True False end 6 4 1 1 True True 1 1 0 True False end 6 4 1 1 True True 1 1 1 True False end 6 4 1 1 True True 1 3 0 True False 1 1 0 in True False center True end 7 True 7 1 4 0 True False 1 1 0 in True False center True end 7 True 7 1 4 1 True False end 6 4 1 1 True True 1 3 1 False False 2 True False 1 0 in True False True True end 43 43 2 False False 3 False False 1 True False Processor False True 0 True False True False 6 6 6 True 0 out True False 6 6 6 True False end True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False end 4 1 1 True 1 0 2 True False end 4 1 1 True 1 0 3 True False 1 1 0 in True False center True end 11 True 0.0099999997764825821 11 1 1 0 True False 1 1 0 in True False center True end 11 True 11 1 1 1 True False 1 1 0 in True False center True end 11 True 11 1 1 2 True False 1 1 0 in True False center True end 11 True 11 1 1 3 True False Clocks False True 0 True False 6 6 True 0 out True False 6 6 6 True False end True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False end 4 1 1 True 1 0 2 True False end 4 1 1 True 1 0 3 True False 1 1 0 in True False center True end 18 True 18 1 1 0 True False 1 1 0 in True False center True end 18 True 18 1 1 1 True False 1 1 0 in True False center True end 18 True 18 1 1 2 True False 1 1 0 in True False center True end 18 True 18 1 1 3 True False Cache False True 1 False True 1 True False 6 6 8 0 out True False 6 6 6 True False True False end 6 4 1 1 Socket(s) True 1 1 0 True False end 6 4 1 1 True Core(s) True 1 3 0 True False end 6 4 1 1 True Thread(s) True 1 5 0 True False 1 1 0 in True False center True end 3 True 3 1 2 0 True False 1 1 0 in True False center True end 5 True 5 1 4 0 True False 1 1 0 in True False center True end 5 True 5 1 6 0 True False 4 1 1 0 0 True False 1 False True 2 True False CPU 1 False True True False True False 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False L1 Cache 0 0 True False 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False L2 Cache 0 1 True False 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False L3 Cache 0 2 True False 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False L4 Cache 0 3 True False 6 6 4 6 0 out True False 6 6 6 6 6 True False True False Test 0 4 1 True False Caches 1 False True False vertical True False 6 6 4 6 0 out True False 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False 1 1 0 in True False True center True end 40 True 40 1 1 2 True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False end 4 1 1 True 1 0 2 True False Motherboard False True 0 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False 1 1 0 in True False True center True end 40 True 40 1 1 2 True False 1 1 0 in True False True center True end 40 True 40 1 1 3 True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False end 4 1 1 True 1 0 2 True False end 4 1 1 True 1 0 3 True False BIOS False True 1 True False 6 6 4 6 0 out True False 6 6 6 True False end True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False Chipset False True 2 2 True False Motherboard 1 2 False True True in True False True False True False 6 6 4 6 0 out True False 6 6 6 True False end True False 1 1 0 in True False True center True end 40 40 2 1 0 True False end 4 4 1 1 True 1 0 0 True False Bank 0 0 0 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 1 0 1 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 2 0 2 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 3 0 3 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 4 0 4 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 5 0 5 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 6 0 6 True False 6 6 4 6 0 out True False 6 6 6 True False end True False 4 1 1 True 0 0 True False 1 1 0 in True False True center True end 40 40 2 1 0 True False Bank 7 0 7 3 True False Memory 1 3 False True False vertical True False 6 6 4 6 0 out True False 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False 1 1 0 in True False True center True end 40 True 40 1 1 2 True False 1 1 0 in True False True center True end 40 True 40 1 1 4 True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False end 4 1 1 True 1 0 2 True False end 4 1 1 True 1 0 4 True False 1 1 0 in True False True center True end 40 True 40 1 1 3 True False end 4 1 1 True 1 0 3 True False Operating System False True 0 True False 6 6 4 6 0 out True False 6 6 6 True False end True False end 4 1 1 True 1 0 0 True False end 4 1 1 True 1 0 1 True False end 4 1 1 True 1 0 2 True False end 4 1 1 True 1 0 3 True False 4 1 1 0 in True False True right True end 18 True 18 1 1 0 True False 4 1 1 0 in True False True right True end 18 True 18 1 1 1 True False 4 1 1 0 in True False True right True end 18 True 18 1 1 2 True False 4 1 1 0 in True False True right True end 18 True 18 1 1 3 True False end 4 1 1 True 1 0 4 True False 4 1 1 0 in True False True right True end 18 True 18 1 1 4 True False 1 1 0 in 172 21 True False 2 0 True False 1 1 0 in 172 21 True False 2 1 True False 1 1 0 in 172 21 True False 2 2 True False 1 1 0 in 172 21 True False 2 3 True False 1 1 0 in 172 21 True False 2 4 True False Memory False True 1 4 True False System 1 4 False True True in True False True False True False 6 6 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False end 4 4 1 1 True 1 0 2 True False end 4 4 1 1 True 1 0 3 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 2 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 3 True False Card 3 0 3 True False 6 6 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False end 4 4 1 1 True 1 0 2 True False end 4 4 1 1 True 1 0 3 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 2 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 3 True False Card 2 0 2 True False 6 6 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False end 4 4 1 1 True 1 0 2 True False end 4 4 1 1 True 1 0 3 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 2 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 3 True False Card 1 0 1 True False 6 6 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False 1 1 0 in True False True center True end 40 True 40 1 1 0 True False 1 1 0 in True False True center True end 40 True 40 1 1 1 True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 True False end 4 4 1 1 True 1 0 2 True False end 4 4 1 1 True 1 0 3 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 2 True False True False 1 1 0 in True False center True end 12 True 12 1 False False 0 True False 1 1 0 in True False center True end 12 True 12 1 False True end 1 True False 1 1 middle True 18 1 False True 2 end 3 1 3 True False Card 0 0 0 5 True False Graphics 5 False True False vertical True False 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 350 True False 1 1 0.0099999997764825821 True end 1 0 True True 1 1 1 1 True False Prime numbers (slow) False True 0 True False 6 6 4 6 0 out True False 6 6 6 6 6 True False end True False end 4 4 1 1 True 1 0 0 True False end 4 4 1 1 True 1 0 1 350 True False 1 1 0.0099999997764825821 True end 1 0 True True 1 1 1 1 True False Prime numbers (fast) False True 1 True False 6 6 4 6 0 out True False 6 6 6 True False True True 1 1 True 0 number 3 0 True True 1 1 True False 0 number 1 0 True False end 4 1 1 True 0 0 True False end 4 1 1 True 2 0 True False Parameters False True 2 6 True False Bench 6 False True False vertical True False 6 6 4 6 0 out True False 6 6 6 True False vertical True False 10 10 False True 0 True False 4 center False True 1 False True 0 True False 6 6 6 0 out True False 6 6 6 True False vertical True False center 1 False True 1 True False center 1 False True 2 True False True False True 2 True False About False True 1 True False 6 6 6 0 out True False 6 6 6 True False vertical True False 10 False True 0 True False center False True 1 True False False True 2 GPL v3 True True True none https://www.gnu.org/licenses/gpl.txt False True 3 True False License False True 2 7 True False About 1 7 False False True 0 True False True True False 4 CPU-X 1 False True 0 True False 4 Version x.x.x 1 False True 1 OK True True True 8 False True 2 False True 1 CPU-X-3.2.4/data/cpu-x-gtk-3.20-dark.css000066400000000000000000000001631341671471500171260ustar00rootroot00000000000000box#footer_box { background-color: rgb (76, 153, 230); } label#value, progressbar { color: rgb (128, 128, 0); } CPU-X-3.2.4/data/cpu-x-gtk-3.20.css000066400000000000000000000001611341671471500162050ustar00rootroot00000000000000box#footer_box { background-color: rgb (76, 153, 230); } label#value, progressbar { color: rgb (0, 0, 128); } CPU-X-3.2.4/data/cpu-x-root.desktop.in000066400000000000000000000013151341671471500173130ustar00rootroot00000000000000[Desktop Entry] Name=CPU-X (Root) Name[cs_CZ]=CPU-X (s právy správce systému) Name[fr]=CPU-X (super-utilisateur) Name[ru]=CPU-X (с правами администратора) Comment=Gathers information on CPU, motherboard and more Comment[cs_CZ]=Shromažďuje informace o procesoru, základní desce a další Comment[fr]=Récolte des informations sur le CPU, la carte-mère et plus Comment[pt_BR]=Coleta informações sobre sua CPU, placa-mãe and mais Comment[ru]=Сбор информации о процессоре, материнской плате и др. Comment[zh]=收集有关 CPU 和主板等的信息 Exec=@EXEC@ TryExec=@TRYEXEC@ Icon=cpu-x Type=Application Categories=GTK;System; Terminal=false CPU-X-3.2.4/data/cpu-x.appdata.xml000066400000000000000000000024201341671471500164630ustar00rootroot00000000000000 cpu-x CC0-1.0 GPL-3.0+ CPU-X Gathers information on CPU, motherboard and more

CPU-X is a Free software that gathers information on CPU, motherboard and more. CPU-X is similar to CPU-Z (Windows), but CPU-X is a Free and Open Source software designed for GNU/Linux; also, it works on *BSD. This software is written in C and built with CMake tool. It can be used in graphical mode by using GTK or in text-based mode by using NCurses. A dump mode is present from command line.

cpu-x.desktop https://x0rg.github.io/CPU-X/ https://github.com/X0rg/CPU-X/issues https://www.transifex.com/xorg/cpu-x/translate/ https://camo.githubusercontent.com/9913692497ac88976d457f559f0283f3b82763dd/687474703a2f2f692e696d6775722e636f6d2f77695465656a332e706e67 cpu-x.desktop
CPU-X-3.2.4/data/cpu-x.desktop.in000066400000000000000000000010421341671471500163270ustar00rootroot00000000000000[Desktop Entry] Name=CPU-X Comment=Gathers information on CPU, motherboard and more Comment[cs_CZ]=Shromažďuje informace o procesoru, základní desce a další Comment[fr]=Récolte des informations sur le CPU, la carte-mère et plus Comment[pt_BR]=Coleta informações sobre sua CPU, placa-mãe and mais Comment[ru]=Сбор информации о процессоре, материнской плате и др. Comment[zh]=收集有关 CPU 和主板等的信息 Exec=@EXEC@ Icon=cpu-x Type=Application Categories=GTK;System; Terminal=false CPU-X-3.2.4/data/cpu-x.gresource.xml000066400000000000000000000020351341671471500170510ustar00rootroot00000000000000 cpu-x-gtk-3.12.ui cpu-x-gtk-3.12.css cpu-x-gtk-3.12-dark.css cpu-x-gtk-3.20.css cpu-x-gtk-3.20-dark.css logos/AMD.png logos/Centaur.png icons/CPU-X_original.png logos/Cyrix.png logos/Intel.png logos/NexGen.png logos/NSC.png logos/Rise.png logos/SiS.png logos/Transmeta.png logos/UMC.png logos/Unknown.png CPU-X-3.2.4/data/cpu-x_polkit.in000066400000000000000000000013471341671471500162510ustar00rootroot00000000000000#!/bin/sh if [ -n "$(command -v pkexec)" ]; then xhost_set=false if [ "$XDG_SESSION_TYPE" = "wayland" ] && [ -n "$(command -v xhost)" ] && ! xhost | grep -q 'SI:localuser:root\|LOCAL:'; then xhost si:localuser:root xhost_set=true fi if pkaction --action-id org.pkexec.cpu-x > /dev/null 2>&1 && command -v cpu-x | grep -qv "/tmp/.mount_CPU-X" ; then # CPU-X is installed on system pkexec --disable-internal-agent "@EXEC@" "$@" else # CPU-X is executed from AppImage pkexec --disable-internal-agent env DISPLAY="$DISPLAY" XAUTHORITY="$XAUTHORITY" "@EXEC@" "$@" fi status=$? if [ $status -eq 126 ] || [ $status -eq 127 ]; then "@EXEC@" "$@" fi if $xhost_set; then xhost -si:localuser:root fi else "@EXEC@" "$@" fi CPU-X-3.2.4/data/icons/000077500000000000000000000000001341671471500144115ustar00rootroot00000000000000CPU-X-3.2.4/data/icons/CMakeLists.txt000066400000000000000000000006551341671471500171570ustar00rootroot00000000000000project(icons LANGUAGES NONE ) # Icons file(GLOB icons CPU-X_*x*.png ) foreach(icon ${icons}) get_filename_component(filename ${icon} NAME_WE) string(REGEX REPLACE "CPU-X_" "" size "${filename}") install(FILES ${icon} DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/${size}/apps/ RENAME cpu-x.png ) endforeach() install(FILES CPU-X_original.png DESTINATION ${CPU_X_DATA_DIRECTORY}/ RENAME CPU-X.png ) CPU-X-3.2.4/data/icons/CPU-X_128x128.png000066400000000000000000000547511341671471500170040ustar00rootroot00000000000000PNG  IHDR>agAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>XIDATxڭwd}ifzf0 @Q")LӢ(^[ts=Z]ycyXgDIi L3+Wwq{]J{p]_ZO=q8}gӉySk4@St5JHﹳpqΡK'/wpe#ZœSᓿK dzƹf?dJF6VdI5Zkz=r//__> @Ny:[~2ZpULr oII}5tŗ_#=jfވ@i,^2g\knǚ ZH~_رc}Ay?et᯻ qcuCKÙ5JiiJxnN|bo<^jt,; 總 ETE TxY TsdHqBPx^!:X`,~=8aV,CR icE.fvjiOg+dʑ"3!ͳde:Aiv={rk;k2tUfޫf{=ޘc" V.KJ.06 %Vt$ؿcs8㞢Z# Ἆt^`Zrn~>? /=W\~e$9:w&"_#dlE 0\^V4Y{'3tnIUnCu8" 鈦g IU;VhR oq-=K+lFg*$PDRv"O~"ˬZgݼH,4eTkٵD^e޽$I/(sYT,N*V!'4BHd@ulib":D }_@񖄶bl0ͅ6v\ ZTJQ+&RM5k?F$)+g^V*'k1I>Њ8?xx`Gk';U&BXgK(xGfuD836̡D39_D \pU\ac>!-Z猒%8'"FRH}JoK rH+E#F<~oITA*@gS^|)^|;2c\oSpr(ՎҚ2kFDd Zc=$ @JfYhmGhM✦<%V /,ή!pI#Kje_Hʑ\"5#VIPN)-"he0HY;U V)hC(7=RkU(N Gx7{xw-QTH#EnMEVkhsѓh!(s@BӪ]X$W:Zk@ X?\i~heYTNr5Z)eZi (cDϕ"TkPDŽ<}BSe8M.\ɥ˗X[ϱt/)ÀbaB(KCYwᔉGHؽ{-oV)>m%\Ex/=Ua#h|P^CGΠ AZ,#-,5J+ˆSi`4u{O={ C>2@ǢS"rq@1ZX&*4/G?ˣt2e<0dKsŠz Aw PqDŽ # 7 LVZSE:=emE5B@r6#w9ժU>|w<;y3_S<1F1R3y,WA4ZRks!KV+~>R{ngU_Jy2Zaˋ*J$wcqbfhBTnsIO!JE>]- Qp6Z')=5(!|/_.k[dZx0[[')9W],K$y&RC$iZR_&}Wz-l%Ɗ~=3Ōw-a0{ :yT@*}h5&k 2M)F ʚ$2a@:{'%ZVx{! A?I K{;W'NBg΢C}Dž. O@=]`I/,h| ~֔! Rrj&Omtf4 R4&@X+H~%{PYڇJ;TUQ#0X>M!zjAϼ8F Rg(g9Y6%s* fѰϴF#h)IeB;_6lVYK;:F㉁1ܨ7HӊW[dLM|8φFyOJk{obƂ;!к Y8C kT☵$39*ZMAV#NHVTU!IR% G9"/'bùy;~hYٵ$A] BP⛛7\M'iH""cYEdKV*7@5q8Es9.&y iI54瑏Ia-ڨ8b+3|!$2w;'42\;fmlh4f<ؠ0 yf;Z@F:BgfX+IY–0uLH562 Jxh Bi*B20@Lq Il 5 N//+Y:b./YJ0@ksɄu]npHe^tgqɄ,˼)$MS1Ʉ<7%U{RHA01L\Iᵃ (Hl`^O=LưuZ4YX,\׮caK9:m=ùu|Fg/NK -Zv8L7oɓ⋜9s˗/s :s†=Aɇnͥ%<XE+КbCh-*ܨaqhW:cŗoL±U0Wo3LF\~ .puv=VhҧNc>ۼ] ;MrX}щsdR$I!j &DF9WXbCM=! ( R&(@T +ku]2ab3)0Y$ 8 )l'low =pJB^ZxOS2 rsJryxmdp{~CJ<^TM(*Q^e}Ҫ g8s8Uuzt!ۼȴ9qH@<7bM3X02 .}JCڥp~^T*ϳH^Gd2tF(C~&:7Q6I/=z{[z$1?d<"՗9 զj: 1 ކEni`c({zA֌cFU7 dYm~m?wInRj5F'Ȳh_JD$̲Ns(NQ=c᷀GK!pQ=bQ A>Gc~dmŷ{_}ٻvj_[[xQ"A4^o,W%,Es2r"wu_yn\KԸa5 22447 Bbh+F"v!J;_]n?=ǍUCxO~/~K|o64jX$?g (X\_z AFCl`*Dkn\F>>f_;lw7w0@g&rn{&:ۘsn1).~_%\*BfskŪhDŋc8w}|49y/_hpdxA4haQ1V9y|ʶL例ot ȩ|b4¸`m^{0L X!ZFDPʍ;0ƉlmnAɓ=5&0Π՚K<9{ujՄvZfښ\CtZ:(GyB/jGAJ!DH#㴩+Q9jGOG \Yk$kM;g:t:lSz%SMPM5gN 曯Z8Þ=kSЧZ~4O*0Asá}ES!3b5sٔy i ChMh* \vxuTb%>_kQȢTH= $")8(2E̬dYƅ~39>ȘZ-]f<{BHwWN?Ǐ%0~R i50@e6^-e"8ᑹ\$ڍq` kXT`7UwM^nbFj]٩.w$J_sN<?- >ZQC ^R/+3h>ki6_96ؑ!l1LQE>'cǥ玟z ?ʃY6G#tٱM EJ,>#%B'N#QfDR؉zpbE@[͑1MNB`N-ia\ FKU_}.{&c/;@#%_Z!fw|$L3q0W9C Wz9:lcY-x]x%eaN{Ufut2ѐi)6SP %Q°]L}o:+:u$Iسg{/NpR9}[9tbai,E)z严,Dlҥq1JP9 ''ΆвHµFfʵV Z+eJ)IQ+WXY]e0PV'~r5uu ll)"WocLw==ȑ#yx89Gؾ!P8GljfJ"9.pcC)X bǕ<f,:A-+@?:>,Ƶ+={m>?0 c?`ؼޙ i FW֚잟cyy={jT*9rCq]FRa׮]Е=8ߴ GL9 x!m >~_i H"twb[v:E-`#L(ړuDr"Ln8#yÉ=:~87n`{{x̃>H@)EdajVVV Zl6giiVEѠ^ȻnN8ysMֶ_d/\3}&S#fE!OF!_`{25YoiBƭ`qHLStaNN%nA78D}'"vW_}Mi4oGJj5Zm5loo3NPyբll6}G>~w-,#nRhV7 #=xVǔ`sCj\~5p2 3A,:(3Gl'hM85x\7g?Ly饗~g'x7MloB/T*4 h۞4ȑ#|w~wPJ1$Ijٻט˪@2:KaC 3Ć ͯ9}n 2wǤ8=a MO/~-;u\ 臩V!k̓Xw}ᲰZ>EC̈ |*o~:"U3^,Qj$e&,A!/++~wͻn;IV~ATU&gzC;GC{վhZFVؿ 7HHGZ;8_GyDOyeMѺ fJwyt4=^( PD9bSew9Q]e(.S^3맽O&~~}y"V!v?2UUOjռ//o|NU`_Vy8t6d;$Dh7G`G'Q1JiFW5֪CZ|C{JT00ĆŅ7yѯr .xWJ˿$'<ciZF^^{:fwtѣG?N^mSz$IȲpH?>++7,_o,IMȒJ@ho\0Ba3֭["ǿYf0'#Ki3` X%QVNSWa_aii}s,,,x~4-^TT*^RgIC|nQܜ-& ZYY?xiQV 9,|,y|+хSj,-1QDVUե83*)Бw)'} #)9.^_Eqc?;VFR/k ;?H$m3apN83gkc3 2G7y#ރqiH}WO9iQyÄ `0ĉSt:K8N~"+8~2q6P[Ŕ/v(/b!]g)n 5%p#!+e $S%w?Jd믟f}}ݫ|#<;- 1C܊y9Ʉw]ٳ4MYZZb׮]{S0  N8ō74Cq0Za?s<5ZSz1 j&=M{Xs3ء"(]lV_gyƹsX]]ekkx̾}ԧ>EVIO3!;6Ʉݻw㏣f׮]ݻk)%Y1c9qTQ󛂓(Zp2Y~Yfu;@$AU$UKD8CY@D a:{Y7׹x~>=Y6F́3G}Ʒ~;QTfOV Aԗ/^fuuQy=r7@|v`ɅK/UaMAR]c `RH?KtR,^pB\匷Q4^KY__7-//rʯ[ޚ>wAe>|8_ihĹ3QYq' < qn@xs 60KLc( Q6zF5:nso7Ntm5666Y]AEkMZѣ8pxVވ Z@k& wqvZ"N`U`LAEiiLdS2 u~(`,Bqoa@4OSVWWWViZ9r8bQf2H9Ʉn$IX]]n\h#^ L&& ׯJw8C.[F)W&I+I+#Pge :Dሎ 07p*b ΣwjRDq"{o58V7n-577W8MFek8Uϒ. H\f/b шl: 9PpC7zi3Z\;wQESZDQ)MgwVm_"BvMڵkL&\̀cE (';$b$9 zݥpq>@ql*7NB Y8+]e.pWs4y ij|!^~ ܪ9&+?2sè]-c !E:6pTyi :l>@Xs` ;2f<@Z$OB11 f[7;9v\_nEXa+ Y~]UqIÊG5-͵B,2nppv MdŠrZɷ3'v:/4ᙫ@e~{xWȑe'By_Q&(պn_Wkx+zLYAy\+ek{JΜ \܇q^5g.ehkaq'd2~}~Zސ?nb$ ~ݽh% ;pXM-B]:9 nNڃp9 6'rr,eb;St k" eg LL4Gt:vލ#knCž#8N$I|U@Ѡn &fUiaC`m+JDS*R/;mʡ2R a3CFjA]v.8"RJ_N`׮]aw"BXՇ$? {/(% ݵ|)R Ǹ8ŗ^]ܹ&ކ%h6 õ${Cğ"l"&hV+@Unh&x+Bm G! 'td̫gSNpa%c14YL4m!XXKBxeQ4&4{{:g\iEbTSGH!I# pK'$ÿ.O_Qg [sFڽ4uYYE6̱il|?_~k%w{č_i~ <sU:Dg_[%7 #OS%ЩFTMeic? arxBIRȁ%i<*+й#yߦM 0,U{5nPBQr_e6BVuǟGsZUH JO2nsUߟ0򗿌R'|3\p$6,. e? zv.κYNL=LIavJdɰsdC{ V W\2e'.Č%hGlF(dAq8 ~VCBϊ&"耂!9seH?D$*$uMm^|M^0W_`0NtLu}]#~ף푍{Tu%* q6`#DAt u~$Dξ w4$}@QD`#&=i6,.SK 72 6_MEI)Y7` )T䈪ئ-/ΞFp:yM{/ |*^a2FsQlb$vf{{ |Vb8dŦc?Xf_EjjseR:@$]&61pH+b; R3yњD HآD(Dx i&UA]ELNB)u +JSPS3Zyn~׸iKݿwc>sˑcD8AnNCZ1h47إZQEc%/7}UhvљlkVS/ @HG?RD7oS7h6M.1IG`E0smoē+ûzm*12P*-\Tڐ||"Mooo1LA}=9ǝ?uv:3b56@(]˄l#F beµ2ϋug{&hYEiN`5nLB1b }7@rl|=@2RISI MSLuEa P, ;ʓ{ᙔkj7ߐ$ ??v-eR1t]O'H#W bL A5?cp^rN ~y0Z|UJEZ;rQ/L+ _YZR`kJ *JKsZO񯾲x2A Bۿ<8p23:|]AI>AZo4 39 N.B:7Uleeo|HNp'-yQ"FH :{߂>?ˤj B8"!w"iZb8q&47'"̡zeem/ k賤9&ХQ@xА}\o~;?qg41L|+WxܤVمBO?FewX?C6V\k{ fmڴA>JQ P9 5a6Y>Q? Tf&8D!"i!a)Q1D CeZ}x(pss1TJkVpvB"l]",WDᬉSbztHnS>O Qʴ& KT*UR ǜ$]Bh_zL JY628^oe7ݕK&@G!@i)1??w۷H!6/"OU%IV GR?:Ȣj T0 dI|zX\r47袢^wׯ3Ll bSjKe][)C~=;+xUPY)/h̀?`@TM~7s~}/¹s8s振͋gc»T!9BYz-d#mɊx,b#TdSD"#*E#' Z̮22isA?hP%Qx#L߹s ݤKcS\GO@Y V㈠DH5I]SLin]ɹk=Fw%ێi]1@GȔ7`i-Z+H]0dC`ll>j1 M%MIIY$퉭-xTmӈNlɷ=Gc4@ QK/ ZTj*t5sf8WOe}ˁ;-d9`:i_]ᙍü=n-P)_R n51 m0~eDRd u6 nnlpYF2dV:X[.P٧}c8U 9 /XHŮ0O̕] $WרX:C-T#Ž%|{g*!v--hmd⤫&dR-xgypEfLƂz=Iopf]ZtfIբnӞk37g&Z-FLx:)I,")%hAZ+H<ڔq.i2d$ 3+sA)Mȗ9 O,/FuRShs|x;&%i `fAIr~c[0uVGjV(g=ȽK{$*I?j7ZqMk4}c=Ԓ\8 ƒ8ecRĆc>Cy?blRo,e H+ TZGc]H-\9&L4f; Xz^|nw \f?H<3wNZ jZL@) JgSSڜ$T* d9F;譐LLЫ.3mFj~A)|5kT:.0\v$Zw|sTݼʍ< xsa0y#4.Nom1o3f\Kݒ*i8| 7s $Fҡ|th2ۋ\Yvp #0fn9BJn\ /@4%d|ʥ+7vf{.l"%޶:c4Geé3c6,g :/] 6SZMWېAJ7S֤9H; Mވ$f$,'{l AVq)SS%7E wR ;L#(RʌE+R5QY6ө`žCwcs )IG 2auǩӯA6579776 }3! 2R&ֳMH;giTF Nh1FӮy0La ZH ks[xiBjL*Պ &q6fl:SmRBڮՈ WIJ I" d2qUL"J)V.3E&-@&)Z<T?mÅ -i·=}1JZ:h 2R)}m[̳4Il ag;OGs@n}Ө+FvM5WJsKGWKD}Ϧƥ($9R t"Ir41.0:M;?ʘr%q-V6[u^LHZiιv:O]oţ>ʅ++$|ZGɄ+gNr'H*-q^}9b&4Rٵ{/iZt<DH8[BƾYJӢM8S2R\gcsE%8`%ņo&myS4jCGU8m6ȾB8T֚AL$2aiaDZHL_;C$n`rv;<^F2[$:Z&}]4U^}W.aY]fkf~n2 q2uD~vO!7NH{Z0ir8_7tH)sMnjxs6UoVdѸoakuȩ KpeUz/#^uﱾ1 6S+mv͢.WuΜ@Ggg AϞz'~ŽFōM*WfN1:[ZNߙ\xݡWB4zj8b- A0!P~I &DBHVRÒ,AÉA ł*FcYӊq&k'h=H)nMF|vԊ~k|σ Y Dhy"Ǐ°C:q:З|ϜxKy?h8«nHǐ2E:k'Xߺaӄ4 M"7?u-#vI:pc _zhH{pjcbA<>dPUID߼s"`Ȯ]sqh Az-ɚ%-2ҹ c__?G1EJmiż/BVHdMPܮ{YtZPZؕn S#dY6iz |`f ʩ /- >EZl4شR@>ARk$f$Մ5}J+&˥:3B1LhO{ZBdʧ**&%0fCZP%t̹ksj֤j̈4q%8!C&$rg#\QHHe2";vWucM [_e|l JT2fln] IiJZ= eG0) }SZ,8Ŋ%Sew ;N$vmr+6r%iA0 cto QTUYan.b߽o)@cD :l>$ s.M K6h/qQwpu7QJ f?}{Q!7^ I̓ W ߉qsz@ ^ZFQXTʧ$EeSJ6Tjd1iF6&-t6Юsc~7?~M _/R9t7_G?z!^:vzxVI-+j1Υ7/e~ˣk2{ޔ9G/+ F^?@F׈gEm?74ZGC6Mvwk.s;puzμ*|#=—oydX}wX{K|y~<-wĩרT|uK9tE:7Z@F눬B{RʖDYA\5C wAbpb,0B[kK,c %R I$9z .1KU"}4A'eRCۑ4O&?*y8q|}~vsy`\!c>тD1 yM sȇ D\E'Kv =.z>:wyW^{ŋQΜ=GCq'?8 ]Q[O=Vz 2!]8@\"V"ZȑH—Fw{WWwt-ڇFu xéUY緣)3SYOT?Z 6눘JJkg/RGM+7nV^5z7WOsn\T$iS?Bnv|+_$*i{uVN%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_16x16.png000066400000000000000000000024461341671471500166260ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTE%Py?a8\/N 2U ,L 4Y /P6\apx 0R 0S)G /R /P 1U)H 2V(G;] /P!Hm -N Gk0Q'PvEi4V(Ot<^9U%A[&AX'?R'>Q&=Q&Pw⿾˼\jr~DDF Ĵ`ov~溸YR:]ZNvvuϷ|öӥhmljĹ^lsz֟q{QQQĹ\krxެjjjTTS[jqw͢AAAƷYiowٽ>==xywvս[@ƲxRø\lruTmH* ɵ`owta u;86///w_oum|ķǹɤhaaGzVhn4K\@GJ>BD?BD=?D(IDAT !"#$$%&'()*+,-./0123456789::;<=>?@ABCDEFGHIJKLM@NOPQRSTHUVWXYZ[O\ ]^_T`abcdefghi jklmnopqrsNtuv wlxyz{|}~u { {t!DFY%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_192x192.png000066400000000000000000001355111341671471500170000ustar00rootroot00000000000000PNG  IHDRRlsBIT|d IDATximQ& wx zhɃldF[ƃl&\-"訨&EDwTWTnTn0`< ,H-K֓xs^+̕sފw>{X+W_ʕ0xOX9g\.b'( 1) r}ϲpoΟio\>[yw҇w[9xFxW7p~]yd9A&;&i"ε=  iL<((g'XOe|}yGy )o^( ;ši$1 O Ȝvuw;bNgIv=ft Wi÷"If+t4& |>B~Bj Tҵ׿eX\\%XŢq^BAUץ^Of7C+yS8f N:q NMemB-J MMv2Escg3C𖱙54zrĤjWtZɄ|UVxήcFFK@)79C~7F1_YԾ7-+ƍz8èbc$03m A3,0@A,NP;@$iI;gu <8-Ec/Hx?]類Z}tڟ p{g;Siml]S>3}%~-<]B̮_ b#9ZY-T+kl`g8h/G TY|F/ŠcO p$ZSa|A<`*)˜0VObJI 7iY N&D[ LPٮ)+ :2c#9BK[[F7S5(}b\F1WY6}nP0~ Q~YɤUo^%/ĵO{ށÕA3XRS ݚa4fak2iH""j9}#%x'pᙯ掺œ&0% 6`N4sv5tl2 Ь Sͥod?0JJ찯h63rE Jl| F{`fg.))|*( |N3qR6/yE5:i<'?qW?>;^{'M8"+R_@|soQBW浘V ux!@R50& NIkMR_ AZiB(˰mp bA j'&io`Dقhr,Sgf}#i'[ηOA_ScmRu: P A,2Mfc|zi<_i,+x# $o2;rq01qaF~5r#2R$ ('aCP,jiImTPċj s8e@U0G,d('c^RAREb͐)$az2 NB3d-8@ KkC9sc[9k0Jȷm:x?|66P"@(mI R3ByY|tb"| /:s<">dsd?#d09=>T'7Tٱ(%YΜsPri5ayV#@zV!kC,, 2t &LdL֒2Y<xτ֍I! #Dk["#>O~d HDrO1n"U-Gd OU1n< 7e =Pvnτb-D&l.P;KQ 0[gCn;a%c*(.ؗ`ҟJ":upL5j$\sUq{I!hJsВ51 Z{t(dͮV`ȴ(H9ӥ#̉J#'a0(š oX30(%T$YZ;aV[X|jdE/pDU[Q%h%+\ERi`t c1Eyx;95 4e-@ʨeWx"eБR %gN9Ǒ3d#zd̚h$U!$f1* "f$Ζf'J4ht@ '$J("qfTP@4bE@T3aUUB@H"\pBqme 87xD5Xv&$d7pm!Z$)<9 }8Iɣ13p:GX_Fo6߯{K"W'Ǜ$(Q*:d:T:}3 G807]FBH@H`uȐ0( q@9BB0Ǡ(UN?GT|7Ɯ@S-8 '̌@!{@C! I]i"*"zuhܻ c9eZPS7 U]c3&%Tu%㐅ep0R(&f+ Pw071 y*4P0V(/)M3F  QθAam2.aie8 ʼY| T+4¥s#Ԁ*~ jZU2!&O'P T" x5^ԉv琘cDJM-!|MI0b׈LrSfK# ,Lؾr((_oH ȬD;r]94!Qw{n~wR`UcVj['-R %i}8!a$GpJHw OySﰹv;.,oC=6V`?'07٧2?A2cX_-lH#EpCL ,bCf|Jwpݙ[0b{m0aL0PDYFOh %ad'1큂4A<BM1! laeE:l D`|: IcTH8'*; ^v/F+Pe-(_`zdJ6oq0%֨\C;nso$_R.JTᳪ# v=SܦPH)9pkN?߂.^ DOɜ33'SRXERJEUgsԊ9 s >u"å (7q9QN(VF0NsfJ,Gpfs.3-M1Fj?2V<#S,S+*RBnµ'On~#—8 "ypq2 k$J`qy<&lh2Uok̿AUa6':GF)lJX\:XJ5g0nL#2@@ƔDy?b<5I YYxZ 6ʖ0U۫raR H3,&WVؗMc#'ѹ3GW!R+ "T&#>^r|ɿL͠2%r T'"f#v%5CBuwNmn`f&8`DNBxe(2FJZxO)9P'IB-DТYڇ%҉@6I) $l ߙ #)|?ҥkS~ WDBHM`J3H kpƏD }S'pOJ*IMI| y@XßA&:߁%loo .&I0ØT {A|hnݣ!XzúT0*HbuI);hL9%xAB`N\ڮ*Ę@Y;T`ΰE- ^ IS%IJhR8BRN FBB stkx<`W]"*0h/fm(S%C&us}/\`gD+@EIJZWtj&ػ;޺&Lj}깍2%=joc sBoQ/ֹүeѴ](Mse:ւe UU,oUUf1 {)&UȊiPXf3x/}!+k;`?lվ9Xd2Zc3yLo!: NڌC݌*vHΪ`xMp{5Tim/&;7o:9B1T1TP`DmSq|v_]&A(Ͻzߧ13MqZ3A)u-WBYp?|~7H3*Kh/ hy1, D!㮜D%03 p-+Ѳ]Uը41m-ƀH{J~ Cp/eYH]aI'jܻZ1|%NbAk\)~v,V9I*1QuWC E 5-T>z^N d_Aܾx {^_i3I"?o;4m! j Tup߻_לKRKc33ؿpЩk!F"8 e<(!6@+GA{b"uHq-sTHy^`FdwΒ{m/D* M@bT Ea jMhYu8tV@مp?P,L#<{Kcx<`c{}pl @3(N}|>7`ei Ŋ=P豶ϨճAE뉚@B^9ߍ ݦR4 ^ND 3MNd *1e&IYVvZ;->MBmn# ?w2AI`0P*&FSOL**xZH{]ΙUTJd ?GcD]ט`g?_w7gPGu{oN~ @N6鿖&!^1N;´69?|uX8t [uN3P'B MIH)"ƄذsDdN1Og'3q&C;qS>AӌsRD RH1"1b۳! B舶92Q4 e3@J$VX{L;8C,31`0<WWvQ.E1e_W5f=ؿM\YQ3:FqǩTUx@gfHs -[K"5tG5N YӇf(=5\/3h79CUn@wt1'Vߛq!Ѵak}A4RXLjiU)͓iLe%@5dw_Y40,M$kk˲۳s>z&(d[q`M4SDl"FCv]B*XsC[&n$De5ĻU[X8"ArMq`~;6D(4YF_03hB3nLg 4!G|h@N>CN]' S;iin6i'%hQѱ[ $۝Dax; -DTs8E[7b$%*,pk<o,S/^.L&QrRV3h`<ΕF:UN]avpa8jBW\ĄW|# G23skbH ?v/ x`8mI8oD"F7>A,]0fGٹ LȈMDӌZ|gbIRk Jܠܮ4$y'opaZ))Z upIۺF'qTc2)xi1ZvIܯQ24!pqvM3ВLBizM2%huH0C dXy(!ܬsccc335Ft:]tܾ@s8}⸵C},B#g +ܠ%SfrB^tqnR.ňƈ)c8<ʋY r '0*Oۓd ’*UͨiS]$ӥYΉdܞP:?-D,ḭ<%DuXw%V\K4[Фi *9h%qly>[q3U%]uUa`>k:%Ӡ:8vh$X9jApJkڱ kwbci6* C}sL@Ue9z ydaqFY&\4 ,(:$Af@W]ŒNQ&`2%N ML+I|ߌLjR1SkT*I)#* &fĦ&6phx0't=u=zG۱. ~-b1)('P YB,n% *9/H|_Ð r?Ḧq&}BM 'yW" mcdEFhjJ|_͌V>`E)ZΑV`{h0[-TR= 9I &xxtj!l2ΞovB٦KX^]h46 p84A xUUp䖦cV&t!Tm`mς>;*D&|eIaI”toY)e+.0THzHW6vJĝt-ËI’E[ιPk~rBB^ZV" C385?RVd 7cB]*>{Ɓ*7p%c4Mc114%UUN˗/O=ӧOw܁Hj4Kе `BBGgX)쵰J| fe^ Ƅi!sje{4gLa)q% (qB$DzJ0*Y-@ QwϕYl7J4'*IQ 5!FfB% <`5:C0ͫkIsX\^6I7eakk Ѩt033U6]U8Y^U]Py(Br4PFUp42ΐF$0)mET{ 9%Xa0y-O"|IQ \u=;^jyT` j& ᜗V"9G"n;-<aM=h!ShIFK `f|k_SO={ϟ˗u>^{`hFݴpFq0ɷnS\-\3ޥ. b* R@J1Tbhvf(Pl,kB?0rƮ=T%2d:7Ŕ㪵AZGC hsNU`" VEZݠ76n¥4qfߜviIؐC":W8u2n*[[X^YgϞœO>g}֘yy1+ C*$-U?`7$[E@H )RfHЁFwԢ2-#>XEOl3cii .]¹s `mm= u>yQuwCc4 0GI[a3cN$=96eZY PY[ ۭck#L\嗇iZidXٲL(Ԗ[1س0D @:c#AV:hꊰ0>*j2j&O̠ d;!v6Հ:kti/K iP@qq#!}m/͋-lq˗/ciiɴb~ՎI:OwY-NM)j-6ĔܲT{ 5ؘ241d68AENAAf2_VuRJKٽFS*٠ {T*q=,ŊK#"K=m%JU1K-an O(8W&1Ym벅yii4&---_C#!zo&Bi0[Bp"._Ǐp(#(34F}fΥ Odˊ8 PM-j5%kAunFRJ`*J:v,~Nm4,1U"#GZO`$Yb o), k/1(_ 4 '߽'M[4rL.Vh9y%̣\/~«$PMVc CspQW ]_0p!x=N,6? >i2<6yW]fR[1A*F4!Ĝ-ʬ <0qIHx7jPn~Lz(@qR&ɻ]%4 MA)YގٙRf ME`H"Hh ^(42Y"B6? ARBkk-->ο3;339΢k;;;6FQ(>y;F{j4?*#ZH$t5Sҧ߻.M7pV#j5l++f S]<Ful0*U5 #t'g?{;jPЎF\jK4R2uf6V39ld%$ڝgaR(!666@}t:t:+cliio~ ؿ?Q~sssؿ?<y!X[[sC6wjԝhHX 2oScsۂ. BIЈj;4P]tu8x?rLK~bs]?f 7|A\mcE{no|/p`YE`0f|c'䲁r @PUdlf7WQJU)7Zw f1Z6k|^s 666Xմh4v1䉶7}7RJ?Br\.VNK \VZ C[+6KLy]IQC&<**T;8>YʻpJU A 8ԝnwm\Y ]tzY@'ά|L88+QbEvH(|*;;;߅f6: Bp_[ ۇ1[n+_*QhPum~DҪ;fQA \f"\U"0/1+t;44Pw:H)bg8fyq p`{@gnO}}*帪p]?SKӈcp3*/"D5EmhX#[QUmoWdE̤Y 6p-/WUʥO*g8bnfu8' x绮|^>M?<9von۷'_ozz.1>{OOʕ+u9,avn5b#ÈR)f0?Qkdd%1S^@N 8hs /{![6I>ddA4 ZS{s$mٸnv7Eqcg9X]zќZcL Lj\RiФqj lIrUԁr2VnNZKՉBdeP5:A,1fffBSO=G>7u~җ71?/`0~wSp`KQL(%W0 er&fo#PwK@mYTS)֩X|-YW*{2{(ΒT,@^Fqq+|oz4^*K^m#Vl.9fl|L[k51Zevҕ\(?OIiUNbqk*kaL]0L@Xfq3xZUnnKgqfrQ4e1hVCe6{ fxq{%cYYV k`7ې QT$bɑE/sڢ8ȚZeʻdh1p*:{ _x衇pԩ=}:ۿ;bX_[oa4Ư4*I]O2:Xor$S`ۇY 8!qDkIKdq-O~f͎`q41h ?Օ`Y7y[ Wc DZ¼e!z[c*eY&?jSSQYf<¹{Ő WL1?3ԩrrji#G0N.]{\ 9U+]s nK s_9RC>=<1T>C T);72MҬY `}ZyZ,HjM;Gؖ,ԘoEE^ڥNiſֿ U_09Kh;EO]yOܺB[PX^{\Y\_z|8},W`yy U96_J ۃyyloacm #n{/ŵOa{0zxfYla|~;eV\;9F$3~ ):Ů@!:OB bY؆ Fn*@eSayBİ|(MB$ 9cǜ yk\A DnefR)ҝMcqYZo+ܼmm4hVanvM`0ދ3gOp׉?c\,Ch " Z>8u,o '~=`0'weѵe8_cvP S:-|*X rgmkE( ^t/*uop[ijDCu-%/4+EW$9Ee)tshߪ9E;XAՉŏaJ^5%P|my.[X?Qo//= <^x>`+M׾[7#^vCƒ_.n30ӛ}?b{00yx͟Rp4`g~owػ04ybMT9`D)tcԯ 2=!*_3IAid_U cxT5))ms~Aе ff>mR̥ޓ'H61\,8t:$y)Pzd \x[g|?f/ =Q+K !N:sދUlmmclMs3ǭjY F\|,D6PW~O!|U Lw*YTHdFCj8W%%TuPȀC~!9]t R.b#yghϓnTĨ;N{qn@tVrᄎHvV.~w=:^z3$T`r[i8v 8vs:_><-4R |Zg #yF{#2rʺKHDhuW{\J]$Ud?14ienR=\*2gI:{ C cc ަ lCgn'@@+N[TZllD2l' Ԅ?>hI~F.ç^ oBy$::z No1W?{?xّeb-\^YƑ# ([@'*80"D[2q%$jRJXxތӧu*O&]1 a*/?5kY\^K.-,WKtӍnJ3Cò-:IkƋ5L,R`\Mruq<"KZ&m\BeCV]WMk=EB8%D*'֒ h%U&dJYX&|nb~&IYY*k$G]=o# rzߑrO.s 8[ .n95W3Kx<3g =Y|PUHZJm`ݞۑ1Qt&itlVbmc(m:jhIyMf) E4 O2FMU-{DTvk[MyF,>+VfV@FK?K= ^ ] Y S5 q\t KK8rH+Iͻ- hYV@CXl-S+w6f IDATEv".՟EDT ?!3JEԀNf@q\p@UcF@a 9,% c[>tz[t;ef,N5LٱrcnN"WZc|,-.!ƈ<<8zNw9tf!0:4(cBi+`N\MA8ˋ"B/pi.y! ;넕+2Ȩ@7 QПA8tm߀| !+^//wivf/0..:s#4C`spet :;f簵۾ǏDž yNY;v "F# s?On^ru/L@3HjӸ88kN_o~pѺСC1fs)%,--+o1b6- sJ5,BX3FK;}g *)͔Ez2{U` ̥x{:a~Ub Ν~`4Xt05`b# $XM0eGkф2Q1c%*ak洉R_Ұ{U$eW52@jCu@sϵvwt:8~8BGTe03 0jJU:fP< VƇ1o5\Gb~~vJi`e,--aaa"J)a0~][CEA}8wí!@Hh!`BGр <)fJQs:dlajPJhkSB oLvI$(Cr2-lW1 b=DG_p]4F#Ffڏi\jp`8GCɓ'qQ`ggG6̾gy\s ]ʞ4 ~Kxիn_ d?j3+w'/fuLIǛATH *jI1([r#RcLe8vf=)^@*R\+$o a-M椴K{pL.JCWW!S"uO<ֆgΜԁnԋn(܂S#m]F3F]W?;af67pA߿jv:t]u]?lll)Ugi6s)'gvR)tz4XgSb`Hy(M2G5/ D<^9$1@#R×$| ̠O֨)(PZ~kqA&Gm->33 d`ښ9 ]7ɘ7?pYcáYJ<ڞ;|͸ O0bMO QBe!Uꊣ`~5,jyB8_k 98"~BlgEYj'*U}g2R L2bť C۷~sN ƈ^i~cYlmmY133Bx{ߋ7MqhtWv: >A7yzxh6iov\j7 Q600n}1F)E"6eOľӎ C]c8:P < )0mIbIC{)ݠFc<#6F{v-ӕU+kN&!F6pV@w u{˿mvt: "=^O}3瞷M#al5mjXʰ꿩sl|.y`@1a=dU{|/,xh{ -@ԄJI7.Zߤla|BqbM+HK cgeT0M=zc=w 5k"Tf葞SYF^|Aȏ~W%`KklooǞ_]4'BO% A>faƢ#Ý9R-maA:24 qB%JvevF>aT h .5KǔAdlBWj-5e~¼,VH޲ N87)#>:un ~{ M~JUvRfffw>n-ѺE ZNO8yТq5gHEIMkU@tcs;Bb2B;y_JƋ<P47PKpmb/(oq]my#Mj(NwMX/ayyv{Wx{߻kG}F]%V)sjNmRU_19q~~?? xBP>6n=QJ)%lΈ2A n"V"5*r8t>H9y4D紜)J U]gglD'KB d@{sC']^F#|[ @+EQwPAP?p}m$-;Mg>/>w;_+AO˜JIۄDQ fecRR#<Ω5QʾbVlJjMPj?H>*qNMuN:aRj>ɰ Q*cBK|L:w@ z%eVw ꎜ<33 auuw}8tP0!/A'_oz׻w ?7ĉkI:ѢH9m)e9] "f"GucsAIR@T N*ዱM?(^0?ʒ+P$= jK2ѐ:9jڒߝ,&2//-Vڮ*LpSO̽yeY/Lw-W.Cq28H'8:!LA5Bj ZRk =CL3;q.{|h4jG`Bܡtdn Kcvm6Y8$Ir@6[$"mhyX^?2@ۼ-TK25}29b t3B*k[0q㥣nFaB894 БAnE~?A֫+r1h4EĿ?GꫯJwXb'N_r\DI룴 ~o$UV٤5 CЄD ^9JxGP9!BR[q@=^6%Ze:@:͖(uӶ2_ '%X4da|B|W&1z'O+?G]Gs!%gEӍ<>򑏠(Ys4MtWI]_\rюIwC\Qc9_ǖi.PHS\(~7z` $bXHߌq1XZ@Su!2 -JlA1\oo͍TqQB`VJ0qԍ !`2{'5x˿ X T D+k3}.R؏R?L32'?)Oxtro2E@\' 6J&2-q .N#5@D0 u(z=d*i@UXJ_ AI=ūeOЫ e|.bfKBe!H}Mq{[*mp@=܋}oUU}>qX ϼ3?3;4Mt(J 1f Ͽ|rqZVW#43{J6=@R+`pqo{6Ïy9OZ~;>jlkP(<ҙjf33 q, ڬ Zь!R&t P0{us]{9MtPgW;څ#N H22EKCIͶ:SLo$ wAn5SŽ9gib)ӧ~/B>yx>%%k9/bn ٵ'3j˸ &F^/h eeC'Zo!:[ڷ { eϱ}ԩ(BJlUἇѵI ]skٰqJ m&@?1Af>dmSt p h"ICŜغjlYU}{h4jI7-^׃FjwUn3A;{^yۋ&O!V2i9W3e(r? iSTgF("4켸A@(KC n!JZ'qS9X4 b |{4e'.:ǿSA::x:bfP6z3 rGf+S}ߏ[o%I.t9ݺp rN4zx"zFc l6i/*@@Bvs Rc,#Q bKZikT,j3FR2 #*B* ʝ"["(5B2@]T_6 S%#Ԡe . ,4Om% `PhU??kkk_ ""g/t/E6$Hài==8z(;MO4Bjm^s}V"ho 9#~Ns*jSiܹF2#̀8E&j&Ȑ ԼmgT֏chI3quGBK6&g d9=["|㡇#W//a}}}!_HR_v8x}tS8vt zu] rW2ӲEVmP  ޓ@ kb]&_跑C\p6@nf*!3,;!PB!X%xIp,l\#C.M%Yr_}ȼ dE{Y< -}kqmg:ro l{O.*-oy .bxQ%b3ݥT <̳xg H+,tdyPwJgm7qOk|;&jTPhzg Z'%ph1 $^!J Da6Jo%hwX16:7&X v$[@%IձtJ;~{{{u~yrⅈzucy F "=׳CEF@ϩЛj/}+^˄\}L&\Ui-ԣBùc:pN\,A:ñ;s,)lɡ=cJ=$LjkeZix:d䁘:2~2@Lovash. [oō7 y|СZXd',rv 7FeYb}}XYY@rX9m< L޶Ya 3HOY-8R/!$ׂ?N m{s\ LC[zYI;C"b`LW 4-Z5զ@ gzދVJ֦<t:Ïǿ/>mf,[d+d wy cpG(T+h2M]˭kkiiˎ `!D"ϣmF΍_[.  *WNjK/-wJzDK=5k&oIDӠ;(`mI T{z:Bm)Nĵo|q񅁩yR/:"!'~`[QU:;=t Һtg~& AAjh 9s㳼1$3xfg&F IDATZ_ dߦ.yv x:0#(շ'EgȈ!dQLR`IbYVlj]h\7eF +AO̽^!DgG7R_~"_ș`uuW]u1vww1 pq\tE1k0<`mwm~@RB\ S8cIX0U죨 {0'eK3Y fZ\$__mqQbl#Z0D&jV",<Ү)ˑIDr)fBސxn@_7s$}^5c~/ <=:t(4V`xh(Pjm O.DSzm ^|OW'Y{mm@Eb` ˋ9b6w Yld.v>-!]פnǑdAW:{{cZغa.59r@#/3Ar\1s;9+2T?}td<Vo1/$tH mӳDtA \m4 M1 -oZ1~Lm@mb8 _;Iu B!_P]oSpA:t[Er>!A](UB;X)(}' g'[$di9qQ8}q朋 0N%2AnT*$|SyC&[^:1S9'cŞp_7P+e«ɠ1Ry$-q ?6w0EZP"x2S 3Y@pN< g%S3{666}h~cb+p#oE @Y[kLۋ\74oCXLc+2 *@ZEvz8I/X51Ei0&@VWN`Q_ q?Jza(K[;M6.\.TnHdD/)%-D[R5 y^ _o:B s=-z^-!9epg ommaww5"\,8p#lg"p7 By_01/y#x,[4-,YP4'&=] :OQ5TmZ kpNa%ݓ<įOڱѮ~( Kg_w߸pދ@K#]* YxR 2@D CgIEMK2=?essM`Х)z^9DTl79 &>#i%ic{{{_g# ~iǼ\2tsu[v^UUى<3_+Rބ=vȸEA@yzjwMj$^2WH :pn#mbv(;_̆- .NKlsMTÇ)ʙ@=F}siR4<@[Bp 7Ā1+pq6ΝÙ3gp̙ Q`E t>Ue(SPJ0[c8=:VZSF*;U_!p8Ah0C/S9 *6rZ|0Cu *OZM0bUƳ.J^I ,ΛdgbuuGEX4N1Q\/ IyGA. >\#*oDQ1m=oƸgϞʼn'BhhcM\}WjoMagFs%i̚2-L d{h"Ę{,̤bV035΁B8=m/&S@&0:;O;836jtioPF%Lv7:\bNS9 (N>hfZ4Cȹw`3TN@?ge{ 7tn 4z4&!KKK#TE2Fvչ:U%ؒ3E ;iz<MHBh{Z xyFM @76AL Ͼf r>DM 1x1Ue SP;#J$Es3d0p6@/ >t2.^O>___V0NNiԣ] iitæqQE~7?Ѕ7Z}~SWlF oW qhᡓ8{,666b nNh_|1;1lQ=i/B>&\{B27Kucv#-,;Tpe xxP7b=8`D˨OR!\br7@֨ ؝Z%43ug"1 IxoƂ}?ٻ 1K*W>?=^ѣXZZ?yX"-Kz ޳Hw KM IӈQX3 xep=Rx fuZkcl!ʲD+~Qf8[3;qbCJ"(<=B@ד)Z%@eA4@2Nu koF4OrC)3(! uc-6b<ϣ7X=oki.~3xvx9%|m݆jXr0$N71.9Ÿ#~Ys,xo:Fo5CT5W܎ٝGTX@[]hu>. nJI 2h\U27TIS0A "KE?աjbf$@NhK܂b#%< 8y5 NF;?k1@at90]j A{os.Lud p%縋]7zR@iL Az3h7ju# W eXch }GNxZPnO5f'"LZq>B+;T C_kmQnˮ5bܵ7@30Y#mB!ȵB !8A܉b&O8?.PW0Zj0)_wDBVQoƃt]5EZ:&C*WAjgF)WKg"c '2C8U7gMe41x1o_9yB :7.=!P"YSTЯ_Mp=?Lpa}ɟ ~'~7pC֭rFx|rOO.s 0,*79DF0>D/JqC?+k`@u?vm^!LC>GAZ>RB S@Gg1pyD7}pzkxjBz‹E2=J źgN颡jxʔBob:,W ҃8L_ &q/CYl? Ï 8s N:-looo|#y&!]~N"9z zޘF"hTVfK^c[(m@40-4AFB"A2 m/}^ gڭ57qݷ^RʖԎ̅{?~?Yc>d;>.G5beC}i \m"#_+&t6EGʵP;AlK/b2(ʑ?% 9{l, ?|k_k^ ~WEį''zeDMS (7-|Ky$z?uQJꆈ 17I{jU1XÐ1:.o 1v̷IJށW3[p\8Z=Lcͼ(nC HZvBj.`g$2{>p?Vs 9; 2{-b-` B7t?ww-'w"1Xk?7M-ɞwT**w.rwWۋğkQ1Eh*PS6~g8t ZҖ0bp>LVbS'Iʌv,N`<$8SId@?kP%z0_.-?oC{pW>I,:eҞ{.A{ň thd4^`4`|Hͭh&X~7P/)Pg(4q rҴN;?b ? pS~__i:;;_UomnOќ[+Q 4`(Qh".Cs`VD@Q8_^ vdJ5 VrĘTNswSt6lԻ& 4L0k F_X T%d| @UBavZu( 0&]OѾ8;M8&CB91goqtG{_uMoīc, uf֚ӳ%3Mlm!3(k8L-=/=!U@)#V7(Xc 'V~IRĽ+Nj<ԣ@1Or"moZ$nݟ'R xҠB#e#~z}^?(T# {ˤXeP(QunRu$Ⱥ__<Ђ&@-wo*W"ױM{{{c\T g]v[ƛ[pu>`pPLK-s&$%6*-a9A޼Y ʢ5thJģww'Լ@7h4fŵ*^!Sŋ+J.iOR`щZLc8I ծAńl)*},zv#7pXO॑qs9]~`+7t~2463Fڱh]@JEo~uWs9h_[J/r/#L |DF .D{6S3#Z@Yr02c~kD@ƚh%O z>O`EЖ)=? s&EJb2ح6J}}שl bB|o!?O+KO>ӧOYWI5MqFy k1<a9@rO5^b,y%y L@c ?~P1,¢{'/lL XdKx_ 7&@pjɧF8?1:EL+U?3c=^x="VyE|sAa`lŴ+d{8V7Mse\S>a` d,R!1F廂I4!Ba >?-ݼy@'GnasP&cWpo5\Û*3Ғܟ6uΟ?|38ydvt ҖE$k%f$xZeB=fcdkPQ_*-Ѯ)GZ#-L];Ɵ})|SÇq⪫gD ͹-ݨDcbcp 6_3(]G{5U1*umhhѷN䶰0N];\{ZƵ^GxfUqz0+\zH!=OQf".D-5\ I;PYJ)EOQ*涀Vjc#^x{x1^{5З!f}ޝE>a|".ꒅ'fkSQo=`߉+ލ7F@ Z  rCs`lE3@; P) iPh_bJV>Vz _zw[D&(lA  q|| КJy>B2s=(]BM0G73f xj;ѣe3w(< XD(42$M,j\Ah M\ 8kU])XWW_~ O9K+ژ {HژL-TQ#] ^ D({:>n`< Q/%d]ERO>[.)["0;7q"8ۜ5)%+/1?ttpM#7AYrNT.7U|,OW=G,{I _ƲW/6P1yc|^ NgQsu0E1&" VUd0/kcPL8߸Y  pibuuKKK% ^"OUUeeٍs~(4/*ۛp_] ]Eh,gtf5g”   >ѐc5Mh@ X75^F$ޠ16]{k qp6hܞԓ mLBO;ҎEjWC89@$3[P]r ޙ/cՋU*]"LY"oy. r%$p aiy }U35eY.x;4f:9dMWVfkl$ջA> oN'N'O%^Z؊X!nc(Qb 2=xՆY17`SEyD({=nf0ˌ@XIy[0@\_XTxʠ2>'ArTqqE{c`׮^U?kwOn|Ź|'1{mR>N6lz-v~/IA ?P1,줏cG<`0@YJ obV6BvC!H_t@$>joiNFlL˙*!L>s E (PJ %-ྌXl%@\{a5ωdN7-- +k/t3rP.>Mj;e  PVLʣT): ȑ> i'a^@f8ʥ1Ɠ}saױ6+ JP!P j0#16x_[ ECX^^`0`,,AA_<;ddP8I6jbzEHPͤS&#|5rŵ9&3#^!z=56)PR#Scze/j&*Huʤ1@ iP^'9pv9p?cW^/K m?A!Bau8zH!FubFL;8啊_Ş%k+ CБP ދgSc]X?w7'X;h6DPwcB5&TS¤6c2_]+\*FK#{}6* >:JZmKp"^19 Ob`-ݚ?)a6&cɔ0 ܻ?}t z({E,z xXǠGCYv(Bl̖e +BP#Y{d ŸBm!c;8w$6N V՚xaCp($CIְ3\b\E"6,:DkCm((Pv!|[GnĹWaqW1 ;-MZ Q Eƴ?>w=N_.[({=w*6֊Ra$2 .͏F9#!ul q lx7MtJL 3+S+3k(}:1 0oz}e [HS }J 7Eg4{=Ea!TR%P5ɹ"]m8t:d[gƢvֲ̱GlMrCp F?vh$5Jg$PĹp3$.WcbIk zqb:<3yٻ(z&ZeGY6K-/>W> eEuT'Yc#&iN0~.݀/Mo~[ .pnuL+dJWN㯟Yýg0`0`8b0b8`8ǽ~OzifY e^_!=aU`@4@LR;Z X_*˸c1!ElX}lan\K j" 7>~T]Wq},A ÃQ|1&) ( bsc-L](^mxr݇s`uYNu.X<ݻ_};.^DZe FC%oU]u "a4L~X7hޓ`|1M440im0m,&Mo^]g101  0z({%ʂmk z(@tw hd E"(dh✺XuY<Ѓx'Ң|@~0YU Iҍ+Ȇ`A& 4KJ=,E릊gJHx5栄Afh֎˾~rI'ov /Ǹ eo"kCQl5g,;d\ M%¦'Wl IbZ8: pt& "]d0ַ ]~9;^.(eƪ"a=sg\q$141' IbwUƖb玹RpԘ+Tȩ OC@%r\Ӡ,-!xj/pGӬ9| kK[B5cD勋&Ta-Œ1kZѡAMGԸ*514LKmC.n76-m yX_Y3_ Pbdqj^D_@:f&Js!ɸW75ƒ F$W bc@V;\^UUOu9*qGp?Xr;N0 CUPU3xL@WsqsΆ"S(Q@a)Kq~6HҌ!-,zDfեH߇V(`[ p'd!I#K8 'B!ǽ^˘L`:aPԹb5 lTMUb\ @ݨq>, Foco,wh2w&l4jȣqml~sf"x~>@o-B#cA}:%=<ق'uvcCTO< BU3g)r0d"#xep|dx 5PU0 O],x({%ܛĎ>,$M 4@<;aRKIC>w#P`M@[p4D]ՙ)*!ٙ qCӝh(ml{ px){ه3d!t`gΝKv\xQfsDYSL;#xۭo t q ɉ# 6qŕW_&p`m]aKMͭ-x`VWERo/:10m=DLt*m}`ygaVI`!(pD3+$//zQ4{rMk ').i(Ni0©ijqdY˜Sf31k #QIDAT^sǍEٌ '$Dl#E)_'yGi-)ӖPL$ %4(5Kчppx(DSxi|-¹D0MS>!˲{@mL6ޣgByUXؒ=_~uWb6@1{EupdOr $}iԎ>Yk !\v%xGprs^))˭"v mŻXX!3KϞyUp7&d}VGpb#_q[]B2 0V2 a4boWpqL,J:wH]ؖ,V86L0VT*JQ@P);*ݠyoX#id4{wΏsN~[e{w}m RdYV#Z(C(UUJ2aF32(+֨iyf! O92Hl& > ǎ+5_w]?֬^}<|D Qem|c)/`1$ kSZD"yK$3 HE66l.5ƨzczİ]oe%/(?E2L@ B"#]SUs&)55xrx<: ?hz;XƈK_x׫Q).>oROP;F!I Q_m%@".W],QLMYb k+M19~c[* <U+OM@Qj3s[ng>u/1\H *TD&$NXU0SbgF&B0z$ i ィ &xr6 G8"rlBH`bm4I4#ZI^LɋniU ZWkH2{ý?{oZ sʂ5M2EE"<{a1ܱ4iC.ۄIu+kw{ƄfnČO( {gTZ(M͚=]jcs{lH)ٲ{twč/r $f`MJ)Q(x0,n,(, 0?@Y+!GmCILHqS# 9@ "V<`%ju {^!bKDS׮Ejd WT(a.tzp^R4"Aqjj}uamPYklg4k6]1ɹ.o&i0X0\η}_} i@oRu2{XnF~WͫU!EsAKc1-wZ\Xd)1(Cphڹ~E\>*TŭE'IC g)γc  ȏoWݝGի9F}d[A;{s5l] Iw m"2J|NS;TvG"z~{{& -?MOb~U@B|7=e/`'z:^|0GS?i`E@ƯFC#tfq`[ ,ܚ#}Q]=Ϻ&tp/3SYd*1*]09~?G=PvG$qBXLLw @+$,+^A cxs⸁vK #_R%k?q.zy&\Qv^I[)L"~0UmAx%Bb(ϗ{u }{"^<^w_`TӿydSE y8MzJMG%՗1M _;i_x{\hRp2u<( CfS5Ҕ :r֦|}/¿}xǚ¤ՈP*cb(QqL<-LD* bsaZj3LWVh' :]ld3)*RONjω``S6Znl$Ù\ ֭^WƊeDHvh4ڱk.1pC!k8TOBI Z.'nRk,hmMM݅CU͛d/v i΢%6r׋aYA9DPpB*F[Wu.KoMAU_l0{8C)FUU!I8yffjPkHDmJd9(MXM$)ȶ{lnt4nQuz@l oHR"?Ul2`(m!YS9zA ۆ/BC=,h"P 9{ԧR0QPV]a[Ģ5I"K$ K/CjTb<6 $K0.:Syq,uЈ君/E> q>t1(!v/X|SS4`+y W5"#NW;?I$٠F 8'8NhFr%C6*p'J$ u ySA&_s*#M@V"׵uPs('_<%#Pbar&;+")ЃѨE/H Ɇ]L}A22X4apO TTN}*/l#qTE w7Pwc0Bp?'`)A ]bE͞ 9)\QaX@E5!}#P&J`zq"c$%RN`(8htk28' /ՎW Hu M5k,fbעם+/cQ X%82b]c>^dCvC(z=#&y&پ<SXXޕw%!ȗZաX.ĭA6iiw rο$j0GFИbs_/M7݄>~(>O`{FwzɰipDTU#EP/x,">h- <'_8_K_XscB#Cu3X;D'ӤkU9/h>:}"_{Hڜ:A9W}7=J԰Sֲu',[:ß X\<8} 802zѿk/xۇ>w/>ugKNyBC:vM]}f sw{x`%0]Ӹ)XrVЍ1\@+WU9nQq`Dbm,"d;x 5|n&b%(BfDJA K>biw j4 PxB ᴪYUroTh(QGG9k\/ņל%-yp`%,qy.{X5<.Sذz).֭Zˆ잭tl\~y&6o\"C_3^DէnP<æ.M,Xe?pi _}",Dn47I`6Vmp3#\s~z8wVoTaA,A=BEu1sF.>b[ ZADR/~߀Ē4ha[A%{Ś!`cOSHCXbGx΂lЧX \v5&;t;XLavjkOZy;7u7[:L9UkցGF1|~}h?^V #/<}Oc&æ㣟9W`l|_җ`Vg9,8NOpY7{)ƕ1?q\#ߺfhv<$_v V^o~ƨ < Uz䚥@Cm-dDތGG [/ P2[!hn9 ?j* mx=T!mzxq|Oᦿ,-ފw_gX:Ʒ5|m8 ~^{8k{~k7^z6p5ģ?/WxrS߯8ua0W S&6X<&@jHxl‚=.d4v? ֬? ;wZ 55/vs=5DPj1v>[8Bd ǐ_FH{zXb,Ѹbg@`q\Si8={5=abKPHE0;7^5STΣ|@)w'uQT8iR|^_^9͍!Y拿Dz'[ywecpcToFZM ֽU}R;|]j~kOMiwK* ,FK6%~}>@]$)L$)l̂EPtfal$@17 2i{ zs@d -G1{ {KV+kPg`}R Y%ËBLJUIENDB`CPU-X-3.2.4/data/icons/CPU-X_22x22.png000066400000000000000000000024601341671471500166140ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|dIDAT8MoE3;=-4"%Xh*jʇPhblB@c Ə \ &&`4HAHY@B)=m=;^Mv3dgyiٹxu߾+@U d`0cTXҽGΓՅ4e03}RƠXEQDAAT'B.]~Hb37.[+1   !_0DO$0quewGGP(ZEO| #!EC{ȟ;3IHI9fg+LO˚{@К/ C[bɜ@Z%*@5ա !H2xgϞe- uc &X lav3ޣ1ϴ>喈͏-aqJ%R P(""ɬVUUJdRO'[;>(s\6bP25 Qރ]B$7ID0` \l %^]#|{Wtj"c%CgsݸNS? eo-A={Μ9CGRٰa+Wd۶m455Z\Z`,MJ!&|رFijj۷3==W_  fR r)9Jmmm3x$i B$5D1S<"BLMMQTCjGިRx:wh÷ׇhVt>W7VDY6jрJhÍC)o<+;QGWWccc|=0@X&_Ƀ">QJYwÀB%[P<Ƨ9zvUs 4l"j`PQADft(ܹ(qGK [Z?H '[ ܽY9IGTIUL-9@r} snT/=ͭXk/|ȹ˖sf5+u%!NƵܶnSJe9.~o&(QN{YÃa%NR$*pn|6.~㏬bfU" fB-" N  !Xغl_22t4K4!oԞY0w$.?dOCIENDB`CPU-X-3.2.4/data/icons/CPU-X_24x24.png000066400000000000000000000033171341671471500166220ustar00rootroot00000000000000PNG  IHDRw=gAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>IDATHUoWr.vAFiԤB%TJ/ Oy7@ !HҒ ZqDQqvl'Ƿs3vґhf׷~7f5mjQPc@FUK5 t/S[\HJ3UߠZ'48aQlhb$AUQHwyXPU,ɣ q"|q.n\A_l'q/~g_.<$ ދ V~w|}ņV³G3\{5,9Y&KK(9ޑ9$jі7@DRBP@ uTf8&o1$D:s!in\{Ћ$FUQ :GuY 5>_7Wfiy 1c n!#!L B "1`y$I?'< pߤz`k׮q1* dØ')YkRU:;ۯ׿COO |gWe̥dFGSW#E%#.]Ǐ:Papcǎ?ɡCOp3X8>$[E(twwIWWO\.sYiYc-HAGLM'eevMfgILHoCmt U$!I[Pj>.0o[ӳJ"6j*QJ`!"MC W](n~ wFtجEwYFF!@ȜlCDj4\`qOa".,cVq|=c[8K LF7RE k5.]aq*pwnqꧨ(FӥAIz+b*8CDskק(^[ז#_y$V색,l~j Ftj,2롣xɊSYI%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_256x256.png000066400000000000000000002261601341671471500170030ustar00rootroot00000000000000PNG  IHDR\rfgAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>IDATxi%u~wy[=+*U H @đl86=uzGmi$̦M-&NsZ-qE)}) U}ɬ%̷/?9~oܗuM|7Yܡx:@ğ:pprp "-&^ݛ{MW0y(NBg-Χo˽ˍf}yLy@dg0prgW]c7'2.rӟn{-_ɟ"s*\w'cڐAkg<s{w֪z ϝy|yɀh) a;1|(J"O/x9rD0]bddVҼ7( h~v%z}v„Sk3i iZxu9`}߷ZcꞘבC۽Fיvz3"=kXu!4xGhpEZODfK<6iȶBcgሙJhVɬ[j':z30AtTXi{t <=;'ی8Ie3C#<`u^x?_1OD.Z>y+>я?CloC~K _yV@Ճs=|,@hSh@ jau& *_9')vEaܒ}L*6Okfpc##QfvX0`rM>Dl<2c& s]snf>$9Wܷo(9SHP^c$_mw߅wNaws }W\ן zP:cn8z\'vJ P$bDS_Fm( L6@aW]J{f2dS9byXrmGqIx/ P! XBb0bᩮRv| 20s`D.`~2o|}x& 4g֖2vTYHw:Fce^HvlP(yt>*\ukƠ^++װhznhuLiD n>|n 7>\ F@-mA'V!BB$+7&S1kZ(օBs& k今J-%%B$%bav8B}cK2~%086d~# j'*]hhՑ̖y(P]!.>)ga}r`c:|fCTbpQr~4[BiX%& VSMVĺp.J{ NPq)AG&[*5Rfq֝/(|tфjHs/k.QKIp&`4a\A9gYeKԶ%HȺJ捰bXMtԝ ;y#t8?c BvєrɰWhhr.sgˀ4 hL'5 ‘Fs#hxsEсHQz@[""8j|Gf⎵*H22AlɺdA gF0ʑ3Eb8O?qGϥukhӹa3K6$ WqƛQ=|+U<~ 8o~ю6gh}VC$-n LHW#'z75Bh>S=^T'0P99ȋ .Bdz$1Gie!-X' e2̙%qKXd) #hceZDQ|v+;O~4#HA8vd|"2̳\>3 f(}gΒx|Lp & Fky^PAV)ׂܑ(KOUUUUcw2@-ߧ5VئvF߲0MX\@ ѣ^:.iTg'P>ۊZͯ`*ppD0SY@bih232j 1Q62Q! Ej8*79̀}e;1s4"Qj<LA?Sf&0ې\B\MXsٽ2*[a$҂v4cVxjfEPH W3YhUI: 3b\| GFZ%cWU,30}+6O.iĪdH0r-"h7@uwL̚ IhLT>)>3{:gLV"ap#YE-%4"N8YL`YD^<<J8K@ev泜 m?5ZRQ "KeΫ!ޔ~U@²27q!Mκje0<S'X1E :6 xb)i{ >;'NFӴ_\(CQiAMڰ e)M櫆pu/'bLX#E a4"qD;N,F\ g6 BSؐM!($Ij @Аm !}O0Njo)y&`KOI]& ) ؐY8& JzX`5>8ciSze\{%<>A(`I4#!>OABm?uѯI*c#'bE rXC;Q d`DB`7 3Z-b#`WȱOHkqh%D4XqAgL՜z B$8|7$ 9"P.:!cW7#.PoghCC"LTEhfaaB:v"ɲ AJF%4L&bբBX8:*YɛD|]5 (L.xdL$*=}2-l `&;3!R,<"_gFn*Ͷ&jjfQplThؐҁ/`$2QpAgHG3iPqx.h5@c/ @Dh%;@)uzUyuaUˍS"f )N{iѲ UZ&ς[Px 'gNeLsVR'4)XD afI:} ꯮hJt]M .O48%@JCa| ̃@21]S^CUa~ðG]yРjObBD8`YxʣmʁBh[ec%BK\|`!_UhԵQx90VUP-r겄W(إX4`tW;`8`k49p P9 j#Ĥ܇`PY@d2Fݪ4-{jPc0!;Y֨ږ%@SB*KN E&XQ~.CK(!v ֠*0O5S *h@n=yo&ir(>E?x 6k"-L1M &Z.H"O $S9}TI?Br fV:S H:[!#mSDu֡%6pqe/ٳ/3Ml5ԁ+amg3"%<!fCխn#uA}IDL!Fd&}2]壄 p۩9|÷~7yq`0I0cG!?? F qOy^Hgܐw&r#F;=`*vmhp3֏SVjr1Ɵ'-6lIhrΖCA9PFk*2Qx5W:&1KԠAҞ,+f83<ZG 鲃[\7L%Y )ę!-gz !&jy +BVlnQhPq8uᄋtk+h'P`ة!ASLSF4t)V ,ٟC k9S5S|;|~A~pmc41u%d5ehܚ S:}Bqy1ΥG~EKrJp/!|@dVxrPbC?uj\6@d ag:L'ƩpU&S+l9AnRViN@J瞅'жG bE I&L;kFp;sw^$V0=pIK *Ab2-#뗐V+x@Hxfw0U b41`|| _ǶLc~?O]w݋IKXh& SLl8F4(a*Ub0qהGRgtS 9A,ksʫKl5\:iD@"&,j/Xl~9s N`ga pkTum(#3:ˈI P!Υ _U\=3SҚek$xBXRe6C g< 1cX>p7p w:?7 a< \U# ۢ3K* $Oo)(v2/#&i,HT| Q5Bq!>66I3as1N5^7&]b`ʙ>c\6B뺗b1]&׮]d2B4zc7MTIc A F?Q;/s=#I_g KaslʶD3Ke %Z83f/PQ2k^G&@SmyzrU9:咽3($8CC^D.H$ň aN]кǭ߅9Sw?utf{8X)82qG0Q  iѪpoMt~){Ϙb-5588_z~~?mlnlLԬ]bD9$*5D2  iG)>9TU'c4t,J$=G~4G &)Mkz?|)q˅]5ZΛSE4ܔ7f 9Rg εϞ  `O2#]ѝ{?t_Oj2ڎKq&6ŗweW>f.@L2 TD0(y#=7yXY[&v?`dhЬ0% y/ĉ)`F1yP33(J'Ĥ#2O  VVV _:U"1?s!ZdVYI%R$OMvN%r旛[F.]4_fQ (I &$ aSw z5])KfY5zum}Wv+{1l/34@a[Mi[AsICw<pP~;c-ĝP*7o#x߇-lnlZxmQĖx\ؐEK Q`#ʀAƑzg-!]k* (nKX9t`>sFBv *%"<L[gO\ A{ gGsI{,ʳFF(dTVa!vi|>~ky_`feŅ9ȴ[r0BRAIEU=?ƨ X__CeBwBGFUU96+  +kLD5\#\-@ύ&4.F5H4ueΉIf,{ iuNJRK'Y}9rZ(%0.KpobAB,f M;AT 4"cC >HuP ۮ {k[vJ!0TEY~=,-0>W`2kyQnۖݡj-`87qChn8,i(\-\YVE&a$c-Q:׺QdӉWC2MSALÜyb%x~+nA2s#)L)aKA4*J1fn09&1ِ4)hD'gJ ː~'y6 ]loo0x4M~LELW\1[p>НxgԳWP)o e'I9krU KAç- <>[[ٍW%I߶A7aqq  3鯈#S(O2Ag"I)6UiP{uӗU-_& `e;!`ْ rB)XʥѾNT$$JqI.N|RE|ol+LsRkcZt vBa|gV悬xrj5Np1vK۪k& d28sss8vm+vp..,#zϽ{h2 "8~Eފ ؛YjW2s*UXZr|sE\t}0K B4ޡWU8t0.jek~x@hrFMcZ)+ݘ|ogLpq + 1@ic\g-C]&Cu D+8q1W S--k,6Hh 1\ԩzRAk 2)|UʄT@FnZpf12ҙg812NP9107¹ױv z;&m qtsx{pO_D~>ԬwI% %i/dUAW6b_J?rCw|[;;GhFҶ59TСX>|$J87@Ps2L=C#|:ar%T0$vߑnpL3>ɼ"|Ԛ΄ncrwGf<(ndwD*\2$ڸ̩0j+N?%\!X[QqjK4I08GnhX.]+㳹ɭڸ@RQ6Z*b*pKr /_c'3FC-hnu,8<|5F% Ed🳶]HYpP]x۰|._[AhFVJݶępP,-Q{ IH 2y2IF̚c Ls&Byh9Hc ms;$Hq3 _e/NLt3T&P~TUn*nw9!$4F*Pp&FweόKnyS%+u8oG&8E@mѶM3F u 10 oȑ#~LF{pk;xmcqi퍖I ( ^pm>3?4!E dz XDRz0nZ#B%)KDzX>x3X mD\%dS2K|D:~!03y,fB[I^BL ҁ阴.6K[E62Xj E[XU_Dp#8SFdiţRODXviC $"u 7 Y!*_yTuUXp#xz"QpmÀ%X,F xxnH)˯a03 0e-U$|"Y_`]r/F[Jż$ ]~j C19+HXu0PXX`GIYj"DTO&`h21ef y^} ,M'bLQ+ YBVFh[.BsuUWטdI݋$Z^@-bn[oO?wӥ$JA3O/'qlnF_%Zhp8ǹ)Mm[MqזC{9M9gHdG"CB$Dl )|ÿtxO V̞=L?l咑!lnCp9;ȼX7K,'2ұMD$6'@eA|#82aN#Pzdn9pI€Y&FViZLBE3{k!6!*TJ/u]q ;2)ߒ0)bM!F:g&gS9t1^:j'] P Zaa0Yd)ԍFH{"[jڮ90 38=̔I8J D}q=1pW"Ҽ R7eD3& iC)f+א*"T+f1Ś`Ϸv]R@$RX_lK}Dt|6BA&yŠ*,b4$Zc0i'nClj# &͟e}w(hM KELL ХE,vn8~8."l5ӷizŜ4McUl(M/m]M^MoLƩ' a !iLy#WfI|/ c{j#P=E-ڶE })ZB$ִ\d=nEvcYU1&p!MO'vAK!QH\1c&K9!۠B ]y`%5ꇻq|{ q< M@˴a٪.~5>uxL;&V5Dt u .YI s?Y W8tmQi:X&[AD#a:-0Q {UǴAN6GڦMZKo6vJϋg+ԽVn|UqktYSdg'&\wۢm_[z *%H PKG_@@]UO&k4EBr<Շ&9b-zv\ymh9 7jd,c <*_1Nz+G9coVf54tۦeFPX(2(- BF|#_:Y&,Ơɰbs79d\C эI!@\Q}i Ifc6t + EO-x6E(礪Ab!ŭ0MB~ A@E,Ibgg[[AL0W4Mxmp! X.j*Ev%׃zEߪu*=g @}Ih!j2 `Qڧkțr =DȈ&?ۖ[f-!фE&QlSϔCzu6IW܀xsR]h{H8қ0)#G\ᙴjiee2L`InKˆ9}(sb!<( Zڂ͚ĬJMh@_gڽVVV18:ZDCXc箪"&s`iGǰ,̘䀌Ѧ`Rby*q+D]h~"IJ[ u qo3 fkՐ?JY[ӟWj۸ʗ؂d;DCpwɖ<4o)'AY: i@JRP:)T! Y9لzZJvX?5\ÍID*A0¶l vjt3{nr"%X!4XY]k+ aig4awwF* ipRKKq-`yy-F7- b`J𞱋&eQV抯j$ *VwZ }x=KLmu$ؤmUoyfe69;]ym0RU8ZlEHZZzɤW . { % y6y1JL",֗|~fe|v0U]óe 3*<\lNGyhE(RLZ1%\%iB̓ڥ2L3թ{$+(Aw<si04h& c9)1H"j֊({48"ҍ>&b @iK:?JKDF=('I;F+ȝ)v7qnQ-y"^DTljoG٤ЂeB&uYs*$F WUĔ*\Ĺ!MDAbzǩ4@m\\cs&hA2ָAP߂bAP5e'XiH#g,Wb"A'$"1(x)\*h/`2i4Nqu J,XcH 8\MN&d$]95Lаc<sr{V2{^^Y&4m6yK| JWSΘաM8l mCy)]Ԛ2 E${$%+o%xBV9vUl,i` p@k[\5*QDWwe C0Ę޴ \c!0nӀTlkwaT_v+\ĕ!󾌝ܴ\u".\3gpEek׮a}}]A}3dϷٕb%9s=M|wHړr7-kikbK<*KљTOs*)rT'$M㋑!IUJqx_ނ!e6Di]3#9_e1 dhܾU#z-Xt`+4rsOJ*7rLJ 4\:E. ]]-C\Jd9JNטCoW"/F Q2r-Vp52m[\|:.\0o_Lx]h\&'vNp2uHg,j%XR, ¸S%N$0FYiP1[pLScd'[޵m{BA"Wy$]{p5*U116`ώ@vk5K&fVy`I$<7iRX0iL*0I>> ZϮD^  7iqgg/2|L0Z[aDplF`' }uO0@!O߯A(#O#9 BkM?&0tΧ\j[eHcfDE 2N%@ 884MlT mmmu/%k+s6 \|n#j57 bi2t(e,]3+B6@6#u(vHV"Rظl7@yFmY M)JD'NĐ[ vw#-C(ĉ)gJt5Y{#mlW^/EA[TT; 9+8z֢-.kh4Yb$Vc1eNB794uT>M?:z(Yd@h%˶΢a[C*ŸN 6;>Dx?T)bTu \!6-wbH-/ њ81/RCIZ4TLnf* > i8ݕe\- ɑWsJ\z\askd *Rzo[?11 :t@q/! i\x MӠ'@gtĂO0vsqmde482-:*桙5xnYUshǥtVAstDE7*%cy6C*G`bj~7_u/u qt |[~[~L?~[&DE}Z$_$ސ1JGW6[NR{b﹩뛋ޟ !{pzJ@zR,֯-g,bQEڪ.=l… C2MӨPUvvv03&Y!Ajh%.ʤih^^\!)ln uK79KLy~VU-¼Р%Zlij=WY 2]ύN#c7|7c}7GoBx׎/#ɻ~oÅ!Cp9LwX&O1 Gi1}L3Bܫt5}SZwQ?s ͩS212l;}$ɏ,R+{.St]>iu`ye<{C,,,`a!v ZAQ 6uV\Qqfң$Pl;%\lm{i@jΥ9rZ09ދ&^>Tn(>X +jPQε9/H;qPqMg>_@7?~g^zaI@0ј Cs+hW2c! x! ƌ.ڰ[Vc7w E ӉV#(K_eLD$"\bRoA:OI㵖 ѕev5F^sss!bgw {NPedk%Z}_KZo0bs[LADq+В" B 9Ķqm9`XҞ<;T}8tt?{𝋓Gg@ɏ=r'v2x0XӧB ]")G )oviaJIK[᠚|Ew gM%o]JY?ϛNld&XS+V?5p5ϣ**q``tO&\!ZOOj@–?frڝ.ͪr3/,4I~ϝX)5rϊ"G)Z=}l#[`M.U}T!N7O>߽s>w\7;=Wzjyukڲz)'LZspp+f+ЂڠNRK:z](K"&pL@I^vmש?gHLiMO#emUm!=1zmbwwWť%w}C{1׮W^7| lnnb8 Q5Kp*X_VrWp[(PF~&K{(mQ6l⇠mj{^TcC_RH9$9@@B]4zrU? s xۿo~~z `kmܱsp>nD@0IB >MB5 Rb2?"{X#o58ac1^CSY9R+$t`0S]. ,J[71 &8x0Ο; lr0s ?q#$=}/oN;~dϝǩSpw㎻簾xAYCVG;;Z!PSa W0MӸBNd9mPC@H]Id$"sn[˹Fkqh~[CD۶?,b "y]?CX"u]caaM`4csk w}7л?c8嵳ckALkfR,ḑLj|dkn_3)J>$9Zv'"n@.`MJR~LW]א!QKO (06ḽ^}W|ֲ;7^?ϼ鵵y)ii2(tJ٠JƱ!QJ.ݔ)58)׷_.Bv $1A )#՟*fS}4[n݆XX8z0nf|G?[oc&_ _|}S>C,cqa  mw?َ]]! eA} [mBK͝@k`;_&(vR6A1,``R4ۦŴU^r9i .S@lxw k+ϝ'VKuo?sh jd ~(q{5su{?:|̌!I0P00%?ojD\OKN:e1 qZ߆G>zr>~c8p`)a0ms pΡ?`8aAƬup a)јɓHRI =QlwT"E( XRZ2uYBݜsE#+VJW/&1Ο?_'8'^ߺtM|m vO?/g/;vo*ЧI3O6wJ!m*wڇ)RƗD!ޅVyǤX3Q>+Pi<85ᄂm0U!]q$5E }e|}$w=3M b ;(P]\΄!o&UK}\쫏 ػNoѧҋ?Ќ[Ha22Y6.lZxG?|8lw*^񇬅섩e(#ʛ/_HNt}e`ki0i  Qonns?/?WpM7㮻K/w7p8<_E,//o'ŋߏqyϛTan~U]c<u6v~ǁg/nWS-}(?HחP V䪵e[QB+dd 7Cg2.giy,W=qo?Sk'h6.CT˸p՟9q_ƒzt޷l_xv0RB}}遞 P@馚&XdI\,IV d[@Pn]2AسdKJnUרuC]N,RKJ9MBhGEtA_6)`cco-,//ceeC<ܳ8q(v qߥiZ7 ?/}G1 3sя?Νßٟo>9<3Ε1L}4Xh4p 1W>A@h X,$MT$e9s>ȚHdHhZ-3LOnARppnF)j:Q&,j !mܠyIEB!&; _X 4<:@MAI%0}8!)m&IX߮$`f$umlX,Y6[!̂8s=gƜ 8YW6̦ dF _=M;9r; v2VV`0{z)\pckk+p1Ɠ V],J v&R8BTg6mɢ˖?a;*衚?5c=~)]~{fiG y"kH|SnxAVDgnbByOJ87 IMx-2ۆ!naQ,zJgYC({:ð +*6Z宥bJ%`RP fP4c*=g4x %2=B Œ8Eք's`@홷bd(O:\ $%_:)&QwJ>OnJevATWj4zP2FwLX ("F vsO${>WZKp7wށǿ\:S;3ppamx2ׁW.6Wqmu/\ \ #[?sxoǰ|L*߶0O'q4/bbs%ne)":JZU/DatjILWXl=5)n7ТCj%9+K}c&MU'Ωؗ6"љKz1otʤIz':_Xy-%e0V^i?}Ԫ_鉔{vMtg9/,(x!O>z jG+8},C;v^=pݫ+WڵkcTuokk+xSd炂i56#f~ڽ1vѮŠ2 +{ut}j(zsVݧA 2-ŅXފ+B$/=#֖W*kfOzdhQc(n_dOAn@>3UKMqa} CxɈ5֛yڳ8^$\A}}?QFlX[]œO/جDH=KV7K]VpLH2?d< +'FA[yd(Bh+NW8^1"/)A]Q dHo@&ED C(ɏXj 3_`wrﱴ|.`w4.Wke,-24 TEIHJKd\ 1ma+ͱe\7fk&{d z]y[z[sD0X{RiO]7يAmlO,)au~&0cqCߋ}!UA=h+(o~B`c7b,q?ho:id\tk5W_[nomy}  #Q)*LӷNv$ױ .v;m?eaǤg~HUU1tB| d>!KDB˅p1zRT,{2.+b٨ƞ˵r`*˖Z)n&P )2E%J^&BJ}ӌYc 2#(dMr=&Qq 5) E <4B:ws] la Pv])u07\ .ތWQ--"zRqd)`#W^7 X؝%;AtdwbkUxdTߖFK`m N.xA. Tރ(Q@P7xnI-fkyŧX2wUB*}.L@N[kixa8!'{b_F|S$˚/P*mK1Gks ݏf&I I{!IT~oçmϽ~6F)M4M3k/ih@Z\MDH#ml'WfWpzqZqͻҪe@l !GNűC?𡇏M aެ65@-油tʐNt.❷_]·Όw :|UL&H޸զÄ˭|ǴWՂr2r6^$U}N*3HYDWy p)$eyVf mҞ:  zlJ/YOA&Mus^nE&[k =4Ԫ3&+#3=3 UYTe/7,֢|:bF{?I/e+QL/%~DB iƓͭ v&{.AHpT1bHlĭ(ތe(ihUD9,(imڤ\z zQ}%VHOy PötN52GY>t )7 AuMA:٩fb-9ۗRHv~L;On}woyܙ 7j ;@h4Uv@ 0qhG-`Z wƘ_j;x Ղ4lD._Jmٟy[s#(p,M/B]Uh'M^D4Ą yu\GX%4' jM`:3SObJ]aG~vs etILJdk>-zH5%&-R] O#@}suFP[MCt1>!mh@qpr 8jo4h]NQR{pkm!lnn왳[ fC4}ʊsy~FG- Jpax2!89*"k8A!p?K6꘦|I@v?L{ Le(^^ϑHaf`k S o\ʠl2GZ[Bh#3o||:EYM9vV0&39l`r~ 7< !Zp5_c hu;'4ȡ_}W6c G'ݲnaxWΜwҮMv.dXSH {O|29@A:',x61V4c%gwN8 J ~>*3ɘMlƻim;g&Bm҃Sl@+{R20\+ CBhhbh"SI;:~12bhgtIX:UV=yTg=cGM1$X26b8簵iqJg#'a: P@@ګ@_#|@Caǡq'^"L8xPHm AJ7:10vW /@C򠺏zaA<{4a}sW^`,//P5tq|_w߅ph|RsokY 5TE5=gzDz:7,@-ڄx2`aasE"Rk˝ue>oռOlJ.dn hB]u7IB2a֑Yz;^Ebe{3@GpM'| qO.\m4M6-_w|hn9^П#>T SB0[[:Jp` \pTyNSꫯ… ѣGK.! sO>=LwH69Z OHAۍ>2W-P~halA)ZD nBmیRd^R>|UO (YԷ_+`Rfi2thcwa*}Ov"g /!jBp:|62)jU%1 (>Y7-^{5wm0iz~snc+Oԣuvs10jV mN"  Ǹh}nnZ8tO`nN8o7x#og{~etMnn*k6/~ }7<33eMdԜK_fnc2sG#HĥeL3GFIG0:(aVP,qvEKq^Mgg}+HuEANϓʹw@IHsSٵ6ې&0^ubMk,qiB?{)"AP,"uW;pF _+PU XvF4={ @;6Z }ԋ X l:Gĉ8z(^TL%?~Νzfo#ptE@Z_(APK~,LBg+6tCn-cBc(}ICjHIN2 ׎|853avPGGOXpBÝE() "@[EBJB7V)~qNiXٳgx`2`0رcQlh/= 8B& '@im&!;Ֆ*^!eJ'qy0XÇqQ:t۰5'82`{{\rшi}N8}j ^`u=wȺL9pd^#n\Kp%|M۠i&>NBH'p*u9g/Y:FOLK a\<)n ͅaKw  ޲v\8s[x3F*D,//èp8&-` _dw-9LZҀ8wUpa+8?9 0bii8t<}?~OիWռ*^Çcaa dA&X/_WU\!1l"dK;­V 4.v "HLXH "x v bǿCFwĄ+DkW=gKbB˖udkDhot{غX^^Ɓ0??~;}ַVVVpTU|fJ?{}biDQb44 &RӜNiC.*4ΟiA̹Y Gw2`#0 ^aH> A)W !%d :|AC=y_  i1,[]$P0qǙl%~H[f4.O82,{tj6+gCc{cHdg!d2_&X7㘛)-.,㘴N(bEU,̡.#l|a~sX\\āL,?u]㡇ooBF#bss+++ JK]???ǹR0784NUj 0,]F(k(PA3]:\`1=-NW<%ub@-2X[ULPj@2dE8yJAi{Z3NӬ(-diL6 Se]Ц|pS]wp"x2H[0 05&I8M w!ԋ/߅k@+֫%4<&akz1onn X\\aR7|3yuݬpA "9sc(+J[lvYj={[Lnr!ZUE8K`ـ6vl}LS&z}b ihǭȪB^ $m7. ijsaܜQ_~Y^ 1S<>rNa F@p[u".T;ܳ%QjiAbFߵA3isccc;;;*o۳[Ѱ"dGXXG؍)"V*3T C+o8z(~a< m =vvv0L0gL&xo[nƭޢ69s?dY͚%x2 ܱKUM*TB$k5!WVS|e,wnNu}EQʩI2%>13~ܽ0I=.O&IQ8j!袚s r]z(ȵlQ^V]<gϞ.vvv2 `2ø;"1Gp)O٫k lmmi^̧u]c0`0`nnsssrm[+BGg?Y| FUUhVq Aɥd2A:/ر#XXXd +LزJK-OPzb1gy@>~ƥG AuzUB*YK*2llb 넜}g_H̎Dq>uEjȑ~Ɋ}5crJ: |r.I}n <4)9^i&x簶ڿt^>}Z!V{dE-[JZd03gu;-\eךc<9ȳdV̾b61A'H[(廖)s_jNnc@{Qf9\xgΜ3 `2|L&V@k6 *6MZX>~ 8p}Q|2*,䳬 {]xo7{1#2U(||K̩59aoÝUEkA#ЙrswLwE@R&kdՀfE+30?GԞ3Z #UmbA 儉a1r#Œs*LHZ<.XؐPP͎]3c˟7&M~kkk?rtP /&\O4q ھWr{{qwum/>~wtL֒onn_ :G9d2UřҀѲ9&bI~>kPb.Y*kGg- '`b[}[p}cDltFýji+Bp+Y([kvop!k joy;H ^Ռ 8=^?*Μ9N0wqG-WFr1ol$9ӧO㓟$z]A]\@.ŋկ~F+‚ff$l+!YڜFN1 .V!{džp"61NH{c@ 1YhWeqcܪ+k>f,_V O?/t,R&. xcLeJQ^,^u`kL@橛ƷK2! L*?N$o>I|裏b8jJmk&@dtq&,5,>OWW/܊hfjXÈr7:|(#Ey솛3,b&AJKLh0=b~.>? JIhA*`?&n;JWPfsU7(xh4`j bOVyV+-Lkl:Ij6Fx@ddLǙxkOiah?pˈTtK,K'"vm'>QR ` ׿Niǒo\H&PT_J4(~B(CE+ .1w VJ,_g5)-o3- ' gp9] ;YnJGHPrqvﱔڛ&m[f($ TrhPRtt2^R;)#%PnI;oܽIg\!J&̳!|?= e \4cz9]`T2؏~lY-֝ /(j`3!`Ad'#r%$e^$+m[^`@nNĹ.6V jHm;0QD,j}fɼEIe4c YB[yCx:CK+0,DM* 0tY`*o&.^YP '6NwydP``edR*J;ZxmHx|˼D~J;[(7Rhv5E'`B~ݼ\9^:AC)(?$&6cy2|H +cvΰʏʳ3-~\|D?WL ry)^nեhx;?ge¡s dKǣww92ck,vMw-O>/'jf;6dwuf2Jо ^!VL` +'%;竃7Pù  /f?K{SogjD>zifl(%dOOwwqܹ=H½m[MexoG{ɋ:f4ka݈ԤS$ ~dzJk %]yd;bm[4mG`SDNv e|tZ|,UMzlE9aH2z謾Hɯ*UrȘ2iʸ.%ظN!.Ϧ&:N `'c;v g4G8[`#3xڶŽދ//XU2sx'q-7;֢n LlDbO薗p 1ijEjVpn%ἀn Dvfߞ}$`Oŕ3%n(DZlY@tvc_NO܋-'}ߚ@6h},iC'RǧIۤMoe"Iraٱ;9{gI?o'p}):m+Y2!a_wZ"?^Rˎ@6baY`cc_—q1,-- hJMH@Fy(s,H|+ TV,][ T%*6v,e-fGٔ}⍸$%l>̚j*ev, \?Ot#LrUM;QbOuhbEh d>;͵QHa<lnnfߢ~;~^Q2dgDRLPbwy'>OOݻO=b5c_x K24S.aM!]hJV]6't۞6ke-`BR0's"/OP\H[)'mBEr> }BCrTMgHtvL):|Uɸ=m⦛n§>)yJ666/}'Np+kuINM=9s1Iz`>~7$B)?OвWS :f^j6 uSmG c"Ã:'Hyaw!k砡 jx2I F$sC JZ-X2fA5s>)gY%# ɻ@.!P]FZf =8~JfXfæ@W+~ }ﻑCYb7l*7](H(թJ &GzEI%m ^ydQk(>w0j?dI vxچ{}5aHĈzj*'e}xb:h9:%W?ܢiIC(ϟ3g_3m[|3#yse{ !:0~?WlCga|fڈ5.kSڮC}EOd vJy<ؘ̳1ggS+7#fۣ+Qޟ+|#_bt6R`C]]^1@.ˈb3BW%0>S¥|4s?AGuc9H\RDs!j -ɼ*X]3X"[3,$dpj>FJe;1LC]Nd6i/t- fQc7+SPhpԠm(4_$ٳpžnn [n%h]Ṯ0]wXKw5g )b7iGk8PmAf#]V@i3ᥗ^]Éԩ n %i,PQrP=YkS2mKUӢG66N1wXKf1@PeRv γݲeqfn!Z(M)NRMpSmRS h@_ @2m=d"S /)۰듟$>я,BK܏o?0Kwaea~?<" 옺J)l8m[_:NpSY̢] Z~,Mj,]DPڣa^|O YBMӰ:0ۊ_3KwƿbFIIxPt1RAA5I. OXPs\LCg%W(fnBxW2ƴů[s?s ]<[a~9d,/ӕ] 9B8x >_ְdW^Kb"l/'.).$>yّ:ωR/4:H?%Gzw>^mƙ%cHUC3mI&@ƿ  /B&lgmSHM*&30Airw-!hPҽ{!Y6j.*33.&Uµk8kޙ駪* NoWWrP0W&,Dٺxi}ýޫ:wV[R<ӸtR*\:~v'`U`—˪=|^H]=wi &DUnC"P118u![3} =8y^vB ]HC΂ PP\7UI[ Ʋ|.Tzj{$Za\Yߗ$t1혯n@{ >rV=#'>iYk{o뽰Y-}QY/@etC#?pu>/]:F$u Ȫ!:"xZɽO&mHnV+A7Ō5@qUJy8I2I9Nˌ k%[Ÿ   7i(^OV#37)?ܺƹsp"vwws?s8pțoGo)o(|Aw}B\$b HPhw+gp3 ߝ2mu I3P#eFp OHQv H$YB$uڴ_>$u 퇡5.\{Z/&k=e4\~r)"9|cy\Tʡ#63WhwKe7]Y0?x5W,InC_KMǿn8eܴZfͻ]++Ont dUUJ$u2஻؏+zWǹz?^wsL&w}xަVl!.g[V0|+@| {ߤ,}N蜝e a/۶Eph$7.L_ mA4_)(t)kciii׀C}AױPfn eX*sJ!Е0W^Q\DB?zn@J3g;ɓ'КX~S4h ٵwN3 {D% (|'t K(:PHDǑ[9k>o }x4G⬋dF1ەgM5s_<0<"WIdFZ@a(ըHxߏ|0L]ߛGf{ѕpرccqq(ʈ@ 0s/`2L^l%;@U 6`+acBbQ )B;BZ2(sĝRRL4e[i6"msSǑDC͡fBω"'ˑ!T /]ʪvwwUM7>`aaafdu:շwF*0>:#G`qqpF`(ݏ/?kVpmX|a i*ֹc责u`kÈa% 8&--5"] ̫Mxij{l kHP4ϴヒn#؍9(xBjz\$~B,w'!ed Yh\>܂~e jDH(8M.hZV.H~zTg,C9nWk% 98g__p:uJwʊvӮX,RٱvvwըUT!pHUj> :ԭЄ%2͵Y1\@]bϵ(MDiGǹĻn#6ADJNs>꽢b{x }om[L<206VL: M4Mi)~wÇUJ:fe;]F8qD.IkkkX[[S 3=wKQZ269=*H] A?Sr=NJϕ Lլ3}RF\lm*gSнS'3Mfkp3d0Ek[ oQ!P q'p"ږ\!'EH!E?e)%*O -ˍ@R.ez $_ iA챹B֢Z] -u]oeZamQ5oT+%lQ{;R>V]`xݶ'{F荸G,!6Q8AJp( nZI/9#֫{2u6 @4"j1ݱ ErNq4yP>a]Wt]$הcCP?mD1EfyX7`?v8簼x;;;hF@e?YBq%D:A &%9kʸCdil؅HVg6ޥ|~UtQg4L13^T$'pb$9ޝM2&gINP\xB!^ <{Xr^C)/0V'BhLUz|5_4a`f ؋E!5}:7Œ@-ЪF@ROʇm!J¥<{%]L+mۀd:\ҽ{+zSKlEwU!βden{]>@9 F# N?Zrʞ L?`C- rR>=1Bhs [g>{? 9$3~'VԵ̧!E ~XYT ) &x8#LWE@gg^'e.gW嚓,lfGeVE %pw] " Jj, `!=` Xr̯D &/#\rOEuJɍM9f¹sQP`܎!˽=0 mG-&D$Xh泹CՁĭż˻-qIooV"@47c:iw Rec{m#Ζ0ˊ&jEԜY.,-,&y){Vm`eQT`[J -R-ZyvˎTb-Gr-DE%ؓ_oIc O.? u:y{qbm;#՟gFgV']U~pi KE4&&aĨ KOh,Mo&LvP%\Zw]y)ҳf W^O.|]̟nA\[Ҭmu߬= 쳖60Hܪ VkX@gLRټ)(\L$4B<*d: b>M"P-*VP grjJf5My4eG3<EЪ`L^ "Kׯm2# bsSBcPƟsYRJi9tiYu{ .bd{{{[Uyew#.Zs87Ǡ pP\ #0ҡ{eJP[3u{.fkd.[BMk=m 8 wQPpM'Ls,1HZ*! 9u(n,a LB =[ɜ6!hz" !2t\7g1_5~DZ `{{XRʩV%Ƨt`J],KC7UKA_#4epUz@ GQvI& (kl]"eLrqץTZvU=HBB_'= fM/M ɄG{gg[[[S,Y!`Z\zf4(hWf[}DZ66602Kj|m,Uj36 MiFs{ju'AG(Ilv"4 ETU%0/ %ku]{g]cƪʋ/JGw܁SNann.v1x<._/bcc@ N"Bh1j*,SXbcb%G@;T+TuYaNV=&a?7ޑzE."wJn1#D91cJ9M'"I\%ӝE]wK]P=lfYx :zft0rS1 4A%k80p}•[[X]]fh4p8pd9v n!daY`o/_IR۸z*>w;@UUFXYY4̙!𶷽 W^˗3!`c;Q]-P vKn0$lw?I"@@J &#OmgV\ZO߄o*qOɁIZ8z(LkȔ HITҝ-"<5dL`FkЉiRSҷ<cn~WU#w[%`gWp&B<3Umd\f }e ϖzY~w/ߏwEB!ŋF?'Oj`[jMDy/-׆!pixx 86~E4<_˕~W^խlfYirf:f%t 7S%eꗝzM<]|??k׮a}}][b+ ^`8jIҒ۴Gպ'PRP0IXYr :>Q{bˆRΟ2<ۙ[~Q([:Uk'bd?_d"9G-%IJ]$pb3J,Quy\^ R!d2tv ޾CEl^@n ZGxu,o\Ù3g077KX*Yڿg1w.{V]MIc49pѣǰU փe.kHmlooc4R|0۬#AIecL c z-bc Oڨx#GrO ʤۯ$0 ŷ$ 2zm2C)a IQB4cg(*.58qGs+ ,z^,״Y ﱉ <ѳ9'Kw*1Ќ-{<ڻpKO'|R5T v ;%P^&] uY/tO& 5~2 -U+Cl6F;X]]:w1 ^OKe_*9zA? ÚP  nmCR#ou ,jXCBc`IS4'I* CnGlAh4x2r1B>l#Dxtz l Kن.-y@.(47%XG|bxi|~"]8ٙuBv;w"5[0Ç077~f񁛞Ɖ[*^x[/ K΋-?Ǹ`}!C%0;h}\c|P],UYD-bGqCn#|Ueu&nT& gr'BB\Lj * `ZP3tE`AK &GO˷Gn!1=qJ&" %i?YL|n.|e:|Yln.=_f22qe| _|S*"e%fYoUtm7<grR90׫pÍsG+#.^??Ƈ?atM3w+u0 /5j""]£{?~\ñu:<6tM;t}U]aLު0 }Wo0xAvDvASM$.qji5u})vl@^G;Y[_%zx s܁+ӟ?mOpm"`lt3=F#̩ :0S%LQ\g׾٩9|#Ļ^'NZm8XyXY 99{$N^;*"b͐fèr'vb|gD53ob}#_)\,,΅\c oˋh 8g%+r(O?\ ׺B#y)+dIc=ό>Ł]a6'aL\Iu$a= n0kuz_~/xW`0sկ~_pm혞bIt\FSט*@RAɈl<@ YlSBT\ 5ƕG-J&h@gHh9>E;SejPbe}?&hHh!&̀spM ~ưW,6o?/bKNzcr[T{ĶB MB!#+Pd}LFk;!Wgi- KF38%r\O=fp~Y)nv.oمg>݋>,zΞ=Gy˿;s^t=Ix&}@W' >,ԗŃH^@#fQbzm熨6W`6ό J#Kb: =ݱV)B;ӦS@x\TBW/_2YICΝųhBpl@\2׾ uT 9:uOJ{omo\cnL#wiՋ12، cN'o^o<Ő.] S>PL1lYů=4;`eu X^^Ϟ=/M|zxRkZ]~Zbbnjk01T"C }_T?+S60eXQP[ kѕ 6 D#]k ZBcϨ$]r޿ VWP;c4D 4PjYЁp;,مgb5^EP G(`ArY>A\MN:')=ƛŏoL={;|K_½ޛg&BI{HvB?wDZW%R}H޾<ȵp[e=*ւaVs0)Z滑(2IJgáJX yi9h}Cf@0Zz+1g=j 1q P9ki08-  KWw%_&""^*C@L"mU/-F0&Ӟaլe̔ 1UV1.N'7֏ە@{f pɰ}B1`mǗ>v3{ ^99 ={[|_?m);wwj8 ETڻ- |W zaT\9=?mav&Y0&֚Ȗm5L8RlZe$!Dme;ӯ5^AS:Nϖ5v=[n 8wʆ4b2kQ u:gJɀcue:f3LdH$v7E D``<7C/`=]EG0h7~WkGIt" KF#>W8V.c)wUJm׃Νÿ73QN «Qs%%LJ傟k[sc#4i}b>e_OYQaz G[ZZDMfs4jDXp:!H|G*&I( C|S"'~WXY^Ɖ.!@.E[ƃ%~ r( qJ6DYU7)ҺY߂**_Q5aQ & ֹ)(nQ /ӷo;>z!Z۲,AD8w <ItŸ[xL + Sm9Z>O\]m?w7dhHAo>W&tϋs1a"1JaSH 1l 6CMOZTpg7~LhMbdaYں‘I$=N$7K/)3a0҂aF]C[^mCC  pU'G.Q^pyo<@9yn`ɖ)K%t (qd3nUDESH0Iğu/,` `=Kakxi6.E@xhKsŲ*gYAo)g =I#yR WݯX-=&y;c5ɇh`'ЁT{xa:B.ǵ MNNSS3_@Q(eɰ)!:/Iql@v^"`[(r;> kSc\ȴIٳgտ“O>t3]oǚ}ia6IЇa '0KAD+gq~&]!J֘ObaRĖR|HыJZ,1V([+%š0E)Y3NxAiEQ>{>fgf\ZǎL$I[ >=@hRCXÈ #w4ѽt5GQA%/m˄WzwPDPr^0^\Fs~iobEutM&1LT*TW,!̋Rm%b |g`i@#^;͹"'NG>0ؤpje3B;Fj✦0؄77ETC=3|s V6!Μ[W .=gR q Za ࣦC,@m+vpRUҡ Zͷ V< `W!ӂEPTWއNobu:9kGoob0i$ߤta7$ҏ>-\ӈgD@u7xߐ6KDžil_/ڟfz7L!)|"YAe#Yֻ cepvlz+֚~/31wUea+{x+ǃEb@$qw& $=ABa j\ EAo̬W`-ADUJ`tTk*'e &E2 *(dz,X0Xà sR>,Ν;cǎڋ_H ;Wqb%MMg* N>T d<ȏ,nS%FS7rʃRP7xdjO f=iÂlh2lp q5|O[[X]ɓoJ*-qS[9d4[z*`8dgG^[)eUxLS0T\? P꺐.;l-GxuB[Q/s[ɹxUUakkes@pRoA=tgc0>Z Y{ʠ=q{G1 Tsh[{Z_lUS9kAWSLՆ7&~  ь6+Kp @9Qh뿓ZnmB.u]G믽ُ]Ғ>A Lr:8YVy^ WQo6.K*ihVrT!R"QH`_m@sUkAINAS/|u#w$ Rw#vV_rM:f؂H~\Z71U;e0J &@#a@;'YV9axq" ]A^wt26TAE!O1eiiH B 6KHd]%`>zu8_m6) B1(2* Md[x(B4 @{讻2Ÿg>>g_,do}ỺA= l տ <+k NoB/a- HZG#UykLTAPl@13-wAc173ݸN@1{<Zxyf`73tH K81!O1_2֤fJ)!L:x;u⁣'4XD&L1%E(@S}#|ݳxac{(D$Wku.@>@=^~e?FZ,8d `~d{}`~X=GZpЌz0\;.o#gڳ. 6 +96 ރ q8da S1hpp ௿ *S'^Ʒ ܈pr;pd`9_`WXƛ$m;XA~TXc}r`]xPM L L}=p]O ZH/}_ow܁}:LO, _BZ#o&QƄk @@*̵]܎rX?{wI0 ȠAf:T? }4y<+^etMj2 9-!h76lT=صkV61(&7?)ȠC @Fz$xx!뮻7|3ߏ~?Q'n} q4|2^u8qI _?@Ċe %?Gqh)x3_42\;PQ#xgQBW4Nox&OI0e7Xk*<1صW.-ҥI\W{\; -,-fr[pSf: J!D)ݔ7&DD(TF[|uBmmMtf+ x`0()4aM 0 'AUU8~8x ٳ_=:' =kiXXX3ghIk ~ Wv­kǤЀU~Tf Tc`<4!aS:1w}c!KG4 sC_S;0z HjCpe+":yf7qg063Xr!`ϝ,YCy ށ}#>Arԑt1eTxRZ dfM')kqZK +Q!d@T@2'K77?}7N_ǯ.,C%\xEQ`ff{޽{1;;u033kc8ʕ+XZZ a:EW|ef=fMH!;Xlۋm̏fWӃNW#xDɿl-:"r\y.o#x913Zo-,ɔ(ѺgqY|_MA8z/+b^9w*ȑ헱 BG FUW(bhB (x8$zY]}^&|rD*+L4zl-/bnۿnӸ헗qʕ{ :{IEI-) xx p3ĎI0ϓ]_$_ 8xl5=,nh(g&Af7<SƋ1۽.O]Ye&;, k{  kKt- 8|p;=]!ȶ b "]aL>9~h]up, (i%x @߯a@] õb#B`L^`B a@ WX=s w{w~4M*I~s{g7¤L' sǵ\"!Mbq ֏\ǼvΥ_U05jDت ,LݍKG~~fla(]}oi8 6Po :#f$y:texr0a?ipQm< 'cEly`7[8D' F 9fy]P5yʇx =q4so"}F/m.jE)6^Ewn(9-4S_C+ qZ={/g[IH= x+-2*P~ۖz:aӺdh %+͹rʪB[Zw‚lZ8ravEGFAeƥtyݳ7!-Snw ʙx&~3"N>o71l@$h,ߦP?'.Ԙ`vd 0$(~ S+g+&B2ӻ[1[:66Z=)}^`,)` j3gp[{kU rO̫]V݀o0p Irp@nc&V;)fLNxeNߌ(1%3 0,cUgm>lMeoŽg1^R,S5eûAdaj =8gz8|N9k=Q m%rBPbx+q}zCskȐ'{;Xb WkuWNkHԎgkxz0NE/ U 6 0av:H0YIRyu.Ğq"d$p1[ naˌmcK9V}H]%/ `]x|/1qea2\/ O G!R庬5p![piA6 tE*yX^ps/ 6Q KWko[++X^Yny+;=Q n egھ]\hUzѬc$鳔N%4`S`m~>lp .,AۨsnS!\m]%]F$JJ6PBc?@Yrخ>X"ʍsq*ޅR ~a9i8>$e~%?ƕx|n\1!L8Du.Uz2C/7 '!, 9O!4Qh^PCsȌvefp='XZb}e k+W`;(Li.6r3`M'R'`0VX|T9DxOaeY@[2L) D6͝-+gfZ1nw)sAo/S~G%` X 3\=3eUI `'cҥ !?fEuJV}(lJPx :.4qy̝SLP @ދM2z{#!ǵzߎ{LxH 4v0Ĩ kkI&^i*M`8bccX]]p8D]7z Tt9I95 X?Z,s6<[z5!ئAcC/x΂YUOKPzo+MA XfWܾfh:II!Gov{Gq;?^y'NƵHj!%0rpn<"ALݱbDa qS`*06Ԡ<{K?'1ظưE.Mju8, V@QK.4,Ura(Cs.off&oѩ߁2p8&ױ-uREYbgB΍F1/"oܱ-4sH=I﹊H~ ?Zރ\¼ 0IlZ_ƭ7ÕuxES uH&P")yQm`@Ƃpf3 "[HZ\9őzV.bʫ(CE N``m@گ3,"KOl3ɝSUPj)$SŠ+ :[1 00 וg@G2p[!]0%P3;}#-8(I쿌S V_x~8DZy4هh?8'P~&@.X|-JS5$ykm SU6|O0<- $oC\^\2/ )'dN)5(Y~$G\#gC7\Ibw!u3s=wDZ qXz rxf A0}RHS[XīANN~sfRu+`z={hR$z\QUfͭ؇05P4'Aiu* dj-8D3> z} +U(hjMcqrs _=s/E2лHZoK"L%"|֛@ =[F)/sJgfrZ i-th ʵ\k1x=q9{T1dJn "0"0 CF=+e2@T7P23LH3BSN{o?zZA:W8~u e&r=Wj6Lߋ2 v]+I{,YRc-qDfcSR:#P-kYW a%j%FI?=s y&~A OVgSqq4|I/~T0ƚ8BllF#Y..#kQ"5^^Z3̩Y,La, a[j ͉Pg?o7\wg_qu jW-PK*z. '#)Ztq6[Z/ v֘詘r<#0#cÏրKk'`W^oFUqg3d#ϔ~q8cG72|)`zj ~EY(l=C͜ )7dH`My'v݊ß];+?ƞ07:>6o *4[S On÷VnF3Gw៞׿5P> sǫ HIa4b>\{w^a Yq2L0p 'q~EWQE5xq} |b}m/e^ ־B e,EoDjuċ;_KVj^fb֣Uk?RSJ(ۛ} un:,\'O$S)dňi0 eDX}s>dGpmBcMqj꜋gD:_ ,`Y@h9% $1pa~{;pif\:Io`~س fQE@ 'wQc[݁=쬸T9sTj}4}Jϥ%pڿ^QYSػC8W8Gp 4@U*Xqm0K3S3hzTK ~e~d.^~*`%DBk'O pIhF=aSYX4 Yxj@Z%Aaи_sSy$'\Saqi[p\c4ZЂkó !YekAȴ$JZ&sY6up ;MC)d.5h涉Xh6! CeAc\vߍ [W_9+cƛ-)լ2S^ @GI^lނ'?>[EkqC7 Rua/QYOGaet`KZؔ*BKF6zRFЗ"i\s6M##+!B]QfHyQ~%l-™7az`t&s0!E]W_$JdJ+Eޅi+5B w3DhHWG1Cm]J3&/ Xx'wCc Ed%7^㙃88qӫDZkec0^Cuc 0j*X {p?Gr$vZ`%&ڲ{փemn]!B<&>z,6ǟׄ7EbU9`#TM7v5=M{fz={Is!WP@C*EC ߐd 7$ %JZՀKΗLB/lhe٘ 3ʔ  gOgW@&,,@%b~"XT ujoD &&6M5pΣ㨥ӊ00s_3;ARd)pMUC-!R||]8ڸ8XʦpS3FŒQlCoE3ش?1rz=jh k҄  eJNFPR!]TEa"NJ{/se7l=[MLa @7٢:pv<V}Yl'|C׏^Q&p _u 1&@9  @Bn@m5eViÐ"!ʣqaJ9 ٍ>E=wc;gξC @Gdu#;e…GV77PHT#.={N݌BBI5ZK*8pm!֡JF'ii%$W㸙>Kk2Δ,BaPJ]!d= 4MTK| hXdڈ&@NYkJ$Zs.\k̘$IVmK Z|CF*щZvX{ά{`]_Ǭ݄O[R5 U%fZQ- |^Z k,fc`_a5A`(o!(4ˏE2OʞxYi=~csF0jLDk(T5bXx)\|9PM=GN&!$KR75JWn75tgi`.P&X؉Ci@Ly5 DEtl6(JN霃g(B Y i,8*GU,FhVvIqwx{Mv b.2(F@UCK .<,6&zBƷE+53ͭXp4\#3b^rpHMĝ( DE ]_XP]ڒ i&oeK2FLu( FL=S^ ɩA+k)`FV{<1o8w 6Vp0EDomZ#d Pу'ϟx<# `Ap4DW{Ml8'M]KVԽAL.H*Hơ!5b$MIHrISkRڶ̶4&uc D9aLRCQpC/ P&4~вC>LF͔b( iAG6`oPd8[dj ^HiMM̎FbP( Eͺ`1A.Q8ȡF8[քƆQ#YCe%WYw#.} Y=? #%Đ(&kUddzE nj"'DG=6QƝ+r^kg?{~?}Οǵo1-vReBqaaozyoKPƳ6i0 Q7uRSVqh5ҁ7M]t0F!';'a:"C1]?G 睏Df&ubUJ,S氥QE.Zޖ ByiC]ZלC/N.A1e cXڜ٬sQz4XFP,Xy*s2W*UIѩ .R)ȇH[{1afp5*Μ^y:{4+˯..,VWqk {m%0YtDa%#6%q#\p P1hy+BAK)DwE!'L{?aaa*9V{]} 5ӯ'A۱T$.A0 /{N{#Q=>a~^/UhH,} pƣ^JA6Po]mai`= C @EhYXF)B ʍC6(K?MB%̱Jh*p8L"eGs#+Z I&tKÀiCSװE ɞQ@i픝L!=@j wuDih76 2La-E9Zَ9e_̀iBU'QL$^a4qh~$ЁXZ_ɋ `@EJjy?ĉx+MIDAT8u@H nx- p>tp@4zpӱCx?'^àp h DX; ӛZcO=8t3m%x8/.0dנ? :tkX_fp 6u0T5hڌi\ pO,R\YM_Ek.6Ăp+*t⼏L-k )JRŒtRVaUe.0Z/::($abB/xB|d *i>aW`G+û` 'x1 sTO;^ sP%/dUFa? }a{%ґj2(lb [kliIަ)7%BR y bݻkn=΢AAI({JU/Աk*67/`4ڄ1e™d y> *66> y5);)SXr;Ź3%?@~Bϝ)0,\\ķ;z`U9 $.h&`fB17;x }ҴLM Z7EU$|sIIqjᚐ~ y\Q:䓫ˌXzi& $ +So@`2F 5 PW40p8$"IkuMSSilSB =qS D[`<0==K+mm,S{nƆ~КE,&x@Rh액lQ:k@bf0 a\bV{EO-+^/x MҒ=4Kqj\>%lcX[`zP_0ʞ`'#GCi>m. È8w,.]\@=ڀ;5EX_ﭭass?_ǁ3SKkr}{4 X|1|{qZ=X'qEQ4ϴ`0 ?x?m }SΛT&}܉7䡝4a9x_{Өk'2DfHcBh$v]lMa(V`| Y0`  m&1D 0ĪY,>/TjVU!eN8lj=3 z2rk 8e\C]^ɧAIá @g0Uí-0o3 ¢/dVWV-,-,ϟ6WưY(26Ma/C|*`qi)/w8|F?nǟ317}Ξ6$. ),5w h K&T[e [B$1dw4`&0Ir~YfہdЄf3#RYFB.QS 'Fpu.*Jk^1N)5F94Ta`Л{چF[C#*/{z{̄ѨÚ0=d> C\uI'-U:zF{fU>NʟyC?X #ٝBz5goQh67@DT?207;]{cqi)|n.u 0\Z^7<}:\8s;eW+ Xuzq* )}jH,D>)vu,]jԣ\ ̢x'| &)Y&1 Wzn hO#70*0ș0 m ^U2i@]^g00GS(?ClV̋^CL)GSكs)5}ab.hˋsP QWcx7N_?<03;%(ɔnVϛpM<ݿ3=,/#+pV6pއs>NWm(֡H@A [( oDTZ*u9$>ټm)/ޣk_zyX*94E& S~`)<3O|!|叱wQ%w>0<.,\Ğ]tFaFѓ|D]sbs>6LOMWXK/BQ⊼Ah#t=|=dHA hB$jj|9BK1%F[FJd)CuSs"#0UXIV)uӈx"6rOR}$t&#kjLPŚ PNB$8CBM@b}Bړ ^U>Eީ.FBd`dTVfh7:X۔kB1J_^ < `$'ѹJL3iLǡ#@dp>=xkkC[wnoCak',k u̲:pe:*Z/" asVjD7EP͢Is 677amxeMUxj >ZWj ۃ 9K"{zoWbFfl /&gFCxϺ&uW$YJ)us\W175?>j4[~BNEfhVc` ,c̛B' )\Ya,op]=^兓hEZV/y9Ьx|?.,# 7݄̬0mwxb,(iN pOmmf B JD%1dE9f4E\\D!}hǔ]cX6ƀEa˼B Bֈy&%N)"yb05k}) RU! Ch!NXcAޣij!(`@8y VOs(B Z/Ri5*S*/Oada); >Ok,5wë'?WN̠2‚́_7`gvZ*-;30DX^[ǯWq9\1Oxr%6)^Iij9|RTP׫x >›wߍnG`z&txڻ\YҒ fCC6wRhP etT-Zb 9St#\@:j()NRϤvQxe'cr\Y LKH6@' NpL$p#%d KLe()"ĺd$MbEQ4Ue+V<}O<(>Oiˉk\ RsƝ0 GN`鼔H+ӥqvsh;왞VSw/'>֗`؃l).+~L!2-#ћG~?>I\Z9@{#D۫EBH ^(6p55s ﱫ{ǟy_GAf'ĪG/q4>y {?c7߉=}aTp(H*wpw̉װvLxݠј%j !ZpƦPRލ|y O\yϽ:ߍ{#Gqӑc8zB^/MV:Fk$3`DqPhs'sFSVX B\i(4MSأw(N[o2AI,},b!T%5rb[B!ኙ 1ғA0AjcƔ`ӹ0?"AKr6R)s]7†*=Ξ[gC}Ao0@UpM: 뀽7~D*P$h;%T ]g4hn<c2^yqy2ܸ&Z~DPWȲi-]e4-5tM_-cnkśZR[/l ̦\!d3nq΍esss33s3Ca,AΣjM:D8B9JKő` =R †6WeD@QG4 af0՟xk^|/q UrD[e"9!2YtB# ?IVFD[FZ11ĮiM o `*\$tMw.{hnw݁G7 eGOK3DU݀B^B xX ƣpb 10Tן`<|+PR1*lGobim7p%,^Yx/cA ِHJ(k;@`;r>lfj7 3vj\xoXf Īus&Gؒk%Jje kfTC=M82c{v`\88߄qVi x:Ɉl'k 3ccu ;ejtk(+Ƶ\ϧ2GtPDI-EKsO]{illl‚ЌPY7Ժ^W^l}WE\2i X& csWh&'J-d>clmn f@s{;-n7 <5|(Mڐ5FƶPQLEoTkp+Zf#+R{4pu- ,mc=D~dML퉌VKPlD?0Ŷڧm(cc:Z)sIH4G5-i|A@(z)lmE rJ5~Q@Q\ ΁$bߡX^F]s(*ϰpM;( 1 <bYe1qJ-2H?:6$!z 1ˆB&7 @ J3# K3rf{Q1G/<< M $ǡvi000iW&(ѸA R6j#L k0p@a@(9/TVCD`-uvYhOQu>lMGO,=~Bo3y8tH oi8hNQ H', O5rה5d$v G6L;j9d8}܋N2c<0&X[^j C(L/0 8vu`/L7;'_?~?FF5)#(lۓMD*yul5% B~D2{2Q Ի3 o? B6zc7&10E[1o \UUPƈg\A*ࠑyxT` 2mHBaڂ -!+*; 7at H h+#'>zQKr(b3ERBĖN$C\xތUJC`-c`|!4wuRPBwCΛ:tE"&GO!Ț؁'2-Tg]YVi8#R'Jga ː)z:NbCg?uT*AfqЅ1lU:b%\SៀsnZJ$.H#nGi2߫tLJrbA407f7^3v"JUAÌ h憟ʈeQWGÞ*2 (lxLZVռ!"OCEE0=A]' "b K(e Gm8sk#/b%|BI^e6?D D# G8g^8ѻ֐2QHg5fNwF;[jkUp^+kv#nv #@=Pz>Vbjn%Yzϼ{ζ+8:t >9~{XX\[y\ ,m~nL*猉 X>D VY]^;E$'[sKnZZ?S$>evQJ^IawYfGŪ8ʿ'>w2ajc L*V9*QCqQOgFq^>"2"P;Y_u7& Ɔr:~>.X?aw) sGn_>=m񈦂f4v09xǨp>x6Vp{0g?Nr'Tz'kBYs Px!3(f֓bÎňEyG0b8޺%i2Fxs9 [x͈ip%>5.r\S$:zVyzW,YkeBqm#LHNdJ)'A55uie<[{S`0 BxnPfaelo Zl ӛF9Ebrz ;o!` 94 p%# MȰd k|=e ^15 \`WEoxl{l\,(wOK|C1?~sW~Kx1^{j(gT-j}#"EW;?H.,QitrE:ڏ}ZJ)C}@Gd.qFaPi ) S|Pe+Ŭ*)myHܹ?}@ܶҏŸɫIq\ 9/{{)¯X5?/~ ~++x>_q'bj\|/*݄ p>/c wb)5 sܑ[/U3`}s7 Sx;_I4 $dua'.yp.0gvNaPtQ=w3_=^~fg/ ;<+.Y튂GP$BJ5d 0,GʽYygxgפ3uSv.jÜ(]6+h9=#K15,}9\X9ka魎*0 Gl9i=ny[a q9~00)dj{/f~ pa+1}k[#|Cc~nsp߇?}ar1;rO\u8wM3p8:g_'->KCH47 P?Yd @؀f _ģ?|/??$Ν| = ^;u?.yO<y<1u*A`Q:ؠmjm tx $Q`L]{qc;/7SX ~a-u2!^Hg@zPd?S}X\U^-7[fקrܺn]vKгIdE[(E#?St/Ű/sְ… q9\YjpV.*6G._.-nKKKX_YeԎq2Wq%j*Wpy2 cym[kXaacm%Ȗm(V=a~0H*E6uWWﻭ^ T T4Z'ɆPу`O~.⡇?C^ć|xxoMD|N2ijx3\=uo[V9.(Y,zZ;u9rO4A4=gV&\r۶X L$b[3:J^!)Øt}Rh%Y6:R8'kS4#R}v0÷݋AL{͍ e): S=0p~>zcme y-P`}}^T7[# fTcUX_g/ 3 o .;%zeqýC3\ǁG}t/{IwczPZ͕a4vڅ<3a'%iű&+2Op3ڮo,{kC ,^3YI5A A!a{۵m]8&Y&<,c8>7YzBDXC!eBl]eǴ"ASl}J0G@F\ʢY Ǔ?z}/Kp<_m7߀ҕ%|~w|{νrYDM=^l(CCaʙ*L@nH^-:La:V6]U,lX\Y&.-cfz V8MEc5R8SdjkB^]<=_'Zj2P)[V!) G9Jh"!)+o"eζ~cL:{D;= :mYmWK J8SR0;EC 8tp13(-=98p f{` 8xv={@`۷{^{`y=pAس{_y2_L =xfjl;\Y^s)c10[W%7y:, ڳgN*Ğ}q lnl93ބ+gQIrh}ujPUupnyzl>b ZJ;`z -w*LSw˞ {oYC ~+kDa ́ӝ_ÓϾY<쏱ze>߻OGtugqa<ci,~ӸK/aycq4~a pi<`X\\ĹgQ;ًu;sŮx:f?zg_#bz7׮L_{} A櫼0qX%.u&c @u?+钼7^YOl?5aQp#߁k.L ݟ2Oj߶dy/lWuw^bLpcP"S5U ?r6EOziȖ}lo*̾l*V0d{0b?σTH%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_32x32.png000066400000000000000000000051011341671471500166110ustar00rootroot00000000000000PNG  IHDR szzgAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk> 6IDATXUm\Uyݵwح7&fhd4@*!;j J@jLQ'[&qqqz_gv^9|wf#sg{sy~7מl/c0U0Dr1Xf9?D(6&gpsvעVs7|qw #I7o=\_a.f 04eeqOZGiQ ;\!m29>Ʒ_<Ư=J)h33ɲ4MًH* W\a}?~;P5А9Y!'3:-JD;3AO0 " ʵqw?I^}UnܸA$?|=y7*fJehYaY6|bmH)(yG/r ^8A'fuu@K@ CY"D8ٱv\RԪ:`v)3>>A0 瞣ltCR:s8o1Om" PUD, A۷?c._:GWU5%hؖxAX/=wDY[Xu 0 Cȳ5.W戻X^[n7f}"wHF vkiUqmv{}S뿟M!^@LYV]-[IqqA[Fdf]_^|K3i ]ڵ tJ:+TUh ~2Z-8vLO}{g=Ο?;-s頁ՠ0xy 1s.z8ٱALNNrWyWx78p_8|qsdmZa«/4 BdY /ӧ9<Y'pzmp"m ү=SѣGVTU$!I(b||9>CΞ{,jð4p||ĶܧnXرc j5(bnn)}67 R0Є GbK`n޼E$ Y"%2s,--9!1ՒS-Křb~) wi;e` ޭ4nF;TJmVԣTP: +f #7?Oerr<nYm^<ģ<3Qoc6QΑeo)[{22Jdh3OO?n!Inf/xv<"ݶa;L5Z;]#z`7%b ̄$2Ҁ kkk\t[gm*̐fW)_ "Co?RTs\1RZb\#SW>⭷wK~r<&oB.rL6fb/nC',"ĐЃPu7ϯ~DyZ,shhNa9ӤjV*Ua8P tY[Ow# <C)߳A=Z%dvܵqNYC@+&-JR@{tFfom ] L~jR~N_'k8' yВ 8"Aea W;ѝϐ&Ly|'8'EpBαqo'v1Fԡ7x84%DQ;G\qs5wΐuS =^F|_瑝4UROTiFkCiyMTFG IDATX][l\y3].%ry%dvŖ Kv/,E> /m})y("@RC m]QbIzGŢDI${=g9 ݳ3oY}oɣ34 ĴkAR  hL t/RA!^9 74pR!055'4XA/BcL|vworZF:2؄ޡQBFT6ָddh_9*34(eрMBX$-T(B# kBeQ}zF,(,&nbE+XЬUp?sy:Ŧ6y$<_|j c,1 ˯}c_9HOO/QaE)Ab/Z5HXN kZzyZm:<̅nk&C{6@EUk5j5E>D\aiEc֒8nRl?= !-(1n5JAZm| )NljwriJ{ b-$c$&!E(Bhܹ˭[%VF[.JDPZ5[v?{܎*ݠ '6$Z:O&@+`W:Қ Z;9 ?X ݉m:bDmC{aqq=c=tvQuAtxL"RvZO4aF)m^ytbaبmM1Y`QJ-Tskxo?ZfXy<h86Z5Ṗm'JV@q$U]vh1(?dre{Y\ZZg:0Vޘo#ã}!]X7n3K)) |15>?Fۜ{O'N1η29sZ(:o%Ay>eZ_\J9T .bˇ0:Á%>طt m:lBp+gٷAY J;wwOd`B> 'Ori/o1Z3=={R#=QJk7tbHRmm˻ ?{:uA<|B@P c7`vv.>Jw"?oj".@H'و1FիW9x/bFA刢bÇfiik׮S106]xk+Խ 8r2𖮰5AE"B>'I* _,,PlaM՚K~|&׈q\sɆbmL+6.*FvGqL"IPשPb :=ax=S (P ?css3TqLZek)I}ftuFokc bWP,gW˾#753Aww7qgEj52?wgm u#gJA2:<cĂM2 q>}^SNnW^/DQ֚8Y^^ۼ/9-*! 0>,i<fxh^z \.377R'6sJY> cQ PKa[Q`uiO)t4@+H‰c17vr VWWP#~q&$nRFecRK[P="hSl L  YN|_G\H m(-5Ηu)bMf-/Hc?! 4}d y0t>D+! Czz{2[D\ iǽ\#?&c& ܙXS(>=jBb]9pj5= rWf|f9G(tn!8['+(N>\U^xOCiGb $RU7Nsc8Σ46`VFx :pG .q\vnW'HWuߊF {US<_;s+Y[[AE{;u#QEEΰt|z&WC\9fr޿plީqrkZ0$BV~fel QҪh4Z\&-AT8y8uSk1a.`smS܉?i>mlMD9O$. LLZa/ Iv|wEsS?{-0G݇ "v*s*w}ΟŅ{:wtwMs 10yG7>HsL`.%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_384x384.png000066400000000000000000005200771341671471500170130ustar00rootroot00000000000000PNG  IHDRǵsBIT|d IDATxkmu9{/yI^EQ,JrdIeɲ9i&v:N #()-EZp AHk'[Y%[oERb-QIZs9:= E\s^9o_L3_<ɿ D}C" "(yj!L N}WqNA/z,N`|Pc>kS,_1KMd[iEky9?9})&9nk۟| `h_źi1Tr0˩aP>~>_DА$+XDiufl͜F$a,xX߭h5s*Â\ROa'\1ϥ*?|>zR3ه=B mKZBaIm>DSTmAx9gv^2ǵZ8'>ù7sz_cy҅tCa>w0f7[Vji\EI"Ѯ1ϹڬzjkgMy/kD Ptsd dUW)5t|9% : JE{כ.46m j:>qJVI|bҀ2@&HAxVz ЊM(O14QQƋ+]H9tVƎyS *X/$}( *G~mxɨǖ7<&6=Jrv I I okÙiz?wiE: gɕ}.rSeg5s} R+CיB^)M(`RC)<&瞙JQblzG(Uzyw!ݴpn* }aGW60nƇ:P?mJLP@# P"2oC)sVF',$6 t!'5ar"bJvk_v{ KK[K}n=V+Px|If/ ;,@51ǘ!4Bxm\o2"$Z1 jm{^ո·wk=wޣVYNbLbVӸ^T_?׃xKm\;7v xw݃~ӳQ<}b pëwCNGWAa vI:͒"ϐ bŋ$z xHZXqķ s bNJ_ g\ϡbcZڊI)ӝC)'hy~QrX l|0C36o(0dBJ~{i"f݉z+-crn=xKaٮERIRH1ГMוe9cQz/ƨqe-`|G]xƴ~,hk_R!m?i>tpbl`<_3^I`M+tK5/0J7?";GJ P U/ ^)n,2MN/xܴ`qygS.l&F5a+f1rHgt$ T;Ŕ 夊E+hK(ӽc6* 3T "|'ґg t&~"6$Deg?7c'PA"&&nU܇M 3(Z%U=׍ѯXUIt!Ɔ9To=(# Ƭi&`$Ō3 i(ϑ7N1F>F9hʖ?yE !ĪZ*Bf!c%_;-AGgcL>˓dTbHH(F c5v{3b3hnfdװ;;0ujXh 1GNMeyast ~ލ+po7ɯ|{qPFd0Tcr.]^WpÑ<"G~f-`4 ,mvZp3w#`c{}Sv*6s-3# 7|X ]0dvtr#@}:3"Ǭ\'L9zPb7L&pe J+e[FkfhXި ~UJUi'a 7u3 Eq.""9*2.ԍI(@wȖxbȎ{Esؔ<'Vb-a:-o Ei>@е04,J4׸$;U@:C?a\P*@HI@Kx9@ UEuڇwpwvۿ'w?RGC!:%orA/< pB8C-r  /|\ $1&_iC)F:S kOhPiՆ\gB-B#IH%L( 1W (Õil <2Oe9&bWºTe6%jVЍ$>hYXIh !ԭpr[2>f/QkV24*8C:v'-gvn:_Pf K8q 甎b35R=I(Calb J#0}P4Z 6Ɲ*}*=%sC +c_G󶃉V4|SMId>{ _ 30"=.Sq$#]iIr10l Ga;P:lkފ=R|_?G#.mp53'MCoq!6 2Xx% 8~ |ǿ,|.Ȋ녏 T,4@nyUwW^d`7S%TpXvKC&NsIФLkpL`mˬB"'K u6.(ial>R{hY(<f8^ZgT$ Z;TDv!D9ȞtaM>{xڽ5^#k}CY~"-8Bs$<'-MC.r3t!<c ) &(uM pNCWy3˫1)D}@bԸSk.{ #gS^LX;X벝yQt.̱^TTO;_:/*3O~߃ϞUCn^\X]*ew)':>|+_ƕķGqԷPnYԉ܅K2VQTC4ٱ)vpGK!' (bē/jEr%1J|76M5']S2"]u*$Wb.v^ 1% rΔ`vefS>" :BA+ [ *#vzE6F\J#/^?r e=˜t:\hC8]c\zB2rOGFY2GJXf+v+7Y)6n@5/ 7cNSOГ(Pv0U~㳮A)1n_(&%Fք*npÐJ-k9aK@\OgB0`(?TĂ27 6ɿF| TњGyO-ae, vgxOO^mp0R/x *T))1Z<ONkaFGN媣`w2ȟqE^s4fi\\NOE, )Zs&$K`['h3&: bcwD!-;.vd|(,WvmFԳ1sfDL8 ՠI㽮s]Ǵ ܀%wcaEɳ̺>gϳ)"RJ9#$ݟsЭ,xB7a< C.*$@(I"t߽"؆-XHϥqE':Mo@1>Oߍb #8N*>~o#&g>o|Q.HrszCS9+q$p3c x{Ƚ'*{w9VW^]5J_ѽ3U>*v(ŁR&<ЂǟƱDlQ?o\c rT4j?nĺxL z=*pj(W4JH<#w]r @lq '1=vOzC"H4%hK< W* $AG=_B+zJ"WA~?H,7x[Xȏ3gd >b4Lx=QǜǍ I[xwBDh ]fFbc|.Sk&Vq\ " [|wƷ^<ط/~;c_?+_|#])u<)g!+ɋ]&o"Bn^r,@5zxUo|ؓ.EMЪn ˪ :(^*LMq+Wn,؟W)ޛ%(w6bvN e8WJ ;MzYZ Y ܀o @dP$ j{=FC<6FDڅ3!x-wK45@c|Ov{X@o_sD8}ʴDfSZ˞WtZPʭBÒm3$*?Óiy@sD?t A;y!t x+OpC8D2Iz2\@xi=W0 Llex>l0®K55s MI2H]uGR6BuRIu6F@-vx||a)oyw7 %zvE2JB1c-Z'ׇKr^C>! YʂXu SMgxgx ^놼$:'%W(0JJ)SWb,4vH2ZyM!RBq蟹7c\1EO=|nl/ Y\ {dd9 G&?]7R vRͶ.k@ A-h8`쐮H,k=䧕Vfr +|aQ":@S7Y질XKb1TTI893ޡMJBYSb2B/Uq]($G Aw9Ul0Ӫ=뀨ESB δ$*WOMa H f!Сfy$$tr:3 VKiG/Pk*~HsrrД,¾.EۍFOA ZR[n4 {3؋KF%=-v:oP{+ỆuR )Iq8Aed1k mZ/ǖ4e?',g 1b~GWQa /XLyA" F#HkZI{ &9.+B'%"J Bc}|K|_c{ -'Bxάu{O-jgŃ&g(y$JuXh)(oˠ%wnd <{u:l`a5Z Vs-,nR V LqXeCZM`M'lQ*9PIsPC Px^,[m-tJU=]KY"z<[KFsk803Z ]CJ\HP2/X^a Of#v*d^:q%E&mnjŴaҺ Z5ԡj HH4@U@.#DfIG,D,j9mh2QHO69IzL.4m6!^H aO#JI 097#|5ѢZ@{y> )Rz7ٳ?)riۯ~o E3p Լ_&P*$LEKoIP\rfwp"R< L 1YLj~T e"fc,XdhsH%{T(LZU9 hX̔8pYs^[IMo^@Zt"JEi9!m$B{JPa #0DPBgj3 Q\R:P >Q^%ࢗ:"va oc.p; pf.CpN&Z'LV:j$a0VC3F8ssB;=SD"@*F0?܅r7S~_o[=ǣcc?_}V;'km Ω̄z p'zCUVrPϬn[lEqCnv )WQ- +[#K.rת AUS&L Mt7o Õ;wƧzA|͎1 f(,6P;#1A;!S 4fah׀e@mγ)//h"()(_;ÞQLm8xݽfmHSS7!@ߏ"4-אw&ќi,tq5-^k2 IDATʍ;@4.U$jSMSY,zkEWz@3eEsl QD&Ih0&ZU$CX#F{hB ՅNuf5ȼó}>~5a%6yy @ֶ#9?u#tz/9xk Urq( xQ (AroIm43utbFLP"] $`ޥҟYIήc؝_ T *P.j{S@T9'ZE`.>ᨱq7_E!"iB)d;1*LPJ_)"hk(#1.,*|kF0K{K[о  Ja( ՝`aJǫv^=b( [ԘpPע-Z, u9I'mgwZ_8Ȋ6|o tI(@7p2bߎRHJ'4O\byNZ:G'eyį1PY2kOalJA#`LHа(ϨΤZCi&h)7a@_J5iYExq{x[HQ0\3 0*i XPE.5-4naCFl 9dq 0;7@2&X5.` m0t#F' 5n/Ci:g Ө1XsD,&BZ$5p`&g]=eac$kc0v9R>|q{#MIF S]ء.~aܫ`?o;VʯM!'4\8ov=g:r *j sHxxC2vKgX7q\:q*.-^ kf|U ̨+D`vb/&%{e75^p+6΄%1Of- D)#"Rs/G 1a` V}lViM[Z` Ux]_KL2fN T*aְE)Ӭ -㮶B@%5\5C6PJ(,]jC@mwqE Ƨˠ/7NPJf,*:7WoV5(͛wiB uPTX2\$eU'BPyr qwoM!TX}Ks1L#jJ7@D61^tgUq-eGy ByG~|-QC}%@EHl'AF}5.^4Wteq8airdaBҙg\W* I4.$CBNp I1JJS,Ya@7g;NtZ8v(ROP fz:yr8 H!,V`sU)M0BgS SP6@B,2VT EQ- #Zk"M`# 4|Rl/ f6ҕ+nϰN(VF71PAUŃ%JbcF2yYԴɰ8Ug4QU)h(\034 ̌Zk\JZܶ q3qY4ē_m92@4?nu$[a /vf+U@kzHV&`dšiė>nیg"{h\yLQMEɪ,PpP0nz8e?*(Zu88i:P 6〳Yj1ëŌR4& 47>܆Te u$+tL!70h+R0% %DY 8Z^[ X PLZF@w}/.b"[-EZr(䗰xH}.~"bGRj-S4I=_ k=hxWiF/buTOT5LU!@ 7 P4ݴ֠nbh BIJ㇧HX՚56fE} =ץ7HI{ nM děYXK_kf6ZVĕR09c*6*CMmț_,ZLT56&ƚľo ̂&"@kjhk&m6C/ւL QMQNӄZ vvFb&@0ͺq~nM`fTʌjI7«:q;ó7O>}/}W= 0eVKK]IeH?Eu8~_v<.>ٯ+| '߻()Q\ zJ׉W 'vMׂ\s%WNch//:fOtU@;sȼeZ2>Px5w C&]? `:M@g (^j af=\x6Ըb'l5p&W$*PE:XF)oIQ' ӄZЬ!VGZ,G)#wEUXV6R}rdֶU7Y |o{ 81Ymhd^}E%yұ{v.WҽҵXyځ1X53a> 5S2^ '; \m(X*Д3R1cx0OiV*[CkvM57~#}9fXf RR[ksvYq96O [hhmt+ʥ8w%/W>|_ş==|_>'{u"v0j@Rj922K# r:6saZ\| &C,xm[Dg`#ₙP"}F$Px ?w{F3 n v-0׵V ̠8"]ZO Kh1OhV8fVt;]n~+W~atwVqJc[ ȳ* qx<?l#Sֳyqe,"@s+f@0wW{CۺrJYk;2[+n͛Ql2^lX=OCFˌdʳVq8e{xSOG_{Nz[ #OU+JK^IP/@kx⢡<8- C_o)Qa{l0 Àك%7=iVl\<^{im}6繦g~n^#?/Y^]3 ƓcN]13q<7xzGW/&qv+<֚yn{!0^ *kJxfҶ4>L/90[AOMH_!WPV/;R0 H C@M)\䷪?"!A'daW*#<M}޺,&@DK62j۱w?7~}~ =>7@`LNYS֨!)±J ] M\҂k *T vE[csQcG]1vbWtdWCXdL] BhBh1t/?'{nT95c2X4P+),蚁PjS8* 7Pg% *hs륍}d r/ӯ+?Sr۝kak`Hn8<<\xOB<`T ƠYMk@aD},%Ou9`1 csеUDyYV,9mT*._eĕ#|sgĀA8"M?8?B)  mˉxK):\qKN>ףFPB)Bi m{'b<\{P~xO{?N i¼AQCW$jgF;dP$2vd 0`5ˊ4Fk7QGJ/Xt^ ELԕ[2k6r*멣e=,;Wd]jLʻ{3GCq39%Ӻd8 CFk0{Hn<ּ` <8881 !`^?g8h85`э~6xy\pnz˖s2;N<Q1 ဗ<z ^|5<|ϗ{ ΞT e:#WP$C*{{iXC\踐OIQbh\x2Cw4G̦F>${#o~ ._'o1YyZZf@/t.3Yz똼;URi_Csczgt ܄ʠY_G639e\O ge,, /{^k% ;wGV}Y<+ZkSȊIkdo0w/Bִ9~i֡%@鹈C_l{miA/?.r> x!Qjx7vYn&$Ki; lw~o?.\t_? gRvF^ +YWuUDYf,Y*`ZOg3hjB'h(Zؑ)(LlR|#K"MbpL2;¼Utek1her)}.ҞbMVhmdmg{\YCSyYI7@PeHv[ŸEQf{_.>ϟ NhsJ7睵!Ά1‚~UH"oBUiorӆuH|벐?] _ IDATcaD-C0cx'ym6dfݥ %(W`\t/~%x?\Kh#ICv}Lu?2ZG+)` RAqe,c[ޮI}Rb7ik1bSy̟n}whꃿu1߸g=rD=!r 8-Dh1HabT*u M`kA-skc@DjluhHGu4%415ԿD'93J{~7Z>'ՑuYd`f7ײ0M;(Ɋ4{}?_K[DpzzZ2<tF ÀC푔C1Mj2bUɴ2DjD$yôac߯ǾYNt7@݃Zhst еk3(dI^W. ppһ%PVt7E D5h=T.P7y癣~2M"DSV&%D]k~ ~<7vgp^] # ]FI8u7ǀ]9Yp}W?o_ء_yyPl X{5,B@xリ:aQr)_Tܾ[9nX]|?7b]œz;֝rC/IsHX*tvC ?O>_]b8Ѧl?=3{Aki}+\gC\JsXy(L{,+*y.+n"@H+а9RqOP-!\ z"q:I_.. rn+c/p\lS2 6V^pdsWu|ݽ887n O"*^ N :@\oLYb0,`[0|_l.Iy~u%gF^(>IA7X^t huLDڕs!cJ*3 Qt9$k0`{By9,.X P<ίo`,蛍mՋ)}$0&0qJ6&15Q2iZ i>QkYv Ie A wcM׿8e%Ta俻niX?=Kb%nL dcHU4{o;[:F{/~p]lSDGK?·44vWx>22~3km>pV.d%?9U eG5[x}QrTg}g8Ӷ1/v{ɭ޿#C͕0}-3 )s"Z&tVoszB_ʨ}Zwk3B. )6bYynTu^p^񯟹Tf]Wn mpcEx幙2CY_va2E%T}D-2noqmG XbHjS}&ƅWd6a=<Ղ͞XR ]tD&KfHJ~Mx߈mqrz7n-[9,}2E(5Si-+5|#@Vjby}ᥬP&4k4ThX e *s7~䊕asWH#-x픗՘:3YZVwR} N|qc,p"h\ >|'+?~w$BiUaC*Hƴn^@3d <78A_YFP̺/v?TFPG¿d'''Ch7Eeܾ=m `@Dc|nտn:}a*NW jya஄*/U #K,adt)"FO+h㵧R|&8B9uh졪ubkW8¬B_mz~Ym7)EүwO]d@Vχ; X_ֲ6k39Ynk8|;LqwTCI2yDž mX+}HߘӦ@#^_P/ DT׽?cfLӌg[HۙpPU."=6P ^OȇN"tn ܠ@{]цDzbF By>tN5uAA} 2E=4 C5CkR/iɘ |Ǣ>/D 9mOuGǝ|n6`[.c>O>8NN? hӵV H@$oȇt8Cu~>oxSFcpiUdt3i 5<Ṙ+!sBBL>d`/#xw4};Gr=8;bwv HCc˳á Ϣ vλ>vJ`>,ahRW8s9>̠S@RAqᎸ<,0]w#\l?La:rr}ߡNtSK^@]Uf6Ǵ-AäA7x;fU{Y6dh/^9R֌r)޲Œ]So@lQYlX!jW؉UvqKF[ק81[>s`K>rS㣹3B\qa#"hΒt_JouA}#ѫ57% 54J3iʄ\ :0 ==4OF:VN^+&W[fPuf/ϔyf@;ð *~m08.̃Oܕ~uOCXƍ[{ge]|p  pY@tt,y-yg \~_XS"LV/15?%_eAk?>ݿӢ8^E.5@Ĥ_e/Radaκ&.cDjF0mut 7p3h@I i~bs\Um4$`,F=;zm;FaI;shʏ$U@ XWj y1㲢); 2G-y}_wby/H(zMÚ!un4 'p9)gmа* ޿33M(daw|ᇾWLӎ$edO5/5=i ɫ#QJ|dye1gvDȪEdGc&ׂcΩ:6H8j'JmOdk'e\gYLZzh2LG,tIif= 3dqY4\?Uwm"XKZy6Us.'K#FӥcÓ&2Xρ4=in x}}s1lx ©f/hNoSQ3{Lgv`tɈ7 zRMiǚo/U$F|/ae.&`=k[o[ѹc3emÈ᷈ {h$Ƭf|{=wbъFOtĸlvƢU0nUxX}3 Z, \h 8 ΰ jac X xX1V8(_!>Hd]ØAwݏ=hRhFI"M-#I2,/U۸-GǮ_G1(uzg(OA^U\x/-ԵJoj+{`1ݚwrgo8-ee\kYӳxP IJ\5(; 6]hY3҇4͘bw#dj(dÐa p8`q~y?5}=yi! =6 È7З}W^G=t#91Jk^݋#%hu9Tx0P[N"Ʌ|F :FI\K}cPˌNUP<}r3&$2l":zH{>mmIh&R/ i2h9h-Qܳ9@]7 F+#|3 bJ*w,6/GS9\O!  AF{0Yt/B$pgB;5{RX}y>B2}Cdr.Dn^mK8 L jYBt<Wnz"#i;f64.b0.0OʢƊ`d胗xj.67 .KC~V r2 ") i~Ў8ac' l+i*f/s aCɬwBl0zbQndBDA7 n.!X< %CZqhv| 8^0A9yU#KjkT' :q,n}w4NvIC⦿ e)h KOhhAoeB><Ykdj gA2cPOӚ3Tsau @Zʗn)>zƶHUqfEQx{nNqOC(\wjpS!'7nPn ko~Mg590J$^|450X*w-H1D/%# Rߊ17T:֎%aJtoK-"> 'bDMFa f*.KqN4mh{qW/Mgeu.s:n4װhjz|Zj$ 4c&λ#{̘-yx4Ƴۍu6`>歛h[}vQ"!.U8pq7CݪuF_htP FF>Fiٱ Eg銴dBC[A{-_|N!)tD's!StY:qMwЎU dn9(V3os,}Ƭ lKCXqfojaC##hiJo>G 9ٖ2DP'T}֒A *bFLMZ@f)W!R ~KY`HEݸ1hU!RO\J 1SV#^DF2ƼEN1Y]jT$RSs]Pޏ鐾MAC -"4Xd60hyp{XcۗsK&JigZ 9]1aw7 Nl }O7Y^DvƚN,fml*2D2FQ֠2&M2/B]1JERk2̤fr}fn6V>AwjݬTBjgvӜ@0;(`!j S'k?`V hap%~  ACk8xi1''@л V՘pģ,ֽl6&h`%}_}F!.f`B+(#Vp<ڭ< aJc"ۨT s%2|G(!1!($#V\)IAQ.azHBP[J5l7 #%bq#9h 2szNJLRבL2 @GfOAF+.`2۸.{an+s 1DU BBp~~z >#Hl87cĜ1dFL-bT(h:!&* נ̷df8u7bv3>Χ/ծ ZiBPZ\0ZܙLM;biĘZk  e lٕt6y9&`EѧhX* 3\xD4 Q; XA? N`ޘH|xZ4)XZȪ|u{d0`.j[Xa5\k0ZB 8 Q!w0ܟfAḚSqChO:κWCm`Uǁw &\ag|,<ɘm,qJa0*dQ7YYwgM&4(G׿MEJP *@ Zqȡ ;=(}:iIRC%M0X:gmA{; g*võ}14{QU_sH!틇 08;-OhZ8Űe2\yNr2L;\n8{hsa| 0UxNǕ|=X'Q[λzh%f'&w7] U}eV{.C;7Kh D Z;,+%HV143U\ !bcK y" 0`hYFJd+Fz5ƄM]gm:A4vE0EZ+ Y=U+!g< j-&(.~7qzz辮gFv2K\\\r<XtB`wrr_o>O|f#f`kAQ5`f~ HEJ}Yd޲6Nx uK}}[k@b|-'/YK(`'&,楆Gm ͞+u>\:$@)<َ*Tq<0od `YЖzj0pƍEX, gGuM춱akC&u bNVg9t8>m z2$3_&s4!+\O. `ʇ$J)m'~_,ÌVKT3 fK$YΙL"d9voK'n=Z!挵kZ4ϖQf =DθIWH^݌&Xײ0DlTZ|k_\i&Ӟ x>|*?ﺐЪF-Z-!ƕ!o:S %b1  [R {) ˱@8EtCD{\6a^#OHoU~e00 i:x{pƝ q䝽ۧ4t ©Xp`%&U$cNU/O(f8^"V>yDl0oh6~2.5aCN,';P,S;3RRC] ֪1u"f";pE(51a r%$OHcjLj3e㪔{6I7)kBsp$ÍKY5sfţ yL1ƍ8==Ľ ^#YJEO]0 EV=fk3l ?ˋ>AHH7 :xWB~*No/! t>2 O k (t(=fuU&#K{)' DC(OLfrMH=׭ $c?3?ҋ~#NC2Tgo'B?%n%h66+l  Y j!f]DdYVR1 לyu_{ xWp Lӄ;w>=ܻw/$_o5wOW5<u$Ed|<k0!A|U+SgUcRi& SrZ= fV5v>:*f4" 4=wV0G^H$qWlaCN̟CwܵSpe&XT1-Eз 7Ԃ6@g3t4?x0qXrۖ C]' "gR*#BjsܨWg @ p0iܘkbm|!97۷oGgh(*GRrii>@=d#P,z<rST3(/AL@z7Ն` ak1Ė|Ⲏ f^_#TkFf* Do  j⽪p +v@ԃ(S!+ o_tXMF:[k>>я $$gLSU-*(+#sQh\KV 1VFFAz/ma3߽"F@6i˲`^P5Bq   Epx"߾m}+)C2!ck< <j*a\9^wK>x#ֻGJfyDDkl҂U=Fg=s^#]i\3d!eי̨M"Wj5uYk/kn܈ XYXt8\n*/Iĵ:&N{z;se٬paexn·޽wL?d5ً][_]@5kԿ) ~| ?5DzfϕDEU5ҽ ^4=Xh~O2X:MDH' %qB53 ;,y~-}`b _7ȀEYl=.:0`I- Fڼ,!?\`e"=BF8'Ť5^@S3{J @.i^>P@KK5r/L۝K#ͱw`b%lU&Z31ɂJv2¶ZCYW72-2lD=`|cQrl "@סlA|@^FLĢ ns~H%:VǃY4VWGo~OEWC)4 Ài:zA; J_PU˄3&2᥈h0hhA\\v&/^SIrc<$T;t9zwng_WՓo#DfӐP(Ӝ5oc3jmR4$!#/&!8H2~qd?!׶ճb\{uC}0 LoT$VnF=39)|ᙩhWt"I(40mWJ?^ie{NeSk_~~In^z)p"c}Ue3wE)P7+thNӴ)rwrnUVs. UߋKC4ˌzPx}AG9Fu2ޘҋPEkKXuhfʵ20z<]ie5i;|@.xE3[eXFv'Em)x0[oԘU>f̶mlF}d lE9mm34+MUz+v䞢V1 %Ro\fPC%ah)n[tLb mTJ\#f9]ulpRHWg,K z&w]E5I[3ufǡ* /pn/}~S1U895Z+~IH6h0[n~;j)!Vɋ@rWZ=3 G8zgaCh7@},ҼIun%<̵Q}{Ԛeen[;~|vrӵ 2&0 K|& A"mˀ)HuY"WЪAM 7}d5{d:W{^U:ot]O1?yG,T +ZsA';!o@^S}(U^ސsQMCpR3ꉧ*0'pYf+%jXyckvQߧ6& v1_/G~䇽Mf HI>Č(duEqv6Hkª'+h׈U^͏?!{"j1oQÇṴQsw'm<_k/7o=X읠Z X&9|y؁Jl>Ug>_M˘pF{يq UGb/ A)% Qb\'b (׃ g d֭yDLgNeeHkDP:G$#圲?ǰ]6Yw.ju( rbzX<>Q}0qOh(λO': c٤0t M_W,i2Ay#dc}:(t4>o^Lbl K7bbfٰC#80 #vVbujUyy%"h;#:n Vm3,łltaxvz]L%5æ\dz'ט70*9uEӪ6o)0l]Qsx^b@e)1ZS%1ɂ4@tk4ɭ}Y<3{gA:qFY̽cGXH7Ii?wk TusBF M!@aGGW.LKvhnY>Y1$oet 06v_D4LU&n2Vuc'C n:B?EU BFC*bB;/`,04J@ =uF"u?Ulc+\0tg}M*3o[i[<|U /4oo|vkY9cRtLbr"4Gu&84O^mLbly 1c9AdZh\&~ìΪuo ߴ_׿Eַ$_#to+x4i ۱l6їIr7f%$}>U¬"b)hҏy4DּzQsJarA5S"΀Snm"Ƶ矡!x-S𘾸9 l W ͗чP,lҳ[TSYvֆYBf"F TwnX7Dw,k=fo`2rrti;&2 jCc [ bQn _[3:c+UN:ֽ̱ 5@(>z7p<0j+$\:>ObOb,xB ƽ@= 4j{7Z/B=[&AMCŧz5<"yx]v m.i?%w'#rP0 5Œr1=l>(R:wM`%z7?y4-m&8zW 7W@0#NgLD*ȉdm@՟mÍ^N?l&fv{m#ds@k~P1p&}vXd`7]-U< tq2E1}FEC:ʫgsG:ɰ b깒_QUj<#zA#(zBʰ\B!=i W+zp:*qi9avr *Gwӥ3cL5R#2, ,a5jX{L":+5Mi諎VN']͇tRX!l"ƼBJM"b`mNgj !SdL΍0'9DL"*ӭth~5ج3̭iL?CVx=NNNV`B ٽ""Y e˲x<޽yy;PUgUpc5B).#`@Rs) LF^d(#DaaHG,;xcbAS ݛѦ?G/u5܆j>x/"RդxQ"%6=J3;/l,W6Z]O!TVmlv 4"f3!ǝ%&f)ϱ:҆ˮރuA- ˤ\_Kjl܁IMT ﳝzhCn*!v&'Q'''o:y4[1㴁Tkk PX5s" dX\! Z(yk{bk`EBk!D28M5h @4{2zGdDkdjY!Temr:6hS8nufU Y-B #-i IDATA۝Yf}T /;Ggvt<ʗkw? ?va<.G s!6E1'TK(p-Pfɣ|TW:ҮǑ|#Wd1sѲFkaSJEȃ悙d̿ʞ),V(R1Sܰv^}3!Lctnk錘kYcO)t*ȿ}*QB|؎INo~0׭c V4| _ޕ&ϰBq }Vܣ&Уo~q?xj2?'??o#7ްih'ӹώ%,`'%"l\Š#dEH~*0`πEu{7ڀe͊θյ4P%7P5w$a>A~WP"@}N;K&"X.4)>jkb 8O4qA2 OϏ{b߯hYH+ gE|.@eoWscj?N xiS*/ϕ \0Bk#kZ8 K}FHB`|Hkh>7M7Þa0Gm%}vW/fVل5j%t>V S]7zpA0΋mzʬ:D{)ڍ?#_WSF9h;|ܿ#xwֽ~vHf6|U9ANLXW՞.+ƼF S(L^=G .Li[  1fi2?Mp-s[dH#J_>~tq7}5v?jF@q&r2b k]L"V?IT&^ߙfz}*?_gn^ϩx8fȭx%]苪6u i+wAQMTܷPg\FT޳p?\<{gd w=7n@\XwVs_X) >w=ۍPֻs*Zj˩ؼ P͞W i#hwsT?ov?o_|ϿW~W"Avg&5|tnh2eE&2޼&p- L*oCRD#@=rMYHeƜۨl2T#ƤoMo&5w(H!'z skYݻwq8VŠo[}nb %JxQrUT'u[=blT͕z̻nZ &C@NAӌ#${_wͿ1P 2,ji Cwm}Zote~D"Q*BkְwE&c<?vrӞe_x;__fɟ|2~L0zL:ꗲ`QoEZY,ʊTOnk1C'X#&+k `nHa$jڽ[JQYՌd̄mD`Jk>=D"&3l*;` MOHOX0xN d>\ xi5g~'>)|O_4M޻_y0jf& jJڸs_a>u lOޣ.`yv|IF0a-ٓ)ur 3- M XU)99Kgy0ExͽȪA.XY(^)hVnwfUA^{_H\\oubH-2hUȘ}OTg #dBFQ $T@Οv׌JɈi+0qT.7cF s]u#3%sڮY:zj~`~i+c 2z AkdϞĄUKϵ?+GR_4GEa-`c~5O8>CkK{wo󸸸'VKd kg\^prwRNL[k99!*`]On5ÿAJU̽?D)|wɍy3e,nCC=GAMYod@!˂ŚV`ܥsl6i:b^&Բcmll+K.ewjqzU 8#3y?oi`+g  ',$eԆyc;AA ,̙͘bud(Z`;{k9Pj ,A|8+I9EJh!T'0Zޣ ʻzR\Mڃ@g{ȦVoje*]W^yr e.w) !B DHzd!EsZ!lI &[y8J$0jK_ۙ7ѻ`v 20f.Z}4E3c};нpx ~ۮs|ǭPG䋫8E2>(2mH`pS7ô0F;`@'VDQbf){z"p P>D@ 2.\A6DerxU8W_MWj_{MkyC?ߏ_0pyw>/Ks8ܽ{ó~bDEp?k}sxۑ`Իb' À7oF,'?OiYeG7%U0NZA2W_󳤗-WJ| zA="g?B@d>MV͹U]27:Z^5B-\#&e&#"1 Lx7ΉHP0WFYoqA[?[N5~/O\iص&x59c?^^ڂ9|k<ĵY\&$pBK_`  M@~'V]?83: CVy3R_pW!?:!bc+[|aOyϺW^}Fi2;`X$~Ǎ7M<_G>Q}__:i㎪5|S%|kƇ_y7oވeY03qv_|%Og <8ciqܬU䣄'Mg]dwL i M))p@_* (&aD5 Pp̓{Yu{fx:@iQ gfNޜabe È/̳rs ?{vϧiVNX/>q^o5x#~Hp,i~5Lb2\ <@⧅J4.Qv!$:A\bux{ Zu)|"ևTMa5rfgu2貦I\:CJԼպ>*[n֭[ #G^|??Qyz5Qy2[ĵ_' gi6u dUZS`}m4zL)ECvؖo&Qmq5ϔ* CL0-%d*WH-qҒ5T0po%cb~yWMY GM[$C{?pAƓD9h=ql|7eR: #Tr0F]e@ fe l@t0y &IWAͮ /'6^]C WFQLTgvh  &1Fuxͷ7~C}??zdO+Ȑÿq>fAe0WA5=zӆ] 6KKN Õi.IkU0ܳ iV :X`K&y]F-a\QWQ%"ND]乀Hjh^3yk^tOUu׵m󼶿"[דm}34roMX"BX`~p Ep&'l&*a Μ[#+dpJ eV5(LŞӿwyUj<{~;ɻ<*֜׀?5u[) 6ADN,Dމ=ZQDhTGyl*݋~[ o.lҡm@^^Nz`* A-yIe *:0 ~][U*T/'BD.6<߹V_0Eύ7ވd. %l m݆׽'?ZlmmQ#FhՕI_גCSI ot6U*[T\j0mM֟d&%]р?~{T5|K=UWfnHuJіIFM~w^ƨמ`-s<=O>v+vFc p1 5FʦePo4E#H|WUAb<>wY^pm/5؞ qoO[ky+`4ĖBx_E2eNmD%6gT==DQoQU1)cɤB p+a5%`v]ӻEUFE%<.;lTG 7<?^1@>FUUǘNXͰÇ^:a{{y17sN>tcn?>O⡇K_Roƍ7uU4Y]UUUoy!ſ Luem4q-k* #B\7?zj<0 oj͈AVnPpyGsܙQTc&M1x<'O]ɽjemAj 3FJq*Tc.X΢+m. UD5[˩_lx坺ŃKLnW^o|W=v37@׈gs<(`T o( /P&@YFpsI]XC?0mq[vlY{Z16 9br?K8g[ /)%#]%kՏn'N{|ӟo;Nc}MAz+n}ы/}wo>lmmb}msθ{GGx'*٭ފwx;f Pyu׹d>}4~~'O:N8_5{뛛\_5oV|Enl6~s9^ƽދ'|7?hQ[+څIQn~ xSs6FS`z}*߀l5m(D܁}.~_xB 3b#gFJ}04 Ln-ڊܵBkt VZ1Al}◟zi-Ѣ9Tafwzvo!E?KLPU2'dr}5'nL?W?>?[1VnWNӵ7=7_Jy_Z'O^8djD9Xqf D%(Dc[SqDR}R"$.+$}yq|fH5&e'n&B҇29ӈLߦt.?367˧:]}/Ξ=__l6ûn={w~ (R^-wk,,R oG|?5>~7 z>~oGm>B<3_syk`DPHʿ}0T5œPM7_'k4ǖ͙x-ӟce\I[)]QS*Phhr&Ed*f U%jT\ɌL@ ie4BsWEcpGO(Z?o;^_{_g>|@YT:Ŀḱow[QT,dzbk6)G܆PW,'=X?stPhb"."BEZHIhR%Y0&ٻٵeqNGo}+wwq_%>okx _cǯ'"Տm7xfkN'>V+>~׽G}C8{l SO=1o[vNIK#`(yF`՞Iz_ .dQ$i\dEa.œ* L !@ACfs`bxa/zϓ~.&$N!=}Һ5D¬ 0RQiHe[pW @5;$4Pb"=}WIi@B loBxX1e׏mf'oU%i2| IDAT"MMb jI3=/%Z`#IdyL&yk}]k48:ܞU1gYo} |/ mKjnקz ~C#Hm;M8z677rmH}K_{^*}G?Q[Ij̭ψ1f .CPt>eB*9 |:!=ʍ%ػ0,8jsI_Z--Kw.l./p9rWgy4O~%/d2 7P*=zi~?~'N</^\z?G;jF+q);%?a02 k<ץ1( Kp@+HT$>@ۜF@"o YP2MGoW&[6.\P*4 ?&,8HBPb,LAjl tAȨi +-ikѾPm 6Ld6Sts`4բܢoj4bIض+g8A*$D,?w]m4h;aZ5 QBE@~4,@@}لPC-LN۟TDظzmh"&g${1=^cDfz-衁ݞ m4u-.y'=n Ǐ+_ i;}_UMlD {{/vvvp7Gɓ'qy\.oZgh;]۾pT :&e~{.).삾m'ΏYn5GeB fVhv<2Zzn>+PH.GUikE9 !w\mkJEHm T-PAlyUhT'-j0hVO݋@J p=߫%%AځkPk`S&u$| ({./$r.k=rngL it ApNC * s/ePpS3VyF.t걒\bsC%:{\tÇСC8}t $Auv0ϗ\j=>Ùܹ3h/%/}&hoJG+?}5$*c̞TU,ix 0л/ߥ2'و]f:>$>C>Zݲ )4CTQ0&QuQ/@DOjL{EI0٤ܙ<>Eṕ$؂"WFv9Hj0 kW] s[DIs7#*/r}%}x9:s#Dp?c xR&4EquVBU"] K(-m"ҹ05E7.@i;2?\q^1_~븸͍u?~|+| Qv _ڗ6@Zm3Ϭ|%7i9ᇿ݋FŸ4Obct0җT{(/;tm5%ڤA%$e +_I8À`{E\4a]9&k(4o"1 Oж]y~"`KaBZxH[EzunLRB4 bTPepaZw: 3$%d k oWi&0wJz,FT*o X!%9ϐDrOAg6Jif*"S:kU(Wl[{ǂPd-0ѹ(+&Y_Yx dAO*tD#C+ڢ*K"KkK32%)Ճ9gBM갽|ǯ=d?ZT 85Gl?I FO?`kp}Oa\\ ]boo{{x'6s\pml uݯ}|߾w`waccw-A xꉓ_"3?ϒ[Pe1i1z eF@0ȀK!;*f}ҫ/U/kܥkӘ 2HFQf%X= ߒ RRB/mSUW.,勤T#h>ja97NYɯ&Fypo#[ WciM| LTo'g9XT}(!ZEp`i_{TF\.1D&IB!(pAoTXj uC 3z7п~-RPE?H;2nwXBkkkk=Y೟ ^`<o|#^Sf5[ G3t]ƅ3'' '/&808BީCԿ{s I]ǣ=݁-<>Op' ;7߰3oYLF(gF)p~̈́=`=~{px=I׶xq&px Xvx+7?Σؘ[J6ӶEӴhھx'{lG&=R I98-e1z"6 ,zTgIO TI6C g)ݨǒ79& &K"63 H˭MU&wRCkU 5gX%r2=tsݰm_ߡu=xp !{iOU޳t]]|ނzsߋ})c6D?8tqeΟ67o04k1f>4"?xy"|O @<={މObkGM@/}sٹ|_{d ccs#ҁ? By=T/UTǖgNľУ@\ސ3@?%FHvT%TYzx`4yQm0rm1 /rvPu.1a<(M ()' Uz4x-3Ox8U(Iۍ%Tv]gZ F:B"0u+bd .1/%b* R@,>TY[DP*Iolb')S u\bp3G~YK>e⾒wQQ-6`%yAG׿wXNoSS3>x/pM@Jh> <7e&[ٳCOlx[7\G@H/ b|kQUq_J^4ڐB8`dN53kooMP)Y O%u#;CDÐ1p+cÅ"h sErv"˿>i>O>_UTGѣ w7X}i ǯ7[V%xC|x4㆛ ՙ@GX/[%aox3>x?\_o~!_m{3u \'»؟d~l݂vX,?駞TG{EeѶM/~|cq  C -LbIj,y@ȣc[+Zү%r39kqqH 7!k;uyyEuⴑj7 Lhh$ϬDL+gS 0+ǬQP{>OI<"-P& _,[K̫x"!s$]S0cbI\РQaV vrEa>B[D44!>Sb8Dr3.$, 6@kVue'^yx^4wm|g@ m핾?wu &W-Z=CoX=_xNbz_#P+*dc6_>b9 V2Čsgφ]__Gixc"14:/u3kf#5:=l?ܧB}@F/?Q:e6m `XY.yN ʌDbnU-IJ[=tZ9QEKѱ.! U ʋ($J;'|´ /6Y+",љ\x=/T% Xl2S&_4;LJ. BH'Zq'6U؆Ebj W*!5hv 4!2 l.tڿQn13u3O݊cGװ#Rm<HH](|=mO 0:=wE B>$=.|/g6w#}'$u6R2+./Pj~G`a+sH ܕt qj G5QJf%k;9W1J=sRm?ȥ\qLuIɬA$J2yn]_8 !h%SOvÅ_,~l ZPF\ѶCˣ 0$gBn'{RG=u77!HBdT.^xNe?tiF=ƒVHKO 0{^ h\ ‡ `Ёᆱ`e=Ϛk3m#~|y:]m zxCv @KW IDAT% odӣ; ` - nY15AmOqGq,p Riq'Pdgϝ3gpk{ƹ3ì(\A͕ȡ0gW}s_оX[?Q2|vu%"t$Ep4%+ѨNglK𰏕K*gڢʝ1+U::}z}ȃC->~%&$SE7L("-}@Њ[ m?V*^Qg)y4aU\YqCY${$2eGpR|`_zTȽf,ҚJ5`*4{^-s>pcY }4.;[>\1$ZGT9Bg;|j HST%iШc0l\X#S%^Ѹá.G @=?$9ľ4&ж-xAq_})):MgcB/eƢ'p`nF$ݽ3'' xz {mX"u?LfkMa $,iWY&#=˂qAS}_d (JDrt$xd.lU$\$# \ ny{~ųTrd1JpgFIGD[8lC[`'zE:UC/e?CuYK JQ0 ҅P$"XRP&/ce쁈g3K<.Kh6n.c}nb13nZ? 0=` Pm40iB;B\< spȳ[pKr愃}`{8sxS;4L8z(c4e`$~mw:yd*}D\AڛecYbDr O:JSL.y[R:T-êi,%H -Ȫzm?`8VNVVYFR.܋4uDt1H {X#[t2"^ TO䌮[Hm\"ҴeH.0/⇪*krV Mrb【4}6H|?魉C7= PC\@aEì^[`5 W H?&>ˆDnK/yϼ#| W,MڇJ*_h焹"O> |Ig٘0%LGIUO<R@zv%e{{{xG,s!>WEmp^.\[n[޳v =srp1 _-Lں0T\e3%T))x-A&@T-8$C4\K6?#f ZA '́|O &krNTucyuH#C5HGT@%̃+@%(]퀢g.H:JIDCJ+5$~)Q 2D)F;Ff* ^( Dsڳ~.\|@2 ؿ`42Ob|Ch^d⎌oȘm4Hhmu1W@AlIE=@!|Tc ޭGuY 7's: y{!Tm:S&HJ`^Th4;<xbwec )Kw1xU"?a`M8a;3k0#Qw 70ַ2]+gh"*4|t;@\a!JІ9pqx こnӊ^FPW Qtl 'w_Dtx櫂sWgp~AsEiVO.}>}DY<3"SV*j =" 8lFs(zsyU]#u3Fu-"u2y2-XpUeJ/, g> HvnjslAX<)TA`p(|SX$>J(z* x B,qł8[kۓsOD2Q]Ʊ(?^X6BJbw d!kȭ臁1^.>H &9w]}Yaɞ1hðMUm{ڙ/;$ƙ3G*8v:̘m0iFzѐ~ `<ˈOݳ g?8yѵzEIF*PUFcԳ ƛk؝noO{D^>LNfNj[g?{sǜ>[0q'/Lgb ::>$A%Q˦3sO.S԰ƙ(+wFh:V[ )c*QR]etBA5=d HoؚMRq)LeA**6߮_`pk@&J`+GTk^_=Bl>qODXT׎ uqAJ"">;3 ^d U: ąa:Sew1p`,飷K9^K{ڛvpǡg ]`c}1]-$-rql"V9Ш6p㩳o5 1c7OGSԛ3<姮hv[[[@ f3!$>S|{kq YI{!bTlm[5 䀑 *O$[ eÛhSY# pLTk%yZcܾ0kEEBUZ9c4CKSX\E*~"e[_'u5p9b:P?dJNRTOJup &. EGT`#":5y! vQ~qZK1&,^CNu֌I} a2U$#x] wIɈ!I˷«8{-9/[0J ngNϞ#o266ud# ș02[B{{6yQ\P?!Lh)֦fxh>8z(n&<+1L0Ͱx|fF*; .#??/#?tV#w)^)&v2#2K-(VNuʧ*I )2I V]. "kԣ T4}i-3KuiA^S U!5yYs= _F+ O b8~J) ?7jxE=d@H8wͭr1;b/ЗC'ΙowٸmIJ'4Ik&dVq z;2 #}4ё=  6<73!DV쳧qE't1)v{MBg2c68{x40k3t#L+-h`wpaqa 86!jŐ#4pBG5r]#M&MX[lnnk#GpuוcLD=)`6СC|>Wﰅ#Ox=nz zK0$}'eύ!u4 ÈZSٽ\taK8`p7n_~O RrU)#+ko&IROܷ4-rΨBU%4mm@L3$b?c?HUڶ#UazαvU*qpDHXj@mZ-(go[ro  QBmPUKPޭvyyA^ĤU2ǩGePM g/W\z7}OV1[[,w=%CT$ ϸrq)94W]yO RoөH )IjS}Q徔,byY e/ n̜;TD-\TDa8 2)A nQw^:w5yg+_r[ɪȉhu]M}obn0zB1vܞ0.{ phD%PidPNm&tHTx:>y:\h0Ͱ->|nv:t;;;+ äč?KCz/c_.BeF}o/ zq fYzMm32+jU9%T5*&0DUJ^7\IޯVj%\œg<`HֵvXU0Ke30o樺 t Denito=Q\ s)CR #_vq} ~fbve] ^Jesdvoi'\*}do:F1*bN{šHBޒP0ʛN$JxĀ>xx[ 3 |5.PIv{ϴgq̙%U@̌nI%7 a|O:T#m\tD1c#)U`mW`I!GT+꤆d$A#o k$lMq=o: &X_&Mȑ#8r{Uz}#[[[ VJzW;]=hƒu$6z 0daL .0l\ckc 6Dj3{bτs"AdU)!3km[TrQ%K~8g ufG7J z4%BmF)h@Rm c4\ikӳ(f,cT"DYl%EEI= $ R!(XsQ]IfN'K\pxFo۶=>$Elpīx( td Sr% LD+8tRŞ$tե05K"?~|+dR@d9gF#\H)w4|v'YZ%?zhp)0S;s'q#ԓ1&[lg߀yb45lll8ښxu]8qDϣ,۶b|>& ְ5 !#{=s>O;^ D#~0%-B`&&">/pY4?|"h%fkBK̐LL2wbT|&&wRi[Y=y IDAT%?vw pH(i[Tc,sMt9#PH [{xeE@&:}o{+߮R( $j]YY. @MLR:ԩj%9)yгJwR0 D?iTO/%. &ʜ=t"5h?5y"Q6`ŚDwp-Υ;5֗B8sooԳ{߈!ݜ3p1Wul-o^}~gNCcQ4v, $(@J;JF511^67 x!TUl;10L0PU}{Wct:EUUX[[ b},Kj{(^oښ2@GK!eàҀÇFR܏'vJLnJ} /ZWKl 'y?וo].A;UUq xrP<У(mU]klR`핐J)8s >Km7Mi9nD/!5FЈW=}E,zw酪@ULHAoq{M,J<8j=BfWX,vEr.( }PJq&B$B0{0&֖@](Fie [ |0l4"AEV|PwQQUasGm0V@U@)_&A$^D9Z[4Mm6`V,&j.xV:*lJ .^2_?g9K@)\r N:v7 ,/ {;1m]= 6 ,y3+z0$`O+Wv&pvFdPEZry{.|lΟ?g駟N:A㺍ŝwޅꫯvaF ^5yNz'*ܶ(5 X7}nz ^f`S>!z|oGϝ4Uii2)̳[I<3\Kq㠔s#}׿G7`.l"@>(>/ছ^m3{y{X ~j9 [o0Oe(`VMX>,q,E}کwV'$mc|=ԞHޓ2y炼C5.[F";@dL"v3A@4ӫi0`]qYR@DPV@PvN읭(A~qF0T0WQ(ecHɈfV\RBjOmWD]]{#01XZ8Ccc䩁mфo?l8 Rz!$悇-/cg$fX}@^ǿ&K^{m<#0iرc;#O-.t鷱zؚE>%4&#NǓ|7t˽vo ?H_W+->[V{{{k'NzSp2/ksl>=ۭo0\˃ yDv$.,,wz\ AFD/*4c3*}s%#a9UP2}/@Hv'EcFw`Ш@)9Sl= DZ8ۢР n B ߶{=k*՚oZy\ *Ѯm ֬YAR;l dlVeRqQ l|S"<6Ҥ0|/Fske$Mf_ tgg/~񋝈6knۍkiO #x Ν>%Nn揈@{\آqtA3&Go|,|//y4jCr8{>/2(!MQJNA^}~ԭ#ae̕p 5eVx0gn-:X*Jj,%4c`5&f0`*b3j_ f ,{4wk$Xayf1T%!Q5pI?dNDc𛝾aA̒ d~%\ ] Dr)PyxH~1,!%kod$ *)DVEy%▭iTI+lWD{g0߼U8fr& FZ?SC $H'| ?Rpe9@rz, -01(R,_J r oƍڑ C- `oo[[[(86g<(|N]q&tTL׋#е=ޮ9M#BXIYXlYʘP۴a`@b,%V VRadהjҸsBڑ(T# Yy9ccB3ʯIYmPUZgUKfу3{E ?ixT7G qfZ@!$; "ԨWL#k8K}Unu%ֈM6uO]1Ū[¼uIQ6M;kםSH^7bk^q|U6霳qlx?~5*w?POO㪫#<⮜U@Zw\.x,@`bi y\uU+ƦD2NVUC*Jugt߬Jk{fQ&߱K7NQ:A.8Y Bڔ'FPBy4$L9ɅL NM:#25[v?D2b -rgZ)Wj!*rLƭǣ᪎5kΟҴ'{ck$aD 6''% Gv1IY#} 7J9oh5"z䴒LUɋj `Vy$D Щ ZZU;:eԾi^2 wRGlm{O?4aoooDpM75:ifvCi)}TlpBC@{ϓ^ OP0 x{ߋ??kG 2=-H^\<mwB0'_c,BՄFJu=&U3JB{[60#PJ edS(=K.o?` @!3qZ- DP:Q h8b ET"b>UzJ)E isU ! #SΈi̞!k'B Wi3b94(F{;nnDޥ$;=v=H MozS3@z- 29.>{((yc =c~"|RJO~ ضz"uXj5?+q4r߸ 7>s4]#4v(뤲*T.=&ҹ][kf_MvI?F[AC3Bǎ߶ a&*YJypcvB\# @w#H5"jZkqG8檤Ibq ąʠjly+ى$\}`ſsp.pUñ(sz(^;  gbc^NAU>\5$i}ZM&Wս2Ȭѯ k]z:yƷ}1IFvvv𖷼H洀h(5?zo#(c snv_"+^ x㍸ۛuDmO٢Z_" À'| //-L?B0,Km=_-\uOnQ Ma]&K oW, =soYlR3&uəݤmiӨcma^ƈ qt%~5@ Oʄ4nLKɯF-,i`8@{#ƪ$4RTm\ŚlEO-Ylk`OM1QljJP< 3žBzP7uIi 5UPBpsPhK.?o6?qZn/r]{wyWC2Rp-.gs0iC={#sV@DF0‡?a~kGl13DfR|{^ t{!NmsR?pu`}ᄛ5\Z XMIr)` iZ5mzPZŸv@d~@0 ZcudV2,`Pg1@SҚ/ڎf2;@01 jʉQ⮕2U4EcR{%a遴Ci"x<'!z(1wB-yZW 1u^4y,M2@1 HC@,ٌU9ثϱydn 796yg7Ʒxb#Rxo9AsP1H<(0>~MяM97e/{/-P@Wm_V 3(h|3W=^r< vga{e"QEPvAxWϩ#R|XToQ6AY;44f)2MM@$p,Fxz aE(bdq?Μ' 3V]*{ ,BTڪ=y܄DF ؎Q#2{\lVZ1,F5٤av+z5jmUm {A50cQSsF NJ>n_6(Y.^.T?k $fP6 BAl8m ؿT7xڹhCc鿗_Os?sM{zF_砠Mze%^ ؏-|cč*i?BGx7vΟ?O_wc1.) .5Q[82&ےb]1`=u~`>%hYsTJ"5oRG(KODcp*@N[Ji:^J`8nYbd}5o렀h~\EET8jHĦ;h1ACa9a%sk=0Tx M~l/u,V9@4xQiiB$WDPo )0S'Vڮ ((*M֚ ?VWɮïp=,___m2azf~PAL 29Q 8L4pOߛf\{4;O=Lc>&~_woz5G?5kǙ(ᜭو sx3D(녁H45JD ZIHduD$ҔZGO2RÆͭiKSN؟CJ{-{AY*d,E5wcČ}D$q @+grRM/AJ iDẐǤ V Cc@ISqܨKuNPovB6c7&lM 9{zR??~|;Eq砠5G7g|;.R|wc-6IQѸ~Z;s\Z''DLskɄ3=n5PTvT~X #&k KP =:7gѺ)g73+!/ %ZY#Bfhm{{`diDtmpC;9!a$Rx8E*Azk? B߹H+׈=6-*EqYjw,RKE6pW'!f43 IDATttD%JF1K_uǶf0%å6-NjjK؅t:5W _N}980^}WO?׷= / ox.N~=`F?Ξ~O$6_|5f5({#RJſ}? 'Nh:E+;K 5B*y f.m\B^,{XiBVg7btO:ߩ!thk\@5%tVFP =jb9@ϞZ-}E܄޷1`eN\"Oh8S/FZrHI]U>Y>-vM"Pb[qw^fD8,y>TA#ڕPU@,TRd q"|)](U9$e L?aO5K$.+LQ2I5*NFaX^ |W{uNm65gy*d~+_s֌m95y ^WAPt{!+v,6Itz'>{lsOU7sc?އ=yx^..K*&EusdVVtSͻqFr 9 J†/Z|~g,X.Tȫ$U`w)-1Ol&u=Ni1,mql].d<( n,I5{^;dpqKKP"0{T_2d*q`f!α9KXM#[K5Z%@?dNKvOn%)Kԏ(:-zbsU uq<bY[1# 0Y3&M;_JI]=!J(z@"/V^ 0 )a$%na} ʵ $^J𡮞0$@8&a?F#Ѐ0,ؿ/Yn<"u q <-ie% E1z5rK8.He#V s J :)RIȨ$lEIh"'#ˮ.ίKI#91MC&+A_:9ę+^Yh,́[kA4~ʈDr߁ vנ{Toƍ781}J뿏pL0XQ9zc]7{~]4<^7*y|o[œN&ϩoxk<53Pƭq"rafN D!^b4݂huמiG="Yj`@X-KK<sF ګoDY%w0G;ϹBZ^'g)Ey"|*5zc^̈[K|a\(br="#J؝Bi' ˷MٸzzwjM5,$ (5X 9e$tj7$2;ciZ&1踺4n ǿs.탍?4ۿ[̤'s lP&{@ ^S//l "ZKX]˷mח^TSsš֤I !:%KeᆦH!^Knȫj*_ 6"^6f ̚GRW-Ϣ9fWuyҎ 0; puQŘ{1ٌ)%CsBڜ )\ӪqNJD}Uܯj2LT'Jq1EBP5cqKѪaG1.;w~gS/Kя~'O ]8zk{x-n|F$9}8}Gz &PJY3S=9xֳe7#4+ouAh u2iWҀ\˺\`'zioڧ EzN@hif0@.5s[X WPeBKа [53IծOv, |#?mgzrp3?7 J:ըkRbt.HP&Kd60 !2al[[b j֨bavj6H(] C )%LMT)Rjk}}0,iT KM7!{TrVbj B+LŎzŎxqpè bUXҳ\5X:˫: R @AUT]ad` PѠ&[ ^!r7}XD+?JD1b!B TK/!؟ )4]ߋBノ^Ԇ+WLN%(P8 $m ȃ)Om.H4`H#V=Q>H٘"B(dJd Q5@< I,yM:Rt>4`W3nPf $9to5QuBצ>Fސ[no{ێD9¼ӿ?g}G?Qh0emQι)=MϿ[DgoHDx^@+spJ/t%Ď3 i@JaYa)%,Tt.yԶgn3F$؄TMӴ g=<7٥r;zidpҢL5tBBljp;-S94ITV ;_!`MWJԸbҷeFtT1+ Kf㺙e.F^eOcijylF7 Ϙ1׮R&TJwaS=Rg?<97I佝0@ߦMm^WUz549N;zF 3 dD{~w??W!}Odw`{Uն- R^T85] DȤp,b0$WʘAtlsyq ɲ>T7PΓJ ch_!= 諫q4 {5Xg`\lB}IF!R< 8DuA!%຀ 2bMaRWt ېj]OdbO;MUG^vu ?ndf| _Dr"4KR:u\mo!vҭ XW4| HSO=K'Y@JJYQ++B\`ڣ}?. ĥI.m՞NV"! ޥLcJ P+t9&uӸt=i2(ժbv ='{0Ib1lĢK؊ 4.C3N@֮a mIy=܋W_YBCa^ʿXmc;?[/~1dƘa97G&0cc1;O|wq'^궘OC֧ T*4J'M~#ÎFV\RD 4sɑIIG/Ol ?G1k׽F}oL3f0s wy7\q~ٷU?~?GARm„dWu, 5oaGvv6lk023qWk\ FMrȫ%x [pX6]%j;D$QYU5hnaiO "ZUZ+\i2qJH$׃yהΒo Z jB.SE=f@jJF2[2"$cKV4>NE’T`-%0ް7>5eD%j/Wr=އjudnk<`/b?5ۮvilfdsҹ7w'OlQYX,X,1 #- mogf\pa5Mk?-X4$o5ς痰~9*,Ba@*ctMz Cb1sge.8(eB{xpVC5\N {g5@q!%5&+2E[P)%b[B2#ـK<F8.CkgȘA Y;هHT+ aHiX @7AFZΨ*A~CeJR"W䜍mŨaP:.;6W]e%3qen|$ua^bꕅĀɟć>!Tۿ;D3Qi ϱ1~5{OOM_zBkF> L@O dx<ȣxGpu? ơN'ֶ3$]@&b i%g$2CJ-}X,*U:4l"lzѨ3 b, aDe2-AcHf2!~ٴdžG5(EbX(Ld9+Am IuLf 557~?c"ŠJQP|?qJ~(K:p׾F?RJ><9 !sq|}>|<.ⱶl"w~;Ο?*1MDzF̻13G- /vvvf-}h"Ϝ6@n"5s@l㠚0Dmü"gd)KPz9ԍT(Ac P0f` ~0 EͱRmQuX<Ͽ-0n"Fh6[FR*MTjvɣս@b\Tk0Ue{K< B95<_ …y7Ioy[p-1aaMQIOvAuF௺*r-rm/@5=Z1~'ƍ7?k\m%|2Es5zm2$U$y,%ƅ+@_T4b?OKD dsT5nH~) {? aQpňg>"JAP\&pE_4ِ ˣG`nI iTA^)p^^ihC 4[u Po 1 1:)@Z.5Ҡ\=נM盋k- j ި0uP$:54DH,);{~}<9+G>};6(~!$+o|${QO1 `Y A H|?Z.kUO`."XTr Z f}-ţ4%lmma%B_%O(-3v+tdZa&}4,!8`oA lS=_$7P ̰f@ G4G`ֻAՒ*m YIR}&s۱MAiZSli΁mRjJ\sf_v߸A\b˰Mɹ4^x_K&NÀ4aљ`V.w4~Hi 7܀w]uX}{8V[L`F\r%3!_,ki61#GmJc*'H h^߉|40¼]q.d=y>XR8VO'{f@UV#Iєd;+.Б~նDdV nЌ&B:oAa4lQLq)MsPSԛʳI19A <0xu8aF|M-#{cT݇1ezWJFd#U_ xlt*x)zSh\OMI-#ƯR|챆#: %' zfT Caa)@dD<HM7|so۰_M~0Gh;s9 oxN>k;;;8v,Is_#8s|+8pq8EٷLS{U,0Q" $bAɹ]:2iJ6,S4XJ+Myaڽ OCϱv=k^FR loocggǏ,_pXMPP/cwwLpqQNJ 9 +OJ ocp'wbT44l8Gέ#u dQƥ]ԹM>7L nJ05",MB̬ *PERe44,oȫ̃ՈKĮFУ$M(2dDmR˲{iSmMjNHXŕy1YŤ ~jgxPqhuT8Gͫ_נMcooz׻p5׬Io9A5AQHQ~:vH2V;v 'NXcQ 0&82reS< b8' EC q fOM֫ˢmM3vx:CX *k+Q' ;㠬Pfϥ ysI &Ya}s\\28{:%L+.UU@2 L#((zq.%KV &BD~joISbpf0g"Xc@d)V1UMŔ54Ǹ,eIL:2X|~RfG`%Ý~3jf5P"~h:wPW\8 1& O\j#8g 3 p K/qADgDrU6Rxq&/%ϟǻn\ve(Un"pϿX&`9 쟻7җD47WŚ45c^ #; 75.zku[1깛sbzcnOX%+R|_oIJ$Ÿ)OĸNYīǞUAֈ|OI撱ZMXM+VK>68mR|eyñKw`9^jZ+[νच~G0̢m@PiYhW;.2ZFȵ *l6#a~sb29xh_=ϸpWvCȡfvM/|T!y-(`ַ3Ogֵ\%*ӳhO,zQs9.jSR0Ց)E"I0O( H] ˉ ͷi\ &” 8+E$Ki ڈh܁QYumT\Ć(A.K7_k#.d\%o~E) n^ۓIޭ1y]CQ+B?^46.wү&gxDc?smڏxCǰ_=,oxo|ԩS8}4?М7ЦEM@tG9XoPQVPMFHݬ&XZ!bV $fb<90ɘ^V/!iY/DXlTEe`jf/}%gLV0./H&,R㊞U84h7X|"\<'^ @JHc4B huh Iy!AyH)ZiFDRQrY^q23쒟T}'J"0xkK#WW0 d,GE9md , \J[ֵ =ĮRڼ&߾MD>n)4ׇg|+]iKǏӧqi`kkˍ10,>'f=@xGpg]Q'\epK@',c֌Ti,*gh(,#2 X@$ iq IK22)K? 4G.<F%'^Vs*jBx-Dϱr|2fUcH(KyZ[jqu޴H܍q3lY k+ן4qU.Y6Wbp//kWE?k;ru}3:UZ.w'~]oaDɓx/^߮_=jM͍Y9oe9PN>FV< }i!%8$lʀLؔδeZ1#vvv!0$̅5sXqcgj&8*= Z\uH! 2^uշ,M'G𝶓g;w?5` >^HsM~L Ig MiӽvR ^YzK{{{ppIlmmĉ8}4|ɵ@};zo漁{x衇\zF$ IL~#mh&kB}hÐC:P2 B@m2Ҵ i%sG*TfZ'چ0i$H5+uyT@:kTژ8/\b&CI& (7KdմH\).Ԓ'VKsVK!au.f7)/wzXȴ"ED"3Y'IgM5e\SN$AWsd|o`D/qpooyk/h͏($s nh .9"";v Nr>@j (2'pGV "㬂y/,)o.9gp 6ZX.͏#V*$u*'AkL]{;lh?UFM7xZ6PGoHh[:BEVBY,R@QK0BQ=Ht{Hjxz:n5X8(I^-K;`fkg$`R(Z!\Jk ke>Fۇvp9?(cnZn}7I9-x>qڏ PP\n>|9?ޱ'O>YalC$Dt}.xs#РZ?C- 4ԍ/]נ!/qDi`#JC02+΃J)~(,uD^b/RV<)~7A¯!@' IDATi@ jor` / ? _,ba镢RK• 5ų-N` T sL&n>8  (t$JDkEl죵ZQ135^ZR#Dq À .4Ŀp/ӧg&ozD"k5hwIsR]o\s5r .ٳ8}4] Y}a\- # \! yl5G/뛡hyNCAry(qܒ Mae_r$\Q&9fB)q) lƀrPLy$֙4`̿ ,t [x-4Fz*BS@) iP{(1Jܿ|s=oZTCJh_,:**RqH%Q-ٲ 5tvn vFhq~! vm?pw!$F$-[EbXK$X>?HQl#p[k}k8|#F8gd_/\d =QEj08ǝm Y~Lq||}c*_ _j;5'|@V@L@D;b{{X6K$D)y.ħk {dm)˩$峜>]crYf0+( 'i@1s(L9hAE69ƭ[Xw2< #*+&gU˰w"N F{r\3+S\+B$Rp"7t*<\+fы*\%cJȇ5''iU;c8QrVhn喑^hDkl6sPFI]sq: 竸#SO=5`+צU;;SʸsCEX QUW?'Yh]^_- ^)Mɜ%̌&j*U^#j*bhxuBxJzQMhܹM=|^"yj&LH̃>V~5Y@s nhյ.9؛H>IؓZ[b)c@bVR mf45O^;I#BJ 49To(f\eYIT1ǩ|u`:tBC8 s5^ C8atx~s\ ff3<3 {c{{^*vzLY ƈ7޸* չ&fGvD5BKQ턧ŬmѶd[VًSuiދ?y>Hh,:*j/F-TP) mU-\\5,FI/;8d&AL ̚dre.U R3ƈN-[pWҮ3!-ԩp(wmWi ,*^;GB`DTƏe%9D>1s2e&.4k&?v? rSO=M* /xNV=+,5 ϝ;7hn4h`v5Ue!\9s9>dZ9}HT;U8CQ2r$DPr{[(|EO_YW,;,NX]~B*IaoP/8b9RI9 bACl0\'14ZXNsPPE9<3L7"Q6z.37U/H7=$J][X! Ms6O`L pRgɽ4W)iXm*o}z~*6ö)*@a9c}}Νo=lS )ZkIx* OoQ٣y={TOcXlMWhRQ{` )IQmhbA-ΉYr JffM,4TTK\73٣N*(k@T[8u"+zCĈ8L8&hEHνYuM6Pi,a1GjN(ϩ^z)rLxMHygm.kIA)uLL'\ v-lm@QgHiڶӧ߯_E۔8ʊ[f֚l6ٳgq5ҩ4|<h]g!>UT2:kI՘Ka[ϕƆІ.$,4,`Di^_q9Hs*J>\ Vk4BlpÈ?E&6uRº i*LF/amQ)@r\^yߕ-TCӲ;DC.}*v\q1"X},|e"*A!ʿi[%r fDz}%Sh2E` ?Ӡ~ Q- cxǼI samm zZ,g ejѕ˜Nsq&0jvZ `g;|i,}d &g̏ARd:V*uR=pJc3rv$7GߘvW 0FDqB8iIi|y>KFU*+` 9<ϱ\.6ɾM3Rm1ȮG Y l*RpT*Z^RBu*i9xr JXz5]RFDW8cBD&E=&]\iW %Lh{ ^YaB,<:Xdfʞ`p[-$7>r Q*eL'H`Prr`tL.hF3 9]GvU&hMBRbB~3jF[iV6p>]zkL$}/\0-zVIǎ`fƙ3g`@ ":PjJȬY0W![\{LqlWT'ÁQkf%#SN ][g`e:dh1ah䑘0RsFX"#4-BhT9H\^PvQXh-/ z> & ZGP?A>N>6VGׯǟ圱 xbiV R0uZ> yu?r홈2|tT6RXɁ0jY@| !j U X+P"N- f)}#IIr.p9~ȵS5%FgTb/{{֣`@ZZ?&&B9{ZIct.=pT]3HY"Sf\PQB^@O4%夔4fPxtAXfg - >K5pm%B {i_o5;o\:3cmm N͛7}kjahWYc0e4M7^zZ0,2Ьz)bZt6a0fz0?5CcJAl֮wK_oVߨk_ ^񢉍FyR+Ш 8ΕT[ah'WL!-QYj͟mj4fc 1TiNn{9KT)fr5qFa[N(U v@ш2dCYkTcabøMw|`|wǠ>[,0l" '4RR탕7qb;g'`k& c0A6͈@Rg ԫK4 NTnֿ`%fOzAM>@gfCA6!7dL`ds*&\HMPkNo%3o߸CK80au'%Pǚ13 ZXyX,R@il- X+P9jo9QJd'dNҁ P*֑z5iE 55ڦrDqPlB?$Qb|1 RB`i%,[R (.Qh|/㉪+U$PƱYr]^b$ Nk 2 =BS޲ֲ4C&u B1'!7u@l,+Qm4N8eM؄j# "-`<*hOaHeN fܻw> Ҭ52zJ@5  xN{S0z|j!Rr'TWY7Si\.Rʃ[+tD]׆gbP 1.z_V:i FqF;eIN^L!LZ",yx]օUs'r"ٔ]y", )Dqce1H$&!x!*F&6B%61.#R@n-=d5{Y2؇2m K$L+ 3ed/`h 7nW@ 0(7Z ~oDZSc:~h (k͵֛z&X\mJ>yo_gsu9w=W9j;?f& ,9 LTFv|(9Bۈ3KqKSǠY(TMUu}MJq@~KA2 RI^-,hu8g;~ AY3ޚ4XniXB9 B_.;,Ꮑ:)Ya|$Z)M>$|3ug"p;BA-!<$^/L;F0_S8 ԏg$_SMq_y%p覀YD^#ʆ`S G3bl@$R(,)'D;XB8 0f(׍W(p'yeEb H̞XB\IakeԀnƲU`6qj'؎_ G/'QE:fvA^IB!p` a]uqd+T#HLoZ! L 5EeA[Mi*Ą-B!*I11-Ek-qID&LëN= VwwWҶWYco>1W9}'?5JREJ$ &BRbYhgڵƺkvCJ&roS-w(RJfpuB0(4 -iI|AԔ9KN,|5gBW7NNUc|Xlf"i0+g12˦%[0ޘް154ʬ,V lvX`>v.; sԨ*@ܴQ6mKfsu7n>^6i۶cJq;{M{qsU=~}z~o@E, RGm5Ѝ_9fIDquY,~.<*é"6 2V*v705 $@X__/tUWyXn@Ih&NJ<B$es_fhD!4S@gfT CP|}OoH.,uXynPFKNJ-R4L. 9Iy]f[BX!T+Չ!#m#+cg\ jbxքƑC`f k '{(nXUߝzL{5檽{]ʪl W}6Ncʇ|zʁV^]G Q 9x1ﺒQED%Y,4ZN'U( Z<2 HFa4Rӌe'ZPU,S/[e aPuDdLpDQ@Z1";~)K}=q5ʏtd Bjp4H:%g3H}@, A9]RaP%#hDHjH1F72PcQ0z<u,˕ZXi"֜fAN*ਅpV~* wɹ>?j{6]ƴ߸,*e?i:ߟkչ0;gpyڻuҗEvHgdh$B125hab\͚'@j)""vI8K>Ԯ%B^!Jo XN>OaJ~bIJuBпmr'T Z5!Ed j {vήe@nBPTbb&bZ$_Ѣ:mSo&@@ݻwqVqht:竴߯k_enjPW' X 躮T4%loRlv6"ҵ ԕ朕{%CAHh@[frյFzIEH)!i=V HqQ$w ɫ_,~K۪w#N0hf7MR 1Y)I8iPmj΅@ vi K^OKF=0*J-Qx% 2`j.U`b˥;gB8{T*@}K8q?>QZ~0_O Ü{,4 zsSAmnmJJ6[3#Ĺ8t_cl|[)I0G,-.405`V|$k On'+GC՘r/4{jjK"=T=jjǯߏUc;}a)m@(%8e;;; Gt9 J*\x)\uX0TM@@`S`d``Aؚ54Qݺ*:9w9X],xRNhfMUZXiVMT%׫8 ~_fnݺu{m(~~[[[cV߻{r \Y񣄀]հi֒5T+/%&}lU+`tRVHJ_ZsI)!6V   R\LA#7Dl| 'O$5'4z/'WNx꠬U@>' iݎ` Z2ӄi92!" h)XEQ&cS"x\ $!l{G6'PqŢǰ5 0o>cggkkk 677lvg51)>~8tG$?huic`Ν;666sg9}l6ÓO>~Dׯ7kװ\.*Ƕ3|J)Jd^Ej9,QY9B&ǎs+xmZcD\.B ZKCFcYr6K!HA<a}}KE%I-pKpL~+$F ?Lö v V"$σDF(YX镈+F-QW*e ( 4Ъ>)D۰}&s3T 1jFCƋNJ>MNm#DLXg|>l6s@D$fgg[[[hց2 bQa=V52zaׇC׮]sc_Gc;cܙ3gpyq \|b bbt)a]cmOG_tKE`^RwABUQڥm$:g?GBa) \+zHT؅wpY@$`YC ],yS F 9ճ'NF&$0<Pa:E#g@i((sI18vj4Xf)lsOF( 2k傀X24\눨Yg)u\ @"Io>`)]wn}#K9UN'49p{R`B`6m[ոg};;;ux z65g]Χ.RƐt:7ۺbDEx|f5q4K@,LK )] B> +D"䮇2YҨj6zc^RI[R}J 'AOfS+wJH'KJ A(ÀZgG( CDRQO'H>ުRͦ:HX-(1rhfȩԡip@]А r's9oDf`tk´x!{0>r!!KXx7]$ #6h?c{{H߬{ە+W9),Kmua*8l_DZ@V=;SQ P(`sO5|b.\4Д{X[`?Ͱd}}ϟf-|xĀffv*ۜW%ѕ2e-Yy_8TuRx@]ާN?%mQbpՅ/S Q eMq0ҦOPQ^!CA/,BրQe?;&$6! o<24p!x(h0B$oO ]آw vf iqP_@n|fx,s%<bdD]/7fs3+{i#ŋsyT*g];Usr|U۔/` 0:UVP]|cCJ ZO lB`SƆ]3mrއu[Dr.BQM&b\f:  sf|=e-;Weo"h*1м@Nkz/ſ(PJcsCRҸdeXXZeVz6WXXjhY?Ch6d4Qt9fe,%PwMb-b/軛2ɟ`Ҵ~@B㓟$XG qtP 5znu)՚* W]u.o#:Y%ߚ=@|=,KfL2L)m|:]iФpXC` 1ŠLc ڶF3<ٚgդ]YZRB\K7Ap%t1F98GNHH}_[IBI X*^Z;S( Ú, Q`jP)ڿCC:vDo)>bRH$p;d25KPef \Y1[;=r M+%bE5YK:*):SqO"rV X_{x;9  I"8`6?Ol!M?{{K|=|k۸6^WN KلNCF1uV6 W{kˀ1>L!坙K])Y1~ 4M I[ m's*ʺ) &RA1D˚g"HYդʠ!H*2p:&10Gl'X@L_[(U$+mdU5/ߠmbDߗ*eZ7$cee/- AN7jghC ɟCc3AjS "':l`-X_~ 6o"K|,"/77!Z7 ?7o\ "/~@=' 1 \ǟ5nR>5诲>t<~.(-yA#=T"(L@ X˄p'BΧ2qgowqs;݌{{jRQBcӠiZӶMF4 ckù{Pi,g Z+|h]G ĶiC'rt]˱]{xSS%#2gav%͐axAȔX줽m )L*XƆj,Ь)"63e]ډTY18Qu$B4f3EBu:(gpb5D+`f%kU3wY 32+D~sinEUZ~uY5 YCSU\o!_MR.c歝'hx;^Ey !] I3 C]7`ɜ]lvonjBŋADg?{@c j*hj[>OSC'9L_ߜxm! NwA#PB^ IJHD^ɐm8G]SDґ+ȃfÇ Ǡd F` nܼl={x }` $VV+EʣA!i("O Eֈdy-Q#d) ,G 焮["4M3cdm)ZO ZVB۶=2ۙFKX*.5!<~kkxkW'lrR+D*B N i%d:p@.؄ r^snfbGƊZ+cwL*i(O^=iq̎Ai?0Vs P_;WWZYtv.NHoJXҌ9.g9'dwq~vg?woZ/?+i (Ӧ0jf5jØ3>bG_׏ '3#U2:I|FT(c/G57CFF0"Z|`%ܼ8nFs߇ 9֞Bu:d/)¦eH}2Dd"q!%Q677` 獅k%CR“E! ꦂm3o j&( 7~S8u><:.9H0~#PRh!YA$ x:ba;qX7MņZcI@RpE(/`݄.Ƴ(muC:U@`Y4((Zwd Zaws<мpi"}Aӯlmd~<51D:eHݴD'ݏZ ּt/ 8tp)p%0˸mLM9+CGTzz i ,A() g#C8X!0Fdւ-A^Sd ᱳr`yM'[Dzm햄`!,Ƚ' hb0@̊#ۨ$!ͦz/yA"Y*1F#> ( "(gĭMvJ2l1өET:w=xm֚`;a-'w*4@﹉"N!VYBսudh#͑Y]lGԨ^ADqX@cQfǴsketFL=_=Ì !o^\-D"G8H~a 3!͋=7K7vYDo|H)'~'&@&4L( `jz{\*h |J}wd;{0e] S\T5:@27L@ ~s %w=v[O6ye[</]Bs_i vN= r;OYSꗋ潦T&T7juVG$P k&uSΘU*4[`[%2`5J ΠvmX=|>(,~= c%Z^VD5{yB-!4$B@'Ez A:JVg)W5Cb6N:yV$VPM~ yEu2Wf^ihU./5-4zT CO:S[)w{o?7q@ /r}s8}tnjPJfSBev׫B>bqڞr&k#}&]R1 T]`(`푁PV˾j fBȐnP :pߡt=bkTAJzs#CM,z18$@ޣCA^CCm?F4,bMX$mZsmBfBt>8% 8uzPlʧ'hȴؽm+MnŋhT}< כKswr3c16{*-DF)$X y/y;_mRXz1[_vR`3ͽ 2NV9rA'X b*>MmE{wJ. IDATn-{/{3%T08-ᅪk?Ưl6s!/"ƙ3gV-r)rGi4Z4xc5ul;>,ײp|)%+˽-jߖ)  ZIgX6%]r+Vi3$9YC?T 悝Q[MI*4axz:0Ȝnigf0Ч^Y j5U}*QM} C0B28M2صBM k?K_"B{ 9um.Cd́T5ePU< Z Y]s]KmZ,h{U:)tdu sX&ЛP]W7j%xwlª^ r#WOVNr*`=o__;u L(CjlQ\$xp.8 $B)Ho3oXl Ѵ739ś/%9?}gqK_x ('R@v;iY¯jT?B1U37 W@Ŝ<<5T\9B Œn>Pi%땨`}sT ڨS1Fy{;/n`={tEyt+P&[*^z<:#/nՅ^j e&?s?kK0VfJC7Qokk?JӯÙ]p*)[}jᖞV((`g~;` ,E"Dbde!}䰋{o]F{N=s^˩eEbIV^BOY=:+$W\!È> 'fBX Ǧe3B,\}^&~vuM?hbu[~G_}ܼ&WI#e0 k̊تBiUU"6=ynR߻8xdErB5"ЫF}Zytߏ1SJHC,` Cdf n=}m~֛]% 5w1}s~3dVahyЁsvur _^9c\V`!;ٚc_OiS90zz4~o?k\j~E~>b2Ǒ:4a>.Q?8UV@ S2f1;@1Jn8@fN%V&] ~}$FufdQri Ukrnu)( NFP0V?G]k3dd`6b%B7+γչODZ И5 9cb[ꄙV;z,"s֊e>aE,'wA؄Aʞ!H}cÚ6&DYb2!#pg0B 7߫jH0.\ui߱ڱul,?by5Lx]wv@x"+|m-A"-$R??[xew!NZK]/Ν;WNF TЪQQ1s0U>N(%&KV S ^۾ RG [@ F@F䄜;=lz >R [`F)1+J֭;bxizXZz.mPO4)B + `O ĸע&s)%DR =v|  ?AooGl(\"DyyCB$_tJ 9;< zeIzf놏~YYykFTb톚.V|+\mf%۷bks/;ɟ诃Wŷ(@3wv͘AY-H"G5B5IAep/nbs~  ?} ]V`ADR;x'A1\sSVqkllY:XS^S@1,MCk)sbJ+?oz4ܷ Y? 2 k_\%ր;Hg."髝=P?({)y2sJGX,ĦJ r+baX1t?O>qB`6 /_//G]qUOA?%^&{ju?MA\="Z(S:G U؜OjxpEuW>, jn> /@UEJS%n?9k%+ 'BIbf/Npfm[ro58;)$٠ef4/kyfD"Ѧ2t a@xthO< O~?_3?'7oko'n _"iefku`pƥfTRzƛ~ Z?KFFJf|?^`8p߀:|CJ]5%% {xJrޟᡵock=t/#9A|` GR#1CpaJ?ߦA]~q 7ǯ[Oz9_+k,:W_u!OMCC!V k`߿ 0Z U| 1[S}jۖj2NQ?~ߕ'Ekhx|SX+h`YȦUg3H8'^HȜD[ϜKW cX.g0bA1i>bng` @M3O:X1de6 16It`\*)heIdY§e"jlBEMIi=Ck_}K(4 U{x??7.׀ Bʷ@|wAh< o=/ྋIkT@$V1&~q=gf:,q{W/|ַ&5UHM55eF?8XmkuO]c}F" dC-7=ī߯t=F  >b(X@jRFJY XB9gpJ]qpeGEi+;[R?`IjoPxnS+()DZSPQaQh@1U/9ro.#1sr~3؝F]KHiT.|,ԫ[uvYzgfEtMlI?:֔L}3,9B,҇c[4ACZsWHz6Fli_r%hPPVY@_<܀gR%i~O7KHy``k4P^{ _p$H[bϩˮ,UO}g pK-AHb[:4{Gϫ3C%V&xϑ"tJyX^۪E~^qS4D#eq!i1H \3K"XsQ%s$.[ c<)jxXv ;sS;KSKV@6?Wxqֵ71sa1qގoL vǂS> MQ/0 ]sVj9m$,Le2O0P/͍Q'fINHrCݹ2BcBdV?bif߇*jg;nSZQ}j)t9 % _z=zWsH}(2BÈ1#0w.*Q@.ּJSت,Юo. v5NhxuJ7ME@TFRɋ3Hw~TU߰U qřވ983ApZ?RSM-o}νohM$@E%QHH$mZ)JTGRGr\YtYT,*@8K H6HЍF@O9{k}97@~}f^D?;E.;6Q#E9~JU"h K)keusOn?=0& E.`3ěxp]@u0ASg΀xyId=SñcVI9U+1H&l4c]hmls$Z *$86E0@fhĐΧc~mb<#'u+  H ŭ:T@Gs -LԿu1tA@9 O-2RJ:(LW48#+zvyfCc~>CCoEybs _3o6;'m;kyyOooaccc!E~L} c}fYW/ƾߤסʑT[ `/Gl}Lo?@=/%/]zq$5cVމ^,_gmh$s1 ӌHV#EuPQ;"|a2Nq:yRZU8 PfU*lta&RExxǴ{[@QxIAlgs:^&H+ph[I1K2(u|e3lbI?TBYP"^9]` Xx2}3"G- R6z\a!'&dR;<6w|K'ge YG!!-+tu6cz~җ/~x{ߛƁtyUk06ߦ^?;JEEDo2r+aW){kKT)}<<6lNS& 2k cJ5HiX폰uZŠ' }1H1YgX:vi4+W"yABȶq3u`5riKﲑڑ;S#k$NswQWQ$wu \V#E'1t"sٵMij"\X2TB8N !7ּBa)ewS{'a2覫'J]2_c CQ4`ouq)UtcexJZ&  M"O)Df5~ ӿ|!R9mӟ4x≜Xd"a :hUtȔCNy~Ʋ|}J"^pX ͝3ccDosy~o8V:{STr-@۠t xh 8GF OJ${CM%$sNk/h (3`:Sl@FLX+H ~yY9@5ky$Riʆ }ڠ)eR2rtwxڿd]Hͭݱ<#[[ jdXmۛouCw{XYY5@ncc `yڷ'ј̙3xꩧ@\q`s7Vz}HL;l=}] v}r)ݙ  Gs8}q]bjlw MLj[GMiXN}JLj/ *bA<0>3\I#8#$9yvhC6޺&.iD58SjK=~@w_hYYDzgEc%A@Ι `mq`pIXj/R? .XdϮ\7 _D $'H}e.,Jc`cpW@n}ѡ1Կ݃ C{~4. uŋy-HHAuދ>s/|C!qNxߟLg/^NP?7tYz UVΝÓO>iPWe%g^ؙ#Qlce |X(.$K~LCPe<⿀綰uiV c%m)~; Njsv$7o}yf -U+9`{"u ;@6ani7p=qxR&"-.p * ׹%D|%jFtfF A[CܹxPkⷨkCJ(!!DT9B 3Hb::9GWWi8U$py<1턗ϼ]}h\$)RWTfV< +BBfl<)P˳mzġ79K t9^)K|q6A_"W6W|`b) kdiB>{cPIׄjQq~'nW] gG>di27!J֧E@E4 w#"g?7n upLqF- wݗ~@DDTWNrBE xrY#5yŸJUtuE 4K&d4ϚNl;563QYE˜TI"uhFUX2g#5 9Y=/?;x'>ås/dv_P\Nj!+b bm5t``/_2J rHu="BTג+J5RoB!SPm!jk%TPQ.gğcMї&'56ְ`)ޛ Xn p*IRHHuo?7` q9_DQ@%tlً `'c!" ?&¤rR:Ye};K#DGG7Wö{e6{}" `E V?q';xᖎsՎI|zQsJ9@ lߵvI>&oC";YAM>#<@,I>x:"6J);_4ڷIQ.:H_^=o~i P$F^myc@3)q^=IG[quA}h}&PrM.y ^c9ZxpI¼,,וHsf4ѓ`W C&3ר.EPvO FEs&mySmT5ZF a&IpۖAIEiPIѥ8(ƚxE&:n" !SD{tqh0Dlxo<8a(ItPyZ\ACcd ÷lMiǏ}{N<ٳHm]7o~SBl"5Ohwy/ys%s$̙{:r{9 tэIݞ> cL"6bdIy@G3QKݘIR h$yD;xub؝ P&OCoiBk扗WTO `cY Tq8p=ُ w k?>u{]m |JF7Ɏr*tfc I'RC) -=MRJZCVCmXb*Kq/$%%xـ+vf 儳vBgeVd;KJo+4]hVyQ#n2~=۟z|;1L`Wc%xy1݌F N`hlvmcSO={nˁ?T/Rt=?\;@;-pJoL@$\<:3E7^ސHTBf0Ź( d8'#!F EBlMઆn<+&hV浢&'u鼮Y/iHFLjIxZɩVEbD԰ b`GQUkWpu}1ĨㅳQ/^,~$4ue~("g!ܲ$\H + W .*"$ҷ"C >'1S86 9b`ҁs}uhHw}8glRq,dnD&+׵כ:π&3PWCA Kk;O?w#?c8ydXDJf`Br2Dc cL2+7̳gsfܱW滖$K.4},'AXsnĿr{l}F(r۵Yk)ޗIʅ +"TU) U m5o)<ă> Vc%cX߉S D8lo|8}B}=n;2E4Ec&c+_w#=D4:cI Z!2Rbg8p$Ya{VwOl8NQu<3uG`mf̀ yIA!EH^ꇎDE)JL㥴"R,ڈx:GrRiq텯^Fܺ0q 㲿T5K P.RZw1T5]C,$V/RM䔧s;fM6@ZM78DL*f#M_"o?##c }csq^8]~#CFeA7 0(i0xIZ[݃S_Ξ=w8rHǸc7vM +_B/ʒ"z-"y^:wC0aQ(JMKh=Oʽ@u@5XH1Np!OPo VDdd OM`2;椶ω<<©tƉU~NSC;ǜ 7s oyCG~M`<ͧݯIS4L]/= (ŜWhvS( $QL-,s?w9 ,{=ڦe{aS>{/"`TNZϵr0z̀} \,T@ݽJbA$&#ȵRG@]m+Mxϼp O>$>-P]O16o7߹\ s??J#zqT!C؅)9ܻQwY4"s%A @h 5OhB8# M%<è*b-)9qPQ[\#)+4F2 Tb3l؋J?IH u=Am3y$4hUvՓ>#+Hqp+t<Ȳ}n~g*&_6% <3zY:K$y5$:Y{`Nil[3T;Yŵ6 }7TڦA:Qo Vj-vj3>C=UۉZʌ@c*&@ av [W>f^6׿uKxp]weaϤ="YRgΜO?W3=""4AŦyVu Q519&h JPGľ)IN| KQ5ТH6D`)87kdN!N4>/{IU8qx`Z&øxUm]`ٷ A5x 6vo+ۇh:%&hc2p!4T ~q7=K"pUH]/!B}BZx@& a" ߾v,pTfMACw 09MAw}fP2idPHyi̟Vszeq"ܸۗ?g1k"._8qy{スT֮RwY=c6.\3<.$zk:q 3 O z~g;|LŽv0#(ǹ!c 5*oH~[A@}N~K>d1lS}f+_e L&Z ,Z{ x'LgX.QRb * ]+]PpF')(3!u4L^n㵵-yt3M v?#^JLVB|@AMDv H&h9sn"Yxw]=@EʁQ9ͻfe$ų `M֧%Q-)9( ۤ*'wt]/}]oNc цm̮^»EB/_??ַNJ9 nh}x^W^>K.=H$~{ǃ+p r/}v2g.y sCd(? p9x CBH3L1~N/;vRd)(`d~L$Bg W D[8/Ϟ1_;?N:5'6;IhWxp+dh\/sxe^ɦ[L&d"; 0Q~xoȑ+72Ic6?[ P~g[fFI"Bf?/YCM %ϠAv[^?߉s8w4 ^~e9s'N=܃;ǎ#RnCt\^z 7nd9ߴ HC!A ؐ0N7<>,D? Ɵ}f}YQCοU`J'oL9KJ5b !8뼹v3zPr12$9=Z/c:YFj!Dcښ&) HQ\oy o} 8oko&<`uV]~ʢ uL{EB$'M~REf@k{gBmι\TT){[+syJXA:uT8]cH~yRAy1Cžcv|wF#7( =&6_#GNOY,މ{8wΝ;@t'N''NzGIܟR&._54Msƍ= 0N1_ ~{]-\iƈOcF[N\ƞg~%1Iڶ@ǍIl<_`zQj7!'47fT;`^PDsT%ELfQcHpy}S`;JI;8X!*j@"y% (e925EIX>v7> NBJN,^C-^X6Ai.k> *Y5S' @UW)dl@=RVQE.EC9C˻'Aw};*pkh9!EA=FmZ?GPc αIYH ~OfzfzhZTANUml_3g +QL dž:ƈׯ[d2A=LR d6Oeto <ƻk@mB+7:Տ~ N<~?NOT0IG)pGٵ3)}b + r$BWSl&*t3& rpa#t#%/o :L_":OfH8{d5#H2vREDQѲ9Axk7/ǏgF pߥ7E"_;""Л<l7j-w|zˮ.*..wGh+ Ha` BI GVߎ_g0<*h-rJ2WU.oE_.s9HDZf3_y8hSePQuf(1"F9m U;9G5)$"ԹuQ }I|+-ƿ'qkѼ}4r^=}@[YcF<.1K=As *XfdpWM4g{:4;&MK" ԥZ *lW뗑fR'dp1$cspN^P9oxb}}G@1r9+PKϙXC" 8ؾW/G:|5I^ӽi ߍoϺ5LS9q3 ~T07;v# B8S[yvT ̚U]ā`LRtIӮò{x#Тz*_qBNr9ꢆ%HKZIE׹Pnl&T S`"`5ŀ4i.r٤hфYmǔ . ++1{h5vT<.yP2`>ZNa0 <*D`.YMP.Uyj njv+Sp)._o ]C^^N~?'ڳCCz늾쑙NXvp!Cs^ f ki…#4E4ZuWy$U)bOBHQJs1ɋeSG hb_LB @qY$$%H=GU&U]pGK&޿sac;0/<PUW{e/3p(aT3>a9a -:jJ(L/HrPIrzqN޼" I|UћIV,˿5sLף|.CNa`WrH[?|N9bD{kyNqfZؘ `R~=NryNjf[RmBk@HB!`_.OߞcŴ(VB.z~VCol=uhËN|%> UDT#O$1A@rOrȪY9Ǥ\Q lZa>Bhf@p`'^<[L QPL=T窞ɩ*A =1_|:<J'LvO}|'8E@* #zR$pQZ|Z9̂PJ; xPܷ7!t rۦp)$dάQ F<[i/@5E`1zb2A,IkʣN kĨ*Rk;6WY3qM#~Hb/LB (/ݷ**$J5}L ^Q{L#UK*p> "Lٝ#zlpLzˈhz#lXd;ieb(प\  gζRsR! e44rH jGPE,!1wr%{px$AB.HYg.9D%`brIEs׍ Y^#U*#Pz"doI1`Nµ9 ^m%#( zyC:m0!V ƈܾC1k r A PzSa !DcGq9Fm!s9Ml/x59$sIۅx6w"I8m~Zp"g3X_y4Z91-F)i0ZBD";)C bouV̠HHnJWILmmd|ׄ}gh$:Ea"}`9a G.H^F3Cl#"kApS5)wJI.YT#HBkX" ;Vϛ(sjj=׿/Ƿ#?tD"@f9'QP;6w@4pk(M+gb\ H1Ƽ@fLr!W1]&U\Ik2F@R$6tқP4;0o_"1F0Du["7'a_a,08lnqA=~ͫm@:&l=KЮJS(f+c;Ѳy !xVK㕭c^P~'U8(FSVCr}9'Sa9%%)EYgNl7ƌ D8a2HpޣipM8ZYW O dŴ9fuO~X֢CN %'_R~!{M>Ð϶RwP@m@1rPBGK:N^ENyV ';鬙!#5P{`Lsj$phj=KG`y̚2C@ o}5q"?w_9`` '6QGpJx%r#GØL&=J{ 岓g7q7ƈquܸq7oD!W~ kĢ O&Im}G_[ECuP?C"y[\z&Vxf~)lexĖ}sj?DAcjWX=$d I`P,O'[퀤iTp3!Ƅd95t0q'={J"^ U5vpNQt kgwL(6Mh\**'D<BA;&5|\BJ"h uQ RjcBófӵIT} 4 zlJSJ92g&x]ׅtMWX}q꧰q>÷NcD9f,Qw&& PՄ? aվ4OHz;A)%ؐ'-TApm#akk ۸|2VVVp Q#C']qISk68J,r*6$.cmm 7nt2 t E `Hdj~ccn&4 <~ &:d@vynX#Iy u.O#oNH2KYrGNUU8(Q@㿒`DbFZǎ\?|0*LҠu6? WMЩ-UijN*.LWO8OЁy o^MQ}]0$`hLˠQ?WQooAkg4lòAOH!vKt%I'@%awPJ6Ʋ`|0wX l EήyvPxLWBUu@iE6L$e&7'Dw^J&`~*m8I = koFDpǠm k?WZER?xr($g^d;˓DUJ~w?\,1su`\+$ 1}ILpahXރ8@Xij2_Mp5\[=)ģo?-]X1oY0IaE NU nBJP@Ysy7FdJcKAY 1#vqia}&nszQСlrz*u} (zeGOA;9(Ηϰ=JܦQ# MKJ_S9Dn=.)> +I;HլmݦJM6c8jŭȃDa#%0 u 4PC#¤"<{ |k_007.o$-c%c +8܋ IkɚE.Fʞj&ƘWiD1+̊8cQ@Qa:cNd)l.*!u͆^bL(ƥ.n ,8arߋ <[.|'_D<^rV[DB;s;u{+sJK%+cLFEIp"p p+ kY9% 3,k#Pttz"rBCT7!A9{y3/u1IhKX]S]jܡRV .̸kmZuX}(^\mLtj2.kF&%\KNjy["& p0Kjhmoރ,ծFB,"q Ii R `kb@ŕ1c:`}T4,MPl NpEBbb,@ձ[QFK* IBjyAAFz隆@W9ѕ@VT/yǗRt۠I2':$Q2 c> ,މ+j۶:jDfN'S6 86B@ lֱyemLqC i2X$Y?~c gMH-(fiqzs??_%,-Mu]g4}-Δh;R EWz/qd?Lc6St L1ƙ:yZ{TOKG ?Pїy=ZTҵw/,UTmSȉLN2ߩFSW5&IF𕗾&UBpiL3s!_泯f۳)Ì12yG$kBSL{YlaiLB UG2n^xU#;?L1 CI6uTr9Z( u ԥo{nsdM+U|r##Rp&rR^9UYT!DŽB9M]yسpν#ҜD"i$YtUlڕr(TC~D>K*UqR(9JɒCq4H21 `w@w=|Xk}ަbQ\s{ zֳh<äY$4J-w!E&hCnZCq nlKƵp0^NxEANͣaa 3~ kXɛ6'gka!E5x|ws 1YCDCOY,eIj=%P'cQG~T"xդWcs}c9Z+(YDշp:?m1/ [=nBȿzl(rza F!:e_~3&o=6\)Zch7.Xϥ'@"6CKbY3'y҄4gƕv2A_Ѐ!F]{-:aeD(* ̱׍T> qmcޥs«y ( 1䂨@V_;5R( e3bfI!Ԓ^n9qЪ;%kbN>GM5!cX߀mɸ2o1_x|MK &ZDMჴ<[`ɲ SN2C%V _=|'Vk`^X8!,AX4\s)4^~(]$éiV`}(z!Q{Xh-#v3xWZ&JW%8X8f}ٴ,`qwi!КE܌ϛ8T< {\xx|oؿ|(S2dVwNbze"7@sXm'p[6bmaw*R.s)ΡVezgWPbAb0QZ X4l}DP%P18Z1׊\׃F>5}PAuч<ԂYEPn z5tY/FJҙ*oȊ1U@[_x%e|@u6wq5/7aJ)Z)-v,I76$",E$8vYkG7Q6Tmmlc4ک>9a4El"ZYWp_#]~ /w5SA ,}ABH `_ql,/bc!\z^nÉ;^0 Cc-r/ Noj)aIeˎQi3"4gYe_y{p|>:_q(OGϹ;UH'Z=ZUgNv{MqQĵI{^k162Ѱ!}58#ph59p@c (dƻC^-\ay^2:ѱtpT1O[G@ANI X=FTUQsi#my ă(H0#I|?oSמ8/~)[ukZ@GrEx(3Z,ivCժ\b ѐШX Q-9aA.`jQg9B÷Z%JZ9a8(iDlNZ+8s yxG*|5i\5+DkZCII%fÙ7}c8qg yO%qq7h.ShƟp/ok5,腩+; cNm;NcCT/SFV1Yz9:j壆ߨd7g m>݄4+#bX|y/hoY ~<ϣ0J hͰ[]FP1}A>dž Bj=2<ƿz*Ny'6(U7Ce{q$c9Ddbа*f` ʥ,uZ!Y}>R/"2GjJԙfqDh69l@erj*,dV@24`պ<`RIlyoogϿݘ2cgߋ?]+J}XP5#w`q% ^ kֲ`̠5,G'c]K(6!8fzDU=W,T( /sťW6HʺjJ2Fϑ_;pkdvPc.0x8wp?.}mc,vP_sM!) ?6ɢF2$қ8^aww à0u&=ː0#-ӹ>*Sh@h׍\B3V )>7e_Z)8/$n}c1$dYg-|1>X"n}"u;#NW}{8dxL./gypk Z!x1oC g^)59D}Vx:s ^4Nj!D,Jj4MJJEBV>(~@)bTՆ]IZ-2V>!8T04XvC @V2QRЌa$v)3 ug'[x:%#7LB`]/ Xn'(Qy5=FҊpGʡ"DZjF2CWD-= m 7(g.E}h} )N(B$? ܜ_ku5 =*nXt%^ /" Voñ]Ycz-QuRžovG镤{U~tQ"՟A].߲E/q^󨃈4$wKAe^LVM| ><_t=ꂲkM-@Vï׳:ޔpLH٣ Eӻxr7=; :sЯ-# 3Р Ø@2) })5;Ql@Vӄ83*z`N OjIl68v (Ĩ 66z܃CtOyvsMo=҄A3r0CC~Ks/Aep*xGO/pп*AaՀ5cۑdp$CJ B8+-EZ_M#k袧u3.ڄ%A=>!EOugFY 9gvYJ-%9#8cvUIR qI:Q }SJQN7߇+G1?c{OtIdڟGFs\I4(4*%l߇?'wZGS~EAED"vZpem)@kDYhfn7׋5X4̰Ja"g71G.{*ޛ /ڷ&9Y@΄\{T:dTpvgvp7|qԨG1 oڅ"jd-bΉ3ק$1,́T "9h0Zf30J9aGLDyf-Q] HP" bhPNpSxGp'OݸhxPݙvo0Wc1O[p=.3<[tTy/uX!k1d kz/Q!-rr0M j:'Uqg+@{%#1Z ΑkF6*3B"vBbܨoҖRZE-j߄==gq۵p81_۴) xU8yF"qЫQ ˾p (C&>G t׍ G.EiFU Gǿa*YSӨ-\\)ENc׊qGa XW95O]\rU_~x}@ p9b6NcPE[`q>j/{.gC M1x=6Q2@(ڙTPKƜ-X"[/bpރ0a{O9ثٲBrv1ġ{oZ=}F/DCa"Q >l){mbRW0"ްDOp9 bixs.۸\o6vZP*xNpSei wZyBBt\QyA҆/3VC:މQ-ׁ8&Q!EC6zVZc]P瘥  5uxu) \8fxܹ8VDSfHPCĹkm89 q\uvFaKDyՖ͈# ΀i(!pYkPDSFL!3?佪EeoifZ2weEd c~.8o.p3aOIτ*y0;xPM0#| $a8/A- gu4q5Ⱦ'ߊԙ>Thu8*wEb;oe!)'01m;iBLI4T ZWz]ѠȖ: .fi61ūEtFHXLk~E_x䫟7{ 1+uIceS`:NyJ w><#X˶FVa@䛡tj(c,$5X7-#JR+AqfX _ϳnM5𿢩$x^;'s7 Yq8" {DZH(yU\%Ri'*4:! 2Ʈ2t:2"VȻw|~70!l/c}I{S` nA838~. =(rCc4@?-B7_{ePF?zAOE):gT Zbhd81K_gYFȡB9QYhYPrqD-x!HW;DP8š ۝Ʒ7o@N[te&x0v T*Df`F>v8t޹zvM4,j6̌ؽ55;0VI,0W$bX7G4$c.5dN60yn7jJ1RG. 1 RF%jag+W+ CuR4nRgTC?U!r0xwEfx 4|:- 0Tjb. ?]`M*8w~} 9 gw6'\@F#؃,h1aj6k&_p=@fVAҳ/U  ؇ - ?{6Oj3a\ gi` $E)U6@CIU |92L\\4EfY{ v#Mh+-ÓkLQ,-*jk#v/8q_Iz\ Vcgʭ#]VnI;?E'!k&ᤗ"M98k4靓%iá>#Vzi V¥,S}j%ouhW:qdBsXP4~X=V { ,IƷ'VjqCi{2nyI-N}yXW\(ONA@VS>" qhZ*RPa*2}ݢz(JAf%FAQ̘6\;󩆾1 ~MD212pҳ׿a{?za\#"÷fW=R `1v1 Fs`B.Ο!ihЈ5jaLO 9B-2dn됊E@N2 憙S`IIm81{.'tOw!:fƬYvN Y1+Jj)v6*XZ!FԜ!FRLI (B$]N+WmAF-QԢ֓s!% 0TT!W7f"XU3ѧ}aƤѺ81מw$sڙi:۳)rh yaٌ:Zϲ=/ պ!%W+iFevEfڲX)pJWlƵ5 @ȤV"jrmA3Ga5I !w+ɢyV0IqժBZ1HY&!g9dI QesH@Y5T.M*(Ss?lHMX!Ssow#QˁǕg~}n+ݺî+C$Z@yҌ@"U3 ʢ(D0osgA%!LZ捣mVm_S) ֫&s¤)gPԱᛒ% Ҩ-#> ZgvSBG$Vk : $\6[l(I2Ś䃤-ݰ.չAa1+4x6:M6c f:ZIB[~pJyVֆyeB<cTUn\|pAfcw2#ض Q@- :GsFsʠB0>d铨4z"BEఆE[MNiΥiL f;NA1c30: 1VBNRtpI%!ގ X1_9}TB{Ra}I/ `,!BTt"^fɏ(V}szB#gH?`iΪ'ҕ+~ 5\YLDo6kENxעZݖ|tIo 9 +|8&|k_O]_UJAWP8m 5 rm_YO\"3< ?<]AD`MAY#3S~dypp!(Up7!ѲRr/l/$1 RM6ZFd'_[,d($ m WX /c'x(TCqlc\Tc59ZulI%#h1Lhِ.(6(1LZ[ BSwZÌ:@X)HZ3d!vZ#[QZGz}|%S$qhCFZt z~ njP2JB#^hD 0DENymuhaG[uodGϱe0:hi||"*Y|l-{P32#"V D`5lYe0 YYL^jN s!`fÀũSKPo0B %O$qHh[sSsYr8qWqbN+/z[ yYgЇY#+CM'#F]h1Z 4cQif2<<5.{mڒJ)8#+ҡ:(L\r#*Htf\Zt:>1'1;yD=LU&Xr3 !i/VTp劗=xRua{L!my.E7c,K[~:9h"+ٿGqab2 }/Do"熿"aApZ/͌RsjSWI:4jsi?Cm]XQJJ}sZP8M@@+*AlFY^@%s_`Q6$`SUjqիcjqgc6; jIevg?@ nYCtP6A׾q%\\>KBQJUfHZNvJR,$E/{_񓱄:v4P|M^.Zs04 p4q d/Vvj0s K󅔂l2f%JcIW=a9UfXwS5[r82s{pXvQtk*5Q:8L-7+\Xw2~fwUxi Z-nX r„AqkN?fA@Zij"&:ymŸ_> qэl+q!rW+\x;)'n5“=#b9ć4= "O0t)iIsRQr& *XF4jfd :kIgQØ_b4j%K[ jIsq8v}Gvy G vńݻ߄wN3x;8Mi{k%Ѩ]gx-},;o}*EK2XcI+29,8q]wJzI"V+kܸ~#+kg5*LVʵ31M[wz: 9c3vV&!9fӘA<#(]úJҜZЫ<4M\\XF{qa0ZGLC;8W.VV  1}8Sy){[SCk6ξб #FзNlG@ "fC>"Nrx3wVa-N;Meig:57L$DWyc`Ey fXdE-ׂp)!ld^K1a@8jJqՔЕ.dpUH V܊Z+qDI2#ڮ6Dya$MKQXgv 礉d&"k5j3w܁{_pcڀn"ҾK({Z.|S)iU;h fJa AbO]0eF*y| w} [v>_ug ν;π-( :`% TV+6EL/UQǓ\O>xޅr-J Y K/eZ0+3σr:b#yl[8"l`0qv;5~i1PES+J1 ڰ%EFiүP \$N )%1*[ iO&f f`&pHiV6*4Xgګn:R1ÌZr9òc2DHۭ; 5k]:AYF,Aҕ+\h˂%W q@NJI~Ӽ b85,5# sԊ1vAü=\]}zݬX6O5hu-c1`lej7w9lYeu@XBDp#%r4ֺW^38,D{XP 5qq%#"'s\@sYVFٖlx"~;Ca'i^9I`4MLU ԌaXa6 X_p8D^\0*%5ZZ?9%pOY_(ELJ\v %>@熴 }Dx# 5U$31>xL 6H${8.ҴrTF^ ݗ׀=v NP.*ѵInYexVi\z jYF'rjEള8"u dD:!݊4L qsx ;3y:AJ"g]8<)%5Gu]x˛ވ^|_WqeoOma!x0b}9k)&vH%rA9=|/ke/6cU,3Rύq IDAT=އ1×WBloAq'xv3&xsj]ӧG ?c]xjQ@ hъp1i:q _okiP"4hyv?MؚM$28}4N(DEoD;;;;< *N 0KÚddκq30"3|Ս;FW. +tHk7ht4n2&AS`i0+kx '*m(7. aG2[ \?|w}oc ťǿR(Org=\vO]m >_/7b*;銠aδLlA56G bnkwm8wU.g΍=86 v¢Y.Sg >~8; &jir``\Mb"`^5hyPs`QG-RtN)H\.(i?BhNZʒ䬵@?‹˗f5"qAAvq;pUL!/Y GE;Cr〚DbFLHTiQ4ʄ ,6c/n\' W9vP rX!z@Cm--͔G9IUo<)ʣ~ x{Ű@0%厬( eOv^'psMp`8focTQr +àBUFb!-[e%phso:ZN[65CŽ+ie7;fVY-JVµc:2ϠoyoR+֟nЬ̀s)c \sgK?6~[WygBN, 8yǽxPkmcО+ _Mx'/ͧ~o}K;=oKSt Ho`~}vpoRhm1}:-1 zk-JSu%P1 jД^YC) 4`gа\T,9ιc֒X\iYBpkƮ?Ze\ Ǟxo>9ehnCwVũvZj4f f":½A pœl!ѽ\3clh4#,L}YאּN & vE-$3 ^̄& ųgC,"49[B=Fh, }y"̦Y㵫Ue'4(K( 8+m&1v136/~IcHd(.ܻtܺyf"4$=`etBQ py>q . ~Ny{sZ@G {׶6ZG,`hAד$MEN ЮSf {9PpGZ\;D⯾0>ޟé^uZWE- Ru Å ^kyڍ^|;yEl,~W~~8 8.(Ҽ@t] }m#cXbcE%RyGc"K&δHaoFLqaA*M\ޑ*Uv +=kJ ʙ-r#iy wSwh@B)v/I7q-ܠn\臖_A[+'l-˸r[DJCϖ1WTu1Q@~jP pA&%l7J]E-41uŔKiLY:;W^ˢdZ/+|H=D@l6o5ùF˺ı|CϿT_*O$ah>Ǥb0) c9gꜮAlf/$-~1CWeD$GtOz Y4pi'\:o~@ fԸL9'YIZݚp(>ǟO;\yJeP$tk6/={{vx>M⃿W?_b{ @,T @YÝ lf|塇p1|$xͽC ˆ̌BYNF٤)r3z0 u.-32=}YEpRZԂ!Ŧgrmv酪Ua)5Ta5)D$yxQ I ,` Ɍۺ$sUe'dh"dyձ:-EĄ`Cʡܕe,mfSMx񅫸xݛ"I 9DUd,#훲EgxM^5B577 HL6C%Ih9!^\k}<^ufNȹf+B=ߥZH3nKmZ s\6ψ(È*IhiX@BE4Ps~No{ۄ+/=OU-4)<`qoa >_ye{8~??ѯ $$ Es8@udITFz [8;GlqoD"C%/̵ dXDMۺ_+ϵE [)<93Hd_?RVΑIJMo}ބy$p ARF˖Ԗe'-YJJHn;ݱGwuWR]r%ꮔ]Vw۲ղ-G,ɲ5Xř 1=Zk} HU_{9gַ&hN?VA|>R<=("]KSH'#JL@Z FPc6wK Ri*h]0"iOR,V%> w]rz4'tHՠYE= iE@[$k31yZz|1.J5m 0Mp)vne1Afj\2;%F 9!g$zǐlkFKO BMF+_ Xܩ΢'n9BB/w:,XX&\F03 3*0uR$sـ>yw2X-lG~x{Dr>|?/]-/)ȉ38XY< <ܺU 'C.C4[(=lXLZ/5׾CódqסOQ`5GH-M5Ṓ򷿛|FHE{%@c/"wc1Svs[&܅0v?en=[T;g|5eȬF"jgU{oف.0>x_Dŵ~Ϥ.=[Ђ(xӰ .PU0Z8x|~{8M1 .(Mt0 uk KȔ Kև)O݄FGP=c=)!Q)*<'i,=jtkxd7`=QxAI3ꈊl% p=(Y 1`R4Sǒ+r`EMSxmͻGmCRD'u./ rQﴋR6CW ?~2%Jb8lC^힑#fl;cl(J,T6ߎfqH;kBb LWy<X#,dŃ=qquO}cvF {=F@+00t\dS[Vb.s $ŌJeq sy){pSǪh˙iWK1CovX""%l(g,:rKKXYv=F f1@=ZsT! S)WW<%F tR:g JA[,vʏZ0g @J%P;$=G:fzNr(R0׼ukq*8}'NA9qӴHN^nBsR{SEX L0CQƹʸYSΒ.5[o2Dl4, {Z͌J1hT iL4z7Oal'lZg#bVS$ҨizcAn(-'#,?}ZJY;E>r A 5UbOH.1͚UZ\1t@ %.Kiz]\?{-"]Qar+_;ɭZWC] IPGU,/^҅?Gl[ ߈&;RU1$ꈔ)d|`Fma`;D/wi2O ypU4v^ LJ(5N@>2*Z^)L&z0qxG> >C9Nޒ:Q֩LQFgsʦyv/cӑWgضm'vԁ&)16w3KUΤ! >udU^5f ؃kP:1p|esNx akV VZFi ib`4zۨ4kG#hԓeO`0{%F!d^4Ĝ:{)*3XWENE,G*p -CKt& ɠBIn]UըjsZ&DV*mBG 11jM5@%_&nس њre[VWҟd-շ:w6ֺ mol`@q~kXp\\^K_F:۵g}1oUc8BZw]7A,kL{mhG#6g,p'lM9:6y3 W`0}E-5a]xǽ_Kϵ;^xy \| ϯ3ر lذ6m PZ,(QQ rozXgYGTh:ke r6f%{IG3nA ^iyʱcr̢!2b'5[$)A ]iЬbe<>Gߖ)LM8H6-*[Uts`U]ɘZ!c{Pya*r摨aq/%MhHW*D|TC:J,.]~s''d2*yb;Z4݊$[8>X)$('i\&DtK Gy0_P.w#._<'q xqo'V S"ȁj8pYb <m-[~f6oŎ۰ef,cnvVRV Ja'yb2 -2C*I0B@Cr*=4X&8!j!(JT?ĐE/ fT9!)EG=^]r#BT;z$OC@ A[T1^p؀CX]YAӴKZ ֟(l! 5Lk=4N;7qiЏwrm؀puGFңb.!pmV9f|h2d Lc͘ɲ!rV[Jt @]RFX6QU%zY-.aYRDRhm:"pgǖy^x#8ua _"eX(e |Doh4Q9_::^=v 84/?սͳ}gnߌ2ŷrBqwcphEv*CmA[qEd^<ء;5`2vfs~[7ovbۺMX7?`8;+k%=ްrWƚݑfi^1 : ] < CXEU ,6F+k]S5R:D9xp^]p F#l!m;Cu`cz\:h5wb5ͥ$YYI*u]DFPԻdARE*rppu='^8^?[t+,4g$^(+Y5֝sGn!]CPÑh& pUafCxOρz3py>'pkkaۼ]f`:?}I$R1!iplbNŠ9(Qw8LЭ60^ŋqq3ϣaYԵph>stC]FbJf6+6 A5B ťeJuu@IN/E|e{u r#4?=7 ;s=Qp>Ba0c;ANpWq[8 T G82f8ke.%]ldxɐ¼eD@|Z_\yz=UjJ 'K$ʗQ$ּ,C0NT#9u(@Ew=W^z w]۱yVVQWku?T۶U1>m  Rk醃Tٯ=-f3@ Z00jI+5]PU*j̼ϡ cT]kuVv_r7mqbi`<sx"Ν_rɨwAEjOih.T%D*sk3SࡩV XGkq0cxT7NV+ Qn&"25sYTX@}P$ĶXdF $]* b-K.HYpT}N:* Ĉ;41`WZUO]vA\r]ˣ k ff$oԠ]^F;VSwR(9gd21ő!bmFWM7 9VL5<)^kMxUȪIJ]F0X{UI4y1Ha44 cMi[L4QH޷WdjCĈH *`TZI\\\DIq]Zf҈y9(--;G4CmUHk T=o= cxq?~<  3K"FAG3鰲">7\GP,fR3AݓTr1b*p=v@MPfW^? [iƷk 6E<*f ZͷG̊׀`rg{9*B+-eHqN; *}&hzfT(y+p;B1cMxILY 3"ehE`̲! _+MWsN $*I؉SŤ UrrрZpf_1V*lـ PKeT]Ӣm1(X@HPyĜ\G\sxs@{5j~X&_0{ZxR(NmיX.UJC kc.y@j`i5% XJ&iaZPFfh`iD%ϒq!`& s(9'KhDB1V($F^h(# qTG U5s!UPU%9Mw[kx]]ݑxzhƘ #t.z";p]S:"{=WJ: b*x*'bh".4(FQQ_A"{1=*E΂JTC$XZI )\{ }0W(LևbSÐZ/NsBE: < h_ѕOzկk YrbQgV DS=Fm*-j96*=7ENHCBsQdfS^0%y-\Al@-`ye+熘ٸefmku~Ojq'-9j4&m`4^Yjw"x~pd<>Oc<' ༤,RRpJ-I][O"BKK֖i^B¾Z*W*_,Q=ADHo!g;Nf1yTw40 OL gJV"5dWEiT#U%"Z UU1czh[-s4EO Sؑ6BƃH3tZCωUo3@܇ЂW) wU&BS@$tnt)W;!U}N![6} hb7R,S k*mLW !MGي2qM%tNr5JD]#ނ~Ы}]chȤ i "Y$ghZ'y v@iN-G ,)Ekʅ[SЋJ!Y^ke֘kUJD}pljψ<O@]nuKoMD6KZ؈-7ÏC}{=}܋} Xyi >gs0l@O)6Q,{ǤTt28hAԓrwzRy¼'AQnʺr6 z]6,6Ag:S?SY66SR/c+]"QScyMF7b6X&`9z=*-}.k:qY5\'ia&94W<Y5Bk(!Ӳ"98ȔV^w4:'E=m Wyt,Cacظu_\8'5?"jW,)iυsOe XlD&d@^hA ">Y#3WW 9_9O8XeѤ;NI.DM)]",bZNtNC$?J\<Ҭ O:1OֽR #`M Cl˒h3'܍\$+ ;\$U)T-$y3SJ6/|)/RcȤ™E;*Uf6l:dĕO:8!.3 iNJLg3bmkYg&ۮޥ9-JVCKnh ̛SQO.KL-% vFk) H9BHyTu zpJR#&jVfz:<&M ~*Z#b7}}'3h# B8phdSqO9 ^+eC"(CI##kB$gb,{NiJb }WOSߕ~ 0A+& }yB}i%* #ʫjXҔ׵&IJDZFJbʁvҥe!XEHFKM)JBNbS@25,U,#{4l:> HNLyQzh¯یzҤ*B :udtU;hˁYPi`k9r`唀Di:dªy2j|$ӈǍ;B q cSƔgꭂ@9#r2NYA*uU!C I,H@`rY9~buó7H˳* ɓHai::`8F*Ø,`jm׉fO;r=XۂPr>7JDc}G.wa%W!X݋f Q59 Tv^'.*.ِ9!u$㩭ȊGF1X um3Bh>:tzfp a)oiCR}.!u%+CHG6 Ƚ+9ew^e D`뀨pլC bѓf@8!,v} .$)eRƄچNNJL&BL&:f]_@YK\H<("N ʐ yB~#i6<$zR!+/(8ZC:S|LTIk^M]kydeϡLr?ԫ| \6U&t)b8ʱ 0I-m<3$.uJw=0M L^Bz)f}NďdłX7ˑ6#r͑,PT"KVoTܧ~^fO'=HyO"3VTz#&vb d Of/výi2a*>_Hrv٠f(5c d9#ċd?||rjX# Ɣ3['SҪ̣J84ļVR`,sb2j@UF`Sge ">NJA^ҸRrVEz/9ϛfV3R 1zKcyj@2ȶ`^r-T֝˨n:鱅۠(AXL&Vy5e3xJ@`W2p&scVJyJ< #g{U|OB[rS԰K)yê)j!$ ۮM"egyVLZ5ٹw?=cN59^ z'.\#jOKPPTb|ͣґk`Bhm& J5U1yN-l@Lw@ ;27/)^B[0ZDp:̩u+X}HJ=07;+͐%BĻ"|9)cCiqR~2)7Hh*M +FBv7i2ĜG2ؼk}ņ`ő,.6) Iť$C$tfw$`^(;;5)CSzZDQr J1DAj,y1ft fU*VTNy<kuvR= ׵&Įb\_rɬJr/Q뇌lܾ?/>]tKrXNxGpiy=utNcn>xX78#|)- N;-#=%MM7 )m2&'E5)ĩ L;@(>c#Sa,{,F8X3 |s6Os5j 3/|M%ri16W!gyY!Gk9e/4DNx+)QZ!Y,T c.3a+ɪ3Ta嗋e3 q߃K*Å嘮ű:VtU  JZ!rr)ܚA%zp9v${T @UqVKzf%Q&9S{F _f[i`}\N߬IzL6–%IW0X; 墬+h5i0%{1>}60MzM^ 0% 7,5TP&s9?_.[_}w0~+>Oc,w `O-֫K \eo V\)&GX*Kq"0>T˦CSTCMgNb}Aڐʴ9#QTJڊWY5$_K8&/Mvt-(2j 1_R4eq`:[S#!hF0DW[S $ Pfgi5%uL#I:<=h:bnJe`Z'hQA/} +6D j,.gd?Q0h3v 4ti/Jӧ0SV_S`>5)9#{>0n|A_ɿ 4 #p]/_º-;q׿nn6=z bKz;Ņ𷾂p] *pƽ?5g+xz'Y4%[0u7>lG =ȫ՛o0tLX>0@ $;ƽnDwصe^=v;o  $?zG/1h?{E`X;, qbWe*^ R$ -!?{I?+[ڌv ;˫fCQ ן HYw \K%J'3QJCd:k<7sUؒ$$lhh2k֨J !ɇe6EW2=.m@h:()^Rwy4,[*=9'ix󒚱vU_Pn8n3*+#J'M6ؼ_ܰusCu-8rr+UYlۼuUw#?+kuX?{w#p";137⍗-IO(=޹;ރC/˃qK'+mݥr^r>RFudamc$tUa60oTLԀk@ {J8 4K4W'k8s,z0!F8r  s.&^#stF˓qK#4N5 .ų+20X3Ο{\Z^te,{}v_Q eYru ЍBnF+j!ORJf ZKX c>,^}i| dzO>#oÓ/'w݈<>9g<0;sbv2Hʦ6B?I)-]ލ 0eSi=ѥі& g_PG9F!NsrB!")g/*Z/(o9 ^Feں=SOi0 N$mR~2R2m€A5u* Ey\Q>쐒]3=T"uؼyF%LU{-/{}]s7oO% C#r ]G>|@F[ToHkn6J`ӳq5z֠hXxgHG DM>X3!eu*źSZT o\5/~zM.S0-kڽ'cs2$SR݅?gZD e^#*g*}kq2 UhbDckr>k@J:wg<;' s/z^y~{ׯk/3oT 4sؼy+N8/=+@vy-8y M[p"8(T 0nnGy);ls}`W+kO"NVwb sn>;nN;$#K cow qO~UgY{>hABX(A Isqef9x3scfwyzνw 8:ւ!SR>?w ZNp,uSј*/K ~I2d%뀜 ]zX^aKbSxn:.B{,5R$o{>{oB};p|GG"?o| 7O.م'9l{?>3ܰOv'='> o/B;7̓A8=whO|3x}3ˏjezSæ֚0V|2fڈZA@dֳԯ=|?uuO-9FY%zC*TrVXer̯߄JgN:F?pCI 1^pLϡ QOݔPF4vkw;\HH5*PhK9y j/ķ lZ#>I_eY F kDÿ#QZX;զP% 6pE.+F #k WRy5jMiY; ңM*i0RI(6:@@!ce{VeFJ- Yp ~@WOT!A|ACڝ>&3kgop@o;=yEvNtQ xK}6}{߉84Foųwއ~60jG8pu۽Xm%svtTa~nN2cӺYrx;Ɲ–?GS!nw`f/=I/V Ǿ̈a\bh2g66+p (z7bTڝm<.r{5\t/`2^}qth'/n~W_xy| Ө(hD `W+yU񳪴ٗASO/eg6 y=)ܚAϰЭϒѝ} Kq7ꅓ2i(N6`pc T=H|Ō+I) Y@*kksTh+W֬Zp<<gvL^YcO8yqGyMCcƦFM?T}sҽ>!ѿ]~+SF9_f(=g0g `Yѭ]{uy-ڥ3 e h.0[?8 '̨@JP?0W}zL1Åa^Ϭ/5@X;9%}ʅ1"U?DpĨIENDB`CPU-X-3.2.4/data/icons/CPU-X_48x48.png000066400000000000000000000112461341671471500166360ustar00rootroot00000000000000PNG  IHDR00WgAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>IDAThmilu#)R$%R$ka&ۍRM IE7mQ T h4HRK.P6j; ymmd˒%.z\߾{&ޛ7sY9#>7V>B`c~F0 ھ '} &|Gu\9w<#x_+.@P~v cbE]B7!Ʉ׵7 & r2\FV+Q]YZ5LѓUnnzV(RdR DZ<k{1VqC@f }F8v;`,XZ6z\ :|O^osB #QB0ƄH06!bѵĽ Jkk5>J)@XpWBaxO>0"qRƶ kEL((t#\ϪӋ{n}{<ɹ7-LoSL7>^*E&"˞ Ժg8CB 5ƀc)V*v{}o秬?u,"288H'hZ#nnx"DUGܽv_"#w5q dV4u҉L'wc JvYTX][l&"QvF5:RZ+F[C+`b)1:J"F0E@JAayu/p\}O}-[FLEc@v}\~T@nOBM)0c".<1 0H X[_\^ȑ#,--̙3}R=(!Uq"Vz tx$rFț M&[!^rp'|Vk;3SO=ū,Fv"/2o~z`$-jlAie(DcBr2 a*/."͑VxnZUӔe֌cr+++\puh , WEP"+ oQMWkuA}y{du+10afrqq*5HTC+× .#](CwmT]{}Uܶ#lL2R `!,E/Z30&$KEU#19/3Wv<7-i6Z#M: MQѴڦ[tm` dkcc& 0:ӻn02q֛ T\84Cfy7 ӌ(5JdK.YGe=w@j0~*t:Wh37d]۶tp1m{81(bU}1`D/+,b#PV8qvwh|goTVv;_c$Sh뺼/l,g,Sawf*T H(У cdLT}8{syQ:TORkغ;ap~t:>|hl&iPFLU$bЍ^6q6H2."A1j*ϿCCC޽fEsAra>vc3FKgۯ֫=LED_g~~/}Kl޼t:M6X,OP'e̠O N#R 9q$Cfc)p] Vq9smb^eckNB`q{> -g)^ezzm۶m69ua.T CCCe7opuf6RT<݈ "\3!pbv_vNׯ_x ~c})%zZFf}}u:렕5I2Hnu&!mndɼ>T b܃yZk|ߏsU.Nf xRqYKN2\kߦ5Uׄ$4&hnT74 fA@ۥ^o^N\.OtǑq&A$rtG*#EA{XzAF -[=-|>2NwBAtVkj lvaz¯h*X?C҈|I?BkDr ֖p a1 wKn-YzIRLOOJ Q/Lh:eI>'<0Ɲ>x%*^ *4QaEq,eI_:dh2QA/iQ%99Ao޽+<eϾw܁TH`aawgekWJ{"ТJ|dH& i{€Β䀏!\eUd :3r|[ɉ'T*4M* rΝ;U &(-6Al,cMw'lq  mGJVQ<#<:+J<@MM`!apۋ~ߍt:nݒbЍd!,9Y~ŲWzdN(Q18w*XBKlMIy>!h;d;33yK}} ^DpJ"0:lz@cϽD4i0`9Y۾@ZˈVN7WI:H KYS|d3va(ӦS?߁/NΎbl66*KLAΤٱkBȰ`@룍u=<_K{5 pB߷Trk\¿?|-K}sp>^?y AhKHGz@i2q׽w4!9֤Z/D8^.g(zaw/<^| ?1)oP;9RyZ۴j[lD GƮo:MFq=l ٦2?C; :&ݴ?kAkLtm |G'V3 W1N`a(HG`2%2alk{Xh:t}vL0mwPo :y|'k9;IۏR&vjQ xAf*@z@&\L4nεG#\Xsv2[bMvMaiyNJb!7qGxp{y;|2N!*aREڝ5?]%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_512x512.png000066400000000000000000010444311341671471500167710ustar00rootroot00000000000000PNG  IHDRxgAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>IDATxeu'}/"2+ b#4WMv ^fg>dL&}ؚjzzC wAXHľwч}/PQ%# {?q^O: m(}>ϒ\[~$(Ѹym(<|r_9}Z;3a}E "~@{0)ץƁpL$Gjc`PHnyqS:CsH黽T8<߁ϩlEx5 }vό/gyCry;d}hO\?蟺s|Rг3|/y.!{DEhc>01A},f_qND sFo._IKY*!Rq6eݣsYqutAtmp'C5P|13>ݟ~"_zڄww|WxhAGt0 !,&[L0M(MW7Ͷm^vdn{%E/)M^DyM3Hdy\du]_y<(&fzj< tfk Hs6bcVǛѡrw۱!޲"oe}zGm{ȾR:(al7NB#~zў;zY'{FNf@XO}| ȅ@ Fp,|[+g?Gw]d3*Vc{Ck>_g|IWϖNC6^PJ|,Hyl3LIz[Qoz{øݳӰ:7D6 yM~H>=!gnozVNn͆`<PFrEgב _FbZm=:,qH댕<Бu\*EQrvH d=$hdp)b!=L)T#W`Po[/w/#%\ʸ|ʳ?>,*bۚ 9@ -D?Jꈁ~gdpo RQ#^v@_ꐎ r#p_IQ}^+;y85^M_]]sg&~hVxMB~d ysERwև͵UƆMg\`ͦ@d4 l cO!  3ҵ6$xrx]p,ylWS)Fkp:,N -w^ϰQۏr1U3xP ӮbX畧p"PdtsXy5FȐèEpyBD7Sӱa90szC/[T=.s 3֯T̨56 9l.}IM4cȆ;-B T'wS(`^yrRVJym.K]GnɈ2lJf3gEi8yx{gP})P~~Yy.ݳFm|>c[).>fɱZc;޳nנkcr$LeF!;w64ee[Zn >SjғƖ~<6uIs(-?=G|Mֹ_Ɠ悀YI#<ܡyy>wpóSuy`*ExnY|OObp\yI|f3g_n  c )5^HFЫLLfR@.ͻS-J nM>i4T"p%φ2Gm p6= yzs.EʣGz0=,BTeA>}q< {9ll$ye3yo2y̆~_KW|X绍cM0>Nx| Csw ϼc Vrɟ?Mͱݎei[ĕ@rHjFB~4|E@6'\Lc~󿌫sc|_}_~5݅y LJsΫ)JD bdAAuRNes v[x]dw n2{ *C I_B1g#KuDBl?J~75n{\OA歷 FKFwPL,7[ .dHt ` 8qanԘڌw 溩%'0UoIk.S'fUM![7 @)+4]ÞCf9Jr ͉2 Ncy3 j\a)_сB*aYeO홈TaT&s}8?_6ݣZ߿& ͩ9oe((Cp&m:M=k}:2'}r0u2ەӖ:D D%Dc$γ%󠺙pr~̧> l5zTw>Q<| O=܅[ ZN6?{85y ][{AWj'?1֗pgoA>\u!`AA殃iU%3d*4/ Ԙd$ .I;.!&䊺#OB"*!(7=CA=[ Pϲ !Нe &*pcnFyy {P~/Rp$AkP|4^w`Y['M#s|6ke =o3 &dYI|p,cYd33(9Xk+u2F3wd h^;N+Bha{öpLi~| Isb b|_9pPsd}և;@ZCߢldNs6jN>V&OݗQ`7qs6.M%u$q{߰ŝ лNg3$;-sقOpΜprz~ se\FZ[ޚS')*AHЩ-56u}!7#묎;ue6UOqcxs]q d)P=)*@uBP@=QILAPҵ##*Ux7D@WO{:> ?oq3(c<݊<~ Qt-/O`p¼ :LsHukWN}%ϿEC!#VGq.81nѥ JbQ`yn{)'%7"FO?xY=.y)H ,r~:9y=w&y^IA-"fdS'L>C>4"4ţkq$UN# DS]шLHb1-R5ák@ Iv~p8͡61ɝS~ǘm9e$EA;8NMR>Y!w|\+'>~c t$ƒI`0̺di5ff<\*7(;u4DP";c38')o aƝ7uN2i<؜3@F KٔDF 5ndZ:-P 䰥\̋Ye2Abs Vt!tt_ĵKBǟ__W,g7~?-}2v?yQwמն I8,)bpTpC2p2jB! 3P ^s ]|xOAjc.в\i3 v!+ZF#6%WH>yF8d n5QQ0g z`#*G:c(}d<20$=e>xWJeVj;vH8C )e,h"%EO9}E9]0dt9 X4sfi~6;VpǸ#fhUʊ0)3>|w=3@@̕JiN8aVG'6 3B_r==0TQp 6@=>No O8y[&I}T90#)NLcG<8NS$?y3#r 'MϘosGQg̕{C0sfBփ447ŀv@ "ӻF"ZLS**)OS& ^7!k_!뙧߽zN m޳ { ]yT\rӆ9aKYi Xz721X2os齬,?&CCMGj5!e#ycM2Lv 3y&siQj7(_3ƎήR*4Pm-kjLX Pokd O ʟw] M(4L3o8_'7*},l]wȜC ' .hrtgcJD{vrSRO^MgGSwLjKPG;61bcaѺdRrxrĕ#'`zWZq ]rh*A#kyixsgC/2!N947 X6}?scO+XZt=s!{c1Rr̾P"n=SΤqX)囮SoNppJg RpYHG辱25o8cs:+~ B&lEF\|GPsY? !U:Ԅj0xeLϒX f'Y1<2|7Nw|w)˂^9܅ҁEצ1^|%pcz ZH>D+QN9&d ⚶1ʊ z;Zi.Zz묽e*h[K_{{Q Ѥ )HA~O:#; ]B2Bg%*c&bwRsGؔN{*gS[ Ǔ4n 쯾E/+_s<+[tfly */~ wï jx lY#]J.YMP(}k{; br*'<=rag503:Kx{p{?OI*? X~-da26xRY17dt}8AS#dDO{E Q(g=MD=y)` P"h%Bj *١!NA|VJjM>kQy5*AHLmМʏ䒲W8rd*73Msbh5vQ^HR䫪ZE:;v^)!9e?OvxIP-厶W P3E [\Z}/z*dd74l}3+F#5WVؕXXܸEOunPceuooɴ.Z\$9l UV|ĸnּPܿ#˱w$kHf_f4es&Q;r|@V,=Bɳ^"8 :7{U[6VX9Ǡk 17-<(c7% ʝ1(3GwPhN!qrw> 9T8hI,e&MFxu?\8 tA̤`qSxx׵{07QXf7gP37n?^l$g8"NQb| 쩤- eϒBr̿M~> ݣA[Ԁv4LbRtlh[c8u\ATR62gU/ P {4NO7d.[B;F9`bBd%Jج.;{B"ұ&hM*"\ԉϔbѤ<7N-K=B!C0:Jih{* zs;:{VrdX-zMDPai[bV9hX ٩uso*pqTMpg.ݝ90?}k[%jk;iIMefp58_Ȍ)ra8Ù;c%+w&;<4މr{8= a76ɧӵpp~YDDҩCS30cCEH86k/TP՘ ,/> 8BjxY@N1gL,]nIU>0uhYDdIE6EQeF 9S $/ty+,Nxq,SHx9 Do Jp8͐*@:|&Xi(ٲx˞݌Z#R !bF-NOdŎ5G P`f UlbAO*H[w+-}[88/ 0etH{zQpW4@BL7zFM[osL$8-9 Vd΂=fR o,={ǧ g2[pFzPCofըpKR Z4Og I`QBPϾ x~ُ/ONց|[?}/m{E FV7tOPއ2[]O s!x&& 1hޡFmf0gF0ʚ"o~".Fq!^AR%{!L^Qn*z+zGeB#EQ|ne:384b40PE[.ԦCDx4Z9AKg2PЊEMDw:; ,P)C ՘;ekz)q" %ϧPOd"4R>*Qf9rY0Um2/; 9Xc١ΪS))3 7Pާ0gA8ʵ5M,((jWt UԣS:BHꈡITT7qΊ`k[ݐ N? wCr:H--z{Z4lHƽGU!^\P:iR'Ś.LHS]#Z5J:' Rv#m&pJ>g ^:41u|; 8EbP{Cn 7&~I<q:㹧q2m<0B* Li MWQ1̭B7MlQ+6WpK^x|f9.shnS-*Ӂ9ޠDL`[I+M醯Cϰ3z_hz׊yp6:ʪBL":"6Eo +""bUAf_ip~,+@Ƕ}J%{VII$ؑ1hJŸ2?@Ru>FG)oJo==Wp61:) k1o҂ 4vtM8LA22kHf Gbu̹>NaAxHzo1WW`>5ٰ6< s~[cN/SwDI ]3t3M" B!֝ogtHZs/kR0vbk ؖ컌8"^k=FF▄P'FLK 5~ AHV%gub.0 00VBq=+vX^׿R7nbot>WEKI5V"B6 Z*YZ+@$jLzr)%?0 r˼C "m%["OAמϯչ)Mz )2$1¿qY@-h&r[kAa͊]: 1wber:o)۞S94?B#OND7'xT@5̨,ˌyQ VyW˼,n7-6T K9*MAuEpI )jXįmmN/oʹ:D-#PFdN˫㠠UO$:F+7ӷY!%;N?^YMmA9}V6S\jCNߎIU%lдEР&>Y@C ƲFPRԈWzWx\^D.9BWCv9-Xv hn'/PJ4UxW@q.K)ZZ#J9*g * 0P\KBz1f}i f5*Gк8'uиn7XgRHԨW:MU Ue!Q^F3@BnsT0Ek`Qn"56g4 N +-iA ")Kh_J a>[t5Ukw,l gmhJ  h?*,u D=ME 5LNeӹ:E^#N,RPJ@Yʮ'ř6$*^uCC~{;w<G ! )Sɸwmϫf-R 7Q8+oZkNlM7|'X94Ys4H<49XjNmJӵ̑(TAH0TJWI8wBB#0l.mrȓr!Y1")]0)-rҹ' "a"$XT:6nXZқ i7ascBRЕx)$dh>clpzHY-գ>+OvtntYh,ls ()*V_RkM0 w}&MucY51#?YO^q2@Lm%_7BnDKJXh:TUBm{nka-QZ+۟5}+J!#Umg@);Qh;(>#s٘.%M +kBKI퍆s#L :Z_8_zQ!j}Pc2+WTv1rZ§h57qL /]u"#:f J<.s|?` ̅_o0UNܕiu<~ӢMWspܼM)o_,L-YKg+II0^i$η^s^4nrOWZ_O)ayy˧řHanP:i͔DҖb%JJcL((ܱS-`nM[+:(#*K+g}{[hK#Mi4VUiR(L5`j|kڤM@-@AR7gc:+j0 KXT(̠!GDªHu|MUR9٠^K }ayZk|To͹s[Ց(&,ʃLJXzӒĪUQy pj&iPA'LfHxJYF!@VZ8WsB l6p[h],&!Ʃc8,.y-7G+Su^*8lx}.1^=2Ct)`):uljՊִȲJ\7+YdmY0 tXz?8B:*yW ɺjݽw(M*68HS-l\ otu#'Տ'=FTpI٤=LW%Ɂ 玨4fnSƼ' Li¶lkE:6t '0U1bxVQlp&tcQtc*آޅm hMDмY5\KA-Rڤ2Qz[й\vVF$北X|YPkA&^59BXv %VKِri+XSXU/֩b^`&u[0Zf ]w-]UgBХI/(eS::KȢq[Dii`Yf8&+I؜PTf,mQC 0{n7ƭ3qf-P&p)qTؐ"L*Z7XdSA0/ YnQ,MCSAn:rл}BɳXP}-Ұp?jUݣiH㻔RE HUTh e@{ދx ǗQV ZiDe`Bh>èSAGGMqu SMjң0qIs4Uq8grt7`eW!u9;QfۏDՅ`0żcۏȜ=!XũXѢ:wdJKkD0: \z^~ML= 5N$#jUoceڛb ziq3f+r%ShjlM zttd͌eA83LG⼕:(ϠP-_=L7sνcN"IS u`K! ,uCjeڱttuԙ⥢𳤵D-АkZPѭ-p#T1\+]P9fvNNЖYѨE2 7jn̗ށ9*5*`,$2nVHYk y]QܺN~k)9"ZA8Р0EXX̂2] ハ;38c/Oy9<o2c B;JREfÉ~ܐ$a=u#mѕU$ͬ/@*cb@JNFv!|~2fDYbh{ `xa$dPHjIITQ“"BP0Z^vHtdRFYd`(GK|wW>|ɏGޏKWUи`;Nw <ļWd֔Rb+Yrh/}痊j:ƺHmьa 2 W%DY%=bLYwHf9Z!uՈ{7D 6)Lc4+iVN[!vhS# 7AjՈNV JIKD8]Ј5^WЊBut:'GD[e֪XKWCe6)R ,mV[9vBLDM+Rq Bcȸk<*Q> 91+5%YI-*X#bPTfG:\Qr[Vh+2.&drMzE/ ܕqE/Zul,]hSf=U4EQ6)s^O͂e}w݋G8n|x/Ͼ/Yp׺]0}5 p(4g=irP9"ӛn9ه FSv;T0`D:@!k\f|1rG9`j)K0: N@869w@Q94ׯc﹄g?Yҕ{iBe` w;,K|~n ZcrAMu mc5pKUR>wB 1G/ |^8 ukm!x"pT'?8OU%AzinZ2KQn1#'G 9eQpՅ-PI@O,*LkMxEEP!mbkj]䩨ȝ)HM֚T L Ukor&9pˢ -` ڍtEo˼ت񪠮rܡ@\=)ygDii ƙ̩̄&Tb.rU;%I?s/©LV]v(24/;}~;W*@ 6o%TnnRޮ{IQD:^ Rp3:<=P|~S]Mو:fd eEr\49_!ʹ"?nïﮛštbu)Kof5 Fc/3K+ }X)EDL¸ve>x>_tt Wv;Dza7cXVeʅed妅e9'0{:ʜK\wH3 ɮ>YZ3>xּzC2gyqK\ZuRWȚv ޵sl_F!J({ks${KAϠMb",讎B)UT=cX*Ğj[ؒe`;ϵ(C򎍱(Za%L" a/KSd<,N1 I:MA$SYF8 |u"hjpm=3ca{5yE!.8)QMA4E qsA$ :$RcjN #+Aue6w9ɗpttT`QnDaoc*Q8 VN}9TVMѐ͙^ޡq&hꆓ 1vbEɒ}Q x噌˸zϽx{S>?:܌S/Jі*òd7Rt}b'܄([&ѿ${Kdͤd9EM#JT@cRM^M)=07Y"'AޏI[`QVPӝ.~|wM6B9as;i8mti1I0x] 3qs[=֒iyH;%EZFޤv߻)ô l.l֦* `D*eQ( [BZ(kdcyx7b| u^ vQtӫYr?:hu4BkHTK(sTO)5^&yŸhv_&E&0iz? $5&͟Bf` 2B[x 2P&,Ћ(i+6  ڐQ#Q?CTpIA$:SzI r&OMKGEo :ًH3V!SwY֒S+:Mu[jP3KW^$"}`4N :C^(B"#Jt$>TnWҴ]='umG݈482JWq|2y^zl{tw*DNndCbȒ5Z4(/d.}]P'm??&c¸žX˙\RC4f-iX ŃFKm96MTBdH X%qg'#,&<8{'FBb<7&،MgAt\gO??Q\t٧gg8wa7J 1l&aVDf  7lX6`f6YEN4>99W [͢4| ]ÞeY{x c=ټdE״Rs0v|a՟=/l,ޚ7CvImaɿg˥hyyw|jF;?KlY롵yb3!tY=1[6xyx0*Ln+-LRHP+mm(4ai3q?1A Wz!؍CX_i㬿d@P@r59bF rʩ`F- 2.rxCo./|/g.L3@Yn2ONn2x<3Nt/E'G'N/ -İ@–kz>r> /-JL6:k),MM?FC7.(Ao~/]tr <qnݺ% `^v$p\ptx{! )8d_Oɑ6/kpΟ dqRx x ]cF7+lz߳2͑)W~54=drV2vfNh,O*OrĜkC lLNJTnXj}/}q~M־޿ !!ƞkV8%£h-*r^}l{zltCZޑpǜ2 Ȣ`N9B,%z{N.agxWH`Wy8@M K@jkj*bĞ>!g"-WO\6QuE^> pR$@і4]ˡAHP8[ a?tnOz???)\zG'pq덛ΰ eJ242֣BCPFcs(rx sk4d']>lH`\g6~vS"fEcϹ6\h\#)備Sٰ1ItBT0my14_=PrşcFDrvBݼj"& tKA=䙭n1}V}?LγtGl&klA䪈MN!t%;9ƙd\疒K1F_)bjm~ HG[P[+l@m=~ Rj)21/mvF,^g(9U en gEtZV@ȜM9㋂À@dN"uMc)BGO}/"7og_k Դ-#7Q<ʳ6x΄&Q&X#{NQ^FFdx|/ ,UsͱN"2ceE$̑.hT7~m8g7{p=(ӄyv R8RƱfcnF:G.+(¦L͠v%Tr/>OV g08uER®S(1P;x@D㳅W=iBH6ICquf(+` QRR=FcvTb߰;@:30MtHFRLaYpBl>R*6vБrOj%Pjak[<: Q.sZ!-]?EƽHCc.XiI4yvt#dl 2>9an+< 2-U:km[J \l7!'͞ȧ}F6MuY x8`< uRdKAQ#`Yو-jtp_g(|vJ}J0ȅ%}`̔gϏ&3{So$4CR\,*I0ppsO_GxWp~6c^wpc6\#ֹ5 l2ljzS+˟%yKh,5­Д m_pTX"]P\E1wVeHׇ"K1 y6w\"R5j#7-ZlN1эlԤ>ޜѱF=6P̮HsܬZ7}rfsBZ:`ð>_0Gz>s匴KA>IV.zlr`r~CFMޱl|Er^Hk뿰Sf <Uh8\_A{2y36hƸOn}+ ,a::Z'?O g@;",ְmhpc? w}QBw ${DG!zdźy+~Sg.~~z}؞\ŭSܼtjδF<3M)BO޼֜_,(@t';!(yO0Ǯm *{KJÿfBԚ,ؽ=3ZTFE6׆#?u ,omᨔ秱:acrg8|xzc kdBV!/Y&u]?5!CʩC 2M֎C5pR_(!_++G늄5P:$ڙ>6{Ґq4K%<8; ɣtqPgή9/]WEؿtH'iR1lc lq}#C¿W=E̠z?m^ @PU/}%qᘝFdEVkɀ 2V3v}+?֎I E088#ޗya\ g~waZ13i# `i *ldhςXRhLD`e#5(/%!A4ϙfgf8kGXpgוV9`fa f[ M%-b?3])fDr-C/݀(m~|5t>Zg=3Qt;Y2{村'3bznȎ@~|OoKv6)eFR  ɜ $*=::Ƭ92r##!4$5gz3;z!6'\ʺދ]O-a)3ca9;0m=CGP +,iDޥp4U-#gDԷwHba6%|@(UC |뤙KzvC(rR\?ٞ (Z.i,SyS&"f>4MŔ/O S˲`c-&YRpS;YfY+.uV~^p&Y*b^&iK,qn)r@W!A>*,]-RuD&._x9j>\?k)LCqˣfTjKHCnwT(@ꤥl@s|ֿ `n3찙# rqA?kB<TlVPlnkڿ0ICq;o8~qzvNoLγ׃_򆍓5 c>̢uQ=G;JՔ{lg}>^^GrNȮ#(3s'^z?u8lF{[T`utژBsp4l1N!l<mn{zbSRkcoϳ66V1B?@hQkG쮣!zH$ay7F>F㝝5`!΀9ǗǐA|Y7~/ 1#-{sv,k`M\zShzwɍs39q~CFvA0TŜQ媗k{lDG`&6C}-{`NnI[NN5sY qrTN)J㜬;Dϗ2-Ek3&qH5ߛAc{/?,E-|by2C#a%Vh7Yӿs sB?ja@Ha$ ]{&LËr@ 4КɣsƓ){q, 8u3cYY\9M:EyC0:~'T?gv$kdPFDċ4Dݙ:%Rg^)FkA&v$foWQj H}gn? ) 1H BN w@* R՚~}9!<$ysd׮NP_>c9-ysdP݊2'GQ0awm W,MR !bw8+4gt5*Qvj*2ӣS#2c`՘_Q>n?NrLS k acW 4kàlݩꙐ'cf?1Ok' 1mA^, |=rB~[/PF)FH K6bP\(#TĝYS(1#X`%W=0 <Z6osN]ÐgOxrȜ<@U."b(Ewq3XZ*z:c%EJ,!0 mF&GbhK~q} LutE - #Ã@%RKJ|,AcV^7O[9nws:=żۉ1Qؿkb 06ŰRsnss"}Ox(>L)G/~.#[snMm!Q!c7rz޾;;V3nsFZ q>G5HH?}%lZ*8iy %N:>*>T<ᑯ[4C%EqaқW$ 3:72thKZh+{B&G9?FFgHL.`::>!~c{UM:H9rhz֠9!k1KpbAj߄n]LQ'":jarDazI KP_4o 62vXqvve`l̢z1J2Ύ^х|Z*6-ZX D|Qd(L9=ʫ6eUVaoXsX"M#: cF0ߥTѼB}#͂FL͠&s܍{E w׮],HHPʙ>"1JCm6Lj9y[0yk){f%,[;(\SZWoФ΃@ }#]0+s2 Z734ccm]sːlN,J#)[- "]i6%.w hu(hZ\&Ś(¼:N[SUҥhnJġZfwݰ֦k6AʕCFDqtt䁔9]IǺuzKG} N&eWwhlKCӬ[c.| " @g4 ),Wn2 _81̻[]4Ҳ 5LInY?mxD^prrk׮;vk=m ɝHXׇ:{vX]1w@(VƷ 4B&w8أxy 1hzȮk9vuNӿl}):[;q: bS*f 2ܢ9{jatS+sZ[z)U2@St'@"aߚjߚRvRs3CAk]}t0Ͱ\,aN (2eP7BDmM!lO^ zČ`@tME_%!bvC5[uO!(MϑΤXDa@3Rasz*"˨!#~H# _#ЈxW~=ql 7l*ë4UFAWn'\wĻ??Fe@y@)߾s.y (`9BhT `8do#pVI$%j/S0h"̬7b #ۑZ>O4 e}YЖ \&ًZ%u {C%94+v:>zq!txb*GH_#C|~ikX$Jr1} )4Nbs$#.g>؝CꏝsTw5у_,Z}z ̖kiKm޼{[ͰaDZ;GՍN\Íq27Hntc?ں}T]6}&a;,<6rYP'!G*@ڀY䞹h̘Qﰮ+_ gd̈]_=5_ohddt];{h2 #G#ƼE3G4x;; 9X"w' RPy´=1~7o_NQr->V]H#{X : `w[G#\u1 _dlSS@z沟 GUm'_zCk 53JD"yYt*ǡ86Db}5\~T8Uωd'hgF<^Ӣ_=4Z]הط߃?`&^y=0;+%s)UqR&bmGmކԇ)Vc5T'1q5]f&GP .ŝ;UCɣSBIѬ&[*i9"g{EY3{fnh暫: bFCs'X2BM0׻P\@0y+6}=e 6)URo'FY߫UJ4QwUIqv\Ŏ Re=g9By)>"[g?#C/1υ69 G ^B/"/'?mn(er`#բwOY1J6-J~ >"~g?A3_ Qȇ!Ī+LG@`8նV:Ѣ겼& _uV] [nd4pxzޑzNO}/1uu#/$s:;AƤ0('lGi>ΉjLň K++{sx?AyT[HzzBfM:1n!̱pp$@$H#LCD.ʧF'N5Dz % rOЩPܩ-ۂ)97֒%j/*QT'wF)|ѼUW^ĐtdE dj_G}1)˯G&wϚ9GT}Pc*ș8"GP Z74$Or<|=5caiSj|>c_gOу ("&C}Վh荙`Z89W8=<E6TńL& P׎"69PAy+[z] 06 z]1,T$.G~j(\a+7xXZ<Ϙ2{ʬ׺]8 @*\kƚ4Dڛ~CF"=G= oDcۍB6LIe92Li.d< m1@ 1.E9ja=ޝi}AbӚxJɡ| h Q2S\s}C9ZbmhosfkЫ#7"-pa+B '*:@c'ϑYɘx0,HA<1i@}ٗ؜(%p<掂3|mo{\CUqĄ!}! GP$憡WDA^. Dd{eY] g5HiN$(ϳ S=-!FJA8<-؁R+Jp||;^y\ ]<-{Z NLgҸCW8W]/xx/_|n3hS~kkQ0~ EDEф es)K[⮷0 0m+Ԙk1d)Y>j2~t|vjy XJDΒφx}N)ɜ\Ƶ{eޣP^yȞH3?C>udAҽ?y`5D1KXCW)O壪c m0qԋoI#-T[j95ej Eh"`}5( luqewFJ?4)ZNƱ5H w40ȜCg6pZ Q~)"6֛W_IMl _К4 j}ANbKַ~"2,.%N _\Aܱ4vŋ/?ėY޵@EQj94lA}9OzE+x<6oeqJNdJ]`x]csg@!jɇ6xC@ eN5ϧee%"}fի(Zպif|n$[a7)5kd`[%ǔysq. 58lil"=™]Na=k.ڠ1ɣFALsdS*"LyNJQ@FCV"W mtMakJ޴EG!YGɢ@9]תN뙉?wrNW )s-kX#,91]x*$>Ȅ(4# x:E#GyʼfٽQŽ#"TJbQ7SCl 8Y`;moQaZ>!Ieu{Jr\&)9 cgt˜eYP$CϚnOHG#Υ-5&jDKnRd{l*Zm3 />r mp DTG?9m6[3cܺy_xC?+OeW#I5k.DýCi #&; P@6 Yrs܏v/Ap_ж(W䶺:@D9m:/;u#n-N be':9.y 3e8!4ŠE]U~f.pD~ iziȺH}>\>ewܙM\DJ;H;bQq*T('q{ꖐ9hhNg"[!u4'%^ꬍfс4^~:"kKqCŜ%Lp2q^%dBxNSucQ NJ\X>*Uyti?l^Je/<,}al6,it+kIuZ($Gwn,G>4]wKϿ ! hOv;9C"@";ATrucGRuDڶОo"Ƣdw\ <nӘ.ݍe7c9TrV~6$r(m] P=@wp5 "^9 e•VȡR6Op"0&Kjru :AځJ %Z";E l.QF~NEDB dvS"[3=xS0! 3ã Z&N9y`5df ̮xMxCmYǷ4/ 78*kiGfI=(j5DnN`oO驌^5Bx w[-&lk7ibC "$%EGϟ|@6lF@'' *Ct~cMyHKB%Ӝ grz90y1d!H3=%v;:2k*[wMy3gV۝Kc)PP,mFo"۝7^ýo~!LK75pdV~Yo S#l.[/Z[G+Fu0&6uD$bk8.rg\I/޿[zټ5Ϲ ZZd=6 nIZ'I~&]W 'Ayj*d2nё֛|H)ʘbnz"/޴)Pm Iv7z$lyIw_0s1(L9c?R4ĞYжoهd͔ccn<ZQ˧s~^ZЛ5:CH])96BlH̙5T{Ģ+'ܚxAzs1x zj]ˢ並ƥ&2߶@AӤNEsk/ę^қ|AAPɩ!9]+BHS`iݏ59AuunI97)#'s:1=d~-9q-N"Sp1=$OMu8d,-!'+@JL!.@q|øS/uT̈́6T}ziݲSnI9\V08P5q8O.]8;;{^LWNbKk?G 7V8^6:fcF<‘/G2~BxW7F?[З' 'Qmfk!,Ԏi#N QلSk*Z u`e𶵥;_|%)T3% e{1k0,[W3?c->]{Q.qSĬqe( -,yU…?Ӻ ?0b핤iDIw%y&И룆Dsϸ^;-Tg >%=J}|DUȧCN! yjh:iƯ0c14,J[GcDN.Q_=9D~1cw]"iNH'+ɢhMr]T=OƜ]t7y^ё6gUh$ڝ(Ʈ,j_{v{6`<|L\o<%acW#f [%>haWFB"2yUhi<gA5B|$2WHrgMtt);O@PQ{d=yp)kY̘.ysJB2&x9=FZZLwX 0ǢT5}?寽BڮJsd7ychVbѼјn@g.`=WFrǪѱD{WJآMNls󱚒^)rIYМz UyIFgud}4@dίAwAYI&1($S?* :ju1]Y˼t0l6$!@\Cq6MXK7pϽW 70n@0\d:(=p/_7^~%ou}~%HYVfRn4^}U=v|ifQdUGP遼rrg%6M>8t`cvN[q[{.35oi(idd0x|LDyīiHٱѣAa@\ fy>ǭ%w-bMQ#ӈ(K>;8)_>Yu,rgN'pY{V"j tG{;*rPRS$(̎U<&t4˟c!>Rc1|-̜[3$bK3# iuMF[ʎh]GZ}3r/ )bH)i9)*zgTou*{F[G)_kD@>Zl$u[6hAwUN= ɮ@F#8;3ԅ[kY,\ΥIQOI%WS y'N"c+JPi%NzI-l n_QFdJU>*`LpISWe$`ۂm}<-d`W$sl堩lJ Ca#~,ÿк=k?̈2(!D6!RI-P!,&D? +@@w("A~=;&޾\7\IvYg2Z UEaykYX5S.UꎂGHXS'[c~cZ#VI#Irf2_HPTk0,gb#AIxH ((]+i^AǢ\gk8Ü{ںD* C7yy8LA^t FuB#s1mN ]3֙D1ΪiM 8:iw4Faލ嗧:Nm?_XhS#@D`~[7'_CD}c)ow.߉j!*o֬R*621U/hcq*~F;P'+ciFIi5NY~&~X6ISlrpD N3JHs^ԵԪi qP38ýySDHQ->\XXHŁgT:aF>!%6r*;d3fW `dCX\nk{ ) rf&#S}?IβϤ n4ؚ\MLh H@FG!U E)ngi^ئ2ýI7%yǛnࠊY"I U("%|’@mk^A2x=1Jܺ2H[ 97C=yE2dƀ!r!J2lNEiJ9əqSžv"cw,u4d`nGFm)()TQQ.쭤%ub j6y`cV j0k@!f;=GF61rmy܈ T'|W+qB, S2(kuJ\淪0j%"ކ69I n|1jX0BF B#h0du+WO3k r&Z=5߹m :G3p@w%re֍.tAAA/ maQ !*gw5]йyv-f % ö,ZN)P:q9 F#prmߤX$b,Z=R@QFyM)&"Uu}cBZ'qԸ:N @3j`Up2[4>BIBv*uĩ Q:F`c/_ߏ<18}R4UhRw&ڇSb*g*DZêO2HzhO:N9wWX]Fru Zsׄ]^X '/5u(e2Y/EUlivf30%.y-](i9 \u/DϼR+HOl]퉄Sk1O,`= qHD&^E154*+ydtL1lR0O Ƹ1*5 'ҥNSO $N(:z0ܖ}wp*,z{'qu|8 D(S#i̋qvAY71P ~Dg<5+ h3Ce19= Q䈘/Q8G| hmKe5LB2AP:(ks8v7q H.nXvSè׽ɑ %V X(a1/;9/DΚύȜi{N| -PrJ! 1ڭYs|9fFz۲,óZ{n K8խ5OZfb7hρ,u(|P9LUs9hZ*~ aw:ˉS<44SKěԞE h[P9܅gUvẅ=w(,б H.ЇDIͰp9dp/jaN hpeoR5f=woT9R! ̨Z&&Ahzc*s]48(&8J{51'W zVsfkv\U>Ru}ccŧfQ8:^xy>90ϷѨ5 / |aJ:D8칷Zqg&y7gt;m]nzƀ8(ۊ| G o(9iT3 K#"7p$V9`刎_r%rP"wDDXHYB KQǠ1/;] rf1o2o/0U:P 5G Zr·l5av כtZ8qjsQuvjz:hg^w2PY{BE9Y'EN+R'ZtLUZR)lj9Emd0QH)L+)(^UQIy" eA{?tfL!uJJOKM1 qL!J=rK/8::nmڳ]ȩdA8>>1Ő;Y5HR[Kn7#M-{9?uiEJBD5NGEצi imaIUB(heQd+Y5{jhTmȈT8lۑ% Z@J6H+unJ"Ašʰ  QOC0Ir8pٔIƼ,M!>YNV G#?RE;-rheC1'>Sُ"kv0[o +z;W89𹦲֨ȉ o}Kx9WaPƿ7@&@ xX1Eچq~ s$îdzbCB9 Ӥh}DΜSM )R@LN|"+GuFT~h$PXgZWq[ܹ&chzoM L*_w|`Ū\aȇB5Z)[ykspd#/iRTThtJ, vWl:-d+:Y2|s6N֒ɱp9*aai y3< /"yƥKDSfw;Lt&\| wuW\ߏbSdk):Љ67Zhu huJ:)o&OT%KuB?,dO ]jqƽPRKfZj}<Z}7\Up,}ʀ7Pd^u/Uː8hq=;tlr>;_u 9ZZHm` U3y{mUΪ7ZvqnMyBɈ/R7I0v8ߝއaHwIipJ{lKzVJ@Q xn9St$ MlYВ ٨n6A0g؛m(d~)?'P8 ;DuՅ[D/{|B(-F5wτws tWFI,EQg|*R_<3cl4`}yrg1gt(߁CP 3NKBM̩is.3f4F܄i?m ˗BPHd`ʼ&$d(fBrgh2N4vIysy]s=X9(E :ҥˮ4 fd~f4C{M~W?6 ?.\zGGGU>41DwHIVD WDU 5~RTjeBo*Yf;sGE~yEWH ۚИ.uў6$Mu3`(J -oKXGztzN0k cRj1x~=^S9Nl!_.ǵyl&g=[kM1噼6GfeizC"ZcYK_2&lS(jf$PnlhZ4a^!6j6<~}{k䃢̎)@eFކ=f>F]b]x#eb6kZ[#WƐ:R7?$"";q9E#^Ͻ1΀B1v5 /˚h!^H6 @cH9%5Hц" Y\tUp]DQFz'@(BAљ="Zm HY[${0tB *0ѰH`XƠxѧWmP 7#&T|~3ӄ[8:>իhiPey\7@k s7jhg=!H]s9ᨺ\a<hk㔝֛Z.ɽNq# 3|^jp/Z2V`ygDň ̸2WJ"@=҃wKEՑ2,}~7VlT؈=+ְLUZE*wS^UC3]xRDAY, f wX+IZPƩ.אR::5G:stL nSE%q]fm]P9/zs`HP5e{q Wچ _uq  IeC1ۗrΒċxЎTV- u,tE c5"a5a] yb LǬ}d'#Ϗ>FDd4]Yא ɧzelXX ,`E=w2Sq)sGX"kcb!2*)Is۲(|C L WNٌ: ǁ1ʣP,i \Q4]!u\N9]s :B-y#ee^xWq)[y^.0a7gרced_x̌_z_CzhLxɨS߳mʜֳ粨dxAh1kT%܇o|Ua@!m1L$AH^XmnS]_CaޫeǑ"'v"3i0 !2$-Y7rN ڪ jimc=C#2$ӱoh,s&vns,1C,,iʼG4ytl<%ՊXJ *λf2,Mq|8*"3792U(Ǟ5`Gz:V#UO2U'$HbP k`"D j]-\J2&,p>@qya(9Th[7˯Rydճ~F[N֑WP`*Bt/P(rV=!BXwaԂr AZs.)o^pML) =D*ˉD;:ozŭAZ;/3^{ug%6tA8޳j~ 8dD+j#!~sw?.]Zgw!Ԝb<H:z5BJc̚?бfLd]"H +XkC,czTu^ d@hL>[֚ ʝ|$ AHqG$=3[4TR4aIb}&;DqFVB_ -0ܧe1{ZZ8,ҚLu4رvI$-Cz%=ZJA*ul1[R;%hsvSuى< Wj-FV @?{~;%? c@e 2EΙO Rz?')okh iTdՅR= 0#dZp(gg@3O=oIWیT0`Wc6^4 #YsZ] ؈F^fzn}Y*yڈk⪼D&[ /@f)1iv D8Q5CD"yKQ} s[ ;W[-)R(ɶo\gD+,@V(bYҌ#TZsș@X"rR]X_ι:LtU*%HVk3$Saڳt͉ZeETʚPKbIR W%Ґ4zŁkliAh;uh_ E 5קEQ(LJ%JC2BaXF'JG7rR_ wH3@]c%T55Lz Dݜ6Ae,*P%@4; >Bs]u+V^sv'a~RtKfD C}#&DY|O퉜0%e@ ”(lGP%cr.y|gn[(k`b\BnR#y&¯ZTiT,|e{[g%\s9<<< /ak{;;;~ ܈`"V!?Y?w=ᮗZʱaC\ۂ-Weȼz+ +A(Q /38psRu^ n:}XY 'SRh@=o0߽UTE38%"! ٤Dz*VگzRUJ@>'%b/??u`MTZYgl8%*~u)@K6Yɬ#%Md B3+#L\x_j PEO|R G jґ-p'ZH͂'‚)Bd2AFs @$ʗ62 +EPd9ܹ{[jGNWcePJ8 ѪVtW E3iE 5 za{F@#[$]*U-U0ɐNTW0KZi a1?2oH*bHZykU9O:A}(0p;z@N >,iYۇyjY]&;.(3B1XDˀ*7au-fHqbA]%Ck=dUko&F5ݲXkXJ%@8&hr#dz|H f͓ OI*d5P ܄i9. T.@|vO@=6+[6B-h7ATN'7%0x1Y~?q5^1~x2w &;D&W (IAF"lY3N8mƸT+[jGUb]O=ã#l4Wi;@ b?L'W l6ӟ3>q-oK^rPkʧe_Բf4HHnjYʕY$*~bXjI2T41L2A#ʪp\2]4aSYh5I) ]^ )P>Ij/l3 ©ĨtƐTIS%A&y{T,TŅFvlWw\fz"7kT Q"k1@%s9B3 {FgC4KCU"ֵ& r(c~cҋj!YGtь9F %jۧlEKRBN@)V]| WMԢ/]E=_TM.!Uzp\Tp`g62Nʬl}]sNXR22cͥAv:lዂaݤH¤b!I-zV&E@;%/+WmKKf$RZ+Q`v(gp[[[k ”=E, bM)ޛ  ٧^f7 .~N-$0+[PKD @+[**r}E-[kM|&A% -C^|q b.ҷ)@쎲յĉZk;-\S"!A 'A%vf-\ j1 9s5>SCZ뜉Z-k\F.84:?"?T\9s 7B""*IقLu {ҽAPJBDcU<D\ & ,%HJC8FRYEr1&#.jMCOdEXtm7_T2: mUY ;9omXw (3\`*,\͊tФOӕ&6N YC  RIqN`Z  S˰FeN-$<{H/ɟNΚgp?10/]*RGRgzH(h`@) jn$yB4>;  ET)g}>U2}m GQ  ш8V+UqTE`G|;v7ڭnHe%`3!@@k'J%Pw4~$ģc0aMQJ/XZM{kBVh ܈R+|Usm9&͔%78ߥrU*bg8_B؈}%"Ṳ!5 H@M}.EŽѺi Qli0`\չ߯ RT49u;h'#d\ Y`*1/e~>aeMhX\j`aI׋n mx  #Be"?^&y1DQ+sEyjub1(P_EOaZ^F~R "4V'z*0']t..-s@ w}_vX6"!87EeIօ/~OjpVFҽ 6SAr.TXE#k5B幒s#Œk(p<¿ھȏC^/I ٧">coz;ϐ$kSBr/UC*%S\<46 N񌉭_1MC#1րZOD JS?}pz]z"8'b>mU|k"w9~v/$Œ`js^Vt V|@е3Z((@T40畺Vk`6 mfm(4p;ᄊKU:PB-spS*-s..OBH*̅]2E(BEĈ,yjEir0qc+2<$"L*jvT,Gңd : '-pǀvu-U!`-m׀-4UL-nb3B8{B)`CPE[VBV*-L cDHҝE)ȵmgCTdAoH:왵نSG$gTK2 :͵Algc *gG/~ @xߧyZzS8$"< wVRz]Sojc)G ǵaqF!A{UT\tHQ:ˁ4 6Z60}Kk⣖ڽToNGyC 2,cmnۮxK[궸!"+ ~j_EVcclag{`" wH)űWP&# 'h%^ʂLxW*E lCDȫ xŮ gEn#d /m[4?e%3!JRevdGHs^edI*%P6 T=4@Wx !? 1V=[f!_Zz|X +#%$[#݊EÊJx0}eI̪o1<)9'΁0͚t`,[ikb^r0e=1X ᱎo=De$޼<ϱRJX,S[ o*:}a6N=|-o,l+ lh^:ޅ(~pL)Jn%@j!V(RuRsB.4I4,h:\*$\*bXLt18.xU Q_K xFli!.U' *ϑ2XP5(Xd/˺~vVl]\9_b#cnah R@Ɔ <0%gV!Rk*P+yR^UQ8V\diɵ0"h\Vw;Dqhܐ:kZ3MyR)QxphE&RJXf+\& ڳ.pwkШ֓C~:7@-jF#v5Я O $'b{M+&I "2'AsxOHо "* l%ٻgEb (a勣+j(ƈEq o?p8vN8.^"R~/{r͔/)^_9$R)j?7 '(|3DDIkJ,;Q|]_}nQ Glsʰ.?-H : b蓯*e@6kFI_Jy0cdK(qUHP4-ڶ]}:5 M!@ +լrA$5.v! +0oPj!`ggaf N0ZܮkȪRqbP;\ x_!䝖Osx! 6OwF_+55 0 &QrEIRa M}LYנ, wRa) k e9^gh ;ى8|ZCH%oӧ)1;mbWI~] n~Xsкct|nŞRWKB%ϲtѥ[驮h@Kat7i<+n,i8qN<]qppФy}4OoC)+5?iu5.u Itc) {8r9GG{L):Ѭys%28"R6Ο-$ It̴((~=dP۸xZR( I![) cg: '@  hac Ŗ9pOk@(׸D uJs:q.()b>ƌU>K $n3/9#1JMB#c1HC`5"D!P*TNeDV>SF8R;HPbb2^)BA`@I\?HK!^b?<ж!P`BO 1zټ?&b!`(@ _ AҚS Eie2K@h-PDF6)%@mxqQR$FUĊEiI,XU?&a"#{6޼Rȯ,#/M,?^a@xCrh%U>ķ1SK'OԩSEJ GGG˗U^wW+<r?6(J ƥK[8fNEoT${$ҶP\eEo[UC ňX E,nUPHC8$ŵ/6w(hZRTL 52Dɨz$ 7XLi%k,̗a6C_ae sRLN2fWƴrfڪ0yu[x+ȥKb@U90G3v/wiz.BM\.* O7~ܘ @v[qdsq ^@\{ZpG3?3Z̊s~%4fR&%rHnKs n pޭҹC5T]sn'c"qM7aww0`\8<._&E!}ߦ?^Bk\K .ⓟ4lj'\HRcЃD#P^CnX@`AًE(!zeSZje?ȥ *Ht'܊] Edަ9"أe /u}]1ͰǏc{{!ΝÅ T7O oOblj;o/'ƒ_wjf9r[z2gfG->ru fH)I=u\0RlbC.mikkBP;)(J9 IƃtT}J 1y0P\;.dTIo cMy\.1bsyEЌH9nqUAyPJTrhvNW]`yRE@z格dp#" [bI;Gk `i*%2I2p[UeGи(+Lt᝺\$J.ϙ +Ƥh/ [} >J@7ZN اg2əؽ_$_rR^g(cltN=9 CWw“hˡcZ<\{ΪWH.j (SXg>++@  "p`UrjP{GJFZDdb=-Z8˔VBU4=8+/C;Ap|*\`/7)W7%,v< ;^3DUq4URC\S A׃VVO#J+dQe5惉giTL 5̗I"S44Dd;}_E͒xxK^*7K~_\[ 6Mxpn%B1W)mBn0sFTLɐqWfgur4q!\}ke pPRaNFNҋcTTыX|or]qC @&)rW 32*@(KL\+]"n>nn5 NHr#B%>{gf#zbn `t+*Mԩ 6A=u/K3\M,$skdbWꞀQ+-\kP&,9h]*pVE-{uX`UT6ɧyZcM5@qqpp/nS~zߗZ⿚Q;k^YlRk^j>}*`z[=0|KC(}' 1>C߻|ĝ1L`Q5~i5r\+rf4% A` I8E{o̧br?ͰhiH}` <{sQ`%wf3@q)E B+UatV,X&"hT.% Viˆ+JA)]_DJCL_RT|-};g,p^@ U? =fLҨ#XX@Q&ڲ׬TYzAltm̅IC>jɌj^ #v40C'Hr!tG^z" ͝d>e{F`?_!-/fa( ^QK tef!%[s:B/#LHHW%uiVVKpes=a*#A~\|%7E{?c7&@>xŽO){<З]j0$͐KS7I\yZhrŕ UsA!="0Ey 0 8Raq/@'~ /hI4}H e+u0* \VF`tTAPmj\j昫qkm#5M5ҰPrBm\ %-w?,ȅsXŤȽ'B@Ib9w"dT!շZ1pkJd˜ĸtw( 2(tfCHtyT{I4=@ɢG]aڬD&-,x#${  %b;.WoS/=CAyĠߔ֭7riIT&M{wEE*%J2C1McMo+R1h{ :'8A2BV. hUI2zzm{!ZJQ!~xx+WYSe~ToReO}ֻV]dMRJWWU8sZ"U$7# O(f!(0p !*Fv)JyhH_5@٤8ɂ%IZId ҕ;UU){T\$lrιV.J.j5x*2%27WryWX[H jP}Gj9ԲQHʞh tR^!Ч<yUmiu-L)jVD1|Y`OpNjZn 7RؿfrY-UiBFgLy_(w똠:A&)\ivP7R49,@K~vޤ(yNTX։nw#A)Pp]b~' R߁C @eN(A A˵TA@qH[PQe[er~BN-\r.^vS5%yׄ {XR6]3ESTПj @-pY|ok|PX=P']UtcҲ'i3 KiiZ\,+"{NKQ#3[Ѝ` T=b~MIptSrμǃ>[IYcS.jET" oSh#ËPZ#@+T̆YM3a QDE"sV]QF`̄=o L5>f BˊP]Tĭ*O,.W7 en@ W9fRI]8r8D#h]Σ.2 ԷcnmpAh-oYm\oʄOWNM g") +P+XRH>;%0 )T,%EF*myf0q+sYM.#x'J~ lק]΍@MP׳kQ)/80#Ν?emos0[k%s!d**"gb_%sF6eCfDZƿWT+!uH-m@,,%MTE*Kt^̠pKj! vKԣP jW"4B$%eqj lJǀIeLjc:+ \ VUHZ+9ElZ0"0kF{#j\ϛ6Zbl d\[Z{D+RROc̘4qe3Wӯ !nUhT4ΩC-|E;a[[[V e 92 M]?2o?9zE (qUSO㭹v$Jw~YhN jˇ NGve;܍ize=jUT "sWg>G/RKqlzKZsVS9k'Y* deTʒ=`WXҐb G,+("+<3P(PzPmrQ4P$gie/IFETK!ZZԜ/( 9pDh@eQX9AI72!; fȼAjMEko^%hFHQQ[)Ћ)1-9>0*:lA <[SL8QS@PeDK\;wSZ$U7ln*"1H͋A˳MgHx #Gj|DAOIƭ5l HjX*+wA+Zk$w[sU6,t)*RQii'q~P?::Z<* bER HGq}׽hnp$b57yur pSl5wKhmF ֓NNm^<@k0.A+L}&[["{rT 5.K Ŷ'YgIV=1lK\B]F]j!v,Am JeEpX-O5 a_ 4c Xk#4qY OPFPY5VTV.zUa0!4 SFcq?&AWg4Az'@{؛Q7#c4B N EҽئI>:J)#c^׿ fc.9S(is]sjTB \ê~V ژ*=/B6V܀0]r /;?O\>' @#VOSTߦt^zZׅo)<;P֌`ݣ^V@~OO͚Ôg8Fk/! ws sYWX4*5_rveS\F4%?>qx N0rޗB[Rz B fX-| i7W*/u_O] eZHZ#"/5Nb+!F}2V?P)QMZU$!k0Nqt`{![PSK^ h\2yX?Ҵl4K 8s]q8,PBMI 2.! 4o1DEe yߧq1C1fnS _|+ Hq4^*'5?DU0:9 VRXlyU .&n4ou5n{Eo=R}\1:QF{F ORji|q-%ͻOl_~a񍯷2L.4tDJQM ~g(ts1EkoAװdnKc6 Ad K60B@B8&. d-)9jF-Zi6rـUB5n ­vBU d P)jDр sҠZHW/9eܼ%qC H3Z>~&4(A9 3|[`oz{Xc_k9ad++\.[?Wt-!>] a*1D$2&uS&~MUlV&+#?↉}őDQ,&/f!X,j24- GBrz)M5wZO]ֹ=/R 8{9q!fxQ{뻷;»6)̓'b~.:~(n ݇ԺwQv̇B lX2V-4C"BK'3du_yJv)HƁ,EmaLҀ1\΀k*f2 6$(nH0`IYkɤ0y9@Bm= +D>F J+%Np|r4S#;H4'\NБQ,إqa cߔfIwюJ& ,iAǑR-j>G,r3OQ}JQ+`k VY=6d#WdX ;ϻ+Kҡ:wj4G@E\”? *7# g&Āss٭csiB7^R5wM)Brθ|2뮻DH 3epV~stR[0t.1}뚇H@QTjgV="XE,%s{i?cey|#{l|@kZղ,]R)(5zz@c9Q0 7\TU#Rux j{xuֆW6!ϭ É 0븚t`sB s9C?5B*#.~2?ጫ|-߬qտs7YSJG7 p⧧M?SP]IV+T1rJ:AүnuOM))n_8dڢ7qmٹ1>({kk/pTJQi~70Wc_b@ %nKitmc)WPJ6pB)CQ>|ih"HTU~Ҹ6EgGx+$@[_0H]%a0DFRWkԂaK}I*#BM cubJd&:h l/Rb舴 [OBP~j W1W0}t-S_m1P<v<4ڨ/ 5*Z "j,υLP 8 g2ኒ5uTwwZkWYȞ nkMEq7}l&e^}s{G_MOY7ZgJ؋)xS~̃e л·|/_TiT j'_jǔ_5}MZhnRT$ת8pfX( }]ZevZ).`Q/1SD,"-p\>̹`>a>TΗ@aIQ BdY* d:d, 4 %2Pv]έ$_\ j4h,3k:!!!nP.` \%&gh♖ ._n@*]9%Uۂ.Cڃg pC=k"IWw XXZ.mlc飽'RE2pz/:kewo u,M,?qȇ!4m Er@3¸AS@`V"%@G<I2(Ip!SP&ߣ 7"={ɿ ,˦7` !*xgǎ+WՀinjN _p 8.Z?Go C(5"(W C_b-۫s5uJ\WlЌ!+â+RsV?DZ.ɚ ^Jts@%$u ʑd {&U55@qT}+CR 2E \~8vvOWCDo.]']A9ڃU4NrrBkp= EۗT0Ԯ!in;fdozP& b"E`9u&j֭2Pm[^ȣs;{{%ƈ#y H}W,g U,.DP-Ҭlߓr=B!qd܉6"PMV?|=%e |bO!ĀPj`k5c< 1aRoW 8jwnymBu7K UJ53?eƲ^ʿ(-1z Xi/&"[GN0 5.Y[,%yڽOT+9V§1׊HBvwRSh}C\>5 1'fۖy9zX)r@Vr  $]Lk",  ii/ ,T5KZ`e7n*>gN( /ʐs*uD 2lzPfc4.@1 (KP:+6Z@hoWz$*hZŐgA޻ gco7 ໪}0Q W@0)u2;]&!F=,06Zrh6^Lus'G-]J輦)`G$IDAT(?f_O꼋%MݫggϞeA#\hӾS$kNGohbkZ$qݵZI#5TBfDl HܘMZ^s%_Ij_kd",`R+~ץ\!V]c朱,KeC0j6AEx@Wk U<rAY.k @q97ڐykľ]-]jɢ/!I1)!KKX^@7R~Gp٧yǐfH];Ĥ 5B'DN7%[friǾ&{p0 B]eޖƂ{K# & oFXBY&|4C<&/}P RQv [-Ka7\pGr߭'L1UQӂZq ~>ZmGÃC# .ɜgrКb0%PB^cJf3Ք}Wդ X-׬Y2 pTҚ=2 DZ31X\:*g޸YʏZwlmGBiPϯ#R)P>[XU[ j^pBϦ6'2og8 I"##W$bثc2BWW5W،ڒxtjs->b ζu-w[kRڦ{n??/~;7viyQ!@^Dp]`BS 8Q≐FVk 2u1cC1˿3.^afdפ(6ّ\\bMˣ BwXX⠱ 1a{{eg]3(nRU pY1E X Z *οU)u< ұ3kĿpZ< ;8[p==|Kowvӗq )0ʧc둑~{kk7-ԁ 3OJX-ZZ QB/д<LF鮡~nڠx(a8a!KZ4]Xbgְ*No$;W@CU^ {&ئ2fTRw#Pک` _Sk #L V<l'zEZzW7 [h2:8]oKo=-[O7\![o|>|> a$0^"F+;8nX8qM jPt],wrrcUN] KLE 2], >yXsY{Ni.s߿к#`(Vv3M"}DqNm?zjֿx}G2uu15p6>Qvlm0hoYzbZCXE{}Rab`Cʬ(Y<`9'䌝зW-ƺ*( EP qdԧ%H(" XAQBȉ= xȼQ "u1U((!`럕j:VY <*2]-5+H8d}msB[M~o_>[Bco]w~wv$?T  s $(HB>;ωg:2!,4/X_qW;!X#IOvSe/uՈsWavWBZgLgcbMչ;П buinhʑ}V2OIk)hҼi=A߻䇸Yn[›"Ao[So;%%:L!lO8NcԢ[zy`@\;@~h?V)-2Z:c5$ d{(^hU Hm 3IOC)$5!VB#kLUsXFQAD@ q-/$KALc!= ,qk~~1/M@Tŗ ;{x%Ԫ҇$bu0ZXP 2fy!"\ !nɔ>I#-rIҽ`lwVs]۾{zX~C$3ݿ8H+6bu&TnMl.rl6[ 2`47%'*N쟵i}c/z5T`ݮP$l®"ؔɳ=4Qfu 6i:\ UM̫W|/Ŷ`=%AEeDzOŵU2j`A%s t"XA|@u):>v{j |TBI3V_XAU,8`3Jdu DC}N(.CE9# 5}*'5?qK[?{;e37 EKWOSlj ( \cB>ױ:ᯈ8-8et^Z zDNyp}M=m_\p4}' >@A+aI`l[6WkޤcI{J9ÐPÜ. Zbf 5pJA=L:>힃sBKxЬO2iKEXCjTqy֍ x֎ED_E ;iksbbt,x"7c`E{*\kup>@CmV6-#XHjj N黷{sja <Pl'7I%07˟__R|NjވÝ'}w_8wU81V+5HKT#e\_diX_# jPզϘyl dmD- b `~e^h!{_tCւ㾺@BT id^`}ɦ&FpXL[Dۃ%v$AJ]cbFD03:s?"E( m}c?_z?E{>nw܁7Mx^^RloocŊŋsᑯ} }A\pA]#SSw?Ly\-xZ&"BKa]kc_u_M420 _tU8_[NKC[*=lo՘;ԹN*kƃ$n*bl )Y:mrI vU>Ȳ/ b!rB?5J  \.ޜ/N:1$pSCkH;|T;RXa/hIb )d°]Yo! vxi/+'g_=ܚ?`J@! {̨8BU*c\R O!UA QQOC.!ɬn&i~'n&e1FQΞD=,T_J`1 (c2'&V- &ȥӠ@av.R˒;̯uc[a M X"E-7V{ů wV:y[cV {?߁>^"?8 )}`K`_ZAro-ও'}~^Sؚoakk%Ξ;cn[o?{_zwL<;\0RK\_$8(B.0@7{Owy ~6 @-tbj܀kjFق ec4^sX@'V+k5 )-0$cjoI߷ \!mq]+,‚Ƴ1f?``دߠ4qŬ~8&™[ 08̶ Cj sB&4[rkdTvh\▦T-ËpuhO1(\$G,+9XN+,iuh0p!BnNL\?oSB?`M5fs޷ҍ^Pf~[[cQĬb@K{{un:y;X.8<~I\YSm˄Z#<̏ %n` ]@j>AW4 ZbB{V)(8Xl+6@E#,R'ax >{D@OG3$&_EuAޠBsV+mپch,kzkj7/xD[+ESb{q+_7oTr5oă_>[?41B>V!pP^zoz'N NބcMnXVX,1`{{k38Sx}>TF}.R VA68i,'w gNSĠn#+}Za\aX_rT7@pGJl0Bm*u?m>_S談ќxt`!ӈ!AĨGUoM5(Y2K]6D+nC*D@l B] kvyUVS &~0$U(V%Rs 0fR6Omt_9 ~G~pi?RxX|l|lbpKk^S%*Γ y5"lGz?ɯ,;$ܬ] %cfiS5XMήg"?Tl؀q1B@A9G^/+| 'Kޅg%P_45 B| *p8A\*<UXTŜ|Иh֪YM=sO\J 1kQJ]keO۝`rLzYnbxo {κX[T:Y3nl! HotКc+'Nǰl@RԴ:q><=S;?nf>urRIHҋh, q& 0j ox[Շ˗.iZL7XrAysqo}yO.Zs?$=}L<ܣ;L( HB65&̢ƘORa f@`ebkq"! zP f*$-02IIN "*1G@Q)Ek5>VaɦYmhRcV2"Мc(<׾^SP <^4G;_~'?#jRS-  sN}ֵ>r^9Id/Bu:NZy[ CgxA h5 J Q i$hF:)Sn3; rUIZ3`1C,d-dvsJfkƪvh@VUCI[+M~^JE$oVzm|kJgdK0j/|{_&:}sNtvwv;Ju>gߛ%% Ck[l9[537߂Ο[+9Tl#Z[=bJH i`*>yo,uHw+e]{j\=UTaRǁ)I@%AZRq49 = kWeҕ}R閭i)%91c\uoɻ"$^)%zť'c)0hY ~$f} 83'qYn p%}ōx10Ww~[[Ud_VR54aEIl"p9."%#g $N3, ߦ`UȚPBwv%jJqJЇClL?M@"e?RqGkٲcDò&ĽP]n&x P&v]`Fuۛ6{ a ?ScPtV(N[y+Gַ~sƴ=?E ~mo;N?ǎ5zJw(`T )!E.^e[ ߏFBuQ C}ר#-9~T\{ ZufN{ޢ\vs-vM  )hU^L)*E64AY bpĖTSK,:mQ{.XJ3fÀƼ45u 0Κ>Ro` 8"lEUU7(Cz7Z4.B*2A!~O5w}O.|/O>~'|7~L+?e beRJtRRb~ʠ3>H'>B~He M♹w) h=Sk;D5ȆRrzeG{al~-=Ӿ$&}~tmfPTO:˺Ч{_ons̙*Dj[QGuMlmͱ±̙xw|'k !>uwak>oPF$ҥKx'Rw܁'OVV0%XpLU돤7:7݄M u`ZiRQ03B j S?>?"4jJ۾$}+BXN')"6p3]-٥tAdwlY'5V*J5>[jHBcS!-j44Ve>HERs@ $qN]HYbk*M؂ 1Cܾ T51E_iSL QS svڭ!2Yhtς.ǻt=\{m2O;뾙SK>_7?~];UWփq0 8}6c+W裏ҥK8u^җb19ckk 8ã^£Z ɍo{7;;^˿~׾Vc^  >;:R'rPUr0'Oλ^> Rpd.W], ۳a2@Nrv |-}+V*>$2SGƟxO?Yqc oo~O/޼<X~zDeΓDʤ1r@^::~oZ͝NL!- zMhεsjGDɣz=rRM,$cm7qZ>jX0yqo*bwsܾɚ}_:u-wzK'-P BuANJD~ ǎM\;O} GGG "_ɿ{5kݝCy]7?f3|wǏ6frG~#|_ψptt|KKi|w|5nEdž [;;,Y_{AڒV,$5mo ?^Xu_CNU?K|~" )= hЏ9Uq$k݀R{@!C=3}Wi5 5*_T"H\˲RB,K\0ZRˏ[G( ܛqLd/ʉkG1gDd@qو$GKPkJRw%O6(//΀1A2So?g?WėzBLs7rܐۿz|+*l_{ k !Ĩ2)>UCA .A*~rH}r }0R&>h|rҵy0Mv#!qoWaNנNJ/}ںj4 i,4zC4e6na{{ ǧ?)~pYX(BN~|_ӱٻS\FR~K< B^@"W(/9mn TV0rDrQX P-Cd^7`8rI`^WO@ 5a;Aݲ5•}PHM[ŲGQ1! r)Uqٕ* a bX㵲&ȸ',5b3)Lʣ l+=Ĕ_) Wc B$փT ǹs?ŋ|;q?<[o3c?އ-|իpmhYo~}Å ?xy:+]}3ݿ4 6&%B8u4f9GG Fuvڹo7PYyswJf^h$<Ȝ2!Ƃ|@gn+*EB#h9^a@~u~*Xrҗ"J@W #YL, RF:4]S>4!ZhX)AdMvim S+X*,@(CB=x)/ =惯=3G'n'um!Og2H#C4QƪCVP^:8IIDIt傝IRYO ,ԦhwL|5Dޔ̪ƀ8OQHY?P߀msٟ]ӋPm'" NV6O7~܀Gp;$`ihGofwǚ5kzOt>1|S»np뭷⡇js7͸[mvmp0z:ujw٠c=::pwx衇}>(Oxכ2?~aņQhAYIQ/Ul>[4u:]]|a5!fDgwzZ7 {ZJ!)VGjsh-EZW"EdjAZZO!`f!ZVU:9QSlJ;u^ ( Wt`FnBe<ʇK.Twcu0"`E_4w8㍷p )j?%WGи@9 Z9k P[%d 9O5o B6 T Rq&q0"ZBS`yE-yo?hS0CHAE6HQ7sasyVd).DU`-q'78GlM9Z 箧ƛQb4˱\.я~;;;x{ߋ?G888h}+֬mckk|'ԩSq}oo/ϟbXϝ;Omoһ²nkmv545MsaQG7]f6-@Սg&t:)j]z! : o18K1 xk+ C?Y9M/cdȋdε`}ר*T.2,+Ƒ8-;HX 7\rQ)\rM#9 ).ʒ5d )/[0sGk|xzx_~SOzV>?;[3g;;;;1l O>b~G>ʯ ٳw8&(<U)߾XXx_ßhR'۶':X W8a~ BP˟POf1>g|5D:iⶽRPH"^4w L^c0@;J`72~\*JIM|N!`D0 (Hr; {@gQacN*=*.T"3lDA9#=Z { M`3_޹!o/(=Ş.8 `>:9߮ZPMVY+JQUPMYRP#.ϋ4[d.&W H-2`;c e!0Z_˨J )AxryxNc39QⰣp~sSX[䉶SFApLmܫQBe=w0!`HCDD88rԹ*~tt'Obkk ?0oʕ+XVkB_ >OGԟ|6Nͽw۸[9?{}#ߏoy[WW< &)jnŅο{ZWMKvm[ϩ B / $ȓ3AP$?Rк =o/7CO 8$P ۋ,}Q\xb2cGƯğ N/6o3H)"1dp__G7|3裏gݨC|e<9Ro"ٳgX^D) )W(85q Һq19h,udΗg3\9rPRrGN,ҭ6MDpNn n,uTǓMx u@V;"*C, - "}sxGl_H /TGԼz Br}M~\|۔Z@97%=k Yt/;m@)Ov(fŬxepzWc!K2Y"O6s!S_.3 +aV%\ >]_&0+~v9(RaPwĘk׿:b-\Ti}FLXj";I!j`LEݸn'N`_җڠU\rO?^sRl>o'ObkΝm"·-<3P\S[n5Z\sytS8= j!vZZ(UR4srVRcJZ`r'}+[{ RՀةߚ5JQΝuT0<ͧ"+ 32 r)X-Q1}/@X,0fdUBh6t@O4rR el@ A?+O-J纾j!gpIIDq кJGKYĈAHC%]%ܢJC(6IpL&ҥ8(A0`ۢڽ@@y<ִf=.-khKJɽUJ)5OG4pJoJu. 1.';'e@?.7o|^`ZԞ jvC~Zg!N;-y>{NZWUUb9/ESf\3Ƒԅ_XVr=\xGGicCT ^@z"o#+˗.ᙧzA"u]c76,{R j=xNt ۏ7J0~&怚aH0"\^јoQAW{eN E95+ F+r.M/а]4k@ v"JN>.@YK ^_X Eʸؠ7pܘPǛf|˗Z{6DloĔ7ߞ|t/Ty!Lptx'|Rc`.]!L3 Tk 1c䟜3 Uŋ9tzaҦgz+RI"~chmt񎕴?qNzZ,PAoUT< nWj'.ᄀ\:D4$,FqRȵl5&*qLA*\rGwh^2gy1p$JAYeVjljȍJR\%6&N4B[7A^ȚZƊ7$@ 8_oS}3RkHB,%֠@{HDGkŤ.5G`J h >:4 Y3#'t% Mi\|2wޑi4άj/b,?6е%o4 <҃<Ƥp0g}~ e/lR»npEf36jR+{9SO|_!0" #"KrJc/_u}=8#ESvA~ᆲYqKr!Sg[Σbu{w@EæKjT4tGEVUG LJnDvq,0̨иqU#(gl+ 54.@J] rR ZAџ-@>!3nȣ m\{j%k sofKluZ8Uǔ@i$ʗEpPW=MI4fd`Ulk]c,T45(=KF, 3f*PǭZrς}}<VS@L[j -py\x%8<ø fܚ5FW?g/}ȇqe+Ny߀SN2n8R׾r՘k)5SR4z2S܃7ӛEa VW0#u@["J9y]/F?̧es.(?ѥ-ǘx$kA3\mb% )2KƕAƻD?NCbHF(Aj1% el vCuMF2Ġ (j-? tV-`\[ɹ_LJA@8Ms= .X'TԉGOЏz\jX(w]s]Z>&"o#sPrMM+RRjͯL{ߖ (fBH3=1IYB[[ׯ:M@<y(3g~ۿ۸x"V%@n.IL[K!*%xkPjDl"ۺ΢Gh c>D랂ޯF5ւylC[qӦw e`tDdXϫ-6K=1L?hkGwY't{ɝ t]s=/~xwc>U>~ AflNo~%иS,/a~p??|oM;0M<dAM/aW̰#^> =.0}'&._96YɄ~9f9n nuu wlA 6KnⲢRV)|d}tz1è}AƦH9%P!AI}{_Fn;zn I;(@/W[F.Bg9AMh[364ڊ)hR~4k=c.Ih'JupoxrJf]R#5R>QU׃bM֌YkyUB}J} E7NemKDx͵QZm2\:LC 3  O!4(s7z/,86X5~ggG}bg?s?w`ggVſO /_.pag~8Z.wܵ~;}){/US_:͏{p{%?[!\^V*l';,Cп="ߏW{/rq^J>}䑍W~Jo-N+n}<tA "o;:rt4=W^ʻ|_[<"G mCu<1[A(VBQ 1As ʮ1c͐jS$Kf4SZ=-qm|X&I af(,PC @ ءS/@x>!1g6;m %BY` B-|#7@ *Z^dԚҖ tסR47T5`-PC͂\fsL*iP&PW5 f~!fB> #6K\vt;lV+Y?w ~*L;\!"!i>0cu`Y>2bshuTc@R-T_mu6ʼn #8 pcVI;"Hͭ =F|?Y&j_;-IĻ65|`WP#-p/h^l_Ai4SQcє+P`ȟ%d}Bj9ULNS>v7P6XQmdS@"&^οσIBMbؚqwow]x;cˍ/\|w =v7m 6<na^^bny 3ŀ?CQןH;K{}S Tk+UX-b|wqg¯|>K) jIBӖW00q^4ٺ'nƶ~7OkB zGx¬Ky{16* Tyq(z)R+P0hzyIbJY!PbKA UH"+qa}bhawmEZ#R!+}Dü Z85U>l4.2Q,i""/?^i7`ppːѮ~BHIDA UbHoK2k73W@*h1[RX6zY M<{\h1rI\O[Zm57AMi %Ec :Ġ_CjJYXk`W3[`,pIP]>gWk_:G0WC4 +>#Swxݛ׾PBn; (M@( )զ@\]ƖOU<VvpҠE>!-D zoqJ煙%l6a,WGGry)A<:6VwU ?n@Cm\H^^ /ߑ$֓9.LsyaXi* 0 }JAuL>vh7-z핚Awd-*/nzk]dd_9 M:ר8v=HY_\2-Sm ij(Oj6~KgmHȜg_CA!`wl?3@.N1v5 z{\OߕF:PR^z[{| N>˻X۰  qjsW>kƊ#o䘲}Mpttrn#!WusA9 8v\F쾖J|t 4 PDs\pRUn#t_? 0\/%M۳*$%)=^| 4<=0D8nX#b*I78˾ZX(EDˮR pLPyXTrEd9(c昀7A\9EH0@ʒkCt45P#/[4К=pQach_nv: A 9~,nis.53TQgZ8&L9SZ6:۾9(V J:ٍ~[|;FWyBmw~룸ewOVgq.?35G&ӻ! + a?I"W8>q}#K`69 erYK~[w/\M_ 0V#{ڦ5EߟHNklNqƇܳWrI *?ѐ5t}T-lN\2R*iB${7R"[z]A,h~^UaN#$ ykG؈!sVAn_ 91ROZ~QA CEUՒ*z ޶81u5̶2j<[0̫H~ @K7z`W7&pe@ѷ6X_-P'V-`ԒBQn߱T6V KXem)75 GNR"jdmZ㾒{to)<17c 8CkTӍ1\,\7* dg-k&zDD| ㎓#` D7s-BR!2aHlZ{П'@.rn]~/+vr/uv_=׮++\Ku̧ t(ֿ&ދUVu]L9}c8rd"%H|5!PGkIX<@ݐ~|UfhK|[A!#9Sڌ7XY^OEZ'Io:ֳ7=]WOoaSAq˗q˭(cG4V;Eתܞ@&42rba\T9  (}U[{jaާ 8#Roa Alj0h BQ+Mzo FE;* ɫP#MX'>gEr `4@oJj/wЬq-IPs?R@kno|.>߸\'_0UHj1O=4ᄅ\L^rwFkIh^e=soAR2#J2?)ѽ'6(Y @aMeohoEZijE, .&BgPIfu?㈀:PrU[g/}oPbC)a6q|oqRme)&/`AbY1;4P ^$k]v (乢F c0S !ܠEHjZ YL_.dK<ĤWS榡 uLkb>m>"rQ( 1&,5p،UϜfx}̀uk@IçnrI6tz5CT1ע`zfMZDxk6 g0@]ZWp/60-$V؛ ݫFa3Eܭ=eqeݶGwWl]0#V/\hz"i=\@&HF} 8:  kh8HԯKZ,Xgk6r}䣈2Q^ƅҊ5oCj aF \ŕ3c wh.C(Ƹ9.+T| $HZb<\0m*5[2W1@K|غ}-ŽB;^TW@HPY0"3iɭ ^%:WJR}RK?j]t[D]k5FT)!TZ {/pPaִ֞+xW˓oQ`-UΣn-񎇑W~@{] 66ӈ V~B.7 +?v4fdl@`XH%+SJkK~tȎ)&2r?@˿"Psvs*o>{?sȮ&`$u8| VkQj&eR&^anP7T (j8j(.DAA!5PY>U6Uᦨ(D VAb؊^1|TrHDa>aAK !b3f)Wk %f`*J^D=RSBAAA9PN.ļ%-B02H\jf#V΄UR-VӒHbOg֗ 6D*Լ,R@ 9Uoy`@u^ky__Sao.uR"K5bJ o LH8Ƥ@ jl Z }yӲm5?=_s-WM/~an[i29 /kGq{l1Dk?=-v_#Ze,DŽ*y)|+c+0z>RhYcbG:0_6|ߢBĀihM<)ċeT%Eҳ n%Hy 5W3X1ZMoϵ HR(1V'\5Px]Ƿl<qT}675VyD.TK sր 2'2Qx{`@hާJyNjZ3Δ,UL \b&ǬYzRiKt { fuB#mK,Pk@Y@T)YF|/i4 1W.Z`,az>>th>mF\/:qLNhd;~ѥv2k΁?-I.cmSϗ/xE^,Hpm]3%HX- GGqD ni7l_xtz>%Rn x"N>aSngWN];}JpkhY䠵˼u9ϒL3|j<*6 O-EVhDcTXuPok~h1 nڻ7NY6}t>+2 %)- TM)R]i u-1sxQyNjtX`*z1^HeRն8DI ZBQ'35%}~m.} Y3h ^].dh RSc/2h|.LWaNsGJy(c"R^\ʗ cJ gVwȌ 03=ƠZmOOJ]%PB>5L_g plXKZHPlrKP@;Ymt33yXdB>LUm?:GwAѪ Ă] )HS}Yկjϫk&6I fSݳ7?5r{ME/s^=čӭ[` Bhi .CB U¨ *~J5nSkBX3U3\\E ɐOy\p%XW]l[Usn6X3۴A6/Pk1j'#MP-PZ|'̕ @!m 'dOB_Nl'%O8AWBQ$OK,uKػ"c L,\Rh%QmףK!6U^!gU Ԉ^9 DhClNAqWhjw/jŜ% @Zi5&`,z_W*hU #<1fф'<8:]\.p1e¥DǩB;+So߹rWmښo Q~~ PH:绻yz d8;l:4=*_ M!2GQsRϭCMG X`}@B) ,9i,CBWQWeUF[S %rbqdt?ZE ZA @24/f4uYF־_K50AN3w!U+c @IȉZ'[)t#*pz aOfJw(s/CUDUu+ʮp;*Tm%ѲY$b 1U֐+s}rGo{>{\ߚp/->-`CMhߟ t-bQ=\ 7eECEw`HaLb` `-sd|a*1fM`ֶȨ}n 3ހECq"LrɸztQluQ=WDK{(ӱp13Fu l掆o{K'ƺ 5?$RFH@Ƞ0 ,}juR$gT+@63Ay`Xԩݢ:ҀmɌb/Z|77%^Y|6pf3d,D`͋c69]5bq s s&Ԕ=W8+ciyZ@c`OݸRaFS$o^`[Ko1.\v+FӔpeUph0#MWR ᩧƧ~BZn}O|#Ux*ђ5 o@VFQE٦ ֱྈYv0gPah 9 CŸZ&\pŸ19jmոE paAr' ㈽刋yҺ5鹈R5Ҹ'F03T >=kl,T`նKD{U|ԣ a?lxzZW-ޓ^qU\9;pQ-֢,0h`W%`.C]<_rU~?aCB 8DiOW/1xxM7/^޹*pr$쏄"a95? xRO[a7Dk_qSQSg&˸r*g&a覜;+P>ӈ ezwҤWċCf,wPQAOxr o{lY:ofNb`(7O* \3zQ闧6e(B0XìLz-&[Pyd i\@ImFȫf*iscYe IwncN:pάUL&_3+]< IIHS#$=Q$JU{$P* h[')[g[m M:;=S](~^U)fB &#iLd[ j@[OunѸӜ5eʃ+"(6N5Y=\g| x GK\p ; 3q?cVH˕#x`WE``E`p$eiS2jt( oH U50 pxY`<:㥷5 b$/ { q@8ⵋW Q?F0 x/J6Ѿ^7Zuq3< 7p_L<33M+s{w! 1N*1[$ @2uAV}lF 1hĠ+UIDATQ[@(EiZʕXW»5`(k_N.ZZG댉=5Yjn j|Hj2PY1hLA?uc9A4zPgD Gla+%MHGQZ mJ)BZ_ִ HpYTT1uSTAvud$pyR444MMOEڧy۠DKQ\ZrqcYGY ya2z> ƂpLT³m'Fе:G وliҥK6Jx*z 0\<0 )G%*0e_~@Z7T-G@~.*Kcoy'U/AkB^E8Rso0~%Fa`o , /,/F,#<' 3Z?#a89q˗El^SAm!"freJp(-p IvMw1WA ]~%fAĂzIr4Hmd8 .ak=B$-0eŒHceB{K]^.Y,kk5<蕾 AR挭@or! # L{k^R:0 BH:kÌj.,x:Bwl[}A,i[+ eƋ)قA\qZ3(ES.5mq6os`r@$$>TAc|W'oyo l>ԥ0~=:c}RP&%`\X2R^ XÞ {"sh@֎ # WG=GM `B0?oV>?x x"Db%Zao1`1-_ Gǰr* xʫ;׾O?|jdѭZyF3C+r\9n" .(2EyKU! },&˥A\YKgu$ ӴM/q1Mk/,guEuPd ~ W۹4./P&b<zz=i1D:wY<*o5BJJz:Ȫz`m9g꣐<yn!lLRge.B?s‘YY`=c,) 5KRR KNPkFVo D!H)C67 m)jV#ߙ :ܓ#N[K@;̸r꫊DqK-X gk ]E,`H  `C@!DrgW}z?뺲 @#YS (+O$oe% k7//RF-0.,#=$ƿNb]8bX 0svW@7x?yu][&3[dbtKh_#CހѺ~C;3=^ܜS@9b V3[BK& R(f-u ,jg[ ]`e-g[jCA ~K)XkaJY c3n3qOdGdi\4VHK`aō,~4H欹(su);--W'+x %IuݦJK>kd516 1H7buK[FoQʨc56X-R8F\AI C&ZwׅeY]Tuy.+*3Uk'ej!6&"ga^qv6'T<5{h=o݉.ϼX2LwoE)J i\I8聮8٤X nUn_$ZЇN 89W7/2j  cETӐ0 { {0/&UO-EG,K, W,l&Kq- ?99B^IL6yNTO@Y<؝ @~ @/`' ZVCHAV:z>Z + jypigG+ ?5Pr CРUc)* JW`G;ޟT p2M񈮋ZA5f`b6C vI1Ÿz3(ˆ\?̌ .4h~O}{Q^!d`f|3p}°Wg:ZZ~&>9;ePl|i g_y%i%U%Ko1^z | ,p˾(XG4 aDZ.1-8pnOߌ}ML+\Y7*fa\bT `.^xO=4>kG9yhC69>3_]fDj&XacFgXuo<ĺ%SF UTV,=1|L>0neDc&j"CJ も!1e[ a#X\pn9j)䮂x/.E[ ULa"QV-[g XDfgI DʨX'W}@5ly 9{ P-h ͘k[#Xp=V-3{ ݜ8-W$51VUJ%zz-[tVTCjSh\kgfPV1Rz-6!0v冁q6.طfl;afWeޫ 'uӉ߸ \]K0^!z W{44UlBEk6@o~JL+pb\`6pXpHRzd  K,s +*U/ ,K,KWlTԴ\Vj=|0=TXa@z8WgΥոꏯe+k;24#EyJ\ 0)Rcy*KH:ѯo>}f`ְN%OHTߋRXWZmȡl.׸fPC H4E dA@ {eUZJ^,oX=\5:1P,dĹe._s~9r-_]ƽj5o*ݢ@t\Y(ZKB׉\@%}Lf;w!)FKB] aT$#䳺nY-vDVpx##m24c8'rqO-}_aԹQkJ /~{cMIp<^ܹ`~2cs!c nreʏ%g?,FJZIx -yGۗ7.qqX޳'r H8F'SioŹ=Gݎ׎nM77_sڛ+{{{rt@N7y?O= }q|cޗ|C7X}UzBbL_nY{Bu+Mʥm @Pӈάm ND72_r)(lioJyP^xeSfky2^nڎ ZXEЮJB(/^CRZrKS׳+ND_t&DF`QRѵl+{:zDe &Dj5ߵ Z֬UѠ^mU@%cZ"}aMn-}RқWԠ>o$*_حVe;~ʇb[9 u׻(/o@7S,_K>n2h$H KWC9!c IɊ?5tp:mYa@+Sg]}Eˌi-=@X& A 8%D_b%^-7߃t9r->g}vfi6pppa0M[=\~ޭ.*{PmW7~6T H\*J*3WkY]>n!WwԈy:@嵀A\VRS I7?.(?a)" ^ О0)6^ fuO)OHrl $.i+ ^8C}2 (Q}CU,#sž`׵ uL,Zo !z:;Q'AsNQa5ǾSzО3si256fxhz=(UB6KlT!L4X2j4^F<16x)5xg:F}P)\uP{v+ p#-ݿ ;!%'x. \ޒ;wl*R䍜7kI;YId#A!.^.^.8:GmA@!) JJ4 r8ÓxΟ?[n  `q8w˥,pg_od[ksRYPiCӼxynDeacS7¹tvހ\By'bmʆRV(+dT(  `\6䲡ys5MAI,<V5rVW1ip5рTLcPZh'Wnpy laO+ ZػF"}/N$J2"ЄZjɐֶ4ɗASع0?6 5fH g>;D (: "j!Pc HV9+1Zso)t 5ճ-Vg;ݺF1իWK/5hTч0oaʥב !e%h:Xg0 5ljٕWt_RwV+t\*#XKa1” 20忐4Wx{՛;M8<Ο?o}{^)ছn¹s,sXט02rw㎦IXCgֵ|NVo_cy:pOCrt߲?G UyƆ5W)M[`GL'dҺ2lAXҨ$ $y$z DC7Gq>*2bcq>a`G$E)0 g,a$%z̀ٛY\V - R }57%@BƔD{F ϰTK ?W\&I@[Dk$JR삹zHaAB5J抔4f@^d=j scX\C,B=" H 4nl$~eox0wȁӫ~Osp)q?mooo3X,%tBxq<Dtr&b*,DJ"}`OGw\u&SQOqDZJqtg׷gފr888s\?^:-8>>>B0 pM7[nqXVW^y?{U1GM/ֽY:f |79N6:V ý/o18hcHq.6-+G1/ck".Ф]\"YA}R RbYQM5.ɟYwTNw0JNvӅH DC3be\$ Cbyl X&>6zuS(x,y6 t6(5h3(\ƀWH@>}+N#JtIk9 b-~kF@2JS`xW1jȭ9:[_~MFIp-ԂSԥ5?2(<;q`)[M xѼcj{ԿxEsoA*V̦O 9'OQ\nUꫯ7lw}>ra xc@Zg#w@8G+ph=˄1W@ Z vg`*kRY{p  %Zi1bX,8Xx>߂qNxx |͸OҘYX׸馛ppp+W`XlT(Yz~rtK0H-D#a(ymEVY[7⤭0&+i 5m\B$;R4hs0h K'q\hsIr~9OjgD'4`o"4ubXT^?}1LEl{b!USj"qRtZ]ۍҔ6(%i찓6V Ȝ:_3,F +E˼ H4͸@6TSNA$Pi+L (y錕HAHN&Dkb -֞OmMw0K 2g" 'o$_ŋ7mŸqw`oK wVE'|Fw!.(ŵ3}VL¶%rH*rQWlB? ,-qq<_o݄aXࠦ4 C[}D D0 d`oo'''XU&]#gpb*4ݓl ӻL`m`g~Df;%.}ugūέqQr_*KnEG`oIPWJfAlM`+E$< hAl&ޘ5㺴P@V?DUlQ%R0DP5 d^v] @Ex8 PagB<.p [.H5*Px@ bLǞ'oϪ$wGÀjemYԜSPL!`eV~2%\!01V5i 0G82H;'ƅs&Ho[=ۗF5XTOOp?26,#ַ}_0-ȏ[)Zث2'/_A>,U O 4gs=x[y[+QH[ø[pFֻXj %`qt7mg\r?࠵$mf*t`|FA|FRp _ܽK*0˨R-;Nм|= ݔJ ?,Ch=Ibi5Am׫>Pm:994$nA]6VNpb3S1i?}KAd5b8RgȚTRB]U"}{  6a-s-ؽ%گcnE8%mg8K z9FV/%P&D. g;hnL'dΉ#$'ɮI{ ?OjgfLFCϫ0>;R *AҊ7iZ5CdV'+0 (}$2fg@̀t>2aQ[c@ka,7PR@01 UdIw2~Cmq_?p1i3NGRjJVU3) i]skhMm*TobG{igp[ 3n0l\# C|t\)dZ8SH2df9Xq>MTH֚Q#ݹ;6>QcuHQy=%Gw OxVVJM7݄oДd[WZމT$ ̵@7)F8$c pr%. M,EzLϜ[oOo^^qrr#\rRj/ V+k#~cmmKM⚋/D5 lA\T#棢 ܸ8z!L=]jۮFC}Ul'(圅SxC_@[f/eFɫ)~zSXjZ\E\B5c6%}\Hl=<FR&km FQJdf0^>ƃSY5+vP;@l"@].oĢMaQ} |b!-)858RX3e0ct$x[4,JO3ki[HI˛5&嗀GFI 9vkM ;%)&2w B@*mx?q9؜b7{o?q3#AaC[`{4p@G/1.Ztg@bnMxr^za0&Qb}Wsluַ6Xpe[s􊆹N ^|E?:>i؀ %@Qc5.A\X79X 'PB YTu(%ʀ)I !cnq%a"HQD(kCCb Toȩa|(kjCbi~20.$ՆkӂӰWAiy A&3bVI3b񻰟<MPJS!B/; +nqW"u^k2[zJ ScE)!^^y*B5]pS=K`C(,r%'ޣNI,![Zտj_Så6zt%7Ǻ٨HcSێ^~y/2y ].z뭸馛y7d(V S?UL˻ON^|̍2`?kM+ (4#rC4/sC",]u~Ͽ~{{{` [%ޯ͸i] QA~_޳YI(ݔϤ P\d,we=[br!q.UiDM@,Viր*bbAV2V3>,uRj=dGpS!L Ei,g4Y38CQC^\!0{5I/̹`m0 ǚV03\Ot|.P@@">acX9g5rT>m<86r&M۴%YTqb9b:&SS4Ac9ɵ߸XH֓fo q#I aI+OZ@~j́6Yjp1RmpJV}h)Hx/U+S0M)-%k%!@EoR/DZfA{gxf;bHT@F|@\}#CJ ``o =sgإĢE@%i1[dJP1uT'RbCT)3c˭BAHOrLnB@CPY$4QTjdn3hwPXʢrU Nm>E&+倄o 9rv֌ȜYDk] q_7v/do*s%c0<‹8Y .+k( nyWΫX]jViqJƅ\w\X8wӈ݌W.ߊuY`hCpA>m}[{:6?J)>VvSDv{Xw{wyXN8dkʧwypm"tLoy0wDԡGD.sӏLTu7&\BJGEmrBYbw!@ +DH'aX0%FIy(kCQrOC`$5h/Ox|L, Uf+!X_vcAJo֞ڽEURBj!D{Eȉ~gYŠ sH.@d0TZ+ј8[c7Tv!m X(G|XЯ m2:xRu({opcH~<~zOdj/dJ#^xO+=mw} }c!p)-q t*N.^~ 4au47>`LX 88@:8ɇH;WaGw@ۅ&{˿Ga<7|3wމzj# Jxu^7 ڛ xͷaoo SP @vU_Pa ;~Oo{7 qb[`#-pPE6;U3,},fxWN";aJRU9JURk=Wl:%gWQV3S )i"Cz}i{um j m''^k=e-0$7 ؄[﫨JR,HW`:^ xWul| x\Lmcy^wJ4Y}H~nɎ:{_l9V gvڨL|~豯АU L QJoE2:y&i9{7s:3{*%Ǚ(x<0m?}h#`N GRp9-}KF/(DI:I(<@9aHb)=g1~߿_O8ٱGz9cZĔK.Wܟ=s< 3th\DXԮS7xv1tBHC\S|Y o寍ˢUT{N^scۦG[Fh bfEbw'zVwDiVD# [w(V6pkU)MXW}e]xa1f'!k}YU()F-|*kS!LeRb!p!!D! @"4f,:Tƭ}j^~+k0%;Gi֭yjt3|chAv7ՅgPRut簰 wP2A=&jHRf;wFˊ/W^m{E я~v[3ppcqqn Hژ¸Q1G>{-K< '''.0M)<`1=w[Ɠ| 5F޻LS“^.8#ogI7Xܝb|n;ZtP@FXZyGhVV=55ZhÐaKb΀ym]SE;L d"1 -'\U.P0k9?k ?>яG?{ #`pTv)5xM|?W&]WLO$ 'ke.J@4 +"nEe5#ƎcPEMR﬚3@CP/mdYXFߔw\TүLkQqLȹx-iZ9ӺcuA,FP5Z`ֺNÐp:´^4%VPgPjئoلL:׺]_'4 R i`O9_:DTZȉ<=#q:[*yY]#8ym:La \|BAl&k2TǪ}g6ZStyAP"ר:e~;}?C|QuD!c7bʯ2` Zo@Su8_=7=v@J`1h9 -*+R+4SPbn`hk |PқYXsu^ P},+FZ'=$g:\K\LXWr|$ '@E; GWA+k]vG_Ȕ#S9 PZˀV`j^J~D P eߔ֏KMUx?j-h|L "$`lV!{-b4XDktg&,* (_p."y:یs)w>[w uۂlF(c"pZ3_ >mCzvۏUP|9T;si~s>m~_… aMflD~oCPwDL?9Y;NuםrȚAϽ:^W} #H%حZ0wt '/ sQ".P@{a.]–maϓvzʂey1wst̐jäegbT"!+b: /Q{[&[Au_2ƺ ,j o7FTS`V{p& wWc;8PД"{˚s, SayjᕤA$QɨBhdF̥$% 2 iu/.RR"R #O{Z>olHl+w1zn]8FJ˯ŗ^j|yO@ bfw̹]1xws @7seO?}s˿˦ L]1`׌ǚ$."R›oo}oY ~7 aZq!nkLZ*Vԣg0 {ܷ" ~v]25c! ^G¿R>%gLI4a:*+ѠD[$ʲ&A/G] E c%n>p𰸿0aFmբ7x/h@¬N}!E@֪HuQ062DNJeh2܈@V%`BgXkjI{r<^xn tuwȠ>:׆!!}?  ʩ+*fqD5-{[!2ƴEW>A<̱:*odE)n+(LY,VU1 IKƓڼZy+^%r0n" G K5cZ <ׯܠ( @+x'nk?v܊j O+Ndň,-8K2R2TAOHN5QX)y:ҡ֛nRXjdKg]}-T 2%s?dkJHG+əXTS1= "7s=t i|Q 4?C0ZDZQzAn =\j\(@"CNC>1G?jsRz$ ұkci#HL<,&w5Aܮ-:picK,uxj71Vrk7TIV=78ʛ%!^'X]CR:Y?˿˸{6oo>9x>XoYY\} 3{'?I77@^;py|gzؿWRJ8z~xއ[n8* oZ-{Pn=4Q6 w[J68ك{Mҿ) ܹG iв,ϣ(ʷ~J$bC_p\ BP{&ZήTf è.ʚ]޴\ysMh#Lpʪ\y:`- ןkڲ]_1=Vfh%qR W%1M7M׺T#AZK$qD JDWڔ=&0u"{Z U*޿7pǸpTJ/*.pK|W3og,DKx $ҫ^lmEz]s1Y({%Zbjs4į}k__##~DgdQ5/*K/~A;18 2N)M7e+eTƪxYZ GpM/%(fv-TTW8\T13**L!g4ⴑ1`bgIG&אʁqN~) odň(Yʆa'Yid |/0L2NKmli@iI8kEA~&Ud0Y; R ԋ#gW.J*Z)8:YF/e2jz=ZstM/Jag.=a X,OxϗuK daǖF nKpM"bіq z.ed&jV+U N?~뷶qRa+iZEYYc ytT 4/<-2\4"xPGE"*5,B sO_4MMZ.N җ3Boʦk.;;O/gئDlSΝ?GX׋?۶d!(ۄ) pÝw,m(uUlcƁ:yNk_ HScL`6C9P$E}6e<4cGE5c&lYira +Q|<9Zg Q% c L1ޛtLd ,Qyƍ}3@iֿ&Ŏil1+->I5lm5295Y5KZuKxhN Jn4%(Z6R`],xr1z$ T]@aA Uu0 Z6XIS.`:/ɉ*!&Jl4?*%!EQu`2#A& )Q3WmW Б ʪPdAp uL ڀXJ)|гI|JIRB/3$ Lrr:B"kMu/WcJVHR-^bN2t~^ަD?ru wql 5<3>-,9g|ӟƧ>yhvYþmhG`NkmS\о]w)s9)ݿw|+C6/vܶ*hٱJ@DR?~|s-C67'A`.;Xvˤ48leA@ 1$ffZlu,IָK_&7cbz57i'{^iM$aÀr^5݉|ITqG̊2Ϝrv[Day8%bX߻L0%͐o;TJ;x)un~ܽUYVU j-Urch'YfΔg JaTw̿VQw8*1Ʊ(ĝg{[ TEh9g*wT!f ̟(/|;xF2{{{W[nenb[ ;gP^O\1> _Ϳ7-|XȚM5 1 9}By>8;zL/ϕ#?k޹FuLD7Cr:!$}.j~~^iSX`Z9/DZErF)EԒ 3$G>K,(Hw[*8(Ӊ k@'X DACi?^v] @(hulЈ6HI&JL(*c.{TkSbѧA\5ZsiE6\@UuԀ7YAGCO yu3Q&%uib0< *0a*,-u]X.¦(KwƓPPxR?r~Uy ֋?>z ?"sAy?j睦8]@/zl9?[x03n6|-\ti֧?'{N uĜп+W|{{qy5fK{.Ԍ'->)ƧPT 5Zpϊʋ>f<;1t!*KDXk+,' 'JyťDHEiHHKNnlGYVer)ʈ",`{~Dw)X .3{[Uޕ6$z4CJ /"{y:rԧ>|3;x%+`;9+>G@n~s~}+ `Ε:-g?qۦDmO^I1;Y,D6qխفt4gnpTJFYo(>X8L.ʬT3B̝qZ4ȭhPEne'H[MXHƨ(aXORQ3P&3150"[;wzxt|]x{1Ts)wU5[N{h)" ec >Qh%2ê3'DF$VmgTX-:eڜu*߿=1N> xy^|>F߶m4᳟,/^ 66DWT4gs6[_|m(׿u 9ע J(b@ $x{Vo/L"|,_g9ޕFTePyKG@h٘_*Շ1>Qm (Iyb k0 $D=L* GJIoL$)RW+erJ\,Bx Em-- ,c. 7kB q].D4/03H:bC1 v YQEHVQ%D\wXU &LqBpJ`lkƭsapwN"xt?O]ǜ>߄^.7|[C ؖm3a_79e`-߶|'; ('$03G܅{キqxX,` R _FT~@,ikؚ=x$]QuSkT<ĺzYZ%@A\Ӣ- #d^A A~͖Ȳ(Ht0 ),&c`WYe3hH  4 K >ppm3={z-ߠX·"U1@jJL hy@Y5%ω&RR@ݍ{Owpx x+n|umA37ǧB%},dstZѧ#7ad&J;EaV\E_\HCs<ÀP持ĀͫaE)aZJmÑFN*]K°iw˜B^ Hm *2w* O -3:5]{j1YH [ KDɳl4ٟ9꒭@>#XV-uW9SFF0 Hw-,o>mD=kz9 %oP#R.Vs6yv>oDg(E;9H$%#X 0_,??H;upB!r=0ww) R >OO裏"ƴwcbSq1?x7to1ṆͫZ|]q }Y #OfG UߺY-+T 0$f1X<px4s6i11s^cSHQc9Ê b_]`6ؔ @ʕF(Ts)<`֦@T8+k^` ktb-yOJ_aTY:V%hkGwX!rp^6[ noq spjJd1xƽo5/YX$6A -ͱQܥTLy =6y1{z̰g:5خŕw3Z_st՝]$5\o}qkY;MӄOWӪ?~3P]VߖUss_:AT/{@h1N|CƭyŸO` *0%} clipl*ȫyZ.(r^*ʮ25]I-0#jy];66Dk V-@Ri;w  hJ?MuCa1H* s #F @xIykP p@  :#" lCүTWj!T$B XȧO/sJVKCas@u2Uڬ-~f􍪦(4XFtr{a4 lu*:~у%{;ϟl"EWJb{f߿[O/ 4]9W.a?g¿k cf}7G}\掛S"  t;އn'晿eSzAh4PGmk crsWQ#͸QKQ75e][: SHDHlv7M< e ;1lH&889fr\9/2>k>+ &Ӡ&dև^7(n\`эjnF#EvJ0 r0K}'7"f0j1jpws.pz1 s* @JUзJ%F(Ȣ4nz b V%G>5deR;6O]W-;p#pHvvMp{ذ.T*8,Րu_]}Q9G5n@\nK[ZBmFS,#󛥞%[)Qd Р@ .7+Kcu1|H#w{v2rx`9SDA2O9 iGĵ RAW@q K/Z.t%%V&ө; &-LA C4ݶג5IK!H)@j +2K_SevEOi9SOt 4`Zk+nX'zjY*3tm01į#E`,=ΚjzA L}`@7dLi`R#VHî5 -cHU g%} ;_Wя~+WT>攞K ؆RJxÏ~MlBۈ'0կ  S%>"_D[w>0c~}EbJyv.ҕcD'aG!:lukJ`_tъ,N-@hhQ; 㐰h>J8tq"ž x7ik02b I6WCg ڷ,N&zж2ޜb Nq1k+[ $@pi.؅͂Lr|ᘽ͵S!2 *vyح/k`.w%Aq88B.|x- nDb-"^:i_IUcEZ3T[U ¶r å?\2utnTX)<(KDlؓE$ b`ZxCHH0b$EB4#X@ A_-hbh\J/u*Aq4USr<>,DwEbAyP!(I_këuhwz2cBXEF4Zmkog .Q44@2 U(@^?E:vO6>-87x=t_!]xMZg*x' Os<($ILYGCm~qd)&|sH <  !5# J)R^^q!kwa Mv R!3x*HCt"\t̓ WY騷Yɺ7&ڶR]=6e X v@o FS-j5[}rYSPS6&l(Z,h1" l™ s冽O= r,@86?2xS,doc%-+۩L®3k&~o7Ё8V-3&{^{?9_wz!+bS|i'k.F4.W6@67f|IךoUe3P 5>3U؝uYqn fQ. ;r "T 86DO/ jv:#NqxBZ=U)yr{/N +zwDfn`J^x 1`ݏ@ 9n>ZoGq]wnigǿӶ ߽?~n.w)gQ,NƟ.{뭷OO}F:bn?FQoW z\Z`L q;!HZ\Os ۅ+ls`4%Gs%fi[%B!~.5*p§r8ٱ`= X,FM# 1PlFE$qY,E<aLıbX|"Rw#n|mn].%`ms㾜3|Aoz?J9%X/s_pwx1 0t<7 dSMS{xCl/3b$3-Qu coRZWk HX`RcviX'B`IR22K#C7L` qOa4.ks 5bOׁIPu 7x)H̬) q5꿃B)|rl,mZ3t9MϹk^soS 4A-s''w~T%sm7\\0W!q[q&<'~_%'ƷjDk]^R,✘oa*MasVįjhnT{OsCPw({ ^Kb˔ګ:V0Mb 4Bz-C=˂u3 ^^i-P?$OƦ@}m 4ORZ5,~92}J+QVaԭr|l1g̵B ƨ]ԘTIrq뼸,RkCЅUaAL!4`t@ բ܅j N``ݺlW_c;5H \*0؍gsK ›O?&3'9SџmQ6__h6ViOξ?soӶmB(*~w~_r ͯ%`+<0s||~( d/z\5}- q $PKܤmmD`>ϰBAB۱ ؊5Wk\rE C̨*\6x#3#q!ϚH3To6*R@C2 [Kbq^GI"Uv['>\GZ?V@U,k5ΕP28* QV˷J*xSbi!(eBE.a*T:a=2%{k4ʅ[/!F/ӉL{!w5u`z zaԩXøccWe>]j()4VOGDxSO{\_:E+_=ϡ l="mSNns0=ybqpp??… VwslX#+oE)P[k.f;%PM),$SZդh%WD^k*n} 6M9GWmD* k_Eӕ Hi@Ak:kS9c%||xzTcXg"bj *L#4 2c"mK4 C:w[ѷLI5Z  8P-ٵD*SY*|R'8F¶VțcHQJ(h(ekP]&m 8M8iМRbÏ{0 o:ej}=+3cck*E4EOsA\ ۺ&^t qrD-|H>J0Ȏ 뛍!prdS<ާ:R -*HC5TkZ1Ή̊{XF`;"!8bk8}Z:1h)a*i>pY|9Khp˯>ǜ!m|j)8X؍mB;`8mnqTqW~S0B'i՚2J|i MTda 9=͒t]h`Jx/%mKPU+{;Ј՘Re_+}jT} iFoOWfv(c<899ٰZVw~wggB.دU x쮌9t4D>GFN&r0랶 ]Mӄ_җ/ſgֶ^?s2ĵ}/g?_ȵs"lo} 6( f=Gu"UwBEe7;FiPı !f.]~c 4L"`fL ^ jU#hL*)Q9`EI@÷QjւO 7U*p$xyaLkbO*@|`/5+֒qQR")5$LrblDaydHZiBAn4{Z68Z̀anѺ %ZMn &BJ(/b 7Ja\T3<,VXj!tThDO*V1Zux~h`|gꫯy_G˿s}//wu׆?a۾Ӷ]i@yW."n׊e(^ q#|[k<ˆ?9vQokmJ@wzGpi,CUuB3ߪtJq'"Ur;~EXIDATK\yAJzV`펭_Z@s/ΙXP^])Di=鳲qK~voA3a찍it&V''x;jDPOϻ Ю_fӢ7>*7RR U>@4BL g+#xZ;y'@U(hb4$s?(RmIie" ȄT"n>%ݦ27SMݱIF ) ! R msИŻ\@L !BD\7Rha!kC:~^sV|Ӿ Ufȩ~Rf?}0 7ؚw S!Lw gox#猏|#W7GNmus͂vfm-ƛ~!)fω^t/T<1nU HZG4-f^j!k5UTm̙&{j@E/S"^kC*K.\{DB\ -'-p뭷 ˁ*Sb/cR]%쮘ŵlU,nTv}goWsY1[ʏL!  F@j #$`Ps*C0J ,]YBFWHKR#v[!6HewwwZ??ޙ^}׳c!V,߳3) sǷ-s#b޹qCЉbjiv=|>چק H-Oguqo2~ v7~#GA,.IR0ׯ[ L EzL%c*kp"Aʋ5/X̍ge] nDf@|$ۋ)b &sS-{W22id+#Kl uY:xXW%@]ҨZv5 |})\b.$'T&(٘ ׊qsc0`J@ 8R,U] .nv̫g} ~[?m|wS cvm6aMI;ۄ|C9W@XZ,^ br;Ĺsz; YR|~s Z'bqi~%{3 DdX+_c c 6 e oB=EBs](!2_8(ji<n-\+vnS7C&<KDcLakA|@X 6*n+"!%9#!9t.Tn2,O%c|5zOd"h ~SD]~t7t>-%bZW։ŪLESiev.a0RqTk~@\Z۹t aP}ѥ_߹YLfǎ} i9MO).V΋Lάe>Ư0 N`NZ/7ޘi}('?Ippp3sZ"uޮk3s/{sHХtm~7j;nm?}^uם!{6"]$TqmAyg>O%be란,iIݸh4JAAY=Y\>z^\ K!^QjEURkh$G?jq,HPV&b7 eM`ϰw4yU}5׺A6o a\v@\KUA<ƪhƠ( .}`hu\4I0d06a~Ԑ\%Yƕ!JAUEBmF[m@Р0PoD'iƾYVPT 酂x Li 0UfHt\U 7rĊCb,ʥxgObw߿C|dgmhY-%Yk]q_>C=O?q\<6ǜ+5(dapڋ0 x|{?W,H.>VAIV# (ssh;"z?o㐽JCY_E[)Ӕtws/`= 1a8`_x%iH8z-hR;%< V'0Œ3e ׫bhj'q2.Qw)ڀ0?ױk< Ė͓Ij 'v38IA 2?XSYߛAUXY֬,_E_W)E*Mi ¢j;2 7*wXCl 5 Q Mٳ aoʈTŎ!"lqs$G*O? .]߮C={siwao;Z|wmϴ pZ ; >搁" zi\0# +346w:= {k6t=V]oYR_WOn( egim1 1o0%# *jwI3ֆǭKlc+-P+ w$GJc¢$ܞ-_yP4|\e[Okk_a8XO+X]Y8 "}qsZC&+c 'A[,7DIcуRJRKR 5t58K *` n7T-rL'6]mm@p6m?DIMbx+6H=du"QAHUh,,pk Hњp`>*Lu}H+ u='`9z@{+ޓ:5PSf똃W^y/ִZ9go6x_8} ?y~wm;fW<"M9;,JgSm7~7WWxG6|ssO^ Dz^O}݇>p!ձGn;7%S=>"{@L7A.։eY@DY%ރ awW0+ K_&o2DXWx뭷S&6:Ū,F pUdR8 - `B]_=׵[tI >kRבX YhjקJdтKIRdOb!cj /Vr  x=MQF թJLM[hd! q Q: 3ެ$Ziv^BElDkaC(ؽ]j |DRv'zu6pMoiyYϵms A|s%&`ۜ琳x9WC\[nWU5jkͮW+q\,Jx֠53>sqy-hC&PecoĐL!l7F- Zq$p^ Ag {Ş9(p׳+A+nhF(cŀo^ y1pJ-BB\2I q Vz`kM@oߟN۬+ﷺ8m Μ00'cZ`J >,yYǛ_4 pl=4.ATgkԑe6Y><ɠrVcHyzu",mk%@F,Y Jǜ97_!=|,D#sP`+Rd/$^N *E{8ORL$ywN 4,e agץš(Q,?mb>PMJ@.`h8OY*&ґ [M׳JVF0 t$f0ƱVJ (rZ5-2kTEhfa) 82"n7+>mTæ"|o~Bnqr y9H<쿭mƈ~ bI[,iodW@, m Ƕw ț ě+_ {챝( 9`Bq}u)?{o>_=3Uv@16G\!5tf=Q(v-fTes,ױz%Drmyqb^JkW˵s\g\ΓT^M@}{}!D\j25gE~>r.'6UB dSle)-92E5Ĵ4tFvRcW\Qك>+o"ŀ*_BZ<[`gQmsy?__ " ~ Ѐxnt= `{?sʝc(B>w9./ &eۡwvZ Plͥ׭3c=]9(75k4 ւ,K ivyϗa1Mki5Y#ZIsك!"}dF VtEÄMeR{J༮sV&Pz)O$r(vQ+,T, 8>NuXK[Lw{매>dm\4l25(] 7'F6ac>Na5#J9HfKYY\PSXS ]Hffշb!Ƶ}Z(~dwohNkiPJC=/}K?oRcN_bۦ wAy.֠?4E`W ^<&V;w/Gzp>0"AQqؖ+1%LJU]fqq;T}^ l*A;[j^Va5M_㜝jO! $Yykj!F"WKC,ʻ+#Eru<0h?A(ڬZVVk {༂%и'},W#R&ӞܘcDCYZ|&A2[^à"$~S")J_xTT[_ojR;eA֎n %"0K b-56 bZ[\1oyֺӶ8L!se*jAAZuoՀ3aTu7aĞG&j1wy'O7t؟'Ӯϻ^F--mh*3)s@}__?qG?uk53)ZfB: C"0nWᑟ{e ^ }}aA I`|ǹ՘PzJH`z&[3S$̕X '19?ڷm ]?k`*ײ?Z: 0 h>m؜9m ۊ!{y< s-jQ=P-kaE+\:kJ\qY+vL-ZGmJΓbHI@we%9z9KC!rbC"s2L7#P*) P}X`ow mߕnq5ȧoh~)`E XI\KgZs[ӂ%~1i_bDR Xf fZw`z &05 e#؈UNQ--:*gϰqp1(ȫU ޕ?{slOvD$ %5-&Ym$ yi:&^W?993O?i ȌZ>1{w)w9^m+lҝ;{gqbFggATvmLz@\y+ZUX,X.X,X,{G:wH.%^OիGao ' asاLոq_K8$њZЖFTaVKD  Bq^"B,YQz.EynMżԋ+/k ! \%K)8:>Facp%`2Ɛ &mS\w2 V:@I쭁ɵ$-%ھJk(S`{*Iռ|#l(*=5khϜ&jF'xGJl_V-=NA+>V'n= Q7L:TD׻:rqEFC gࡇ:mB*ko~;+*iz|riϳ b]]ˮϧ \ ӟ//4r̉=coo{{{h̡NsߨwRcO(bl*wy5ZƯ KU<Xv7%?Js^ >pi"ە"u5!PIK$x,vj"HAwb/Ku{f(a9$CK?WYe Sɒ @iԲ6׶K+#fY*(x"~f-4Hne !QoH0^Mh[ȵdou8"M=k ia" ƏS}mZy{th, "O%`KM/ge9󢿯!Rl6*8j}=t0yj}jo[oεnlYr!\O@`"ZDW.d+\ЏmuVy{I/]+O-Q,xq բDEy,;M? B56 èRb\`iR~/)QXQ奜Hdx},B; I_Z=КI+av oӼ;YaE X)b-I6 @Y@9k7`cLcb-젾z+c~%mXZ$ d-S@*\)iDϊ.ӽl^21@ɪd2(mkV4Weݶqe?Ry0F^Eű*&os{_8ϕfcErp^ ۬9?ZGGG |3 -"\׷򿑭Z;+K Sֶ)qsCsbK/(4m,*&g?}p4x׌.:XG]q+H\@lOnG/l0b1n hCaO>CT؁*(2ha1(\(@Њ ċňŀK1(?~UcF*`ŁdQU@㡸ˤqӻoܸ-1 ]xdZT  d] 5p%img@@:QsUCgv!ͥ5$$Ԕ-/=i:+0@䎻v9'Tr,k)rEs%4Wc0@%m~ nUKMr%/-Q z|_#Cnh:CgL5rCB`Bf<h oV/`V.UZl\LW&mݥ&ffs2ױ0E Y>Ͳ3uA"ΫgoR AD< jCY>-a3|!MFgK`?gҷsHYk3fD<猻'o{#|&y:8 ]J[aN)VH O?4smڬ>JLa0[870:mNA֚$ F1*׆=lb}8 r40j6B)3 sB|vHun)bBCbK1t 0h{@ 5 0q)|BEFmÐ2Op"kZMaMIDjD Y 1h)5PWXY~zCz=Ac5i?CcnE)04>UYCJIЉArZYg 0^x8ϕOBܬ~ԧ>qY[,-9cod;˻޻*vl Rk4f}@ ؅T̹LED^x \ #j#';= wAghjC*~DY,uRO1嵻 !5NsΘlj h%Џ]+Q{jKVzSOw޹W_}M:nFZJ _җpppAgU]??˾ws%` 殱k{h=ø뮻7zS 4Wsp9w: 9/Q•W3Ϻ}Psy>[AT4LjU&)]rcN<עCv0ZڼVB5I[qmhn%.e] IRJ`W HHTĐHiPzZ%:[5$y2R Zx)AJqvAn׿]_ e0ͲE|b.c }x?JC w*ǞKmAU%Lk/Q .|1"XVҡ3ZtrNU$ů/bs\_Mgخ:Fgvܮ皋7|3>@V+V^6!Ν; WP {mHB<,^4𮖼1=눿 qf on@;)Thj(k߮? OV}l>H`;!M;2d, Fz E0 DK?B)kM'o 3x&,0p 6:̒rS5`|LfFmEڜ.lE}`&ݫ5jhˇvk$is v`۸}ϟOOn|s]^1 ײ۔mޖ `?i|[4M8>>իWqrrj9\9%v )zO>l0?_0dmF=ź곧5 Ҁ*H+-q彬P72Lq1֮}Ůc| 2w),| )P <$ҮE\ )I. Z$mlʊUo|N'5lY ."}>N h)*WwMlb99%}sZL=y]w݅{?7'''Xw?~6?"xW`ܘ=ppۆEi`:ݪhS=x'pIE$߯i<~U)5,.JRtP&Vd%A*Z9rR| \9ҤYcg>Qd7#!*XO4(+m&wF7pkBӠ1ze0LO0%AװZQ/E-?ܠ m.-Њ=%?h(S HLR] oL 5H6-ub=y׾Ng91)fdςnۮ0ss9ܾpI@HJ[ +e5VْmZeRy[RMW*IRe["K,%" aJ&)nߞo^kΑ̱^{%֭sݬ71Ɣ 8b6!>yeV+V.]cܿ_sƍr$m)sМ3n߾W_y?/6yYX(n'AϞqV/nHT@ɒ$T!PJQ:*Ŕ({YRsPkUnaz)ť e,|1EGЋi/R uki欅n#F\PsaPBAr`IoqC! mE0'=%Cp@8F-3+ʘBi,1Pi%"P@-6%B ։f`f ԓYX-NbƐ üF˩X^%H0|_=M͢o񾩥ޞ[,@-6*E?O=?nL9 at;o(`1 u|͑ڋ,~z*|}!P]a\N< 5̅7=~x[. %9"|oP>_Tِ(93F?NQV֎Rfw(bո-}?RF-fg!  ե6gj-()aA GRʞLzxܻs _A려V ë7B?!Vv{b$1Bu;W6q j2 64kՎiaEhSpՋ5]Hɠ%TL+aqO3p",dvA5%K85m/L3%>"HB3 E/ 7oDzuO^TӸzƋ/|z=~ǯhc~׌m]YF6;\M7 yܰ 5wy])P6&^#KF{nLm{Ng#qV%]=Zkūg{F>4&C(ՋUg29Sf\5艛W/otꟌqOi' .Z,- o%BYZkAj K50AGO._M7pGdU2ZѽYBCشv oq1CaE b9& ҎEȂ0&Xw}sUM(1#cD|-~mhlt1Z4dhM5ܾ㨥^=a ΉU<6!`HG8B`FC5Nρ %[{ zۈONjsG>3SⳘ\|mw`j~3}96'R/zX0~s7|]]igeq]ܾ}ׯ]kȇUq SP NSB iRFP^T+.̄0P0e?UfQHR/jdEOIVfr)ޯf %ĔPZXe2 ̃` f=veL)"QiEޚGTXXa}6EsGο2Yex,~D\jfA$hA &䈉"o!Ԍ_ƤJ~ 'Rz +ܼy9gVLU8 ]7ny.YηE~W<\fO<7nޛEG5?bՙkuMvJ [Jܽs^WS"܉?B!@C&Ł59֬*FSZd$T: f!B"gqjhKe&(_FŌ/f$&0"_9ё[K#.@*PġzMOO@U5$`?9O9r}]U0HC'Ofb :7vSʛui8K6'"Ϡ1{n,!wG⤝0"7[NRpYxj޶.ZVuX0Sᰁ=ols51RmMYF{En(x6^Nθu&^~6E4?ONN?JPyNmة}Ϋ췑}}-4 ^ϜQ}?#xob\ndD.5@g11p3bo<32\p@ߎkXqy'?9ҲĹUkƠjviA5Ukao!̌D98,U@E 0 .j)C^ @,cטdx4@4hZ64''*5b\Xyv m3pei?& nAˬH&,ePRk`QҢopeX,=!I!ѓD9u 3^16oH4UxaG- 9ϷIi,X gR371C\A*I=* ]g"w^?6`yco1鶋Q`prrj垠l.u]Sdz-geLD -nʋښ˸MNElUeAmltlOʝg [[,arŌ?_$<)K `0` w,7?IB )'!s3C"J-(cWڜ٩;Nn q~6n9:NNnpvQF˅#" Ŕ) ڇXD !3"S8'ܤ:=1[忤 V*. 1=)zQDsTL~ec#&.(L抁_+`R ob **0>}A chΛ(ߖ\_8FnX0 XVx'On[.oP7ln6^x/cF?3HﺮΡ^RJ\Nv pdtxTc"Z8~[zX'1X.^?=i? kt'"h+^äG!r BBKDrt.Icػ!U/ꨂLC"5&,kG$ܘNJLAkgPҸ"_3AJAg1 %5r[:^1AD%UdB""}$"f1 hQ8q ߑM.+,h1z${j€D5ȏ<C?&؞F@DwSAՏ ۩eFSO=PyPm^֋*9+0onbR qeڍ5Mv RZkr r+q hiȢP& FPoj!V8nϖ| E%;1t E# RSuu%$X8tJN{{{AthAPL(cn\ 2h.hZL`.bфx+$\IP.ȃ" }69@La! BVzUaɳ H7O7ZS%?0ySV|> yuPLGX] iGwd}nxs1 Jd})? .yn9#no|#!_~{XVν랦At[hnwõ E<22b3 ƲHsuh꫖yoޮ(VadY+ԓdyUtA)ZފRXBURB)˱&%0sj"0o Fu2jEj|{Xj.FzP*]C `%-FsFxX ${:0WʉXM(ao X@vJUa@F {ng 8)HZ۹w`ƣ7+yDUʠ!c[9!/713F3P+bFAK_4BC7yS 03Vz 8tܾ Bnۦ,{9|+_Lr4Gws@| oCZ ?kDllZm2L k6! W#.v jTRYÑ7xuk%_ P]Ψ mcNXt:R/1H{(RS t)5G>LZz1jAwpIcfG>4¤F9?@)驽 /Ԡ ?<8lm\ELR1<<ﳢzɩjx $FG%F-[U$  Y+}YV"2`2 kg1{ (T@K _dNfeG 4̑dnXյXa|mp?kd>smvSS:<3( 30}ejg^,xqƣGqJڬF5M]qR~Z@AՑ~܉ǝR*ZS2Q@Z*ʰv'Oͧ@JMDǭ5$${{{xuK&{[rd4sbD%pf`Yz7 .]d -cJ 7lGܸu8Z"VX O+6kȔ'jmƒ[\d)a k?gm9̨65;뜙[}M!-x͒ zwjCr{oTs[6P[xg\.w>wpA1"f7{v]7jV5U!n3߻'^r,5E"/9"tUeRY_4Lu3{-=ic& ThYyeE _tAb=yapH|# =&sZ-׏L J` .A**][MnDQLn@r-1{~+d_ KX?Vj:Yk']?W l+żlA ð!tlBPJBqsR| ^d<|{ юG4إ܇ReSm7(Ў@co#Gw''8>kt6Ǹz{wH_{gmߋDk{ln Z+^7n7b)X`Z9K)oSҮL51,%:WJ,aK)nA09(R ;dx[q4q`$lMZcs,[K5rRCåhw@XKAa+>~v *iAy 2T2$dzv'j3B#f=>qT*}IX5{7#@,J#@h(POp7UƯYAg׫<^s:նߊRu I<nq$j`)RKY4=9Gc.^\)1G-5naIP[- iQd,J(LQu$Y_Ll}?n`%x?yXKpUꫣi{o jo׳MџU`: bܺy O<Ly\ʎP qa֧ƑЏXsD K-5{ HZ8,>ajԊ!>r4y0e{\ ;ߏ.G.[W]V+<@>d8O;ɠ '2iҬ_hxܤg:6aиҤjNS+4%Dm)*,/UrIzͱhnjߺYj֖cc6#Q!?">+  YT`+b]07nܘgC#ڶQ!OQpsn `@$Αvۿm政m)%V+ܽsO=z ͓E9da8G7G+\u=G|gzZ'PSoEً5ANmX.("1qظC{6> N\ʈ )}QXRk!%2 1!ء6é!<_Yv!y^b!fYIfCXV[NVV73\A:em&!D1(ȓD -]*8mqkX.>OnRIi^W^9p##녶 -!'o޾x-nDYcYT$j*f9'{mŹ!k2ЗK 2^C*xV]= |¶0YJ-^=K%;k$(2͜Zq.porA$ ~Vkm(9#~7L3`Tm\wz;k\y,={9 kc=Eyg)~p %{{{a%_op$? '`ޘI9֮'(5n &Sbꡍ b 9!z64ίM~bxsj0vGF9S"a8-'5!e Z⸥NN@C=#BÅSb!\X?ZzT/X5NԸK e16#PCq8+T'$ G3+BMFp+/NZZ$nh1IBe5DY(:i$ f-XSQKt,q#.#uڵR״U貺 ,;Aߏ^y==ޜ׽Kyׯ_0"`FR1FvP )%λx|{~NתaTJ޻vKk[Q[vH{ l:2V`AS>,40-.W[h!v,?ƆVndbMMѨzi>%:E?y˗/E׶txϦ^pzz:R1}{pl뙦]Ӝcp gzhR\iZ{r>&USAKKݓ w&Ol ,[o,+D͐T)4 ZJnIRmz TR.H!t ЁL4v Ye{iQ:2AK`{0-=\eAʝ(o,E ٽKmBIʭ3y`ޥ JtQFE{<'1PxTHQ0(yҌpDWrL7`ݯq]\zu?} ~j.]:PvR,ânRR'|V!?U4#*F補2 X[v1`}]bɢUMZeqXCzjM[jt,@ }qL@;2[Ch/ΙBok Rͅ)~w3-!Δt8edժrՉ E:9Y|MJMCJҺPj()IFQtԯbKhS1Շ̮ndbq5O uHdg4D ~Z0g, 2Hq ~9u#azVF@4,jDF[D=kr^E<91`ȋEt "Ԉ=8O*+s½[rMy@MLeI3%XE`< CkO jO-UFa@9ÑQ-\lklᅭ$-p7% ZT-pD1^zGȜKYclRrN@ Lu}+09(i5 kޠ N-@a[8 [aŤ*NlUi՞lZq2y25 ITizɸծM6mr=WTc^#aiFݷCZB:Ej܄Ln߹#,٪fST`*0 8wA :QپWς0NpWSCjX׳ͬK|q=1OOO}_!*t`-oBn-zen9JudT?Vz+"j5Cʇ'K Ocds H#l3{D1("ppxnD mvyYYwAj Y'D$ axxcOשeXX3dѣP^a%)iAFxXzLRC<;JSJȰw`i" 3JNF J}Tp.[%/%=RT&Il (̃AP6 RDZO*f)en6u֫qbCG,A=EObM {@]^y ?)0=.3ϣ/ܦǜ+v5%5AcOQ3{QA䀈9rq"TØ7{ֆһfK1NӸ[i^ בCI)g/\$rn }UK+fSƠ 0t*Eti㣴?qM#\LtOO5h9؋o/4XAU5:'kXAVx&([Z*i|F-a. &h ?M1쓅aP!RZP]).hbҞRM@ mscf] F6A^?q t. `v$xo@GHTZ, |)\+ 2^Qc},m{t]@|[=M)`Z ٶ=ǹ& Z|st ulFx(YS>I 9WK5a HdbFE.lZdX$_hY~A!E8R2R{h+*̪ӌџO@81%1B1.f)l6YF,P; {Q:Y=X!| 0ru+l(S#t){<Ǯ!# { KWs+LxmZ+ƞ$65;{/>ߵ;nKBFi̭zb8'4 ă 8' *qjc . oN݊{Pn]Y^9~΂BzBq< djF z0{!Zv^3XuV1Oxp#*j6)?sjǼomr=X k/{XGșU0 N} 8JccQCR'{ Qܧv~B'hqQƸ33#˭ܹ &H<6C4V$ihV,D!O ^g9aI`\Z`"=fE^gpYjfWV?S9SX0LK9a@Jm3AEXȬ\nJ1]'HsnLSM&n3Z~??/Bͳf2vJ)qD Kqڈ*e~u~VoutCR`2AT;(:I<g \9m,i4уhCL Z)5( ݫo\:MupLO^jJuI%1y9/ã)l' k%$&%Ty۟+*# $<kEL IRf&H8BɌؓڳ%4 _qp9a0]a\:!BQ!L`gߋ׷ vy?J)8>>QB{p9ݦJ;~~nܸ!rt~5[Zb&rmZEQb<❅䇾SENНѥ,圍lzPE` tlJC 1 8%ԡĨ(JocHΦL&@OK?V9rh|`,1Я\2ǦA#F*(v3見&%0U40v 0P QM0х/渱KZ!H)Š#֢1!>,ݭ0Hn<$\sBЄg&DFBw~Zҥ#MڦUzޚV )w۶k{Amۅl!5&֊_ӱsWz~wszSko0vp\h$_XXS[cdMy[@}yһ$iwhL!WRu3'8> #i)RC1b"5/ >ȆZ3{ŹZx.RZ#PRr;[Au K4 My&ڼ ޯ킥 :_a@ȓ D4ʽF ,[!d'^ĒZC>+BZu9ħ!$HhĵVWKmESrTH*){s>Z-f(D>#.z;f{/<޹a&Eml/4 s%ܹsgpؕqMYLc߫ ~n׼zsu&gyZMLRa! ӂY Hy]Ҩ#pCa-$ 4fZ4Qqb( [e?qxt1׊AX P 1Wux!VpZ%Z#%4Ŕ2pLjB;2hR_fpZ66wͻ"q#8.LvΆ VُHRE $I!|s ,Ű\v:IHB6c2 DRmkV)KJDVֶ&, *-6V/+Ad\rlφ]5i:\M[}6܊vM)}?F$Ht?¬;lJ7<Mxa*]J6/~}_8Js< e:P;/Uv(ZZ_Ct9#h!{!dm8='J*X z&iJ5UV#A+ھa(]H]F-jnh2-6}nԑ )f4$"lS9 nsg+hNaV㩍ZWY&8p 0ypOpYe0Q J@bWx]+3?-(Y *<$DyJs16,T,zEY6*KM稚Ɨr"7ЊRT.:c ˋbhDDAbV%+a"`OsrЪn(6+UMo#.EJDh%'qΑ-h!i/}= pCqQJ pali_3R<Z|- s˨]2ȝ#N#2؏Td%hnꨜQ.]#DlY@7u"4az-AHR&%VA49eVj]Pzï}h} zX>h]񂷇oZ˒Gu2AaF蔹bl]f `I4#%FqrdLƞlRr98L =\t GGGX=ly0~?56"K` {Xa%;}}nW.o|Ч!sa|X7nc=k׮{rr[n͛899[ck\,z*b;&5QبBEqip7j1xn1ohTV?h0`ԯ]_|pu5j#zQa?#~:^|E};ww믿7o{S#PbXuAiMSHfABPCd0kU=C,I< [C)EW0 RYSP\A{{b{\IYϠqt0a`/УnK0:\zwڱV jȄHalq0 l !@sF5hBc fˋ6p0z\ )V"^p]LW?M\`fI&$ 1eYZ[`oqb.h 6q&CT̑bYn>@Cо5;/ů6q iҏ6  pzzb@L-~GhT1٘hoeW~p!0}wzz{O_?q\zc͛Yt]ׯƍG>S;xw;ߖ^Wt6/dT5m!()4v"b,_תRB?*hnEs5Y K<`>NtImT*3 ̰%JCzc,:Cwz|0(A-2) ۗAe 7 x4Dͬ+|2紺^mh81BoڼR)>=Dp4%Iy1sX|ސ!7g\FI `VokaMQA}E0  Fw@ 1&BѪ+3=ܻko3eDX,X,`fGrθw\G?W% #pFQlwyp^O?mwy0h[Ƕ"=ѐݽ{pM"{1|s=8>>5C۔g!r^x/ݻW^ynel޲ 4_0ܱ: a`JlCĠk3$¹}%bCcF-bBAZW3rj C)*9#R2_E3rāYauz"jٚ/ UZ-ؗ\@i!rPkA2WseedNGLw4LIG= Fj T)k}t,tF_Kc7(͇fg ]0̎\&x:Q\['CHM{kM=W$-@a7c0$1OjG:aPdjw!Z=Ե=8,VӌG=|~ (0c;`;){=(VQ) |6- \|qtt7oΝ;[S=]+W.{[l!7A 23aͭSxUsSr5VQ6HM^,Y:57Vkd{Y֪<`JIREr}?xƙ[|P,<4ꖠ-kU*mQ _1o- r&(D?{fz,Qd'_ڂ>ZZ -תYCekgbV\gIM!0}n)Vs OMf0c[=jh\>R6΅ M׮]{C)Q/>a&8ַMc, ǯ/C?4݂7n6%j ˎH)Ν;?>k A 8Kѿ)+IDAT_܀8s}1w}^nmw)]YŠF#֊7|Ç>!|ĥKp||<28 Κ*/^79kWGC[X+8xAD{a_6zVq\F|2luOv;W4 ʤi)P(0H=g.gT#B VWKN-MB]JmD\.qx2R^X7h^XZ"u$i.}PBׇ@D7HZa4]1"iT(i8;Dޞ)5$-Ġ0M`VoȄ F7BW c"uZd Tkkc#A$b6,tP "#\j"G/G;ԓX&V^>z . FO>7"o4aaOfY|1o]rI&覂/g,c`?ED>62YSH^~e<iaAk,K}rr'|֬p#O<a;WⳖ )|PxfȊNIfB.jebNV#(z .9 ߟ_IP q^. ښLCkB*bXt"õA qR,X:W9Zc5N`h:NvfR*^Bܨ֩Y@N0h(T܈zVoeBy>D5en\-N}#JiW7P*AT& 0r X %JWŶAqOii#ObwIߔL}#.8oc}o('7cP!Mj%^X^;_?xR5W^y{{{^%0Jb}\Ig(};y!V}w)]mϡy7`옂6OO899 VNOO7  n _,{{{y\.q5?tzyt 03xF֛ϼTXyi9d5Y*å6L^ֆ+^f[(1^ "qd2$6 0Hm] "`aX_>P]3'RK ާ;|Q80êOaH,p8[k-[ԝ4O ͅKo풾6L2aMő־^#9'DcA!&e5zM6RlǍkkF\SH +!;JPtyo\"B߯{ÀױF&x}OA ,Ztv jPO׸XkXK3ʷ6>w/p# z`f  p#`[h g+6Y^DcM!9`[8<)0iΝ;xct/"McL3" sa\:Gcf;qډ ?ST=kíOZ  :Yjg(#vvRZʀeRPr 3$T[&\ΙQmD#=5*~{lqG9hc(}qkY5hz -nd$;a\#@1#7e9yf]V `iJ)KFbQИ嵢.0f;#H$r!f0F@ RkTCvZcVcW&~"yȚϫiCWXq\h?a'Xyob[z9 @̈́PJE+t~9_g8㋡"o/m@$Mc1'cNa>!0mSqmAm((q^yIXgc UF .w̸}6_y ̥Ʊ>S+poo^zx/j#I-^?U+5I`YyTUkA)R)׀J4HI,1Pm*Ct ڞ!%U VZ@yҀR+ړ[-P+iFG6F}?5mw X@7:E !+Dw@ W(qcR|u$LHZ@^z%?Hjc1mowrϟk,N.} .`[ZgC^wEC0ԬrP9`'+TV(o@$n!Cs@$N6Y,xgGm#j)ͻ+ixu5b75q~^r\e|D *Ѓ֌A[ ܁) "`inU0h85I>vD 4ƞ0~3#' sJ s39P@g[K/xO@@RƁ12I1f@VR{Sa{J cmh*]MB~KóFEo .NbDXMؕu@ k<}S6NzgW'n b}U wrM )$MNjTኦLHV0A}Rp~3VQaM0k_p@N CFU@lw!>;Koo[, |3z Sokk,K) `}V}ƽ!޹'wVQ'Xc?g̥Z[ֹ~oǒKGT8a%*+nΑ3bBcdž>zraѭrj`ax^as<,p eC_K5?)<*rU.&Ι9z>.{{MX v@{+\Rq)+PyA=lKeuKBb(h^ 9@v|gP*DRnqqhoTArr6+ QbFnR9*I2f$ބ) +U/wˬ1 32ck!Xî*aUINA}7(.FX'np ԣo FJG> ԁ2PMQL}a8?82ыҗF0#`[jU :+=0n~QT`{Me<>Q?W~dd:ǟ:~q3TxRA&`+=>?Xqr ܹ _[{noqՔsS@sv.2Ut{ǰQA[@%΃hY>(Cs]yh%󔡄\[ħ5JixR15%dJL FΩDzi/wbsL%S:PcJﵖӍL`^bX{w9k<7Ey;G}Jy!37Ht*`/#4Vk2)"ubx\=PP) 0(K R$j姚wezˏ+n WV ګ Q(ݧGAy|Tz,hfE%֫S%BcO?OU CxS|ۧx^~~GxSz+V}E?4/d,SDѓ3~l⾛Y ,.ąD4hඟ;JN);5`K#[yŌFE"Ս[F?XYv]DJXM)9{d  rúGA#ljƑ݋;HeFb:~oEӟk cVoVt܍{6o@}P7?)М[k/j5?UqwޞB-j^G?qmsAYp?}=xی].?~`6WZ >Kco! +"0-pPYʋ'd-??\ ܹ_phwo㕷OWkzV'+qt8Y1J$!CJENŹ Lj|@n뱷b+مghȢ7-<`<07B\ARS'n) m,(*wP-AbMEL`8OIQeFMDXߡJ@E>T+T|GKܟYYA (܋oyC` w @QKu<9upêb,,uf#kd/RG =._l2*k)E˘\61еEm JDӷ9d`EBj08*::>B9z (4XZRF*RaQY(K!Z$J ?/;x+8%^x)oPP/lڥ=8[a TȲ$]'g% eTb+YDY-6<{hvayś }-8l 5');"i|߮˹-/ưB%$TCQ|zdd Rۋ S#| :G9yzؕFJSbjV@5#FLU!^n`y6 J 1(#Zh5:9?pi~)乃P̱S҈fP[4A+`˕U# GG/?On?P8{{{쀔oo֊ς#!0"H~gv~osVG~&Nq[ 5fRȦIJR 5(M̑;E  p!@f|غG0Fck a9C}iQpKxHvT5$lp^i_zcs4猂D" &qSDzORqKKyԗvgXƳJ5Pe\R'O3(SF5%},X{@Z5{'2(ƨl>Qe%_{{2,|KȋVG nC3EĨśrÔZjn%o邡`H{ k{mD8ze'xijG> 9"- iA ISf"S`ec8 +!?{fm?ŵŷu6x-w@ '*4L:ŹaO]{TYaR} ?/k899ٚOko??9")2ohMDuΛs]a](@gke xBӪ{!`jQұ3U ?"jpx*_:k'EϱRFr c!e'fhuZ2P=B,..? 2lMI6Hﺮ0-PE+,qkyd")7|E R?w0z?xGr״g \p|tFƥ .H:0.]`[91t+yƜlD p_|K+I^(M9ZU^&TRQblrGSj(c{wSo h ^rE)25?JIPq"H%ǀe<Pz~7At MpIi "HDHYk FW {i(;_ŗ* 0$೟,J)d O0ybkS"ٿ CU9ӹ?E,˺?2,| Ph$żPtBEPVETU`qypg=0=S. M6B))ڥ<"8 `)IUirN hK2| 354CsvvrLSj%][ЂlMP(I[ptژ1YT FrY+I\){8ػ_ᛯ/0p,EH?8<<3Y|mv lC.J|Py9Z X$)#-,3mp{Ԝ(le570/B6 6CcF 8H[x,55\ D]p6btRΕoI-tO!CDFҎl()\oDhmxqc{dZ$.Q#-e9K3KyƂ#\AUh()!rzu_ $lXdMoF쭱/_ r^{[x_klC`,+Tg,%29&B.ĝ+7H 4k-^4ai*7bWI[թwXL9]~,O Vhl-JR4͘0*eZ%~(e^'ڳIO^G.U7zAh.4fDSd>+dEc+#ufJGw]K2W+DC*zbNg>RO} .]{8֏6 r>a]uqsmr^6V՛ߦw Jw͓nDy2?< zSEOqԔ= M& a#Ee?!mRF/NLgCX B5J^8c0@ᙻiSQVn!l鉬с)%6DkB (TІ:f5B:sZTXVAfc]$,U-8X,;+ի+)ǛgU+ko@s䨶W+x_-a ^GZ!_y]d1G9='AعbEz՘`M5Ornz((~KUa2(nVH"Bo޾-`nuu iHH$e~%w`H$f' \J XڄHYqlXgmZџx/;_*F4ӝx31iW$sZWYS,V@02(!OC×ZFEdy6/5~~ 0?˗/BmΊ<뻈S61u a-r4e8{\#&K9&i绉FoXſZjoX"YPDpI@Y pyy.b<. t#3S::jɡBr圑*aII _Q- g]ζxx6XߞBʡB6g"t$QDR8bV ݪR0x薸ԋs|QxoŷqxSR[{\+rKմ1)hmr eT ~x%JK\U H)eLN J] Uh~ֿ~CGo|]ܿ669k!$"7d1fUܼZtF*],x62r*%TV|1`uRZ9'aQE+EdP 1rW c"/EIy3cRSJAVM$kNb_"k i/_$G 8,%A@̈qC[sBlu,uR]y |#@0$`ſ#羛6w.ֿgۼ9#kW1 Q+,ek-uv' ?LQaܾsLU A8V -P>[69@|noX*UGV3l"Jym.6DiW 1sK3DTw%6G$ ɂJ)ItimT7׃$ 3oiZ 9אSWNKY@fn(T7M V$boف 'Lxe|[50iY2@6 'YΒ.ȥGR e<ę]ĿHHwF+|N ctIL6R۟Er߮pr D0 ^86~3qm,&[KXv VV/=O@.\eY3t` $]cZ \ &%?,Wg]=f:__իWGc`sa ox?,EGۮcNo]URN_|]Tc.BJj)2b¦Xs!`ʓQ 1,Z?@E q#GԪSm>b*aB*B1 DA3iIkĈS*[, ۗ`|lcR Jb@t>q*2>NF d-,)UkHDゎK=G-F93Ch{H)lL"We2 s "JP5q*)ՠ!oHFFɠSZ1 AF#:uA" o]@ZD1lAn=,yk8'Tqzn\{^鱿~zz ~< GJal 'DzXd@!N$E40u@. ^H J W߸wYoՙ]50 _+~ئ|<1m6% `r1 0&-A&a &"7AzF^a\!p 5̇!{$A"m~ 5偭 #%O\ v7,u@-]5JR=4Jr~k|&5_[D,$9TUz@"9˜ApX+Eբ 4ֵ1y_?c( F½WBS p4U{?{2VOdS)G[=TҖ^;}1  T J{s(qzSUb1 In 8Y"ih f} '8p|*ʍXvEڨ~_ׁ֯rTOA<`F< k'XUFj 7/|?~ME:Nr-=Ƽ|3G}tco,͵P6Da l m|6gx9?EVӟn{ z@s Fqz[w6̄UdtQ`Fm3aJ?\G7@# Xyeu i,dxL2N5DU٤|#UV*z4_玭Ai.^y1nR2r ړrRM[x m-֘€{aPڄk=,2jY{FGj=Һu aj!Vk A hu)Gm?O'㴯"^܄yYx)[\H#LYc8։NW+ڵDUGGKTo"#Og$09{C慓 0,C zS/aq +[HZt #6z tKS\t. >o74] d<VOix @QJ$; UF. +POn]| 93[aW*{1}?RFܖ: Hwm9?;yBS rW\ިw L f @,TYR-hh:/eSsJ?3Adf%UI3JDZ_t˻T̆1ǫN8(, 4;k 秜691Ȍbs1MntCr|+sF"?$%%E -E 1Xl$BZk0/Nxzh޼- Kn5 /8PgW)YꀌjWچRkON#y=MMڪA 3_o$!qk2l p.jDm\^~F?e|!]>]!0/ucQ0mp wz"u1?7戁M~QҩȚ1#mT1o'/(|nb& "'3 _k =v13 r/E̋sq[\"5CAs[l=@=$m 3 aM?gDx|<|#8 !] yݣw@W>kdCg aĮk[2{a2YuRٺsF.M]u"`r9yX'm|Ղ@}S@ ,QNO$KJ9[w !>,k @8>c?+ݗ⨗?p'R4qbC0G]nC0 '%UeZbqqmZ7Uu{vHԵJ  &o HIfl.`c(LQIkamZ^01]},~/GO ~_}CGӳKt֙Je0R.] 1sa=(w@GF,3R"̊<lOO) -|9v*\xbH 0T6IgZ\Xv>B" M )p%-$/*`AR"}1o9S=W^5-LC{fB; 'LYV*2ȅ"W7_o}]|wun>2iN뿎KKx'H(% L%rcN?\wfg(y<]q~ kpo @2 . {c92{η]0o=E# 0J7*AEKfތQ< \ U )-C= *ӬcW~߶cآ~^?b SP6B[h_mijG){S~̾lnb OT%4g@:QPբb=vgQ}н]^-Z:ʤF+uXU7t+Uz5cUFMB-B"g# 2<+YXU劓ӓIVA[SG+{A̱;we#~e?AP͙\2 <˿gyf㷶4"{>$K0Vsu(B)`M߮k_0,p#9Ïǰ97amH]&Hg͎aHIq:J廟ǟT'P!,YLPn0*P)qB+h*!crC)(DJ,c2 KӻxvAeB BkųGOHfVĜoW?i<?_&^Mb{F0#h Z*1KC|v[H[$ a)I A3Nf4g-})S6K Hwjl35\V[MEYa6W]^Э^geu#B70Vs}++4(,3ZI k4 QWP'/_FwDlnD`po圀!0NkU-oKz1n6E-Ag)Xfvw w:7G-psds\";Btm[\QQP/? scyPh@*斓o2؊ "-w"AXx9v_ A9B0 ٜF:UjIuTT=e_@ tDrKkWϵx!#J+l۸0o x.7O'8wK^xx}0TJ5(HaT~0 PG'i‰wM@^uuM*ؙ b脷\Щe^TJKm91EhU\Q`30(a>r-tT!/FΌ_CPHɳSoGϱ9~vڄfh@$)Z( )F,8HjT?E9k7߼'16Ř|בR//'Ps)`.#`?O!d&w*&yӜiӟ9Zp^9_Cjd66BZ3Y^H!xo[ӹ6G1&;%j3UNR*nۿwcC4+ޣT:5M|CXX\kcf>d"`XbZ(#gY+RkEL133nNVt]~1\/0@tm(i9)[O%>δ.K>>8?;oگ-HhhɈ J]"b Mւey1fj"7zfEH4%C6ԣja:_ ;tƭCiCaRn4߿/t?0gk߆"?gz*~~ NI1%pLH`.<1~ۼ{?qUoo p.oN|ZјOr[A[v~57>%ЌaLA_P| }1r:M^@UGOa9!~ }y%?,?@Ox(a.\%k[੧_ r׆]Fx`szsFTJ;+`y6cU:Z);uG^ Q7Ϧچmɭj!zFQRYY'50Ów*Vל`rHS h1v&,^VimWuj2c5v D&$y("KjL֘`#kY|%N.a 2>K n'ɨMA!L -С=內@N[6Ȗ#f- $di0׾&T.ze|Xn8%)ElXEVE F!!y~'ѐ FRA+|6dj R|5]&.%̗s7Ə[FfA,b; u@QO?~yy$(w>1|2e X mauMZ.[=ݗmZniM ROljof̄VNLD(x~ kn_+k/mnheAinsiXRyghCNdv)z-҃Zȃ^i^>=E(le  Z)bh!( !FҠi2%Wd DXv& !2 {<1UMA*;4kD # UPe^-ubN0:!rR[|XOsѠ"[SX2ztfՊoLdZeaVI+ İʋKX] 6 @eƏoNLo|-2G }6 F2{"X=i'PO 5Ҫ SQN? ~ƻ!pbߦk~xguHǿSw MboKys\JXWXH&hc͇FGpk 龓9a8LPcOCv)@)#Dɂ5OAe;<&⍣Ge%0l@9y%i2æ4[4;ωgO)!C*| +zt w-45Я) `}*qF>=!=N's)B`5 ec Dx}3<~eRv7oOfm0dL=$RR%oB42bxSS5֕"ZJVxE&eـC*L9g08QoN1qaݏ%VӿKL0 _kSjp??ԥ۔2})h0/b+ײͫ2>`4.Tj6 RQSnO<,?#?h7܉<~~?{I1 9C\ .<sf`))Srտ^@׌x8I3A Q-([\_eӞӐhLsCP190XJ/o/5/nُ]Uj]PAXwИ iYosʮ)gI+'{3(s/A=miC[F ֎crQKյ*LkB `}j\O|qW_W/1ʘ{$@uZA:y$Q'83wˈ{*Upba PJXj tɽŲ6;XRm |j@a}ab^B8 *#9 &ēz {3x2.|*!unSP@\Bt=՟uB\|V|w={~z`BC_D >0m.e럫"8wm>&WUW_c:&QFkoӹ4g&~>U<>|6T~pyN]l[ C@P5)&p< x_Q[s3q8D=)KPbP{h2Re)0H9_ EЀ4@ ʬeJjǟ-ƥD]ZmH)E,oz:A?eKA+_+bd51c3A8H ?1H]k 'wKO̓8:Ub҄?eoS0!sFYDq&1ߦwS+ooW#վ_coAW#Ok&f9 L{>&vi Akjy" {Wl>r -r'1Yi^rU; Z=k$2ine [SES(=D:8`Z`' #]1y!9`VURj.Eym-M>j_fF=[o'kC9@OlvvsW[j >7Vi+D E-U'E*0A}0Z[`Nbr̵1qMVC-H@\Le!`LC#tjk5T\PM R0eC.ژqM RIS'.@B(0ܿ??(߿k&q^z="Zsئxo66C`6?2}6>[xjS4's/*話DbZ(tO!@wDn-f9" l!(@[ 'l\C&mNuj֎Pi Ԏ*ꀲ>?~7Nvgm]~ǐRBM朽6#`M(܇` "1Xw)sF6kwůʯWp2aUj`$$BcxQ -~^ǟwm~h6AZ(`mé+,QZ_<\[,?jfoعd] Y;! eК)& V(} iEIɚb yDrrlf~$Jb<͐)Q)00pƪr<^?A&Nk#CV:\c_.Gp_㭗4@-jVFJ jq<bh?%`nDj(ulP$YT8<RRAFxV Rgbت<Hw+O#+.qgXAB>;3erQmQl3Bx 02ȋek >^=_klG(;Q|?#?➱)|Sycwxؖ?K)޽{_5|} Y{LK1& yKq~>a> 9? N.*okZkx35\UUƏQ@ o,>0L̯ƨZ&0~K4'}Qr@TiiԉPeMvY!J:)PGVMۧ`6bF)T)՞˯"![İBx2j%Mg0xdPO?y .`a1X5X $k_p-U]K5\HjJu8/c>_w1C`.q%?'qppj6]FT l+ tY6~Q0]n}uytt~׿>傰P9"m$43*wl sV.zMteg3SE'+Hz-]Jx8ByZQvd _t@:*HLX51@KJ`sFFo-HPĕ `(-t#- ` UG ʖ0NbF"UIZym宽8Ii0B"' qp4$,}0~G)8Z|L-`c<؂+8 (vlDA|>!-|Ѿ4;)'xmFa5V`*1>HS% PWquq𥗏-eOO_zvoY#J._? 05Mx |+_woVD֛2E) ?g8o򘷬vsі`>Fƃ V6#Wx2? egRT^yAgCb BT 0q=u +3RjT,rgξz >fh( %Vxt4)W I'v??3;$n%*~D`8gySst]si~qK)²KMv4PxƤ&9v(Ѡ=SGǡ crigF̏FRH^< Z♃ cbTrؕ|'%gyspRB֒l/fK$o:d͉"=zoĖA ȞePY|.'#e PXn j =NPCm0tXP^Q]F#7| gKRėe@W]00ɻ~o)6A Iؠ5N;걛#-dЬ<`(!RDSwXb!&KbMCNK\0Bbi `duaQ3%|>Jg,yr/](5L(8أTYRŏ*-S*Tr/u|_? /O}SwSW"fp޸ߜ=+o ?El[t.7EuT2wF>ېQx.LRX 6;Q6f .ArJK<|ݽשգm",_k_Q'ZV-^?BʀVw`Χ)a k 3bs5T"':N-4 {{KuY$lRz/$+PVtkt}_o;??4n=z)=d~h:w# -I VJʈHy({ԀyޢoGӑ в"r ;10 Lkt~0 ZEiO>u|sGe&ьgy#`й{Ms Rd(6֭[g>o}[[?,r^qtFF#6mVbdуA)Fdx?n"}!8_EHzjYOyuI 6i꘩FBb(QV rݲ xˑv T*:zdO&FɚWz*$f1Pl- t%Էa x}//&G'w@=7ȃniJM^'EH|)q\` ` ؊,A!ϗ5h&+Z{{K~z-5!j~JB\t&XZjAFIWKH61fJy2Jypuí^M %7͂,5N[T$"|*߼5xOܟ>[]oϽ˱T  (H EQldCv#ÎGIIM P 5WeUVVo5}λ/3+-݊=g5o֣W~W裏JڡN;qJ'wrI_G~v%krds["۶y[?-]l+HS{0>T$MDJ? 7b`|k ϱw&`7]-^Z_IU?J P!gQ7Q ✽]b隓l( VcXly5cUa6_cI nf )8/ Jl1O<c8.}pabm="f:w&y{% RxYMGfk19Ԧ\}R [HX;`MSĢ@6FH+$5RFa0s2#GJ=s]ͩ,] ύ!< -Luz~@r_Y) @A 0B`GH79|#jjX_:~a{G8V?IO n cۆh\x>wr! Pt gu-kw[fk8yḓOӱR\zgO'|&O% [)/i)!_%UiWrSu9u  ʱ**)/3YT4)%<$zR\;k1ߒI2pҎ2 B)EzֵJCI&'v Z.<gz O= ;ۖǾݽ/Eeu$r&`WJEĿ'l%+J^{[>tF'"RƀeӫEQ#Tu.d1LeTvk%k=:ڭNf FB%Bm);t'qj@7(2콝a_ `"@QU U&>/'ZW0 Àz _q;t[`?[9[qN{'o~W^X-p:G~h v3Pf>_&{?~ n4ۧ^2 @~C!Z$c#a'ѿ[|v`⧨)RONAvգ/k%w_!>D8V9^DO)?!B(,r&}pkT%qW~3Z@1.oh[x^'P:gv/&Dx _SO>1gD#şwzq28hJ;N XN {dl ԁ&!(LbBLuX QGVD)%S)MRm;Ns1ǨZP  [4Y dͬͤ}p'mX8[PP? '7,~I0DpU 15X)~ǟ=M\psaXP=YpIA[;[!'N >g/yvZFđ4g2qhhk^z4;}4W[Nu?_[7W|jZ r&*g 6n=Cjb̺ 3ᵠaOʝE%ځ<lSYd[f`H dM¤렭ɖi9DC a f2y"-pH@ Sd;DQnhFHOqΝ9 cS)NJϝB\=Я>$E хO6  >GYOe<֠ PK !cGj0kw=\$ȶ}'*4YJSoMU8h!!I-lm!Vɰa@ ۱}pa[7'A}ŠV(sl[vgOZJAϛJxcV"}|羊O<~g>WBm8;]_wmw;f~GUֿbxAQũE~[^7A o퓐/ }&u?ϯߋɫȞ$L(ӫy36aY]X3Z CbF^ǬvT`QչͣAm ζxZAySʾ,p LU2|c a161 tD\+@` )!8z[G'Re׭gtqZ:膉ϢhBU@\4TUJJ |:6/Pv\79mB~D9B)<9c Y$d5 QlRJ:diNZ۲[8]o^Z^;7Tyd*?q(F2#|x=ܹǜ]V &ow _/'8(<>ݬŋַ{ # f?w$3w 'vv-޼Җ-A϶#YbBE(cE rQa@ŰA٧uZIp60#x8 AV[<($-@c{IH}@\O aN\ 8b>7v]х'=7Q/@y|xo;<3Oa Tƫ~CqgO^{t=0LyuD#>9N~؏Bc) ZˮlX,hDng$QUV[FڏC6tv@UkTPY;( .ݖMo ND2mKe!Z0 ?A٬w us|?-/G9wA,(8ɹmww;`L7q[̫??ŵkp۶fܢ" 񺤎)tۺg'[20o! ɶز}}bvIOt~lO}@seP8cTJ1#3YrfUr\]!eWi+8rǪD ukGE4rΉ&ۉ,c@mmX)}VA^o?W~?$.X W1( o 5%_`mmؚq.Bl8eMy 3Sm$ѡ΄/%+ԯ [5 /4F8qçm솉@J)* %,i۠c޲׍Is}8 3r{رsO>kAgPrB:YI}@?=R SUP"@%3x??ėE<쳞!Lk[-;w돝 ?lN<q1\]}{Pٯlsg?޿ Po6|:{nO靓;@ KLK.-у:\j7RF@kF3J-Nv´C" bSŀ_䭂Sc rlFl`L UP y K%5j# qf`<7}:Z2hsX<+#wg{Vq )PlI狴ZO`R AGQBeP}NWlw!E0O-yZ-ci˥Y+,4t'q1d@<+# RbfP$9!˹mALK3v@t?02?'"x_27NGG[t>… z1ukd~IN;m?ouyo&o߲v=S+\:/6 ڟ;tll?۞7{6$`0:wRMۘ̿J?HșGB.F+$#bx F2r;B i VDC@wQ6r($$@bAVC;Zxy2uTԷ>A`9E@ʜGYA3@ mڟ&RIBC#Z qO_;N߇n~]9_/wsq͹fBDfؓoS ZO ]YcVfh tjT3~߱1G5jwRh; G)đ5@I]co^z˥3{+[oN7@Łj" EB@ ~c_{xq%>Oɐ[mk>dssvppp}{xZn;;N',8[Sp )||M~FR׷Rk.=i;9v9\[5NIDATͿd#ϣ: B.L#a-q/SQ!KnY [%((b~b,w9 u mx D?5`,0!6#M$@u갿PttK# HeS}KEa+nɢ:v%nGNߣ w  }"m5<]šQZ>骥 " i+T݌hP։*়.讑LXK}HVND6&v*K)BTd" [2UĢܷ8cNm~mz ~bR%s[ sH3~cсVl(@hAxU" BP U'?^pG?9q5זA;8x/???s[xq;*}}wybElj .}ODfH6m,2=%u8"ȝL%RSBjpe;#ֽ}cubJ- q @jmpP K~}w%\  J͸gX:Oąbkeט(.>=Qg g9|9ܻs` ;I(c`EZb$*,EdJ'y4cǜԟI!!paeH&+Lk_+t䰎JDs*+/C'ksNqqajNwuߊ89g ȃ#$gοCȜh?TFX 먵^åKO} =Μ9s¶Up[G^{X{,K*  aX$EtHDH F,E jDfX?uT/ %vyq"aYDPn(JP}L{!!`/«Q$85绣C9m6A1j "~M=Z%JY- !bUW1$U@g93b щPV_t &݆jH,,R iɧVjJ u0`7~"ӌ36:؆twms2qCx0hn{9w[Xߵ^?dGh<G3@& 3ƧpKx#'}{kg}< Ν;$';oܪ~/8<Zz 4 8.pAO W|LPI~\u.2+h8ɬ1F2++T̟宜vĶ(sF(PBБE-fBC) (@鈣ƌY"1AC|xcq]phk#ʼnC-rBYkˆo5s@'v%P kjT->ag`6Pא iSqۥỳ1| >U26QoZh u1=Sx1(~-=f?y7pL>+n @`գ1uj Eb dβ>ѕKܓO[OBxk駟O?3gss'VyOo޼z ?q q`Ξx-Wͪ&زoy"g?8|? ߳{m-mc޳৶[ᗬh>:gvN=V?B ND6+iSaT. Zl܁1i9@l B)h! ı&/! "VK6l`=alqD:+_O8C8j (nI} \?O@*xy Oɭ`ݛfY3[Xe#'q"L& R2u Cm( &jr^XьO"s 6QaB~Ut|vַj[jEQa/V8d$Qta$o}O\h!o}!ۜ]gێ i+q@ M&lCoTc6*8Vnn2"_%;coY[d-\v ^z O>${1zt_PBYT>X7u[V']i?y÷?G߿dvM`W;ӿ9q$P8CDYũsHY{B'ymͅTV"*9,C4!q8nYk@ -&z <8<$p=v2voܸׯ_ǻヒ7o㷂*_.s \Z@ skFhᚣh8O?-BW0{`qŸ6 *u?ͳa{^9O`Ay$|ג%OSWNPb\R6t(w/f0үsA% $ #5֖.lP \ `@Qr rES`_ ˷^A=Gb-Nɷ'zdm-St-N~SѲ/@:1E"#J(B\QIovGQ` @Rd@A_%g-4#B-ݔ,fn`w'ײso9Pw7''6?f13f'pU`Q6o%R2Q|K'ûқ7;1F,?~!~Gs#0 H)?n`pTtY~)8ŋx"}\zڻfD!4uEG D#uoYͿ2a;X=X}ocyIY̝b?!&&rjACP3DM |ѻ%GFvHo  ,wͶ+?Gl2#T. yGR\p. lJƵHKg %s ӫ5pA"\*Fe"Ch!M.X.R5`DB8Y}HZF5@:^ 7\[I$6xXJCӫ;wړhR[_ow^wa~:mec_rL02@Pl0_'?3oǕk :4Ayzk`f,K,Kw}x'ӧOcoor=9v'y`aׯc7o;#k׮aZaGf n@$| Z sN@gTNDnOWS< |7r JztŸE3"jaxױ|bwqfe/yٕ,Q&f%-dH Y2H PNJTё%!+# (h#^䵥 z\Eȉ>A"SbypB\IHy-dݮ2}73W~!\?~?دU@3 T9oڵ&YѵA!P%)L9I{Z/! R@$ypf)DNl40F65*=o^,ŒvG llR6g'Hm!"e'~۶,gI/<!xLQ :З:, SG.Nq6tܼx_{S/~#c~7]>0l^q !8{,aߏy.o>Y63p\r9gl6\zա鵺7qmvw>ԮG!/mkx|Ϝ1d`gܡ-͹*)6@ _3usFs@)@ |t琟{NBKjW.n=co\*Un,{o@ Dg2Pp)$; Z09Q4UبfM􇕨xՃK"̌+\_:Ac9;+4x] wq}~4!,Ç%4ٽĵfW8 )I5j"YjOu|? ` "7c/V ѭugGPHGÅK*e: f1'9g܁q''ݖ?Iy`n+ Kv(w9_ 쐀`eI0 G}~nw'Rච&Ξc`zj۱K^߷B{`ˡ\@Fɷcop=EtX^47Mڷ= X&S:3T?ױyX:+W >bl֊D{t^&+*Ljg $iL!\$bY%gေ$}Ұumic {U9땝d%Z 6)`;0$TR #7Ybwԗ'}E`4A'ᄒmB [}dԡ1 |0!}*鐼O<)%mo w_^ieV5oo}d"j-8\rkEZ뎗((8:qyXfhIv nYnzZƄaPؖ1m?_~=Q7hcmH:_cwC4T5|=qxxJ_AUV+38wc8jztQN`p)ukV폟yt_om2L4$p?i_K1 WB) ~gqÃa"MNTPP}Dot==LfDHcjmp`Ĕ A,lURBQQ1f_M7B6R> :( XιCK%888ڀB"%Q%\dSR]naZ5bxra:A%m {]"p: A1iMHfE?_#U@{hkL=JުzQ-XuI ђl!JPX.0,TtĔTe*xolQ"!5PGGN=zwOݢpӺچP~ۿ;"ly1{˰gwi d/Xk !VW.;≳;Ùg?Y9vd;͠]^3?ΓK5=GNa'J%wcsZŭomKؾl]uf;-7_*ik$>3vc̿?TKbՒN%֚'Yqz@&Jخ5Z=@6 "$$A! R3* ?Fo'˻Yۓڝd?+.mh^fA >h^zUwqjP).]FW=dO["=c;(jjrc'}#;El5,'reQAL*/ib5 1nFC<*rIׄi ON]‚kժpu,307'˅3IOr[>$c ,М7՗fm\zlQ,` 2b>p>o|@-z$mCؙ9s>Nv;n[sߙO>T'Sgpl{~9[RFݚ~ns^cn~ &S aD‡g>O:理dzQt溈a3]6^cInsKg,"&Hm<(%W+A(Zsu,YNiNX"( p'/ ڕ,A:\q?¿kqsp鍗]@cmC`';W<#r(4bj" D2EI@dqu2_Pǚ2"u iSC޳r(:OWU*UNPEŘGUuxQ+!, H|.V01Uhپ6nUkm1Hv`('SkN7?\0U"XjuUx"v/7/޽Btmۜ۝}ֽ? c x&eט#9{̦& ٠=v- B;u"f8K%x"ՂňHd vy;h*.H(BZ >}lש(UZPєLɯQrQ>U$B+(]k -. 8+B%Ԡ5cZ,Zݵ+@3Gx<ҹGG1\{ؽDžn8YvK$ fWˆDvn9v<#m#1!!MySv~ˬ4gg<1 BQ%2F6!G Z=1XG]~W7}vd5ba-wM;.:v|y+e~hvF՟cוz>lA1&UPdPj@/-rtģ?76NS6Dv۱+8z { us ҂z{[4o=AϝetˏS%D_HjodR6HyWQ/<2^O1Y#3t"OTupg=m#g65vɒݤ@U&9; J^,"uh[sAYV.1*)?LWTV@WzR4cB.&cM&^%2u[8`w]Uݴ/{S bz^>.ёO2%[6n8}c-*,Z**R4K$C'f>{Mp hY-*LAzUwr%Mi@ઐS;.t^C87@^K/E[ISg؟WIYIEΏc}?cƲZݓ:E Pôpt萠 PQ7=Eʔ=*- `OD08;ӏ (ebپ=alos}>d 8gWW Ga5`~P(u#-1"c $P_e[NE,ZeФ, )aa|Uųܺ*#@ sΈQȹIB2.9b{IGZhQZ>6ⷿ] ٕG W?7/!჏;G_Q3.=p}՚! κZ%U,jEsUh{ilMw:l'jjL@85POn"lMD+@95ۄ`N׈:<.BHdjO+H<55u}eu20#uԍTNVHMrzcNv` o[|[KY0p,OйE 8V?鏃 ?KB#PP7+]/O=/>wL/*̃^p/lG`H/<@5k/@m04ljҷr֖q۟o?(}߲Rx/3bɢ1Z֔mdMsBtz:>aThb@XI| HZ 1NdR rc!AN:Mhd"jfTR v#U}f aLQIDhNGQx/׿5,pa,.|pU34 ?=!$Ԫ 2 ?,BZ :i"(1b\Prߍ OQ1['@1ev-n!D@Wi`ktیHa(6p *&Ȏ6Y-ؙ]9ɍͶfvlV ) 0yft9ϲ|T]`УU@{k`<:{<3᏾wMΜ 8 ﷺ}I:`1"5!-XMɸy{V8!㷟aW 7j?gA q ?Y~$2g,E >;7WF~YoPjvTB`A>2#ZF1YH(WlQ:( "@1#@TdkRJAyYB01 )`D~qMF`n6A0v1Ӻ'gy˝%jp!E<ēP˻}@_`u!D2# .ZnF9ހ`S6HR! F'N6H*쁴UXc28 < !!.njHb>|>d=p%F:S638}f*u R/jveN0foYŴMf5{{=MڷOúgs!e&$Q<{˄Ҡ{xOP JIV,L7@P֢ \c |a"!`Ɩ+gJ)q,9+Q 0<N.PMyU^φne" Vqx_K a}pW>zt4bwwi*( c^!KwBd!1k*V0\H R'7#JB gh $S'<Ϩ«z }R@'., >_[HT=Mh` ?:#*d$FPkwHx54`zC<3[cbp;^ܟ,㯙gh%*Ζjq?|8Cߞ=y% )x`د͏*9؏6R}X  m-q.V_ܗŽ˵΃Z}l6l63L?rKiPJ <(X"ŊJ$EǢJ ,v"*V^ ?EA Ґz[abj{Jlk]0H$U#hu)q%bH2/bcC^(a *&LYmk"D(p*rfPRʱ5foݼ+ 􋱶8$Eh˒Q>%\YYs? w`Z]I\z'1n>}3ásU0flPPA@@Pp폹QNL8z0;CI1aCXUU-H.g.!o\LK$mlA!^bl|ƙ;휀ϭu,VA1fo1ޢ؋Ie? @PgD SKA^%Rm=ט?ƿxlꚇG|)p xk Yںc-(ys*c@~̳~#u}6ɯVriZ +Nxa|ӸV/ #e*FQsSu" '>Qkl$~:0ֻ/eC`K). GKt^= {\"oFT*tjN"@(]*NkTo8BoVeWo0֫R`;#3Y0R"&PD'~?+_CJ o}p/|+CE߳$nn6 ROмpQ L~7u{dT;bPBQ6Nl2f\ؑmpHV]y:臺 3iэ'lfy "Q&ޓVĝ8+߻ / ټ($"NӉu+wJSZwZd~eLswV#z C}2;&^W'v{6] P^\tܙp$6@m;ڵky&pߙQK׌#P$A\޲{il?NgMT%wt79)ÿfǕQ7o50\6XX,cAg[GY} Ё3乲#*P+pÈ\(ɏ(*4`eHH[$غ0/%\8G/:~sGX=wYlZf B7kv7KYlu!i1DPDAZC^_t{ֽ ևFSv(3!4i[kfQq1Bq @(C" 5:(ub#XIxDj&C2fx͜o8}Ϛtmkgj`SHOJ U#Vk+v;ɹ!w{7oč7p 57;/q~yD?3:xdVui=Ox|?'|o#'ĘQVàZ]F%rJFՖ>;YVp $ ]!.4Vۣo׼j@! >G7_jAlā j % bLJ&  PԞͦG4gq}p6?Ԅ&LIb=IT >:pC֦$tV*֎ֹ_JmMxLD!POc}g`H z#$3%z]l2v x:=tUeHSd~^ë2Öy!v?WQD ԉ${/p@dmy AR%guLDRWHNQR\i-QgL dK˓YS!Ǣ"TkBQ8$c'W!FhT2u[pSi5AyFuzM|yc'٘zn %BL]11h@7gvl~Rh#-ot|%+K\РRzSƿEyVi%TZU5/@C;ϥ7 MJvI_ (TeN?W/}7_}8 Dm\mnS-h>;` Ln]pNw}ڿvK6{ֿ i:ء"ǎ l}:ks?̸zs\+ױ3g0 SYhL9c-w8~pMܼy?^˺x#vtmlY:]pv,mOXribud%.Fe]@ŀ*st%p3A9v'gԆNi+bo6h,( `6C 2hA`^U >%f 0Ďh8''8*O1nJ47^0 %u& v0%3)(%e2zm|?3ˀ\ȵ Av;}/dA Gf) Nז$d 6Q&^/C;^B53 bb7H͝PuČ{`S3OVz!5N=3>+o9.\# | *@ھe9D9kT;z,q"7ރ=!au˴9&dG|2~Eb@jZ^q5 ÀSNy0X,0 mkoi8b^888j89O&H^"b*^[2R<u<\,ITAr_ljLاX%5`D 7߼0:Gc袘Ku>GF}SX=^a2i }sjO#xa1#.!Ԝۂ"s6^z'/cpW^zˠ~*B@p#D~FG!郂d\ IB4,ĉf%AHϢY8@Gi1ibהZ0`%HA>fdh~NL {~ QGW]6[z'8yXiۚ\7Gf)9s>ϞAВO ꌮso ug=vgs^=C)aeL8rLIFAe%Rj#͌}nRrrTҭ2}qRٯkV+VcmCYJe0,0b`Uu]ǿzGTKt&'#'B틶:ss6@d䊥d;sbc}AT.m;_ ¢/TJŎ1rAM\_2 (>5ńZdV@ mh^yyL ֨cSćej9Vlh X۟Lxt{kx5P -_vRзc7+^gQ {5EztC96ɯҌC62nN3( MyȍVc 1F-* iFtH٪Gsx'0q朏'H5R2R3(u>|0ւ+ob<|?1.lmaIMZt rG Gצ C$ hf/S <,S@fVI[z_(i'" i0 QQebV_,?V#VG4(쨙Umun-*U[eJ)sFQF#ahh |w>rJK1J`ss 8"0 ߳ޛ9b0/9R䠄hm}_>%h_@7_BP_h6Χo0Ey!M]})t? J6.N>t%Plω]~ '@;AZjkւaнʩ (L 4n%6""8k dW$4nQxEʹ+3ZBU4Y`\ !%#R1 (|uYMPN7Uy* Ep }J;Wt?>8x_q87֡BCChq@g\}8fdU tI{I) Y /#4Acu%g "Ѵ ,MJ0{<~Iq}M|&•;"?)Ghܖ;;$ܻݐ5KPPtۻHCz_\ ȢF>o5) ,goV:u a0$&HL z-6wm3Mzn(/!i̲}sS>Y`8)D3E*>1ѳK2k|u# iϭߺßPF bTD;o{7ViĴ<t$Q\((R9y'jՄ %H( RjrYQ-ۻtS9"#P@# ETMDaHȹ 5vAf`yH)vӴz(Q>k6ּ,:d6Ͱ; )`{i\qgZqxpz6_Bau#Gj{_B'^k`~T݂u`m>%KüOPY !U{[~{AW+KW z3 0cV?uO1@AϜ]إd!X,7a&焠e֔wڲ~l[ G]k,L˙P*\ǿ(? sBg]!'aE7c'?:C$ H)5T#Jst8^5TcXH@@o?J?I8rSS(f U qrZ-1y`J&ǀ+ M8.E< 7rK88Z⾬-]I:햺C7_z~]<3_W{C?|^wyϻHpkt;6AՙaI ~`!IO0Zog#xܑNJ'T'9~mXgP[km#ښ@\$#˘e3DY&YA!"&,QH,&F$* [FqBcV~`e &]x#8d ?~c+X8S#`r(hp`ωn@O>d7 1OӵLƙuԬk& |-6~r ;KZhu^+ٗ-PVc.siPx֖D 6]d/Yyٌcr3SkEHɝ(ʹb! ub @*6$OM״䬆@4n.CK[ ~xGşƥDӒ,ҝ9y \K#>FoH{JAs P!^ ,tBFǤv-JQ}D{Z0N}NIu2C[W p1Q$dUOYH_tXxu,oױ\ǂ7ziMȌwuPtC hYco>/Y.۪ljZW{?{8}z>dٗ!]rn%GȮ{䮩7cP`Va]KEYY՝&gˌd\D]pf#OQZH#HG)@ج-2]j C[|ֆfMa#vVJ}9*8ps>ERFD-1,NE^~G>~by<*_} w{.EA dk0:%琿ft] G?\Ξr i46vPeH w2P!Qr_L Q/{b_21.ҵ= :q6nŃ\ƥ=뜥!>aϠ'o/79}sm?A:9O9Nb_²v"Ij"Yp+J@!D"IDtH lGm@-XE!A]l!Ǭٷk%3**jV6~V g~S 0F{~< iwv;o`~1ZXd,R(5H)l3xr;aq֢$h}PXD 6'k }Te.~)VEڠtHֽ4 Ð ň}Fƒ}X{m(P׭ A3* 6AH&cif0( hL5R,gqzm\&N-\ (8Ym G_ח&b>2fU\_ xi=XTm/c@ ȑ:@S_A!Mt*h&ޓ &C=LlZph"cRrT<@# y*! O>A vle\=i9A55 ufs<`XA.רy -y#\eW7#l$N?~Gu bspa;`eU7b2kNإ-VAu+Q* hțG%#pD}ݳA/Qsn:tz6"yY y\Y*Z/,;Nݗ& >v WݬM%&gb[KRԫc#hRGc5WFZVu/fQ+'p{ػ#}͈Z,RE2*A)Fy2BwrZqFvhQ6@lcni*f#R]Ԧ)褿HTeJa!D@C9WF,A}@ה 4B*,)Y%` QrepPRVϐ9r0D ^B rzws7>}7s7;:OO֮#ᶏ0 (ʧZ}˳$HI Y:~7X[  HG+?.3W@NuB'}gk#zk򣪽͙ϲz9s[&k%)Ղ VYR LhLM'7S=Dc[plqjWX3 яRGHwKK ;;ܮ|?tNZJ5o$8PܲuLޠx@SYԵ6O>KA`CP>d~{c=lWy A|Xb2%Yyw5~jjH#EF`iRFXN534w-A*ᐤ{5\޿7~Sz*8o%Eͺ= j}P({^S N@H@Z L9RHBZoYM!n'k VI~n,{5VbJɨڿ4n6(74AJ n٢ǦHh#y| ݧ*z:)%hLD 6Ւ6  [`dz^HΑur v9AZcXRǜL\ ŕ :z_/cwu ^.KԞgk[=4\9$57 LSu-lhF '^ԵwR#{zKe3\Ԇ` )&/dqF KJ"$&i 9ziJV6,s.%jH~bz C[9z ;$΢7(dAUJ P@(!B Wo⍫|b/·@AKyEwc EP#\+=@|H! aV"?VuI?'Ei!AV b/VaBִd<!&Uc:ZRC[,b[:rsE+9uuymnܧ#p^ݹ 20 !Af]' )d%u8/A0$PȚb_,Rq[j3:ZKPz`ٰu"qEX_oQtg#RHhjA8uֻg_ƅ;X|KXlVdB;}]+-ՒRH8uz9ƹDo}a5ڮzŸ#U]y=gFr@땴ϚɅ,{W)i uxKkm*B(cn'N% pyf6X[ H^i= :.}_ ?#t.-91eA1[_ 0BUBJxK<q"YzM[Du[O X魜c5`n5xihJً)mZMNbKxH2"'Ț  SP ÀzrADxQrժeb)riB.$VT"֓U+8A\+P{ELk*D!"<3_ܧpp?xusvE6XRo堗2#"mJ(c(X"jXm־ةcf̎6Ft1V?OCLU阡YIJC%U3ckW ьs7 Z;NIZ[T[* N.S` ^nj݈ Rvh?5Rb q$À5|0u|+8oG+|VH(L%$l`{'qey,c)m YůNa hAy^W)՞hPZZB6PD,MƆf vB7{d2V@ܺP:KeըWJ !RPwc<υwq_}|W+xo?PY *r!J""> `WWb[gN܆:E#_cQ a[ڕ-֕ެҽF03+8!K9+C\TZ[ 5Rl%9hy8W /ԒX ˼] }GG,7tBe܀to0Rk1ۋq{=GC%{Q &<<"1괛/cGq4x9u(E%kg?)I;o|Ӹ|=O#gW}G\jN5a,EJ77#{{ЈW`\ԩ4naN} DM7g Wi5AhXTkEEU\i:H7e=[ȹJ6Lc|_2GJa+xǎ5oA")5FjnߕgF(lmkbLQ`}lMg +742KHnoc 8P6dK!1gGya!Df RJda{9zJK fFB:<@J ׁ~| )HIpKڴz 7XmF?'v, 11@SxG3 {j?_zŭ̏qK@7(U:fOz"]]]86SjSkA GXo68H_lж?XjFt ƯxslY-x*=dvkU(.Ui{8V-&+:s4nvX}<(G*uXT6XgT+k1#)bPR uEٻ7;m2_wpl d.y<5h@Deښm*m󎾯RJ~{FpU\#}T0G"E"jbYF 5e? e&7s H ](\0qH)b%WKAQ()%^zaY,nbYnO$d|T0&qb(n(y cֲCrT\ 9:>3V8V&vJ5;W/TKEԑ1#7+ 0QڷoTkyScڳ_B6:RN]W2 ̢#y }`1fik@MbZp *9Z0v5PdRB>( `cANJa?8)9:4q,؂)TTh 0V]cA#RPEj: <]fقCIJ)ȥ8D(d$ĭ֘L ujgީc]L Z`׳'Nz˥C1A ̷rn"*١[ PcJT8bH5@nB֡aI<! iPi3JI)`O];!wvv^qz}7nj+UA#!ʍpmq}ѨCJ;dbuIתGL_(`C{-2-kq mC+Y6jLl;A%K&+iuЀYze'&U݀.e#)J,\V]eOh86lZ!LZGTK6Eڣ!UWf(DbFf78Gtؕ1 Q+wŬ6Eb YjL;$h+IuH5E29GL#㨙! ]^k;V[G 6K9p#uAUV@2ylp[pc2ARlZ+:0^AlPU#=2D9-h1b$ccv)YO$'6XJ %0 U8txϱ=E@ԨyXP[CDY3\1.- W#V#|J)t?p5kCm-@,A,huXgu1 Ip5W& [,(XHX.c8S(4ihh^X2}<_?m]67)  0(˴m+[ 9k:%kyLsZji"٨ wq9GFjȄhY+sXˮ7ЗmAR:,EAb8bv,wU2-φX)uߝ+V΀qzG`~U2}2Ԍ(kQ_&υ\ۆ>~{ >~".Bt9w{G%@!.9c0J)$,aj 8ӱXqeDL,1F-"9/@6uU攚aD*G\93aUI2͘dF$FeE TDQzQjտ0N7| d9YnpRvU V6ٚ|]j~mCIl0ercD&·d#z dˬ%ghQr7;RJvcmtRٱگ ;\&N`fXh.8$挪^;P(aʹI6a̍Je봷 I}IPuYP$Rs"7ֆeCI2NZL_g"5ZDˌ":UjQ(=q&rFÊhWO2N[ETwgQc҃r$p1rXQBNE\Ød,+/kcq ЊM,(Ťai@8’cDJe'"b]Y3vvտܫV#!ΥУCBdAH.sJrځ%&=>A,Z N0i띖37[W&%RYRzCL*쎎<݅Y O\|S7L- DN:0ZoZot q,yCI H[T2W 2.tކ̱S-ecI XIѰqiY]CO"kp)w"p7SܶG6% ZaU7c32C@$x2'.W#V7e\cҒf˥3%S]t"R+ fpf-握 8.8jf{Ekecl60WM%B1տ?iv]fɅj '- RpĀ UMLG!MJRRz!,qv?X_%%=\30UwR׷Bʭ'RВB#q,o|R d~vK !=Zryb0; X0%8UBZLƈLҔ B(Y"Lv:aE9Q%FZ2G U,b@tj,dcYH?9c̓`l41g$i5bʥ?zD\bLʁ(ڒ]7%h)A ()ҢC( j ̶ 9tPr X1[EP)M$$Kiד٥[Ǒd|ʄZvdGGXJ5Tq8ԌnWi L#wJV"N(4 |o/ .}tK@EK!s@Wb<{q 5o:_P7cxwpG;, n:`g_vҋ/@v@@TR{72fImkN:gÀm0hj}nٕIFd@Ms35~Re.ֵ].^a=AA!Σp]`$@B *4݅#,:s\2{Mv-df9u-v'yUae {a7 586t$*TW:UGzGES " e* ּ!Gusoܜ@)A;9MXE\P# 8VMiXnF}6vVk+agR$z!0[_JzU28J`dKl]D(f!XՎQj֬Aʺ2fa”-y\PJjF 2ḍGf64z l}^ylcmy1!tl#1& CJ"N4*ú֊ao]k K-(\PFD7\ E *p1"|BuRbHX՘lKt=fF6VuE#!GF>HK#cR`sЉmnUrqyZ6ACfK])H`L4 6iV0Ā!e~9r:䉥]kĦr)兎⍶4(U1ut(YJ$ Md M9j: NK; ,M"3][nՌDIޡɣVIՐz09gCS64(UZ|S'mb聀M^ jPIBU4p"d؍JIZnCYέ ]wr=n ЖQ0" \2 fPكkb kfe pSxJ:H߻B}"LxohۈŽ` b- (zwzJ~f\"ǰT9 F(&H"בּqے̱(0b@L$L JfU+kSVh%NcUIT"pWe2AD!P'B1xW _mX*8ۜvmP5&5AHtyL U] BPU,U{ϊ^Z b&VdrA f(W(i jSx6Ͼ$#d!p#ҙ&p8h'w])㶢P>RF4y|^[o{bW^{yuqq{fZu#p9Zu:?g!JϑHsn22G{xOhD4_|| X.,S.G5rY.3??\﨎ؿ8bjr6P#qQ\\ cS; qtp  9gd״T)F-549Ⱥ~qQ1⿬Am ,܂\qڌyhm7(v]%($kzf}bY`(w@9&bqS DrݕC!jbvهdnQۼpz i+X F6fףj!HHԬbJ,фfLI>$18##ZpH&EMХe]( ZG@2;v j[JnA$H ĜpxB" )RN]GU[F> @:'#oqvyS46ֿ)1V!V [g Ug UQ.u}+ 鹎%ȹQАQgP2p&널wX#FRKAGҰYUS l\G~*V%ڹȫT9}#[K՝7!BeoVxĆ{eQ[w=+1+z%JcYV.wXo6j-HHOܟ>v\oeϹûo/pp;L&Wwl1LeI}pFB PYac:V˕J)]\{6&tS m f E 6p/{baC29 }Fj9Iui) @%Y=VOnM˽gjBL3匮z6%Ʀ@jT2Evh q#Hlbf ՚e[-duڤE]>qfnP4% pǂ҈Q%t}6AGd+9Vη&!K ȹH }nz dthv^fNY.XJz6~`QM_mY!ӣ@?OJ5W 藪ɲQ+)Zuh g]T\WacE$wɃ'F猘4Nȹ"k%("`>uB?ʫr>. v(tdJ}q;ASWZ*>g x'ךX%=P>S DuItQƬ./*4"nŻl0̰Z-UŮJZOkBϰV#,n!lL lL`ZMyGE>MYfCAj`H!@zTA.;QluجZQ` Q^~Ѕ튺qQ@XW*8f J1A"h-~(: ղNֺUۍLZ;}6ƕ($j Ƭ RYՀڳ"R&fq7Rљ*KI6TJ h%_!jYY%^Uźi!+"]7.“sRQ*ڬ&;^I"%RX&oF~dAU*9u ˃ߦkp>U[jk4myoߏMTʉd4y8a.@?#`{kǏ/D:J@@24B?aUDiÀo=:yL񯖻n6CImRgEl7X7pG~ƱM f=q#nra{ߛk>}8`rR Ob} %X\<QH!k\=H-2=R/4EdC7GZa@2AR]l%a}n&ƫx㝷ʋ<ѩ!n% A01ݭn j1hG܍J[գ2%ֶn/eEFGzaֵ(9z!3꾱ﲮr(ZRJlR4딭_aSdutvH*BhxlQkB\'@mPoة&zZOy \ķ*i"9\8i]R52ouZx'$:4-QV"*\*z( aӕqb4RZ+PNm-0$"x7K*k΍O~Q؛R%\\,}D|*CY7dh8E]{ru2ryXxjl6s"jd'-NӤe +wi1b|q5!'O\cǏ<FMZ*>urξvp))H/^}9'eʀ:<500UKd%˳ tC%cʌ!S;-)1 [$>뱚2H85 o"A1 YC\Ӱo˂7qo;>"il/ʘҏ(,y- :4dkwΞ80b\-0iըPքY2z^]K.aʹ[Ae+V!`|%X.fVi0mr-43|Xj6 x%sG$ **\A !<9 HVX<%ϕPQ y5XEδRatxسOawQ }NK݀bux7*m> %P)xp۳Bw"m2zk+4 cmo yI13^|>B7| o~t_42 -؞ Rz%\*grI3:qKAI ϚԔF)hsсBRO9rF)NJJ puӈ=+eٺu02 W1 ) QdC w=LG<6771ɘC=#{]ynL|Iu]%$n0$U$d@S3IP#JY49b<6q5%ѿjھ !RkS˄v 'N,b*ϾGu%P79f8G? 6(!-"Rˁ -e"R8ɣ$oXV vWAc /}_η[7ތq6rbdP:~gӤ&D U9j'qlV.^1Ņ HgИ0lCIBx$AUu^X`^@? iY !l5N40@j\sS#o9M1#JZ.am %eTbڂ`hkLq%͌ f3>脯"#AK+i cCc Lck!FWQ"A!1sCS9 2l&`T'tV+iilD<AXMHIsR")Ȱ9HT$*4*&":ɑ2CWQ6X`)JNIHQR8PƔ5s`պ28gt. (2Zhjن*kv3 I9cZ {{)c6d 6 Ɔ&Bj h󔠂 CN8rҒ'lmnz% FAZ 6# lo`O|҈}Ͽ .J>9!Ѡ~%jox30{Y=XS¿% ^x-w*%@XY]iśO_SW`GܓEGg M{ g咉!*yn=ዸR} ?6"Ii5[,J̣Q?RDhyJ؟|[G~iWM»zP 48_eEr[I,VK`oO@Aj0;oّ, =˥>gU-/]Lqyñcǰn&X@ꠁQ3l柿!N7lnmࢆXeq8NDF- صZ4MR'V%Ĝ׊QTLאi5*dB)pa' ޞ/بUg8wLaUNXLK,KPfPM"CcZ.ӈn4Pqǰ=lrŸB*|.D,+lE3add-GaB0aIՈ0 c>p8‚̆*g3\&BT.fj{Q?J8M%\ J0$8ؘ1vw1 JNW#a&1l{ k(elol.1661{,K"%K.a>&ɨC.lA"n`ؘcJ#JZ9css[JsDa`oo8Q/R0h pȎaQ^^ "dŐK,(W?(DʀW]65krZ7 oQy 06fʚb6N(r =i*ޭC! #PZ0 LJPJ[uRߓrZ"63I8'N`Za5olc6EN [8{o9{+dP! ɂI 0%B'# /i [Qo`L%hxc?OA f0hF8AL-`T$ϿמQL{8>kܛC@oc~\#ya?װ{u/~wb̘2+>]_[_)0OMI@IE7,B,Bm#}儸oG@yJkO,qMgf}+@7Cߡpdk )$c23Z/ ɆRt$CNP#Xyv" l V,VT${1hOЁa ĠNF2lOQM-7t}DA{g w)ں$[Z/28Gq%|/ {D(I' 4j$ZA;Sd6<1Drz2tZ<LWUbVK@$$hU!&TqMh0ReFH.w}4XHF!I{',DŽ>4NHR6IiD""Cȹ,6 V%761{{{Um0Ku=˕<7t! d28^P LIN]qr8qIW,y iLhB* %91D%LK͐P0/YV""DÞq٦>fذXds]w@%YK;-;X W"rOCFs"9@ $]m!<_RNC.cN(˥wH% `0VųXVr2;гN,]AH  2Ôi(S*CY_ͮw?[3<<зpc&"oAx7qG}pX0&yCZ<|]xfj+#I陸 Ҟ8ooW?qwދ `Z1U{[vߍ`.24HeY 2ʖ) "!T4}0:6|:>trnPX V02ë" _.E1VӈU[br .ul׿M|/gA \V*V~\KDtĞ kodLTcOnITR#$l.,4~')]Q&3׭#3il<&%3Iu54a}&"*l{LoL eedž3:Uiں#Jr | }\~vqWcRF1挤\rH9\B) hɺd(r=A'e48o#]4YD U=slۖ*]XM -SY; ˄L^v݌@`H@t8}a'=ڎ,-:G}߸nDj% >G#kPE4:SHI{NŐbUШE#C"&Li=<h}f_!}xWg"R#N}' pe[+pw~a웈ݬZ#Yx˳ቋgy=c҈wIC}JFL!D &7iE4`(>/P7.6t[r6vwe5: уZSl%zJ J"J:ˈQD  kơrt#žB4PW8Pk@J_،LpVCGfjt$w-HZ ,( dB+9>!DY">8L@,b^xe|{'J6c:`2c7VEAT0X8 .F:9t z9ރOYΐB'5"pԕ„PHrYVǞż@!td 5] (R %b` J𒨕k(::lH mz.-@TK^ܲ7D L*UuKa7/sg^/_F%#p+GԮiA3#v9ܦ|A&f['e6 NdM.baB|#`__s_D#3d6+M$vMj @t V T7.-5a6I\ 8bP.;{}˄m9j-"jC=7]1\DW#l|7^q4x)x'7!rJ#- Ǯ'qec1NxW_bΜ;+D 2,3pao;/($I7nZ9t8r1xOk_ | SR{RRW! e"7ۄqqf2mkk.ji2F3%NV?/To5ȁ+a^R T +ƌ)‚jJ*b_b( FCkf D I>+.ٵhmߓ3+1&GQ9d<9""lpt\|ңs U 4PèYK P 7d"<z0a\ALݤIZBl[x00 #vduBG/x{dħ~ ˴A cAv_gڗvq>? &m?T[k4j_v*5jn7B27w0-v6ToVY?jR$8ExͶYe5Aa{%FC`Xutl΃(HWX,8/^~oYޭ?yP8g=NR4t$5L\u%o+>`P@ Nno.?v }کFPMo=[P^Ͽ@8dA$[gc 6_aSX0Q34ezv-0pn=_Pi\!%hu>ϟ<( %GFE7A[me0(W8wsx,ʴX>`sFZu(x呯> CÙ_+O=;8vpu Uf;1„/U9z0>h[!`b#稭'ft B e.γ: !! PfSN4X]D͢o :?4\q BRꛚ}pMu1~}Bf@h25TꇴYۡ0  BPR™w—e\t8ٳgթe:DB)~1*"!Ιh TquH>#(u/WsYq(*JK!v6Ym<%kPکJcV !fmaK _Kf C[*qb5EZf!/q,&μuh7(!Jb2*>8"ٔg3mPSQ }VbăC ?~lCU%?s) ʈ>\{p W`{;G/v;r{A^pC'}]M}fagΏ^μ8ξ}OJ-&Ӈʦɬ[HFjNS"& mN";q\6쫯ݟ8z츾j[;AȮ ֞uxMctnN_|%ghgNCdV=s-T'!SqX̧ځ>]z/"EZYd8CSW3G!fꫂAi|mv Tv'ȔQiϊX\ƍ,VdL8m'£>_!ΐ٠OyFx-z7SnR(Rs5@Akٱ;T$꽷km.#F`-Umzl`+2cm9l3l DAu RX-f3spVmqf  54 3SY,:X$EK$#%@v O?{S9:FA&q|9*2"%^g֎R!g. p3PN%~N@D\@_4N +kA:W? !> 18k(oα= ( !dhyoP$ͥ3sE[ll@ŧTP-t&9% + z"cD0M+j0f;u }Mi%gӷ`@UR+zY GOOK<.;=@:]\=g W@&z a/݌OG2H (5XÉ`fLe8v YL+pdk Q&;q-KʆAvo6Rq#-R ruawndjaf79c<!ϵ^r[搷U(:f8杦 i;9Wj{4RD`\-71(V7.1끰ge٫5A;wo}9]gWY3S0A r @/ O3Rpiv9 鐠 (f):lMIW|ɌVmhGv,*Ԥ< #7AWQ?G}.2JH[ɓڀBXUK}v8\- \.ȩS*a_ڤڗE#%8AoK7;˸F NBxBeCnb^Vin+4E\кƾ Bh>꽓;Kq#hS/PuV_W"f3Q` ȕcՄ._{7_KB$4澗rc3nF4ДZvSBȍc/:{H_xS|@ˏ~7q]&y) }20e Oߍgg|rIxY" L"5(#ΏK[ť}} H{ڛs☋Y6^֍tJ6dmmoЦN^bJ=#R!kRqgo6Xy92צaXVK"]k8NJ!#23m9I*t\W_{P)N]Mˎ2\m3_P%{uS(ʔ>3j6*@@1STy:xm^J6f # *P-9Hܯs6\_=M,9cX`V[@ M:Hɣ%Y@HU>!F:0'2Չ0!.,/a%j(Kb㩓Zj59{ pUnz\#2q)w9j?8 Y[+v 5rXNu;V|~boQg8Ox_Bz?.M[w݀_$<^d7 iǿX;v{'9_#KMS 6ff<e8 B>8W-O/QR±!f="jvZC\Ϧ-nu-= Ux\wX &u]2Ϧii_m[ȳ]nx:iR-N#00g1Pt.dSNps;61,@a%z]@e3:s!* LF u1Qa!bJN]@! k JFi#PI!R.LHP*[GR-Jэ\EB6[@A)?s|{ ]y Vn } D$H!ȝ;Leo`h}բkGJpH>[}q KVH6" vmb:S0MvB9g~2(iRG 3a+B^`s?zϟAM;{*eAI.`55G0$y-S#X&ƼSXM`CT#۾>P1;y->u]XC-Nlu?}[_Cb<‹x#/.6Ka!!vm†uڼ  |[N0/\mw߇cG$М+Ԗ]ڵC"e֋^lzPDX'lzKim]єV5!=JZL9˰0Y;2Iu:LJlC kuXY\TZ?#3}HE2$a6lpVfySvRe] Lj싷ej 548RrhT6;ÝAQ;WJPVV£%ݣ9}*RVwtS+'>BBpRY:aF&,*q0A "Sh )OJuKG "P ; ;וߘoqxXFi!qiFm=1gq}ߋ>WDaumFi_^w {`fçYz"edT4 Yw)Yh/  x! DŽ+|+?xI9Y}gk<`'Ӏ̖6(IËmߎNmj Ax%i6AWJH[;85G G70\x ПǾ+o@e2W:XLԢ$Ν@T;%if!G@v/ k>[nKqu׃6Qb4˼uf@l@ _ۆ^#ܥuw{O מak`aA駔o[N#zA^6d4rɟs6*"3| N .?/khء!jk}՗, dHv>LkAW3HA m?3WX dC7μϪs-Ml-5J QӤ-(Xt-m0MHRkY*^nr[f.`m-(ȲӜ /"@&$R1[,_uv# V7p 2)v(TZ:M;2%ڌßcS!5i9B9gim q\uC?r VK,ETZ@0d+3;G oVZنgEB0ckDm.d-ѯ(bn#[6٫i̿9'=ʏQ>ZAKh~؂ 0JBF4bC?ozA?׿$. 0+"C>["%m >:F&'M}W\w3b88sF(H{"u3 |4>_.O=7t69 LĊU21RA[-۴mܺ( `(w0)2,X ,Var|FZ 1(,_Jڞ'R1Vbtkhl٫XQ xUU嬒@ZnJB`\i{Q%cQ* kYK]3Y免f͌\ [ nBbd١hf/wrd!{{X, GEg[v+P-tT`ٵț8S0@Z3e'~lWjE9*߯k X`laOt)U(fvǹa[ي;760F,T*a l@uX:19gϣEL0y-p݆M! v"Bp۸ۑ #U "MokԴڲYakJXsb炡Q"}ͺ5)Asm1gU?j.C$ ^߂brY K9*fő5{[Z4DFsR@\ yBZp#/?7x3@Ɗ:q5-.%ќ3/;nI(֠@I!P 9l^s'~W/|{>4?7_}Q|eAuP@.ܷ? .8?Gw< ̸'@':Fגjtؕztl*GvA3b6zquM7KbWpq5`csMcVI`.m*IBoZ_0 H;b%Dɝ*j& h_=je  :4NҧneJ+\x/0@H )'u j[PrǘùW6聜3Xmb4A ҄@&%Lx7o?3qY#k5u+dg j| #Z4HlE( v\$ s!gv$=jJϳ*!lD-fpǍpuEZ|؋ak{jJ@iEE 5ϫ :..ۓ5y׾W^wB촪(t0!bn {+:fA?m={Cg:OI5*/*#ɉ|Rh{PRLEuHnk:8~TI>_mcȆpT WP;a l[qL+9[n]_SKx(KMc=ȯ} F)UULz{xhTb~p[@#g=G='[gGQ׺냵͉P.9,M8X%L{g36 5lqY+k) jj B@hHbo:g_} 7]w-&,Ͻ[;ʫ~a>DG@"lpS/Iv9k׀γ֕k&mUZSiZB 7ud7+'A\ܶ*ΪRFPtFZ+YY@Kdr50bXDTTmd+Y_W)yj\Cl_i H1ٔMMG9p<{sLAwMDf$=#L Zep|;qϽS}lGzI0\,IСK;b'C\& NK(d8dDCB#RglټuHCڈ_. ՙ6N8!}P)'-iHty)F4I@dN]:ݧ J)#=̊Bb̠8!Ą4.Ά x b3oΰq9GqcM]D^hPŌ!vݥuKmAsU%#יӔ1&)!P`(H+{Yy767XߡGRA 1G@K ^X4Nb&lS'Odj9s8[X8Ȍ^Xl 1j{Ζ1Z / m]T,@A2f/fn$v볡CM@$Ӕ0N8`cS f݀#GvYJJ 'YP!ܑ~fS-ScQϬپvi)iF6dm%\'}/ <G+cc%PV`QI36XF,MSFJ}0c٥f^ۊM C0 Yʋ!"kH4mnŁJޚ#S w.܍ }ӄͰyE )/AyD?@L+Li( `5%ː& -l7bDbqB ]eAI N )`+)~nnؔ{꾱 ,s3g#OMږ@& HT˳"V{Xsm6vFW%al2a4i4JhzvjJi[99 blRi@iK+Z *sňshD5Ȱbu;:1#`^EmB2,MHJ`v7>BA BQ&nx61@:L+FYKI$0sˣÿ 0kmk;'1rI9t=C5+1lޜBz{#bh3"kgTF^;Vlr\[sAxNQs:fKwd'vI $7tBK ;d4;&r~$JUK r{o,ӈrrX'3T]+Qæ"3s퉥Phf`g v{tAXIv|%YaLX./̙x)@Zd& BOJ!3l z`"@TNBQbas6KK?bT"2CiFNG;PG }lm/ҥQ.^.Igit3\Ap5Ut;\k< DɾM6|2X]ƀh}ԩBAE8c%و=o۱*,]&2OS3=+8 r\C 2?^Y]]'ʷ&iJZ.d6 ؤI$dM!1ԑ5dճmKcAho1nB^02p#ZU}f$ *%~ (< 'ink;jgl4 N+) SQ :oL @2CIb)Ē!Fg&V  7Ne2*"^-rzy2Ќ vsaйrARqAM(t&ALnpGLnۖVfB;Č.{z _sI~9qY++7Sڌ&S >*AXN׮zp(4>޷&QmE)m8P ^`]keҖ)gڍԷ)bԛl{fJiy1l԰%ݐIT+ .QNڨ!5 KРZL sM وȓ\_) (yDпsfB9X`>CCmb6cIlo\ TDcNeIFČJlH^!`b16a>s8onv\__Njo-0̰1$P\if<)5+ !Jc+DrҿS^#kC%)T<,o%N óU%M VZw2&.ؔ cphE8 J- dc%Xay0-ڳdA!LIx=dGMR֫kY6Y[„GIDAT&3B2I@ s~颱QOl(^A(Y  id`J""IxD," Dǂ.s,RNٗ]Xsb@(vFx] PGYv:~Xsk$01í~Ȃdjwح1dO8?9*eJ~- [kf~}! /18fb*~;CP|Voiє}.E!ې5sQH_7Z(~Jm:7 owZ&f 0:2w?~_b =ȟdpP D(|ѤjاۼS$DQ6axmθfD%{нSو:G+(r ~}Tb0UGZ(oC5fjl/I0ƶ&?kρZcy@[߉WN#aX둉K]_큟R`$N$Q-`5(Ȑ@M<b/GAC5iV{UIP̀^mmWi@;@1!&e!6.W VҲ5kW޿G3RVCW>lhWKmQqC?|?wU~.s}& U@%WV#uW[ bɇ jf߻ X|Xz@:hW3_{>8h^7HT@Rp-_<#59@&P-TdQA2ଙ])|jW*[/em;\Z3gbs :=  a5K.L~mr~5Zlf|ęII - TG+oJ}uUGo>jjeG,xıAAϯc\nCCo3~y]h^$À7Dz;*c\kb4{yVpjv- /~P!0-@09V/>Qjdo-'v6 iu3dB4Q JX$ʁ 3)pI(iD2(XFR7Ug3<& 4%Ph'08 .`z/'ݽ1c8~':m4!"K^gͪWAnRɲqr6;jO}5N6 w:| o.3܈15Qg[l2 zxh硚݇fXL~.a{5`~kbY` '$p}Z -]яtD4 =Jy@(KjĔJIJa3&n{(9#@>`vLdPɽ ƹ*+OB@z@ΖM 5O0V 2S%ҵyQk8! [Z \IP·G&Cu"h><7gv-*mKc"LNIz6v4ckmq+#s\5%gCk.BgkHn~8Ijgx-u> 6WkHP&"/e1ٷ 04uR*S_N"r(0Ab8y7. 'AFškA'Y]R%0?-0p4J;I[Q`I뢦.zR_AچX`gb-jr~cƄw^ʡ W#> Ml`Ya<#&[lD,93Wrvƌbi^CF2 A**iTx) -!6V}Gm])&V됏HDiKP:+r 2u8TCE P%@3~s8V;\q3"-bQ0i# Dtĭ;uNq5kQ[2qS@j[oS)@6cD b Ly)NgɾVfIPd(]n[je՚9zM\%׆+ uh&H2^dO,o)zc hws&xT_ܗ;&av;pNpNZˍ)y!hp+$,xdE.a>NRr؜^YDWj Io-L0-Zz;~:*k?QS٤Pj0 b -%Hz[nANhdye= E+XAJ4IȌDd#F,?[fA %H gqHb!@$q\d0US3X:?f/HZXO-*!%VŽh?8yVZ`UjkrE9t%tLBX;p=2(iJb kQQMWd5pԿUkie*P{vkyU%v+)EDЉA+ X@c$E?SbBA@(* :ȶnm#q0p<.k#u~_2RatAKi҆ॣa ic38Znrno1Lʨ!(PL6TK@GT"H1oh]y6P'dp4ړ/TɝƷhrYtLzp_#ˑ<{4TWTҖULSߡAͰ>}׮Q5ѤG[Ư'Jreyc5;V/Ә3f-][-AC+6Ci}ԩml5 [DJZ%)$;3jݖoH"N.9Q Ht%v0uJf(ns0ABQ3`Sۼ ҳK<:юuK02dʛ@ଐVcZ~qܧgR`j)dJ|Y y> J.yv/ kVge RВl'4.yfk1{( QuGLPaj@j,,gEpO#W&ilV *ַ|+\%BTdv>o.4G&(P&>*l!"H =u)'gL43@D.;R{&381k5v-#n x"ƢXECA\GU{l:ɮNYxkЕaC# U)[mOk4hhBuVzK- {7hKH-ђJ+>0ya 2h4={o0ɊBZ"! HYkhWEmZ  !~2pU8?ΓKPƟ!h9}zŒauszr ^ (n D@Z t;3D'܉Kʕ#kU,&:tqY G9\L d e?ٝPkzaHm0kN cg2aI[PTG9W BlnA(/CGcQvb9*b`yDyA%R֙"BQ>bep CR+ެCDSZ4"KFQ%EETqzӱmPP[Eh[v|v$5+<0 5A2ިh#z>& m9賬Bͨpi h6RqX)gr9e&ܡ`2p1 ƍpMmzmҟ|_ATIbA^WMug'#554fMr7cSӷv%yW0V 1uLi*A)45tE[XF+usC%Ji 'k ġȍ(8-5`٭Z9v䙫z~>iq$w+'FzɣׇrFǡPNݫHQE E9c2(_*xSC> Ω;kvֽl)HiqiG&prMO,@2̨]k欒{Ѳ=lr 5i3Q?ǞA$jh=!-S蚐ZhǕ9ʯ8BdL$YzG4n6;3gy`SډKa5Gv:Y/)NHny]2ʬJz:rHj~ɖ6钎4l\˞:{a=u9jH:NP`"AhƁ /HkoԸtX-3*ĦNj_1Yv¤]6 kǔt!Y*cBMk_ߚ难bZAP[wd)FRE#& MPZ#ͮ֐-As7/d-S%ֺU؂l#=нز]"}Cc@sRkŖhۃ0xp9qW;Aݬ_ pvFQfX`{ jthM},<0PwboJYi?h"UQ֍5% d2RZ'Zm:l)Z{9SϺCXB@W~_U| 0}k_-y}6@XXoB(~XLnDԡy\&ّE^_a,"f~hQUUѨr)j,ֱ _úG@(RA닭 SysSpA#p>jӐnԟQ.6@U-SDMekley$NQ[ $ĆZL8z4gfpo͍֮DS+t&(3!/`V֞嫫L97E ʤgLUxE(bC-j B;`_zSur(z]G v-ojaY[j6FHȃ=9uk h@a[[f׬osh{˛`ޝs@;턜%66? %92ƚٯ֖&JNcP n6ZM6$tchPjNkA3V!2Mm2tp{BuH5ǕYۮ9ʟp-8lv@=3gs3JkOFQW4J vN jn~3.#BBzPhvf޴~maJS۷jQ/5gZx8mcdbh1i#ٜ}E\w 4ȡ̓<؉0m*l9^ 0$Siљܚ!T3;bo ^/4å k N8C-X&)Qm0׾?DPؠW}:v~D3D>zФύH[Ś}kG,1d 956Gv-RbH"-%0[neGl3թQ=[k VB  djz۞QZ B?:Psڨ(Eufd]ϹXukAq GFv[@׽/ɘ픹/q~v_v?آ^PO-ozYN+ߣq*cRl)V :kU9^s\uWFTѤw;ØRj=:EuV.WiQլڦl˩k?1ǫGK,~W@p{}wמYQ|cggg.\c?x0-TD#@l Sdsmhlk5Ϊ'#h(l=ReΡIay4(- hqtmP~o sPVqE[9fGN K$kLi,Hd2-AyTdME€0P} $)DVX#7r%~˲7^ :- /▫Oh7.!eV3iJjxS>4 }E*`[Y!hՈn/2;!߄+ ?,^{~\w%1VF| _qGy +ĝc1J}wߎW~uEo f <:B%_?̉:WG3t,J`<*ɖM !%09W]{=Hk+$Q7F!LBԑnK֒Zf0ìu2-+bÓe VF`נm<Tm z 5t Ԭ0!oٳ/ k@Ɋ&yJOoq>i TJd=>@VWmZ$K4Rnc.0w2>NܬbdhƓ=ZS,{'oS98W c;g:eJK˦F_iDK:΢,EYi]H!_Mf-kl(5+H*#̎?;o@.I/Hx76d)ª?^xiħ?1eAF@:z ګ0:CZn)ǠPvd5C uӵPZ48q!PHY璉4ԞW5c(E"j5{YuFvp'P%Vس2a ?Z?dϲm{p fi lk1G5iP{AU`~ư 6bԳWZ92n `_ckP~9܊y+rSj8GÑC$`Rdl>ɏm [ր1eR߀n(Jqݟ-WÔ $n /;qYcY2%o+T \yO_uqeH#rJE"xEB\S>?Epm:&~[>h_3& /]B *ݩ{7pao pb Aj)`K8 (RSft!`y,/Udb- oz9n+'n|iagKshSUf>?L^ٵ&++d 9!k2iGw͍3j{ɿ/7!,K0Z#ǿz *iG,+@Gok~9!6]~/qztv7i׵]k7XKGQmmU!N jxn,5hu]-B|{ZVXRgvg{fmk.i\_:ъʝ9q1d)kFtG.wp0f9T0N]8֑2}H>~9(8~$b E豣0eug+ lJGϺSa\qqc[H*ѽK+qّ0lȉˑRʙYv.qktֈXy (JgvIv @&g[˱|jVy.a{>^8 2=,A =A3h}VO{^E(w+AxsxԓON0#}Kww/?}Ca>Dl:\8A}K,Й R4U+[NԼbo% kgСOͦ '㛕K]}5>vj<-6'@PX[?"-9CPjNk= > uVֆdtE:g/IϜ/~p5ԯV[RBp^w演c9wszmuv_k#PD=_n۶C{t8ٕiu92L^q=Ğuվ5x-aggucw[&l_};:>Gg%P˖CL#ek/T&._ᮛAS0=,zEt-I0^U@$`I'>"#ײF*֡M5lI㌆[!S;Ɩ(KA s7xo;~G.1ll܅]ho mnL˺jy&ë]"-7@DAmsGԴĭ!oHEny-7`ʖm6,x31,ҴנÃNSAZWAtkPU$ɞ5h&{eY|X"9>ko.2}.# *Na|ǽ:zੇqAnw윸 K' eZ84a[< 8ƇoF{ (00&Ɵ`>6 B?7>^+7IN˸ te4صLIJ6L2=96R_cwsz-~,AƳ/wNn?]7L{.~!<~ Nb;{/}?%N_UcG]䑾|Tej떇9t-5xknVmIz֡vʛ3=leȺٿ^&wd@1nzjԖ,ɛ/MZ%YS5g#@e{X@)&0öc]R0:2FԈjm[Zۻ qu^kS@qEJ6Ԯ c[Y[[]o(AmG<.lw} ȇ?eb+x_;!}/6ޟρ N]wagk<~Y=Gw~pIp /=~- c?n.>מy%M n'pj›<:V΀M \q׽u^Uwu(nO"ni‹, cyo9O7;?kvKa3Ki$7nԥ/,/o)S l|*lemTB4]`ᠰ55q .e w~[8~(.>w>~')K n?AH(93.;2Ƒx'{Y~@kCkfmTp֞miX6a'cHZ'rJ @:"7 };Ʀ;-Ğǡgaޟ[;e: =kk0d ءj"~Z30\1}4YX5C,S,jiwUy[nOT=4H#}C2l Ϩ]CgO0Z yҮj:4 (Yb ph B\? κ==A76CI$.?~W-_ٱ+sO,/ԭ_‡9ˎnk/Εޮ73{P{"))Q/ɲc' ؎? yJے%[ilALwzv [tWUWWW}]uwEmGw>#b'X[G>~[qjء#r2x`~L**X9p̛>Lazrqu7Z_  px jpMo%9}G_Xk)đDbGyYMIaR|ZS?,@qgvŎ фj_3Ym+i£w7n-5J 4@4")ބV)VXlVeV$lNS4klP~쮼0/c]桏 `!G7D[hMGXقó ڑ9h3X̅1<clpNn(Һ5 fLNwIkl+VLvcʆR(~]= wԆu\<ޙE$ƅy3x1"ÂqȮtr'ʛ+44dvd'"bmx0FAi;r27P͖B "TQ$o`/njFmh0:4=}(ŦoJ҄]zP詣X߇r$#SZ܋rzu/bF[Z.SR JM\$P`꽸0с\1{Q6Z (FTcdB 0N'!>-K80Y@M&HНk$2LFQ&}}Q VJn?C5@eq:nIk('XI^>$/3#Mn9>hQ$~H6qc">33'MrP nO/^f|ӳX_,yXK J 6rʈrX{;by d1šQYܕN#%OkB"x,Nle9c靻hPF}s3ҘӴ -DAϣ mjكCg'E@Kƥf`F? 6DA;L^>|9]!tT18](F;PkqZس32&|'h/ladgHfڑ;Å,(7R-|nm(>T1E|69O :Xz4$Pp",ʫz'o'X_qgq*6Fce4Q٭ vC /̠ 43[֖#iK-#\OP5V6of[aar$Fn D=(H "JtkO! 5)ihF12iކ1/96 <g?  R~vwȆs /bן]Ba1Ҹdj/tG2SMX}|p c毜ʽ5VϏ[`txk \kJſ>O@7WqgruxuP$)ܝ^`9Sv [%Mmr^~cD|{N qg=?s@!Kׄ޿ժs O9==L|dM;oAwTNodc#W1Oξ"6Vi !1͘Ov9o9- n7X.˟[[ .#{ Ybaܳ<&q}}oG{i`iS[X m?8c?F+׾ 7^…i<7=Bdt֭GyHh,ߝgᥓ_K'Pu*y /V2B;U8wqnB6簷E$ (4}T-]<L !GyHܘptbij-40<&DB:+њ1UeCaKf |!!5Rɳzjnٕ0?h!M&ȍA&9QȺRfÎFG;e&trGzhjQ"2rK=*AX1A;!D΢h,׏n87n נA/y :%cLq{zp!n]D|ʃy{zd 殠=Tw_D_/T\oX+x@*~_P&1i 9?qO\{ Fs;7zSǟǞj/V<} 5MP?~JT Kxp, 'Rn1OZޟʹM;ƙ5CTaǸuu4{W7^v5x/Ѻ+KsCtA(jY} >ka3%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_64x64.png000066400000000000000000000165601341671471500166360ustar00rootroot00000000000000PNG  IHDR@@iqgAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>eIDATxڍy]}?-7 gHQHjY(Ŏ,v("ub[mM.Z PG\HTN ]e\B"EQ$E9CξqιQ=~g~0PyvBJ@Kŧ6tBȾ] T]#t^֊(LoooUJk)J<*̉BkU\7GZ>F5(}i*cvZi dimyL_Ɲ+›Ot5JT3Oc&h,Qe Co,$k'T+m-@\ZsR !$ 7gma9bЊӍbƧ5B+{mn8"4FHA@K3Wy *i w9ܡ܀ܦUhk5OEH)8d#3T:w֥4Zghui ֠f-JZ44Fyc0xR` P-5k5T*UBN{9ʡ]kMe% >->NsR6|S:9BXA+aU@d*C0 iooioMNN0Plg9P+eL+UZ)4G $D:7K 4NUWVYXX`}}ϓLMMqAF |L4iݬ*6q@+R)qVxnq '0Q4PFr.R lwZ`m}+W2??Ocpp~_9dٸZaa ¹OW05J+Vh|/Y|+!?)@[Vx} @cI{8q7nNDŽa?LiJHB$mA35*Ȳd&' ]X|KشfeuM._kƕ+WX[[#cRH)gqA/YPoD;֩" N4VZZzh#dC .y ;$4MY^Yevv3gp5VWW$z\vWi!e#urTt¯oTW=gsi˃۰rTt!yi&-⢵AEQ&lll1A0>>N "%5B*HҢk ")ύq'譸E^㯱rwoyȔJ0hG`T IS4e1BDQ)%|8?Ncd$n)$P&(v㹂[z̃(C6j.?/ڹ7Oi"awX0TK3HӌqljӔ EOϾ $abjΞcyi鯁ֺk̵U ,V%:@?{33Jޜw\ig#g">\]M()3\}83w{104.S9+ɔ"\O)X HJVg7rnfa uuEkJf •y,(U䕬ܹ3ǽ{s$+G0n240DfiqRU,ZyŠdeew6GvMg ~V<?E,Ls#@z.?Hcۈԣ>ӫ<˻gs ^/Gtظ_zR"-sk}Y0LfJEJ^,R.enݴϬO,~ʀk i+}?qʊ%9[Dt:${in^I0V͇e|u>|3gpiۇɒV}jہJ "\QSֲ5- FѷitR&.|׹3w;k1f<‘Ol_/xя~ĩS)%?ɫL홢-ݠ؁^r(-+#Dyծ3A5h5IrfZ[_S200@LZ-׹~ت"=X+$ilYRg.wN1 # ݻ<裹F(0TgD FGGI1* nXYY R,Ce)*KvuY:ɑ}9:%Q")%.℻w){hN헅"Jޥ4M̰HeDQDբnjmei_Qn>Cp>TW|P7+ Wi|Iv,//CCC_ZZk 7ons!qB UST> KLďu)P\<}Ǒ5fNt&EiϝK$2$!"(077G+B)iD4PNfB*)BТĴʄ$iJOYlMIӡ^f]ެs2ϗ)Ihw:;3k{jJ"(U- # 1 !m39A! Lefh|u.eZ1==@*eYnK"5WYYhmQ01C|ء?g;[7jaUNiѠaV`0  dJ[$ LLLPT怏FeqLףjzO5WoqkG']ej_)o${W@6nۺfXjdׁYNSD3.nSCVhߦ9xӏ.p:I/|fI(HpGu=F'1]e`47If} _ҒZQCx.vPv,5PP2bw䯨i6k |㫜f{{/}KyjtVolmm<[kKYѾN) 7z( ʈ2)d4o˩:\'+]T*B䜉W3ߢ/3888f{{e昿{0D$]Tj2'(<33l'ϒz_CLaAWcYɂ7+@pҚX&[Q~N ґoZW^ѣ۷jv,--j͒vBț|U&Y.sA*9\WԛwE1](>; , n0WZ>‡] _ǹ;CzyvNv$I¶iZt:.]BrlNqvc6I e?IW7 Dͬ9@/׬Jخ-4͗`STTLVʙPj|䯵i7@(6B־cݡ2 #&Oz8`^SVjA/!DK. T6V}XxkO3)jV'"΢WQR}[32ADQmO:ӿOgj[Pnx@9J TeFLy%2~16PIh#@~T -pA&<umL/Zi=ECdK4)̈5=xvFtȵ+k?g`*&F JaqJ{OLeV'P!$Q%Bj`%h- gfXSL^RVt]`hMRW#d?ߙyar;,%M,PCfOm\6CK'4a7Ι1{Fmf)ghmk2Ohxkt#FFi$Nf|(ÍaO 6JNiM(-RLJ@)A2Eۡ풤iPzl`=TԦwIZg#V܄ӜPx^BZgylGo2:: zJB% 3(4dt;&IW zT)]`~q{#J.em}$MI#3 -X GGw0WBRkL}5 t:LdRk{OJIqBC]aXX\K-ӅGǐCsn\duÙffz (ak{nɑ3|7XX(ܥxy{Z|L-Օ)a5d1\daUƭJk$1` B5˹st1k/m4V XJWpRg>zQ4UȝiIg˟E :KMLm@!{dÍA|SRGZ.C)Ma筷?@z~hcq-?~oǞVS 4R@tޕ\+k)-M5dB9w5 O.RӥըRQe)Isk_i@W6;o3:X->"đ }0{ ?/ R_w~&5Fdeʂ<{'`f4csm %s$ k\!'ϼF8*\r w<{Yg=,j*CJE А%," ]qgap'vpfIzfl*VIa$Ex!RDQB]/冈Bӏm|NMm~Xe`t,io WS0Ij\f"jxhR$QhBH RO4VAq{h-1̷zoҠa|<Ԇ"OIDATxڅyeW{sw@ѱ1/_㵟 B%VPN~9f (L;rBǦmtQdmB4N̻J,m_xmB+d3y}&*JhI∕UzF+3H!% *nR0$h3Sa'v h4 rŽQ 2@ 2+B@sK C0JNJBi0IHsNk&p4Z 1=A$$ HB'h ^N͵W?'TNPBk^*rIheڛiVQA"0)w?HuV˴Z +an'<)k(v]1֠E{?y d@ 3VUc?7'mMX[ޭpr=C&UXmA`s"?yϿ|N?F! 0"U 51tZQ5= e~j*F=I89#K]6(TglZkmL*ǨF)E\&cX[17V74UTg&`ͿG0^ RJH<I ?xQNAD̵wD-; u;{8M&&$*%Z}뇬og$J!SEX\yxKM# C `||rRiAI;kӚJgZqt-hޝt6LX3/.`0`i&^I{5>~ WC@je5Jw`ŀ`jjq@Z`5@HIA@H)B F"šlaSJi>DŽB œ2 C 52V$ILRZ_a}}(T*|2ެl*MǠ|ܢsr8N(Kj (ǑId 2,2p98R#IH!f[8"oZ11OHeլR.3w閫4cMM331zRf&4BCx9F4!I >SIniaWZoӸ\l~0Ѣn٦!SVp L8(vy(PJQ4ǵY,b%qDQJQVfQ$ Ōݲsf2Dl+xRI¦v56W\ٳ,--1 j۷o иJ!H)HIB@b( iLDP޲m2OΧ9"Fh|6Αfbv[[t}jǏÜ;waosE>s( 'B P e`&j@s֤ib#b,% ɭ ty7wz@N*_QJWoɋ/ӧYZZ$&hZt]J2ssL'9[Zs,Ickff .LN9πz5v"B9/FM{s / /pInܸA%MS$cǎq~7>n2B9Ot~nJ#0βdIBERPg^a %ܻ֊uZǏ)J FGGBX]]ĉS ?ʎ*8'K{xFk$;!J5Dna٥-&R!}P9w4%udx# &Nq& 4Milllx*LOO3?fffR oi~E2[ .Rw'wəV1|}9hww\iN_2b +Eyq,Fnj*U(ޔq!$!\0!TJ?w4g8=G>cw\>OKdpmdLI" J3C\tk׮pqZ-9w,aYXaE.t6z+`ޥ A&xRb81s4O:1n T#_CӠ8bwj[s)7a9dٵZ7o|{oJ>)=Ƴ>'ٵgHgJV_Ry! 0i$^5آxG# 7d+0>S,n-ԩSN{3uFCV_/kW"͙@*5MZp7<vW/ɭkvg8i!ȼkAH>Q'~%|rimɼkОZLr5j$8S~5}C /DEu8F1wp7w 0ܢ |cITktHHdpN@.{o,DU67ۄ1?IU_$M:ƇAȕ7FR^G?X٭ES a[LIlVvF&}!9A)Mqk;8 2Ef>ќܧ; YW1<(Q*z,,m=jeKiY>pik6-ByK2D{*E6(+ԅ %^ǂoJ1fgfx4Q狲39y 4JLYkȨ4ab nᙝ)ePź0UAC֏&|%5$ V7 ._ Y~H}*OEv.,XKSo`Kg䡹x.ԅ[egړeyJ1ۤp[y>ꕫ=z !ejvwpuB'س{7LLL{nx v`0s3;7CtA509XR|ᐾn1rɵxC~?pwf?,~z,SOկ~NCTVqqN>яOV݂)yb6@bx:޴(ۀ:2 e);wÇj>F`82::$9zP\^aaa'}Ї).`к][5$&]X¥^K/ٳػw/>Y0^PV0 i4u `nn/| >}U\ sLNNc>J؊<|.grqHj+IFTci#t:}YfffB!JQczzfIT MSz)>l6)z=9}4/IRDg6$q4vx oќݟ\ U@\9._0BP*rtZfɦ4%IxgX\\ﳱ&8.[-f5I*`Xƴ ۃD&ic̛eްM/{KTʯԩS4u/{*52N$qZq?<3gRFE^~Uw^<**M}}͗->IZdN~f? o+VVVx駹{RDds?ah8T*O099f`@ m:$J͂LwfhN}6oS$acEףhJ6`sBzcy1qׯ_jB*-RmܹTɵ5AJ+2;PGF!^`9~OTՂ{qQE C4鰸Hę76"S.4=y+U3E AJ]qkew9 sټ%\r*"011&}"iot (☵ufffطo`rJ싉 qOrD*va~2u񏐶*VpY]>s`:=yoϽ5Dž󒱱1붅8pzNd؂x*K˫e&'Vaȁĭk]w@F Z feH} eH i{*C3QZO^y6Z Rxv$i3gss~gGL*kݹ[j s[i0 Usc)LLBOw)IŴ;vB rg0 4!Cu/o~4lGygϹA nd~Y&$wOJI *Bixk'Y^ 4a<]hJy\ks)Vn06>NXvVIY)M%#(co7ڔ}wl{[3yGi4Aཐ ø2htZ**He}PȱkSvfBWR7KieEob"`Vg^M7hl~9Ar ՅPK{<~w^??d0SՐRzoi8 7n`iy]D}dQXBMwNҟ0+)lXyIxy06|f"@k 4Zߢ*.#cU?X⥷RN:׾52=r'.Mbmm%i69ޅ4rv+~aXeZsksDSm|PA`>s$ZC6(U+HwYś=}:#_Ǚ^{)vBe;WpVTa碲[\#|:D,JeZuOm1/i((|Wgzzڃu ׹x"/_&Iv(AIY6BRfc #o%kѬLiB# =@ Ү)8lW٠ @hLV4屔nqbw^=x-rl8\.h4spSON7ƹ8ѝOQ.MضBwD^@qkbj28/TlR D6T Y"1@IjsX M&T.ja(jZFX*s`GlVZS;9QyYAHأZ 9io0hbQDXz`5A.9M~yzCl?U)~n0L|Gk,` r%㽬7QQXVR\2 FwJ59Gr=2݅a٤ިSVT*RR) TuܓNmQPߧ7!&<$/hg.\HI,,Zg0f~]XHheITFhֶL8dy u 7`0`45ZpiL&4I|]$"$J#’ 6Z] ̜DU8GiɥSo0lr'N}T)8aӥBSA IFDz~N8NFavMHH%c$NJzWJݞT,1ʼn8BRՈDzV o$vVPMT7VvWoس{s2;v?0n-;9Cd] LYF읪h *eh{෿4 w[ϳ<1khl6tJW)Nr"?{hhܻ&MYUe7oݻ%j=A{ >hqQ._$*5xb}.APVnij+\>w_N0@sF" q&Z__?xŕ.T`ϴGs_ƍED lBXmJA`aH$M4F 8NmM~s?[vx*W?ĩ Ȱ\T|8"o|vAe  Ø:S4U1M%ٶ \R7])7xET&y@7"2B~dIwOB{.v.@}@KB!ȰPb۹보+t0GAo SB-ݍ _?!$JUY^IX\ZaC#"hAXA)@%/nB\JJjM/I! 5i2R GOsBgA b7z$@yt۫TF ]]l{H0>]DܸpƄAȶ6QƆ1tc Q7(xyf]I{IJ̙/ȍH~r|E6W2l`|f~Y~y*.RD%M*E9xT!\;oۇ0\p:жy#xU2sq!:d@jBr8{9FF'~őe+3ʾ6oR5;9Ծ2ʶ zM,@mB.A}X_uɝEwxNZ彮ME*#c=}77(@h%{b%tEXtdate:create2016-01-04T17:28:07+00:00e;%tEXtdate:modify2016-01-04T17:28:07+00:00fQIENDB`CPU-X-3.2.4/data/icons/CPU-X_96x96.png000066400000000000000000000337361341671471500166540ustar00rootroot00000000000000PNG  IHDR``w8gAMA asRGB cHRMz&u0`:pQ<bKGD pHYsHHFk>6IDATxڕi%u;~=w1M 2AICFL(('++YY?dWh_J ˦E8Y ЍnÝk8'P{uw[9%O}3KGZ)@B)h=tT)~3 ZLZ!GL<4bE!w\ŮE dDh1;Hgd=_(l:{_&f|*242P(F{{H !|RU7PC ;}7=,tYs䇸3X^z~R4МくK/ 5:134ח#OFdB뢪Rh"WhӺ#dT+Ԫg#4ڟW)T-e !Z{%iw~ZyDh# +BG˄g2sNZdV5"J/|½|oB^PFjXXTM^^J^' PyI( B!ТǙG6%2Κ2ƚ79~?/vjU&r ^ȼ&#bD إ4uM4X3'f$[5V&d|DnEr7RV"ҐE bXX awB_@DQ:E#dփF)cQ:os~oG{Þdp  F"# s0FPh 5ScB .L m>lvd?f !RR Ua\P1U)P gWΚZ,Mk"W20aNXxRDsTڼ\(Fo_篰C i3W<] ֽV, %ZHn _~~f;mB Vjh_ Zxuy: AΫ֥+i;T 탫tUr4PgCiMo0^\?xy%{&y&qTz?$9-c)[~0ј,+Rү<+ R^ @:TTpk߷ aÝe "DT*@@D Bh:)N{7'{?|?K GrٛhU* jr2h/;_gqzp)RB=*06V[ C +R\Rfĺ\o zW&Di"b:E@|-LP* O=I,l3J@o"oM2*H)?•em=.ߞTB_@+>Pn>8ɛt TQ,E Q#h㏲OZ֦ZD^U`}!V~bn~(QEn辦 "m<.\۪SvR|˚#XTܰG.B.Z*M7<`{g}4m4my~oȦ!#G`0;?yYE*$"4C)EQ$&RQ@*=֢JDPZ l[f慨xY!@QTA(UPOT1fxe=(8rp?"+  Q),{wB V!uPaVK Z*SԄRʸpXɔl֢JEAQVBZxpEȘzN-sQqV간2NyPayf]F }y(ԒJ)<#ȳ]w5ux\4RH(Jg>-|( ,CF0*8a6By\ +% +UT0>)eoCE!CƵI dqafM0J@/lhP"G$nW],ֻݣ(JbE_]~]ѿ/Z@c3b{Kף2 Zj5ٿÇLuP JeZEiA-JgϞ7ʕ+v(v6~85V32&U. Ԫ22Wܺ,*,%M^)ĀEp~"k9a<Fgj7o/kq%VWW]B0B/~ȭ-P.(o8,ҁ="AEقTE G< WjsOUrDKN%toevX[u~DȄ|V޵I0 sΝ;믿ΥKy&;;;^."QkM\x_yǎziT~d@+e;X%ೱ6-hC+lv&rط4JWi?=C;NVq7`{[H aȵuFW\᭷biiF8&I4Mzlnnr9vwI˵)LBy( Qz2"j]925$z|Q^A˅9)JzM%8;:d0HӔenܸ:n4M :333qh4bgghD n\fumY>pYM>yA\j%lR$DEBI%R?w/hRlzA*驮C.m;C48&j wpm0$LM1 H[~b~~zNǴM&+++dYF}6BR8:a=> zKd{ą.m!lQDy:9raџ=vo ZԩМ^ FG0P"b] 񩁮r:(J|?WS*6^װZƧ|Oh4h 1"2á0m$"/$Z, MHK@HWWWJ@֧ q{WwO`.>BWf&aTJei*66aq%lAB)Fwsctfx+ {| _`<ʙ&?(( /;З& >>3Nv r1(NI8-=A|N]yx:뻆B Dt8:xZtVJl6yZ?/~Q+LW__g_id4sHbusfksE6<Š6擟O.U?xϾC=ٍ֍.RJ:BY-׫n`+ OlʭtspM}I^ʕ+.zoeVO~7M^7M6F2ПݺXTv1%{PY>4Y6,|$EF~A}`4{lF|SDyTPAji&Tמ-tB"N=AeEKKK8x)[RFCr/gp.nKX3\At#TKm~C~ġ<:Dj7K jT%vNYEHy8Ҽp B9n ʦ XvW/ ~ SS1V)%KKWfaaS'PYW^Փ׾@U`tOQ^se!VIT4zѼ[.TK$H vB]po4Èz 5z@0X\>/xuzZ9,[`vvRګZ !zΏYYX]5;'G GveePsQ݀ qJ,GK#SVfPeRn޸e1O>$f(h4t:9x ۷y昚^s!/)[[[lll\x{xl6vh1] H%MeV-粞 q?(2& Q:_I Wϸt+++mf\^xM;v4.+F.H=K,! ;B4TVDAvnr5t[ʚV8JQΞ.ѣGMN)=8&ʂ(Ǵmz)?C@ s.;;;\zW^Y[,S^.p4uJvR\ ԩm""p-a(dF=0ڨo=Tյ5Ξ{˧_8qRJ/Խ.&~AQQF#|AN:E`qqY(b<v={kWTvNҤwV S|Nv eRBF&pTߦ`pc  6˕8|LzWC=ēO>Y >\ veZ{f9pN^6% >ZQƃE`އVhQ"D:&8xf!Q Հf@9/MzB]j<T p {=h| _`zzzW捼7Ol2 7wwrA3 Ffp8k,-]یŗR &3h]{l9k|-$aqqǏW,Up x4q]qS~4X]YE vMG<]QynB߬#}cڶ' ]8#jХk Cl'M>]a1\zJU> dYF?`qTf?Jya?)Rg~QplIЎyOGc{!Q !!Jiv<<==)5#;eN@Gih43( O& *m0 "CNEc)U$DوpY^Yd jTw,f,*JZFka8z}LWO Z!r z4333m;m3!,b}b * zڬ" ҥLX=B tC9lT%j9c9U!1It?y+Mjiwky{ǖ9}; 4y_Y嵵lo zVgvn4~V6):-b7ժ0(1vv2;Y!euz´o-CiZ5zO/#wCrύ4/];;;lmm3lYXED!%Yvu7O/_{&c ĸ9^'(_Jy+8!\%Qhj"Cw^b~2rﯢEibg7\' ZMNm B*CѴ}벵x<橧s? ;% S ;;;lnnxM\tAf[bW&{$ه 8C*mr;P`eFѦVdvBNǟfa2(&[2dJ2|9> z di7ƫz\0駟f8zVyjy/ploo:Dyе!d<*H7eEs 7`= +g+ +Q0&E y-3שS#VA! kj3_8×|wx7 FNi֣~essUa6DtCa r1fz'QVXl!e. ~铐;޵FSY_T˜H9ӀDoPDyY.LK mhN[5^8o333|S^{~&*b.xn_bC?!އfw6?=gQD=$h$#@wqYR\MBʹ10GYzHWa0]

7* 9hO)킰->A~ŏ0ȇ0ZGtΓlM{: Q]3%F!7s}ZMsLt2/8@D"E:5Av 5K9H`fCk5Z8IQdX/°RsE=%H}`2PKhݝP/uKÊ@u7!KŔcnKe\ ha0p@]4W^ff5:I1!5S]6ol- sۘ^ !DZA"Ո̮CM/rA:`{;EdsLOw6+jf1sKfZ=!q"CucՕ5FfpQ=Mzِ <@/춌n?<ς ڐVq: iVggH6ަ3VS/6*'kogqd8%%-¹ 9$\0[(͹S[rd*(t+:n8z`9 jh674F))$[\ˍm ȳ\DmKQ)1ḤQEOyl(JHwO2h0 $D"E,>D:]&ANhj HIrQ2Lu]j\uj˯^36W\g8pjȻl6h4L&1I-!#8"B+&m8UA8$/ pL!+5tyPRF\_dCR zz #Ga,&=bHP$jZQ1(͜0tG$˅B2B\Y G8".6gqc4Ri)XY/PKH(1SIJi*q9[[یA͗~LlD8Vb[\Z̩;Di;v;dEn;wװqI(й+Z8B^p b]DYʽlt|Ib榙|ddխDbC$P 2kfU9H%zlv(tXrq5K% ,hy_ꅳ;TArg{)Dz4\~z5m|@`fH>od[3E2xs0.gI66TvweN b;4w9F;dj8 z܌ l<Vsip!>Ƕ G`Sudž&p\of9:@37W@`Yksqb(Lَ^r稬k7yXї*\+H_=2,A~TP6>_f 2X~xYR%[eLxD6m7ZPHaؕ~;5Q~V*2N)e th>n `jܩ`?CĤ cC2\ނC=2KeQ)ͬHxI#1̴Zh އN@|:>{sQKO=\Z?9 ɺnen}&7LofV^jnMoQJF7`%BF4dx͡%U;n:1\,@Inrn:75 }Ysqq.RJ[wK@"`&0nc< b(}'+{r0MB |X)umhi8m|wccJ{\Ʀn1;uSz}5.vs15o}GW{{d^i^kf9y;Z~&a1isZ?vislu9\*ܛJS_E΂(+~a\/pz¯Yx܅P_kƾK,zw0ս_ݎ}:GR8qNk߾+ԛlNhh.IA.l%0 ?ǻ)uj W]S9y0,?"'YcPQ+H H <Dk}\+(tBn ʆ\M&#vYS& ! y 'Р\g! wA2x殝_0ԁݍ6ZB^*5^Łߝ@|^39w;1_A_{.(LCa$Rps/\O:Ea"yiu{>O?"2{u8Ӕs{U֣26@k<^7}: =n~nQp=ʼ]å O"W8 nc^~T~+U|M'G'~q-l3^]\oSEY[9>*63 2d<,Bg.F0!3uj5S5yospn= = 4z2 'f"Q9c~eMbk`Vc?͎qwǼN>vv0z; 26s ?c ? ԋHxӬ2紱^.* ]en>^i I2pBv%zCù6>s>߫N=|;=by+ڐ'py+Wcnd-Z]vbߟiry/LX+ߚ±aMgCF5qxp J=22q|p="rϼ , ,»E6y[&8M3úTи>VB_qd WWƺ> S61(V@LY(td穂i s RJZ&{_{1NW뽠zŹykUe{ޯ+8 WJ`]Bp:,`RX5\~&@TBc>f8~3T<@h X;r=b1n2~sѸ/پ\~p *~>*4U=z 9KJs|kesi!^A\X|$o Aܩœ~ נ~ȇ72B ԯB^Ci-ip9A~K[1JK'h;Y8;U{=N},- Zb}A+"%, \k.5% LnyĪۈd |}Y7R@g;Hj֢ 0BѢ;]͢f݀M0xûNNhބX4Ni]?wī0:j6w>^ŁHPiH3Y8< CzYHV15:se.~ߖN !(^jA< yUA+\rExfp\.;BYqytd+Dj O)k,txG-R8(]\MV,9/! v;x>@ o{Øn> ZX){8uKLG/1,_&G0<)[[NyC(o{C+'/;IM2-Ĩ:Ɏ܄<^ppօ)"jU ia4)3+RVF2q;Oe { \D yspYZʢ<(q *K;u6>tU@hHl1$R[6<Wqdw3c}*Apa=;epyRd:+~u|%^|Z{o ExnZRws>U~_I8uGH.+NASpzթ=c\s:Wҕh)>8x'^:߳ypw\$7xTt .LW] ̴7[+?nb4Ezq~\h=f+|ţoC<GK3>#ț %.GvAg[Bϝ{/C,o8zԯ n탹5Ňf5W];k'-G<Ƞ֤0$"z -+Q\d:6/ mea <3 <* 0"KR 22HY#1c7ѷqtҨK晖rr'ۼ>HTQm%Q5{fLUyq۴sٙz- P^ֺϹ^Sz̚NҔfNj?XR1<_Pzpm;>< }{3%뿎Woy??qV)B(' y `]Ͻ칦]T%¥J5m'~`Npa|׏3V=a']G_>?.$}\ƿy2^:UO8{ U_ ??֋N*^?Y:xK>SJ౓|{RӭTQIC" Au2c")|WEc;^N5MX3l}7~On`xpR|E ^u<"3 70jBlB3 A Ⲛ5¢Ďǵ vb 3\P+ Zks]mPGnx.ӱFh@(1e*Y nCؤy ʝY3 ^pzRbB[ .+s5s`s@˫8Jǁ`ʩ-zj.d]Ba#wuC.܊r& ~2?ȕXVItPF%R ˤv)^>` sB"q?̈ }uoEpnig qnT)FTy)Ї$ŋ)cmMiG&U 8Gxk=K0/j+q9@#C5u K[^x^8tqqLXMGO^] yn pLG:XgrP$;ډ9Ӫg Gݫ#)%\濋oނᄷ>(/xӭkn=^_uNS_r\.IۃZ *94r. O`.*&- ˚fsZ4Ln鬄`qO@a|P|dJ}jt[sss Po[l"|^ŁW(P-X]Rǖm3B1ްF)L#{#*̮z {TIef1|(ue%XsGYw!ސ(+ҝ:*<.Nu"\8M%@aRh nٺHKN(4kJ=wp3IKaF"ϳ{*K?5*{E~ ^/D6/|aI&d\KXt 3cugdf3XvUOyšG^{#\rzߵsov"# =կ^u<"[H J *+Y]#Ǔi`y8yװ8[8 Y?SŰ `)3l1lZې6gwUV 'J:*fE,1m7xbBؘ>_oe1Bd*ԛP\S\ cF( DD }=[(PUؚˈB %igF T&@3\4<4 |O}} W9e~@h10GXԽ)z; g)uțcM4RTBXWR%žiaӟIߏy9: |qR깫}C=c" Aሳ\֣^c8!#^2*mg 5튬X/m%9″xoY?s,Fbo"py8Q'x=Nk%hxr%uWz<5֟0rӭkxp;߰'11pO{>{8a:z1쇄9V:0kaq8eZ-!z^1 (u? 6;xڮRtdua[cLʴQ-3C]`uUQ~ L8*$aZY_襤%&k9FT*?6'ͯ!SfJ]׬1"T^to (63pK<2g$(B~|ԊՄZT֦H4¼P4RsROw"!:7ėJо;dr_Łf)qqnd(<i|rʇ ?E#!õ$ӭF?EY](4v~} ^p2%Qm<(wׅ*"[>"sF bĿ>QS߶_~ qGd78#snUf 0JaV;I7> 9 bSBP2UL6y(32,B*X!&Om15Z`u›';MY!#(V*KjR2җޓn WA/nzFy͆q#+2v8Q oœX| 'ưJo:}58F\[zqp`yNft\~cV!UӺ71&W=+B x3SsW,s+0"iPMQ_Fv*țEvyg4[r4FBíAxy"fiiđNp6?e`O\"drYksQh $L(!W9dS&e/o8'a^& -7HKe!ԯ@C>c8G7ccfdV=瞾?BVp7yW:,p7 y}0jZ@kW8A) oN@TYnV _1jN !3padf|CõxYLpc"[lpK@nV\Q^W~0"̎BjT`DN!7{9JQ &`F4"2@d%"z`$( j:,@Hz }24-}6W ZC&%(A KUB IDAT@AYi].m\ jJp?.[&NMZUp.jufT\U9Jh.c`VW\Eھѽ2=WYKT GJ{ܵliɁ5OŁƊxp`jf2oU=M >f%JH,DQ$Oہ{ʚ ߃W؇ݟSTV~!Sf|Y?%le%H|O~ 5o.\|XXiv/G<<3zg8>O=fb\Ɯ).'<8*b)כڱzjQ[U{LdÑ0HU{J"qdT J0Af%9Ul` 9g,F (,ժTჳ~xnN0_c. w K}'09̱7@s.D-ga$OHUV9ROXUwW ;Ε^W-T,3!t 57]br>mBU/wT7wbO 3X 3-$Xs_UR0[A4yt\JX ھvyg{ڽcL(db ] x l;ĊϦ~Iq~qg# W!:B-5(~Ɗ}˻0yO w\6lTpAp(Í]8`CT<0" r ~24H {(ְB< JŪ>t lG@ -+cYlxsç# i2k6o5oEx0ݺ[+}OsFZ]t?% }8Axn= G}$2õࣿx?7Fr\+rypuÿCL(bh1 ^"3Z'EbsA|K?l+3wOc~I63(UtdЪ`aSk˔FEcT?(BU RIҏ)~ L?+q2\W"guӪr3<5Onߤ Ѥvx{لBc`.J kU9zSYB!ͥlU $#sCTQQ`t^V+XT*Ra1)Wc)}%L=fx8?O`D}J-EW/&ҳa9_Jc qck'ApR_iMPC_ovk.h`ߍϿ4g>X G~>1^"<Ƶ^wp<^s+JnpĔr? nߍ@O:~]A'q2C<‡?bKe{V5}5#xT? a!`h`ľU*(;UIo#tJlc31 @b*BǴ] 3 }\#t栖wq6·+#`%,슍9S8F a8~FeR7t-$s2C)gZ@B(ɹzXvY39\`6`?2F#ZTuAdV(-TYIp nYngnC D ,V@ + |gUWFiMauh0J<⍈_oF a$RO8Ietx!!PI)_gSsa-}ڔUdy>(9.}( Q\8D$cҁipW%\~ Oф~_zz+0Hi@Z૿?N/^фtx2y'J`:K{!J< a-Rͥ)Gr)n0țcA2S߯}oz7|''/y-KVfMpƸ$BiaC$$ dB+u7X$bhG^{RB~邛T?1 .Y[G8*{XWW>rła%ɔW؄VWtp@\(ao Mgcr9(iX` Ԥ;SZKoX(S•'g :n!Qx*haPk^|@f?cd! OP"N('=a-ŒfL<3+2e*H" '6u}!EPPUD?kMI~k4NY ~-c | 62ʺ݁94 yHlFᡥnz:ʯ ѡ9]|Aಮ̵L\[ |Rdﶫ1DzU ޜHWR]sCIBI7H* 3lZlj,V[O=Ÿ8`˹S>{?;p}|+xǧ^[6#Ʉ]CvGy U0x}^`T~xv8 m JG!|wpǀbS̬jL-UVyTEؿPJHZz2iŠir=-qv (X˅Kq|d[,a}02L7rTNl3d}w)YN "cd%ϻ5>+A -^DI+F CuXyupS?aievvGE:E wfkF}Oi'z/c^*+u`.B ȃ$23zp*FI }a﫾~$OGdBJ}|_a,~V}01~²'\^&l&3G,:SO#^zTI`جO%\ԗM8( #/  5?-ҁ(01̻܀?R E> tE>򣾡ޓ_o~^wp8=O*kt{C7GHr\5.LÈUL A3;6@m¿k`~z' hP [:+!_oRQB5WݽN<M"Ę9q,:V'!撇a;ZJlѲFWYPϵL) )`JUc6GMjG2ǟm߄+{rU}=f,C)]On`xxxqd,!nM~>'S)ratJ9p|>KeX{G/lFuf!` Y{!s$32;X+jA55w W:[ L FW.ncPYh2kN#Xep<;RdkGT>;SUKIJ/^l$$SLlqT /Z[ezwE\SOkū 3IfG=~Ҿ[UQ/Xi\oT*V\1KߵY3-FsCko!,lV*=6Ocsy c  iyOWVsV?@vx)!$q;O ^# M/*.c6,M8Qޞ<,^i#aXft|JE61C$C=H.k(oz)|8 Jrp? *BsvtaJ%[1Y#H\٬c 7 B$ZE?{7;htAHOW;H22 EB:lfC׌ UPq DRҘKu [5QBnd ^7Q#z\~+,^fG&DҎA#E PX<^3sI0cQ\0AEnvfIi=W@ 98y+u@:G\I% w$`g2D{ 6;&.#x|8i4LqaF䓹My k^)X1ôd;PD|jƀl};sNlq?Xh,lecݢ*{zq0Ol7A0ex"?K M~1N٭:ǘcSd^ e>b9ߟ`-Oi@4#Q`WA+gp3gc{JAWYAm ;Wdp!;Íb}5eK6tG 7*<ѪoN&p+l)SCY Q0F=K\ݸDGl~uKLbȘÞ[ qv+>Y=Bhs̓{oQ#B'0,DHⱇz5ď#-ڳIѦ5ôv?0,er!Xfr"QQ(jBIing<ԲJrXJ<I$tE˔ӮSaΐY&.T~nx'ջXz]DSFvrQjϳZ.lQZւpn9 s~MRe*Z6J"SKS`g=LXB&ky!yrk]hd륞,o0V68YkZyS=py`\9'QVy82FfGyKO`JoH^aUs6[`1{ Z7Gn]gmp0^OG݇I gyP`!DTCRyjDZ,+قHx8v 򗒊Z*qb{]&r="D˯iU(]К,ʟk##aIZ$gƪ'3oq_Eڻ\>V1rK"l}{e+YJd/E>@i &tBpSb5b>ChEfY&S =B\:69D'(^@&Q2J!f_(&eq] գ/ܪc̜V1yA9M} 3<8^@Ĵ+1˙Z|k-CJ\^}k7j3YivcB^,;)`٬k JOsoԌ[7cr֚չ #0mO3VqSXT?N`=_:c*pC;'yzK[!+SQcCg Sq#o#Ut+9Dd2mkZ~B1\1*qe K2CR,IsF%1'!KhD85ᕡo<`U|Ȼ*gM.7^\7pVw 'xin('Ȓld,)cpql f6`p d?ӈ`{OA)$8wKTLolg#f9HOeWn|}oLzP~_8ɽ~)mN$ +a:|j@QKL<;¢=SG=YQ1\FGj9>j|0e;k*]s8pJe큺Ͻfj BZ -|-X˲K4śnaZozA3 0 GMD:bΚ3͘k^]XV"M}|N8q90°D0noIPz|Bm19% @(TWj|,;+XxD*_U~ *Hسe|^"y1DnU8TNͩ*RBX&KYgTjBeF \|"1Q͢ nPO/>q `-sh4н `^ošQ]AhaeaCnkrf`oR7>2,nƙ@]P#7[ͅ6‡F` e^O.xIiHBs@\%/#&XfKDB1MQ7P=>GQͱ,e^H\T$|ZR~4Fuű {0+1,Kdن7<+u"KP+vˏtO5N+{puSA=Ag` veoʼ,l 0ޒ@H#C joPr.%T1ْlMA!h91hߍe6y1 bV!c 7h؄mHp0pU*+m$ AUs.ڜpҖ1$?*[KF! 0mDŽ;9-b8X+q8蒋}~oasӾؾ||3ע`ZYQ\wqNZ*,(~;z=HۅHnӌhʝ#Zb 44|RΪZ N+MsZ4&[ W@;O6t1%=Nda!q"+z:* ݰP5^f"Nh SZQ#RZ}S1 Glpmm\@LC.` ,`ISFЄ Ͼg5[aBS#8#x\^cJȐ+By[JJ['.\a+Q"Nsvsv`^1^E;~$9k{@J{]UeU%.W־SJJǡ5[$χ\tۆl יZKT 5|yJ=Я&D9C0Zx\)ʜclw׃|$CW%% `mCi3J;R WP,Do`Qdti98VrIc(.ntD RZ,51s!\vB 79+%/b4b݆XQYCg޺6BbG(anx*n 5HjTW\EԵi>Sҝ9E+b*ɼ^J%QZ-` E`sU+&<w$XU ->06ur'P(gP' 8q(G\`6&60U$*f-- };z-:£ Khkb`UZxYZa5UA7(4Cܺ98RK*8MḼntPt7y\=R:YTm\S3$f83X;)oyO2O7(!0bU*WJ BtLn]O[m_2dPLSv #Lzte<XX!?@9֑ (Ѽ /xd@W&q($QՃ"nwc'vKUҁ& htsń'pLh$)n˓,b}{V bU 'D|],1(Qb X:|eY#XRM 2vfnU ^*$= Ҡ&j^-S$(~ƉA>y ORk:e㵽b{kym+{\1JLNPC-8 ~:6ENQ 0) < [B`9iVy&u% -w <:9mߢ[W|eW=g 1< HI=jRcNcRV{;6ԡpxTcӤ<9{b i)yJ& <*~ Q8ֽ[ta,lm`dVئν]V?y1PLlP?0[\h*|1ںo}Vt^0Si *$[S3G]X[ *7qjJ9C0>JVggg$nE׷Ӏ+Xy+G" 7x] <<+a58_Nn! :&LӄnуV lq/zV+Lӄf"BJ yLK0uX,L8Q^c/QLH (zzeG $2)I4MXt diD3Gu lFb`Ę z3c= [bG,VH`:t0 4y0 a ]> $q_9gð0H)y D "#c 5b`ZvQtLPO^0l&,1Ό $o #81i.;X.\-@Ȗ_BI~d?k3iBOX򉝃AJbY" ׮'5 ÀK:(\2a9}oT{ V>d0#', M5#WbMa<.U]ׁR`l6H ,K5f!;7";+z:Z:#@]"POB 0`b27q~d HKv KTBZ/YKcu.[uԋ'TxT؛7 ʰlXaڌY·YswK`P_WVWbH3%3tn/(W>vV[pUl<;ɪf+[M>:aZ%L,݈<c󤊱yt(!>+=! åM-&)G6(iq8<UUCGre'/}7~0=Xr x <ҀxBwaiYHu˳~.`*[mCjgރ[׸ǬjtD%Zh*+[_{ L뎄F$}&zYZ7*"PSLCtJ2 'x;铫¦~ Kkz}"/~YYVP+SZM+(͍Iư 9RZG1-<h328cCuFt t$s@=FE4]lْ}'ZݭU%PKMa`H!C̘2aˆ#!3 C 0!5Wu;;C]ʌ]vd;bz~{B `eT Վ{gU=-%:CQHmYE$AJgG+@M?Xh*`f,"pHrq<{(.q)E8QU2sWEEcG/3C;Pb~f홏!P.DAmy6!"h*ѶR sC{CvKD㣀I'dê"we"B׃>Hd@Ts { ﳥ>"[e)uTrh3+Z 6"(]J6ls<kp2lhcL1D9x@_3ki6[:I4騀G0B@ ړc13" @_>vRpZ*֌dL)L36݀fx_ 2[ /YSqz U0bLp5@TtP 8u2!geIet|w];ŏ:$ IDATx5}7H6Yu0^yAP>rCj p'u,jgީS0z7؞Y)1 Ƌ F]lKGFԅٲ?8g EؘwL A1!!7rZЛPٵ}"$fHɓ #OӡVyqIS=Wܶ^=NӼyO_?)v;r3lz)@TȕPhw :D JuHJKu0gR ԴLwO@,u΁@uOzAhyNk%F 5<-@y "rC7RbQyr ŁRYW,^XǪB='3[AJPA'FRq2bίE4W# th ?vR##kLJlϕEcF?xPi</⼾[ pJ 5J^,^JcR=6}1B\xBYQ]* 'D-RRء(:k39L*k[5-I@ '6HHA- `Ąxnd"Ê@ck$IhL0I4;gYgL-'-\#! 1$2oN4&$JVȉ%0?^a*H2vGռq;1Yܪ3ѷ -6&x !t\  #g  dDE8g&[;6;K0AQیk$={0~kG;:W` #[1f jx r@(2UVHY;蠵@D|&G !m"ANFy]ֆe6N2w{){޼nvQ*NI:bg)CϫU~55',t3&{ec ytv*0|ƨd!ϑq, Ms| !ܷ1B10d[>7l,7gRk2/=m_%ӟ#W> .DB}~? >xVsF!Eo|٦F!SD~ӑg2HAt 6VX`!B ѿa!ب^@$}>O-!)6͋@V As}э8͙H+gq6~f3HZ( g}gzN3, ڟM&f'2GJJژ ¢i+1t1H{@sjVR}, unŵD6)Yԡ`U?  BŋؼkGO I&}&@'B"֏DnڙJ`pCVpfX7,?gZZ vԇ^KF"v՞Ӏ*Ƌw:KlF2 bALuWaD$P§ֺL%dMANR0 {NK<&n}>HHb | &mt~>|N )v5o!f#I &JԹ =h"9y(gegf 9Uß ሱlo.Ʋ,T2IB0cd˦Hj1& {N N唎9 y|I>|8&}m8 `4=aԱa/aFjgb@"|?ٹJ-IPbqKi%pJ9y% 8*!OqE엳$׎k7nb4tO{Y~nhv))}Y*bӘy7>:AF|Y | ʻw>~}Ļ5ŏ>?;/?)hZ?DB5Lѹو3^U߬gh NZܙ0,: ġk$F֔۠~%C_c,fyjq4LVeZ;B.ŀy(z pK^\=^0yTN77x&^JŦ0 8,բU:18z*%gGD>B/' ZDz2@Zh PmL8,1jL@Ŗ#zbF73X޴^dL<穝鮣+^Y XUw1b¼m“"_c8)w'/(k.ka޶zqIcӴuyxYC#kJ?BԾc/Ǘ}nJ! )-/Q((N36EHQXn,*2GӤi‡BVff&Gc(Ob{L:TO {B߇)vwS[ ?rD/,?Һ-PnBEo$S~sNMb<50)]({gJrÉ8q+/hܘjt}K[q_WvI!B*IRΓ'[s -6MR+,q)zۘME pkpgO {vL ><6`u8-:@]!vRFųpc; )}̖)ѡ(bNdH(@_/{3WmoBl;$)<@x<d"!pɲ|OmIk?S).ddMyg* {';3>ɔCa[q$/#`ǚri{l_I9OюqVJr?JJ qMD>7j4Ȍ6ٜIaHq 2ղI3ObP pdTc-ҧb`#%yHwFjV5F:,|mAat}?sƋ@2Aj */muCMmVa^T2duDkٱ oa28W'WZ';TLVOd˂P1_I#tbé|~9ezczfc Sw|oh ,ͷ<%k"=PO?E@a> &r˞Wï`kn{$;5pnҋH1s!iys $.uқ=.g , 9#: BuvQŒv0Y_2R VG8I3WljڰJ.gƚ5}[),F*HsxA#3BUkTJKodYۈ Wp#[(K- ^аLҁe_* ,R/_yg~vXqJa$I|<2qωSgצ g3Er`ngtr$AR}ֹ |>1<<&'Cem7i u߮1>9=et/?s:!lcpƱiƤg]1{㌏xk[^x}cDe?bPنfzcјbR@(vsA ˁzLO?]("ˁt0?4)R~И1`$(T0I|CݛNXDzx{f_K ׈a(A>00|zeE߮ި4L2`Su`7RRȦg leRx$ye1 wTM[Ȃ6nI.sLT(ŲQtR&2##~On=IǖR2`٫S{&#c?PL{JK$:)WRԈe3OᆗRJz$Q|AYue qP.r V!( FЩ0S3߭03fwj<ޅփ3"q%l󼫢{VJ_6$Jmץ3KHvtN jtTUt9( 6= h*CD倊ߟT4~&#6pD`^oǒ\fq(nזf0+PEËx 'a򫽺~bÛN\"T4'T/ xNJr+_2br {N?զB[x^F@*2\eI0)LJ53xfS9 u7d{ӆ)0tZ"svZ#3N#w:A,@A婀Tؼi&ؽ a;u.?E^CȁZ3Fuq062i{23 ^iڟZYuiH8fˊcQ<[Q15X:JY'dq~D܋頻Uw'xD_J6$Lt҅`U%yF)Demx{W1`{I p"oD !c!;ٸǎ^/]d}%u] _dY\ 넽-`J  bF]xx$(kA O{|?l~B'=@H4ó(V;){ZzzgTN|j"2׼P-Nl2Pmɧ QY܈E#}T_}=]mxu*̜r$ᆞ0:g,}o:0Ywj[96 u r)_ i49#ROM"h| _GrWq"P;7ԩ4<_~vF;o! Ɵ+X7~AǂZ7eU3ύIj;LND8| DE]HW~c^@ ֆ IDAT~;Qڕ"kd1@>ŔdVo>FHf?FPwi2 -`r{z7S"}dG{elEǸNȽfK I\9r><_{}vFf$"$/Hsl7CU/zA*wࣣ,]a]lZNXKA傧'R-8BXZ5~W56,+-H0?ϰҚl345ƒhmUf@@KD, {Hkz560 {/ mݾw\r QK'@S;Sɽ ¾~i\G ' b!!i" UdφE?P\!-i=~?1?s{|pVu&뺢^*uǑn1Q@x7 BsۤY*۵ t; %%_2ט[q7KP diBgNd':S>#3׹gh0Ry0X0xG7={X h/Qsp+L:&ʴ {,g-c[V Ȗi>c ΫApCg}Zxź<ȋg3}ٸ_$qj9kSRL1 qݬ}bγ_cptJ nr DFxdWcT$3Z&ċyͣu IƬ_~1NJ ŜIּ aїT<-"2[,n,fvyb=]k$8ۍ%Ban^}UV}s91,^9vܑd*P[7m>v pT'}ֵ:2G2k1:ߠ*]=pk,_N"cJbCw6y^ Ń']jMоOwo#H}d1߂H5 )'?D5(Q[Z+EpC&O g TA6贿#"2 D֭WBgnް:;iw}OP, &*f~~&kѱ%b,_[ Q=C {-!ːmWbҀ2?h%"<,e"V`xҪ'#,CUҊ=17Rk3a!{K2I>vԵ~ nkj,y2,0CP6Z%[#1:xA}.Wq-D,v\C4[,y dUvAv>1_=2)Bk-7F`ߟB8a5=LFLTWbLsCUY@ JCEts;vsV*P+m^]? RZ?0t({l~~O{Wr @7%iV?`wNR4D@Igɨ`析ZAnƋF?ݐ{ 0QIG} 3FE'\r9Wfg\ѯ6ƌ7D?B2y '߼<Fj>{Izl^Y0 4@g>۷<Mo7j%RGí9vj>VݳV/NfD'}iKq@׈􆨌>Tͷǫz/ѧ #6u.>X~NcC7Ybi]3p16*;؃KsL< H;:MhK*T ee]~"HK #;OV-v`$X/@(|;'l(EAAM,j'7Q*$5UAF$%5-:bE|>{9j%!3 a< oXq(D"݊"gC|}OQkz3zSf^.Td&d{, wCѴpExϼ[NnP$eI>isxNc*4.۝ YBs\rA?3}J)hħ ul2[Ǿ ƾV"ͥqh*ε>:%G̅W*%Ajɶ b1Ivm*ߞ- Pe)9 <$NJʿPճ ̹m?&hI!~X!IJ)F 57x6K `B&Q6vb_/EAs9MxE*$ tO{]N1,6g9S^&+?ÉK2 fi|//kT(Arg>>5c(l@?NND;.qQaϠhrͤĈ]O$DZڊ8 -~,dV Zw(ޣ^_,ZgbA$ /1{ QȺs8m >w*GZ#b}GYDP)~>=ۍ_Q%!aĩ`EOHrR1$ְ:] 2$zƬ8퐈qY!=WD솽&*Dl F'_kZQgp#<&#V$[."؊.@x;ְ}#]!< )reYQDfՉ)c팃}Ҋwџp]6=NgbgtKV^9ɉXJO*NJ¹WNEQjEțX f(] 悮ItQx0aNO" mThB  x (aJu|Vǥ [U XaHLTߋut=594([qDDzdU/\醚wX=TuDqlO&LpE7o a@4ȑ$"ERnBSbvW˷T0_^v3JPHa,_%{&u"bќxݭF@Iю.N4kDC\ɨUm El'}i`zkؿ`ҵR؛Ҷ ApFxlB[uRw0Y F HČIPKLSFL.aj;xH@xvCUԽ(8gœld!;y`#(IGxFsn?U"p<%"׋U*8ǂ0!z}~7ϠM^po72G:ee#gcX{JӞgFnӵ1y\#,; =m+bF`koyv%f7M 'YI4ש ,UPbbisJz%,M>i L}>Ha )&4.X k» qZ/¤Vޡoe1`lM g~@kݟea}gvÃk5 }3"kLN+0vm\/+.~@Qk!R|,mrێ;̔*T!By34KYܼ0[ &a)rIͺhI@+Zj]j>}_|n[K՞?%UM!e_tU9:Ƣk?#4#h~<tlRf^+R̫/, 5h7YQ }Z=$aw,nJ1Y3ao;6ŵ RA玽`6ew錨\]q]!\ ֻ ~?? %bцHu{>):>ceJPW ޯZ+V־U;. }͞R .#֦yV =;ͤqa]W\.V(m&U686D:仇{pkvBy=k\Ѻb;((8cuŶmgm*3Zp\^Q%'"E+py| Xu7R{B8h4 c/fD+/?Og˳^Z|A968?86x-^| {=!;;k0p#OP!ܿ{4Z{ vUź.ix _Cǻ۶a=V<>>W~Wg?WۆeYp_G Kw=<__?ú9{/25[O1// q͋b.8ZWv&e{vk:c(w8>dH~<&z[Y^9Z 'H)HA00u`%%XI@Tun׆P#a<#/%xPgI|HZqS[;g 9e4W;1IK˗v=3l3л{z{,oVV6gVYJ9:!2D0Kn|Ȩfo}'Y# -Yo $*ɝePLn]7cT&v|>U8^'y^ż +Prc <>◾]ǟӇw)r[Z|jӺ `H0`Vó ]R Ŭڪ躘qCGdw+P^@caOFPpzZMu`HWRwGY=eqlgAdEBDCG7dZV.Dh6lۆO>۶x>ed6,GOPgϓ++|Zmw qc(ww^fMwBs\b"[gMT J A,65IWZ}Y \.eMuxo@X撞' @>gf}A~br8|h @k!b,ş6O=LX ~gi)q ",Kz7;ֺrg[Z,YaƀR,JJÓ/_6J lK)xzu] ;j}̾>KC1)c{ j<%ZL<︻˶pOg_^5.W2#}e ݓI2T-sqzT$}sXD}ʘCDBIy໋PEZW,\"*>iGUղ506gz=v[`_97p'CL׺=P\.Pǰf@X=k?&؏/c+AR'cZFȐ_LRԧe=1W^+ŀ,; BO7:DЎy3UE{`JޯY*gÛr)η "q;^1>=Ag!:^::\'̇oňpcc6 p_󇳬*9i7| br&6q4F0"|=$0ǓDgY2K>7[^b4{IIFB@v|PJW,3< ~AW+~~_O[x|~C*uM*ċ,Wphzj;q""54Mv}K:7Lni5ǻa+~?Q g8 $ 6`״> 4O7V<șb+*(8;1 ի^{irOֽ!G_&??HБv*`A"\: ˚@RT_@Br P& u iܤ1!V{z~U) 2Y> ׂ_vp!\Z4_JV+]LI(G0,%ouqh*`?B&8ie~1Bl^ؒ(I  nޣ)$U YW$I?^r>(g[Ðy*9ykd^7޼0M,Va)"VԊ,,L5 lEuMQ綧 %}&b4UzF FR ws:u`xƌ)m$SU|)Ã}+Km.970$< *`U,_V*nkTPԈ"3ڱ_WEж G]*P$y!rࣇwff#ǁl.Yп5[[1v# 3|^k]pcxтW𷏎v\_^??zO>?c<~GBr12# jG ۯ*1[[m'}L*31fYƄn8<(4UЅA'T}R[/[_ =~,w$<]nx 5~(-G]<fAZELPK:>3swk)02*S!KZ9;QIpճ1!]!xP5MM D SڭP,tSIG,L|fF/ns%H]5?ͳ@1}G3 q\C!Nj!f΂|6˲d As&Q g iй 4y|3M)OÚG#c-5-^= 3p'&c4@d)Z(0*-Z9sBDPKI'kh1NHέ/۶Z|DǑf[{6gT.'yF̜TMU!- Ҳu]-kw>Ls Q?1Gm10.R\zvZO"l"bqj'2=^p,z<7`@q} -5˫Xܣs6Ϲݣ{^32zȱό>uK[0x閎M=ʧ@8/ rKL*_m?owo'ѡz. OdHi麜^NqsP;  #NbN? 2 :ڡs[2wp <# XoT#c@Ym8ptS`ubp~ϓY&Аo>娮@2 D6?Aq wQc3 6,&ЙPJ٭{c $P51 Á}yg_.ooK|f|U[[ !ƯΒ`&9 d+E='חp7*b3rdAXUumv:V-~0fZя@6:ԋKqށbmVvw4+"2Qxh;e A[,.&qq2 \yvF*RK+"]ųf:n_j}0ٛmdkD60R5H$9Щy*SySqz=.-Qs@(.QAݥAk)9V~dDE E1a\@'A 0S 9a'p>3abD>, 5&`P c={n <|zS\W %V3"mA4x^q]I!w-d"H\,8}Uuy1s;+/| on`fP_8 ~gCnnjo6K°xfV Q3\ ÊdG)hv8)[Yc{atp}~ݻweexYx X| r)eFQ¶Rdn yNZb/Bx^ BaxTK_a%=7RvZ{zvۑr_aT#VV~;VWP+@&~Ūu AKvX tu/ >} GO2~?==>{яqF f%"iUiLpc2Q:R|dx ']J4R&'ɰۡގ RAЮ8,Oijj %<8󟿡׷CDb@gTuW%~5SZ\R_CHrRkA'Q{<4'~YYNH{z{r߰,e;_`۟pc+@ T zcuȋھCaw˓ru{(Pj6C,/'PcL 萓y T|xƚi{>qj݉L* i }} ϩwq- XGb^s@y+Kì҆;|Fl tt`[_hf ,5# *>kփ ddJ)a]̞WF c+Hh\ټ|BL!ZT\,4cZ!9Ĕ"Xnwp>ͥ)OBހ0M#\.m[Fx wb8ţGƋYVgß»>G0=<"l5@@_t1TnT -g ;)j/8KG} ౥0exa saB",SI4 %~/Xv.+`Р5zXe68$q^ڴ[IG9]\ĹZE's &LFW0O53|n7q1Ili#ˁM`+AJ1#\]AO׶a;5|n>9gHRЗ q^=T{ssYysS97' 1j3-;r+˚E1|҅ɇ-nXׄeu ޶mt4Ha 4"$w祸u ޗ~fY hg&lBa/jc PisX78$oIHkjh540b°+VgL#L ^cOժ4#<#Č,~u4@+41_¶2bjiiA jf<C:718cpszhVwk YpD*²d`F6; eKoR$8u1c+D78 ΄*\p@huOhAq(lz ,o[BJ\}x)lZ4̾eȋ܀5Hk u[bXUB_.qĹ SZ>f a@Fšղ\.x X%d`2m}J o?mkX\BNҫކ_"~Sylt#ⵆ/-sPܬzw*h9 $lROV<;55m趞 T[H9aK FqG FuFrC*X,g>:T *4& X /k0@$)F#- ÀfÖ ĮKaHC qb)XbƼG h"i]qZc\%!Rmp{x8o@4ayyhBw/0Ἤ /`/עqn'R]~6 ~`j0ʬ-Z"$#^hqqae66`3+NήT8,iCZ͂=b"ip0ahrab\BĒ $\B>g4M8ak=pS,ފBY~ Ve-*dlۆBpx6KqHa=8#!ĈQyݶἤ5*  n(q*.!cHtĵX63\἞-L1KӲna6feLád +)ÖldSReXR;d,ج}ϸ a0|sq Ug ;D1L#bӆi: mc/R|SEFxo̭4!cü8w:pubchO7C!V*!5`6kY-A 35?=ͦ tݗ Q>> "fMڊ OM*8U*uq, (UH-I,LAj)n[N ' w0;> tl 66c;Lw?1|߷)05wM[to7X q۪;u:q|0RN82maM㊔=|0"Gެd[9saFcIVGSv#q1 ~̢  rR[9+*E0`Y5ж-`&K͆e# S%P!#n3n0Ere6UI)![M#7xP;$-iRS0sˢ]aKp[Z V0ڨ)Eq@a>gl[9x<-Gl8X@!H5ꌡ`*2-[ր,5e8m9SK[}Y͞ܒMLâͲN'K(,PJf@rp# 1ںE0/9l*B3 )cI}֒ynd %r(aX?- V?lh~g5u, rsm.&0"e%ed!afm a,,c6IdIsV܀ פ9ge+1 :j蛒bgTᴌqAZ0#߿+ļU|ua^϶Z _VK b\\sÀ5Y\&d̍,ˆMH\N.x<;&+;oL7bOxP-m+#&֌sݐk۱( M l,%-=L~p.!oL1[+J 7\ay`pW88&g|0#O#߃{>+oTSD8ރfm)Y^ˮ՚2gq+uaBKhb"ЅJ,Bf؄Mq}imzǤUϋ:tJmSIk)ɉ͕ҥ1]I-'oژ*V>& p*Q$W}}綵9)MP}Pj!rn@7LE0 a9f FK&$ű&~ BJá3gu: wA ` h}_9\1[ HմnE ëY5v_5b96bNqu9TAu3CD2n+Ux?FÞڽOђamvqҝƁ[\ic~ Nu<o p=)4UEǪFqjHJ̠tm n3|"@cݫ)Fpʹ}Z#u>^k|7ڶ :wJJ3vJIXHt}}9l|]RSɶҤ~W:|ϢZPcu%GNr*]h-Hqزѩ87|s<t=W%Fsg5i+V{ΦaOUӝ· .e$gN1Nw{G|M5>|x2^`aDZ:9ŁhX ZNr,"dbه_R26ĩʊ)DiKGl3r7D[_m . dTGe]M-ʾ}Dn\甆'>ǸHsmԶ B݊"vV,_;`s c[: %o 8s tg?@ KόH_Wwq Mx`+ gjC^=z  T 3Egm\;W`!IL]B)5ֶ}j/]:v,\Z kCoM Z>˱kz@}{4ӯ0h:ƜsM,pI0v T|⚲=] uta IDAT(@~{AW1ZaK~VMIJߺ62J_| kuC`}_\[dOhu-R罯{lRWI v~_\Z@~}D)`us*Ꜳo^9ߩeYpbns>,w+?|H߯y0lמODctp,&b@*-wq~w)^*=Te{>ѯXen^(mTa=mҌfv뤩bDd>yvc1L:W~ o+I6Tszj)u)8dLU]]SH9oOAjPYfZ|Kت4^GIEvKYz tƘrZ`VUXgUk˹ !.zbȮչhYt; M\z};+PQq_hG%Z6Z0Ip>4R !Zq\0_@6 o$ W?(7{M²༜ !duB)QA$ y%ahbw(??7kaF=\ݎ-S Pp̪'c3 1҃AA85vj 鵶jy N=US%9Ѐ?!Z|X)Zqwbs@,f>mb\W_'RK)!Z{uL| {9Q$d)UGuS w)}|獩Fq~>cu]A w\`+un3 .;[#`vۗc ˜sp|'u@T'ړӢ4YyTq*-EF뽐yWGh7@΍K\ӽ|I ĕ tѵ!+}I['9qw5fT9 "*`f>vcR,2{` H~xa)UV ÙZ?128+V|e{M̋/i{SԜkk qn=AyR@B i0Qv`A5 2jjzSml.VKEn;6%0 j6)ب}!-(xe1[vk4@@Neή/c:]gd}Pp?5ܻ|ZEzVZԸslhaIUhB#6޹_Di4ak^3;{r.R.LwLHSQ*RbL)Y;$/}1=\0`bձu,F> ^W. ! 떕$MM^m P}}g)M*.`#ӭ|lbCX˗p+tw/>+^|ۋwpsݯ|g,n0M8yo^N^G{n3l[c Rt2e Yר!?`Tj9k|iP:(:Btn<#%,`;t&vxJe۹?FW@8:T3t͍u[AE^-ח 8.U}{ XzCi"o[YOKBk/V-lG &un'h{kνE-J PQ߱=]g뤱e'HW;]5kvfa{!GӃu*3PuGAWC9 -9}k ^S=9S>K]Zuu_o͚9U뺗IGwZȩP!SiSB 2}<Д3.f dK<cSXo)#$w~ |7~x_"^y;sƛYiɾ\lˆ<%<ƝuŰ]K!rP]}f=K r8eCʔ<@^ # PVK[_a,Zr+"DR+^ȱTx, LXʹ 5J%F|W-[bJ]jբ B"u9cǸ\SлI[J Wd|$>P>u}* P5D9i/>^: ip-<,A7 kPJ} ׉SMxKBl[IT^Y,xXhؚpȘc3oyۺ|s۞4{^ 1ƃ2P[4˗ZZwMؿ_Ɨ?K/0y8-p1)yCtL1qlLYaL@=?f@=,iqB zzn_+xVHWIk;D/Pq H8&}@zг5g/T]{w*hi?{#S Ԭi`8%SrB(?z}< e(,)b:v~w/} T߫#ۀWjTR@RP\RU P<j|>'XPv1Z,MuLWZ,B ] ݷ|Ι76xOZ KM 4Ь{Ԃ繾K &mnfl\A}`l[zv;_H1Fa7Ϛ|ktSRugȢZb+rfս g_iy}KM} ᾞ 77ksNUAV(]W,/)RJ>7 Wѣxģӝ+Lro}ƗƏ?N~uYYV+)b{cM-V*zۓ +%[(z J.\n AhkϹLmΙUu8ea@>x<%$ݶH5CeVP:Z!tT oap%Fݶ/b5Er)˕r* ؛q05x i(#rϰ V2xmUp[yf<? O%7/gܜnpsAJ2#'R\w#WH h&ie23i:ꣿsD-;4ݧZFƒO1=$M&[gj~lTCd{aJd eqݪeUX^y^籷lgIDw8L[KUa u6?^!]rGB .ϡ4?}>}dqd0o)btkϹ-W7!n}Ydon y__FS漺`sZ҄@+5JS&X]boF)t|X(hgΝsE~9u qL8t:@UhZԵ`_P>uCGAK} 431fИ>\E[{~pOp\z +݋B,F [9/!9]JY>Q[;ߧAN*Eꪮ`^ԌjnRg*!Hk:z^[\ε_sbrF3%f_@K;j%)~%P6MS_!A\W#wx;ށ%n8Nk3,h˖`.3%0cA;[M`v[,"_:#۟yYPp>,Y-^\%3}/@qzds7@E[`܊PH-.%)[JR^3\*ivoǽWJqkV' ;iြ~Do;c8}$~~{xo'gܜnc&ZD+HV~o1~=hM۪ {#Q>4>z޻τ`} z0cԾ􇽎Pg+ X}$0au<1?D:@}&0XmiI=PG:<ZI鴷0}硩Oi)7,ICn|m !*l6Rwq_=*0|dK+׀Iջ5@z;FGYw-Zv*V1= F U\>4>={vG" 8τܡD i6O%&0o w MYJWĕ sD mT\ Q60/ZP.,݅[[D[V o3洏i6w)I @jZZB~iǥRW3tS rd` t H/,{~?{woy># ي;V;pܺ:52i{I+ˑ.szvD5& bl=B0eRzTCz*pa+0fU$V`}jp,ۊ;r<@+鵍=T׃ǁ~ 鰺2x̭!ƈ:7Zc"P}҇ҢZ4LӾWAH)\USi?t+-XHS@Hg,|ƲЭ5q+]YwT )HW]p8`կMR*5zzVPBR5[rp1O*88}ݏoW?4@%B @۽5(j)umG4a@bez EP m AƖfXcB,`q0kuYD tU+Iu2a # 2w}1.(S]8,}w*%UdK#={oqsˆx|7Qd0#c{ti9cDm}q0iSUIO23 [K4/4M龐 05Nm$d3R؎jh^s7^z`Cm=`H3o,t9P-"馦rukU"kBWԨһ:ncQru`1.'Ƹ۽{8ӯ҃{oA*4sZn ::^UOdz0ԃ6au$Odt{7Szf17y Z^㼧rpM:v1]rҵRkiI'|NAKEi@R~&ƳkBR/祭)@fRV[3t?=:_y@I}=74/iX\z6u}3}ݳm/ J\~^04H$ gG>lxokğcn IDAT߉EO`XMZM+iyVYa2ᇆ[r^@€](l7'Q\hAa\U/ w߹szOߛ:^Zf]_ȜE@'ZAX_.&3Rbi%RcYy=pیp9Bx{9gBހt3csNAy3ͱ1zxh2ɘ{&>nr1 f;8\z d<==ne>|Gq.>ki?O:]u~jz9mp|)%q(_[T=T]? v*4ۇM?z x<*Ӷ.5Y5fFUNOJ*Ԫ6K?lJ{q =SeFP7F9.U0_Upp95zi:_z^skSD { ӄ2|8\pza]ϽU9bR^5<ϫUJiWAi=usl|X0>{:?a-Li?/FtsR]HeSB[/KO߫ ,qwlf03ϝN'LT0a557ZH@qB `p{pob8 >5Js\QrJ%f"np9㫫RtM-ֵ&2J5v_(K,8K}]ook|&8ᆱ՚z>c7RI 19%mmUo-Dҽ(W@^^C+/>K/m/ۜ0'dG*m۶;WAU*u?5%Ȝ=7>jHN2t=@>3U/d&N{PGEsGߥko&z@+=kҹYwCwS fJ[Ajɴ Ռ_rPAN׬Ya}Cho 4'}oma[7:^N85OͱPqBf^T0Q)0x)_*cS~Ͻ0B95cy1cGDoy#>=O?p95[V nٳxJotD/#.\U#Jc#t {w3}xE #z1" >6R:KUֿӆ+[}U8)vl ݣd}ms SOc7,7L%/\a?.L=6sFN>e??7\"m'#Rt(Lhտ1QZ0*PAwBcƶ%kD{-;8눂:N~Z=$& -4wl9N;ڻw}V5t㴳 8Kl(g;Ոkt8vU'5iJk?zCYǯȞ,V\eQˆ+].[ J xV)]Q]?{rQյGh~LG#5S 7z^AExJ_)LT_r4G(_Ґ6%EAҢ<8;7ǡm)]hv)Ubuѽq)_!н>}5StKTyWA ޷L.Psg98n&9>=NZL:%ݪ+HuX{:f{O B<טΗeW. s& :gHouRcc[H+ һ;*ei0b>Û a/ /v܏'|//?.v;/$,[%Rx[=̌CyYb슢 i&+᜹Pk0X.U 1OX: "ϭe2PZľ/#"hC-nJ鎽{w0k+Kk $ZEJ恚)k8β2L{U|Kw/Ν簥sGo7Gp@cJP`jZ>T-׌U&=2f=I2GlS~wHȈ9O@I *T҃5`o ؃Xm[㊜#R`iSj&ٲ ~{M&KvP ;zK~=Tw^Ln8G=KI^Ax NzvϾg^zmŖ"Xѹu5Hiú`1ן!ReĸޢC rƶV -aBO!)27!X^i]ƺεrƺ9bOK3vܷ>KXeTc{_v9%=XU ]\+0 \;~L|= ε2)mHH0^l+bN9nq8ojQЭJ"jULȫtÀ0Y>3Q0C5npc2#@[_k8L+`:XGy^) exgk;@~ʒycczx&٦<ƐUf&RfLߩZ5j&W "z-SP]}e_^Xb2e훶u)TD3S-(,-cQ˗ Xts蜫4m(}h!9v#=WOJio 3:0 &2UM5,Qk΁}Z՞}*{;`[%P4CpR2ǽ[ Ski[[Zz nRuhzWs 1W;LE`9>_?|9Ck9g02ĴK=5&UM=*y8!cDg!62KƣO} Ͽ~~ o-.j)SDv]L2X)_ˢC(z @W+[q fn+C6%MxEaܳrU2e5`eu/1} [.WYޚ }ݏfi""\T,%O׻bY Cl\?e i۝c?z0>0búlX3uAJvN'a֐ޅ`9n0۰EF:ݺyi{`ZNեqy/ k.3}ՃH{Yΰ`u>@^~? rJ5m[gwx\z@sRW·pܺ /[ iGsу&q l\Cwvۉx_*Ri] x}RE{[)uZNmݟ;|w83=zÄw>8~ 'w5p!>ݫ˚g 1-.`|YVԺōJviBGaUE-m3\q e1&Mh-"I'1v8O,PfVUPA:-o0ܲJ@}aCi]uV-?]ձԴ9x>^X_w};0<{< iB\tu5 HNdi!?ԭzajl`ZMsPfԲ0(=CͪYQRu+Y쁕jzLW]zx(?{퓾C}qzWJð?tڡ!!}tꜫ QۃK;C0ݾ_^ Stky~fzDk{m~WiӢLm Ι{YXUٙ`ú.2㶣^RZ質<+o ={{_{[zi{sǾ5]wq]/հOM z]Wcz?>ާq3J]p{йU7-[Ι(8oD6c>  f$֬;u[K98F@Wy}TK_O*(Kٯ}""r*qDx8y7v+ pцo-fs*te9gKW5aݜ3ZWҵ>fGW PInٻ52xiq0Ͱ.5 "OL ݚv]J݋J!;baLx"[1*p%rͤ|oBJR,MʥZ +'܋خGlۂ+?cFB s ^̻CL ʄˀ{L쵰|NUעi[/i/)X0y>_0:NK1 a9f/,^zRo`J:nՐ)LwR{[9zAO@[{coKK{I$6y腆^{7z=n/蜳-,?%%C?+u Pяsh~~Vy#]8Kvئ\TM?s 3c/ ]w+%Q>{Fp)~҃*mؾ&UK Ks6]ުֳ&>_jb'鏂~[{;39 #ûV`7gsuWXW s."DŽ_>>{1a; +?Ħq@{W4 "Ep 5ļra?,3A>!T=r<^аϋlR*0hzߺjZG{l8MRak<+,$ơxpS~?g~w [`ufr Ch|<"c:^|OWx~*~<}*|$D@S^Ã5Er9.\ByT6\Rw !?}(q(v{.% ]z1" C%-XT,L# MHq UcCJ  mYv bKpod/%VH]Zj6s‚N܏~ <#X-aMKv[n@ۅ.1} @]q߀}xeHgvfXRFVnJ+Wf^kԧ 9^롣~mZ CrƴC풋w]N bN|6^@ 佯V9b;F~>/d=\z>FFZ~x>}~hK kx{"OJs񸽯8=HT+ǥH3M; ~? Qz{E%zeǬmUy0ײλr䥦]&v^a5gt[k :FzLQH.)H<-Y/Ai^=[tjkٟ7ǬJ %iP &`;ZFئ k*,F^1J&2>aC }|i?Qg^ i1e3c%y+X1oa0cQ0I"\=,pmfUqpfȩ x5{qt [_ueaZDĉk5 c=""0s4fʉua{yw 0 R̝\6V;;PrUh?p}<G~Ͽ#pcČ5 O8n7VԢG(P)n6{n^kme4 K}$ S U#wbG(PRLm/=Cd{e8wY[>οUSyIcNs >Ny녞GmߥqT5ǭPҸ-F8s;„ZкLAm* }K)Y_C߬K]A=SPeW>(Xb{Jj>iB/t^)у^kBRZUzZzk}7LJMCI%jU]eHAP A2 žKv; gu=`O:n}CZ]ڋg8ߗ9 'S;*[a׾鿧gkcs ]]y@Jw/˲9stQv ]b9gY޽ epͣGc~tϾ-XΏw_/|_׽,7;l^1ĘRR מYrIJy06$x"|ZD/'sky=̭ZDPH)%rÅP $(ϛ 6eQuZE!P+cKɏ IDAT*\ґH> 6[goLJ'$JnN7-KҭǴZп׸fOi8v#Kje* k} e1LNVXpFƫ 4UfƒYQvFY@jØ4!b1z}ɬYn<" p<1kڸΝqmX#I~*1ʢ)эge[»Pc?7=&m։]'册6bnņWJWkǂvGb&|}=>~㿀o0~?˿+i/CV97>gl-fڌƹ\{Zъ;x9ӹxn-ѣܹmoijd|Ni[fy6 9+ӹ3fh9y55xpu QP@sfwP:w׹vo/>7 scv8#mmW 0n}lk8:QCUhP$/vZ?qGe[l眻9Eɸ6XܶlcF6GLaռcn*{ubDF$ 4FIyب˅&XEq!"&H\&:ɤZY\&c$`]z+,R8g٘~ QI 7rB'l2a9]]Ͽ'~+O|huYϐj7=pKE,'# )MKZ˄-,zOd4>#Ґ'HDVgp JWUW/w!Xi,v/hR;sI g'A G[{gh!UC#0%Tu1iY23jF)wBsk˨:}: }vg@d] !͒%fsrޢuk'Wo>{ܵu.8V7i絈+D)QӚ@nܡ~SF<i o0 o6GۍvϏ}US6)q{Jw=8hȪMρOk߾w.S:M Ϙ^+#EֶkIɹyn|Y {pk9 o?[kŶ3a',s~A%_UÀ]k fu~q#g#PJ{)a) 3Dh'>㺔4w$ %B[d,M ϔAi^eL(2v"R+p8^N.,sW) irXHsӔt ZVl6W1+Vd&8~v_WpڳXY뤸% AH)!Mm99p86=Zasŋ|?_kw;?_)s'ϰdJS?_ߺ.Ҙi-d %1 gcY'Bylݳ3_TV yP3SmuPc?9~7,4ڑKҫ~挘j\5Y?#uFM:0ṶJ>Ey"Ɗi<8Ͳ`ϴY9£B+[PpZ-F 5`RAM;RxCCUG7(D@=_jM6;Xkh 4^O HZ+9Ph.v03Lgs;lMHk_y@@j-)#Mk|0昚w^@C8kͬ 3YKs>F<.`c7aMXe8rJ7Ŋ+5fZ-% eA\k2M2Z9c2 Қ[d3fc׌>|x|7'"6jD3ZVP>v88gcuq 3or S+lN,-s)쭵8^ۭk$!ZwMc$fg[+ WLq[J[YZ#^}ULӄzKO}3O?4Oa8dy©,H|ļl=zi`8N &QΜq< 4Y9gdl ELNL>^o2[[?ă Bb6d8p* ;ZwIdFl\gvDﶎ_ ϲ)(,P%.bYEYD<#@DK1Ax!aRjUU}D%t+9ySH)l8ƤdpkHc6Дi"P(օz)GLd"(My Gk: cw/F$j (X\aS Gm.{֚H:Fׂ>Zi| >4-@Ƹځx 6е}ݴWBjFpSx>nUbῂ1X"¦)JaYf< M)e)fjhI֘%"UgywF5pՠ)4fwDN|$Iת&#D1J-B!!! &ޘ%;N[ ^,*sEpR@MC1:Ӓϓ~jܡ+Bezmk[(Lq5K&єƘ^<֛Y,F"./ $!$^yR+}R'I5˲83 I2WE3c(DˋnQ(`(2gDMb!Nk f.ȌmkXSpϔirzMȹS%OUil/&vo_?})@ Z*ln- >Ns9.ó36kNGl[l68^7[ܻ?gy)g{JyU8rY\^#]eBQL ZY8?ys=֤vRJ3OG~/|uxJךɺwE+V- DCCf(>"s 5X;a%$`aM]kO纞h>K>n^iފ^<-F7uS}9c&$BFX^(eм ?O6L T9^p^p<<ൖUhj ؼe)b" pFRJvsR#B)}򴎿8; T.0G9|΍0Zyt,USLn @v)0@p0X]\y 6zxpyD?]#.c͈;h ,lUhA @Q3=։jS7돼 T"u7`m)dhH$]5Dl+A&#_F=D5T!UҀ@}U"@A$(5 FMteT>9%}R\ IDAT,EɽH贈%h[N1jM[˜23kk__fZQvRbZ_#Iɮ$,6s `&[TZ sk}ndxLS-UE,\Oލ~p i a5@Nr CkO&@7F˿QhˤGbrx[3"B;w}ϿW//?1g.R؋{ xhZ62(ٳkb u=Ժlq&v޼MZ0ewVzhf P̓|iYDFTnrvgSĔd" xU6[Cn\hޢ$!٢k H4_`g|}/*f$]̏( k5Jp%Eid31[S؎6*N4%./h솆xunIL#7K@M; vG1t&Z30P%f rW9xoU\;NXn_[[ς o]Ӗ|u(: kXyIFRXYJg"g BE>/@)!1dP*,Ϗ=iguql,kqQBR5:aB 6"SJb`փSYt WmXj`ӲF5DKR Tͦ F9o\ed;- %}-5b8 ZJйv8&^HVC!RuZ5;uM@[~ӍP}e]7qAAԶ:cbAV q`f ,r{5eӌF F`[{'1C)(ĵ~U:L)K2+ $]S!Jޘ4Ќtۡ{\ 5X5@ͬf4EHcNw]?O?;)Wi 2U@k|5 P/ݪGÂf `Aԭhi/GIR@hoعb:(ӼQ׬[P\0Tr_BXjGv$GCRyixn1Sf6\N vyF鸮8lĮHoG`-'itKܻw]5mt9;a~ߍk{ۍ;y|šk}x_zH skbڠ<%Bf10(X?aZƨw0t@;Lgq}pnncՇ[\ HOE/>)%4(ϩ?9 1rDiLHUB$Ao4t)ZɺǪYp0Ω>E55,7 *E1AV"MrhwS y%# IJ5n DC5pYRgh(u%wf'rA>s_Dlp(.lE"@f)@Uy&pq+;дڰEMJU$qSbqEʔ٘攝L% %鏳*IH8a#c$.^gV2TInTo0uk pRNSFk涤J}/#hB34Ͳ3Z/8Hۻ"(j8Z86ot" &'QagV+sѓg |8p},v{.6ӄ^{ x_@//} oƽ{ 5LsV lOacmV1 v.HkeRF=NC_7{Yh #Hg)0{9J@v)ĝ 6{2o.`EmDo/eA~KN7_QM[xaD-!v3D[pus{QՄ\NdQ:q`hb /H@]+?4́m+ĈbvsG*[_GR+-G,\C5pQI쳸9ct$߻w׃U4ɉGVLZ3Q5X۸PD"jff66=i64V0j=LD@>9Xt`aejo#7'14(bK NO,+\1dF72#QZk}_QM[7͛Dz4B,ڣMk]4ScS5oY;!\ւE_O4 uP,Z`$^dEU}Br~ά(h11-se[LH$F+Ū摍)KH7׿LaB]$H{l)K`=Yct ij+MH(Ťd]n1|@):zϒ3aͼK^5,l Sj69x9)]`2?sϽ//77C? XyQHnri̛@sgDr- :e| VW4zǔ:Ppi]O$?m/ʳB#63cU pAg p bym5)⚥m>iCx~eo PB9Q0[\:NUff?F`zNb*HX"ƽ;x%7I\fFR-RU\earjDw#6c}]šjCTAgB4827A#iκfҹB c\^1wmy5q$"ec.:!Ktx)8K-G”U}i qDvZ$ֹK S=<3xhjjYϾR MD| LMtk)@!:J\GLt <o >  u=Þe!+0˗ZVz&);ű!m/yVHLȍUtJh9!ajYHB]׈rf7Y}O]fHjT[ n<'W]WqA5K-ȕq<=B*\ 0j*=ϳXJ dx K);4cZbKŬ5Gx]M~!I(d]2KYuW$Ԇ&AKh@olIF]/m)`csC`U"唐hZe`k*;9n%DM9eVȎY(Ly\T343a%8MǼ 9g :W- )''ٵTd u.^=+ eq0?X՘r3] *5#yCSe9TdY,h$En%Y$u 'ܶ6ӬA ֊졪Fj]eM]du 2i3gw$/{ KVt.J=R/ {*{"/y:YhB HZrP ,v**xy#2 ,,x?D)'9*K1祜ݵ0M3j;R㡦i2_E")En2$2v)'e,3Pt]jJ$?WH,wo]W 6-3" ar`r/ByZ#Z]TA.:'{Ziǐ=7'u=qȚD$ϊ %6cjXW`Uݘ-%r̍f.Gl15V01ON.SE6c8bc J3mqk9ɽw_ i3Qbu,Begx8TtEIls|N`maALl.zv&KuV} 5{'9(i-]gO]v+ydH5_iN a/&'Y;\Ԛ\ I䧠vR ^)R7"6غf$3\AiBRxBN 6*xLXbђ+@@ҬM`P e_s=I;0+! ,匤6,AY3Jc;}=nXofqil簂V&UD`Lų5&8"ѶF|8!n],-ŭR7kl{0xv Fx@R) o&+?өg:1&ꩍi&Yh/ cpcM~nR2,,nhgy>xğطOx්ӕ{ШЉnf!z MpPBYr-2O1$˶@4$YG5D")u< Vbnrg 3淶hDoٔm&yT |߳O;LTِ\Q-l~$"f\ P y^έ }՟gzFso`>#QH; P|^EBHk;UԸK#Ia6Tww1mj( 5M@5m5embYmXsu͋W`4NXJ )@X[lm,{iD%u@aX;kYN1{K@;sYDzЃQHg}YlBIoVo'{Sg҂h)BEE>)M3b Q֫dvDZҞ˽BMsPe,ʔ)'54n>r+Pt99  h=P5jHHξ*$WhPiqѵ ZkxKI]i-+Y,r 0bxV2FHmU&%s]f 5#B&%'WuGJ  4 QXZ{jws q* M;bA,K EaYLaE vgaUSJ.o[ف?)LH8iI%Fd7))YDDR*$3%#&P`9A#YԽ RZl6I$u,0Ghn?/eQ)1>*!J˲u<[JoZq<q<ӟ4r5# IDATnIdQJ'v(b{1#"ڃYVw= #*h#XE[U /!`eYDnZV{t= 8 UVWdtCwyxkGЎZoj|\YnZ4ՠqwSc$ \ÀQ'9>_?pDj%9ڳeː6*H}}՟: *hPɕA冖O1R6ִ3k;P.AC;VVS12+KgT_j8:? Fpo P JKMQش|' DX=*H@jʓE;ԛaM.dϽ{ZD" #Av sK/^ 1΅-n%kبd,KekXRc@}{\E̢y>?ٍ ؂RӒ%԰c=^A*5 d15*n{ޟf}Yv4)^jL?8,I͞fi 7.8F kJl=vK[VS9eˈPOek2l 6i[~tS>Qɱmn 1_Jcx$ij5r% ¯K;@Uĉ=6֦b?)z:g` bv)!4=6kPs>*,rBt콺qZ>Xt#!*RSO?Ν;xg,oać>!g>vVKATtYߥgU85qϚ +Zpx{bQ$(^} xWW_M;P­mr%"C&O\{.I;m`r1+j~pFk5H#qe"D#"7 ,ݥaq$Ӷ n`I !(? wܴ" ټzbPQIt`C7y=e{=&lpy../$r\i@WϾZ#.&Fc!~hۊ7klc]N<C9nFN1Ӗh)퇶 S̾boıbmUk:Uܴq+,"q>, }dʫb`&uR*uHڪ<)-lNXJ/`(%2=xְ,Q> nq炙ޒs'w֋g-4iD,\gY jfE Jǭq`4Qi] +[=R*R6 &7[{fM7+Gd /JM-@;M"E -fbNjmx<|>?YK_puu3O~i.EouQb%Qė&Dxg?g?kEJp>W aí\UGJB"ZMSB|Z,nx`<2.פ_έQ N^|,"C]_8C+DF2G ϝ)B~Be{ qCk#7\__JB_nkqG6o&LMvYgڄ$՝x&-*DS]?]]7Ǩaf̛yն]QZ7PCf *![B m_\+5SF n 1#A+Piu,$hq }@D5D-% x+WL4PK"pmIN\bS+ne A^C%a$ ) B`Y֕hś]e'0~ d*#|X`1%9kynH B J]gV9?hT5@q&in @64=h72ww$u%Z]ւ I8`I;/oUe2ȁ:0&q7@=spFPҭΧQ5;Q$SP{$̅XΐLt9Gޔ%Nnk47x葻 vÛo׿ ?xk8P#Da+4x$fv&jоFz )Iw7^}& |+>vYдӁ skfu%Jk.R$(!VYc"B+GmcB3Ҽ{śH;HHkct}j$,ݚP0)Z=L7nK (oNB/ "1"4E`a譭4tFLz1V5Z>kvq},%Y|5葈DP3 ^g42[>`7 *mv?xWƺ"Bì~bC 'R.dNÁGHT6 t+TN:AbWƹŚ F+] nO\StUZDXC}>5 Q&rZ*TnHk]AQ[g~?8]-@Q}+ 0]q4[5i}+/Yc ۮu'2Ǭk"'!J#r|ʉD K i? X s.]clFLȺ̅YGǽXFQxzc1B|uDbR&i{4%6I[Jrp]̊,m0FX [;Up%4jJ"^T\Рr?O <델?&bf LJ>fLq"y)? R*VCVy:Yla->׷bI )%G=;WZ%_ yW̞C&+-qKNȒz2Ψuj vef#CNZm8 ҳF?W+Wum`1NYTBи=m9@T~u*f+x5\Pi v۟VqYDer#{>Q|`,Gp+`-Ԏ9`_4 ֮eN~.pd{4 Zevx({qv]`rol4lg?XD+ 5em*: #"l&t Lcr}yp~F B|j[[sq=G+P?r\X hq`dLf}0n  ӰthH+lM=aF,tX; b "wcتk{%ft( VFt=U[`Uݥj`4zS")>ek- M!sn]o.3%u/#o!0!v׈AԱ5] >z0sm,J SB2_]#l3"#a X6}h^s˝0 y3@",lXR0Tc 4m.To?'ѮY\kQ>P]eA ZvR)-WMk$jј<N 5p@x e$SP\I?EC(Չ:ߞ+NkWjڨ+X5[cvraK:W^ ZCӵ'r2*1۹b.JDԗ,o%k scVo Jz\H\(X c}Mu~n1֪ϻmmn6 Ȳ3kHbmzݐhU1txd`VrZ$~ښ~@}.MjV34уB J2A2aƃs&O ꫯѣG`f+??TKR֧ jMfKѺEyqvS6 E4)p8 q;wPjƃr@k-[}߈_kP A~ݿR+:^udƾC Ds֕>Dꅱ,gp?Ĉ2֍_N) U(LHmc{ .\ QZ&˧VnG̗_{4AH8 40>qؐ)õeyFkp"{)σuSq=L7WW cUf"ZHn8fAVͺ5R 9M%t)EG*TC^4)#f,10e9:c.h-Zl%u)2#X$8C]KP;(U%pAfakYx<]Lf)~gIڢnIӔ٭7{H ,^l ݔQۂx87~ǜEfp+>k|/21M RԟKgJ.<\빑Ʀ:iUR -+}Ϸॻw\@4l`B:j`>Ie9hZ\JaQih\|j;SG$ˏmw[LVSt7.,,_Nvk ./a)dp8,<q7kc=\k!fDkap1MCu$vǬ];dDW3 P[7G`qUZ.yLi0d"1.Ab {7Rb=?8YVѲKK*ՖfV@4I+cZ5Cu7jTLɁ]t5y;ڜ؋ե>IZ(Q׺=M#ps&*̽$eqUiͲNHl `yy2kYR5ԂZ,=4l6Ɂ'.;-R ܂2Sșa AY&o5[a+jsL$ $M)|ïztB /B  fz޳̪}`XQG?#sZ+sa 4UHG팘E{Bc{6Dj,6PysBroNŠA $g6ً%JQ]d<Lt 0ݠГ캻Ө=o&aSXѴDVMI;X-*17>xO ̩ pGku1c쉌*x=1ܸ#n4CUx`[~XU5:VrlsDZ.^x~$5ʑv@cGKVhMzSX_J)H4̬fE W"o|_ 0)&_:qf*00%`}c稰ic}~+t5/"n{VWۛnSb$}κGh>a8#c,*vx垼ZPl:p"w$=m(} #jŐtG-= *x_ ~8 t&c xiaqҕ=쉗'"p{_Y 8&E7]ǘ^y7ߛ9iL{ ⮪ּ~N+4n`4 *;}4} FkBTJb #1A?Jkb$uLߗ"ՂeYmV9x6F%<9sGdQuvj ݲ>9=A'n.u$ٚ(hI  ht鉋hXzU[\'}OZJ|jTU-r',yGmH^kTl!ZTyP'S=y#i?@h|̭̖/͍ 9B;~Д F 084yGn mŜ{Odz"#:9̞f\ߝ`ߏr֟ft2}βytπX3zدlJ)8c ~Pg>kPhgcmo֊uC~!{nwOcI+VYAj K~cQI.|֠N q{ֲ\ѴO?şy _P@,;{McF>6FcA xs<^IoiD",n=ISfAk-|&#HV&HL*nԂX>;T2~aǷHOCж Vazk(AҠ7':'*- D)EqY(ꚏ7O*k#E..b$N<Дzp2|M=EfGcQst/c:+Fxr IDAT-sgaB&1V$^_4-uX!\hM7mlX}>VeI2d (1|?h@x&{ ti3$#a%H.bFK˲ \v1TvjtXq}1|b3*f Ѿ׫wv{7Z`~KGkNVt1pLf 1*2%5 F &\ ˜e 6K T=W>=Λ֯;PrvGuPkfQ:XL}AF1_fj- }.rFRrec:yCc99[{3a2`#?wƆ0Tvp5Dbc#W-i$5ZdMyBF"$1aKax/,-`uփD蠑`{49:~oR L"o}w.q({}A|;#G*8/^ָٱ=pjb?*tvVzw skȉǜb0Xte!u\msX}*6r!$=&oG12m~lIػG|5;ZsdwO:mϺEPV=uv&_LO۠w?-٣ΏH~eoiJތ$˝uv}R'w\Wǁӎ@7"q[=,XJAFpfFh|˴b!154hjW{ۜ/fy/Okד YUM@}o9 { w@k{},eu1g e~v\Vc@^{I CID[ȝ,ժ%À9(8}Qϸ:Ek0)mnizU8PjDz`cC՚9۶Yrj8 G=Ӷe,˲X_ǁ>V<>>zxwOؤ/KBdP(*)'̬+LD5|Pl}讥:ǡ_ʊy xO{nv`@5η:uMC|B=nb Aȹ恐@qt+v> ڙi@{YqH\-Q>5-v OJ~ PUrj.= `ZUr[Ѥ˄$zxޤļ3*ی xP v(<m9%To)A!d﯐\uao1= &JT!F \| 8(߰,ҟ="%qKY۶c۟lATX[`3a36.yA*A>>m=q8WX7h{g??<<낒/^W?b ?TI4{cTfc~q(bIRHe]P/^@׌oWI]I sJYn6ɌZ2':=~GPoZ!Xʯo${/5niUhQ^vpS$n}z80A|^cav{ovūQ6$YBZm1?f8: U_g= QY nM"Pfo$2D~[*r+::'\qTA9k ίc͂@ ѰHQy0<+{ZfrpnZ{&͎aKWG䍠PÐn9%I*~ .c ݆u4=]О3] TVh_gL`KPa3Jܒu ћ +%fwg " 99E$1.ғP.lvv?BI֘K]% S)XNDT(@n@R##*%4R9ֵac){nϟXBrԨ{]-\@.Hl>HD V| R>%U<јc,4{h45e ҆SF* x{Mlݪպ3kQ MAJ 1Іn/&b)1N#hʀ٩W!ÓN]؏9q_a@l,K=$2veԚ&ww&ve5{T5dpGTT1I@v=ׅu]M+4%qugn>c: `Ófokr"p@J-XF+xv?*V0}A^ziq1 *!z2z -@m; xݯ`6٠w=Z+6,i$Or7,eNYHV4 q*'̎5 \͙o` R.4}LШvpoz\%R.q VK^wdz~A`8ԬmlF z ve-+*$3~4n MvDkot̺vY-4QnJna~KMBV9%!^HW<{x  U՚$OwϬ0HZAQ,X;ЎXΕڬs.©z`]$,H$_NVof[l'=Ȅ}qhA86I /e.6fAK]؊3_ bmG$IhL_Ō{D֧^eT0Z|<Ϸ,7T\V^[ƢLɺ^UYh@҇ G4+9(O [ר)dI_ɉd,)[IU7Xv˺X2ڑ:NrWea"z̛VWāR)(0l  >*vOtvݧ9aT9gb3IƆ].y.7-LrH?S$ 2%R1h38sF tH#QaNfN,K\pPE$VT!hsvu$eјݻi8r*$k؏艹<V!d5ٴ“:!NA T2Qrdl\  w$<\(&O"NaS p61>56= iHǎopJ õq ۾ƗuNL8tQwV$׆zXPײ@;s8#.%憶{!%#xS|;4 @%IŜ3Y){C'9BꆒK439#dK1VH􏮨 Vd?ɣ8k~slÏ74,,B!ZcWy,>iD~FE5F%l m@s ^ׅ֚;orx3|(+҃{߯G"QS~7qo+sr JP?6FcLǒӿQƆheƝ@D lxĆm(`] kݱ"-dtJ&Dکo~Y\R2!+XE9ǣ°uZ焜TS*&,&̄!LheN?E>}ƾ;l!1I,E >Sr)vͮ5j 0gB#h?A'j,Gǎ}GP k5z" PNwD(\b0ɛJl֜?H^4!['Fܟtp͝!C(o}0X>8,1.wghxR37-帛<:y"n  e)լ\fzWq:J3yK=1Oux9Tnz˥3̈́ݢ1HjT-qW{ g{PKTł=_?s8^ q]U{̳$M;rnvf -"Jqjb{3U%w\h:x !>z"g [3Mb%ț sCfD :tZkgA j;f <[ De5-K~Cw⣏>}6.3.c=c1@8X8a"bvK`)lF[O]`ϴ_?fԨ257q%Y8J!e+`!9HiZD5k~Rjhf¬.*#Nn"\kMd%~Vz\]+v`ғUJa"oSG L ^Cf)sXN?h({A ZdM5Gx)gVѓ#ވn|ak< 5f2- b7SwXßIWKpE# H!u1QPsg1''N͉X?ӢWZS15Rc`>%S"c}N;>#F u?%s>kDFA2AfJX Uu:&p`6`l2j4糾Io])Srԧ*iRx}Y0-#H"YCx@UVLGnހ =+vdۏ+)FuL>m, 9svY$;&y0ޡk}-QE<.sP⺣ I[" N  |ί|oYtM1%I{ 6 \EL4$ $u;(X 4QYuAjmމ޻k jfy;]1VҒШesCHgU%bzT$U.QQN^vXjk|Hd87aDn- ɟ8>fh[|~H8k8 ~0kR Hy06z=1=-k$f`؏`!i"~޾roC?NFqLܩ]Bɽa[qLK ꃣ޸\.8ܙ&4F39 z6w$Y+q r@P+-JTs5VpZS=:NTb۹}\stCfQ!5ϐyզy 1mc'"h "S tp:|FuJ1TQգqt !DʀeUr@mt=#2~nsczFo]J)O20D7~oִ18"V{p˲\F6CRJ;JOOi&4O5TT] ZŲ! 8ͦYWRN 퍀-0D-xNI,`l!ە'J~]uHF HHӺ\H5:*R,ʦSkKvTrk7>=xܥyX`V'h.Ruɺ1¢hb^Ot5nAԳ bڎMA.$@x ") &*bUV+֑KX 0ݷ3p(71ڰk56 ƚŪ7GK)tQ& J{"nz"!@0 qbqfE&M \Vra >kynU $#StlHP_a)kPmU W憫&*XH AzoXKHrfDݯ<,9DDpV q2NE dsְ+jkh*ZB6P;\m;r)轢7ZCzC>VZVݭ5GXH0Gl+L|ȉ.I NsD)7lUDR\pZŘ*)^e\e8v zdPPL>t&Sg:~S+Z+.;KS5uD^k3 0uիWqO. r |xɋ k}d>Ɂi ]ѓ!@# Eh"}A.H˂O[WtlW83|]z֎ @ _DGYl+hn(e=i)1x]"__kK>:(Wu%,l|?c) َ(#}G7Nwy~jS,J3uyq!"XD$4af{{kt$B_}my57`9\32Q2x-N%Dv98@atBݫmjAՎ,ŎBJXLh~:6uKN Z!SR9%/V}lԡJFv.Ƀ)8l QݻBsQBve\CڮD25.y@.Ąr)өF"]ISs",-&d'X{(rYBAp.%ѐBĩ)}ywusf0wЀ#ccL&}zY1+n]r 7eŶmLR$jڦ Zc4>jU |5&|/uaWk8WukHr48El?s gm`s =JL!j0|\}FXRK% Ϟ=O^m `6;!y"lhki$PsAqi= +f|kA/5%lD 4-nTOXN%hr=s$W)C)p:m4I +|/_#r[DB2w_h)ACc_;)zN.brKnt*4AMH–(\pJ.d=!7X~1ϭ$!>)=_pz+nSj"`1Ff_^z.1ˑYޖ=GD&!I' 19L] 缐+ʄ y.]Db$_ޏ!1%}@[l4^D |y%Ibh?nԙȼ&JUJAZАMVCԭ Лb,8Zn6ztjyGWT{oJ D{W`B%gSySR tR9СHRh~nEۣv;8?Z*_R/zlqו;eh{dH>slBXsa遘 ҂ёDu ,8f؃ E+g&'N &az!p-.ĄžcQڱ=nșBhUO0 @@YR۶!]q2h]яv֘$lF=\xi6ʛ¾V4hI0AƧA zl4D̄Y L=eY 7eDHN6n5Vζ@J9bn\)_}HGHڜij #qBTK_Ƥ &d $ղ,ve)k'|s h> ;:[s:)+z[+C=\jHnCОWr[ۄ5g f,yMV,f$ +NS?7UE6 +=SA8ځ9< p`,~ln֐qʡD\2M7'"yes}I[Ã9ډ@^VU 1((~,Έr9%࢓KPg-,JbBewh8-y՞$CED X,hD)ڑ* bgS{SNIGՄk'j-![Pu  U/V)%$(M0iYHMZJh=`9%N* Xn@nV5ca$rkibmy944L%}CuYq݌3/fθCl-MǤ[娬@r=ϫC- xv}}J:w77+ yܬۈe=QeB!2VŵA0*%gO[ =)訞rA?>\p ~XFlJT君ڼxFӒl7wIG2=%qн@ rO8pm ]\?E^HbEΌeY²ogǁ;{DuYɗ 8n7Ku?멡*9l64 zDUbþVr/wJ>. UR3ObZvxC䁗u>,\ -R8ŃK i{NA9Բ3r6*_ÓC-`S.CT⺽'+8]"NRz3v!XGxb6Y^6<èo)…’KF1LYP&GΒ ccu-XT80wN.UYF K9'd㪻dYhЕ(AXa Z^$q.#hϹ%Ս7lnHG;ñsIئzkT3:)"2^XJ6VywHGUDbUVD0o8N\cY=A@#iau *OU&VݚxIl)@ۮV!n 9حZDd[{yj8޷Vv^|u`E* :dU=Gw[eY5<14$ 7mSi_"Ls6:ל Z'ڪQ:r9%4xn}M& P ϕ6KX-Ve!œ&?2wjBX֫JJimš=Ka IQRʲwXEi80Ma=ŔdcQ3zdgpvZ- q2Y5ClX{zuXӗwww(N[8Em ]RqѶmgۆz}GG+ev,woي EQ=0);I;<*\Rpw8$GTT2۶ 76vϐ.oA'JRfoe<\AQPe; U+"+jnah7}II&m WEFͺSuc@̟s^z.9N׸yr]r^9 U#~ٵ:OE{R^Z=VHuDƬCsZ Ls2 :byw͉pI\@>tpZsdo7WGڼ.@kϣ,='{-FDP[ƈ-h}($Hef$3&)Iqb''׊R(B*g ;]Ԋh;R΍ BvT+ xjo*WJJQ"c"(S]\?減  $ JZX;daN:Ea^<3|^Ks9ysq{y >m?NPUU1ɕvAY.버\Y!Pӽs!\$39rw*PZH"۱(|YI*8+mѻ]T+eCinʪ8vmm&N)aI~NC2ڸuO UQvm/˂!w6Zƻ7,7cߙ4zGY/%%s3"R IPL]ic[yJS\#~ֆ|+7w}ؤgN\erô o?O~{&!\WhaLΙը|WYy3ybd1n`Q2i{\ZÚê9g;߲:btdlTAF׶(*xԱ5wV:][y~G3)PZA~VĆg*wjޣQ2,vsN1 \)[ eRAݏpN"w -I)PkVwx;٢ajqX~ q8`1Q2s[30 #Vl{dRۣ#I>@&D} 1 tIJZQs $"ض=ݚ;A=:^>3sXEuogl Z7cGB뱈^ N}o=*K Dr8ƲpOɏ{)R2c- `|]X ǐ=зW]֏mbfo__pߪ[țD9 OH^Eu~@=I W{m*gDrsɐ/ {}Y ι=Oi8/;~B뇨I >]klW|IӽR0usebAwXa'u͎d.ֻ";k>g&%pQ{{.ޡ+*V)f,攠 O@eZ[tEbN/$t "+\JNc" Ԓp%M84R(s[A;߂=JhK6թ?JFՁPPX >@2w ӻV7qkXvrn??~ϟ?NS)jykϟ ^x}QJwmis IDATV1U`(]H$/geiv'K& ;Y:YڼaA8mW{Ϊ_a,%4!hPvҒ``%[~2p5zW1g05Te㻁R$3'u c3#B Cl/!^2T+Ttj:Q_|i'M9OΔt-HqZ7O .v?ZKcOg"*V%̃ϯY*D16q݈cj_%Qq|dgkZ0(|&^j0:v\ZusVFK}C^$ݱkmxOOO_ Dpݟ {i duE`/[x ̀A$̨'9.kW-Q)"fU"u(T.Yv08: 177&$_ KDהL m\N9U:n*jddo?d䆞LY- ZL2ޝ'^qP_( 6DAwՐ91wo˔K4 d9"nwFګnUQ`T6N|Z󛃖rDUO<<)r#$?|SF4,$I] ޺mZ:{$Q*GYD_$m6*T4z]! WVᓏ_[6Ͼ7/sBqK|oLcvދyG'."2pJF ⽚AFN9vj犹yp9Nyy3{+!é9X G5-Fƒ678DmYPF}<Ü*kUKhjkI`I,H9l[VjX;lKh.(jc]׆*\.w>ZBnwV` nP a{0@'[5̟ec#PV[/somFzeY۩ i>@1shqPNʠS;-nW^}9]Jںhu-v4eT1&Brè֛5a_B5*+ {ߕu]q}+esޘ=7:'uUMQy~?" R.M5'];\B?6lkn͠'Z&mY2o)su$FK&RgU Ik_~z k44DB\65|G 8vE"2goHB6x U '\Q($`g a)@\98Yr{ @cz`pRxyT`; ԬC gϏnb㛌#zdt!=˅5EQnA#~w}cqb*pY|lA#@:-Ѝ迣E"ҙ\퀋 ؚF{DᨍuIxR[а,LxUOθc(-fƺ"FU4(7& >NJO=6xM|!Zh4+Zk֘< 4o Duo<3ݗ/?÷m|;7%Ɇ=;c'iZߛcx|"0MX{<ȰglIL :H(h`V^e=lkR < DdwT>RfjaoglEK<<+I$.ؼX9P_A缟`:0V$xا~8kB21UXG*{>ߋ .~\da?>ILM7ӋyQwu˗/e:0@ش=)3hB6i#6H&-e OaSJG1AYP ˗~g33o6ѩNxpcL+{ұq^kFyq@ =sPdhl/˂{'YGn52&5jFr¹װ=Q,QֺwiՒm\]ݺbFn2T3x} =U}C"=fΚFM 1) ?7v#eM]N焱@P#F\^8?ϛ?,!# {.D~ Cpmrr 9mqϾ+|xvϞzj4Ss+͋l[B;vqXU 'H LkmX Rѩu7.=*y l$]9y=I# Sل{ $D&=VF[e4's 5!wʉe]-{A+u bX{f\2hl̀Ns>*mns#4dYc5 Ml`a9q߳U$ɬ}\ , ٬cpgPT/)hsmY]蟯<g-ƒ̪t N:"gI=ĹXeWVęy `sۮ'0c`=F=T5\u*d^۬J{:3mwTV+,H e IFc#Ľ߯m[Rs>G߆ ymy!~0?ˑ8Q$Kl+6iIbd'&ȏ$J}9ZsQyjԜksЧҾךk1ǨQ_W_zSڿ=_w U-+L2ŝ NC[ZdjsrҶBN#x'/tבP5udh~֖/LGr7GrGjS#>r)3DXeCA|O44@ȞeB6g=4YJUq)KAG+Swvb91M9` #+K 1"Q'A ؐl}F`y_[v?}s~ x Ò(QKv@/G>u@0 sl&\Y4oReX غ6ӝs# պ[TE`Vkqi$ބϫz7J-#El}p7P|9'OpD203l> 5}wwz .~],w:iP䊊vi+1hh>+ ԑȆ%cIsX-Y7vf RuJ`5fi[׀Ǐ[s$6]re ԷT'TVG2k`4qҐڒΏ,H끻bYLFIXfjb]GefQ]5b뒾fbӠ3ס~P60{j?vog"~.qTorñdž{7T#w8a 6Tj d~ lh' tHHV GW^?=nnL2wՎ޹}`]-seR{ {βr-)I?<"0׊^Qv`=&R=~'@& 0…t]a@= 9vp㚙f?UՕZYAIAW̞ FcWg8կ=G"ta7|Gj=D=xW*Sf{U-+V v3EI5MX\5o fQvX+S*^==⽏zs-yZͲvt6R\I@µT-{URcYjMaS y r >y#:ZRP\zFud9)Wq91E,FCi$ZMJ5"vQ"Ŝ3~p2TSxFI ݳ3{UݧuuRM8o2h@Sz4Ut6E>(-f{ůOs0ݵCY빖)g{'rVd?/^6| _D??}c8==PCzfK#wuWW2)Hİ,`c- ٽ8>q-xZ+VUL)=`mXsGW)rY{fʉXr9޻˒"= @2?"#1lۨv:Y-{քqY=P7F"ǪԾH^xɞRAGb2u^Dވɲ,P"S{ 1/ ]潜2x>/aJePV[!\]yRkor5KzQ!łbYθ#^z0N3q.rp'c/F*n.A{팤i17acp[Nb gTώLl xf{@:,ЦbZ1IE C\ ]ըZ̜6Ƕa'Y7t|sH*Ĺ@]E|<[L&[3u:q`rgD{ G8iTXiǐ͋jJl p]q TJ) ?gßٿ9eHgf[n<DHu`]??ozCQ m]OM`novY-qРӧbf%etv'DޗR4[tYlt;e"t>[6ushZ֝,RO%蹃m NS̳(s'wPYyCNϬFM\=L\q]n׏4/(%GPkYhV6777SƂ.+j zi9u:-`x@kB,ޜT3M8Y)t K@'M ᳜)SKA=d[Lmq6 ;j>m~nx~,, nn@CՃ2R .=, fJ՝]݁ޣ'͵'_0vqbvFS/npFy(([8)W ;|1`P5${LDlQ.b ;oi 3Jx` s4&@4w R@zӌnBvuEuI6Nl (yy(vds!^qɎh%s{_/LJ 4cvFc16^糋pXospsq¨*d.j B:jMRm.h@(UG֦-zAFFLpSgzuT\j4ҮٻDbEEݙь"īm!CSrJ5$=.ALՅ17+AvftaíFugGۚ *B=QP{YYx;M9_${0r({ ׀f{wD+F 09޳͌ U'S=՚݆7ɩ.ys`uuhcIE"G:rqYZ3_J,\YF5l %L&v "]RPd^~fQ(,Gp2wTzЉ>?۱wbM8bރ ^jNcJ: FJפ(l `F{5htCW?ϡ $YMH<D[dhò8Ȩd&˯שXfvxָ5+w+8'@)9zM7e*d4Q0h5yoO0% rwlL{DdjlcL{>I?.5ӵ9# 62hٿ'p.3!{ּvsɈ}Q?9|3? "^emdtrvۨb@jF0lZ:#cپ!k`b!uxd]3 /eL*6o]qjKTWE:bYƘ@Y =Qqꈼf0gʺG>.yOx(z[}zyZƗ]kj)8cZٗ"m7Xbsbu\5Jufnm5ZG (C s`z16cn+H !~zzrzPdRRLl)9XkrNJZ982(])%uvº}ܾZ zօT( V%9es)w?_!͈j}'wUf2v\ ^kHXx*Ճ9Ei7ȊmD/2]5H;.$9A8rAa򙧷wΛE7{ e Ӈb!7R}xs H=Zl?Y!^bInEsB[ "|rjOBc7]lG'{YW:L-s>ґQs4(2ãxjgdRѕP15A9T|.ٙϿc u5VeA7YkjZ{>s`[ ooMOEeC5Ǭ6j.t;S<9pscY{<==aG0wf,K+\[|%>8,i~-$Ec=^h'h22Ђx{@E[m!S;vP hF_ `d;R⵵v97аD =Zz9Ǜ"?] Jr4sfѺ)l< 븖ߗH9Stxް~~RF$GXD$p_:ge6:^%9,#Rw&[NJhAL5{eႩv# $ Λ&y Ձ 'u_?@%[ZX<X  R ֟t$d毢Vۨ/"*@[a`dNB?|29zs&F:(Fn¢WQ•hPHmPRР&^,F9%j8F8JZ_ g=~EțtpߛA t\"{@XW~m`>{s@dO˺Fj×Om ߏ,auAv٦k7Uivt e{H@k@cD@F&@@ 'D$Fjil ,(!w:jѵ}6ӆp[-JC9|`"諫uyPdG=к.8O㞼N4=[=)\G #*OZ&j z4Oh)Wiqn- r3h[1Ox9ˬ9aPF9qԭ͇J$0Zoڊlc8{ײ\O.c׵Yjem>SbN&dϼN\Uq{{Rӳm)K4cۺiY ڟJw6no/1-m'}}%0{:3kK_e %4ɇxНemeV?QR|oT#7N tюѺ6jȯ-/N,XH=wWp<@0U-#uuA4Ukhp yIf{jU* Nd#6Av1D ){ |-qU|q0T"iw btF2"(Tu~9l, :ݡt1^]: 6%?-eD~W}-RYWwM~Z3PIHY:E.f{ȟ"6n=;JrwNh#+*jXّ9(9!3Hxx, ;gF@5@um" tiZf]#_Oӄ_/ď GQ`fkNƔiZk];k 8#<)Ai#I*.߁A|: H}5p<]=BnR@{%,+Xt)&oZ힪ˇznjVDT`V(2ܦc8̲9hZ694Twt/BRxS|񈼃_xj0,+}^JڸVuss~I)|S NQ8o#Khױerffutl 4p8BUG'<<>wnQ'bU2Y2mښ 1k2 kz?Qӛ_1}vL*-^Y+(YR{I3uW)k!"U=:hbh oDr$VKMDr IO zi*8:z/в@j`|^y[*|% s"eؼ}Z#B9S%BQpiCG4Y@t~,~n܅_P`\Ȯ_/ifn^)@l0b7VV<2A 6zew-1Z+O6󊠑 nރ! ]Pgo22x2@ɀZ^X2#fҞsn J#_KNn;h>"a@8:nPS?EU5q/DH_*/Gg yGLdYL"Dkِ^Bevk'#lA;k/dU ܍R'_ ; `-s'eǜԓ}PY@˖g:i<4M87x5 ,S:}=׾sxC?Nr 3z_qXk0:yA=$yv>l8_mg7̙ g;z1 yT::ϱU" @)}P'A*|aҳ`sC`$;wؗ(i,Y6X (nT;FJ!ȯ#(IM48p+[^p۞+V.QZWR F(Y {\ٹF24Fd&;(赍ьg%=wѹ?U}eY]D lt/`]Ox^_E$+98aMDeiЉ9@PH4ݺouZ7:Q+! z(qˆ|mS}+P#KRdWD^cF!ó6?(th\ك} _w?SZq,Nhݨځy:`;Y;&ҨFo(]yA%>5:3[oZەil=ak/0h>WK=zNL,3kȘ]P2ʨ8 A=X,|߳@oBy?erڝe=D|,9Ԕ=0f&X P\\ﺮ8ϸ9MD-p(SmE a7mMfM'.d'd:9,62ldlr ͥf]Ǥ0k/!f 1Ip٪u *H3\E: "ԑy-椣H|wr& _gz12' `(/("h@{`@F6{ﻬ9\DQG^;!F@:Zμh8YF;[\vחǽ W!R-,ŸԌBzѺquUr#.8׈I|X<ن3(ycUKTOysC[#A!6>e\XG[hj|ދ˪>.& U,5]_vZoBE526m].楴n`cqN6X_dBJ>C>>kAe g /\WK~읛k@>p>ȵHΈwgo_^ٵ- #czu;nNL]5 u6#JqTk} [ ][֦ݻu1]LRm5GLZѐmsV㱶2elk} z(%r>u3EKCʺi21`)TE]h)ُf " 4N:oK7"yYA{Pu>"M@R&p7)kNM9fzz)d :ev3a污L w\77+{~sjRC);aFR3F%2"-ߏ se(D9'9k=>^*({,z\#`#|;*X!ı1~4˫G|:CUZ,Ybzzhsѩ 쎁 {<`q5+PcDSl`m+E#HYLE #KhՍ$E|sX"2mj5rnd=x]Vs#;_sV\gEeH^WN{g'> yc97m$w> 1G!f]N5R fhHϽY-C5TTȏ&vv}SYQ41 ?Oe(b͈GY9O\π9wv bZH[aZoKjqIp#lݥLba / (2d`)81d6@|-Ekma9 "6. ڭ 1F 9"{KgѪq_XmGaTň9Am||2Li4խ\]O ݓ0atoΑ @zd)C E:A!FG9po@s}5r-#B[x"Ks<) a57F|S*;h:*癦{ $ˣSpќ 1 rn >/})[%Z.MG+gpio{'>~CoNCRoAQ#eŚ`8 zUڱ-{;N$|g45 v@4:9)1R>\H 'k`D#_LF6.M2oջϯm*ْ;?k&?W75W6g(&YO\!nJ5do[UD'|iYHS(qT4+7>Q[T"` gFa`;͝ QʤbF&w Zk}S# %{Q$ is{ IDATHgZD`t:EŤC ~cs H_g\{r |a3(k tnm_s? A|!/ď7ooJ 0 |♢P+oj T0"ݤ鈍1f-(ӹ1-M;DGAZR˂umlE2=`Aź,.o;e)6Q(vF Bs_mAƭ $}`B?Ъ=H(!8OPm|2JjʽsH'ByΛٸmD4E['~v2י{@ )|Oj a Ÿ, ooWr0g8XKcq{\ER]E Qֶu(ouQGev@uoz>TXD$W=29߁FUxq_xIxսmvM֋RYاQM0yFBX|z:ֲݔEK0?7M &LlbDyht/2>lõ@{: tڀՅUA" @R&y,6>hf!{Q@>?YO fhjW!kd4~V 9gMgEmOFcG.:>:HQu{t)O6Gց*K&NDEtc)i\*>#VD~`P=/nU^ ZGw*m sWBw\e6DIMسxTɇz[s%^9mTuSy›8q$ӈ*HG ,>mV[V@I$l,q 4 &͓57rM9iicQ_cadLj$MA r#yZKv xĒTPb5zI8UZ9HlߐmE/~.9RpT]=7qێaqIRJ`)Gp.,RJtAGKMZ, [G UFTJGh` PPK&a1f0\%7\lQkNɋNe= պXUGS03;Y}u! 8I7b9ƈ2K?7ւ_~K;>Ð  dXmھ.d _>cm5@r.B sE<{O㿹yf=Gޑm%[>ҎkꒊbH1'/06("f}]!GH1J(ta *2+ɷȂ$X]բsEA_'H9H.`-s1a B"iP/n9&uh˔3jNt&ܦ ! s `Kp╆o=O)ިQ:Jb}[gט-}]<>>jnoo)ƞte)__>ZAeqb4氭:M8X<7M ΧPN<]J ty0·i5]H)[i $2PH޼zdj4s%YU(367t1 rnFxCv7m4,s,+1!t a2xXLKd_Q!\֟8Bn+PfXz4q.&5zIP0 <'/.u86N('2>9-,N ">q&r[!oni -u}kT(Fd8/A#׹qI! m|2J3cDy̢C:ќ"ygl#L+H R\Nwg!p ÉszGEgT64aIADp<0% ɝFYi/Yl@Mo k(:(K=vK/eetԝ0YUol~Mfy](ə==CrQz~M)k XgW@?5 0?ZyEWʘ u$O -bzNSF-}ug|w rPE m$^!"d#!% *aXO?TG;!MTzX=l!3M5%YmM1MFþsw50ZR0j $ y4]Xk+67yz-hRƽ!0nhj]%˺b>,CR$ؼv>лEF zoxxxefRd=ں`]8ξ>ooo{ӄ=넇'ri:|\fs PxRs)1 onPD0S.i9c im Z`u1Ul2-t=}Cll!,)r* %Rgob(q(#Jco| ։q΂ѕ:t8ӶPuf:kt$O6(P] jb: q??7ˆ<.#mC,]ČFޱ7/EWɈPor{jobJwg+3Buaq;ϧ TkJEEw%R=2u֭Vd|w92;ن;M/ 5- F(-1^&DVx!lӪ@_s ;o2"Q%0oqܰ We;{gAtp)AAB ̂dj5ekD2?ک}Fӛǵq̙5\/D՟u:d{Ũ#|oT(+ L66etڣ!܃4F?! 6lۍ Pnmר!bF.;M7Ƨ z^;T찍EKP|cCځy6*@Qt[uػ\|mFsjV/wRlMͨ-Vv`Zl4^bn4H ExSN |"؉x&Hd*E=@(UO8sZ@JPZϖ!k̉}bdӚ pM1{pi>8)Ր׉j.h}~l,}k{Z@ 0c͉"'/6jbfe3#E~e%wųpBF$N%)`)6ƠLxTn9e'_ol޹ xЙZ,E _$ y|%;9{g>klH829@2T>wײ"տƟ|dƤz?V{jbЁν9E !VX PSGUCfx!%7찎Nt X:GJ4 0lS*zJe7HFHy~??xud:gA#nooq{{:™S2dDِk 2Շpne :r \s3(k~oG]9r kS5oo۾~ Λ{bT s8O)2JdSX{Eń*hmz=_/DJTGeG!n;{dp8|9ٰWQ:z[Q]iYIk)#8()Ιɝ^{{eT>wf>VwbJbY&v{@g%i\x :"d"ϛ9齤e)qYD}kx8, V,˰9OO']О!;5~8q:q>Go .5{פXOm ^߶H0}eLi7vvԊm4B'߳,B8j?!nMj Nl!meJ:޾~~'@B:Lж@Wʽs7; +jF }HAcCwRmZH$wdhliz1-:,#rxٸkQ4snzmc#E?F6=a16ev[Fes Hv=r}D{w>JGx8qPKqPG/G!47:"%"~•]l*]>$D?"`7oy3;6""6 Tc2e 0(!ڔEmiKGH5!yz*9-XU=%0 8Ϳ>g7:ϟ(Oӄ!+G!׀Ⱦy!XSԯeC^Bs~ٯknCg+;^ӱz0ym|'>?z #PPoUKeLNtk =N94̙05o 0JU tBJE.BavK:R &-V ژ3#ח?i֭g`6aР I)zɄΞq"e] mpnȇ>֑e 0^c15}$>Įfid7A/)^]'LղAՁCP|>[35&CnrZQlD-}LUK" XF4#1]&Uø29@HJi`@drſC)h<2w8O~nNߺZ@~289z`d@0 w:y6cV~%$is9S4><>'|~oQ'܁E#&E1N!6OaMzz6#=EL{{t@^meQ;THLfS ;]tۼ, ADKULU?3wTT1^ |NG.dU ӹΑu 5a#(9O^vڻd%N@Bk>R& rww;ކ$(7Nj,5e _׸p@Y5u` @kNG8C2=0cq_==boW'0Cu-νkSkMuŋ-OO ǃ}.Yvy_'Q˘0>{*6m`'ϼëGԹȊ2EvCjrUJX5%оe; z1Ȳ!Jd㐵eU$i0f+VO"yЙ"o? /B2Q،Hg"݁rBr6$(Dró`"{)Yd~H~-ۿ= y.3׎ _[i4dV@PL /.^R *iĨt#R P0E0DZ)9kz-wTGNah&&8cv;*/l=ud LӼQh UW%sXtz22* IDATbe&-2+@ũa])WwT$z#0`ڛjut;Z%Z,0ժAf8/ J[co;O$(7+ŀЈ}ߚx>.eh!b| &xP#@H8̳e%^[` y{j&!evDRue `AC%>&V1*7gؼ+}fLt!lD)c/e9z |qDp^a#I;iwFO Q\-e8x6qf)m&ٟڌCπEaHd3h63F uH%K/tڊ#G6zE~x.@-ͳs ө3!OOOx^|:^/du dz3K6ُ=Kֈ>q \q{_W|SiU^vU`yۈm@t:Ǽl6zcsT^efkNr0[tYSaP72 ]Tn/P"nH9sH9Va6v{ּL0fۺ*Xi2׺0\ $8S 3adq Tѳ̆F@Jsbf(5#'TF.789HKD! `j04cYim4ʍǶtlXղN>|`[d8 HZ>| oz2(RtT(2bKs|rcz Jqn,y7{!i^]@o1(1@ĉ!H$Y"1ŀd1"-+E֚ƥF>$!֚sjk\q _;0V`I~yӡT<3hV.oa0O0 OH3ܱzImbD04ayBn'!;lRl'˗"fSg͖zjX<P7%k37QdIpˊ44Sz龎Y&j9qBБ81FkL4cZ(0nm!o=`@Qy킫4 1h<3hg /\v7&$47#ihZM\iǛ{NӄznN zf@ 6q?(E0hr_icd` rRVXgMQ`{3E+,"¶nS:`Y{2b{?U}ſZgÄ"sB}^~ׯ_OOOu u X62#s3r0ҧϸ@HT" +gG=6iKI{64ט',^RڸɬԥK@ugC f+ $(VI4QUcebq4rXD ŔrA><- vBҠ*V\VJ^ Ց nzAvM9gdGrũͧ sszJpJ%DuHH[@P<6L);%=J֯uJg֊eT {9M99C_$ܱ{H̷m|SJx%OO Rw<ݶĐ"|)W^bOOOzi;0[kE%#Xynq"=x+rG񴢲ӔzqYyθ?Oň(nOV;IQ-F,!(IaC&]ҥVGurkr7g XO~-,YƩ@@!ͮ@HC.$fMiP] ˴= I8gjZ&Gjh&ј ˘[I(8g12NO(H95 rNu5> PMprKhko]Տx}"aɓ'M}ӖYL6!~lZكpED@V\*tkHY{IW-S%(H%dFF[@d~"pN#vHgve?'][FZ fݣj7TX`-+X) Qݤ y;OWDbCWQٶ TՉPh~L k%4etϔ[=Ʈ/lj >&B|jI^2%2Urx9`2s+&FzgVE2fA2yq>?bg[e񘛜0JgZ<IF}aZًRСMg\KT1+0X V> 2: JV̈́2S,dy,.>"1"`nlA΅*6S˄^8'Mʕt`jF(^iH ]I1(wZ[qbR#uC&.uZ1ñu, лE޲[|j̭o[ǣDq.>hr/$~\2*;5⾀"ӴQ;'VɁ uk .ia;45ƽgE :!b=ȵC~2@{mιlZ̘B,{HAVYbFM|)[z劺eǶJeFporzK[C%kځ1&d,ZXu#6+B"@y ?Ge11~}}㑆_]Y5Z Y5~Lkh뚖燸*9B-Ͷэb~mzm-͝ˀRo9&.[bFEAމ P8) (2I}HzqWIY@P  D-SdVڼsͪ|f Z-,rSaVSo6Q; OQY-!C5R¬Z""o]4KQ QP4*8x~9D7?PM/,wۥxŒQJwqhe94尹cp7yfWqAiJ@iǒy/"(C[ hQB (=3h:S<tݭ..L>gHd,"q(u&!LBӸk|b#uWMMArFyX,-JCuxa!٧h[zr@gxЕp]j[v2\nY:Tb5Be> m @]uF;M$UuZ}˔ȝڐb_k^'bi;|=zPoU<Y5$IN,IK\F$T0KpGE-m.MjL1㕒wK?qU$*櫬wm4pP1{6ɪM1 }SlM7W5ct' ,ܠ4R^.|GWm[tFJRb2l,ݏ ÎnXmWLLOZ[ D-IÉ[`562Η ?zqYWBŖ@p<ڢM>*D'&Āb[p</'5,V3cq"P  o j14ps.7\t?2~o^`Wu'4jx0 6~jD?Gv ؏|g~o4Y:T-.hkckΑ 8P_9jG?d׵yhYMq!&At}:fxc*$hib5B*m)JN"Ԕ7d}iFI_\ԴΠ dIJfL+ZJh7e]Z;`eLi,5 8Lh6<otB}FAi9GwZ+[C,.习[BFK\L9_m}^6Gnm]6>,M2)ŦEIaB^]@N`/~S w6cJMJ V lFv̉+d.7/b @?N6~ҒE1M1T`T-Hj_R5ed4Z ec]ct!Q(ntrf .uA ^D(ʎݪ Mi`XZQH8je|M!bgʳ C$Ix. E3ٶl\ rk"ILӶKp` xߋ?z9;O-'1)9)z?#f'QLex"RT+[Qa֐`!и!ikX$6"X|=ߋk,5qm>9mdXe؎4pUأtp?;3^3r)(-i^2}[&i8"Ftc&N Y Zc`d6izgǨ@mZ?)%dk?Y>{ύnf{ױ6e6"^5= D,S &,M@s'JO~`זi-j]+7OčaYq&u2'JGUcfde&3њkȭkzM E8-njgVdلj(L5uX1K[A%Zg\%6Ę8oF5Ɔ¬7|$(.ĀQ8$~<>ih*KK ˬ\ GOY8!g9 yg  |+qK Y |j*ۈU+n6;R='`ʼn3R>u@x,F/)r:K=ua @ @^XVB7"1^֦}o l@( cޟ1e-BYUec>|QW"O)0X\%4RR}s٪jjnr3'IZU h>i,u8eq%,Z;AAvAKnj#by%w 82Bmf­`/g_Ԟ;[dpݝ^3MD̄&mr-KE&>HSMEޙE3*A0IjP_u-񼭨;C i eu$F8 |/.X`ٱqb)zuzVcȁņ5ŭ'*w'+vD.{dB3YɎPC5fR. 6["+k EaS u}`Z@ಂU TҎm{0/ZZw$f$ }G c1E#1d069`Ͷ_"AϒzQFNb"}FpMCcD|f"[|@0IM*R XHS%Pmw0b GR&0kk` yf00@ cĢTvn2kː_ *9H ֙> F-;VK w &ѝWE7n 9x$F+bBb%m d"-#F/ǻcqF%Ļʹq{w XZGsƺm~ANj湭]Cy$C>L17E \jj I- r(q`ö~}E{k|.0[}P-S+vH(ڬV#d1 C>ObϚRX)V`%{?&Bı\jSƔ'u5 "4WiP#QhLhnެb@申FXߜh0K^v&T6Ņ\' քF#T"fQIP]`98%o'k\_+ R w^| Ȍ ̋A㒘 Zdft儿brr[E % fY.t@[›5\M%J&'GW N/>#D^'XB&bQѥsEZEn읂XmLCTLW-.@؁&bZ?c("_z:"Z6["5%6Aݘhi0;)Q/s8M6 % <5]:59AwƄKPG p/2L 'DzA2pݧ_w@i~윦mV@^o[[\1c&lĦy7 Y@*Eb0|.1Lȼ2W"'sy'%AԶ[UX3?g:cuM4J´RfOR\JYeL\c E*ҳeRAv1ŪUa곹v`8Tɟh!q]@w=p:!G G L7ԣrd 9}Bsh;|@Ѷ[`dܞ"# `$w/o!Xj0}2 ҀP9o eV~lMkAݱThe*v/ev) i|sS`ǴlHݿWSFa_ *ja3"| X (V`$z;s%¶U&%SYL4 [R#QBz0Crm&6G ̴1i(#2RSĀ2H.@,̇{W q^]⶞#ؐ2#|ٱFq+P>GW1>d 9~?=nI7Bbkk7,t%iĸրco vL3  Gll؅8װBoiteNM `ؓhX(\J& < 5(bDfmPee5_7eB7}jMbCXǪԂ"Yiϋ;*ImǼZAʼnNDuٜDSO /El2Z>os6lNyƺ]`)h YHT}\q/bWkKTS)Q(㴜<8@Ҽ,SƶeU%Tޱ]V_m|P6`Hk<{+6q" *aYS$)ВZ$3O\5nUUQ6ZCYe?%9g/vHi@:){aEV6 aZ!3m|-ܥs;%1Ii!Pammd`isH`N@č)!%MGo1G#POS7 p\1VoU7~|칻}9 0^@ЌM pz_ܘ90Qrw${wX3%@!9_aB3j0w*B2 dn$VM&B-WL DuRBgU]1 D&<'2co@,beTY(O_׮[mۓ 12GA2bݪ>Z>9@O@ƭs9Gdqq"1DAf[1 7@"MRf}Hoc)F. x.;\dJ ,VԬk Yjz?)?Dw5 K[P24ѷZ[9@UsJʬlL16Ch]Z求ew)А6 \L!֓ ՖطNm5o[˥m:75QQAx13;@"J.=)p-CpY/Xk m[*}w`Yw)z[+>Oc_ >C q<ڵy%j1 |*s>4oYޤ *ޫUdJ`)G8,uBSpm .%C],wc]wNyM3[&I-Z&Qn*`U g D*n^n0ab:i0 peo7f7aC QR/?]w⓶\nn#!56jgk[׿x\)mZu_ܣGh֢g dlOnaԄ)nwb!& QEʾ4 $@!jiZ%fp&V0+CR2\16ժ*$4$Z{g.$Z*N*sSmr@‘##Ah# GǞ9п& kWj#G@@ȑU!> zNpqPJ&DAF1jF8T(@"2}X,.`J+HޟVdΚ bs҉C4Mx?0n-CFh<˲ܱ ^w*6j}}@S֠nBo}QJ%&kg&"}}nO͘Ӭ/~FD GH&*֒%М{4Gennx[G˥^@sqG: zʚpwwcӄV>x#Uf׬#&典Jj@3l놳:P`I]#vzH<Ă3wBӾ'IQG OI ت3!XlM,4MwL` 3#kl>Y! )bːrS !QZ o/ͥ4%),cScJKmGhCѳj [)PQPann|+j m01~|@$ZB>N[V16x < q8d!@ItzmE$**ۿtN#<)8hieWp8on]hJD' c}q`x[6R&;ͭ`j hI)xmfi4Hޕ0TѸ4$1+=`*$`]Je""V1|g=b1e^\b桃}9c\\/eǾimZLU+e;*1 ۶C-ʾc]/Ki. W(? ~]s 1Ee89Z%۔QYvɲ,ľ{Bū{G! ;wxX#e03ʓ6iy)SzyJ$.ZfI"W#6s947(_BrP֞VԐקiSa"_3Nc) 3KjrVNDMXD,2 P<3%$\InETfi?bN80:Jƶp۴{{JյAUkıMuE֍ zp!o V- ):˔,LIQb+`pc8jNJ[?9d: '?%Tֽ cfnPbU|*N}Ua*gvdܫMR8Nַ%3Gymm]D B%,$#m\zDFq+0]N}〕[-b֑*2}5~3 .@ָz`(T0Da[Ԧ+R^*t;v4Ry(/6SuSY#)__~;yrʂJZ4.1H j{Je2OXֳ-&಼[f{VdE()("75@219ZUę,y\ D, )۰FPrd4Z@>9}m>3dTY'o"4;oo{cpz:~%`\ow&Jo&icb,amB=& 0F3bv1گ\dbD&P\LNXRfINcPӒ5d2-)%ᣏ>tyeZVm9. "I-BO@:-?ʽR+|)rWRvN|9a^&̹;Y,71y- <_Piה bvWNV¼#CB~yԧuN'.$$P+f _򞁈M26eMwĨEy pr3S >4v/V OK0i,H@GYMB\$AEqi_*KEPA'M TSV"TX hY`r j:TG)hq'4-W gsMe"9]SjHkX̬SRW(Bu$H(T&x@( ND8g~>^he΋j(! 28 TR]72P %¨siyjHRPY1,#T*+wK V r5ϫ*-J90˦jhk A"sac'mھ;o~[WVq~zt:bd!cX=}|z'ݎ/h9)⻊h,#r<ր+^63ckH1u$9{e!h%qՆÁ vH𤢵n\`Y$)݂BoL9ڔ&n]JlHSL*kUVo'k]0\F2E*{:v>oyGU;d*\QlFZ/)aW*refuYWLS2/Kp?cczZQ/oZF+fDd ZĄMܳRbԲBgAykHA\|lF<Н@7RJd{rw{o@!Loak)vQ\kޟKl@"mKcC"s"jBLXvO(_ >* :M,l.0s1ݸZZ,fsk)xC!6^8f)m/UV~vR5@VA\ ʮY/ Ck3ȸ5Tɝ_*#@l{L+lYrR"` f lFx}4{5I`Y]{E*צNu`}JJLc4iSFO,jn!yǖ_B@9Q?"c18Ņr-!B q{? ; $[ $~?" |oU(\_]ǟtu<ʶo\nX~܏@`%vpߦgz@S,t/]\FZ RˤgV[3TʃiJ_N)NLͫ z$"`b9 w^`_$^1LuKIK$2MKo$ys3eFNR,͛77m,4,EA4- ~kk$rէpwC/ض}۱m06=x A"50OIxTU,}lW<Η >,`F 4<:[ 23n5E$<P5ȝX8x; \Z=*{[׬:LVMfC tI@SY]sx3K2g{ )DR $ ;"vZ Lt20ר25j~)Ի EO4T0ڱ#QYc,:<$F <)!v »a?;bmfe0tmĕ)ч/܏=0 IDATٸJHEK͝S`UR[`=oW!/".v$)s7ٜ .I?w!VFmA5tE9*3;X&~({UWn‰f $?M3j-5}̇- (=\wew]|K_ra rq-?FG@$ҷfX*??㯷a/sl#%0癟|dfro"S5ᘯ5FDrj*)X i{s c4]Ik]gL#d]0l@qEcvmp<#쁈`*7m$AVٓu,$n`/ F0F"`lmYFaZ7{YBۏs`Dŧs8?jppAQJ~"h>FY!/T))cnJ7o/~׫wob9ʄu(aغ=6 9cO=]}?>oYH.Er~H݁ıþ3h&]C!n@qISX5ptӌHˆӏܾp}px/TDѬ Esk**ېGkWmUȔr}Q^r"*Vܔ9p-mvL9yⲮ1Bݤ leGγSHm׺Y,ۺt:a]Wh-(=ƗZs:#yθ;Y,, fNHbQ'<)LYbMA>#V6JIe]*6 wΛ ӃXʖrµmNjP4$A\A VBBP`a>?ƈJC@N.WnuZz4O D/?he1Za4z& 5]g͸F@|[!&iob5=M%#"lqQ- :QVVEPuI"8 f%AϔtM(VjŒԬn㮚~{bK U,SX[S.D)VGxNux9LU1zG! ,W^W 6Qs3րC`!i_L{ >,#GXń/ Gџ9ρNy4<{"9R ׻5 )ݼ֣p s W_~cryBR<pnV"7G8Cv>PHDJ TC2t'k qӍo l; ƅˢ<@K۽ВՅP}vkEa:;Ƥl'0o,#jMLxRj] {1N7Ä]Q?j``۶gDm368C\s1ok"@_Q!A;l>H 8L/j>ieNn]Zѻ_%D XEm1w0~lDS,~cw݊YZ(˒-P2o[Y ¹-Ud(CH luy-& &LqMj]iŒ#=΃#־GhEsܱ<@Ȼw@}0m1|WG?6$ѸTmb#@*KWwo)Z{Lk<:Z P=k+,K\]y뤊>N3%dxd6|-JsYcP̢"F'ۭ=@|g9D@ rʚũݧUWڊVWYHT*M k- y:-6o3^,4K5F F@5c1#[!afRNLX4c_`*J@]v;V5FeTόWY^q,+OS0."ݬ/ ^t=O 4W*lΒ+idV2? j-hJ4$7D{G"XV5=J9X|SHIR:xq`YP<yʘFDJ)] $ lIj*_ EPkQ-&E`bm"k8O/s#59" @ϰ/[ϱYpT)?_s&:HYgۦsPm-Ô1}PGϲŬ`G1cv[[(0e-U,"K-UY}\LsPh#~>`@魚9ĒhHD0ڰcv-88HICnG]cwPlnV18Fh9S YB@n@~R@ismѾ[c#0:!GbEw2MO _<'f<:0Wߺ>wpi7B)HynbhOtmΛ`q_s ]xs"W\jqoXGj Mo *ZoIb H]q 8Dn˹YԹ6e"',˂Z͊k쥖!J% OOb1VkMw6#*t M׵yr`(yM7Ӕ`䌬kܺj8_s5mQNL!'I3aEJMf"}%{uυ2(cdn.Ph2W茉!:LZ[:Q`Rq;tw)粒u8\kXy X\U9{)j߼2/X E_3Qn;,Bd^R5ە 5? aփ͘Eir,f X_Vf4bd>Fl \1 tV 6[Cˠϔ&EK+?I3IYfS=2yE(Ӕ13 f|NhZ~Pd6W0!/<+$֔&D&-Ǔ1(Tھ߄NpBjѕ> t˙L-,+AYߚ5>kq:L LeRk5 @P{Z-}rv&X~TZCR) tY`M+,L`VޙDIjb*:&(>G_<Q YAF(*HϋBq\+gޕ gxs|=R=ݘuu$"ݾtPEMۣH#N{B8>rS@cRvM1F+IYibSWpħD~y8-kR7a}"2{kŮYm)(& R˵в(j”,QB,?V2G oZou2ySf4ˊLJZ,',~h#OAɓ͂d$3Z;eq:j)C ad,M(JrQ`YYd$*FzȔMSke] \V.YfICWtHj^YcD(ZIۓU֊ۦ <`Ƽ+yE P^DZ:av !_|epjڿyZ1-L,C9^ ]/6^h}JaBgdmQZjx+"vu8 MG㇈, ?6a| !M`q'^q+܏r`hU*~DԹYgb&(*%s+"XK~0f=40mAΤ|30ЁNF\rgƫ~~_;~$(FK۬Vw }iAȘ^4ρqLwt-i#Lj 7* }?q R<aѽ#8u7;fGlݷS}Vg{`+0di)Q֌֓ݑ˔J)BTb$&F -T.NnE=R1 (R^H7Rbt@jybUyc-E O9ʾhH";XceF ZV5ʻ}+Wv>eE'U @M9A [1Uƞĝ, hQ2,u?KmÛ7g*8Yk2+ʦW;ϔ͗^@OU٬au}DRPuW~{" NH Gn\ `, F$TS֓:bn]$*ah{/gm1 v:-YOBPz./Ģ w-VgBtԠNh`ךR$["9rqcEvʼᦇOT2Z!mƹ|dFc|i 6Z\We}>d[8.Bq4="#@(-3P_/Biu?3ڳ eqfNƹ&FXcж y+@dא`İF jG ˄ 6\c)ރ0իN[B"5ZCFp֎ܲ-Gng&}c%y\;o5!{V>#;" P}h`>Ge񻳾S8e6<fGt<4UdY0 W:7 RFR$n b!S*P5HoNv8ݝб"Vo&e1lU@T'\?M3)C4Yg$^%eIE0OvmZQMSavua\ 4fu.kxŪ33>'IRen KT)ŦEr"`1~g[l_r{S/ieŕU*YK | ܄[/E x40[+ ,U9gOi:uxM@c5nDC[n~{|Vh282y .Q+J홨4#X!FmR='"dbvuπ-mU&Ⱦ }8iք#ͺ3-e =Pj`][-p.ߋ]XSV4Eج;lϓ+sbl.z-&J}!M 6&p o#ɢO{MeB b۳ q3%ߺ\V|_r$q,Zۄczkǭ„,!c ޟ26}dc^kWcϵ{q`$]@^;/a3  m9?tc#y}撣>{ |^ǮPNTB `hri\EH,ˌg3!Rˈ<{`kvoO{mUs v`";<v#6%Q"AZRRTR5jUZBI*J `bCy{9߷Zk1s̹ιok>#hitx4j~#s_RDk d @#h>IX1#hA9&(:23ܠiD0sevhR3#Z7s$ɛbqT(a׉dDHQh!Tu,05RTx$T-`.S{0O24 CwX¾-ȃ}S0&Ղ<.2fkqMdж }%`TRm%3#%fR3s3939_5sՔ`J̷ ^훶'p\1\M11QfBx? FLRz__V[sE,mcRv[ )R‡>{x%O{$_*h!߁qLsܖ]=, V7m\q4c&M#aZ(aφˏ*!'MC8-8K!7}ֳ,6B",#ER"j.XǧpѠ7uZ$o9*S ,@ My40=5"Y/䋿2wb1['+g)4n6J n^6F|VwouF5cRA2SׄV1%cC Ph (W=LRoHh_Xĵ-~y&o]J<ӪeA)3I`l2/sլCe)ePQH$&_777$F3E4p|Kiȸ890ap)#ext$c~ `)5Dz) ,GI]i [.7t"g쬤a/~ \eB|ݗfX҄RwACPzрSD)< rtxEbtxBA<=dKr\wʴ/;+2|ɸ*.gEBIU!vŸ)IDCM.XWox(3K(L{?mWQwIDzK{rV+00J)ETv3?C{pA![}{@|g*F:D۰%Oh,:HuFV@fCU^9DHgLwqpF0P{Vma%I,"ױR| ogEX$1xE"X촵^ѭ_#Ψt߷s#Jz:2ශv䮾ӂXHB΍V1S}8;9 t|> 8:!Rp*4XA?N>ۡ-t|Y\దfpEsYuZY9?(P+hIh=yKFȲr7XF4';W*L)|$&U2!_N`:gSҦYO fh6q q\__cG^0 0dؤIRG5ٸτGt=Qטwܑ1x] r)d2ᩙBYΖS9_E9KηEMˍր!:E"s/2q*X0/'#[JYCɐGq/3ۓ$!8J+ @`y>u?jL \xa׋D.Fe $pEǢfDa-X,j&k0n 16Q`p ude˜GTM0gI +aAKY#9wh"E#Uxm/JrI%Q(|C;C;9ť"БUE+u:fSd Qe,cP.”ǀ òJ =]׵ϴG[L5F 喼L3NT}9@aKv9`٨J'J|<8 vN_[#& y /{jðmx9Fl=FEp׃oʞ?xPw%F#vs0n!eLD5u6#pZjrj_l_'4{h5ps~xEFQ[>[[ǣ4 F"89 h=֗D ҇ ?'5\[5>|lx t+-nvH|~su?k36޺ zY]hm߿~j]ʫf'tOB܂քMl(X_-KH,ƏEÂIhlNt.ަD˜fA&\=576fˬMM̶KiO<@<: oV>B4'@΃hx[i`Ҵ=IXJ6C޴? ~CG?$e9Tp=O(%Tء'4IƈG)>gNK ͫՇ=B|M^/mo=#sh@;_woc!ظ JXd\xAQsʚ\j}QE!ev$LCd2fߌn;ah#D~cA"1vDXh[Ȉ >ڗRqph*ɓFd`G*,k2@io^E73TGEļ:%`KJ`K8q@,SQHk@D W%N.3/G&D\ړ%Nk%YhJ LL6zLGD\/]C 4fR; ݒDf *( :_jGzр{#w?aLZHAZ apG)@XohEI*vƜ< lQls L1I{"LM`aaѷe`uiEl SJ(C[d&e*ck!G2/:? 49-C{[[PHƒ=So kYN Έnj#C뇯 L!w%O#Qדs蚱Ѕ@]Job'wxe ي/gU6FΡ0E"R՟fY<3Sk@^`ovAכ[niducsmiHI3oB:F@"c {Q@N?嶴5mv y6|Yp<q:>ɓ䚗GsQ: `8tmuOL7aDz$,L\Q>ݥ|ϣJ>WR|y$yg$Vo^>HR}yx67͊6|5-Sw^uX> l)=y/^j]aMm@sgE2hxP!-e%24S3RV*i@aI :Yǭ,9MQ Va@Ih$Z H}o,0HTAd>_¼;r$ip&{F)RQbfu/ ńF)1h :{9 ǣ8җ{NQ0p9Cv⫺0w `a)Yiyk4hiAlg Dا<݀#\KW:YrvXX-9xͯTH[w}豮a׾_?YO׬FŻ^t >t: |ko?3_o|w7!OSx$-IׯIj 9Lϗ  jWQ겺-3%t&;k&JhiȐq_;]\L-g8inᓄ5hQ*mD*6osZ%:Ƭe.[&n*1իz[%3كZKw 7k$:lu yshmN}vsw՘h8>r}ՃjW2!ld*`àt0V\1`bņ sј :'Mk}q/gQЗ3&ݲKq,{w&[W/p?Am )V|>ӭqo}>gϋscog|;k$MzƖ[ۜ8[GZ}ݍl?b^t b ĮW=)߃ؿ~rvX((k ;I6v!bD$ rO4oDڹATL%kL) LD7`Ox MYJd@QgW=3D#E#(5']AZP]>xq5m$$5-%2n&e n*G, 'ο'X(>l ES5%):YƢCDAZ Y,9ʜ7DUbՀѠ e Nl}CYyhˠ?V-B%VlByMd P `v>3IC=DF[WdYˍ(IT($jQ bH8E|P!% Lҟj /v!.1^&g);21 ǣDLY?*(Z6AYɋ:Ӵ8]cwa.= Db>5M5lI K^ fU@YĝC)HD؍#p0_.HHw=˘L$B@ԧƃCd$:ְDͼ?Iy꥚pc&{ O O_oQ1ں#ƿ^$ 6$D݅UeW1k Ԭ3 ꜕R¤6¬a>I@,싾kVocRU M=ΙT e'X}2/Wei螴kGGSȤK 36Ryk)Mj?6/d󽶢2šYVӼ˖RŘ93K{- 0F~:Cyyn*ݠ0ul\|HK)u]S݂#3 ۠7= ?6../Poxm:zf>-gZՃ-@kM(mܽs9`{9a =3jb@,nɘ9%Sz(nPJV3jH?h%7f}$|qlP@\?!"S+{8 D~AJ[E}Y i) r AjaKX`& Go0zNǣk䜐R4M0e#7?%Xi@ R /X٣ƪ,/Mcr¤" iUOyQ*Zũ=g.=Uɔ:p\=6:P$Xy88]3#̣Γ15+l=B[ILܗmWfpwyt;jbB-z 0àa~YV^yU,$L19el,G {<{!e1gK qj/&Pts}#B]/^MЋx[DH\ɡ2/4m Yy_(_afW B؁$Q.H;O˦t{x؂c D^]$9i<瓄*Ԕj,CnO&H@箭"D ?`xB)50H(ddRbxghcqGઑIXWD$qEJR5dxcV9܏lsڜ#V#" )sn^B85(30 <@!ن("2kԬؠcK"<̳ۈJ[o,ԣm em]8oIWc~ۺj "nkӻsb}FK,JP4# [Bs:.b^d?AzȽU 6_6~xfV+mл]m{P֕++f haEmLZ洄PS]}P:03h`ڂˣUTJ[-L&ZXk\ \hSI51  iaکDeQUp̌Y%XcL:5ਟsr^ABWA{"3 "\\\t>naG@ O2].Mj}@ ^JEZ>P(E[׌X_H`!6@Hn*Fc^- jDu/msv< z}_S;G!Gy"tTDX5c1S}9~ Ñ\ϴLu ŏJV i[ԛm%}FMYJ8vRi}q.)maa6.`3iC5kWt|mӖrmm?SqZtWR5#&}6ݘk~nTRL='Ab3DhG$$!FTdw'D*OY/ [q}́巼ʸpA/`sVd` F8!=\ KQRJD1=T(/圳ƏώZ83`~(fŨl3Y{Oddu%|#XK{?zK̯va8n>jgաqyVe¾`\Ps/rb|e5>Xk~ Ȥ2= CV^F͙L%xmVoy=-BXCm|G{0 Э|z>'znJ; LDx1:Ԟo;w}@I~ Xkd=x`uN|bm9?k̃-wo=\h(imZ@s N^[V'F+ *|2z 3S}6Qj[.YBM4!G+19SKqͱz>1$0XI@|NTb̗dA4dP 4Tj-r 9f0MW 0Rʰ(FKcaig,iR}ne19 *$WL(N eYj0# aR?CmWgiJ*lF)$Q]0"fypsQ> 1t ]ދ(jV_oxl?qSވeՊpQ01 1 'ep: wR Ҩ# Sk 7ǃHK, D&ޘ-Au8Y=W0f%[:wbƹ+!aޏ 6"WcԜ-slGChb&w< h2ڛyVFEmJ:LjF)N : 6iR.K8vycRhU5:@h &M#fW\_g0uɼzym\6.sYoб~ QrN']iEP֞~AccT9tz"~AI_Vs}(vXE,gӍN(Y7ha) ęVWG[6?M :1A*~ 97jiu|, 9:en % ' 5#80!f] ,n:Tk IYRƝle`ge'JDߨA)su,X`nB3"+NHbVGy߼ bR[D*L ba#,-,(1s~ڡ):'Xd|]88 S <%;zc5Q_dbʂl0|1 n~EP'a5ˢfU5DEե$[gim~{=DaL_>Rq-lgkNj0yZ8%D+^C{qSJD=,  ?Q4$fC+Z:9X5ud}1 }HQ'5I!ÊkUufÇm7| oͨUiUÄk5۷L В(8֞ ߾[D-s pJSpcgρ-/}Kٟ9/I "TB*ì,}aƣ@hLT{h&9WbcXOt00u6#f(=ěwIJWjzcWATJp"HX`>?h(L0-sD 8e 38v&Zh 򶲇Ҿ_'g7wH=tҴ4ڐ9MDΙo>.Xٺzч*V>yO{8/(J&}<!>~gP4|,QH4-=_Pܼ!{܆()#!9B zg7` wk#Uպz). yId4=BzL&::߷9gXV!%,ʷT#N%5S3;e\= I0#y3#Zq(~9ouaԼ%`?p5Ja8L;ȗͧQ4=9RRMϠ)8{̳ =ǣM'\\@axdMr2tnshӷ$>f=#nXʂ0?_?BːY]cI`&N3}kj]X:BCDXHS?;?9wW0}9?ֱQa,Mh%frQiOo!fe `о)W Dɞ=`!+4EjYISau~HVgh'[ږ}ViIY5JkRxۡ*H!+Õ:p^͡ȽXCW7ِoZ uy 꺤0hkiDz -0S$DUYDU0ˢSYv@I"2:ı~ƶk$D s6`zcQzst4"j=9x\9GI]kdk,n#y1=B4[@ &+߁ODņ²,iQGzKp]|_/zʻ[רy9W>imYs l=/m|7Ѩh#A@[ofA]{JB{ٺ՛V-"L)RDl6 ̙Qͯ!a [j!v@UO"3UuY'O,2cs']+3$" "9g?&Ad:ZHY̥(wC@i:toOCB\?x ( %{&vā<;~~à8/*oQAnה?/՝tM~Q sOt0T!w}au6`yDdD7."ClE78{,<՟_~"~ӟ(@ vC)p+Eyx5VG'Q7> XTc 9 ;J0 &=hmK)8e'a-&8a=ḽYIi6n $QfPDHYÂCTƈYG#v Pl՞Qնef/#z~HD+Hķ;Ճg}2VrKAgZu=teX,E*Ed3>ޅ}fo9mȇ;Vϧ\lg/{VAC,+_#g Z]ۚoMߨ#guZI.B3(Ň+p IDAT܄v^+KDkb!.0,3JE#J> Uk/3֟˲p:1 c C0Mm(<(9Leͱҳir^JtR^Ƣ~, qyqr0ka?\1,An޴s >'oQh\(=c F^eVb񷶞8WAJ>T57ͻV-ooq*.Q itڙd= 72_!4"/%x̸_c|ߌ;w1a0ACCnnbKO D#|k_ߋ_}$[\sκ??qnwks' ˅ϼ.uNX G}V L~ k_G+l}sVoKj%wJ;ZHTs_ƺF8$gp`,`MC[mE^|j\{T,Ӡ<[׃ \t\@\?CKh|DˬY$RTR06;~( ~ea$\Y>fJ` SyqG|d6҃T 0X"e>GuUKM+SsIђ&a^ZM]A%:f-3|+4aI=omp'xT.Y<&ǧ|zl|K.la&77%HR/- huqj,摳xHt {fP 2}d(#x-!h Y m`{z IlP(PUMdu,-f *p8լ֖*1a%o9e'r_(﯁.RJggjX{].vxl!DfvM% ghjMvy#Zk^ GW<5F7zKF1%x1JV~!O\^]\__>~| o|߹Zm܇s {[k>׿WJM)FbV0 ;J=?3yv8 i~.ȥ _߄ߏw\$->{g2߁s;"@=^hE!=J6>m]BJa/-QE*$k[,Gfl{Ϫ Y &R ژ%QZf)sݧ!"wr<@2`g$̮cG7]Q )e 7CI| Q(uΒkl`H!8(ï@Ds㈔%t2sE}[RH0F7Cθ3VsДi2 >eX~ʣ1=·Qڷe"_ybzZEZJju7^}4Tl$Y4R[(QjG9 "3!2bjL"@uW͆~w  ЁJ Z欂=mNDt\1O9̙( ҍZgUsX,~>+Aœ =Z=09KD0b!i1X&n ay+i1wo}ؕF^30> ߃)SW×]}[̬ Lb3>?x駝Xo/gl9זv Εݏ׿ߊw|Wpn^]͇.΀i:$ݮXn`)o}WΝ; B={nnRduiHOuMs8~'r^zݷQƯmoHWRp RĘ}nkNҜ?\whDfE|@4 6%8:DZy ss?s;3&6_oWn iuN揃F;jc 2H8%eosûUZ3\Ϙwq7 b5)Pf^E:WآY ضA+(5-hK^4Dku $d51^Ӊ(`żʨ ɢp9%Yh0wMcAbWza?à3<6@ؚ1JotZ2/`ӼT0!K2yy>,L}."b].0e)8bIEY,9>畗1U`Y4ʓq{}j>*aլ=#톽`;âI7"#xz~4g j ^3^?|<9DaA*UD5(1H\( PS< RPnNUForCd<n\/#6[؄{%&6sx"BGػ E|TjQ(j|M GmD0Y Ĵ̏@H@Վ{Ԕ3ϴI~w`@sLzڗtL?*vpy@QyaRYh=H"فW907'f,JCq4a z+}?pƣ\qqqq\\Ν+\bEXmlyFi>s;>CJo}} ǣ\RWa P$Jno}_~\m *917c/w"訥-7CxX*`haHaύeY`H (@Ehv-:E7a 199R爙6縈<3kƼ6qhPr:̳B,,BDƘisVsY<{@ A~5rFM6d1CRbZ*0N<͵Z۽i TSJLMeAY en!Yc"Xx<9$"k͌< oKI#_1웴%Z]b@>?7 +R‡e"#Qk((D$`WUYE+4vUZDEQF9=Ʒ0|̂@+2B2N!H & GeF$iRte,E%0IqA[{.p}]Lي)rGlࣈhM}T5KКj-!G9iC !bpE#OD-n"iU gsHnֆ dK)~QTX}Q438W,F! Wkg۸U!xsq<-ٔkLӌK0777 r.q!_:\aDÐBJC"_Y*Dwɚ4PR!qaJ( o]bc~ g҂?d`Tt*ܐ b]JC Bin-c}Syd]N3pʏ:_"#M󼢦fG={v04jVoq0bf {WJe IY,n۾hu'j_ 1PJ*6>0яaI[rG$6[U3}Jdvf̻Qз.mDwSͰck\ǺTjDǞX3w^_]QRkVjTI$RRv]Z.MN2s9' NL𜇌D3EP2' Z_s$n05PAװI*gHoV`ݳ˘#<n~q"TwJF ӄ~qc&L]qhΨN⻗4V9nj)h, 1Dcb#.0/\#SxsxAfF&!ÄT~#obL2zl?Pn 0f:=xD*kxBPڛg5jUHpf>,|3)jNg\ԉ˵[u9se"UDf#$Ƅj#&YhJߣ1(se` w-Vofi\q& 69K%MmCvoc0̵M=:s M{!;x>.=6IaWy|gBZ1aÞ7/+ xmz2|ܙ_LΥib1{YeW] r P5'e. Y%GdoEzFD 7+`f fo Uu߹PP-:7p@&,2pxY5n*gDm v{DR u=.//=?apmX?Wu8b` [J{Om y4O`3e1Y}Q R& +r&c`EprDA:D⅋@ef.H%n{W/\ `AT^N_o{\]^.u2 T=j#Uz"6T Ʉ #I׳<R={0.L˟M Z gWb/b<.[/!"|0<#Ush\[[{ܾn,o\{ g׭`Cjsa/i1F<1`C DpXefcՊ@~ >q}Z~@4ʄeDp0M5\dte\Q i<C(~vHasr].KrHD"TDn읖7[#>:JVz`e9W6@sXC=4Rjlhp).'HDtLL߬* fp0ȴ]K9z^iiSO]SE+>\dL ퟾q/Fmǽx q6NwԜ10|]ϋD3Nӄ'z_O^a׿__ݸŅGj3K˓]2y  IDAT6@# 8*)9ϞYe2R7zY ??L/R Y+9~w7jhpi*0 KKz/jsp0J[ߟ D!ѥ:RZrJǢ9GreA@V feYMat9i'%M0>hE˜9}bR5U%G4N3A7Gi{O [ Dͼ% s8op,?Fw Ǜ,e5dfCob>#h>1eYeq5Dv&N''6"6*f K`kɕO e%e,,feOaEb7/3UL{}jfQYqC(eM+B YꨄD61k`LV鸫AIىA7W7L_UAIr0[}hwpsJH`PIw8~ݽ+]+ɒe2W0TO&*^S)051dGbRC&`cHMA AXd˲,9gV?G:^ʓ^^}ςYTʄ4c?mSfND&Th?X˙ >% D#%'IU,/,.h:IƠ2L%>nL)~Ȭvߊlvnn m4 PP D"C)^RGoF/ѳl7ƵFR=ɚ`j/t]B/֐{kg yeBRزk0 ^/NײOX.%Mɓ8 0L\Uµ%pT"JJHK,!]'@DMX38SGVkZ".Awj4;w{@s>iCC}gus _of @U  RUK>Rw*D DW (HS IƾYoLX%i; 9P Yk+9[eU Xh;OV>1dT3y*#7>|>s=g R+Xݣ,PJF3fkYŀƪj0:af_|W%'XoxƄBܬ xKD&$CgAe .3,[.P2~#z nT8q "@(UK)κpM* Z^uEa}vB=]bBWľ\,0ddb^(FAq`N0!2~2&= /ݵj0RFI k@ g5:D@O*hZNH&0%|ՈgfΜ^s~9w>2cso''jn&q+yDS,,P,hࢢ֒긖ƘZ.0`b[JM<=q-@7}˷;nj_,fUZNH5UhL!"!X1K]B jY$n kހw|]4⮹5˵H@OI+PWj#=1X w&PX4% ȡ땧̓Gx>Kn^`@0FBf6u% hQ qoN\(> R].{8S K`Cb*QKzhyˆ* 5Uuu-т9U0{[塚= A]B$X{j0bP9ӵliy]lw]qrU`ȿG̱)x,Bےp/x|jypps|eȅVR2 $ tMR?~7o۽}ހFW9m sFq"#9Sx _n(K.ZԏQj֐^]'Hή)bn;܂1.Uw ~P b TQ 9#b:DI*S!6#TUtFpux@'{3<4֛"YhEieukF+1_V6V4ILMh \W9z߯CJ֩+(T7 FB(z9¤oaElWR}dWC t]`9 Uh}@f߫RdoB1AΫOw{QIw=i ;^V\Dȉ3,rbZ..nq^:~g[ux˷gX , ! [B,2X!p=b`P2  ]aB@ȨPWcI $YjmlAR=y2Gls4`Pwy"<V elFuao@}o3 *cMaw5lNwwrA: Aj&2؞Q淗?UK\q8@FU_K~ b>]7FU]o8x BtY$`[* K5-@u[Ԫ _CDHN|@3-_qvq@>88(Nȼ[ (kWf #ոU23PC>7;678V  A7{3^g9F{ewPf|=\L,411"%PH{,%rJȫˏ"fϹ,{UM窺T7BۚU+VJ!Q&3< 4YOa  T!evVD9ZXE\;0?VM}žWvGR_AKTq@w>Qj eK ʥK!P"nآ|vQHjeޏe0&ME%u԰VRQ \B >6fD\صZl J\6'عBj{Bl*̛!ҥNܿ2rf$)ȼ߲bi !Bt5*S^(ADrkmRHjH~'Ob}n Shz^b+M%sָA5⧩l'XkKAH ~2nppٕl y矝3pӈݒ+ tT[+JJa-D<`ԉ f%@ ZeF*(˚ Nz>e+Z94͝t<aGl>jЂ0/話 TXkUuM2 a*oɫT\vPWMhP ߕdq)r/%9%DvsʼcVHR6m>=QG1
    cTӋڕghB9sAfĭhmn]U@D91-j_ I(㋾8}4 41)`CYgT/ _Z9m "6O" {K)V,D8P),KUt BmڷBMw &8gZ y)?Dhj?AwPWj))ZX*p v͉-peC@ϵ,(E3ĚZ+z$-@C CrURטzm 3b\b^p b`bD K+ $ׇ v =i\LM/&\< x]MV_?讗|?(a t p0Glp(P"fl,WLXkR_ k2|(}WlddueR}qI!e8x `"U-rz}]$ 5J[T؂c_SK Z3cLr;0R18qJSD,Y!EU0C$}ݺ 3i@ik)q&`Y@"M8/D]dLZvzsRiWFi\'t좑#ssS s˔7t#4QAn/]Ow܁[oUPvξ\,*^ny~gFƢl87ϜAXVXifU`#G?û.;w.-o}۷կ~̮5 | D Q/|=s_[KWj:S{ݮ`?\t?M5਀B9Ld+6S6i76捧N09r PDlz o4r8ͱ:C#5{+eՋVWB/5[m 4.78hd΃)g:Mk0 &vd<*ǰ"5`52nƑ3Wm[l@MEn7}"с2})b$;cpbS!٪ʈjO!Q˵f5>lĂb>t SOۈC %n-YUBuQKOƇߧ_g wgS?Yy(K LkӔnܫfieu".̴04v{d+aIXP'Jfe!VLTxûp\Ɨ\/HObϋV(XLۢew4;ݲk,jCxUk9£~uԼfZxL * &@P=' scԝ1*OqӾ6(Œ:kMZitɓB_cnp 0aᓟ$?usr]wỿx9Ք|}a QKeڟk}^6s Dj6sg~s?snH)aooֶxwmo{_$Ipf``#Qu͎@,qsY6Efi#j7ԝ2\Kn1ShL[Tإ@Z=-@pD5~͔a 7V-=:4t @@D:PWys8Q:$SU^JZKvre$v40 5(n\@!Z.1F b19Ʊ6땮ЩuDS^X!8LfPJ"d y.ul9ս)@h|2 U0qo~,I F_ b:NlÈ>0qk+\T+u|oʮʁTE] CEn⸑ j@K>~j@~lu 4V 5A @sM]|4C5 8b֏9hFYߡ@ -ұTNFd[(S3kEڽ*) X,>~⪲%RfF 1o*p!RugSMB0F"\DMLllLC@5NR 7ٺBR}D>d«L{jiEaP1b4#QB9ڽy5d.#;g<81zW?l~kƄv'NlR= BЂ__~"rja^lw |;aXE:Y-l8yIWu(Mquӧ2O]?7'?bSNaXX}Cevw}y5:' |@?Gd\&"l\cfJ-m_i4R‹bB㍪Ȧw$-P1SD `xFO J8$$0`ʷ-9Hi}=Fcܓ,c8Kk|*`IhEHךZN+#jmi&:~luGU{^Y&Q\PE8"J ~nRu=G+XXβ$rt^=1Duխ]c.Ft!0`oD[8M6GeD2Uz5P=5y+`$ bB6@<@gLK+-Bx!7oy|ǯ>F? }5"?Gg??M%Oy഼gW)j+#S' $8H:4IEF1!MvaxYH)D[G1$hVo3I>3mJi{fZ/Ds@(4`,ba#};}[I2YhSY!Tbc]|hzdq͒ X^(H)I$~⁈#ꬭ@}<%d־H*CN kUfPyӬ)f몥1qpcqS F`]"\ؽ^w}3z<\±&Qhw[==8y$N>'\t .\0ND <Ewb1v.ZKKUnȵuo~3I,6bѬ?S=7MxGq)\wuqvm{C5V~~ /^ĻzJ} s-xG|Z&;~յEe6$ӜY&s!YR̓J+HajuQZ8Gp#gڛl[\H@.I{0Pvo~`_qQ왙7xlD=FT/wzX H܉,U@zq]5Ua|;h|+*S; VX@VR Pzu*3TeDEH:.<2Bs DRzb5;r~QhuCGm_]PZH&ËCD8yiO=uBIlC؎9Z&X4@PkWɠq| t7<e} HBm@G~kS7~W\[O ZkD>wm@ P-x [GBD`(o-d@bB;Hz;Ɏ^@hU͜1F YT#؋Q` xTaQƼ#8Odykr.:ePiUО4jm}#kxV UEI d5 I*:# W~ IDATQ:W~ծCeδLu< *"RV}Tظ}%swۀsڟ9e l]䜫Ԏ/hwH!GV{{(R[v(rn;< og?Y9s7|3^=^ ?~U7~7ۿ_53|<1"so[X12m;sTi:ϩ4% h~ |qݟ,(jRQRբh^50EBC}(PR*8<[UIFatTx@!BW a*O,%#-ᅲG dB6>)1<7s^y\^4!5y,`{5QEkL OzF>Rp }cl6s !m)\+`O*^+dwΞw=Eꋕ} lKfD 1I 3S*qU3iDb8}=ǯa9!f-N2S*oLC\?G|5ox8{HxٿkD>C! 2ah![A{0%f`~`g8bq|q+88 o㈼]P04dJXA]:.aA@`= 1b+@`+5@ԙD3S 8?cGi A\g 과>j4Ej]<('3<8ͼj0~~<nf/}ᵯ}-w >(z)z;Mͬ=h"ϻƒ:עz-HI}E\ՒƂpϽ?yqy>}wy'+wuN;wy{pwP{ַⵯ{(/cG) dY>vZ)_Gu!}k :?8I i O+0]ŲWZ:GiV7YߋOqЮ`2h(qH .ټA}O$Dy5kx () :P޺Peqے`kMk v{huP0uRe X l\8 5A9ׇ[.6[)L I0zUM"]JXV-/j ,*"`,x2PdD5[y#:( $DZ,R8g 쟻c .Sa*ĽLRu#RTi/y~%ߧ[Ǒie". $m;~_߾?_p-5"]P4n0 'u z3EIvySʒWS*V7-`zb ADI "Ɯ#Ƽiw0Wo\亖RsB5^#/wbG4\yKF|xj%Tq&ƾ8&%cdIJ/3hJ// (.4S8TH$q'Qt. !K5+4y;aBM5cZ&bj=?N.@=6=B 7wj ѿMN>wɓ[׾wuN>~-h}΂߿_Z9s]'qSX,u ]ɋ_BnNYnY$ʍMo>Μ9zoگ?85aI}݇W}W|ʹkT㭊}g\ 5:mU'* ; 7] 1Zϙhܔ( `JD뮻wy'kOƥK[[J vY _ E^}s*/?έn, t]~ѣW\7?p9s/x 𖷼o|Rw~wpŋ8Ͽ{꯮Zmp윰$$vM|Z"wd[vV Wi%=ˊ];vsc{ZO \XߛJfCpܨt^G֌UTp)uj1I(R 0qÎ!иJ-|x\8f#JMYx_AQ#pF,zI`"n]3gXj]RLgiʗX*~rH}lbX Θ52l6XN vd PC7.yḢV9WUI]xM0msޅ=% m@,Bܻ!TBw>tdJBGњGYȼuevB@H >םGϗ65f оiNTEK2[pj೥dnF-6KkQn,5G1@$6Ȝl꫎ku[v56c+Մ=qKBDX3~v%F\/\6*( gVB򵭁kHOHpDLQk 5ݘ(i}ʽM H3% {fq|,̸ULy˵z;O!r.]X.8u^n8?3|œO>co|tYr~oj/~e ɟwߍSN9y+oxc?x<8wn>ȏhڧK+{,/9$w-5YMÀYbppxd6AKmйLcR*_=$LGn!Ot4<ERU_3}D-*poj0`,a~|6I4HEh#AlD"qUr'dBPڤ^.]3h H  5}n}?plZ`k"zEͤ9QҚ/KfpyBܶZDA\S&r0[Dp5Eg0d9$B`47j׺v~G'A2H9d᷃.5sM,=JRp yp&+ͼhRrЎ2{O9oGKӳAϑW|<gpA-۩sι1nA~D .\>!<#t6ͱVq'8o~~Ǣ_~xOٳtYC{EM: <pq8HjV˝;g1׎p blTaD&?m ?omgMբHB+#_ #L4 9d1SW塅 ʑNU/u`> 1>uCAgD ^Bu?|hUtaYnA(X(ABGTv}{LqYGXnZ83Hq..^h\ݼaދs𰱆oy[$[UB7pκϻI U$“O>|XV8y$nf|~)>|?z gϞ506 d6!/: Ϡymӽ}BO~4xYhMV :%% *m9ȂHown}gX@F@\ce2 3P`Dm6F 0EcXFS ]A<R lR>OOJyXvUֈG >zy0L Z»bL c^ 'NrŋB.Xl@0т)2Ѫ5H_oN7D98w Yv#r iaϸA*DI]]J}m`&2~8خ{f$hbEl`0 Jŧ28 .3Xn3Cz0{ XOwy&n!\+n^d$$_{6+i4.mkt~ٍ#/ ;:>ϷKpégMϟy^JO)>l s7{ﹺ9b)# (C-B-'*HAv n7[B-tkj~FQK?E"uWkџ_ /pY-Q{68_cR["G&6RŜο%kXxWrbjUp/PHf( _-!%lu-'4~$n}A?r #'ɅSZLe!FUeE)/ N3enG8q-5YY>K.;ܗ!ADVL>_I`lѱv׋3'V+,_pzŢZHQD*YFL .nZRuo$sIHB )սܽS@)ZP˓w@P2Hk\0-56\; q T$F >pXt >PgDW/AEjJYM4p%WZq=0pV]c ^P@AIj,1Q\Â- e8%Dpwy`4&,YzDcAl j(h߄O+reϞ %1q L TW$c= BFhк2I|BɽL3mpuQU?yZ$C7QdzVl)NPkɁy`O9{>3(NG4워i*`.{W_ -pU ~%7/ >կg>;G> 8\mՙo%4Vcz׻uVFx衇SOܹsp3cWldM Ek\GzsL;BA8 YdSAda Q81 sJߥ s^YacrCm.K@wDXc +baZ8STOV(9;6ۗwɮٍ<!@bi 0U& K- ÀݏXLl0/,J Z9<Ku+)L"b;ɍ]bn IDATfOЁAqrkZ`)zZ(m%1U ,ga0Sr퓔"V=`\b(-.ftOՅAWjiR*\&o~S$1VԾ=0>"I κ 7.* cu$ ׮]CL-=_A zZ"IaC@薈=4n9;@LS)!3P*rI ,שE`aǕ.{]S1&|bBvg%+V7-}4L3ۨ._9WL|"<vZ, Rwͬqfj/L ՠ'ntlo2Mwl0`G15{ AF3{;4&˕]ѼS;MPs{i̝kTs6KX.{1E/8fv7>(n;wiD/cx+_e._)rvsUsor`BR)zAɟ :, , l61x \p!ybqz:MDy>3nd9iUkveS&LǦ*8םٽ/+k U6={ C]07/1n -=YhּBӔ@U]kRar0l.(] @->8j6}Q8i`:zAݐG Bu>b/CdKȢ4ɃNR(͹@c\ ្{l6Qr<Y)Xr1Y`!_ BZ9/[@7v\8h YǗ7K) nk M%lLi) lei!R:+^@)v5'1Su-y4˧ցE02޻hF̮_Ƿ 4ARbkݮPJ43y5[f@ѿ-EAse@\8r>Xi&Y^1D&8W (@Y3} Zmu?%jA PnfzR P !;m;j>o V:6D5P^!"u y2uM2whWr¶iPjakxgɘ8&d>1&r}qSSPCn[d1iLҳݮ >8 3UF?uO||awa0G? .S]Azԝ %roDӷknV霋 ʯ /}ߛ'4o3!z+V+Ӯqvj1Ō ̴kjaӿf鞹~އ` >jK *g]B;MhnQv/&d5%by@##9H 0#PGc o7)5`L 1ɧb9杖9` 6-b$jZ`@3U&7%G,0<I5DCb%P8dVb~s:v3ۜ% L! }c1 jI$sO;DGn} X`4E?ӥ9a܀mYcC)$vYcɮz 9GǮdG,E7 [z{5f**"oNB(B\4Id./5L&:z O˦ > ;1<[>K$s1kڼd Ȏj %`+y!dy[h_?K3DŽ8b2BEU3鶣U>;/M{4Me.vp)Av=ӞDSHk?N[rwpO=?8yٯa(sl欣n޴)Q![ł5.'ƈ//?f|S2!( O}!%6CX{ N?jfŋƅh{K_({"  e3QA+\JS~h7rPj b;ckK=%C\\_J ]je0 a8aDyXI(C}!igUT3plň(LI;#QK tT٠G*՝$3h 4x@D5|VJ@=iՌ26ʌUai[u]ҫvLI ,=;!H-@L,-N⫩.TD Hl P=v9& n{`.1R?k_}L5{ vBvqUݘ_wÛo*fɏqK/s{?왵Qfj!b'x'O|[O&^ӟ45:i뙫OG\2WИ;B57 JfK߿Q#[ /[Kȹfª124O_WW{xjW.Ks{Kf}=SZJ$m Z!xJO!NZDT`xF}V0K_2Zhx0[ M/c@sq&ע:4| g7|+*)s)wUdW?bUՕOkUH@vW@s眭>]% }!pz*霍j0bDu=qY6BKr/!&<$2]Ec5 %8uGq*=\dnG0n,cAdwT/5* Ǚ$NB $ P(ICQ?AHjܨv a@$`ut#`U&kć UK}xcT2x*1csi>,/Iͦ#ds 6uc Fo9)$kM~/NGZ5+F8bhGM*W7yGau)$PD ]kƒ7uT&^2u%>՜?i-Qq>eߓhಱ5>94wfGWvf sG^â]=pw`#zj_Wqxx@3.TX R@@KL@.@ *Uejn5n ڳxv+f_P90nyPwl7pfWM7O->ZC86O|@dBK{kۣCH o*0}ʕ [)XoPQvv|>8UrAJWD{{k*Ѯx>Oh+\G8i*tL݈{ey aCC?C8<<h-I{Sj^2d 8@Ε<}ǫ2q xqGl7k 〃Kk< RI)$/yKh\jQ__ Õ91w̬*\@WдJotbv{#>y$fS*񟪠"$$ I~5p 5Mȼ? YXK8cn,3z8 /|"R`*giaKpP9#nPkxlv7c} .oTg p),)s@evˮUZy >")}갷Xrxmdy k1$2- 3g-KhLCQE?_j{BHU_2vȳ#bQ a8@|h,S7+$VL@IKYT<!Vqg){k|C=}N@H@0C&*FLKJLN3P'Y%5~6#o.mŀh QF b%]ZDV+XNPݩTy i J-r)їbg:B3{Och|i'.8D1')l΋m"MT7:5\pOF+zn8s9R<4nN߇ .`o˜3:/q@7<\-{ܛ/#>f , ?}kJ8 )a"v=D[Đ"! ۆ 9kp9ORۦWҞ*>0urYk2>^)so\h3S.L;ORsv;fQg1xKz FVK8`],5;cW=PIK JO Pko&{s.$!TADd ca+:d ZLƐh!$)8qJ'BXbX.1b;l6s(nmXC.^D8y]MDv?/$g,gxk:mM7B:*Eրg'lsƸZ"(ȱyS^ܯՊIT2+mhC9qy@@-tRP#\RB2Uo%$c|ڵ"하 "6NKe*a1ZD::׌>%ւAl?#MEA@,XƀC!,!,-9`,}VՌVWS(PXH]FXFgW+jU{B|T\9\4"E4YYĪmi!@eܜ}?GS)Sр6%FHFD IfԄ,iG``g\-yksI j ae2Ƽ3(sm~#$㽾Zp0NwHJ́/ ̴brl߁R M7ވv@Ɖu]xn@@%2p׽?/~)F?SO!B #@Q撟z΃Լ$Al7kP0]*H~cʼn'q̍H} sHPl`״B+^ 4PF)SOJNAA\f$4gjUW `Rz`}dkn YS~Pub薝7zt(E ם: bxHEL~S C)ձq.e:N '[% ,J^=8@7DZ\ǎJFA?D";o!0tv;@${e}M,hb&2XE\0H +r9Jtڳ5+h\AǀVRW-HAR'Bfrq""REo\-X# r&Be&,oenz4Д ȃ#vΫ5DjPͫE0@NA 5FOOey -Vfm7~#\bVC`8u }pI=~ a(H1H5}fϵo^`nDg>L\pI{ӟ6%8X7Xo6 "\txakvPƀ@"SE/Ç>>-hP1D4Q&hZhäj۶C~$CH(tE#h B ǃ9{U59gլZkswܽZjժU5k'6W~ [ N2Z;x)*&cP/\PoN( CċlUzSzs4`5kg"AU(͆FQn 45@]`j8L=8iy#)`E0H!}.9jZ`H{$&2.8"aݖSBaڳYbJ#2Kz*݄qANXƳ|(ut@Qfv!0sL:V3"qk^T!ɢe+ʩ 7Cy\` Ԥ5]+IN m~$ ?RU۶EYA?rm=9TdX:joziBcvLKqY9PvQaaXp "cr3V4h T5w2 e7kKjf! IqLyQNQV)6Y*/m3ۺDDis(sguc&]⍄}X5.vN٪-fN_Z uZ_VY9(w,+n^/&z`ʹK*+xnN~}8~ғ13\'=IxK_׿e}Zr0`9D`30o{ ~ނa1 PI&3GfS/8 HJrJM&Qͼr∙mZE;eRCQu߳lyf>"D!b7Mnj`0C܈ FB@@Gjy[\qγfG7~+Al n* IDAT (pATx`r:r{j!HPL@i]Ns1#Zj&ɦh *0 'QB19C@dr%1M1G+>8|0J܋*-E;-W2s{Z9/!ը&*Nz,!@dI>_oeIZ3MDԯ4R 4;E:j7@Ń2cF.lͱ݁+Ӽ*C6T&p׀&kuƯ3SI[f»;.[rd{EՋܥ˗ }C38;f6Wx^SYALƁq|wW7pR}C5${AfhT(17pa|K Eer\+OBW}3~-\.v*NNN0M8^rE9M1c 1()|@iׯ=1k0CR,[vך=p~=֤݁AGt?9)9WhHh E5%ߏ 8(BF7 _@z/@.n1WZG(e@%ya鯁F )КF&ޓ^1@4u1}cS0&̷9e0zk@nsv)FDENL!$ ~# G#i7K~ےhIbx; +4rj5Z ʿϨ f*<Y}XAr*P^PZX\"EBTYk‘GywA*#WυA۽E) w^(:F$C=A#Yxn4&vTˣ$mX%s;@H[;Zi];A&%_ q3[[WJD8#P8'G>ɑTO 1?3ge=kowT"+㲲; k6`g>'#?g;LmOM#, )00ƑqG`60 6nqߎWwIOywA H5sVaK(HA=?W'﹘>-gͥ!mK{5:9-_M3zaR`Uv=@qk"]yX@?PEȹ}o6wt0$1K>-TAY>d}7T(#SQ ,l"ݗnUSَr3HY3\&9gͥ1XPZKlpvvZ2ri| "v3Raip5̓nXWMXaVw87RXq~ix564:0d!6(W1 r@Cq`т*l.w :#8%S/'ܞVGp8 9U@/kט1Z n9i.j}B@Cln"v,1E= mVv][H4kU ^q^M*m4s!h5`np~tΞq7ǡ0 7ILc 6IeՐ B3Fl 0~Z`- js7)&3jh?j۝LEjy߾VE˴۱00 tjM;}~x;|5"}؇zogg[K|~/^k""F WN+'3pe<ng[Ӟltw=j7w6b9QM5O$D@XqAJ=)fEZ3#!w!W9[JۼD0sr$`T+r|r4K~X Q̊,<3#jN6/_ v)qYY|U߇OĆ719g@Aj{#$jiFzP2Dl 3h89?$#x >p8{CT}MˀE(#jGgDT=)O#B@r?! pnq'nJ-~((sSVRIVD Hk C\ӼihL}Z`mđsnں'^{d=Mޛq^͕Yˋ$vMJ?ĈY ): 5DI3Oھ0`w akVFXB[{+}ﮜ(Dyh9o,;B;wva/}XD+ 5ŌCg~߀{1PC->+_J! ،t  Ӟ2c7On (zr~-_"=n5PbשrbWq7p7>#zHw|Hv4 {F(E&L3'FQͷ.ztf'1 sn >Z3 ?7!wy灛4Th/)]}_w}Ϲu٬QàNX~vaUxd;@"Zς"$ROLHiVF՜Md*ɦ"CEWYY`Y8oTxttTlJ9gQ%, ,v3& ^[9רB;$Yewk9&h4 pa5̂gmJ^3"C@.`O y]n4Ӄ}C?x'>/em1ۿo|/!02QI4v\!})m_uK32s׮IKn*sWm`>ܸH3p|8>"}lF"=7~ ˿z_`< O >"Q L;cOG6*1bBvq([TyN8l M橌F}g$+w\0 8:>K4h@63+T,8"]Jr{&NKb(]L>0Nεug\Tp"ej\hc29Q k3͂RRB\"S f GQ+[%?0< $VwJz^CFꠟ!]h5!nqF3~opxvmnXMd@EUҶT\A+h\ѾIf_4ÀxqQ+=ed_0UG&`ց(k#nO+7 @9NeG^UsHI #0Bu1Kܬ**8-f4Kxa  2 FbƜ2j; 8eQ9%2xx1~m_20&n/—|#1J*S-0jZ3bxk~j9Hbw l\pkWKƻ3щUМrt}7j waEMv^sCH"ҢZ.f;} ~ ,u3|4.!7Xޓ }gP׿MͲ}[-iK=Y͇lICnj?pQ/t'A γތ"9::SQP@Hy.4xQ"qKEfQմTyLN 3h@q& #(tH}`&mb{pMwG#d fup1,v@CFPR/u <|~輮*=>0|폚 @VV?&FP"QH:#: (/UkfUŖ^O̲2[Sy)%' uSФܨߤH$buWH!}*LV Lp"[o_H$aEa}ȸt-a Tz1J-feB18e_;V]} sίlWp2s'ۛ6Ԧ:)Jx7=&e/ xGn/~C4 9gcd|+'$lqDq/s kLKwwv]\T3/4"7n.>ai{6~8J-;,mq|] ڼrpCut6~$V@jBkˇ75YHL3,4TNC9 69RIy#lU(K&r@TB '´39'L\#bj0O%$"̳r10&M'<@DӤhy%`=Д48`7IbWdHN Qr y$4 9C+O'ө "%nwV*2б #2x8S-h$Y$pځJr.P̳D f%⍲[]cr{)ʼn<U#M1Z Kh4)Eq>:AJpRJ`, [ Q PȊchEOjZ66c0)\exkޑjWMa?9+1:X2:kږjUHO$ؽ$E¶3#DPU@MCek7|gQ6GML)1Y@jfn%sLPvgld11=IB2ujHD#0LSo}~q?3/[ ¥M$3+f|7|~{~^\6p>ݏ+G=U< O  gm}gi}/a^@ ؃ 0 {0Me\;&Պlw@#~~ 'BFD΄9e$Hs*bfVHOF t foKA]B5{zڅ~̀&W:QE.r+s4 'x@*n`wioh< (9DT!RjL|Ш,Pɞ"$Nޠ]ypMGWXTl\4/MIDJ N.a3~cZT5QfU|lt%}9P4D,y:iF@KҌۭۜi:sSprr,{X'}fJTͼck^B"/Q5(*fe %-1\I=}4(f. QT(TQk^Rp}?^%#郀#[@BGdSGClj$SA̲z(}J e&׷ؐ])*9sɥ8bz} ,zնar,+Dh/+c1s'u?Lk)qke-Cxዾg  ?)я߈Ϻ|<}>,ˀ_#p | *ӈɓ' X =(1鲁bx?;-ƔFȏ ~" ,y.֔9 {Տ~o-?wt =јmj[H߃xXW+"LQw4?}mY[JsSh7<] pz IDATzκ, 1!aa1iEt YH3m}STL2qetzmLT۴* Y%Y.ZyN 8P::N.qeJ8t `yI)!goY#f1%/fj!Z9H)!A@YHĈ27obs$ׯ]/Hp=2'x3*6LE:[ <ywp|vBA[a,[^3:8Ar{}D>kW5hXV 1̹9qAroQ!z51sUL '̽jK:4hiwl&TpmxQzfni/<3%esMhm@Tkƺ~Dbe Ʋ(s5´b2WZ?W:ƽn^ m'qg(^Fvy]Pjfm+l*_B۞os_YkV~]\r'J\3~]'9?Z3X%wN]Ǿs|};G'_:uZ5\@l;+r;{AeY1J[-:tk|:&psp"AHj5 VH5˒o~qG>r>Ov͛N /E|es]3LNusZiuҵ~G.]@Oup+sFfԐDTLUBQ |҂yHH@,y%|G<`97"b3 Q"Y]s*`bSq']Rx_?C#5c-H`|lvocn) 4LlT ь=YqNJ\ks\!!dNn}׿͛Sî3x$v'0<녇,2&Ĵ3^W7y||MfCwa ]Eu^n]Pˤ^a|EuS-cN؞ $4n% J\&\Iomp/{g9eL;q^4-k^<{J"ZwJJ**}f p, h<,5"LU9ųJUw.u}A"G@r*E)A$e8bΩ %'#yӴۉf zw18DOCuN$H0ȞI0|#Cd$cprr~:ZlQqҀ:P̵ \!I?_N+8# GǗ/k  &tUM8MC4%;OMTXѬO=8HqȰDyV>q| GoR>"ȚvW~w,\ytc^'H,3@6($ňv B0+}Y_d~:gy\IPcUIUy YnZ;I^^Z9|;< NK)߲{ns_q_B%>| }&|_{Lf-h\im xĎ1*haH-%QI?K~.}ukw0dNs sƻ׽nen +k4Ҏ,iӏ~vvmT7듛+Z@yww *_҄m_3JpU."j:ҐqMf΃ !9#IFE X0'jD[tu*˜$ylOa@){OJeh|%+ctY Ȥ$R AEY |IQ!Flƍ\Q40I"SEox*@$ }I#sVӜfq!ۍ71 "L(yV-R.[`-A]o޼ 6HrcQ!כO0)Br GQzA loh}XywSd,/* hnYSTydHYJkM(ʲ>ufdKt K5B%f4$#E3,CxvBb Lӄn.- è9}\#; R" 7ZBege2a05xoշ)b{y*0Y)astB[VʍQXqQ'457g Q |J{( I̬+e))lN.amͽCBXkj?)G'q{O;iDݠ$~)%_/z1%N,N*C8 TӦZ>cc4h`ɖ][&&j4켕5Pbb,wu*LcC |_Sp?|f=p}Q&x>͑&u !sy0X 6̀Ѱ@{" dNN@$ ^cg 4w]4qn;i[0 %ɠ> Z1g4 8@|G#PΘv[1gF PT^B-R2!""b8ypBCN(h˸k.yˑ$4 À.o$ G$rM}};{J IL N+BG1,Y`ZQ2013+2$o8OSITm'u@\[M~Cwap9B(*Yl/kP,DrB&Bc Dm^k(6=y=AՍ=deMBzYƈU0R77rlvY-]kB_F3/;ubVUufқm)%x]M`1MFrsYps͋Z2El4T-Y)1MEAtFAR4$ϒgq}|<1 = ߾kU68ܮO>P_:_^޹7Wm5&z9R?R3Y$cRCBN0mMuGV UZ@4m%5.@%9/$cީev;1UU(2,4oYyprtY͸raȍ}3W(@af ;8@ oܸNNNp>fCݘx_{DUjR`CqI@f1"#2$I+( !OgUhQ:;h@˜Q#t}}3!zj6פx[/D Cyl@FMhiB&(U;"/ԟňg2QЙXOAn+0\ԬPiI.}m>3{%̠k1+>)cZ.qb#"3OA2Vj9,#QZ-=#HJJϺN[h(͕=-Q%_$UGk _4Ͳe=m=?KcF̷Pxn㇋[iϨBmb#)TFk;>5۷0l6Fcm.L#eab R5Dy1=Q\aMV$S2( zI!Ȩ`/yu0spDhcI W-YeX P8gi|3_8 n\O 5z eI|@?~OreENo@Dx "LbVƑkj[ E!Q|?rbAiRpA xw4Vωu6] r[H3@++ G$XqR7˩8`C8vE*3'q_i Y$74SeZEa>1 >7ivK: mʰczٌe.ZP-bE%_{Ѥ@-xܤ9ZT`Ķ|H#c6>k!Aen50de-cV|0GޣaD.)kKB5瞩#V*v|1؅TTd: 1 r: a,S6N Q E4QOq uJC?u'(nѺxv현&օ:%8%z)~ gV0EAќdߟc ٍqw3<@S.&길ft?ۆxqhMtw KIGGu6זf0]őE'5,Y4:rV%LB *]2@ Y$J0HЇy^9g<#A"iDdg0AE"Y\-nڌ#vY̵-oiYAD0 L@0}G73˔8  K}({USb<ҁfS6F\:A۳x: pbaـ"(`0# MHeyߖ&:P|4+N-TE7M=^}5Mh&_l亪[z;W{ $~1j5}!V3dG&+B=)<{$*qNUvOv&\2sEUњ(d4(EH"4zg DѴ$ b _Dj8Kϳ/8Rio~pMIj;\zش֎ؤ wDǪL^} egm4yE={Z׆9t~lX}, ?< w*'4Dunъ?O9"ƥ^'ڐ}{0Bp H艌}+~ $ x3Twn_qџ"*5bg x||.fp߮/{.h5h!`YaԲ>7D5&^5v h[\[;Ehf9 wlNB˱l+d}Hc[ +{Z̜ɯ< eZ`mQ q`CsDy'hI301)24^B;+on&p\\0zmKB+ӝyn4G` "ɶ Y3PU.UdOT~ӽV}̦'Vw5B_aO?8.;5F(>FObh_\wK.ټWL`p7ʄ ľsb3!yQk>X.W-IPƸu ڐbF X/^<#ї?SU>dHYӌڟͣxֳ,2r߰4ˣƻ!m]_{hu>`CdI)Kk.&xp.S}DNU.j´ Ayj!@ ܉Erj>*2RBS#kεbф$_S$T(go%u=^,S|?U;Fp$8k ' M 4#p톍#@K^ q&XnC tz3^Rөyޱ ˞ny1WM\.p$]hIB,dԵUBNLqS3օ\@h)S".T `;Щ[S' kH qz2u"+c9O9YoFͩztWPMPxqJ,<( ԍ'ƄE3Zږ{UÃ{$T`6$\5Oi 7(0O ?Sy5n3Գ͐/WL_{mJ(ӃOo '1hDL(4iYHf6 x P80msk*0y{znp8! GH7?2+HEqhWڞ)\ύv@1נ/DCR@i֥mNO} Lh@J*SD5&/2fS3x 2(08oM](9Y&K> Fa͒$)fi}-bl5wGPl>YL_^k%tW%sgh6q9nG$H(`au8bRW*n+ON]k,Z=}b~\jkw-a}R:&kWB{Lu%/r*mȩ 4"/ƫ r*$0Gwfyi"C jT!>Ju:n~wuX(da32$^f۟)W^Kϥn}jsMk>l IDATvr&X]Sb+{u/qc}-}r2,\qscWHx|tT\\!d`ߨ!@PqԖmWX;AJ dH󌨾6\-{& o{EKGe$ƱXY?ѽQ̓ ង AB+4R2*4G|?RqdOO\#dw |2a=< TG7XA9i4) 3O5p2g æLӌmo݌#nn.]; q,!-#4O3QsRv] MʫVz'I/s k[A 50]9[+<Uks~P *,+W% v$dkVebcQ $x>AͣcN98U J\bN3SHa'zX$aU+0D2ɒQ%*)c3€icd|B&x[taՖrE!`.=PL-y6kI[BST T@Y B4O%Ms29^Eݬoy{-^nv)^[$wXZ>d|&_=)[ˏ zjɇbLt}r{`rr4}!ٽ" ng}d,/3 1Dar/wa%V [z׏,>RbWip挔9MO3|O>>[;cMo¬ ck&`?쎭vvY_\%kw r1YTsqcBb .̢@aT dh0`FV#S+ڞP#OҜT!G| cP! O#y:i=}4!$Q!sc'|( na%Wnё0xq#?ia81Y\!N6!hO"08l 5J԰ F, n?Dα\}ۄ$x{JoĄGD垒˖h M~B#E-ԍk[+ p&_pol}jPF(y.T0DV0G8ERy%Ơ{FuqoFp`hAפ;f TկP1[߈}>K,q " 1yZ*aFuY ΐ<\ oǥ޳ni;]qrLl}Z9Yz;֎=9LEϕ~^~eƸ;r7Ypq=[>_9d}" FpPSJ:8gQz_ry 0!+f^2X)g ̉gFcfaS2_._Ń7ڀ}<SQѢ:<]:k?.)W_34]L.h2&'R(X? kd9Ө+,xLHwENjFԂA R}*b޶h ^D481!б4SO 6JRUJDot8qKN1ƞ%gFVFoY]ObZE$gVZᅦ90V {`qo`cZC_O电M)G\IxA=,k, +|' B~Al8pB1j94,l$a,3?FVo0! mϛ= ?D#6VejQ/ieuM65Z"ҏ!V3V %m"f嶳Ŧ'b0II8n0  8vd8lqۻIDgc z`jˇ3}"N K_7@@1VT}{mj_:k%+4+Es${4"7xS9SFZmVƬ OB3osX9uP;Zc`?8y[~*seUS %FN4KݜV$sF&%!р[w?P 4|Mq&<ћgv1L^'TK"k iN^ѴtF6JVϤsY.ߒk CК09@g wyٻm+{e$оrڇ㗿X|?YMjKi59d6_J PZ Wnf8=;+QDq,BB7 A; ,Ny!B6l`eZVARJyv)&u7LjFJdB(}4#ōa=(jg| sRBߍbE˂ 1iPPyOd۸H>"Qƾ"yJ԰f%(ttwsImEc^4pڅUdrʕJ[-P( ;5H.abfE?sj#?sڼ~#))Rx5DnA $̷ƀ]J8 >dF2!U^ǡVSmɒz8xsuzyU,j[]`1#͕cfu\Rcz<$w߇_{M|$N&j:8:.VK?Ek _r\~vVYV>g8@@kTȉ1ό91gvdHi2#^;9Xr.F+ۄӎ胙s07)CEuUDI-HbJ0( !"X%_,{sa!>)'}$` kk!1u- YQᤀO<+sԲjL5r jyƸ!V}YoY<=7Eحu=Acryr .qHS) F9]'m,'ۦI-l R«$ʀ+HyԻên2I3g@Ђ$w56 4 9c+ty%jbjJt"]+m6=wX-68\-7WVU\3&LTt3hrx~s;wHsB ~M3TC$y0<SB)WI 0QS;ywX[A .q=^jbLP1 m\?vXVlvO7Z?z~gϯ[otz 4{ANLXs*E%}U<SdƁE I{3k߻vHp 3 a"va}eGWmHTYK@<L[1<iʘSSŀqȈGǾc `bV,9g߳2$zLzQdKyK֏9ݹ+֦۾kϸwĭR*-jڱkŴl20:gP$%sSs@D\rI3ߒX|4f b,%0}hf1fM^8g5JEA+xg]ߚ5vm`}O%OA6w$+XkZlg^ isTv0EiՒH8 dMR@~@K'[ fmkI+rKšsΙI@F 5S~'l;> Rd [ZO" gEyk\ 81nQrFL1w& }bB}vtw~Z:U[Ƌ|H! վ]̹RZS "'< .jF:Nɒ))2.VG \cDV>ZGD:h;#nHFgfw{5.]Df Kd b䞞1YPsӨvr c]LK;%e-b"^5 TM[b)*]fX{?=~^!(E- )!/fmC\WaQ![zϚ->Rk+ɄNٟޤ/ DžH cUyr޹n* l0J6=<#QCLyDzzu"['U٫ ak`KDfvb(/2DOA*G|T wH mmG1KȌjY 3bwnX@ȼ6/L< L'`{p`a.824.a(k`@"B /R"~-.r ,`~=s0w.wlshk!iѵ ɟskxpa[) jp5i|[؂rER0 5ccMKTkh&`[0P kp49cYTAJ*mƓH |.!GIe,NX8Tai(HY`r^2ZI/h{ֲ,w;w8IYAZA݈wQ,? EBQ뚤ЭE_D@c7N1u30 ~P t8/_hYH3 dIthRTZB@`2yH@eV^L>0Y0X̶M>qg}@ f!3,#H 4ψC/jSR⩳q׭*E1IF'$py!L|;yAd⠚ C璫1)Ek|@ݓj5"X2pؼ@kZ?Y!DL?k )9r$[ڲ$  1t[4$k YZ-_E~*9~EfDBH NU/=Z\h߹:Bۜ2ٵU}JPgoҮNZ;s3a*˗}OIQ-> FŴ.&F)5!sM&"(`g)դИԅn{ۼםc5w @Z5sjR2̄dXxx =wa Ę 03()gh έo)~4xSJ7?3jq.6xc͟}.(ټMF+/0`btx'IoژASJꖭ޻)CܞښW&kp`U@H;135 ۭ'F! HIvz`!qVYME$ŀyY0OXfQY+/dzv8=BnIL10# L'Q2R(E1̠PxE ˈP"ԁ#@V(1VP8csȴI\52 s@AK_w UObHFCWeY!6+ +9hέ- e\ɟ^yay}fnPgs>,@I#677J.@[5! k&{F[[-טVM!r &5{f32`d1lJ0m;VXzaqacVdEg`_G83 5L f\5̌h_$DI ()( W_}u4ФyƤzr=`+Պ=gpG6?\7Ⱦݾlm&ۖ=Wr6ya7rOf׾p$נq,y'֑049 !K$|ޖ@ 130RYYC>ͶrZ>[ :M DTw,%Y τ?0'eMa!\^2@÷}@Uky"fM9Ob 4>l>HǢqFnXa2 ߕgUOon?B'T)D|Qͽ,rBk w7ĠJ*n"yNMsr^TH,oPo6bU@4\<5 TWaB4O䌨rC.~I2}Mӄot:9 $Yh'm=6)ع8ei Eݳ"PxK/]*Jı͘EWϝ7 B4вRo΋3(-cqRWU2iJeW(soX 𺴙V߻QuX jbju(ƄPA Y,ǢVT\E˒; ")&!-`- GB 4HͿMs :@]3۔WOR IDATuA*q ov ׯ}yX7]A[}GhĶ?q]OCȨջqtn8SV,Սص XpiP?& L RFF j2aP?Z0̏i"b gð}~u8\4<ƀ}$W Upy >n n7'.I $VkD,1 i~沺]k0O^t:Zh^[Djܚ&>t8M Ԭ"P®uOqP:o(G DL @Ĺq1\&֔ HKShi'yW%]r Z@C8c-j(uPq赻,k%3dPU,Y޺̘祳&-˂ipcz~]P1MY4KX Z7d-]k@"()Xt撱L%ot[\/q{׻IPf)hJÕE#(ߓ/YS|[(hAB9S,4\\yd= Ol?:" uE-&7/(zk5sZ 8V[K`#$44A/u\Ks$(16۴2J:A׈Y{ikVtpE,:bAҀtZTcI-$Xzu*,)$TXc@êB{Exvf^'z2S;OcvuOOj?;zs'i1nڒ ,jw(J%K⢦4L*fvb F4J?8kY8c|"j1:v.ymvw.Oa6kPJe麯t2'=0n >>ca#4CCT.Ԓf| dx(]hc`ş[qE'_+ek 6w}F2ipr>4E6^qrs}&Imf{*U$Buhw>z@"M2@D2Q=nn6MWVj:i@)K.};O /R-#:|+3JXHج14禐Ū*WT1DGnMll?,PJ DH)pR ,xgsU9yKPDޝ`q"^ 5KT.\c](%]/i==E,2V"]%\ԂAjJX\ hȡZxQA\3"@5>pȤ]nmIJHƴ ܈B.DAe-J&gw xKVmԝFWLv3# wLscǭgS]m>Bg_O2 )'SBO/`oXu՟̌),k<3B.@)8y HYF;#9A,$Uk6VfZd% @zwX4oKHˎ8yNGñn w7w7Ƿ0hڡHEp)osnNklZho7?>!*AǥK[C=@Uplhc2d8~%ƫ%4HݝqkL-,>L6Na5C"$#w\{"1U T(VlkRn2FdT $iUEH(*nlRd"siLI2(w;c+LA+j@.w1 l|`u'5ep{:hdMhcCZ.J8kIQu=, zbڄJg+\Լ1sͨ|%}*U/Cxk{H1yDυo>=?Tה3^&R5zÈe.'GF 1#2H b!q#Lvv Bg$ݴLa jCL#OkDa*s6 o[ 51,S,)P'a{xsx [F΄#&sOqe Oul~ t} B"MPd׃ú  Og?9HR/T t%GL;Wi+'LRpU³]mY+!upED{oDo3:NC\=\e X Zb%g>%14=x絑=SFRr@XcW@`+"Ŕ'繦[ Dh<<?M8ok%oVִ{CM&0Uح^QG%¬_4\Xv B()y1\S(s-% wΥZb XPL^r'5bg}^)LÊ ^&e;MI꠰̬Vbu)F )!R@Y292 E 1ۆaPQ501DdrR sRJI)|, LJ̳/x-Iu"kgza|N;q2+28O J8,uø'$D-ѓeMsm|M 8$|Tfnpxkn V`K T]? b]g@`Y |↥clJxP Y-jCSgE5vjޛFо ϨtPVU$ \stսy5 M/ TXePAb,oi1Ζ:bl͐}-fW-Vw71|YV7$:"D]!Y hX}>4Na 6AmꀜI{r'"qR7ks H4[>>j׺K:cxM+Xc~ϣ#혷}ST׬t{->` % sƎ x,$g̠a d֑0<'$qbuע8HJ>$SSXHE ~BjfJI,"fqnXDAДA3v*R (O.vT\Bi>9iU ME؏_Pl0- J%ey!Q Bѵb@VdիWD"1&Pr.E=BsfRpV}#kO3c7W80hjLKk pE ɫHNF<}@|>mey9VkD!֘@iD^KUgz}DF`qeJ;%.~vTHu*Fs:#g$o8gDj٣Dn_ S =nhȴUsηgOu-`{woY,1(5˕DžaTi͋#qeX3Xy_1Nj3;`'֨ jjbmZ#ڰ#@: \&ezW1/d3Q΃ߟ%>x+1ijyT1q'_緾CW¸>)gB W/p`e`',F\ia2뇹eEu .&Y,"堟濭hN0M@Mc+}:7-FgŹbKHxzfB<1L&~?7wwG-[<(U H"!)DRUJqH!!^ᗿqڴ\%^vz@΀S':{//'436.fkhUi6Ȗ#ߍ{9dSzvD} ,`tb,3T/ȅp i"eDP8 (I@I/ܳ( AԿ8=+0e2E X=G7u;r%E\H1%$g`Ɍ|O$7?f|t'/FiA X(b aH)"!GgwMkm@dB7&Ԙdز.w~Go} _Wcl[_iuNry~vgsn>:͝ʝXƧ 5Ӂ o.$F4:ŝ" ]: wAD(`) סZ;r;V]BM!j(f^ @=/0L3!iGqkƟ|8;{ fG 0!``Q ƂbHÀwkEă!}_ӹ5sKqk׶=G?e]ZDwskmXnD/:85*VbCU5FHc gҠ1FK)bRCpAj,mQ޺]/L%eQTX.244$qI2y@gJb9K>rk0#!`Gqw`g,K-y8"Ґp80Op.Z?x)Y$#ِk=;Xڻf%`VI)wօRP7}>9njJY. L z|@TW/0^bB^f0K4 G8 Țqn~i`om e(LHv^  YA` G۹#XzLg.kcRW0+3K޴br`T!ˡ-f]x5=0Ө備z}Z #uu=Ѐg̨L1]ž] V l]+)_=ɾaĜ /ZA8Ҳh jz}RXQSp!D:7z7v$L[:ϨIk=WX?78+/ҳu]:iCxtʪ-|f G3_-SrYfJFRʐ25$E0ku( BLZY|%/2:itn))XZC߳@_/,>k<3aVp7 >6p/\ A}A&bD A#)! qLq@%4]7DXYmY> |[I;c_nE1|Hf ;s/S9cknфiQKӥ;Z#a3 rVk 1Z5s`QA() _s٪Robp+kMEA.N[zƬA1aPkMj fTMúh'k!UF|]$̅ɶNYT:0ޭ l]+D|.ioo h%Vs1z@\Vъ)57*sohEώbOmh=s/ZޡHSV@EޭZIٝUm+ vwC]|o)kpRmYulyyN 9ngw+½V_ ֿz{o/`zE.3Z=@ʌ8If9F?@fgFsY@XdƇ-Wggː0: ./g2>^~um}n _" PAPw͐p5o>&^ OJ~[, |yKʹ+$w;IQ<gZ+ οD.Y)!1&Tγ('s'n./A\,(9^E2I?s}"`q7hddg mHw{F;$S\f . by!HFH13kp5C Xjڬɻz98?WujLwpct;ϛз/)m`!\moۏO/?7?du8! V^ . @(2xX q (TKhx D03SPshJֱtH @X J$Eܯ$+XFrpy(kGĚE." j& (aLÈa?n t> u1@e%+j s_oo t\SuAOj"5wmycVSLUzb8lZ`*L TpOxCeެYDI,Xa|D2?&Cq<Ƅ;XRf&ı _ݥ!Xi@@Iؔjmf{7"B (Z #d,QTA noo*\]q82bXJIIҘ&ˈ|SN̮Nh Mega6j)LW55vv˓ؖ3$}cc6ZBץӷ߷Ml9~_|Kb,<on PfF8X7:s#X!\RHB_@ D0 :R Nj܇]obY&,"ʐ< ("ҧp: xxno~̸9dL`BpCJE!DŽ"8"n{xlňA+׬j$&H9FH"ǔ@UbD.X 'n@:~ 0h\,#Aw*8j*Ya(ew€鄘Iī  PJ‰E &>QSR0I!Q'v0 4G.P* #2TŸ),;VirU l(;0]OE uI2t1 qLu>sŀH*Y *(L t`D=T|R$&*veيP".X&h@pچ RfKU+fG$aL@/]D-rvѯrF=C{TԵ8Y[۸Dܿ灎1A2nd)Dj4~8&2QO1QA•r6 D̎aFX( JP^.G@o7}aZ,`NԻAy ڍaK1MhL1﷢qkJPZ/ǐ{ ޛ ȼ#fp&1x /3Py'`% JJ´(@ ET6ԛ[5:! Z.2 BW TK-#p$d+,WOi 7=׌O)%iS = 5G1Q}!&ИWß߼»&hl d F֖y4@a*im~?z?WS~u"O8HOھk>^~w&0ջ0uXH Im;bX¾uS)OASXhn7 U&0zl.\˗eHMJтKPB H)?ŏ_ZG.YO`.Ol D|XU6o[Ndu kˆPCך\P`lOV]lM9UC=#KD}H @,dJР^EJؽh0 rËߕ`yƲdvY2E `֬97pH)DT],Ub c4sj ִRR0/fD]\:@"L$ǖCLxջ Wn9'7$ U/IS M? ]kEH[PJ H1Z{r{WSH%[1%[&UgMJ9&O[>" ݸBT 1Fui]C6kkNjiK[0`lDVJܯb(Ʊ0վt~ 1lr{p'`< \yV*Fksj2Us+pK`!P; Ixͽӓ̓M5I_]ltAk}O1 r82"Rd[# Ɣ H0(Fff x :؄¨YF\hdkSEj XƬeB5(X|'01G;ƇjHt@&1 ibXvA d QbB( Àz8b 2#/?<ϰ\r8V2mi z՞--_V; `]H*,t ڕ鞊^O>ұK emk@ ]8uT)r+> r՞2z<IK:-)5~ o ;S\#Mbe`u;Mb,B)H3x52]s.[ʱ)œVpth4*Y2Pf, #Ţl5Ɉ1&ibuIj>|Mz]zFgڄ3@pw/ = z݌X) K(YBD-\J0 5(4X1D0[EIXߣ⛻,>c>@E0&dzK͚jk=X{oq/ +Smd:Žsf-O|&Z}ת}QmŇ\_>"B$`L8qO00!i :t$~ɳS딪w_@ 2-5/P2sA!̳tfpo'qzod ABK\I! 3b! ɦaΫ߽WK+>kņ]jIhCG7揹Ϭ"v}Zͻ^~__OO&xjI?e{2_p~ud9L½_::繣s=iMa8FMG UpYaP[UM)eVNd>WY]j\5ͽef2g kײD$Y9)K %皉KdV7.I) 1`h

    ψ!AӀPݒ"$´X+2$ò"q$`=,FV[G,&̲q4g`Q .sM4#VX;_!J…;{ͻ.[iDTbٲzBUai5׌t{4&ޟaT,!FNGljZ͖[KUX 0 -EA'sW̰RXv iU+1׶6Nm*gfk[ꠍ۽WOOOy<@^Y= BH[CM;˿+0"r |?x/wN$X=B`8( ys\ `7!$`*F-Gs)jVPmYH.)y2a9KGp#A' c!` @Xy) A .P+YQ × o~ #0ꪳ\]]t *b dǪe'=+<}mcӔO>;Gws?ݺޢ[ 6ϵ;j]>:Yu1Aʰ`.}͊QqƼ+H=ew ۓIh`m*֨  ps!#(Ym39%X `:4)d/(X'!*2>{gFq:Mf2HUsHIi)T]N$KAb_Y=Slc;Yd08"ĀyD)df˛-yQ Bq~wPJ,%)VpV wUXx/,X>\@Yě(" ХHYCez@}w> RMLmYQ VpSwZ,O2ê !Qm¬YZJvb''E%hV$1fn.SFP*8Pc8yҀP J؂JEK)4L۷b¦vOa篷4id)Ta&ft0 -KT}[ @RT\ED@WWHu$p{Ffm p x1?H~N\XǠ^! WE#% L"녍~¼NiG^ gnm%7Ȁ9wr=ZTX8+S6Fc,5PI 7yԔ]E a25ޔե ). VF (X!, 3,l D*-FQC5 ̂RR!ʤY#|Yf(dJÀyYjd"(% H`LVyGd3Ξ/˄qq{p-C ?REz%" xìZ%f *eBD^8f T $QjZhUf}%.|A~n=  !yWeAeGRܷdtBPL8'm&`WnEbVIj^;i ep؃_;p83bJhQ#j(!! cpq,@[`C$^ &H"%dHAD$IZI!wwZjU጑ۻ/UkߺNy~a֪cUU/2bM8v2 " DL'UlSY+%^8+Ĕvh]L2S ̴R:bnxM63?,eКJ7ڹWt\dnX_#0ǘ~7[,}{us̼1ƸfsT O^E=ۭw7'wPn'Cg`Ek?ߛ 00 #@%FCkI -p3 b l7@iC HeY>;PBf!9+9 I1nK,M  >FXYB ϙEYs7O>L h2mGl^ٌ%h l6GLӄfSB(@$zpl;eA"Y˿Y[zVVը[wsɓ\)\Nn`@= oF@QYR 5jбVj]GƋyq\@%xL'?E;ʬobEQHEFڢEZ%|srał΋Kc۫#E[ԿK+(p#rZat4=_>EȌZ˺R0z.) xT,-Zi53/Ԧ\ӚB4 Sֆwkg-,׶5EmH vO߯tW>]Bɿs%p^ BΪdDjd<1 Yk^ҏuCh2fxi;Omw&;cgc~+_v~o>ρ|Po)O3n@m GX2af @S~ʱU2Qi1; Qh~;2K60cnCEyHyC4u~圴'V5D R )CQu= ziz7Xxf Y˒YKvBʦp$|L1EL89eYfh ?d ݸqͦV,1CR%[ˈ!DǯbOXxUo6 ׯ_C?oؠhʘ!,W`POEeD$`"C¼m2Kf.SB+ w1"V<:Y]~QW\`/Fkj[VQ7׬2nYӋ-@/57"mz,@nC&etݒBhRM6pY.vKPm'ϺZ2l1jz V$I͎ -0# }YQy yeh nL2n fz5{v$FK9P+–ZٷؙQl9qZEøˆ2)?} cp5rϸv=s H_ĈZʑ%>v7cI³ˇ!9Q V 1eTa\ϲ+%|@YXA &(hx8 #G"inQf X s d&\\\mo{/)"9)\AVsIO\>#=pRD#MS>;ߓwF.$75iŇU,dQ;3!SZ+WL !`%Jt&U̻H%ŭ28jalc V< fbfXؔ T4֝{,DR6i@)jݼvW/ܐYLEY *Wa/qXr.M^P@fQ`#uJ>Pmսt0Zrsj3mwg7(^. `hLsyyNc< `X3 ޻:BQR:0IŴk[JmEy'L)CtZcYjiMZ@`,}Y!B~ЌZ 1'mVV̯\h[0>Hp1!󋵘 mx_#W FS*`OOԬqo~ W/a9 tXߣ 3;G s?߬>P?eOaYHSfYZFTL`l cn$=B5kl-b.a~( fjԗ ,2!U`*28Yb XRbrC`aİ5g 5 cA+@ӟS0. b1T_,#[Mߏ駿O>w!'('qHK֎uG}=ڦuz?]\{b@Y!3@_ۄ+ 6WTBI(K"iޱ(و$U}.2 xPq@yLfղ/AIocDN&+;FRG$CcdeY0 W3oa?aɻbb! `Q;$T nKi ȇe.T hk⠻Xn}Wn{u)H[clh@1c5\qAor((6uD:kOkS o,N@}*>l8 TY/l!0BTz]k!$3 msndG.I\]esj9ei{ior@3<"nw)eIe Ttn9,MLtH%ǴyYuWԋu5 Աt#[~re.1f4p0zvPZR7:@6u>=-NTf:.y䑒9݃|q`asRUKt3Wt#``, BYipXZ9~ 2fAN-Guz9KWLy7՝‹_ok~}iںq晭VSۈPG>JbT-Rf4 š EM!PB,qelXxJ-rbbAcZ䖌EV<,9FIջUHTR》K~ iYJ3>7Nfk7qyy)mEѡ}f-ZviYŕY;dmjaSy6f $ qĵkt2KJJyXKuM NX}onNAR9ג1Tq:߉" mtٗ\QAkJ^Vv)ZGq\%.DKZ,T6!:T R'$h&4m8ˊg޺uۢSZ|6l8v.#a@wG)c݈[d`n`6RSB Q#X}N|nhapcC4CƎSfޢ{~TaPH}*gAna$ qY__xZmEӯVۣ1ۡ/'@iK#GLJA,3 g HK&?YG5fn.I )3"L-K3*H`ab! Vq@3ES+y%~N?jBls7w`c0p9Zhr!s<66Rw=2Oe4c^6"s}Yu[\,`̕\2f)`YnE~Wm$oRY{x=L1I1gK)a׺\RKzNZf&PCAB Ƭ`,D4RG %QZ_0- H #h{hb(u/JwF Ƴ2Kd^/)a4[TqwT8z8j)0`al`u AyvYZf3,rNbMcf )>iaѠsBI B R]3vA>$iSZ]qj X )PnJy^ Ud'ZCŴ76;e:ˤ0n%|GDH3d| yNjYQ*%#{Ȳl1pEoH^ZDY6K )*:sF@FNȇ \I+m3Wi16J:8y'cq1ʈB9,1䀙9( R(Y5Rݮi,Yʇ(UNC Y8I*ਕw0Ӳ@xT46\c<4]{@3jnFʻ"Xc^gfHk۴,쮓>CLFXܫ0its<*!h tծ2ZGIɵr-PB}4D1kw^uw۩3;=w}ӳE):ل|AݺgMo{t c>CO^Hp1*NJ#,YW0\Tf8m]^@g| tCm0w! f~=:1?lAG@Y1FkF33=}%P9wg 翀oxk^;嚆©=VmŴSf[j]JKJ{ (M]אQ\RMTǗxA;FMzy_d炥 ʳe>EK߉k\yť*`YfjT@ÔdjsPH⻒fZ+oZ|8Juqnjɐv۫5 Rkneꀴq!憅cY@6^2i{$32 j hK&"Qآ0^}4צb5#$E@= .AdV"-u g0+QNg%0fP2Fɳm]Cd>%xEqܷq@V-TAV:Lr~ptً r6[mt0ǝ֌k9ݵ;1o~~Qľ$裏j_MgjlpOK<.<'Hf 8 Va"@|9dvSHNgp B#(dR7ap^­Mߤj҃FzK ުb4o]:J&nn,R>yu-3j\|XBߗsƿ_OS&N/ۯJ; 2?+lȸ*%]йiױfry5j[w.b ;Vݵ &+垁B)2hEs3Ydy@bL-P;MJ$5/P ykL-##S:ӒRDRi<ݮ%%lVX挔lYD)gn .SXH:DY67@%,Nj*𗂅j5#i @*' nn($@|;) QO6-DdwCKE=0wisRZA-P3iQ;ǨcAB"}-%XrĬr."SD9ǛF4K 0 %)-Ub ZHX"l7jI'ٯ"x۔ڃdա72HdF |(`À0(ZcXkŔ#&ЌänX>/5Rs5 ij|< !ࡇƒ>~,Y A`,"Sbz,ƽŬq~;GO}_/} d 2Kŭފ+(%>@ԭ>㑡>NGkXMy+񱥨P  v:ՂND%UQ7:vAd}S*hC9ְޓsⰫYIFղ_Yu\v]5I4`&?t-޼iPejlZ,S*X6v;PNDX,:xqXf)rHJ%61M{yl74D*/ LfיB#@JcB}8V݋1 ^ /ݏp~S 3?tP2dQAC:~;^, a(r\ꈸ*H$1 wx{u-"A!M@ @82G/d @J} N*1E)9bj]Zb`pgWJ쪶_rsWSNh] 4un'UyBy ЏzﴈJT˒TB@tLu.i j+C1`iVװ#@k벻5w" ϰͿH(mNk0 25|;30)/`- 9eyG!%9E+v'8Wg|O|Q wt8p"XUP@K{9Z)IAI(wbAc@1lF19|G+۫e)|{P9-o>;>g 2F^0SV DTK.̫+Z-#B"kބ\H CY=* b >r^яMk))K 7MDԀv^ e9'A'fQS2\X,-)KN}3K3%լ$6X$4iDt@Ŵ/_vJ-~'u SܜVUkiNe9x᰷ص\E-x~K.@(ZTkl )1]R) @ A q81|xM;X)rk;.Q5Z4CxO@k@w x4oAAӚW_/>OG~ݹ87I8UDT-BQ Etu_$"YTyJRoS\;ٻfsz:S-KP[S~9KJ8 H4x<HbS3   Q4iYq Im̵-kf'`l!`ƼHF@aV7FXڻv/`Lʕ" B`J+Uvst- }+o<\jJ;qg;mZKeksMt |TW+,qDjAHtaεȴD`" PQ>m)\PK\I5`]^W()fɰss{ 롘|Tˈgr]!jCs k238pcPfLX!dax- [Ԥ %@Ä+,U8zYg/YY5朑\Vȥ,2Z+a2N!Ѫ8 0,9TAfH+ :O8P5㧿&hC8FӀkۇ&߆2B"ݦ@/R-!k1!DDxGq=^19B,X#bg4^oVXcs~؟?fޣ+W9箐MU]ם <784 > ns9r^,.< U1i|RK;_t7Ƨ/4(^,&)gX,eLWʌ xx=Re/cX\eߢQY|0ϲqcV^$޻8CJ  yv$npHWbU! I-_%ZYle\) $@5C#//\]s۷pﱿ|)y_8N/ 0 LARR /{ n<|Bߒy! 3ͪפ f#x9d +)ůuD;n{aWc@JƬrQYe!p./d2a)zDk56"ƈ$UNJ9?mz6J6d2em6YeM>X/&gߨ5Ot ()~?^WŸ3Pk SҦ:JeQ c¬)ZFh(aMH?{+5[b(</^{@?`r"bVT@bx{@ği靶"bUľ/<_f-p;aJ';qE@mwwzmWui\b.'$jzhCWI~܅`dlF!(Mgv5U=N)m$ [MYƋe "+pETBDJ Q~?*mpLދs-5KˍTQc1ثn_Ƭ!('oݺy> u#u2#lU)PɧP$8gMբE4M9-j~ى^hvpm`v ͪ1v-X -bUN DA .nEzEI/@Vh:@ *_"\euF Ձ\(*j Hvj6F#S c4 SJ3/b[0e`@aIJR\M`Ef(fyf2b% *aR?Y\*.Q* Y5A5ȊR]W ֙e\ ڼIZq 8` ` fƔ>x &(c`V0v2~Yho"cv8ўq{ui1cE_m{аX{|}O]鷯}kYS7@+Y< 1ϦemcK</oh ֐"FVJtSXH@mPYL߈' $p8D>fqF ھwv5j%gF-of}^?tiMI+J߁;&SjKprreݗk+Čw^ھe&1+@lϡ\cS5/+"m[ۯʭ.$Sw,mcB~/٫Ҭw)mRJef L1oc'6-=e_,˂yK0&l7o0AHA<Ǎ<#GHHi I/dB!c`af${7!U\Lj{QF"^=/ Ep4òD~J2'M.XC ^h*G*H짪v}A @`{+ˈ%Rc͑ K4/t "~%K*/2%eD6eI@%f 0ʠ& "=psk2f0ۧUDV(5 L=?9Sј-Z#( YeF1&]˿aD.PS1X:kT2z̳+ ړ!_ IDAT@UQWN= 0 XF6ۜc"0 іlz"V{j ZƧ0 ]《1A1=ge#'PӅ4Gɷ|~c}B^tM5b7MGï5H*#ϹfĶ/wxˣ?o%&ƄP "ߣ|VS bWU&ZAq=\<0ɧ;ax=9F|>w{+w￶~wpNYEuKX(m? m"hʡip/*9&C3Lp[z\_ ov>yzO5Dq P 笠fu& *uԧҮr9Q/wmlUY&s@2'qMP>GxJV+旷<Բ rN%7!qo21fy/*[qDŽf*9e2 ?Ӎ{GӞEx&gDfaދ;̛Et3C*SpxfKVIjyNa#.^"yiY)@N-sr&A y 1gsz5+h1ARܫ85 X] ƒ4h)Ԣ#NmV_0倆h4YTmZz?U "XZ>!+#㦏e>'%`@M5M P4&"s`^f ;D+LW!hkmhN;'(rx =q >6qw7V^@\p8ϐf쁔~®GG}R7ƫ{h-YiS⑤ 8\`fBv:ŒҶpruZK vk4^LA2Gi(4DVYKN n!e*<|yBPC?1P9ԓ1Mk:sFB*RҎOq R˂QX%X"1Ռ6M4YAPiv}}[Anfqp8̘ׯ_~@5p]/CTUNVTa 9)+:sF\i)wa0, UH3"ւՙO+S۫6d4ރ$(h@9BH8Q/ "nX7Ԝ1CrA顺N'/.'E(w:0QbC|u8Zvzgun35RJUKs iF q3 _Zf)Ix|FԜd NP f/Q~44Җ0o3l4+8mH R'wRE>Z9an__cĭ[CiZ9e-#ܴ.Oo!xcclo -<\]SuP&p0y~(bM;{ 5 Ͼ [ -ՠ!%"k+C@й}G?#6k^mشcѿӻUx^l"I_s?3Na1ox)s:!QiHPetСiں^'Z)\Q:j vX"x!!gbw(Eהl X6&64mf pB!fz3g0iOYAI@Ք6,商)X1m?9&V0HiAZΪ0<ނ m\Dy`mY1FZ_KkzV (!q0 8p@J q0nA2P)o m!t'pNœGܶH  FWb 1k֮]Y`S0I,F"<9BX6.-6$"Vf0Ӣq%-ͫ%$%ZI S)-ilTjjwL[hd (ZZwMOŊ03^<# Xug &{e~g1{-3|@NYC|۽Ek%~>甋fJ)rzڃa͗py_5҇vpϱr[~k}>([[GbE_]UBma=dnV Fffh'RbɵYRQAIRC~xUR[!-ѲsND.<2u_Ƈ׬qeILN (p_ @åַ[4VDK;Vށ[{Ubjih-THk 'TW"gJ'2MnnHH@kmf *R^E9 ˈ5}.cM0nv 6H&XR/Wq~gq "f/Z?{/R^m.Y e!};f_J ) Pn僼l+…De&&h2gXGNh \ Ozm>sդ=9k?f9y_iumOeY0 L_B( RLj>- AJjDH6bqePgRԤ\ޑ wj!zpͲUNJZN.̴=#/^{1[LJ;su7G?b Yy9VwG 0W+xؿ^1bc/̯3W6Zx | =@j-V Z>TJ\nd~${|#9)pj>6 9Kio] MV݂ /׽l$@g7٥Yg'W ٕݓU[fB+jG1*,{fIo @+H Jb5 ![;+XQScVL)~ f?g˂n%B\tIDq4 ZG- @?F͇H4^p^U[7cw٣/[W#$ןg=mQu$r-/nQ9#LL9a#\itNR5dD3Q;kAPzc'#}[5&WDbQ 6;g"b7đ2BvŜkhQ|Hi5)J2jbC(c_P5IRF HҨs^Є+7={T޷"ʻv)ܿcO ^9kuzGu׬:+g9 ǽ`>o?k׮Z>.Zz׻AH# 4^/\iMY kZPz݀Zf s 1V9e9bkpОǝ>{Kd*J.OvUr D'j~,B5-v6z7On3ЂPJnrT:D+'Ik[6R\UIfЬM`Rߐ&FJ‹+S-āgiIH,n7R%`c&,JUY1LnEnm"aTˎUdX @f!o)ȱIC,TaޫNg-)Pjz"e^mK |.F۰,3YvL_YGXϧ0/}|4%LayANp!/1b>HQ-ԫF(@ƙhݠ1HiMʹT?0c=LV2v+ZV_[b,Z1sYĬˀ!Ef})5S qc* Ťn xMjMUm)8?uuߘH`"q6"Gi+@ #O/Bȫ\fOߪ0Tޗ uߓz7olѧGu xzl/P}&L=sk\?}?'[kgyO}Y~~7oĭ[:wF1ӍNJZ_ͽb?Nk酨#唞8}QL/;,Av(u[`;;ˉWL}{7wd N)RPBOSbp xfKnB56XxH3#X]2TXM~!y {!~]("i`bQA=(4kТsP׎!r9ݮ ۭz2dlB@ )5ɞ%p!Pĭ[€o>dps}_c.TKJ n3:.eU a"F2qmH2rQfEڶ1DI2,\2bs:3YwZ:P"($/-/Dku@_C0^ !4R f-`t 6d"+{(me[-I'`ӌ0 -'Qm. qt2B4T,HM0X \g0(Jf,qѢbd@CwbCM5Zwy}+U^$m2 RhB-5I>(kv+>Y#&F0jQp}FH=\Za4-XQvSR2ZrsZݘk;n,d[}fhXsN?XB6JkRsu 3}v{qGk)k8[wg Ֆfi+7s4V7{ջm ~/{cCE9kSϝ_3M~~ ;ZZ]@;8,cMbeemnhvo-#!|Ï5yM.cDYBvr0J łDPٽ 'LJZQ<?ܷuQKU8RI3g$jȈZCUǣUFGϡ41xH歰,$N&ZdU s:쐋{Oi4MF'buÀaΦ@l6}6ʜɜ /1=2 ]ƭcG{2UU^$Qޟs@u} ÀD9h C@Z2'LԆKSgurfLi^Fv,a.OsHWϊi L@FdvB b,# ЮS@VKMNRZVt~leW xI3GA_h!¨uGE.B, ;J߫v}!`hYt1I0=h/f"J{ẅ-X,ӎ  I$i){OfZ#p\k3E`+)'ng&K !jyVZ1* 1< ϼHP!<>&$a 3'l rcjFsBjy\uj<* ,c@ӟXbҐSd:cJxO~Sqj;Y?NYD;Fؾ^c*rMeIA ^x}5^sY ?SWw&"??|e,[ {<(PbClܽ˝ir*=2`cKGe9 @uEBt_}Z?oF+TPEX2%1֌x'߇Cad7[z_wݵڛ)dRjM}4]֑[YCbqA4{J!29XalF,Id~⚠b!nR룝J,TZThݤso#^ƀZ3@&d: (wfZP`1ůGukyB#z2WmF)kޗߚU7-bbB,]gdZۤ D@ RɳiZ@%T(Jz̡XM^֤! ZPv,,Fu&Jlұ5 clj'a, oeiwPlElZ`r\Nq֝h Xx"٘#sF n2{IjJF>k( ~mśL0 uwFݘ64=J]x>щ_TCKwZEPԧpqqRD@3o=@_H9-s}oZ˵gmmk>'cC>BD|?׽O=T#̯h~ z8{遐!=yOҷi]]i:=C%Z* &W,[d=v7Uk$ۣT[Կ .qK[!0SH66ȥ%J`?l{*`Qōֹ]Wf`4(SҌf+0 ro17{Β Dum* ;RַM3ƱƐ^~ FZy1 Q'?Uo'1f"֮Ţh|e'Ra'$+.Wvx3O#/{u"0 8aH&4K!DOI V%\((GP, +nh嗩ƼfZAw!`U(uN!p P]^e84ʣP)CP0 XrBHArg¼G2eYD bH(eMPo1;?PYeEC3Z ,\F"+1lzyy@j~fdJeV(r3K% 3;b׾1*X\Xv Lư5\%@iD bA3?g9LP4tm 9p#hߍ]y4yӛ? Һ.Ş0@$n8r.VX?rG()#@̞QzXv)=f=eMXt=9y*c?jBOO~<6@|;TACros[Dg>wo|c}D^0~z^l&=6cր?Z;Gpw IDAT  "yҔݺawOA 8,C=,\Sؚ؊(gen[e +emb*",rAcZc<$!,iRádzE0"vOfƠw2cc>0 #aRQvkbDr`W)u'HBA!b{&y$q7-KZr'3BU3@ͤVYBCT:JĺC$>GZUeϘs}ι{/F-AK01ӐF0$M)P|5~HyS#&$&&;m+j[PB T hU646U|(r{k9c1k^{Yyϻ^s5\cg|ef]Va2Kڤm$2P4BƤX}0+#3M0)N@ÞXP5culMOъ>1޽qPK<֍nm-aٿm!& d x~gE/:[ӿf v^/Pn=&6C7u\#@_Ꮝb2|ݏاr-3E7=}-~4ڵ@) dNFV?/{Q< @NwNk[Ұ qsv^hi4 n`G`CMx>_L[:g+P*ت\\j$TFԳ\Yy:P0eRA%1 RZ(.Ke_#hQ#$NEY7*4Oe3PܣJ8UQQ@zu"g.',i4d[# {mOXĬ@ &J^<% noBYˌpp dSpwȝ;wP(ugsB7&$k,iYLd{p^Nagtu72_@ԗzNV8 )WҠ|\ݳ5@GS<I_O$/8,&(e8Tfp>ی10󚙇KTNh3[32̵Q+ϊ za@MP] !Ē5!hhV"b  a Õe]_Ɇ8 Vfy6bR+0Mj!$׾ʭ.Nԋ?nĝT?}ⓟ?~#r}Px\>ݮ}݃^DAHDF}NY@,wM߄e?#㸋~yE 2ᯧ~Y[_>Mo(t=Z۷P/^$4FWێ{rWaWèz{e}QC FAVN򻤩|m.X5  p:*1TS0Py+.Pzn.S5Nm@w;$UB/q#A7W5bZsDJ0EjwqFKwQ۷!9kU,ĊR]2x80& 4aV@UYShJv ˜M:*-@%נ0,^)m22u iw* (\^pW?Ygjvjy!fqM4fĀK $L#j)'pR`0SqH)cUUa1UJͣ J86zrk(a@@Q+qB?swp_Q^zUOZ:ZO cF\f|Yaͳ)Ek"iք8@jY%ï];˲ M$Ik*xQyEIc3BDrQz]`GWvکҊ8Yb.;h^ 0Y @l~XIoR YNq|9 ^2%0, {%eYu` pY2J.ɢp'lr菒Gaxޓ}8]ZU\VŬ@3J _:M뉹fY3 IYap%^+Cφ+4sB@t~ iThd-cBĨ7R$_(g@As>Y֍A/4Ee25cDQ?GS Y4 6!@%$E N0 A\H`I c/XTE #NuM{΃Yܐl{NA6@uq|~~eԧJlYCz򗿼ule~*bk~x%^^,:VИ^ X?Gi-)ݻzP4/ŷ}۷Xxq$h]{HOoGv_5"u$ƈ%뻟#l0@ݻ[ 5 ;O'UXJ#OCs% 5˕@_3^)ߍdC!YKZ0ZfPw[ܒCO&iHjfw\dxWj\堮^%5ZX#REޞұIc;|y5O~I+O$'QGí0uJ g !vTY" S_" :IdàY_YR2S[9!줜Dz3ȇKIͫSI ,.\3dPN~`^+۽!O!>/h@ Hʠ?.j NNŮOss}1CU=04ZW֒Η^ܚ2'L9"E!a`H /N&%n'Bo%!$l#:UO@$/?^oDQ%A|4)Ip4e9mV^+r D{mY@h 0٩Hor5bVLB<^J}d i%fZC<!GlV?ggG3NndLuoAoiU4p, :O>![ d-kBEhaq ӄ֑V1k,V?ȃK-JHB.3| 6[K0S ^O8(_X1&#D( B\b ) npKP΍*RI*a )AZ/2g̒6$!B$ADT\GNa)zUn_1Og "{ɔ8;w0Yb9ԽX>2g]wg )DDo#M{3""5)KKNȄuH.Fܹ|@aJ*:~F:Q0+Z@t&W(8"LC8 ` W'[JOl׬bhܲPc?J887" Ta*)۬#:T8@BMRfM.FSke< k Jõ0ЙZ4g4aYƽnB\z3nB 6(^Sjto[$nV,K #렘D\, 2BP \R*G؛vxaNpĮ=|Ac"Hv/`h2~m(?BB-U'{q]!Oo>i i>#?#Y[>cYHzKYD5Yg>=Կ[RwOC<0:ׁ^DK\v@BI߷_#/^6g9-2j@xv|f78{)VZQ#en{ }7JB8= n|i'g.C;>x2x "G!J 溬sCG3C, (1,3a eh}W$3-SebbҺ`њ$ʊSLwUFqݦcE)lH"J6UlPX|L(.opa/SӲŬ_K=,nX&u xӱ>퀴H,Z=YFօc50̮$r*$ .<$ [1*jKw$c(+GstPYP1T\r$ [S皐R4y SC0[leJ9i\;fƘNzڞ? D3" Zȷᷞ1LI4 RAU̴H@Sc3aXt qoVUǫ)H@RCcnn쾛&?1nf&cm[BWw0ԟ֭[7!#@AȖ5^W#obZmu֛^gve`z KP(pݷfD@< #˅ vȝnApl||+}hܴNSls{<|\fGY/=|77Q::AU  a.AGMt~B7z=aU: !:W2{] en)J V9Yl(m8SD\<,%E,JiE -.Fx+KĖPnDRkcx6놌Dn2/|˷ S~P{;6=s{!Fk߀#vTypȜl77WHY(ܚ_~O[?~=m?=kN*tMo\OYDܒ<{8A$hidZeD) -J/H*?~ dȜG7]ΌV$! P %¤J}vCY^[RZ-3UF(HlHkL=O.QUU]c0O5id77Һ t n]4N.:",GBHi:1ƻHah, yŝ*˫z&q(̵Ąki ^ a.Kawx= _} i-;_/bQ؆3(e2Ơ<Г=Y]ZE:l(cZ5ALgx#Sb(N%m"uqZ[f3$o/?yt##|U<(c8ń2z@IɘWr`ZR13Wi'"[J& &R%)31O@2a}5hιC0$D5ӖU#F8F[Y:->{ٕY"ъ3V67vksPʙ+|AmL~GwbcC~qrWbf5g; }Z^<{0bwo>[e<`m=h=u`:K)p򒗼~vs͍8yk7^{cc'307;2<"e eBZ1P[FBQ0:VH1E>`vL]1n[@05-)h ]H9_c-NW,cլ]4%NAN=$|.ˢPq*ࡦ%-pXdXWWW`P`q9蘏R$1BDH+ ]|eΰbA" gL$Aq£>BkŦS{뇺aYGxr k>y8x1g7w[+(VE<>^/_[@,.2nGA6H7dIkrR@O\iAO#21 uW7u, icjA_B+!}6 G}6FikLƨQ3}"(L=*$*gK )>[I ]JhZЫtjܘdcw>3 -f,.׮v}(mfӣۺ 2m52{ nݺ~ r xܳl^3؏X}N [@^Pg(f֑1Ak2Y2a4PM7wQFc4'~wkxo#@.{ߟ׏h{espnb7"D/}g=句%")(y{gI!Nטv>GGAH1isd ,7cVk\HͳiɯHȣr<9E"uo̚p!{o+gT cj$B-+F8X-Gb{er啺Aq9Ψ_2K!LF' R5νH3gSλ- +u}8ImY\̇ [wӀ|U 8;Ge0U`2͉U]$&DY\LyAu+*'= W);DEFq)}S vy>$(0Èy\)br+zh[Uaql@ &T͗|'04;oMo1I߷Pk&&bl6ژB^elsJDrF] ʰ൳f(LNpN /Lpw1Nă1La2::NocGY~Ǘbt!=#W <@C4=(Gù!wso-{xj IDAT}!#7vh8+rS37W{/|y 1mxe-?fznc y1Wx󞋳5{UP*q2{ q o#N<=h^װ]IBHw\X F22麠t*Kj]1P]7M3&G)R"fUfӎg7aK~"47&,뢮fA˜qc]R]2uÊ ⩮j `sá}W{XZ¡NJyB#Bck꒕#25|\8;!3 p@ӡUXY~24(nOkؼ>! Т- IUrB=Y7AQ&ͥ f@vFJ`lEdpj$Ci 7gY؏ X50r&e%z& f5mnMašZv¼* 4˗.MPkϰGܯ1?ן^A-x lԧ^=C?s?=ǹkRGk?je8:_ ?|+ޜ@-(|2+]jݚ$S6XtQǹh[Rz|" +WFNECw\i[=h nƪٝR^WI ŭ$Uphlm$^@=qpe~`χV1O.\"k* 0^ߋj9sb!L1bWrf gggXH0%\]]j h:CtP'Ro0 aRqNSe$%]7"pHpOmI"xZSr(.Y9i=E\lԉ) tȒ׃)Έ&DdDJ9̐ e!~IM$<#1@qBe/XTDPN)R22KA>.. 0H ^!z͌"*mB, Ş 4nmňULAVkBJ ED]?)kLFEd Y?f#inpR4Oll A3^yp17r2gVTLݹ(#;uСFu3R͞dKk]6n8_2V$>twc ysEh[/\zm)mw݃mI<뇏{W򏀈-G *S~=~_җtk8ۜmlA#;֝ +D-w<^u.8V/6~*md z[sSYy7Y# iX)d{RF5$붬 8elքY8JȫNIk;w.U+K8ȇ;iנ\ b50@(C- *1&FuD.&pmIܾwz"BbI]DĬ2 :89nD)Vk^cʔNj "vaD2`LP#[f)i3.,bkVo 2%YjiB@3c]S€$)+"B@2MyXI_U9I !q\|%Z4i1=a\Yt)wb+h_uo̭9Haf'h7N_UAij]rFb;+SdBuoF7^(@كq{P/ڰ;(!} \h`x~~a88>#Ud&y#0M[Ns~g(s_;@)Y%%AZvMVI忪,"OܳQ6P3Zk=~6|/Iw9YM/S1/EptYTu) jDK 벂Iܕ; (+0 4!sCkr@2FRlĭK3R?D0I4^H/ ebPy!h0>B&ջCqOc.<YJ$I{LsV3%pGyYBhF,W75=T!Y\\FtU rUYo8B#-g@$~SM2|rmj wak6wGF }4hZd 23cB1噊UP|)B~V.zQ4`)!\^ ϬP/A{! u_m o $H!B~fάkI/0!Ly!닭k/|VkrLF)cy8Ճm4_;QS?ۆ3Ύ2c~u*.dd)c?'}Jh5mל֒*bG W=Q{u=0h@b+uV%uVw?o}+~~ <ܝFķ}:cF֍ݷF1~w?G!o4G9s22Z!|7{ݏžOD#qC+mK V+N9frD̥_CcQ%Oy1(}F!OA?$Z1!p([2bQpD! @ܤBMm9K2;k|!?%`ٱ? R=z-mKc[ϖeh]FXCF`!eAu.[W~Wpyyy[\}P+zj1n3yr{s??k;}).MXHf8U ~R3Y&an_5 o 8(=B*uؕ* k%rz.SntZ.bw`dEj6X6 9楖eYhjiθ5 PX+" H)}k" Vo<$plr[! Y3nuh)_R ZmE. |JR/P~TQ& 拚^{,W EkS&M$D,*(Z[Χ䷻guw3 35>gV'hrjt ,XFJs&ՙj *gG" s)c$׊[\C|g3bvDT=At4yS$cT^ix͈c)Jp"cȹoRs X+Ԃʴ< q'*׭1= HsA ~BuRF`덱)1̨fevy~ Ƀ^ǭk;:݅_P\u%/vm}^ @15*bgϬ@BFora}Y;F @l-p-oy ~WyƱ0A\<ڮ- "s󝢍OtVF^9vjcwz^/0Ţ2'&`J&XLSg֚sI>+zjN$/̐K ˥E/sqK+fqȹ@MU/B\a麩khu*`b9_w3ҪCk7q⒀VJz=S1`u#Ma$q6kF TBcg* )DENJevAݢX3ͣYkԏV 0uCKt)2#qp}d>6dٻemYC7g!a5R`HF[F~԰-02u`d-#=i]S㼵įگũOl\]aLKuV:?|o{OuϪtk;ZšLQjl nkV[ EoTi@y -FS6@UԈ Bu-T=LVCd%5Ve?0zO bR]ςeneIkBI#A;Qε1[Ң֒dd?"HȽWMd Yj|DPbr@")%a @kLpkdҶ[08f $Vd!]!^o+l"{( Yg%D2Υ!%lpui:HB5.Jwetnܫ)˚(::1BR?>hR݈GQK^km)z&i4T+nQI\pt ɋ5H*c1h֗5iNO1dT۶`X z3[;A:RA, O rBWֶ,;V+2ШfմĨU#fLVS?5Ap>YDΩwHlHp%RWj3κm U )l~l^^mQl\sZݹץMBN 2!g;~]ȝ;>8o\w O(UfٹSSʔ/v0B@fjce -h7CH>纮=** $jV&°wFSF79%V0jMj"i[f$"`2W`,AĚ lR'dϒyhߵe H3)1nY_פJŒ&RYB&@|!9 @[. 2S܁1(Cj\) ;0J('i@- UKݐup(NWYjVa1f2fl \L4{Le:/E <1@\ ^RYi%Dk D-<[*5{!9.Z rYo^BHm]o2}lm ~jcwD&;rNўSd wKh-ٯQ?>Sv\7#~i|w}g4e2 Tȭru#q1kcrsE2^bP-dEY? CB! OkգĹsJtºx^Y2feu`|43#".P@T 0%5r?&"(礘3!gq>??W!a<%oZ拀S8t] d+('L0P2vq߀ԃT!-q"Q&Bs|b:?8fHxbg/AaBݧ%wTR@8[L\*$;|Qf4mN@`I, r|2?(8؞Z׬͓fJ2˕]̊R'S~TiFXɚN'Ŕך@o$ Z4. VE0X| c$HA/%u !czcnB=}&Ouo"YA@-•R8A~!UR5/PMaVwq]6R pHC. 4BeJ8rd1p u σ}s{/'jlodSW~TIPu d ~v v\mm))zu47yS Ќ @ݸcm =Xh{sŇ?a8=MH# IDAT߯v[B [`/w'mPsP=hjJcȵU)C'Dr3oxA鲧ct_hr\,V[ SgR9Eos&S#4$失VfRΔKA7NSA^czRK:n %Q@I`&djf;{X,v'NȔqزxLӄ)N%K4I-c \JvYL\VT]*77VNVe3D zo~w~=A;hy?$>+,~߁~o]\͐"=Qfk `d`H,'gJ-(n*AeĢz£k;eiqh 3:Nn Vș%[NY+mD0^Vq"v!Np~!nYqšWXqBj2ǖ*Y]] 3ڻ$)x۩d-Vef%eAJ 3p)g  BS ,Y8u^8Ecw|ÇW&aߴse5Y7Ovȩz):^jHZ(bLmY g f 4s} NKJȜ%(kWI̼Ȫ]֎Y^LKy<)"0&`ĮALxi͂$pѠHI:T -PB2vO9!p`FLI|WCw 8W24]f-^x0}?\?l7ܮ#uLN/Lz@Aw#}[ܡ"{u dd kl4g~{衇я~Fc{jN[?¯Q іăSnZmx+ڇ>B({W~ OdE* @U eZqfuhur+ bc ȮCq)$ʪd7_bfߚG1ڎXrժ 9B<Ǹsۊ@̤/s!4*̯Taڋ讓Qtnj p  228Y/%EimH5$fFay e4\ܙ4ڸ~ ږ MGW-ąL q3"QfcB  'ټVOMA2j5^įћQvAklcI_x,I͎?'pqql @>[nmo{Ch=-ѷ{ u`_ݱNo9՟^?eY>z2!#27Scx9~{衇?eLb?fFcׯ~IelzKwh|=/{ѯӟ__ Ǭ%o7-S;Z7SGqYʃ B:TY;!xU˟3` 0 Zy5h1EY fd.Y)b]̱x6rtKZ @&D?bT7#f$BJȒ>]dY~Ge&ѹ9l9!U 1ܥyBQ\})/繖eHpg;rR]UYgg@qFZ4S)NG3dmX  Zk!"LB3 ҹVc@+t|=6m;a" ed{5]$0 jlT$ݰl RGŻ >+PߖN|I}mg3V"jB+xAu|'e(Nε"r .fWShƧd S<$wt>^1Z05K䬖oYϕlL6Etoye@53֕v*Dk)||֭8׺^]#2 5?x3)|=OÖ [BNcAYdž?m[ ĎoSa_ϭNWUx}seLNö-pՆݯ%?uďۖddʠy5={=SGs8NΡ_RQFqK`=ה_&ʫŢfE4 0&7_R989l$b@Am i3Im%minhPR6_ _+%xⅵo۟pMѹ@#0Dz}FF@Į5~l@S dt߯S nD=]wS’}ӯќFz"9> z?~>[UTרF5(AYEnm]L6z 5"(WMk`TE ICHJCP0i'u= (ٱRy/ɽQ?NSc@%hxE, `:(K@:F^8% ]H cUA/I `t1 䄼 KS@^EΘwsheB>랕.X{̳T''8C)cg?˲W H &-N(K gPN@,ClZD)|x#m9k/vB] U 2WjҾ=f{J V0E6DwNgq!Y-.dAUJvBYn$@BTxA~r6-ļF}2sƽ&R^ڀJ`] TA83˂k۸is잫]z, vw4Y2LkɬE晈0 U+V3hVŘX@B HkrY !yPYY*& bմ pk i.BP뗈{VSZF1l 17+ԝS'o⒵eoŃ>xcq6##Mv̿[#>V1鯽n,Fo:+)>mW/| |fl;ۀ_=p筟kFFٱF\]kd4wmx!t*AFC/Q1j1_2FJ32TJ\eC xֵC6P^nH#IJ],y]I2`B6cyF ̌z"4%Ѻ@%F$3c1YuX3y%AdΘisD]MLXr :e_>\E1'dPegc1P9Zzvq`d r_XD8KO ذ2`ŤQ ̺&T`A^k de}0A۶Ɇi~.}b+Rp2+di*~lJvl9"js7"6(OLiBq{ aĈVy c, ŷS[GS>vmO? A?ăSNY3mLgl @Zbjr˂ 5ӓ#*̨e )ȁ &a k՘|[LVA:>ۘpf|ШExz׾(sf݀lf9w :o=1Φm׻im #5#@rgofh7}x߸yhn"~ހ6x0bnj2"@ħo:~~ב*o#&w)-hG|Lsev]VxL Y"*QUȀvNZ+,107U^^ICYpYA.{Ornk@uyt;T(^JVX~1YyQEgE ]STW"$[BNjiRNM֔E@~!TGd &ՌmZd  e:&;BBV8gvZP %Ypyn׀,i1F ~7[7l$fi&S5Y ê./\\,;X%+`%@zõN9:`m>t;H ڲ}ܰ=ۿy5d@+`8 T5zֳJ:ʩ!#@>F95&{J\G g/~O~d;w*2Gc_?bCNŊ7o>Y9c]3֟#:bTO䅺>M. xh1Jz\Am[ニes.%04s,p D@/#`? y)C-KxV0EWF`7sQYnI%Q649a~rv-ν6M͔y2ذv혎ZNB%3$ieF2C2*E~!E2Dzc(-Kڤkq>?| EdzllVq7@1~M-oR od;!KL|/~}"ǀ#9~JvDr  l\[Rki̗/uyk {q,J(3rC%l6=.w#./.0wqv۷B|. MW4c;(# "e]#e1w'DT4k+Cyޖ<iVY88U$,0V3xHZ͹~ R3NsJ~/R3NUR4C5]}\Tp-0!l2 ª*OaZxّ.ʶ!HS ܉y0Gm{X,NS{tx5lbZ{,&SN-IfCn%ҝ:˳;q=( ȸ%F/hvj\ZHL2V#@ȩl$-oVgn՟Ӊ9s5U_\Q:{=еԯ!ǤO.[fD02g)(YbP_Ksp{*}7;>Ҽ/Y.d(Fdm~ֈǿg!u]Ep];⧕hIHz${~c䃼TIo&XcO#`:x`i-SٟK[W^;O}VjFͲ1αiGyq ~mƢF0[K~ /ޮ)c?OBh>2)!U ~$3)'IrR 65{\^ z8lQs|n/Ѱp9:UQip3EgCrclۢ҅%bo@4™ڔ̜v\tyDh%j2N XDm+&*Uŕ/!  DWE}ףϢl^z*el6`f,KP䑓6ىW:U̥121mvnLޓͨ-E˲~$4{)[4F%m%IDJ Khd8os&c+fj\.1LIp vr|CpulLiEu Ȟ5I<ȗOO.%|=|PAe[ޯ b:lv{r&d7*m_z@w\WS-ϫ__ooG>۶ZsAT90 dNRO?o>WZ hXiNi*//OҫD Cد ntP@W}"}˾hmo`r_GTxR ͪF `-ݰJps$"u8/{`CZ&Q#md4G谄l&be$? h½j}~R*n`rw)i;Xj`8MzOJ{2J$'Cl> ·n>>Dd⯑{ RDHy#`J`VR3Ӫ/hu fPYQ T\`~'-'s٬H5rH^ 3䉷?`!SdFjSpRlZ<*Ҭ^0FUWO|E n-=5iݢm FQn348co:p( )elvcL(\a,7e!mt ى@Θ%"$U*lz/90 nR0 NtVE( bkw5P2 UYl~kSg1 3 I})U\э-5],X@B'R 8e@F*s*F2ښ0fbFh6J9tL%셱K0{zϔ߇dFhm^_{p vkY!}-oy;a.10(8$tD/1@Ueϥ\{oG?Xڜ=\Mh-i?a[W|qvv:k$VfE$*ѹfEj`nѭ5ȚmhS0fնC"~Mbf6 qNW\E5 f$!bAhb#:.Tfqܶ58ھM,dqMQW3zaX2qvhZo@TpyYarfd샀„HǀdDH?32a1 Sѧjm|HV| nJ ĵ xNUw2VW=(gq42WTM|HY|~Zv?q߀KqY9lʮzࠅ8-xR<fH!9`q,wi Ε Oj#֝(U2$[)` Ѯ!|8*F"aYn%&͝t4 F1a^d3~P4e$s cJ,~F`K>MZ"KjIL)O++X4 cfvcbu-SjOÒnJ 40>,k  .y**10fu"hzc_Ok$`* <)dZgLia܁4Rhj&VAtxxϥf~nk)e^TcɏmR X!Es=syV2@MpIfa)aBIu((cQ\i!H /s}M7pRJusyY}a]'!g&k֊~~7`T*$Ѻߪ{z<,JE{xI` Ēr9Ԉؑ%$3 RJӖoH2bO Т%+7}1 etZTya\0ݜt8hT`6DB"L6X&L| j^Sbɛ $ LuLO|D͜@֜-SJZY$Z1pw'[9L T]ij!8 Xca~cR :puCαWODַ(}/Sc$^[7[jCNaSU nb6o$ >́Dv,͹]jk `F`$ٿ3GӇtpJ)a\^Ҕ _e # s6?cieMxDM`ERƶ J"eaGI 7sAWᦦ's*{l'i&2!$y;m&mG^7yb;HZ)rjEji| e2AP,V:>o)b :nB:Xƨbjy_(`dJ$%qI+QIbk;|9!s?s({Q%^:$lo(A0hjfC F~SfAk Y=\ x}W",&&U-ޱȒSܠTv"/EN_nHZ!C8 O7RZ vA5"V7@#P`@}4P"i8?k+jNDZ{w~|k (hW.vYJ-j)גJb'儮@[,p!'i"#$%Фb# s՟O({Ȍ\VmNO*=hgҿ~V 7v퓟wq&a8j5}B(7/E~s kcu,$%cd>}?ƸZ @_x^'=R[W87kl>DZPعPiFYYj~U_ l6'2jٹ8.i+OwUnjBʾ5& ф?d I1*H DX_,Q-Ch@#!(($Bɧ$DY29ekր/vOUȷz"iQ@STN} CK0do|v)gv;Rn3} %(V_Q4B|l/$4IRkaa"TCm3vq~>"<\jGi9Ok<2 ?ׄZg$ĿD\'ByƷ%QL0`*i}։G,C @h~ aR;L-|^LEDq!K)qZEFFeHaؾ3u uOAg 8DCJo71@E @ 0%c6DIC|C Nj}9|KI`b 4B XFtd9>LbNfjiz`*HABڞI6k9.ղڲ D٣&2OHV /]'N#NԺg!\u|BNyG?L> ;K$5bDZ>Kx,s HY\;wqJSc?c_56)i ,˼%=wrtׯ Fߋ'x Jeg+X֮ef]||״w.l?S4;7 >7,yLJ-xXzV-0MT$ŸV̢gשBRMF?HuR) _Vwѵ RD}1]Em߄8*03ꌴ:KhsA ȘOķ4 Țg#WM 2 ,= k5jG(uH9D' #mnjABE"faŜk}YYˬ9Jc. F#9`qR0I!yLLrBZ64/-\LQ*Ô)ik7 aк0Yy`yPd+DbXu,~~$GD~8͙y!n KYlUUS6 ymf%jF6p`d0Nzh惒Wy:>H"xqD\FF h:ֵ0˯oCIRc8x;WqJk`X;u Lcf ,;"KeOk.]nGc=7 x{זȱgjK#0&Z~l 'W~cp8oJ Z#MaL_gki0鞔ܖ\xIcd;D@QRF܋jf3 '`Ƃp\ B^M$ 0 GQk` {k!{ۋ,>*j&WJAip8~RRU#Pu] H)~bsA,3ďFK$8Èa0#Ja 8@aFE2aC+KFj3W`EaBƯ "M<~"}HMdMMynwJ :`Ia8+13aZj j: 1 jԀ%Vu2(tXMn;G!fC{hV$.40†̹ D 4 R7&nGbdMl~7{5}H[s\[h|WPPի۲]2wP(Z I5Bv8no4 J d7IT'&s&Kе>NAWnQSQ9A'mq M}{ۥ>-,i,c |뀑5L"/ zdcW?=7/F홁N?$O(N.e4-0`HcS(zr"-9eե,ϨkG{H!U͌YOdHRΟQIS"N朱1T.aM=pf׊nӃhWt]yE=w  $a{wXN-+PiVYYҩ0@qМJ50`0nƶ,RZFp^Yk"P4K{ m$oʠ x2Hܣ{ P8-棉{CI^̄Q˴^m΁~xIIHSFf<&#t+hpˤY{̌jxR q^b rf6M̼΅e*0pŗ:Ff3Z D4 qۼTrmԧDG4N2dl5_t&k H9 \VgIDn׫3d7:}HތZ3 W cr_rR@ ƣ(V5$>4?pyaV#- IDATF%yQO}!30:LR >|w6.M6r1O}兽g0"#Nq+͉oU2ϊ*-`AI4~2EUa{i0)#ۂ .. mGP*øC!U(fZԁ*0#HQ{V>yUaձIbpzVGΤ1G)gW>,YG՗ +-0TdŦ^YoZFR5ѲjbO ( Hj3cS|cU^S{cJ" .R%1牌)_OpuO,J;foݿ[9  8]3cvgXko\?/w*y8֎Ք ; DlKt^||W&ZVn3|3;^q0 Ƃ NFJ,s֤fVuP-bx/ b<LZрe~{c=%?=ȻY/@=MIB0b9y7N9!w[ 2_~nJm4Dl8 ^ʚ[dcаb` Ԕсqݠ `,ˤ'Y&e #ɵmÇE-"|tKy:S܃K~1E@BlY^v'# ڊRQlM;sI DgL,2Y䀶0 <|†mLf;9/̿X}ߣ{h0Q8f )cbXOb]'NZ.wQ52(ĸƼwAU#)#9K9Q$Z FUf#X $>6Q-TeE 3G-ZQQ#v6FS[es0WNו<1eoʜv uͲ@񒗼_+r s} (\<;Uϲtr{BN )ozӛKKxyx"10\`|uz#KLW-|?g{:5@25Q]r1p 3@fSK3ͲlNe4@fNj@S(`9~x^HgQl=@" 祭!RMse\Pk(`D~v3 b#u=J[,Wր$~gvd% b8i\x1/%9X+>i|sË_e(R W ^јU#Sl|FZF_ lMߍF_( Ϊu1ReIpe!JH (*fƀLԂʄɸ[ĎjnL?~ei@R6! RJԑ=ߔe_/79F\1s 5~{^dsۘD{ nƠ v,k2~tHQpPIn+v@L@ ~(ŒI\۵"Ŀǃ.ݷt0N>{zq/ =~gFN"vDMs3^XwY#kR3 ~{ߏѷZO'deBoKwuy Zh?@BX 8OhB/-iam Glk?:#RmJ7ˁl`- @'J"H%qsw{aCCNsz缪#{QƂaKTX5f_7 M9Hp$a6VY~Z &QJA3?D2-;=,,P-Y r`Q]y)!w)y"$w!"JYoc.X$G6 ZHWRAsiwr)֩fYk Ƿ}۷-^{ dbS4#kdΠ/1s&%G<RcwL}o~3~z2&W9}>;#ZH|7pqq???@cF_c|8mba}c .t9% ~tjd\쉚&TFD`4ʼ=d^ߓ{IǚZ=3H$\hWYcMUiBrux 6Q CeM@1]󠙥B)I|.+ g/Ԝ=!djJsu]\F:.\^@+“Emy% S<"$W(fVeQkM{:G 6(;O3Cx0te!n)賐fQY}8Z(ƾт%.*c%?\+b1i֡I;|2ɬ\сBɬk9n+Z[(]Pu ch=],150tqBL*PURcY)Ą4,Z͟EVʚ̀wrn* ^DF4868)@CW\ ˃4-xm< 0gϿ7[ߐ%1wk\|\x,[@@B<NmIqq~`aqrx8~w~'HԴcsb.옃yK;iBc}_Uz`+8&av?A͘h "xLVBRjRN˭]sd7fVKf\D M#tA֠>[<227-ߖC:a'#dZ3ZlV)~fV.PV+QM3v\rCvx-ܺD *H#'ˈ\,ZX\KH}>6a_ G^08VlsvȦkȍ b'ѱG`%F\R  Fͪj( MLsQg~:fR SEMF0Aơ: SOr8i9F`RjoL:m>J"9AJj'̣9;&De hJ8HPEjpiSz mM1aw|̢SZ'VgX\*2j2Ѝ]9HP |Z$S[s%ICj[L˙fIը Fl-0XJ"ke mMg&M<8mt>L*xx.U,g__Qr9%djC7e/{I 8i맖?eO$vnR[2K`gڹc4EF}~sY'oOO}Kku5s3'ߗuGZ57[ڵ xKE羚~"cep%j{+xT.g,q'W5bmN-"TóR)!uuMI&ZHyʝh\@u`hvpKP!E+9 .59g0kS'hQFzů28X3("Ak26-6ghV -2u$卢VɻaGMP miޔ;@Qn~0 7n> Pkk0hCi*tQLG5M{yIIq dE V"n54A}F VA_v̖r[l:yYN-:K$'A\ ?[:*/=+Cm؈dM>1KRQ B`!LT["<K_ht[(&HY#Ng-f9L"$>U*շF(s5JTE6d_FlBfTG(QH2T(VhWI& 萟wb>D0M~R+vTژ~XfJ. ט'=f6iE@c=wāQ.|7Nc`"2Kmᅧ _( 0`;ʜrط|˷=y>OOy ا$i>1R{WSח?}s˾l,"Y'O.AF,k:B\+3+d̕rf hn`Ϯ1@\Qۜd/'W|fF33ߪcj[DYF-dJoK}`̳踎BC0w`;a!eь1kĄ6RP `ѩv]Zj]Х,. ~vJfWSB"_VRDjm#FISIc%mN9%䍪ܙQFvHyٲ;EzITxXDf 8l#PFANȓʌLYC H;MKTM%h *of'2@!@H &~5JUd`{2ruXID t1:bȼ8hMtaC myQAV[x]rHKl@3~7z衃'Lٝ\:wQ?חJr $9t侵cS~UNǩ-oy /50"3oFXs`2pv_ r iEMo~d2vƬbm< ~8Ln2x>>5Oj4+U,bJ"(5ͺ=~Hx+htᏛAO Dh~\%1ٺg%ۯ4ӒrYQC[ 6@Yp" u9F{ 6r`#I-6ouId~yǸ)ZH`*سBUiBGoH.N  gRiOVPm%P'቉1UI$L1iI#m3r\# gK?=n^g0u-рȤ4][Kn?|4܄>f3wB*?.|7|N9eǩPXb,=]@)}Uu,oo_r_5 FⱦYLSdɔ+k#"Q3~~t'tk.1+ %2[⭓;`&+dNW2pWS/7[fE{7 ѫ @\D;V  a^օ J82ӹaDĿ) {螭!uHSS",V E7o9id-R",gDɳSK_]B%ؾ ^/FQ.ֺ0TMY,Bp*dBf~#oڗ67V!/SsR`TOinDt a"Qx 'eW͈ڰi=NF&|CNp[Q !jm朱n J4}xQ$囌Z0RJjPسql" -UnjT#DHQD׸YD}1b`ٳ~G- A0}A\!!X$S"k՘c)>kҢcͥZ[ɡ$ͭoJ C#h9L:6\ JڧnRhL7;l]8?:,غ4>s{,TRBd IDATE/OO͟]bsv1*ڄx|CSu9 c ,S&W(;G~G&ח mYd"~ vn~F DO~cug#g3:{rƤ%ISAY麂RU͵jb< R2mXNg99~$-3Mu٢n2֛Q}`Zr.g (?% J-XeAbr!sҭ o޼.}mb\?IAsq&#"1c 0ȝP" UY>w}%ylkYer_Jqr[ZQ$ 8 c!o64X☓&[ )Qwp 2 g.!tf1洵gJ$B ^%JBTZ3?RȚ )QҐd֗("% 1M)[ꓰYQ\~J\ Te $+)o|/D+r[)#eKO4N$9I-R$g:2.MIm.وa8-u' 5\Yc.oٞjB֜O (y׻ޅG}t| L1eq)݀xu=T ƽR֧ssUOR?qU'>502nM01?1ZZ~Db?b.c׀ȼ}O>ϧ}6 ?L4110*ﻲ@Qp,µZK\%2L&HA6ԀQ h@* 2KQ+>ZniØ5hIJ)(J˻@+(I)0R­۷pqyk%%ܻπ$|k9_B[VLs+;"k}4pۙq$jk{3)䀧NX7 [+fFFE/f__zOqR?k H7og~gU@cݜkws,cmS |9O">׈a\g>?s߷9X~w_C{_n}8CAl;uŐHm\b7^LFLg U( `B)@ \@s)1[Naܻ2Z33G-ҚL9#|_%l6-gL`.D͝gYv"FLv:rLa()&H<Ѿ:Y̾./w@b> }* A*!sK嵅DR~IEO\mmCEgu[@;-<3H k6?4Ye;m\s̷h (ԤO 13^2U(S407HBPqH|\JS[!#0RQ͍DaBT[ĬuH$/yy`Gw:WY0F|%@C/H7ʠF(jc6->u㦦me7$OiP"~<]/RX \dՀTdޔ(`:RR(GgψIig砜1YZ*>OƍڐSgEdw/yK0? `/w 6hNv29-1)44zc) d X~cuDlf|_}L{,g̶l98}e X\Lv>!u\/<퓞e"s+m#[qKfG[lQrkRo3_7 ݏLoO; 1BG] {r?K[ ŀ RRJL}$͉q5f;d3#) ݨ3ÀZ+6-QlM 3ʞ]B-j1K@HV1\h;Hҿs<08KnLṻ.cF'A6;QĘPEa/nGhs˒,KӋ8̍Laܣ(_j0̰faզGMi@ $'2^m)g-UlM<5rq,uFav@0_̴B 66 4b'&lHjc/x̥<A~ÏL2 YsX?E3x׿#7g^ڹc篺v?J8s䬾%qбTuZ]1IKuW|W5y $026zDߍy~G@5 H4Z#YK3 0m, ,'-ԘvNj5H }sZH93cam Gu"E|ٿMIʔ:TOfW>mK00?QJ%sf'sa֍I)r C"%Tb^:bw../lpyGl7[t}DBXK->V)$Ԁ"Uvpͱf]Qb"V%Na:<퐺-vP HT!#RKKߘok'⟛f+[ ]d`&Wh@O{_"4.pEnLnfX{ ϓD0;-bT]$ ,ᅭnӜҬ7W\jKr5w"(!9`nFSJDX:%nQIh#tia6ΘO$6nגk{fѸT5)C}]d$ N!6\E-$o̧=hTHDd@]fUs?EC"A,.tܬRJN–DxG+[3O= MȒd t6 w/jǝ$W]N{q,%Ј#M8lˬ3?wkW9X*S@x'}k`$X.޷Կx_d^vB%Mͪ4IӀ%? /N)<='\*=@ A'0W7FH"d=ǚ*١RJt_لU vI<ZH'wלk%}"WgO`hOGBAE)upk3]~Leu*Wqc`1.v`yO.ق-r$!#gqy,ov-7Cऔ1ԢgQ"r~&UՓ.H%DuL=d_T+B-O%N͔Yj3J)gdab,ZEg)35 }=3,c VP HA:ɣ؈W"#nP8rϘ PfI1W/=^J mRKfK#5 ?} sєMh3vA 0q;G kk:~VgVUlʶZ=A UN`a(_}xӨ(/ayAhݡ,.1s3b4 \vKvFjrmQ*[1#=.ɔsyФ$F<5Mgɺ==ItӤZ!3bnyhBqބ7o~9D$.[AePguR]n^j?h.nѵT͔|6x6!u>V#bGt!{&rif\)]TS[2w4M΂Yޙ(y-sPJp,ÜToB4ġ4ٚlL=.rԐK&YQJlL~7 P?}8~,q;`\%صc[z%@rkڷ2_E_׾_-ȸtѼg.=dt?#`)!ʯozΔ c?gOaG@jˍY\2 "d"Np_NYŢ;YOHJA^wsRrK8s{pU'܁H̦AL`QKU}H]o&8ѳ#Zq4#c{{6Ʀ?C?NNȸVfdBрbX;]'nR0r$RJA_|}M8d # a"ɠ|RDd*2rP-jCA! C97~ڜ\Q/oI u|(zyN;Aүf5K ҈H=0H&Cl*VKC$Z$i ċbDv@yd∹R#N"MWa(p??eEᖩ@rr=7!%bfslCQuHd ,^8,6PsAlMjGd*vh0P4 ucmKYƱ´M6lIc>!Q r6䘏૿glWQSڹc[n)#?v^>_:wk)`ؽk7GܤB[> @X\'ӎW7.n@LbKTJ@V׬^3s Z&ׄnuڹ% BDYC\ew(,EۉU٥t մL 4 DrXOy*li1 Ք.BkLGSt8pFO5E +cG^p?S\a㔕XžWWWx[n7xq7`%/y ~G~$7+Ko&kKD>5M){=Z#k<.|X53kVg=5cYf|=oo[!b0qZ= gAY7In`3cRXvc2%Y I6\l!+xIo_Pn)%I B.RUҝ3H8mi-Dl&l!ս@D;KHRCǦ)cGB0&І09OO<$Rˏ IDAT 4ŤHV|{ l)A"J<LRtO?sşx!?U礂`q>'ߧfݰkp4G*X`RW|ڲej?ħ*ms K45o3qIOōG@[oA;̤%P;ecxÐ@$y' Ʋdg-o]HmB=2i,1-T35:iV-0hd,L;cP ZHMQJxb]5>?Њ;Y} Uߊ:)2D`ڏ -8I& e 2#Z1M74kUʘ' aB(4fJdAُB Ag~Ti8\޵I5kTQ͚?xG ɶc{=:бt(9n݀kkSyy鞧G?Q_zu?v>p\O=xRHv10 o6;$}O{Sc Yb~[ar 77nU2K&Lf΍72 =BA2I/!sOY2K,HpAQnsv4b?JL%ɬ0&PXjsd'֙ŧ\CJ(ӄۍ()F<#+/ `؏#a"R#<"2W b5kg@RDŽ'LN<1 e/13Wӄ_1O{%Ex9ĵJ97t3eU[_ {-ql9.zɕz~cNs hPцyEqJWG-x)XmV !'vzAz40 eHjlW5%R%WD)$zd! C_fιjXHRfh(Y904BS1$n߫=jJ\ kx -*ڽ27f3p 9^w:Fxᜂ*n@HKh'4&j]bϨ5fd.QEi3r5S5B?i  UՠckBCAڻ|?gGn8ˌu5o~3[EzTqK:-? oإ׶rK` ,\w>c/>^у//YEcoo.V11?~06!k֐2?xާcCwq:pr*XSsکs, w@Mk`d1F';eַ0nݺ5[Kϳ^{`p][z|:ksԃPoX V_Y{~@h>xϤ?3>kJvBJ [GJ~/ܔYfj(*<ZXirQ =9[f"YV/ү0+8eJ.f3h,ưj=/8pAId%U ӄ1OnzOMCiP${LZ۸sR. pf -1.+Pc[&u+oM)LVb{ { F0HLGhf`VeΣFkgIlڀ9KBA! "T10@ %OfUskƫ\2^ƍ+mDAVTĠ"ǥI$Ѹ7A p2\ҧز^؋lۍ2k5{P"gX@Z9=q"B@r^77$Xɳ@]MZz WsaPkQ#Pƭ_ҏ3$=9l z Jds#2 R*A_y , +bh |9/2؝`@n>N l=ЗnMɩN9nR:9S/]eE̼]\\G5yұXW`v,}H<~=dYv?C]c0;XT mcL|.sR[*Yƭ+@ 5#TDVSj[Iεzx]YT8l6YjW4G,34S$Q%9?;E q! 0v~qJWv}evD. ,X<)o#lQ*ܭcCO' ;"kE8{B$xFd~((0hi SMZ<2.E|iZȂKCnWB|.f I*J̵!|K_Z#}{ꏽ|]ck1,Qb[Ce}Vw(s8Ksm+`̞7y._\}疬W^j#Edi*C-_h. ;ƣp5%oà6;1HdRBHicARF`DEF#NJe1iFLgۗ!1a0_%r$-O!,u !nf+{6 5^$FIrσIcRK-\ u/e Mhq*{k ^H yYAT`1%?Abٹq%>WWzIF4]'8ZO~ţ qb JVE@6؊0T9eƆp{M2: /vEL̕ZҢTT7D_ ŭyh³>fhLf *o܅* >jfEXS9GEg0W.;$uas˕ fB@ NFhZԤD4AunUr'w6XVtJss|O?)){Oؚ?3?3.%:@rXz)mM>vS$ @,P ~ZϻqÀw_nJ~ZswXwO=pXVvYE@ZHBj(ÿ"ΰ3zirE|<,Gmta6:DRjYRaOPM%AޟK?ڷnEuy󤢻\]/S5R9On'ggIaزk~wLk pM1bYEan~I$dyn`mL^jX\f<^j_ޥTW.m21ՀIr<`uC°x)1M!VY h8+PL5K-[CVw{hZV^5Xe5JEn ]kjbIBRsCrC[5C5 lQ%1!k^1u15@ ⶌ g݋ DV&~;Z͑CQb8 L* ^|k1Oayͳk 5S2tLjlLf kn4:#DMLzm ְcjR6͔i5f&)nW 7NCkqeQeտE0۷oj햎n ^!??WB0>^vl{/m>cdiߩdM_tNk:0DNi[ KDov|__}  ĎkZ2a,{?=0Y= >o}Kx'#- ]s׬r:TQ @YQyxA~:'V]*KFG= ka\}Aɒdi>z6KĎY#K}15W/u\9/uо Of_zvVfE)ؔuVBh`# cL-+#]\ŁF9s"je~LvI4~@O̭ROy $8UKS08fq*bIn[^ܚG}Uͪa) l P P/aHryvGrv#h=(F 8ń@,2.+ 0<^,=_VB)($i|(m/_~IKOUҒ e/CKKI $n$@@ĔĬo`vTq$'nd`\;mV",VHL8"k 5 8EiY!%%~.rXziaU9Ka,0nDL (|6 u[(U>MkQ ГA[^ \4ocj 3nZf%ZvJl DX \!3JB75pWS-YB\k zWeHMY1t*xx4 KB9ؿ"ɵngO<..n}~~ ggg_6I,ܱ,yK r<Qi' e( RʒU-["#ڜeέܼۚ?kDx )jk DƤ@jyR+j(=x, Z,Z`\G+8!ma+,&Pf JIA3#ͬi" !F0Mß#TlJ0"9(>cԅrMhc.bT%uLEAH&1fLRRgtyS*!ُ:F̒oٙ,OzЛV+j60,&Քš5!DX)?bFMMhnjbZΥTЗ&2`f.{ (cSXnlx؍sdCZ1卺:/O{ӏַ߸i,{R8Ym ;ys9~׎kkw 5h|KϓkM>J'\7Vkϳ?8!`kďBZ}xs \k {f2S45H* lI/1gOĝJd&"M`啶q6aH"sLðAeRRvC(8ǂIo6 b\[MzGcO= WHɪW z;+- 6kq2W+!ċ'1l7@Q]Ѓ~0dP<$ğyp IDAT, iMC"^|j{a-dE,.-vDI0NJ6I϶պ)\s?ǢFDֈ XK,_˱5&^PRɞ߄F_TEmT-Tje*pAo A]cKZUݪ3BvJ[bȴvBU7 =xxzcN9ö=b%K‘ z!u]b>εpvJc ĥwx'ol.s F}/zXQq֒+֒^@ȩ8ǎ?ۖ~o0/~ݳo@/D o|;<Қ_K@@}{Y9e/OxMwP|6>WF[OԃT8 0܇MjIZFDR4ٗ%|1<͔a(I#BbCU*K1 y)W2aJb'8TyxuL q$iHsuَ)Jha@'lĕa8B3mna͵ya-Viȇ {!i3`$.Ҡ s* vbjI &gFH[V~'-r XV7DFTyHcQ1aǥlTZĐ_yۤPLD@|<53O2 Ejȓfȯů@_?gkkX=Mnw"N`i?ur5Kn%x;M-k h F>GMO(EI-#d DuNd*!b3#OY-wBQ4^#dl6㈢J%քY #͵Ś69wajI3*g{g d( c\n۵Lhhf*3߬ (mkm%c| Gz ͣȷ2^V`Q+39JރV=|C5]nPŕ8A5K#yY  1)ƗDyid4TZr<^39݄f A ,(ZH_B#؈G}5Z'R}uч0M%H&(g# J,H"Bf̾, VgnNؘkݔsQJX wjѥ; H6iB*mP,y:~tI:a5-,cL.,]|:/<''5?v_wͲc岺ϼ2zҶ./O~ zיޔO,KY Xnv%vg!^/(nsF܀'+p3HS X0 l@!dB @L,RCUzXt,(܃U@1& dxa4fv#6-xa3`Pz&uHzIꫥ!XMqj Vʙ & m?qaʙV{ cG5} 4 nKp֕Vg\@qX2vjY +UGNVpڃQrjB @YAS8fgp֘4W/8y40i,tF~!ACHZ5#>{P$2]yO)YLDɌ\Ӵ0*džZU`?`6^:I0kY,;4˒hi <ȉ0׼εKSƭcҝNPPg~Q6&`Ѧ o,#p J==O?= YrZ%Ǭ"~MX+_Q%ܮg3ggp>؆xrzhsZ4c䙫o Q-/V8ZxHF"bIb*(2W;+%V'q7)$CU_r >f\co 4΅M RerĖe,T\9k {y 3K<֭[sN-C!_rj 80bq v ya6`i+'-J&G4:"=`-"V5 `l@c@$hZYq/x%os`lx qHZJF RGh5L, X RE`Ըe  5kZeJ3+IV K˜VfX'hrK)}A;@t-0 Z{@L5FЄQODBXSJ&i{u2A>V{LW7=#@MZ`ɏfCbn: 9sf!?E'[BNqɲX(/hx ?c^ Ζkn[NP?k<0t~5p 2`I S/&08V+ KdOTWD)EDw <`ky1ݤ14!sdL*,PK`D`j^%LÐ` tRJ_]H!⑋3<9\Dn8%o# syuɊyxWUdԂ\<^jVNJF=ܬY$f (Ac=:E 6LkMM*N%I=frYz U$*Tg'loDjb qQ&F4_Ӻv̀#$[Mġ-\&֋R] 8MS0D-7/j8DR6/"'@Uc,q Ԁw'3<[h½\2RUL:ԊD3jh?Ȭ" :X ^}8V .2iv:Y&DcN.ζrH0%x|04|T-g p%*ͼ 2VcO &tC-xMǪ ق%"CB-HI51)$&Uӱ-n8??aJ$1.#jY?zͷߜPl׶zdS(m{9hL%F_{3]|< ?Ǯ60#htsVHQc¼KPw$:kV>A3OŚVwV+C ' p Hau{_<]uֺhš8@K1PebU5lA'{ݯP,"l:H7#g2 HThE˞͂v}"3>,}1gzK1Ptڜ翀/~ xɧ}D4JCu2H iȸP1su2`~k+sw%c?}K[49*I^u)/>'SP.R8ˡj֎f<;8lE]w#jq"0R)>Qs=kexUqy2%\]^%R@,9k,fܷTƵt0+ˈ, -C'?ېkݲyF4Mk1"`"Fq`@f>Fd wXLj&U0dX2OX+QE j%%vZx.0 c&6Rg)H-Ơgkc9^h6FZΪ$p7̪s2=p== =h:EAH;_گ_{ Xmo{^<1?k_:1z ^݂;&WPr y`ڱ<ڻ֎=J 3㻿?UX_#OO8`> X%`c{ ݳ ?~SJ}LU>p`N^pTѡRz?`ޗL aPBYŮ%tGH*w QxUQ S ~G4SԁSTSQ*O X[0 17 JDAlk&6o^JAc Q-}Prv|:%"f%?u"jw%JRIR t8$AZY9( 9ԻPa7$p: f;ٶQe R 4s1TK=:=@ G;`Z 2hFKe kXLѴH ҕRK P'r@lz~.H> )fเ]}AZmz{]gDOؼoَvkArJi4m}k~iikftӔθLjnfjcX\Lض1zt܊e!5Eu|zURA@L*u,}#koiE q>t`㽂S`uڶ~׿j|BPH<7DQFx{`rR13O5pH:MBx y,;*r7 8NXDA3hqsуC"Ҙ؅˓A { FSt:4ɸ]맔l~w`L i\2dߍagWgm|*(*8#(GI7v}&eIk.ߛS@q%-k8ùĉe$k3HqB=vNX:k+^uA0ZL}N'W0wh> M`t6@OrO>4YwW_RT!Ab3Z)=;m7&%U#K]Y2Dpp ,=b!I,F茴zdwv:c1; V3ƚcߜ'pBdYOd_ >o̘Te0kZfF|4^Whc 7֥|FfIoB / oY!6~|l vo-nvp@H{yT0owkKmuI+nv@A%+G\Kd=n"&" i& IDATp> l)dLŚ c/>\J|nu,fV,};vg;>mW R&3(4@AsQݚW}%v ${5MO 9OPjI/$+`=2{Ȓ0r#k+vM (+mD31pq~ꚢ_=%U2aٛ;8D5+uVdEֶcWܢj- Т* 0,k bH.^/Fxcf,mМr* SĜ:$G.rF2M!=7&ا굠iFP0Ǭ0b45׬耎hڠ~)fʦb~uT+UԒjMYЧ 3 HfA)$-4gzE=_}__vuV)R'9hkkÀ3~c=B[vl{J{ ^}dIsS0ҟwq{az}׍G YXo~KK`<g5|\ _G~zܳN㏍=?>&`x/v!ٽw(U`QMh1 8jqVfWT!PϡZbM˹N<1Pa?P@"n_1Z:sfrД3_ePD5tG~܋ VVO6q@ !3 oȐʸЬ<@$Q ^(^2>'㴯? x\,C$lG"T{$gxA6lWW/C-vH!@GL!7T SF*bA^pԽ !&$6h1қ0v ‚ԯǩ&0fVZ!7A H(5E,|$ayK 1T&0O*N,Y?lgcTP0ESPkj؊G3!1J!GXWԷ54(!B)b3MЗ?W$/^Sf wB X8Bg4jmr2u<Fzg:͌Ҿ1~ۃ>/M)Pƿ翋:9@07RK03^W}8ulT8 a{#ɚ~0m T\oFsNגP^kcb_uO]xa؃z^@#0fy]<}>"Zgnm|[Wa?[on\ h܊}«y3E^#( f,RZZ<{^8挈TW% .*/Th(lE!D"/P؆x01%}/I3*S OӄŒfSv奸, )X9 |)TY֙ˋ$ D'E&PbdrU{w;ZVr8vEDc }q- Wlwe1i?^0Z+`cm[kȃh{ؐz-9_=[}w &n[|~+~w~gyNz*ָ>~H zFAK>kgqyyV& xTqkxa2<0Zc= <Ȁk橥-DS&I.\o,{";iy2k|&3cFĘj~?"f# FfSݮA8+UڪŦR3h<,>OZ2ۤ Ӓ5a׬"=F,ʼn-~=*H4MZ @%r rDuBsVYY|G㐅-ko9ils KO߳Yi—s)ZPܨV :Y\Xtm"{m.Mҽ@u(}vv"h GٳijZ Cf6^f@Sygu65,8"%y,nLw#XEiYVeP9,S XEA,$!v@2QYyurn22&@[=XEC<\kuYE"߆@bJ" $Hb y"cA%-0 AlڡC wݶZz)k8!X bh+Si3H>0`nRlXxn7EMD!Xf g6:a_Ƹ2%uq߬29#k, ~6M-5KҐ+% s6AE'd Jl̓퇙_Q¥ E&2~Om[R >v4k̓ "l׿ŚBAcH;l7۶X^kBze "l0 6Mn,xiӔRcpݳgZzU0 >Vit A݄4ېXض\0`H\-yLM̳gyd-QLRUנ*),'9~w֯i+7߶^k^x8"O:J)4GϘԬC)&Klr "≁-j*kj~tY:9$17AZLeؽMrufRf ^x`& 'I`_jNA[ M$܊fYQ{.Lɀd.O:JRTBW-$i\DWBG(s$7ٵ4W AKjs}QKuoU3UDfYh7\۬,kj'r'/||]ŅkzP@D[nw@57!KBo BF[Ӥ]mǬo w|?5-}u}~ǚ%dW/~g|Y^ǎsnmEpl Z`==ZjD;RzوhCyji!7 _oVܸZ 7fF"UR@EbIwD\D]*JZd2nt1c:k . ,rO(R3hQ=s1/1+)[/[0A>7UH]W+﫟7-hhdپĵmek)Ej=@>LBPeɤEq@xJoqxixJX8qh $D | E{kan2PT"`$,FyWULw*QtSC6Xւ30O5v=X̷^:' H 3! Cf3SQ[fS% P3ZA4ijՆyQa;q&M,N.E<IĴ6+H҂P@Ո ?1~fU5U P 2K=1OXO*,͊d.jZꨰcBo!m¾$x4zPᵄo7|7/"K=@NSwm۱@v/| L}_Ʊ/c]Zs8ȭyW߮ U}2bYC-m`}oȱ}Ka[3pw6yr 4KC8kYQd* 1ZNNrh¬<0]nۍ C$nd*|`jwU!TИӖbv1ЫQwK ! !a#D8v C<Ȃxߏ{ޫ?rYs[}o[XZ/L&G,VQZ}qܹs.ψ>9?3n8H[z%DG$"dUd:eYA1ڊZ7ȏ řC8ЪDJ9$5@yEjl7,q?G`2QHNyEX !_fD f2N4LGa4Pan D-1)B]5[Ҟ؄%">e-G ~PlzZs)&ՊV-" PKAJJڂ "~ E-5ϘQ?D 8Z#E5kja^ B%vplo k_.yʠ>WW6q3xZïگA}Ԯ`:puoH|-A۱αν( DZ{Sy^[3[9VApBF+@ڵ2"+*N)ⳍߏrmu`$^knPX- %BiȬra\ PI6Z 5D=H\˲ e9tRU!.B('eU-BsI|, Ud[f sUhEϮ37c<.R AW+H6dy`@dnl6MY2F?`%Ci$=+ Zm :1 B@^H&57t;6QK~HӒF8MFBbfZ%BI&G* XJʟ=6 |67z E0}V4 RVk ))K.m[paqC D!ihfov^"qӸϒ 0ƨEL!߄m;A9wvC#k pۂa#;:pY/pp{'u،i&o&^z%<3nk1Z"rObɌ.$! C5_ f ~L`50l!1!zަ%vRP2kQF REA@ϢjOf mqs(O<:8p$DYkZ<h Z+Yy!XYxYnlj2<P=^7yʰՆnNxϐXRz [d+E-#1a5{MR)T`BOp a, љ6kȦ)S9 5mcz]?/+n ![uXɞYH .//++'F._[׈ǍFH}ۂλIȽ-8u@m>~7 _+A} wރY9|$i: $3ص W̫Lr<`Kh|OIIrΠ)&?d~m9!Z?A|B4 bγjJ79K_*,jvd@4|SjYhG0: QF$QUaԂE "i I-=.4RBmw .6 ;@007I(ሊ&B'm/GFefuߊEL&D:8gX%NUꖢ8"ؚxֈȂ"]4Lϵ35/2>g1=#ȑbHDx뭷=Myf}q}nym*_pu8ؽX;~^F,[:#铟$z)[W؜Ѫo$)|#[G02-_וsѿ/l`(%gZx#FKt=4DtE.H,!1 {pbVMSZ FR@Fs â"hɈ)!׮=:ʆc 8M`߯(7QLPB"pԪ __b!uh%9u\ݻ9.l{~}{v /292Jf73{P2:oZy5b|SBn F@/3,%]N& q'*>+OYyId!nU[c$]-<79)X׃$4R]> ;ù*.- JdDWa^宜xFOI"a^\^x<NUl)Hդ5ٙXtTiu/_Y+de=[9s'帠.SʘH ʡ9=,Gkܪ:E wWer@}絮4Y([F3AآaM\>>XYDED߻5"9-XT#x,5  F@-Λ"D(_NQW?R&a{W[W!ff)E*`iMugKZNLsX P8ۍY@(u2DzX`׀5ϳh Ha k/^ 7}tMT 9v W8@Y`,jhͨZ\dTKI#l2Gs=+LI5W<&Zi|Aaƪ%ن-Ak(5 }-[o~DV|oƹ9+\ݻ/\'2Z9)o[O}~ٲjlV9v뼛۔</}KWXp^:bYcV-_hrV[}o![V-RFD<o])뎝{?)7r%y-!9I M\ϪJzr27DdK9O=wyw1@vEEP"+ +kyypM^cjÔ-!(9g{.]^~KuwNƠRZ`䥔$-uvh̖E}ϽVU#fM#:J w L`vAi*=+>#ȽKs\#`a{4rueQJ["{Z8mDZq[P 37 Um@i*ڢ@P.*(M<i":7?VGARME|Txrz&crDZ]kaA/Q#T_ Q28uM:vQǺ=. *WΉB+ivG'f-KȨ}[Tx /ocMxDKʩA*FB{q{Yn֯¿c-` Ĝ2 םs?(>~lQ쾀(,EŶ9EښߣBj q~"I}E}svZTx[_ .wxNVvDS/bRqflTXU۪3*|0~UJgҐ'kdη&џ,I3$dROȬDݗ(XOdLgI,zX4I|E/U@)/./%Ik9O yZC#BNj6%L#BNA13yvyu e C=G(5`G uQB (MrHi Qw!6s,Dk-M+з`bj0uY`0RKh\DtH/4i" ȳ5'ԱdJ_}l\h+Ոj)e.YD=-(Fodh@3*֛{-O}WԌ@_cGqA o~~n|#Hxq^Uoho{mrpaҐ:iKVFw[hkv_z%o&FFጙWyEǣGٳhN,7u-ҳǟ_矓ߠʡ>zo+p5~mxk;fuL6E{6ga)E šP{%oK e;.N\1Mt_&KTYp<Hg%Y)w޽{P&r4y2b7PkŅW3$8D;Ih\k)g4$d-9uh{Hf$QgT,ز<<\^|D96\.s7 ?yDLjn"I>1AQ%(V=4%7H ,"2t05F 5kȧ堝AJB*j8urOKIʂ[a&>,j=h ee!so|!°m)klU`:eA>?EPnSGz-鞨mhG֫c)Vې&LLoD͹u8Ca06do\M^HQ,H:>Yl<&JIxptE@<]wԲ ר]v 'oe m5|g2yz '(09>}N*_X$+\9~SQH?U8?m}w _v\`$FβRpvv~ x\uj oc >{wu7|יTXlOF! {7Ry\ZU,ѭ, ;L<11, VrK)O=asʸDҧ ǂi$Cۃ9l4pn u0%sN E| p8z4M8E,H`Hf?s&H;7n\Eb=0ԟr9{KMA#VP `Mm}*A ^zD3xeyC\J Tdr50) 7Ȓ`BPx\KbhQ!`EkZ5.6SJIS,“Q0N]rΨL`K:͡ f׸<D3ہ1gt- Bʹr[MJX:]LqSlieج$&`Βw%N@m_3k*iR RII |q}qBZ_lDլZDڭ +ݚ 6W耓?O87ZBF˨ô|^{ mg8yKo'qRnc9ﷱP\F)P;%hvly#=߃O76)9)Z#(1R:g} @lY" zvv||UYd¢^ HqАs1_rcU%Ѵr{S$KQZ4H wʰҊpi"Ԩ,XҨvJ)h35LN_7*Zqyy{ɱQ`p8!wL6ZuskUk"r_yDۮgRyzA$k )MhW~A@7 ( 겸I6*O&4s}\ʂ^Y9Ơ:ٱMtB׌5`S({r[ǩco\7[|D&B!Z~'~_ׯXE|E DJ<(ZYSxeቿFn4&߁|_<$ ~#Nd @g@@Fd{XP}&tH]3 ߒ/=hѐ`̍?")ݪi`*yVcȔ\Ҩ*G䈳;8wR:X)!eԆ4'A9VLsB˱0adVuF.Or8fX^2sw2n}n737 =1 5&#@P;¥XEhˆ|Gt[ _N$MnYԮP@R7S^t]yc(  ȶ8!M2 ̔do,jJHW,ju8ćwH(_ĽSmʒWV\lMhWЀESSV xЬ%*1w=4y(YhiB&Bњ4Ӟ̲q']`[iܒA6ƸNu5ɳ[<#'kc` F}GN2(BY&ѺZLBhlV,iD@a->bH 0uW+@ch]ᦂW`/(^ F_ߘо?y,jQ㎈k~n#˲`ۭ4aggmٚݢ{[d"F{mv_{ &J{}=Sc%G8+Q1TBУS<n?Drm\Պe)4C#蔽5RT(:~zM2ϸ<SBw;XēOw`6rF$ boAhRGLo },d@!@f\nwk/kL}GMX]Ȳش;@0r\|L5fI"@N<^@'6@d&RdufRuѓ:,56P֡{ ~{hE&P2W .V1jD'z 1/} ij![$>(Y]?z?e׽jn*7ۀ9o[ zp ]W+%p.3_߬q=+ykghrXmr tm=fE0r A)@buz$A,ɎuGC9qK9W0Y5IY5uҊהh6ؔ^*yÂo5 .*PYi;<#OҮS ž UZ+ip֨+0RS:R.{zckfG'tØcuX4͇<mr^{On*E r9$F˵'U"R4˽ZWR;}Q "p 9"Kܺ!:4D`WЧ :T C}D&20u,D/$s(![@ 0)cgWɒ I7*-E┛i6,ox^'m(ϜV6J)r5 $~0ذ(KsO2X)դd{̒T$ZHJ*SJu IDAT/h) PQ#3bШiX7QyM6NAs+q垸CN@]-A98fF0* /__ N 5ׁ9UʣM@[ Mߦ>-Kx(~[[Rb(w̶غoomgl^@o[Shi|>QU uYgr++>J: *ܸkI]Nde$ J8*@)\ Z6օ]QkՒgԪ<6{)`C4CۄH|M8 Yl eY$Q$deL2HcZlae27mrG =v5Mj(,$lD hE lg 'ХA`U0RGXpȸ:*3kZauW=d/wV*V1`M+4F)XL ,ňC)I$%.)D0ȉRO$@uЄ^ qƪt=/&zg"i L';5Co $j ^jL coX=o\HMړy Vb,[`^#YmÖ5Ou:FLq4Zg}O[H eV!* [zE#=-%)1ZEn/M+߿?Ga O1@]LЍ 3a(QKUŧ a厈$Hh2Bzkj9Dq4'9iLaar\X5e$*eq0[Hm1_hcΗ=_c,vgy lڴ,%^g%k;o|+KH[Vq Cvv8O駟^39c}w??*o`^\F>u溺[3"Ug>|k_lQL ۢgE8)w۾n ["ӆ\vk=olS=H#A*V[ZZ Yg9;&El [y2XZ0V9G\X@`eAt+epuy)ӦZkȜ5'Wv\NIPZf$+ѹs5Sθ<P9ܞc74u+зq+)3 ԓɬ2 L[SJYKgX.x^~uTpQ@aSJs@$"~f0,1F}3Cu(ZѴ'GA6\SO=XM;E9<iڡ`a+PBH#?8<\bS'ʸCPv[4-ȭ5;II͒/n"VFQ!2qL@&"C_Bv^%A@mvSL*=˴sDby:#;[jޚ? ads2C37 ,V_q@!e2f=>Dc|&Ѹٵe0]i$g;/oȖEdtP*Q)Vkٟ=y;QyTws =:g[e~#^ٟfѳb8_ӳ Dj(a T#~ @XQrW@YZ~)l@$ o&R+uzhiRޫ:-,B&U82 (D$Fe$3ZkhDD;9FUҢC- f6sZ&. sjV--nͣfԳx/#ܹR*RPw{LQRpDk,?uX_{l U ,#gM,p7 3(_\eLI维A&YkZuE}id-{.lh? f{u ^XCNDgĖvp8Cк(D&q]|qmͷ~ hy1 ն}CxꩧoT>igk DeK11F|Y'd%cc)=qcG{/'AZz TPQEe:R̔elȕFꑓX>K8y{j4g16@ 9OPKEm7(2v 4ڶ=gJЬ!,,3*.3wr2v(M#oF"c$h_)qݼQ=T8N=ܯ{\^o<˭ɠu|&I*SZ IHkU6ШP+CUއe+ L=zO\#ؼ_ nA/o'0 { 0F)+8F@qFAys6m>c)zYE"Xn]7[ϼ<ׁjZ|h "WiTN}7;/[FAfx1 ?*+-p(n{۔(pDkkϕKļ"}9|>6o=﹃gid>|I7= WZЭʠao+s"T.vs1RJ6 %uOeJWlV+]IQe|i(R&?ľZe"eC3 Y,?) sF=QDwJƫ_F,ܘM~ȤXdV,תI9; ̸wt?'76޵1ϕ).k8X2)%DF>/8' ,HaZ{u;MVkHHA) `#B!Ї^lܵtKES~?_Hkg,޲Z@5ȶՏb(.ʂajzE**OkmQh8׈@'s/%xؤQh2E+QVMGXxQes=A)kXhy#VF$#h--l emB.iMoaS)|oɭr<ڴGJHW^y??XNMxTM֍w[n{F!ˎV+f+⴬ܯeq ^ [OY6F۽Uqnn^>,/ҏ5}|ߪXq lLo'[UG߳Z '@\3a bt ue2ZEP D`MNAžY>40Ř?QD޴Eַ9˔zP@k̵3[K)S ήʱUG*QL %_gMbܲn IDATr=.?Jnj鶯:0V駿:}<5QƁkxB^\!}!ZOdȩT8 f>D3RNCBD݇Vܟ4쓤!^L@iuɢMN QfWQMكEvz`ymϒlv;c#25AT@HM[8SbL0U£;r&r REuGc2s%V($ s<PPS|;wp'ٓuM{wr.fQ@K#qd*(}_dwaDBqBƂP!M-H{)AVy@$.Hcx0zqRLCC5wqcIzw)KnEa;(L9# h: 朽  %,QZHhbujln؟^31cbk=b%͔r\k|*yVyny1_ER-;ͤ66Zb2,F6Q>'˚:, lFo>n4b8HWxG>kYE>oFTyr-q x/uﶬ!q4SM;.:G &F&@u그>l@@cV73կg~[])zt?lmõM9e[1<Ӕ2#ewBѠ07] 8b%% @FyBUmzN2``kd{lAޘǃsGi/ѩRvyy)묙9wZiH2 u'hN>~@Sn|-rzi $)(@PoD*ž<88k2k&{dJZn(!E^+?"G-"L0 #IX]7O%MD0@=_Цn.TfP~_iZH ѸyKhBm?tn,:i 8j;:1J!΂q[bbݔ#$Ekp_WF A*wFl}Tl2 4ЇV˸kE2 ")!?oΧ~ϳRm6t[02ZE^ ug߳.&bHiB/Jɢ'/e'$T'pd2%$fUAӐG 9Q=o9 @j~J"L6f$_I[yqyy:J^J=b1Z$z"-݂f7ߚ=}6fZC%- k_ 2k39D>\םӴc'w>). dĸ!f~aVr}k M@]I^F a5!u3N +G>TR}*+-|Q(r5rM6-_ c^#h̓`F,,#[!X]yč_??yelrhyT\"n0߫cx-=7yDF5):;*®ozw @h50kYYk f¬K kM*Zm.:J kE"hLYõ;@a>{L*7k(*i٣?(b/i@SG͵vam݌(kD@Np%{>;5 d .mp02jɆ+Z!@k_x7ozōx J,G$oW8F@{aSt{SNY<V ?x}sϭDLn#Fpc 4ĺ[0/ 8ejC+wuDs]t$'tpk(*6Cz#69W3MHw?VE99Y#RRIhYUf&6n^3桑4M-%"-tPdu7Z73p,NU1֐x5*h-39wk G2.T j^ǘLz ݹ 5+ n LxA0wy\2vPU֌vP KJ4-вG&i]<~{o Rz~~fIv D z *eU O 952ASRKkVtH#E\ `sUCK#&O-,a sePxP}"1oBu?8<%1k+g,Bf eB"(B}Y,N1v];%A&e$>l#^AY kG0,&gfՂ鍙ݼj<)F4c2E=42p4*@u-6PKj-Kj'.l_e>&8&4CE0+Hn/U2dIq F Id7t`o+ zXmq6lT_ !z;w~_G~GdR76*k FA_ / *~XyTrx9f1(O?ͭÜVDokV]{?~7>sn$c}n_~Ut5ƾN@)@W@ _R $uØ e)pCQ@ cbȍ/0Mٳ'r,>HĪP$'rF-=ӺU`FYu3R؊gW%{YI> m/֩O,[xױ B DF%ETC?{o#I ~OD="kɭv5MN70`6#1 LdOIdrpwS7SuU3ȥR""*8J +O'Wp#V1`q]_ʳc `Y$•DbX!0'd 暐$1xPf@0VJ=Ҁ4"U:c T ္U4 iZ 8hELND@0$ɒ:ԛdY5nL L8ݳHF0'9NR& cZA+w0 k6$H K>x@)>~E6@3FHhԥ,ASዶD0.fPƨjʗ|,ir T(9 _"Xr)z`?*%\oleV;c2sgvIRcƝ AB2,w 덇5ϋPך@8z[kS<iE[%)|~%:&> $mEL3X zأd }!aelq/LHǞF$>w O?/S{"+k} I/cL;?%@"1 PD5ojZSI*=`YJ] f{2Q }: kk?E;; b0ԉ "H"e%C)eR۰_?Gf} 0%aXQAPX)#ge_:d:&]m#dɲn!8FiՓ眑q!gep3At|q e*?#dLWx[Z1@p [lT%g~{uHR>@j<[vBܶV_U# is.`IWf $iG:ٛXh[ZAlLMI ab-9W#h( 3X6-4#^Y6s\$Tʌ6XkLպj)Z45Uc°RL}6i.["[aZftHqV-, ތ5h\Q*Q`Bb'?^& f(jV 3,tWdtTQfdD~Ưo-k "XFRb}3իWX@W3#%[s'?g} !0heD4"k?Ks=Kc]}Jv%6jL2?LͱB,yѡ2厾,$giA]LoR=!SJhVu6U }c$ 拘\Ul#jm8N8y Ζ=E¬X<<̢]3a f4Թ Q"%I%o#L#`)+EpQ#w;+je|xSzJ^W:^Jڈ!\Ba( 4 NAbQP}HaM KC:yzw2DFxD@B˜j}0I*2UWU`[2`D(ɈjY' up 6iI&FH=MdDA JXl !m復&e2M={ł.oKpDg=%]'R!ip ON HEl5E?/"j4M#ͱ(ؚj?R"Tnd"An$C$"yN$00e081mr0o_Y9u_gmiF\Ӯu )߃s)û)H/6zؖ50bOJpl[y8u_6ǹkrK8o? qA|HR|Cvkk}$D4oR6geHY0XIYPm$IvwH5絏I3T k~xJ8'T[Jxi1 PIRԎ՟0Dg*V%׌J d׆i.(Rܽq8a*{/q{9=w6!df3 N$Ģ vi}qjv&@gu$ WJIMP*7N̄B4A M{4kd*)~m­l12$*iɯ5nf9ٻӈ*9_p*zgJg"n3g^=B?$xOad IDAT/k[>AC AubFP"N:@L$tDMVB3_,|";'5o q@ &43NDCj€e0k{r|ۓJ4L9KR.{)IC)n:7f0Fp %I?ʺ`ؤZ#߈,enf"h+^iօ]ņ~;7yD0Įcg-N{Y}:5ZAmk1[`ߚk}5!EkȞ/i=q-;~]"XLiV r1t vBHV>h@ Np>kvPqxD@M:Qà^L"R\['>%J#E(s5jkT,Z/ 5ӴտMf׾&OX݁pwۛ׿*&S@ &` qH`TF0+0 jG,֔p+,9$Ǫ+#dpXgoSӬB9[0gu\K#o%[bX#PT҇zH3pZ]mfg `Wk0LP7ZN(KT!kozQ"VKc@7iH1'Z> LJLRO(NW2)¥ fF yݧD֢P$a ܯNkbFd4eM*H)?hh,|/澰K9*p-:aFo鑝i]Kɶ̲lYm-@p-Tݚ~_TrX{ /$/&0"/Ge}K~z[8ڼu߽Y֚y"p0d0w,'\m2H6sƐuqNWmrki @8hP΃tC$1QU P-`ӪTT#n ^wq&?j'hh,P06#J;qT\4x=XDX&CxtJˌOnnn/pssfݽG; q ,0INB<o427# _S7"XBlDd1ɣHHyЈY E"dE+F5 7p-h\H 1ᡩ$\0hQyD'by8do( In42DL&qfa&])@Q,d"S\ Vc`bCH)p8"aq7ϭ7u%j{TЛ^ t+59^cłf/Dz][ /9 LLi*d̶ւ6fxGɣp 8}IsTc#cUSU"Zq8QR"Ԇ a:Rעi.^!p ڔXk xp8HYEx[lDMЉS$!t^wazfq\NY-XnMgBD-ٺ.xB6j ܋E 4K^fe! D0i&%ᓵ3}cУ*..>Hza 3 Z=a<^MdyxxpcxKa$Ϣw>44}# </ (!(oɈ`9nf +踀C wC\EIg?[2w 93jDlF2&;eXxJ c? >!J4o~9傦#Qh]b izS4YCqkȇQB&SI(Bؽ8x˺'|%Y4 S,fpk3&B㊻ :֖a!+ @ BF4^*w!^ a4O&P4|e0j5R&v LSM9z*&fI9+{=xŋg'ç_(uY\ ",G~Ga-<CF?mIׯŋE=sk}K)|_zy>~ ޚ[okp> )%/|T5X\k_%v>]f\:nO@CD~>x$EP۫+R@i4%3۵k䷩P̄Ĭ<}?>}nKgmͷ7֪"lkN' An^Ifqt:M9S5͵kknq{{>FDԁmxvB[XV˖_$9qa@Hو`Hx'kDp3,23( CXJܰ*w8~H)%fVRll:"+4k#bHv ^D+B ͯx,WƃD/@CRdLI.PЧ3o)$,yVϗ0j)=6R@It-ͯbI$A",̪k sRmIJ#nVbCr>2yי{D-SJr̢,>J'9U{UkDS -J_-DQb>]zb%qiJ`ONL"cuBIԎI6իWchD3\ )Up쑀"y{)Z)_9_|YMzlO=or4k}osn=skϹ> % 9Z)2)5IGd<`Añl§=߮Uj='5ļ۴iBXӇ7 7Bdu1(VԂi-pp@H,D⫁&Iۋ/0>iLVIrB0-ɢEf[}|YItfFn؉vysȃ 4#'%p~  Big7 k Їps,ϫ +  MVP5kq3QغYZ=r'0J.JN| - 4yQ`̋o׍60 Iiƛ^#0'йԊLڨo^F'%y""<}ElJnB[rBEך,IRnbWyq$Cs:wXPf%-cX(Ţm EMz!CC-jDEo|OڑL5nnn6Ry.r5{]" 빰y;n n[o |lb޼Iv\}'`|^.,o/ 6fՎ'' ٭lo`V ^!)D͜TņٺުIY%˽GC4pA^Fg? Dįi09À4~p{P#$04BhZ_JML%'!E:Bb[zJ_Fh> eKIblO`TP3+,us,ib:[Fօ&!?) (4P՟<"6@Q]K|x#|wZ"rc⣄GβsfSG=i`dd!0AU͉ A_@/Rd>I (t$ L -,4єXpgy.*٩(EA4ѝSG&IiQ%ۦO.EB>zt@k -6|.fwٞh̪'Yd olK,~7;GƇ~tli8nsx$4\qq-M,{d~'5br 0z :T @q r\_{ι{%~R<7XbѲsR" L3BvvpǵPmb^j5NH 8}MͪZk;kKG!ӣg`hq-GoގYu.VGb1̨$n,Od>>JT}DR-xŢ"Kږ0YF>Tpj Mo~*M;0omV#praZO0~=f#zn=tŖY},%KȄE0"Zx0$''ipPX¢ )dl Pвgcf?e]gP`1-bfLJA} )zao6##PP1 ݴlJUl63 39(T C4d5Q9͒#Va1sTg,ɖL[(]9hU#%QyK!~Ieר02Ql2A`sVTt [كӤ}J0g a"ƟzyL@@q XpK+ )^ @]s\mo# &c)[{\Y=ܪ#fω u͑5i@ɽ{Fח&-I|aFEiB?60r6?N8;UgmN'{$s%ЪԢFtrSn L-D0u@!@B[$Z Ir9Jǥ!wgem&Y5nsJafh ˲EZ9du cSqqӈJbi$'`35,DY]*E@ f&NCOctt q;[ :[mH UP-ZZQD3bkוVCUY8VFk1C+E&wP dolJ)B*Z$+/xShd럌 cuq*Zތt\ ֯[Eɛ8̆<ms ]"&&{M 0OmGŧܸ;~똧߽m]k푏H4˲c#fĆ{3}\3ׂh%8 ~0gF#)Fpm;$|{ IB,?wS&LSϭi[ BGlĵ\!Z?i$FN4SJEIlh Thl̨oȈ^e[^ IDAT4 `.2:Ϗ (Ʃ"Cٔ2<̞'h5w9Kfa9x>\W_j&VfnPnnU 2í ,1!_i+*jhS ,b nb*/S^gKD@H`A,"d莍@ԞM>t͉%X|nK"sjh2jƘ͑sرݑ6FvM@W0uig"P}̌#Qc[D N!?/eId0ͳ%/÷QҞ%/q5a<ℴ_i^lvBhsFc&PҮ]B6w{evuC̋֋1VW⩓鄟O"@ֆlk,=x~~Mߗ+[\{-)Y'pqp{5Iv\Өrio.urQqld&v^i<N"Ue3TT/I4"R!ĪS> 2fۣe"g8J)aG1f H`SqfX&ygd4I^%4yz~c`{7W6 f)fjE"29Sa<0NÞG#!&2a{b7778`b1!#X)iqND2TXb6߃Ҡ f%8Uj{`ovfodxX17 +hX*Gj1U7ztKuإIFE0Nt*MMj7?1"ⶐECd5p7ޝ%ɂْĩlG*N`'K0k\ F_L!qd+0 sYl }!!vr39# @&NPZk4O I`V\f0yzq[|5;kU" A4щ~7k>=`&"+o n}]$iOKd|=rs`|ɥ9 H2bOY͈IF}[t'H{f3UD Jَ )IH,N 0mJR,!eA[q% ck֙[C+DT@Hgk~DμԐ, ȄeH F`dSpC7$5<"Q'ul8$xx0QoI#YN C|)2g"3fj/ׯ%zgt4áFN' 0b$nӳ i2uD\߈ȣxC>%~~?//Ua^Ϫ{ˋY;vi#H;εXɤUIHGA`'&9Sфjy1Y=~->ڇX4r0h6DS<(EZ4. =ZmPS\[EA c}$ªa6$3&`5ϭG@rqٸ\8E!npўET/GEMduiADdM:K% E2Ĭx6aQcA[ ?"a03'vfƃ87q8<m=" GPVJ`61/l. Cɢ f )lA{NKL%@V'$՚a,.Dtϊ]a=YB(< Y$)!+ޘ :sgu<@P0ZhI(A9 `'uRg$[+Niy&|J m63+{[k̹K̖(yB<8@dOY,Ak@/QB ɭ@O! HguӵS?3YQ.T$&9c+GțH,| QҜ$6o 1c֣ CF+0vRFf\ F.}>UJzĮ`G*rLqXTl'VgË42ڍ m뻵9U}KCIy"C'"`ٲ[J$-]i.śۯ{cKU>Α:=1 7ϵ{^?m1{Is>d?O k@VH.wpLb{uo Q ؏!hpwoFc@O̺XGS5H/!֊0Y̵!gO)3ZpQ`q0M$p@hP"V_ VPJF?53-jBwA71n߻7h8 n@܊\/f  IdYާ PN#2KQLAP`lXjC-#7)kH6uzmFT"a.VV+%$JDR|rDDٌyq8p<er` %-F1zuulT n<r}Bc e+hU2Q`/R-Rd{#:KG}M-i.=+y3-o#wvze8oVȨCub`*"ZmYʤWdwEԳ x77o$٣c8b'0W/B}VPSRk2Ihp'Tp@80KQC-,d5..aqpV7C./ӳeo&&[5hWTUYDH5<46x$ w8Q'Z-&0b.3Z)83(ؗv_ |t`DȈ4fhLy0 %S*vHhq4MBZ P>% ݯg$tET@fA&[Rl=Jفne6qtU6,64m,d9,f0 \Uj#%i!*."߇%n@Ot҅rXS GMNi_aN#];ÛymBFƱޚz2F7nnE$"y`vm{etHSi,rf/krblxvvv_%e1pLY},:<`]%sg}v0]Wkukux\TPU˷]E2uonwiNlw_1x^ϑu}L# Y]s69 ~m/sWt~$}ߑK DEVFڇ&މ,q%h43%0UgI N p0=~tm<iRMHHzD͔{O$,e(غV%M, 17xKk^Э55Rt7gTԞ%%%~!|߳>d.l^0z~ (>4`k2)}am<iA"K`H1v`)e)#hH-C{f`Oۆ[TpfWwGd13 S'&k%.bDp:8v"4I7EeN@l`尳E?|FeZ˱j}HD>c˿.Zl}Jv&}ڸU.ܸ:.s\u.c.uŜ[kCUdqyN G69q~Vp<,~ؿyDM%{'K!iXų.O'ݻzB$9G$`%KzRϿ0Z)aāZdda蚆!P(Ff7k0iDy^ ;1Zk(ULR/n_x89 ,skH;!\W0BV4:uڤ1fE%b*Dr!mWB(T'Yޝi֢cVx ;CRIySpaz˜7\f!s&6qѳB=㶀R%B;dq yCrvI6VYb۵55qȧ$&U6Hm)A|'4J$od ,5u'kvTeA}zܗx߀Naa7rѩrS!0&M[]=k Dנe X9b2;o-IL)aq5#M maveM MuiMRޤל&2C@Dɉ9ӈlm\[!{-MIٻo,s`ؗ֊_ߟĦ'ƺФÐ}:k`tTApR^ ੪D otDۓIr6S.ٹZrJa@L=  CvR[O{8Qk!f~bU!tYfO10pT&u` Ph@ΠFw2k8iP/X$\$:> Ò8},ZVsCB%>^D͊em%=!ڹTy ˽S-:$ S-Cʠ1,d/oXm"3`XI:K05' Si;o  NX9HIDiD9VAۨr&U2zo9a|-!N4ťn3zϦfVܝ0nVTjeA%GgeW˴F8p5#/잭еV,䠩ԪoZ0|G ~zfogIz9㗿%zstliGqkpd,7K@n ~ [}קsSs2ΗXl^Mj<[mܚO!>^yQ<:@ 5c=MfM@͆7k:[ *qM24 -MA$NjIHsVh]}'LBX''Z KEƢOa0 MT̴TMZg ۮ;TI\[ lL@cG]̞U5億TMâ54],͇BQYX%I9d?嬋,tld#DM#c%(vz_>cyQpS@" Pùt#L[RAIcɘD qDLRЖR19= *oQ{Drk6ۏV sYJ1"UuҚ/H9Bb՚:!KWrB]#$ggaI,DEEM>"#{I @Xd} 9=$S^*\Kqn3;`]ێv7|xB{&@oknVֿ}SSss#-HG,{YXZf IDATe흷[m%k8ntaN].[8X#[.?#~ݙfemw+S< 9*l)e0ڲZBxf ϊCoB$/΋ S /8i$1Q2Qk@D9X)I}=c@'עkC$ ^,j"# ܉%%pɽ{4A 92Ak-Ky^<$͌> "/ҐQK_HS3*ijA7\آhV˾\%@wbc &:;pծ11I{X"v9bM ɖ߇IL?y9g>z"ZȚ`Ҋ&p--6 ɯ~+ǟٟmYǚtLDsȥT>wk,|]|SU{*Aٚg׀O%({?g}ܻ{c[sv#!V97ֳko1,b+`PANn L@]e&PZͩ2T 9}'$V3КXEd5M61c'q'Ge?GEnZƂmrNJ"D0SFQB3M=+aftaKx<⦄!&psx2UIGp1ńy)4&r@" `4YPC)3!Kᩩ 1h?i^ :kpI6Q _G4%b/B2ʐb Ze6f;ALPӬ<6;x%+5bݹ`) n&G6X>7-M&7u@M5XLuXd gKZ3{l B&MLG1)mA yN-7̳$RBT.9p1Oˬ=ʗٙZan #ĺFsQ~Obh57ۃfmHCvU9)Qꛉm-,Rk蜥7hZzjfDK.Ha:վ`\oI u > P72<׿5iAo؜Z=h}m!#{Z@u){׼l\S=w_)=X"I׍O>y4$d7qďcY|>ז~\y 3[+yB? vN4>.VLЩ`\Cfr&WMaɭ)) ^hjyP,Un!N:~fe^7Wg n:0 ^h>ps{;3vAƭN{xf1G!Q|/Bڡ$}P#={=ԏ;E~#2Ã1A%,٣ol/@d7H_/ۘ~C-ֈj P(%.NfbU9x,̴(+Ynj'/צ"y>Q*7$5Bmf\m*E Ipw{&*W3[Z93J}͙>>' Tal&uk)YBGG} "r9ֈ m O6mL)Ys*.@bF1l9'F`"$ a-6>XB"`nK:_`?"ksm!|oV;Gl5[֊vX7{&kv 1kIg$| >3?r}抭7;Yw v4agh@_NhS$= %(!v5X&j ?sx:=¦, ;lD<0r4$Ե6igq4$"ͪ1D wHi_`f$M+"h}e(HSb&qpG,R S/GߔBx|'ӓϝ>Ŧa @O#/ݻZr]gbڻ{IKIJ2EzdɆmB$ ??+?7P3$lj-@^փB)6sOUW~Uι6[yS]UU};`_3zpH:MgO?vljq<+l۶ vaj]vζ}wڹmLڲ@&@xl;g=i,snY#_?=md_ڶh/_>Ӟ]Wի+Whc 6[ x|bL5KMǍ"W^.yEEf". X#kdl%3N~)0D W\mXڶcx)xI?QO4b$J 0LbejŠ,Re"/cgc9GZbOd=6?7YJ"Y#0c z }'{'5b\eR➑c> C,D(Hñf!,-2*DuLK{D&Wy\fekTrbc>Ե+n3u:@3X3@!Y 9 J񍤭>?DfY!h N9 5wkem"1)Wװ,8׮c\4;Q`.yR_B!Er *eH.[Zm$G4pe-I/tJNH 񬈿W@ИsL;mоGv]&IcvRS8VőJa<~ݫWq~r=c=LؼDۜsxqM\|y4'jP߻5L=1P4Ek2v5El=w dHeYHw&2wmVm9ӵkڙwy/gkT4?.`x'2-]Vxg5< 13n`:\"5D~>PIn)SsN+؏Q*Ø8u=PBt9B"qMłD.9)8e(1ebȊ-ˢI t:D@KdυnÀ#Bxqn\J;q,#9 }>7bK* 5"G\D z fbـB anEU&9a{A$B8 H7W-cqK 9 LI@Y(1kMFwog@ĬUAW\;g G63- vpE| ɐd7Yu!+"8138DĪw.HD&[qbYv' ϨsUdnN!S7˗/''?I\v ַpʕS.dӜgfګG>@ڜ_!$92K̆- 5` סR^hy0`S%|-E'tZc1RDrN#wh! `g* va$J?Gb*nw^$ #~n @ASc>8_W[JJl\Wtc_ uAy1X} h!6]d,CT* س+B!ƕߡlL9$D-"UiRX,C*BM" ڦEL !V{8HX4-|(㉹*hA,fU:"P+C$(dr@"ڵ`MN u`󺈝<*aV5Ti_qDTM1$<< aΛʠX8D k$u2~;fRQU{EK Lnk{5XPƊ03V.^8\OO\OOIvNw ms#buw}{.>}6`I8dט mt}X?+r=O=>c_UQ[5#s:g}[RK/C|+_۷ @N퉂ˀ@8eXQCQZIH`JF )鈄Uz:-aYlk,[ِZbկe$9xGx@TbpB, X,z98sz4rO\À;q:;s,[+O1تd᚜UA48Xw7Č{,M@-ׯ%0yV#~F=(E=H@Dt*7 :7ʄ4Ȝ@HĀ;"悚7*VYv_@9PbIFq#^qJ34r`RЁF 7@ Zke4C]6:kVNK"? ycNe}7b^ 1k⥸94 .wɅ GEQSwcm,}%Vܬ)*R)dm%l` ش"1˩&"m"&Fm rn^@FA3uBHXlPhI Ȝ@#]xC%.FR8[7<mU1<+&oՠm[xjL֏{ؾYJ~65ek^o9w\{r7O `l7 Sɍ~fRU_wf}6N9o~#"}g?lSwO?s^1$S2$㥗^Bu׾&&]@I>GGGԧ?9S ?U@N] IDATp-\Af"s)Τ^evƋ7cʹ1 J.:~VǃL烼x% 6o!Ƚ" i5ɀFCX,y2oV,0u=V#~p;+ie܁n#~pZ˥f4<ش6oHd&ojielq Krdqc_,!#rZ)=ʘ&JAA%6}j*9Ki}OGD63N͈ruh{9Hq9Ǡ  <.Iè0aqȃmqPC 3cMUBPĢlHgaC:0 ֽ?pI1Tj0nG(n<־"`;Ng\uK\Rt.i縊qz:a*)lr#ͤa}AyZ<L.D(!ghlG*&Km gpky0XzL``0Y B!Ύ 7cw)M()>ޙ˜zUH,L"E)37 ^O=v}w?حׇ# 1/|!G;7"l zʬkn`9M{Bb2uӪԿkA ܲv{첽@ v4~x;,ϰ; 9 l;=i`afժRo\k0 ׿>я~4g Ri]&1i7z}f27o]sFGt^JeXGqMOw3~D*q'.e ![k4] Z67B#W#C HŀEgtW{SO页\p^]>C:&n]ߣYoV%V %ơihN-UOس!ITTY )F }E.y%-a=ng PD7i^Q<\Gk;tNk T;!ao39{C8g=mc*/i1,7@:F$[6,}lmX,."$sQ151H^S[y!D8%ÛǷGH1R# Z{ps?}1~3ZPiΞb{[nƍ9T(5Lj3֏:]-s΁{{F^?m }7ϳM@I}lqP0{6~֦^ ~ﳟ,\j<kRNJU?߮@d J`dɱʦi{7x#[HNsU/~1WA5Zp.U[WSXKݶ*&x-,3ܑ:T[YPwD6ȋ3[4H+ZYd[i|ñ TgsJ{ۏ"2z99։&hT@KY]3P$cbXj-K19C&8Lga 3@leĚhdisFEˮ!@:9/ JbLb.S ~SJ@l1*$Q;aU S!9wsTj! kvFoX)J4ˬD%ؼXuɩ;T vj*VNvӜe`Ddo'|`z(Jnܸk?D|CO>zm[V7n ׇ@JDRH},W/M" &6 >7qőcj %v|[0H}v7bN ;ۄ]YAԮu$> Ŧ>smn;wMd9iFw Ї>R@d"2w|ҋZ DkR};ށq dq$!J˝zN*Vqߒ]Cl.U.&Ő{=Ę? gI:&א17Ćݜ,&ARq-r:f^h*' !m.YI$]o۴CSXLVhIή7k BRܕ)1'QO4H5D{L>3<ύ0m]$½=cz5KzN8M*%YG`D%($Hwk֋`Ȼ ` Bj(UEV9_%ۃ"B̊:f(چ6 -# kaYQ,Oz8˃ q.[VCI';![]'iZj52B@e&0j-P߀sSAL&zRbAdTF)1EkVEk H0|vS#lo) 8d+ j #Rw:Fҕp\ffQMC`BjN)y_PbetRIM5 44q^1$ӮY3>[iX#`XD<uH;~: YڄD Z~ 5BXᑽ_s/A_^DJcSn׿u|cu2FPǏTx(b>V_3]Ksy7 w=kw v9v@u@YڙMOL|/H6u5÷n o"&~IC()J#_oE{w]>dB$ַm|8!mL0-"k22g) sq`4!f6wvO{n]AܾmY@F=B|6#Nۜ4lrn6޶>5H)@gm5kLA0nlZCjR?g}`G})%ܼy3׀3ʕ7>!S)w^mvݦbV;ǚ(M\r8FDW"#6M;G &_"+srF)gJ ɽ}:s)%A;dUMk@/5 &_p$qG2bXiDQň0g fG.[sZP$=-.Q eNyR|#hZV(GЁhq^NVC✷r>@I균VQqIV]RŬl!3sf$덐à/f`\,Z~PSW @EpdgV)2#EO %mSIZ2_M̲]yb!pXv 1eOv" X,Xw$  ({ֲn9Đu",R²G wc$!k{(, }*6w<ňGD9Cu_5 n"|p8~Qsjk8HȀ| AVss8\ ykȷ "N{xlV[Y/J4 ȸۃɖE"үU'D&%#w;zJ2+&9XEOJ8/bF{vȄTdO8) =\4Ii.j&fo>} ٹȅ| ź_ lIRRqMe8a*'֙_jZ^3Ӕ-Q :냶 FAM%.ƀ:U0]F,%$ar{@n]Djh̪S1"x[>y{}7 ?DI(Y"vin@ɮlsê3Mso; mWoSч>fH%"˗qƍ F[n _F/K8C32UZ)$LK҄,LedfMI<-81mwp(/%Md)Qj[j+I[F7=t_u}+2-$}z!e zb1ъ ; €p#jIXVh%]n) ?+ց1T Zm`SmE1͞1hmx:Bh}r;wARC+I\ VL&b=8DyΡKɒ:p%8 -diڽ `S~n؈s:ĊLFw+X8UL,' R… fm)iHGR@Yß.ܜ|Tܸt!bqYRy۶n}'vd1sTP) [WUb= 1F%ELQol*bmZ9Gp˸HUGQ@,M.sUӒ4~*YE?ٲՉ%"s \5^*9o|hx;F`d L,eԕc1 R?bk^60k$;M4&oL62+^Ν {tLc0Wo:?|1~67-ԀdjƆlse{G}7o?_,쒜cLS, ?D _W Rocbe>*fRJL$$)",}\,&CXQbGD^\3meIHcƶh_2Ks1rKMl} /{+^0'-cuH3oM9leaHl](6ruk[܊kX$dT< %tn{)zg'M~ʛJ,71X*zHXDXsSq)֖i`;` ;1 gъ8+Inrmh< k@Rƚ,@*YhC/1OQ95aƄ(N0ŭu?^VoX5PZܴI YӴ$.%MBl k#ڦJ Uݤ%P%hP\s>vh>10 5@Pg+~s 鏐7Wo"+@ZtF]0DV{&%qOni >"}u͓1S! 1F9>O'<F8N$vzh~趫5de_k@Rm&akz} ss]^SM s&Pst6Bj-w]\|5dedSmq>T0FX H"mz&\t ΝxgO·;'(+aM٣@@BL&2s4u* pMFWDڮXRj]:q$,1u]i2` H,FF6DĄ>if)"%&P "1_ܢc h5;vSZ{m˴0U4PSBI@vyWJhnEqpֱ}]+&߷& H-!Ɏ+,4 IDATPπnf ,YAJg?z*B(|߶ D9IGfpIJ -#; LX p{a- )$DDg`Acef =.Hj 4v. hQ~@T/Wh@˫lnKc&Ykݮ(e=A*T|Ls e2%5ܧ1&MfS a Fpby@MJf8$En%`ɲs9[` HHjΥBxb˖w>pƅؔ=πJ8*W񅟕)o!D:!brjm5b"2b|w0Ik4с$KjW_ٞjTN??Gl(ƍ侬k1uE-x HsN箽m vv7wi H B=&7>,ۄ\m54Ο; FCB"Z:;%^$?k iKnʆM.@ľ)\Ne1AZm81S_t("-}sxC>U&J/}+àV`xfqs3>g4h&Q~6wDQjB,e2IH%K * )%ZCZ!@$+}-;Ґw K,j$ٯJpbqG4`\L2B.m- RGR;q0kκ"<)9h`W18P8'E[X|֐@ma*9]W̗K%-wxRMm;Tԅ7'\I@YJiLd*A AR_s?$]'7ƢXz$xTܾ+ RX!u"_Aꮀu GщQXN@r, !d#zuCLt7a+'\, … 8<<ħ>I87U"qڽ+ 8i4ݻ=J(5 ,Hc'l(`\Ôe ",KY\<pZbGo)Y`XK6kߒc232*FB=ϛ-+y:VhmA}"Z7'O2|e[c)B:LB8NAbgJ}V0#npzE:@ȲKQډ-/y.Y'6䥠K}nGĒ!~p4:Fdcd[޷hdCRB?pI4D8 #B6yz ZURcbfBM1c.U\\iaE EӢY L+YyL"}ŪcFdu) %Z(aC&YcD26@[E˘е&]0"dWLFBd.7e)MuDbO]o A~da2Ui&EeP%?_-Aٿvp;yW2bHC4G__ŋOQ 'Hj`RZwF?3֐z[ 9;mm 6=ݞ;d 9a*4O{?{/6%#Iay\f[pd٧.๧ ^?o%7͖ o#ڷuo<4 2ݦ9@cĝ;x,ϩ4!e3Yd~ Y`<|wT,$vi2,[Md@ŘZr9(d T88Z]7"4 0ڷ1Aܮ$ה|#¼4nh\.]޵RR1J"3eh@vawE܎crq:նXVU$̀Yb]3-*4  d." e,+xiwf_skG: sɪ\xwʵ]qeu@zPjXи| 5cPP`xXR$e-z O^CcϯM`F@ER[lr%4@L-P3"Vk^kkb}%}+;/\RQɼEN [*nzRАrli`i%pMH0g"[̈-$zcj~vv#DQY|Ty |$i uM e5ɫ˯_Ho!uo:nh8De$L3KQ-oZbF_H֒!x} o;}>:!dbQRO,#__GV2 ࠊa5akspl5`jz@Rz$gV2}@H}V7Ms>w1=מ% ??q@LvF.uJ)TžoO'K?E 7n^G[!sm9 LFS欯vT( B*)TkXlFXXԫ5FQY5`c2L9Zc)&o\UOW"sߕ6AEVR>X09}AҥHx{q!1kbCB7y-$똗ὗ8laY.{\.uVGG1jEspحpe-4etDlY@JQ׳#tyF=kzK=]20ЋH,΃CP:#-|!g}@ClT'X;@ުB5@3(mD%LHddp#AHp~ \sÅ5]8ƒ<:?Mu?`J!ma$ R#J] ЅŒ1 Il +1kǘ @&?bY10!&HWcN1 )h_q 1Z",B@BBI'@ [" {kPM %tHRMVˇf26.!} 1JZ$f4듦cXQ7^{_%p萆#RwtD!zhj2b_ (@XAAtdDL#%C2~=;G#MTciEM~W~.\*b bכ%dgdkm5d v <ܶ&6@|<|;>U !m~;_9qO񦱞9WJj] &N>5mp N!r pNgDnM[RHymT˜-&Y3@I<JL=s. tdane$9 >D!,E&wf50M1 X,1Wxh[JK!@*X͈7f].biNНGaZ1.\ns[V@s@͢|rY 8S{I#/L tO`fhpQ9r vNlwg{ 9@a Hȗ:]SW Z>wKDV +ӂ_LarC 91" C|XR~v)iF4jC(۶E8F@l9a2F 0(i\pdJRIkzHof'fᷬ)&$!%1)u!j6G \%b1b3>"BCQs s_|fƞAҍ>p9DZ_E5P q.$L 5{{Y 4`D7w0P=xpH[xץ'7%I`90^/} K.{O_ۓ뵶Ιnor窷M>M6 Q]\۞u^vMhR2^=Oq^eE3!@T`U@2ZF2 %d_2Q6VZ[{2W> ޺qC|5c|;k|B瀈X6 bc^m۠wCvЀ;+ 5k[s"s"LɆr=[l),sW#  d|F}j!%)HDaU\sۦՄ&X,bPf.B<u&0éTXB5Y\»~bB@9JUXHbY$h;*r)R{ÐK/O-.Ca=`\ &p5 a1&r,ɲ_ 9ߕvQS(Jj{R $s )_ f@AgԺpthGAu6-̝>:*HY`}+l&*DηaЅ/k 6A4P2@bI-IٕzU&&wx&ysRfQ*aV@7lX!M`nhZjXfD|m=-x:/%hSk\eJPj x%eg=~gރ[HU *0!AʳWc.\TS"IH 4*5֜L]R/(5FPA-攭Ul2=Rc NsZ%6Gu;FO(h:"^N-/0Ģᤰ"bɞKصKpd,\h҅ѳoPrȔme4<2A*(ǎHL4̈́{-ÊEN(HjJ01" i0`4ri0ĿW*FʅZET& N\7̌5cr5^{l@`aldQmI<7 ϟns{Mܻ?mMM?o |o̭X& q ="Q9uUA);>g`@T+(XE3!KzV`C&iQn4qc)=VxYt6n$4cе, qkKf#T Lr?181JpH1{Dx~ q}ڋ0]R2$)vEdf@`iȷ ( Ly%Z4JfhLR L2i\B4 P;,A4WNS)]tlV"za$0\M͵&B>&԰YzXŤe.ھ3mc ʠT⧁ѨH$s1aKY\kk|}Meg`Ω3V8eZ1DiQ' a29Wfje H|'be3[->>^/pnH[x0dq!2mG8!eyZ%lH=\19 Q@LPE3Ihc  $ԃc$t=[/_-i9[ElwΡ:/G@ nRm񻱐ρMe03¶=߶{ iШꎵ @fq“#@%D0 @ꀸЃ)ƕ&Y<@(@ j`;ND`Ƣ5l?Q &!+ @ĩ/&-H3!`x't+MOW\x>8~/gqF`OUpI8be&N a莁ƼKB,Ӕ)LgLRuF_ܮDO!X$X}߉$`q! f'+|( €2R0YwsZJ?3li ̙70FVa6egA 0Ās{{hbr`98VK( #qZ W,ςY`<{pauXz ~5to}O)̷~\ɟѡaSN]4Ym9UVhD %0Y-. ͢ }ޕ 8,3V8e<,<f\N˗N0h 9WEkZdLbī MFR u+(=חcp}dJ,>qJڃ݈cc!)1\lv@@I?&qBt)\5#cNz[6x @ 1Izi9[@mʒu2w #&:1 GM=7s i66@fu]|_˗sD9y}$_=涭9s.r.1vHX \'qZRj5R*5ҪQ?*UJrmd$b1.k` 0Dž{99%˲yb% 2f9 Nr=u%e s?`C5m^/~pO=IA*ٷ%0|QEP #Yb͂~-$8-̗ڋ1@D2KC܁i(NYV+ʤ) SYtX['vڗ)mLD T)[FelER~P1V΄9ZMu+0ihMiҖ12T2Ƒ n"$(;~ ,q CS'}m$Q'͇WjH:! ]@h@\ ޼ 恨߫#Xn4Ί%3XFHӸؿ~??m>UC70N\ZyL|6sV{ߵ޷ݿt}ou[;}}@v0v+>XxpM^|7 <#5bSr(<`#nB(OuuE4dpf @YԊBVBaCbXE1(=; `6>XR7~B&( H&PF{ ,*"WB}|O#E(t>s1*%5-X|X s=xA]"1a-6BRD:\hfQe>c˓5`btՄvCf1[@ek`&""\p^/_,wjƤ-DP,$13ļMep0 qf)`u.XO ?N_"A<˛YxU:E\|c8>9AQg#^.?x @&7 )%/6c>cR FJԌU&2gl' =P fhgwM:ߺ 2-+1e,̭ -`ZfIgU=kX]QSu$Z-TKlS8sAҵCW gtI ZFP\6!OzZv`ظv8xFB+/oAMp H_A`n`>=aTmdJ"h3&5!-5;FdT j6j8b$8E{ 7~픰؂HZM߭<;N~;f7KaV&D~ukȸkuYpv"rZIHC4˃u1 -V(-XWE-P(u!q4[E2QMzV;N@aNE۬EJ$5!1zex(Fx.4,J83]y%O_̵N*1i.88knKt(Ë,(eNm4{@PaV/ux !hb`{K)0 E8hWMVaQL=kh q"t|tfxu)2[H@`..e*s$ej_Yβ8s>Ҷ'y;,3 ˢjB[# L@ԅs&0&Bʃ"CJ!)"XK \nn x_cIRڕ+ !6DMls׵ƤmnAlnZ1\Y3,%.x|U@+7W?f>He|}. ~mPKH.C%P~"7A YbBLP.}.LUŒR wk 2ٴ2 [y_ vy7O#?(~gZ](`v`oAυq x׻ޅў{)mv|ߒ\ov=}ܽ9ok_Ϗ)io?SW%2/߳4M0A^7D=(r\F% Ŗx)u߀eoVWrhA(v~F@T?,v**g~ǍX?@T_H3)r*y  "dt. gw8נ(+Au/:o9x!w}wM9_/!B uӀԁhޚu^@^BИwD4~(j&YBni+cK%b.-`ф|2bD&}caݔ4D`D+;7{WlҿۚPpy^c3_.yϘK2ךP^:: xh&"P̝UtĈtG#F7ƈSp8;W#ăiBﰲz=vVn>נu(l~w/V뇧#lNsR-! TMbI3pYj"&f 2nm;VT5 QyvBg>1y@+| 2^uP>Dž7Zo!%ϩh(M{/nBK"X dP0Bx @pz!y_6e di@r7GyUd^u?s-?|[z6&K3= Ɲ;(}!YD 8\|{Bewd^ct@umppEEY߆aQ/G6X-JG/ڵh d\ ޾7eAP {Gu2XHހO!uk|ߋO ٯ^-c?кk??0չI[Y9iϭ/si:qϳ}֢P;~}Ks[ 1?,0-kL@uPl=@ Zh Ҁ"4VL&qKVJ4E.*-p2Ѻzvjsjԥ*"H9\^18+rCcU eYk`c+qED@@8œ!{+onfK?;y>njIϋ2_t^ Zr59^9ҙ=hj1GޮFƙOU@ipV@Ŋ4cbD8ROMs06uXYe`C-V\7`o;OUpm6_24n&IYɱeţ7E :@iQ dV&HFmGOxA/U^c\XupաGb6epWD(BkNO@ìs- nSs&m5*IBjC3f X 'lj ja Zl_)"Ҁ A(G-> ^ev^ )扥pV2q`EZ[Z)օ- bT5e)&=qe pBq+D غؕ 2i,@]ESjeZ3 c/7A| <^e? ɷIR)ٰZXAEl4HY:@jP (ARy{Ș RDڬnooOB`"u_t0w |+'kbi+<ZBZ}1#vv,p,83L>`L@yKsv,ZG=A _ DkQDew;B7@QױOUho1(`\YEAMSoqJ{˜J <{'9*Wd5*b@: tg0d0"՗hm,"2(y]44>djr!Fu7~ @\RA|2ԸWig (3JcR.R{"E{n -0DJ "]Q3a(2 ;V2٫:W&~ZjlR ]4%N΢@"Cv/Ɋ&QY :ָ%xpȫ (#83&gm_x~_y\21 IF <" '{lj 7TOSJLMBT(*S_6%58_nb(^z5.$& ,=`} zN 6&X.4'uRS"TZ2lP]%iuJz|ȜOBď‰ CR.}`ahjrftvnL [Z7'X. x MgY5D\Y& 72[EvXJ!ҁ2ƒ ޢ XP4XdaK_?x Ox7GkpLZΆNP4D 8L1V j&-/LO4kƟ7hu߿?Z Bеë_S)|η9/J[疗%2?sayZ0ݶqsY}ܷN{Xgt" Ka}x`TجCLyƛ4Yj}ADɪWv3tʽ9,Nk} YvlTЏ9*; iC}t sZfSPܧ|Nb:(lG*Hٟي!f q>ӸgDY+{egY8)S T;>w ; ʒ55',E<7%My5r*%֘U/=FEd=ynC"7V[5NvSucSD( C)'u[:E@#*?0=,Xw'o%nO~|2l5v׀ͩ/PU2 {Dcg#PٯUMKbQp`MBQCxDȂz:luf0c8Xhq(ջr.T/fJ6!gҲp$g,;ZʥXEkSh .e9ƊP,"PW6 NT*)5^@%>&`jYq`# EP툔{2/q`~z̿ ڏ7@]e`k 9a(&tw&N0Vg-i$~ 1N?j5CNys ׸;?(H™߭߮M)%}c=G}0;[TcW<d gkʯ [N;%[ݖK@kH?y]Ӿߥߒ%d=#G 4X IDATknT΋\0,D`tw2FCXQE@̒ˣ?km,J.PEj5)S=ͳi2LM h/P\$408O}_L߬BtE"rM_*NB0>WV+PR۶; gݴuW@ڷVrdn]z i80xZ!: Y|,ً+Rf c9gǁԹzvqJ,6"xaL@}שQyғVVq%Ænvv㍡B[dz7%IL.EXMTN6Bi}! W3lYl -q jYkgĂݔB U-׋\i!Pf3yĈ<$! qhT5 K^Z\Ncn[z8PɈR #gY>Tw @y@s؜0P ?g},klQce48YD)oA; /yV,;-0L~s]v#}ŵy,EH<T% ],Sтxcc_pywiYЍ+=>|+$jM]=#UX[&79nas}Fh=9TYXmfִv۽vzs ә[ AI3*z[dB KVRl(ʧvv= Nq ǂU4iy!ڻ$DaP\Vx,3 t2't)Db1#3@ț+GP< ΐu+ae"jEdAy3e/iGEKݸ 081tiBɞ MV<"s ٨O !QU&)lg]!ٵ,MZA5 Z܅HoJ?A~lU!KF,^A=VxQ?kyϹV;HT"!ܳ~TaH}DIhK3m\E 7- d.{$ǧgK !k9, pO= j 2^P H:PMPAPr-)e D.]n4\g5!$"!2ooa]oدb3T͚չ nY #7>wk݅oo.J87t{mX>,۷-y}+ʾq iZx9=+38.u"c"*qpauԁ@Yu"TBaRfŻNp#\%ACO&eK;u0>+N@JBFR4}MFȤ2 'd ꐇ@=bx(rJ \JVtK~FSMyKˠ.$tH ZQI\Kc ʯ UK9Z2L"t]ĘG4IfݯM䔰>8n7߫02T6f3z:qj}hqE'<9asB#7NnϬJ431U4sʐZD6z"XubU?w-R59#^awqBq Okr)g DiWiqt6|UA"IesI1&V̲8;ă{/<z𸃜\kYtmvow/FdɔӺ@o] oT4;{enEdH03iڳҗ FV+BƝ.5K',D]\Jꌀ٪֖g"@JЯVa5L33 j+Z2kkZFsN6Ɖ3c^!L13Մ3a-83+\ ?]FQ5y`?[q5=t; &/?ݟх!7!*ꒅOhNvS=εg^R*ge&BT\1+J< u5xx3pѦmC9k_E񖷼e|][kMtqowɪ0=,%|γ3}oigB<k˾gsA 1@., 1kqLf_HzAKjf`_s)!]T@  pf c63LGmm?u2'@Yn% 2{#R@@,`5"aa,<@uy'ʃx8ƭ57.(jiJ̈]SG R,2I|| H KtD0@$寪Ae&Dq}nMTBrh\Jl@Sj]WɡrD=O)ԬLNSR ZGyKXĈ!L 1=uC^.]8gNqx2& qe q*תhJbǏ DYi5Dԃ1?"pi 8o~wj-ww5+'Gљդ"5]M٬uCIgV/{qz a|N'ڧn Yyl[䌁[OA =ϘˆB\Gڇ_/} CO"4BVh5Ϧ[Ekܭܳnm?}[K ^7yν%`vVK}YdXEϻ[V+&eZy2cԬq[EpoVP (A~/A3y}Js<@zB1G-~~bh'̀ؼ`*T3z}h`#bd`AQ5ɈbS ztnBPƃD 0&g}c"LSP@"v_+VSŮG%dTqf<v-¾ѭV!:R0 g"t+` T"Ɣ0 J75QfɊtT Zh 0С9Yʶ731@bqv<9[BjFN&v!ЂHxӃ{)^[x'o~!>W1\/Axauj<ﮠERh5ա-&bLbI`/#Vs` ep [+k{.@F)?1RjH)~NsWMlӮyVp?_S7vHYz;KNR:wsw }/,۽%6O7[ %DXi'SKJÆ}oG~ML3V'sXNQ; 4rqW´DfV/ss M|ܙIz6w*6+&! &mfA`t`Mcށ- _3Η67oaoaE:2ڵDݪDlc{L-X4 %Z@@(֎Ex,bPX×܏+#2˟ƻJa?N=۵ݽ'/\kPf5? |4J5NKQL \L^;Ć-Rf9 X2ug@.j,h:e4/j5p{%pU[c8!-CPRdĵRc}pW.+gJ0]fv\PФuQ=1FNK&e$%3)WQEPkNJ ¹@T+dYmx$pjр#'?!/O5 _@e@C1 Z=zOkbd߾.H 7\!A8P @ZS a< \GkoŸo3VmpZtHvZ0ag:K3=Bt>)0sڛk+F:zr;g,7󀐳, g_}%˟ '[&ZȞއSX"EGC#ZTEUQFW0QT4RGfcm{hT,~ 7MlY=Txj;岊Je(Db8R2# PEߛZ@g/=GR1Sg*%!LA_3#Į3acN]c{n1xT{ӛ"xVaY2-=q^kܬ!"()n"+ :w^ki˟TƬ?DU1io.> 80#iPPgMMIgtK@[5s$WdZ#4?O!4 ysT3]: sDL,^y2D4ū?_;#`eN] B vGuTnl6 .\,eJFTeoGxaɸ(ZT;{4N|8k&E5h uJn%1tE mZHZr %F  <CgMآlNv]F*3O??B1BSfa)~Xsk JNnGx unnfri炜irH#c"fFJ&L3cZ=X@d_COz+$okz#1eBS4B ՍL[8b4DY7WFPk`*2 Xps5jT5V4wh!|d&c-2xXW⮄ `<~׿UGU#;.ÓI` w J }M7ZMN}18. /nf^P*J8h-;&co7o@Dϓ4,[06N?`GX s ݹ%g -'ms suvޮ?m]wֳBZe9O9繦Wo/bBxA%_s^E0= įV"TwpQNoDkmi}nw6T6ɃLϫ3C ږd0y4u2!1Mȡ³]AcsEIVPAU չvEִ\sN<]JP¦Ϯ3RbŌw]g^lcN*(,5f_MvAmhWK{8 !S~Z\ yjN/{|/N+;kO(>ZAv`;5)L!Dd.-`kLa}Ͼ<H8V׎WV=?-J3[ݾ1"8| G&m$+B/̔-(<<"w-|,lfȀWOtR' N`8]ݴ a9!4Uh>_0>wIDUNj5HN}oUVGdx_DP+B?)J9AMհ K‘ l]#5c4 0׮^Uc`/h|.H6 B F}vr^S0x(PԄ"Tlp)V7 [k!}3w OqX8 i"  RJj{-0Z1vYd1ti&K֌Y=$O3aěTVr~)ـ.S)@ IDATtMjv Cr~4"-%a7JA*,O9%N)sG*s03CPD#(` 3vNq.{"~E"% 6g}@zMA!>i^BY(!+2qi np PD#d dLfD,~ X~#^W18_@~ }|'h+_]|tjwL9ʄџjhdg℞P6,ʨGX@uAr\^O|ݷIB868;@o{,ZF ZZ0&~Ng{NHkY @Ys p;r;p2*sKJրsgP,ٲ<SX  >" S"*;oq uʹ;i&[ӊO~΁ Z Js OOrQEZzIY 48aUw("8H]U t'h   x3O!mT6_OpDCĭ`;0?Z_5pCsB6nw?X@8㴵C LHnU2j8yGx[ЬGBcIeh[l"9d"rq:}qԎ%ye3uB83; :-D . BRb0ͥof cg)h nk!j=D~PcM2mk|۠Vsm؈5j> φS:D0<'_<Ə͏ޏ׼Cxo:0\Onx`ƅ43\|^YU][Z?y@j^h{ : 1A@IA)D:^CW|?'.  Aiwk80qOO{q_s=Ϻ_;?c*$h,YC7m&gSZ=9} NcJ˻//_A4"]4i>ܤ-,Ifl ߥ6TpY8x $\߅r9Q N!:}ڝvBS,8$ %0/~/yְ0k@5/xY2)UZ缶+lBA,(J8^;~G&'.񙅟j=ڎ*@w1lc@ZQRU"XaUS:-j}IcHdžBnCNɔ#DetT^ qq7:>*,flZHy 6-.^nݺZ+Fˊ+{4rm52/&vpB 1l [9B @3..Ou~2 ǷEHCMS`eb.bٱjM{V1M{7u\JE5$}fI`TƥuB'TZcDB !dLQٯŃHcJUu/\µ.b@7B,M%; #B\]ϪH R ʬ+0ZEB곇{Nt\\R V%|xsnU܏ٗA} Jl&; C&h Wt!]FWA| Ht~f}A>=w{̘߳ P5 #Uė JsV`b$Er?͉LB uɛ ƭ~אROOcsr bo/}`c ,e_}k~>r; ̭ƒ=vcp*YLh!6{ nJYRda̭#%ۇBy4׶~ۤ٩ Od='n@Sd/ ~}%h}32~S~ ra任H.fͺM=b(`+ӦmE KiYv8Q4J%zl]@߯cDBJP*rDl@"µh sI;i ĦŘ6; f*,HӨ(1z#hĤݿtALLzc4B𸐢 V  UK3=1}]&%30G]4fdR-l`JUk ӵ=#E(Koݛ&wky{kDiђc2E}8QR*bwqFI҆_#4$4Y+s#=GOAR})_Uɦ(qHQ> TY34ZBe^:PLtj*t/`4^ kr}Q>n+"mGl6.2t&M  QJvK5OL1q B;- Aeq@EN*SOƳkX*)4&H"FT;f&ұAJ!}A'p>/܏N'1>eEunw"FǶdb!VR ,P<B|ȸk~M6ۢ%rAjT {Yڄ9dN^ < b,]pqm3zOuD=vfjm-G,@ps \bLNns1aQ4иj+D D XAT i/i~L`"o[?(sxK_WE5@Gld'Fx7I @H!pg.+sukC;OTFƠCPL Y"VpBN;*?߄}tmhgċ, ŏ|#y{&{I`/rkVyu4޷}9o ,${ ط hY$.r(90Bg ('RD؂aٲ  " 8V@juH:a RѢ2 h<a-fy"("U"1XJ ;H,]ds7MWx2Q XxV`/US%Yq,} hܡƘU7ZCxt6']QqUf*"{V! Cqs;U)a^!n "0E1.1RQ,K|V]Wi`Q4e"T ٲmsprp kH2.3wob.XҠ ZLsD>2j-\|7sVYLYdip| @xk=P5[]~,mwTꑓ0Pm=Je ъLTɸ%9!oE^bY,+ 4blRC,V#(k8mCrU# bcV/gr4 \M_uǪȾ7y|+йbl%DYfI0~AADn7? ܋%< l։jl|LHҼ2D6@:ȷ+]o٩$exw B s/nG+,*vV_ܖaKl˫AS*Q8AۉcV!!~3ΤŮ4kzxM/ GR{buogky}c0f϶c隥kty|,@ZPp^҂9h%籐LWIBfD-.l g@uD enIpk瞺`av P%M5W{~=T Bs4+tAAln0^)Cv)%J9+q. ؋@:ܥQMV;F@5UX"| [cJΌWEDZH<㰳?t^1 Z-= VW# ?Zi}9Rؘ~%=1C{[>}ߝF D’qL'IIH* BpL^ȢTJ\.;vPHe$!$HhF{}tWXkO}w+s{ZXeʔX ,ڧѦH>==nONNP3\7o]ǔ3RfGbݷ$+gC`-ofLVIP( '_8`G'$}g}i@~KA9 J"IKQ !MQiKA ה" 쳒DҠvj+PSm.URҘ HX-B` -ly>b1-fnMv=G_6 Mx1>@Zf1FFl! `ε5P6&Xf.˷ncc֓R>7+_U/x`udF!s,5xN  ۠| ` VCNAp X;5*(DTǽY)s~j%0sC/kf8 Sj,LuSӼ/kmGWBw&Oӈ(Tj2)#|7^oyBYb*APK~hRPk*yw6\KkX?]^ y27U.@J UPI ZA| H >/@4eavVThgvX< F1w҄Bm4kH} ʼcN `+)yDDN@~ /1?w2Ƙt:iIK,~w'=_Z5551Zn+?.k}_Ǐ]s;@@>z!kˬ#k>, w.I*+!YQu~/Mk< 08~=zpYCn[" o&Iy3iqoj"9 (XS.#9RFFݬ#r iSkf&&J̋>f(POc1R)Zj MAU@7Ƥ-T8̙F+W5NO7ֲ]v; Lu( clq!6&AES'ݦ'TLiJ8=~o6ܸ~]KD1#ƍX8Bt%7Y"ZП)#h/gHP2O8Jy΋Ag(qi@% ;|HU!EMҟyI`Y}¾@u#!˒AfQ$99p? -9 ,nY4㈩.p-أ `8=QGߟ`FU4t}?:/%O $G63~(Z 8p6IG t<:Vx!JF-#ͳڣ(X`;"٩kBtPefM'#9_Ȅ#9'^@Ss)FN!兀`DH)?#^I@kI@!!{^O$~McHkL캪EtnZ %=րϚƲ5`v\@ Y.sb%X۷f YZ=u-2ɥf9vXvVhO|m@9KAKYv?(5̋]ysM 52lXsƽ%O~/xW0Q BNMýAZo^q1~mTY LbvZ^)NIE!`Ԃ]g,f=bU TCfo  }AijRu}/1;֭[8t]f8J-(_Fy4o[r;9K}/~aP^L{„&. xR+Y?#z0Zif5=1Z.V~omVGy܅w(!+3 Vc0[4f*g1&"*fE o12Cu UZe6JFM9B0(mv:mNKp{,6N'MY3~3Rx)|.LjВ$@Q>Hf12jsKn`E X<%=ľYN:Y$G)i'RșR;&z;1u$C 2C^`Pw/MSg85p:Ƃu9$D0;3yw(f& ڱ#\W]^ dgw-h%=p;\8Pq;kͥ}&^ eLoOc~[Peƈq"d 0"#hH(BP]M2bj ֢b\g6n Kfiʭ{1:&O.VW6\m0Ku2@Y]:@" ɢo <_SO,)@#sF/~x߈7M{f]q{){paY5cйkVf}]mء5/8䎵fucXk?頩 #,B.XJ;rphD> .T]k`eo;VOnV 1nj#]X8fʔPEz]_P+7ahL=x~s "_Nj1cgJ>sOb(^r;%ֻYź$!GԹT)0 R\-rB2Ѓ@Hyv-r%ypHunO)9zMe'0UQEhV됎[ Qi税}N 953 }U8n;r!DFN;Lӈ EE^5 V_d"^Uոg`sP63l8d  Ƨs3z$*BѢмvow ZOE1djșZC}q(N&wr/e'EacAۧr5(` @^;,%gbBkUMLT`1SRLSBA VO2`:}?hp!(%gtQsR]g W>oxQL7o QܮbB1*Csq "ïЩ;s|mCUe-*@׾~~@]+_%k/~ULh`*s" s2f@k\M LxV}CcTiiiBR̫C @ϬfŹETO҉UB ("7 ybT :DgObyk )$EbiF4=e  QS_ f%䋱WZ/>d1iڸ`ᆯ).B2OfRXE հYc'QjaɲpW?xӣzu-1c[ \ֶ}Cx߈7&NNN51b kd `mKq̪N }KA~ |X@ևcd aA, *]NAjrG]K4 = N/tٻ]96@Ff'.|cU!*)Hܤ|S@Ȱů|}x䏽ƭФ׳( \"AM颴TqKV#s'TmvBZ/e%$aA׉[Y86)kݮ>b{’RfНb7MSYjJ{AK,)2A$֡ "[Ԥ)M D*nB y )$m흜b:Pw'1FGiՠ#uEV  aEi XR $/~w0ʏ#h?iD2-]~i eahI}3_ICsJf %+gAB6qřox)2.!1D C&RN{HQc,wj(Y Zvdz~U_'o\KiQČY< `NYDA䄐•Q%"3?U`{G(܂B "e~4'HJ!*0Z}r_,;p Dw %G@u  Q:!BYNE70<ŷoM@A:$z=.ϙ>7x\+{?>}l0X׶cZwBS r[Gň+ B{L%]Qha"5 2*DX|.k5 ^{{ RjZ'Ĵ"|+f,I]"1 VY'$U4U+\Vh?[b@jK-1@N\L4$`TD RR4*ŨATe$YVڵk"UѻøfsEq`vM:7o ji2 Hھvv{;4)Xs:,.d;*|YfU*aؠ{t1b&ܕ2ƻlN$e2gfY.o(Q=R0\ܶK]\ 8F{i#"3/M `c{)H 2H(u 9ike#oQe!1tr&{Izb5٤a!vC1FAQ@#B b'Zn~QEͯm X|0ւ-&ʵgC`z^)hU1\V _ Hi isM fGWWoG".exe$B@ESIBAvb@!}9Xj:=yt?W\d +U;` ؁pĨV,P3g1 'Vmc@b mDc~G^߾@;0wZBr}{7oxjv/B]2 f!_߾_%Y>ñ`YB|_] lNJ{ \Zn]`zM[@@ 7yĖŷ1/\tK|XlL0s`'soyo~λRԢ׹ƍngrIEX{$/$2}%0O'x<P%x4 kUZMqAS "BD5k%LB컕ZyY161 ZiJ5"wdא iʈCP :34],Q5z]I, 6U6jy6m~׏Yu*}iGR{c۟C؜qkrvU 0Kai mS`teAj!1W]%6RpWcc'0>'?.@$DHa苴}HtAs* 0ᬖV+*sQ72kQ-5W2n@I,hV&Bɢ1Ѫ~-K|H1j$LeDp!A34 :{q N ;bC J̮ bR]\斞 IDAT]0RQԁbYɹeGɳ= úPHaVEYaBUȵ h|čj mSІj{-x,5ۺv 4 ܱU`@DeXz*(2foc dIXeե#2!G 8wy̝W.;&r_}GK׬cwm{ߍ_Y> kg߫,-?w]vU}@C%89._w B`@k#s֞ćX*Mr4 h¬ &kZ'5黯B5AX->g]XUEN2SK~S#[W ΄0OO~_5Q@`~UIc j @iҶh`TʚU*h &P8#b NSaL>8}^4% I81bjĩL)!vĢq770M,,u3ƮɀFۻIG *"tvspvr E_e70Y$F\a/ %iE-X/G ?/!<~}-=/p;Ps-gKɶEڪyx) 8+P0a(h9'P7HO48p/Y`@*=A'EPx\pQD*#rY/Cln]f4Lj)M\arYHQSfL0SɝrBR-FR2uBv}q]VRZtٷ'sdJbt]{ЈAd)0W,oB7eZ l)!G)j<3FCcvW[^l\&d* q|Xjz;R$le{r?R>"t*׭"} kϹ'/,]ْl\vl-=U@ڻZ!K| :h|H]a׬n}ERo5{/_7 Ah0Ƌ]3PW6|۟RۨsCꭀt J@@V*CDጀ ('~)%t} uBDU>.OV˂X<$ V> *ԹnQ->(R-`uA~0lcW1OuZr%iJ+2w7Pd)K*^KLdKVfRB)nݾ-q( NOOWy fJD$ro"ӓ|h&lk?ƀhlH.D p ɫi<FW+DW?!g0Nxſo}ĸgG_|};q7Tpflw"td)&EV6(iv-/,>[V4卽m 5tͺqI-~!$m.Қܷ~@Mڧ[1wS`nu;cL̤ !)@@*I)Ge' P=ƚ" ~|lҮriDFu0LBD#->A- AMż4A@״w}{YQ`]u85z?d@7!_WB2fϬ`CR ID,sB CF h$yy$Nn#<}kg0- ~3Ł_>o~~]k.[¹$KsH(^^_~yߡݩ%_5P} }3!u0V͆u5ϋ%~Ҵm|y1F$T8͵vݵ:>V%=! g*Y) <Dg\WپXLP(Y=`Vb M{G.^ $~Ng%! ȷWV ezoo?~41ޗZZw!%Ⲹe@e.T\cnX B< QX{$kbMfiJ]{z>x8ɭot#zdύZ?gj 5sZh)RHE46o}$cNI  {/B@!LrvaDXB Rq!WdRzG$.4u!r̖SJ4JRIB3v8h'JLt àbȝTS&˱XczsRe,Jnq %>UnaUVaJajju(Yd-S ]F)-v2m6yR+H+U ީ%P3x jE- D'p0_p13rih"n7.2Uu?p2%c{@dED2 I-0- L#qȲi0b~Sۯ!^,З+Uj[&W+nآp6aD pi;N4"NJGJ 5rm,E+DHm.NHz1#Po}]/޳]DŽoy-Oԕ˄C[C\f8~˿C,y`rhe 粱^gB"X拰}&l|]djZ_vJ4+ోmkVHT`sϴ.4iһ%8QRYhmQ1GU;P)J#wiw~œJ4 0P@MlY[\ݶ,%ɑgvL9RJC? *EňBŤD= ?OL"f9IV\%VSʐ8!HrR #N6'"I3n[Oߐ$F t4gH*EXxԕ,30Bf`f\\lEєȹ0RF!`(e@7O5BpWWG-bGD|C,|m,Y7"c"!#c: }f~.ƈxJO]8Obz(݀ \tqapFG"|_f"ǹZE8V@Mrcvba))a{1iA s^Zbt1,Y4}$*,n,ݘ_V{qѢ‚T rځO>Gw)|쓻:X__35uc#};sE[C}ko ((ňxMjc ]]64k), Kaqf}pN~JCcevLbݧndhw_>[m#{r&7@e0UVΕ_ E6 * b7 @&;_aOԁ+9ɻ T<>iS$]ݶg XKI eEچ8Q쐭z9AA@I $ x; @A Lj !`n+7oDGl6H9! v*S[Ri}& 5?XA_Ս^yNR Z56*,؇]%4!Mez$X.$R7Nn}_e֙+YT97ᥨcO{"C$bu\JO ˄% 9vUƚ= H=yW^q,>dc`䙂Cai9,ƚ7("Fl-bْx4 o( 7=ܽfӜ7E+VAe&5hƃ3ʾݨ#^rʦ:&AD {uT԰Ne3dPQT& INʋ?9n#U K֌#dM, d V9#(eew"$Hj1vZ x[ WГsuB#JرjsIK'H12yzu } T }4P% 볘%Np4n[loo0$Yݳl^Z 1xUZ}Ed֒PդR+OO>c[Kč_~'p'Nu&*DX_WV7ݎZRpAު(S0W Eu"+Jf*L "H,!C$|J AKMbN5rNQS)\Jͯ2* ,}:V!14l)Cr.]40*[E{Z=:;;5PZ#m fved~koK>R_L)\ IDATvlE6:L[Js!_ 6.!ό6/B";N<YX%V:AäحMl]kރۮƋ]Ɖ]rڐ$,o_shۻ5qq@guZp Rjm{P1YIkƿ<}x˟'"B+Ŧ J9XQ> IA 2`)[OUtI2t) ݂yzS暼d2a`N YvrNZ+ѩR BJۋ @REc s%FG3@^oD;p [)%؅iw ]{NBܱ6+pƮʱH` 3.8D4E )ۧ}0>_? g(\3+nbݠ/əcfwsk@dFK FQ}γ8Hb٨u@ k-YN$XGz=B5{Vlu}Éd*uqBJ)H,B;YS.;)6i@=p1 F̽ʞed1G^+aVasYYjp@ VPJANslĜ2'\0B5_Kkzz|NܳLLiEp<rćǂy n@r5k0῰;Vw6 $I2˙Q$7\%-['_\k>=yZnkNȚ`|m ,sM0?5pY>,[s!kci?8wW\v\ 1kzXY@̒A;!$]~˞wk=4צ.x _\e% "( Բfka^!"9k433RಫSo %D⚭$Q6:ijd%VE^kw]a\$Ȼ$ I( ij 6ޙtDֺNlY\@z9]۳VN7`mr(Z}qr;( 5i FpNX(ELt' $fn"9q#*=hjef ?[0 "{_q)Tef&8y`n2g4ɗl.Y6s.e^ |?IHYRJφTdft][ zRgL~?e#3VM; Xgta6.&H%ʣ79&̲ALN4;|IBϰ‡90BCddJ(i @/g:F߿f)ڥ5di`} 4Dִ>c?$/XJ\4\>WyCۡwn3?3**Z[/_<~0}tkp%G:^ dd< W avZgy{=˲ٍŶ` '.xyjFF#Qy$rR$*ߞ~ W~faAӠTD rj%zJfGOR#!kf{[>췺{f;>J U0e ɥbBrvQrNIU^TGr bCO@8z\g{叵VϚٳ;G:̩gzzzzZ5SOxj"+"T ĝ{͵ɀ,Ʊ)[EY[ZaIZ\ɸ~: R9) ػpdIG/rG"&F3~+b(x<(y@@jMr AOjzۧI 4H`:~Q>S@kg>cNp+6 g>-nJGXDղ.ӎP.ϨŊX,ZD4Զ%،}=+BHq@*1iC;=`\T0oӊ)Mėaś&UCWjEhM"BB: 6Y̧qƒ"`eU d$AQzbRЂJ9#4!D n]j#R]F̍[%yp<ApQz߃1 8cWҘ9zƳr?`Yʕ6=@YUPq— @crLfLvX<+E4rqzY@wd0-tvu|w~:ʼ>Fڭ^ؖR‹_Vmw)ؚ3YCbYcǎ/𯁉5p֑-"p~~3G~G&z*\0 XM 0z 8@H{pѸiDds<~V0sS8鸯>qMSvEh-bb%E]QLUS/%DŸ8y~}߃|+[[&)fn8T0 PyRK-Qs'b@L ƨNO0R Z EZ)%H(fRf!E0Xͦn:Y5 QC7wnA^bc @U' y"DVS.IhBAԊU-hk~? a\ R9x;0 d77,u<Q !V"Q['GAV1Uk6w3`#FTҚJm{ Ond[[o H;Kk_hq}^u[j]f=X xE/\NJ.y96~-oG?у6!ڼ)FR#)%46"Ǥk&R-#?;iݔ~@6\Hdn ]UAJ&kD-S,IB)u 4 \ޜw>{}khY$&f qWsV|VP 0kZe>k_o>>sa\ n9Ï9v`. JN\?>ikYD@nm"iJ&R Wj\P")}Z(=p k^g@Txay9:p./e@rm[@ZW~Ζ^]Dl@QVOBb&FԞwԚ!%Qnz_z(pr sYe>]U^,"W֬W 1,,@1-9kٶ|?S?|#m8MD|hr@MZ&YL?[<2Ӹ} ^\ s2dylMnM5Ia k;$!Z*@딶̠"&^D|mx믝%x]CW!D[0aBl* K^n(`m5,feF ߴ;>9YܹV @s-ZZq\ ” 8u`9/G"5wY }A @|ↄ)cs)Ya;")(X BsA Q}@ =@J{k t}w:R` \@PGʺ6)D*Aѿ+yg ^9+8'Px~y!Dh`v 3C9@&dh~r\ p"z!zN-auiG-nlj,RBx[,Y|'7Of5mnc%gN$ K\`:(D)@\HR+bH1{6 ~oqx/B)K!433 WFxh"!߁YvUz_ۮЗ`+Tƽ\,I>J}=QTEt.71&íO˼ wrV]H☿>-e]cp1K@:`]ktN)hvN Ĩ$<PQ*I2y}E{_p-3gh9YԒ!]b s1**2"`9*wʌJ5:JQjoSk*aY܄'O7YG9fe vK jm׷1Ke7.#yJiڿMMU(Xzm/&7v[<;ilN=`:91cxp0k&z%9V#4>H_kmi;RVE<fdmi4u~98i# U)@Pe EAyrv /`do׿1cV%(0vr %kBOO/.Ec p˱v})i!CbY@h&~Y{ n?s.YKOoxkr[;va7<Ǐ͏huki(2jiҵ&ʽ4cSŀ_O_?JҨMF l,@"t)5Ø3BNJﯵe<&)ĥKLt04@,.mቫhZ]ٜ98ɬhkmJK^DR߭]_@N'(Z~ȽdZ^Tٸ,XgL*$8qڴNJReqgސ"5U3@$)o ?2l`P֫uc#t緎ڱXi$&S" T`Xe&E˪w1!375#s@H[Th0c@)%Rɾ~/ b ٻΥ!HZ; aU MИ/.wkZUiƍu_j؏-HQQ'@h&"㘱 JQ5]PZׂuxqi.WggM?eYDj5Ϊ 9uۨg| +_I3ـKK_3P/Ȳ;Dր\~_}G5_"f:0.']1{x;sd%n"64zFܲ.wdzj Mv[U:d_s88쇖ɂaQDzςh3-Ӹ&=X_#!`T83I“_w?@;[sM+ +W JHSZbzv_eaRiJ(\oZȃI @II 9glONT`-fF j8-=;Bn;w&XcX,hŃҬ <ŽZM5qޅ*c8evASK>DK&NKe8bBca2*2"Pkff= #^ vc}nd n`3>uDG$!1!flWgglzt]d8Z+)E~@:Dvw]1;6y@\G10e!ЂVkV!.V,a Qֹ:x>>CXo_W&xpp6iw=paa~o"rg Jt?,nS-bJ`/#rC1 \d΀1lyjg{aCS@C.~ZUz)38p[)jz?̓0)2#WM4j6- XJ f̖$8MZ]N;v;RD(B+ȋ/_SL 1R܄bvO؝[ Vzk pƸYk7k?ݗn&,o=-ƹ}%(Y3ziU)8AƄ+bmኔp`Pj"f`[e_okn˿__Ż+1kq 5P}m3MHvmzs^|Yqz % /ft\-s8ھ3 q@hg= 7ڠ8TQI&Ȅ`$+ï!CbDR1dB.VBB̓l rD>n"B +[jYn[b/ /(׃=ڀ)1L.!'~rW/FNivo7@4~5eX: 8+~7~~}߃yJTOE ŧ*/TP'(;(H:_`S pI1!{QIBꢤ/H9:a0R*q n^=KwQcw4ښE>[B>ūUY-ITC='}6w$k8uNIAyFXYLZ3E҉ȼ\u1VWYKFqP//M]-7z&5p?5p5ޠ i-cV;)J>hN`cBXsuYEv{Y 64iףHU5t@ FgR@,]m̴cmyBPJI9Wjû}xŷXQllO+ uId5cX-G!,_i7©i)= zDKL \觥땁1`],@3Q&MGU/lhvrp R/y7@{g7ao5uk95@wpH ɸ` nz7?7gzu0u_ux+_,L |ϵK@\61 r`Fk D_ Ř (:vks@8>]:k[߉A'%-4꫊[74vbv#ujq欵a?$Ygy`rlޝYݒXv# c:s% 1 aLVG*"0^M|C9zɉ*e$E~eR,ԲXyO˜ ĬDZ4ZS@TT ҬjD7zJus0bRYTW߼ySkk˒=+P'qgtJo{Z%n/}u3P=x~&y%JE YD\[T۰HؖM2eA=N, 4 u@IeuR0ߕ~V\S*L?NWY]_Y)O VCDVeu.䚫"KY:Xj@Qҭz !P8R sw-q,8V5̊/$LhLrt=Ynē5w ~qnj̓+8)`*8ts.H)JKު~J&u y3|m?NBb b"iдx3FxYam6>L@> M_~_q;Yn_lH `KJfZ[~?$x!<| S1u֝f5ȠB@B2 (.#rE)hFlf0ZB%㛌k@S .)u1cw~EzlȸX0>^?0^1'H)J̇u]U.VHki3ZkôW&^4q7@]71 aϛiTj~L $4oX[\%?0#<b.̓[<L*{݌y{a+}o1KϏ]Gnz i$&3 dY1 -NZ%\}&aS|YHFo[D uw97|89"<y'Wb5܃{,+K1`u|>-"W}⳱~ymk֭[xe~SZ6K7≡ M/p Y۾iU 2 6]^Ӎe}/<٘mv*GG=$kF[iMϓ,3 ͭ\,#"p0d+dDg䇱lP I]Z+B S*:UJ nʪ͞%hsUPy6%<8sg !" I\[ VDǷ۟5 RJH]B7@Ʊz^ j_nmA`ĜT-nT&.^J6r)x2fӇQ| )R"uT%G0 @G@!(ԣ aU1(az#_ߏ$O HZ-^gM/_6`ec Zo7?1%CLvZ/=5diXY.{; ZI~@PYs!XMQH_ud)B[/8#D'x/gΎ-Ao F_ R b}]f\k8\:. B_;6ƫlkKD'?7W精S%©2ژ&m8ߔn 6r5<}pb,3%_*$In~sI7bd!C1?/Y 7IeT 4$.PfD[_-`S .ٰDH$H08Q8y )gKA}&+Ib{)h $fBXݳK.w;KAK9؜b< P>>,V1%$ "]'Yv+FXis t}D*+<؝l mm:FdԼ,XCB(Zc,#@ˢŵϑ$QChn]P/@o>=>~3c(O"N{Oaٯ{O)ż?9@SF)`u .dCVNB>sM0ؑ1hp@h73ē*-p\})fΨA.5UZwQݭxʡOOY UF@2C&MPOέRʖC=)U3bJR@Q 7eӈ]RJs`䮖"B@.Y[Lب,iB YĶ5Ak @Hc\w=YU-Ӝcc `lw cQ{uUVퟑ1g hL@y]JLZd$$&TY oao_Goʼ2gᵯ}-{1hBKf Yf ]YBִsmzp@*=6q_u[oo/ߧߢZ|kY"&*Y"f5Y3zAX`~Ғ\\ ^fi)Cuw/i|hv%D3ܶv9Y-3I!<ThN *EĖեl*~?/~jR&YLT@w1aGG5AeQ|5&fU2b5DAEc!J.$u= #n߹fIqX3zLİE){M+5'M V,䎨rqk._j {02Z1ކ'TtGp]\m5}e-(m2RJnxU/Ւ6#c}~&{00ÏR8ٹl\}V7NJP<~G~a".ND#>"3:|<6K*0 #b@3x!JQ@ס3+o:w[Γu7F5`7t IDATZ3zW0"J1 `-JU1?&$HN (VQWK}5F!v(clZ1@l֐NC~k^^S3&urkxʚrx{<]=Haټ3ȅϮ ?ʍP[ Ԧ46El%^D1ܾo٣a6ƫ^ƼBo ,,}]l,Hsm E` [;~*!"wZzw>_vi-v6tɶ| vX ,=y00k鰍YIV Rת1<2!z 8rⵏ?M c1ʷQCͰ&_'Y("E-,kB1`ѥ$^!lnjacDܢ*Fb̝dbVa/;ņw4JUqkD81 8NrqD8jZ߀3W R@Ļ\9U[ƌL$t'` "-~2\A$0Ȏ&Y%.ן|fp}pcW+؜m#?A⨹~WG}ѺZEоsݿ[תiK-*NZL6p%L?Ĉ>ae.RrB˴H1*3s / 5F=-Jd4 yeъVRIIvG$>9$әKi <袷'56ՌȳS:f98v Ҭ[6Z%['aםks޴ybv (8 ǵgcn6g㳛o J8p"H<(2fnD ϿByU)Ȭn\r`uW(ڎ$~vX1`|f'Pt:f8H;p9(6˶}&_0nDZs/ֱh.֬J0o~3nܸq:kZw%L%òD+N\u6>%cF|3F\;C^`wrIgc?R@hiץ5\9v}KcM,ϙmV \j\$qt# %|7߄ǾϣDZ*2r"BPeGa N9ԊZ j)(ENH%qno6hJ `qQ8Zb ̟YGrV Q )DƙZZ+F< kG64=q\xl}PeQ*UKƫNҴp)~=.߽œhU|#=nWW< xZGq^i,DN6nVBT5~e¬(uʜeT+ T2BR Ċ+j 2Se[`V1A񅨡c9}tzW%Sdz-o #Z۶(` PLw"˜J"bB[6y-`[j2D |$o՞ c$Z~B3Vq4AA 4}o8 ʫQVQ&}?Ɉ'| 2_w* 3ZP߿<׾m)_f\>ќ|~OO4z/E/`u%fnݚ0x@_ϭ n}{:fm}3r v0>uhcfA~ILFL>{)Vf RI"ZZoq BZP$(p N>5q 'QwY\Gzq GC-5d "d)^\CaGeKN %#)CwRF4aх%lt~T=:A3{Ĝ{#FHaK~X](1F}q$MqSB$B0I&`n )Zz!WBN3V+D!sFD#(0OԀ=ƎE&fM@.~ v,"l"=iuC*@5iTʔy( lNQw`ej*FYZk)i/# 9m;]5jtxK^R @ =1FTX)-t4SNl贈)-@3j1LOӲ*fV#jnk37t]{/(Im!Fd^}^X Yu֒ڣ]2%i fݹZ?^wd@g&+TXgVo xmsʒpUݎ@ -[~?bA&$ԕ,Ve<ݾ>?[F<_^(6av-fd `ؚ prlk߯]H{~"Ec+Y~|;?.;/܈ik(H֨sgSC3nZgB?ƌv, õ_,m4rWC;-i YY9q}UD;3JJ)|u2@텒Խ $8@K*Yl'ZYh&I8=;N 9KRV}PK$A퍁!wJdF CRubZ-eRk0y( ױ &i_;UZ0K z 3Vm\Gv`tgo^n#n 6 KŇ?qo@>5>?YHs8!rPD>[@AU%"΍VZwDtj.R0*0Q"uc"R3# <>C{Q17DCh 280 h(Rl@DŽfuM 1p/i.>U3 ]]-nAǔZTxc4RfQ* ).3I'WdDn 1"Щ|Tَĺxj@ir_4Xɣ\3Buf @Qe65.e=y*!D?~wwkMAqsy5~r%XvdE1`@ }'jdFEܶASѨFI5W-@յm" 2pZL \х굞1FΆYB &3Z+xaq5'r|UHeҺ,=ў#>DVdl Onhԃ8 *sFWS\.rw1T/7а< 3I7k 7Ux2chW HRh4帖}xrTciJAjC}zڗ>Ei ;[x=z'񖷼O<^җ_gsaxic2Ke`䪂UemjMh\wkYΏv;oƝ;weW9NDxs{frݬ~W.lxYc ̳&dZC,IwBV 5iGȏ] ~} t*W}"nW]?kٲfF*x*ᑤ~X'0\IMՔ@$B @* oB#M&= ח!2jS'ha^Х 8q 8}-`przp1Z,x&idIKfɭ̔EA1:9' ΥeuVTI5,MC̩}*b&<#c$ZK=ϯ`ޑ2c@36ǜwY/ T߃W}Ƕ5}Y&y:wJ :Z[̃ 3f;7Y7/#b@Z00+;%Z=eG`ܹ׽1o]}__>1|7~1|_۬ekc\~hr|;րU@U,,Ǯ}ј [w{ĈMbӔ cPJgP'L=G영om֔%^\߿x [6\Oݵ7sxZvi4O}6ŗgٍ+@E٘n7J$S!R:*YyNb4Nrbw)Z\5ܼ+"{a;Gd{Tf)"tA J䒑BM/T@QӖ-ߙy}'_"+3jMFq񼝸,!VBH}DMB׉u!Yސ`nW'P5jRA;514 )F Q> O~ogQoyIa^L[?W"<p,kVkC΄+FI*_\$=]W([V- ؝ o#PD (#CAts N6*ւLm'Ey pܞ6  v5bzi*vJV2QPA-F+ a~IՕ17fQ%sU HYjHHfj)Y@c@ 9"ia6IcGZpδ1 lKK!LsfLVlsA]?y?͋1=VX;ˬ s\vVsUA,F@Wy$ǾXH$m*qFp~ FϽ}Cԧ>w-]d-$X5Kce\e{E^]v,!ַa˶ }DZYW_n J0=U] Okí[_G+=+f4 m\ք~?7n2;o51:F}}שj10;3L9鞳ZB (O fgA?Y Fq`$!4 E\y,Rbsuxzܹ#2 dfR2r.R2\QG9+b"=!P؜lS°?kqg0*6qaܣۜĠs2"wHDl!zp&ԼR ~|)ƼǵQKAEv#6΁!v ؞J[*4]TTmmUn߼ $$@%* QmE)pJ&x?VM֘v-"Fr2+{X[<[Uݽ>;or8gș8|HZeC%Fd+6l0"%1lHE0XDhk۔fs(r^u{wWʏVUu{ޱ]gwwuuַߚ~\A4(ȲQƌIQ/Ɖh.iP=06պM !b\\ [slQκ*6:+-ږYf:0]TB &6jj=ᔁOqŒg͕*mĭ]$ M1 NmGY`A_Ӏ:l S{zA+U.p2u_q<7JGB 8u$uT]r=,DiI"ƈ$ 1J Z3vPͣs;%hO0p|;?7/_Ưگ?~a]k<2= xu5gz,#g{G]Nb9|_'>37Y|*&ʜ%0݌:GRz>ɜ77(Hs=~>(}MR2v.c5Q)_|>x<&s}xNH|%$X?" aI'P@]^\LC$9"7t]V8B%gwA[\RSXm2!1!& sIc=N8pѶMvr49 t5$FK, a:I<[RJX,hy䁋[a%t'2[U&a&ՇKNMffǬac e %PܰHEF2zO0\>OqA^xgobx[h߃by2HטYjKHCvohYM9eظ)CQSGHX€i <D`Bx@]kj6$fD Nc(.XMז\=hgLCkEDb.-epe_ u"@*i_\ݤ=/g躅f{-4!h]P+Vg+-rVF Z 2hYЧ $/ &m f>`lhY0`}ZaA ;] tzIu XqrˇgHhcp$NaP$+vSr6'^½w݋^|7?8x O4^0rϲ0%~ Rq:_s7]4q3wg} =vY;m'1甌x5q跿CPP1;R>&331QÜ2>USHV{?u(ϫfʠHc*1 9DT'%IP:5<23MuwxM*?KPx`"P E)uWZǍVc$?R[!fP ,!b9AbvEΝú_Wk2ZT.Diw:vo=ڶE裬-m+I9yVnY ?eLj`0 (BK)I9;!&0-q$;&sw ~ w[g$߹x?>6~~u[Q7„:n*sNҫm(*3W3 IDAT񏟹͛ @o~B\! \̓'s)2#n:8 Fczu B&Tǭ}ŀN`)kgv/D{7zr=SIޡejзr*1 G a5R>%sIL$.uܰd6Z@g.d;9pυjr$\pSVs׊7#n 4hMiJmX,듵XMђ{;yXw%2Ehy]T~dh}IZ8ds_.=hnuV89>0l8 N_gMs\#U1hUYq ѹ/cS?ᖇ8|'DZpl\2wnAǞAY"[OK$1 Ŋ("uBboٜ! KC]5a,M aW :y e$h-33bHܶv3"Ӄm>@5l.HZ֕S@g45f'> |\[s,>ޣp JywG3.J+OM삀1sM7֨iٮd砀z^ߙ<;ݱY;=GdIIy{K`2Ã5?PqBؖeyHy8GΌX n7pIBb¦]5~0 h: ^#&RC$s;j-'t0V RBӨd~j0)=i:`bpg$F5 69 i۾G"rJIPHݬ4j;p W tv \i.Qb1k?SIq9må7`l^y2zʫ˚%[utaяƣ>:Zr-QX(ȴfzsF;׾5|򓟼8 pQR&"<" A ۬ƒXSg( h* Wig~YU<=oL5WO1Od&1d.ZšP'LbBR$D &B3!EׄY% 5pmjp:_7M?Lb V|x"bv)qPA6^\ȍEg$r!UMHE*&:L"8U[Ek0V''J=q0&VE:# CP|V,#evRc@RHP[ hy3*vr S!KGpףiی-10)#;;p}?*f&"}6¾UExj|R F1r&YeV-Qj/mfqN`p %e~2ocRIMMk ōKd IvUozO*S|dQҿ!g.9a^9ԚLj,Y R<;PВՑi~J&:<1Kl+ognx'x{ރGyd2)~m1'EA5XgGSf[~_|qtttsw)± .AVz4~ Hɱ FiQ]wz3Wsjyg_:6lQgwNN]+@%@|1"'MnWHA<l (sk_#qsS@,1'YǹPz6MvMs  H|bld~"Qrٺ!#)[qd lyiֆZ n X]<7*hxK].rtrG} hu9Q6) .׬Rcu*4פtaasG$uGF<7Z4~R ja`^²ABR/!gHLѯ+vK<|k2x~IxGwsYj7k}֎)g=`Z֕}|3cӹ XL2yN|3dtf^TDMSى'mV^;e &NV1B4hPEޤl]5 y2Du(XARrH,Iqɋ5?X0]+41_;JN59fEDdmw" D7*'Pbl[4N!;mJX(kr mnrwA^r@Vb5\%9AcQU961ƜH},&7cMC؂/L) H "dRc@C-KRYJ}L)R[p'$NN^ӳpsg?ݯXG`0ٟOy~[e5 uC(:{0{;eߜUW!sMU'䐃^yP1a(i˻(gQ ^( `%&$.Z! xIܱ{+ywm?HAܝ,6fb"@|#){8rISw -a] 01\qq1{U(!0l5v#LT%^u9,l[?vh/ %p:'X-ϋׇPou{nd,PDrvX29/,!c}?DnGݢz8Z`oscnƖC|NIX/@yiFK'譄 ҉v=N^y]`;f8\u<~q@< 8(#fAZD椬uab'FeNS@2R[~FH/еK*#ĘbG⒥%1>li[F &s넞<#bSJZ|ӠU˂ţ"pwZKjf.02+V]&b!ig$*I7UIᦆ1cXkdEcԍLG_PHqy@bGxY`']=? djUjGBy}-ȸ25۱~V ;*Li$w~fTӿXOrܟ&e"jй΂ɉ9 ; 0!0 jr !տ~_]\=aڛ?8>u^d>rZᬠzYcNgf<xny܈c?X} 4NtR%tO^ o2W;dT]~!gy캾$Bn%WT3sk,2L9(=X=5IU$'.Lj%Q`YYɵp-Z|)kC[7TQNSTMJG۵pNec}E !u=::%maEMݶHݵ vA73jpmcZ!Eqa_nOn.:aL),m&2qv]Sbpܣ&l5V Km09 5#S)$I4pRgf^#ӠvBڜ_W7XB8pa8q ^K-.̕Ne3(FU;, b0^KNEZd '6W%xKRTݶ-֎{/#5ˑpn}mAOjPQJ cYȸvrSN,{:P1WzYx$~6,Z,u tw}I@7I fW\OZ@ Swڪ .-{VmcxNQ:!9% :"$ [2[Yw߃?ylxc#<, \o`{5+)7 \}Ǯe03 |3s7b_С[6OI?L$2KP=PR܂zYN9 `dt]L07sk{BZ8SF(TV@lH)W\ܱT[ސ8M\ 1(ce9j?73+sHvD0EFνB+ 9[Xes89vEA888#\T"l7¤v.C>[v8&8`1J\IY(B4fD@Zl ZIS+xs@r y U ̜J5Mr!ǀ)8!HL2:=-G>ݡum"<㓏k/~>SG#o}(>/2JqA)|#1(YA;BhJ aҊʍ9ASjUH#PRJG NX,899gR!v%$eJ`fx*>-[fٲj%q ~.YՀڕx`jv(@ɆYDhq"̅e,; 6Y,J3bigC'f|ʌP/\Ő};;F r=HvTmb!VU懒)GQ9 97TK 1G89Yk{=/`"?3fo~sY}휶}3ʍz,~._O}Sws6Uzݱnb8MkcӾ7k!5}sVF2yU(tؾjR}z3&_kvfM珺^0Xi-5ͦjdn䢥 0JYEڡ1ғc%&āLHpU<6.M$akyE)K.eW< (#f) $nS1L@.s vPnBCch|OV} ̛FS$C[M^xzu+ ed<8Dfr55DW㩤Hd KyH (He~htHiWEn-8m&j,(3,d "u%RH23$ \?q9,ý=/k<%AawSʭԓ|%o<J}|DGO@ɢLLc2(B\ ,۷]1a ٠Jd=oB9{num<)2)-oX%yp5Ѭ m95!gOڴc-U6pEQ]!EۅY{)uFJu]nA߾P ٝk2,3;jA,+V^3 ݄}[<ž͖)=KժW9dcuxTR:mT0IT'7G%(O@o$@ ñL.$0 a:9r/՘Y`Uaԧ>Žދ|{f_ZRn@\u3g?i\zu~Կ@[; ^UH< ,iArU ld%qhB\L= =3|5=kf|2=X* 9>-5Ml@(I %+4k`_[V>!05.y_ (s o묹 |pP٬!x.FSDB4pp^\*6CY7 6#y:$}߃:q!bXZu>b{4hS@aDќO'c3jDMX׷ ._ap.$ 5 f[P(RX jA2|L8!|)NF IDAT jctw=7?7?8ċ|Cݹ"xD.M̔W'>ܡThef)}Ⱦ tP(ӈTq$gKj,9;ԧ$.;Z$0 %l+jfK#U ˂|d,l 6׮]u;6ĔF(_Cۉ:I Ab۵oi $C2hF[֢8n;^oRl'Qﷺg&\jkAsLZ-J- x$`ϑv^ T;E;Th5SuZGVOl$zk]<@ Ja3`;n_Q|+d")N+6F77ADA Fc4p#l`z@n88Ǖ+Wӎk}#nXS0BDC4&LR,&YʕV?z@ y4G=1Uz\<[*}T&  Τ?Fdhkm5 :@K]_7x[D$YO(.ptA-T- (jc6daMIaC?dA?[C=+8Mɮl2X2D* &uDc@Wet@V@XYR xCXznBsz;{v/ fƝwމߏs΍>ix5͉1F<37 >չQ׫+^ע??(Iq̃`yYe),dJ` 46tr}4mKH~ӏڂإyJ`QˬYiwppOށlnqKvS[w "r}Kt^ybaFZIF6PdtzyC~Gm&.F!` }ERtFhV6A GL&@UI &ڢW~׬XҖy0 htƄc, t]F|-"4#z4]dZdWٺ6j %]N7^-|{--ץQ2@kGX[A :VLcО5VcӖրdtT adiWTvYLtp%-$S ^eW\bL@2u:K=įO??mpg#?#URo&IƑ7mn#0xCN=7Hg9'͔\orN=^zg~yR"p`tB7IP:hwLl*sH U!%qWe+|Gz +~|?i`T~kI*7 xU{^@-Ud(Դ Y#k3 XWE >Z!H{9O?\\'x~]<_CŸ+%V请*Yuɱ;JX@]e9ލ* =ZG G G<έ X[R)]f`)< C m b`9i5J̀ť+Ŕ϶x A2ħh 8`W}g\'0I/VF8$K:H^^ c /(Q^&A._"0 ma|>zv5V=jg=3*=+ CYG Q^Rg˸y҄WQ #%6il3)0lN@GWx?{nTR[E`>gxk_;y\۹gW߶C8>>s=z /ҙ۸:|8ٿ?𡒧D!?!'PoXR à:% HQŔYKe@b_F ;mDBd~>C4#rI =KrĴb(aH9w~@ǚЙYmk gf9#M,YɉcbM!Apebg{QӇ^}s0[1z]Mqa<9 Ƈx]Le">:gQ?}PP }*AUDl3e}Kd@:2^X Fr\K @-hxFd!XpcTGfGā@At ] |dpd_ c^ /0xހwqڶtu]kkzOx7c\t ?┋年_|~Ή)=!3bq [ee94/H>ID+ID -N:n rf6,#WaZ ^b L ED%ΰ/r]R .S7v$brYCe2gv ,AI@?uw!)q ~wЅnPg3,c4=uʢ ΛLogOk6Q$3\Sc:1S.\P=[ +K:HC0 tS7Q˳0p k GW^,Ю&>Ȝ~e?::“O>gc >nv~X,y"W\^Ic, >9?8ޞ Sj0x}Z1IR/MvJ=\¨{;FRVD6'PssOF&aևcFҸNFK(zg eIhX% =$%*d.7)pU^ 9DDz?ݲLiT^LW[bsWV^y"p%}`Rl{aj)QIWi f]m;4m] 1Jͬ^Lɨz}3jsN"7|:i orEZX NҀ!/Z-Ԫ#-Ϋtun=ז,Оc'I5-Ҧ, ΁28b^8 x11pIh_}H'A˷z˭ 0@ԇ>ؐϴYX2vr[}[Dx*5(}f;!YAڶ-x+lFA,8GNTTy#AdHDBR (')8[Y#XBY Jm d.ӗpr!r"c ɒ RJ|c}ƹ{DZ?/h4y&nL.iR4x#aBX5UQ3' #RI"5xp>f/Ld"32'B~ 4&02 :gG@+);^nu}y~?A@%<R~;vE\xs_9 8޿T$Pa1v9aGjo'xf 504=>UmC:}6m϶5 Bj22#+ S,4@ h֌KQ〞$4p[īGX,Vh}oJK @kYGؾ㯴xV'ao_F. $o$svmcM>ʘ&gRNؙL)=}oՖb0>@vHĆ8>fLVN@o%FB2!%pptmxHKPĺ kps%! pyAyp-.J. !$p ʊƼ2#A k಼&DK(b\m[B##W}HXgj b.V%bGr }s=%պtrel <3ZPl=^F``ZsG Dnt7gNiGEuE`Cڪo,!l}Lt6 s=%'6sh+ e`? z=묀>>wV->DJPs< zXgY\t4_L:Mg-{ڹk|FyZ,LVheOpT?b)X, VdI@9$FԍrTjm i<<|?n_@ν$HU'1 fR hwR [!eAIb:Y0d~u"& Zbč('pȱ)[?\.4b9jeLaWi#mX.h}oKjcⴖ-2)iќLirGf*W&ţ%&EXt8Y+?8e³Q9 2\31FYEW_|p+'Ih x{=pC5YN~5ʫ DF橼..V ԯ)-@_, P׭ţ *V/=zSik-B$̇9]b$,~ܩ fof=bHH4e,i\-Q +x]s9e93D?u`I`]i Jyfdbs=a AhB0.4YPe܎uZHO] >}-]؀Xu[~@yN1Z੺ a g+fslvgݟ- %-qW{q?KbX9)em5ѾRIKޑOJ4xc//ѮWgrn$^dYEc}Fs-q >ndi@V) TF۫}6</zzM%5@]t4aǦ`ᕔ}_ i\Zm8ӓtoC|nǢM6KD.sI 2 p x{P{be Y/Y5N`&#fkBD׶p^ D(YS7 XݩYЄs! 1m _$q2H4kiD1" |65!So6jPe/Hx>uf kM=΍c;`^ooq#-vR?ƈ}ۇG0MWzB IDAT=EQeN!Quƅ0_"}JH83%|?ӡ`R71e(Hl1Ƥ ks*$#@ZfrʫrW[*i`bQJA@ BuՍdLr R ,W o]?U\zܞ@+)g/ >{+w@rY@J`5;qW,DY|*: կogl8Iyu`Q0Rn19y4wM泝zA!Y1!Z3^Gֱ2ZAX~ű_1,[}r"D&$w{/nf8pmVD%5J5aY994Mq!y,ԑ$ Qx[x$Tw¤X\] XviL61 :k`{N CJh!.f!FVX׈)lGl68`-r &I6'd:r~d]4rEf;UeNr`հ0p>A609譖^8s>O*~x{/i@J !GDJ`qINVޝEfZ0@Y%xTߴN rJwuSQJ};ĤS0bIY:7[k6l(,yaҜ!z*c'2!!%H؜`{2b~y_}?YKi9;(Vie}ވcW :掝vlG޹m) K:U!un (?T u{ g\Im[y2L<γ5A;:&@HmA Bʑ4%, ZR" QbB~ A]XU2-Ie sTNِ/ Mm =B4-'5~EvUĦ`.s@bHn,`!D5aH>rr@ MxMfML PfNYi[4<Ƥ:vMVQY( byn=[" z}1^e25;yl6,'@vVJjALjE<Ɖk3MixN@vYlHP}613 `rfbTkҮrB\_•/>Bw#\}^@H'mzUTEϬݳLY%K^9z(lN," y'(p UDDՀ![)2I5+1NlN\ ¿qACf}`ِJ `srΡсjB]1O)o!m;y:jwPB0r{qo]uɨAP6"R"ǀ4@!VV4RJ.:e.Is ,&HnWFV*'ulpo\7y Y6{.lrٱ{W۶dhb5A㢛NTH-X5Jm (HAR7a J w[f{22(um(vC1 mv9n5 Xwv^g ryqKj{hv͎Q(n%fEk,(qsẠM']cmIoUuhH )ZI%DJ'Yc8qرI ? #ȏ Ce(Nz&"ٴeK֓HQ8pf=ϽV~VsK {z߷9gͻ![$l`:4-^,! ȪzY'dFnwC (&io%KԮ#Xs& 8Ʉn.'iF(`3pyQF:So A I4iqBBK1؀ NqF 3!T0 iga Kߜq;>D\όs8"Zf54k/x6K-5C3;62~HV3")Gb&dWH='lK"XlQD:3t߉鋿-#SsQ4{<zucwp{}Ip !qmAϣב/1c]X w*p*EXPR`YQReYE)N38;[t__z'XǙeI\,Hmב=K unKHyDŽ;)]g1b̈́'9Xlǐ,־q?w/]Dy[%הdUtdA@:g-%y Pr;fYTUT(a+$(B>R-H2 9t+wimʌ):9:GĮBhf09GB泩A#qyR9I\u2S'W^ڇ5>!T#=f󷈚.@}f71K`AJΘ-&Ful6vHy9f_) S%"h 5'[./=%j>.ؼ!h аƂțGRYdH05"BEo/}?m}4?8'__~q|ҶGD҈HKJi\D<GP6Eb)/h uӐ*%QJH q3sRKΓƨ C3=(!uQKҒ7{gP 1"nu9x!sA0'RtLu)xHF iteDPȴ2E&-½4"O; 'I$̺Z"ߊ_TBBy)xys`YHٍk6=99xݪ۳᫻"% ]`H5$U;dxA KB5ϊXd& ӢJBM~PR/@ o %~Dα?ݢ{.;sOyKM㈉_EB}[muoCT{>8)'-ڼw#kuB= z@re*d@A J@xYĢy܁⊨ S}#pX"a\*9)@XYQ3]B %gLY|'BIYYr5ib@%%t}/@x9 1 sp Ԝ\pA-a˳aZ-Z8b ]lLJaˉ47B-pfT9zהn7؏3qwbȟn3;^]ףd%b'UK31S659ƈ` y&^4lZJH-ssت6I KNPD5k<g+鏾MGx+{W?pɏ/]^y))Gu`a|T a6lv JU[$p$ ͹s:)ņER k[ zE=hDH0dNR@y!F WyEE5,U#[i]9C dB $)X8e (QD"#&V%i9ZV1p}JQ*/mk߻3pD_JzYXcolM[:.ew- #u zBaGaA$VmWH *ίAmivnXCQ ,n_a >;^ԩ3,AjTWI, i7b=p^xϻ_u_V};DLԬyߏzgxsO-H"`ش"Lj؃l)?jll/!#n^z|+j]詀s/b4ceXhB4,Z %ZdHg5§OS^f;Q!j\h4(5(AQ㐛WũT BABt}W_t&dDuTZb%F4iNDRt$ψ!0V 唑J]C#i0DJ ]70kε%_[ ]1'{CJYW@7|P?RyHӌ@P]qxtV}ȲsC - v~Ÿ֗ ?ǫ/_ʀ ?ï!T6bBZ{l;9jDZY҇ǭ+?PK䃪 Hԏ Ј Hv6y2[[P)V9o[}%HtS@JD`fYU!q?u`7j$hYE5v9%WuTIW}sCT$k:AEKv53yNQB0GQszbHr)nH%>eF8Q dpaN5j\**Iff`|v؃c[o;F懶kyR&v nKFl]= a\=j\[ڡx# n>$ő0IH ]bzlo }5 Ӓ\=K2rH8͇R oxk=,r`!X, =b<9OQk2re\ͻhm{Vu:n.t v?49 FQ3Gnp< QE"dCD"c͛ ~߃GdM.5EJBbPi .[dỎB`=A:U`#K D,y=6 >ŏa= ]}%4)kjqa@;{~=1...sb\%k9gR >gfxƥd P{!<}DR2qh6 blxWUɄDXqNR1B?f?ߊv];\cޏ8h]"pufz׈0/͠t`w>ZLeN{eS"5qu!3ZWs W+ ,${t5å>:r͜`m}@kB mH:x_rY z7=3 b" QS*v&Rjɥ$VVmJA5gi]^bwz)/[8=Ҏ+jH_̧G@ֿԿ,HMǮ{'x$\/a>) EchT,c6o?kݸlhn8FG(yFʌ7q4M :flǾC <2kNKCR O( @eЩ!Pyg4ê?fpft nR9Dɾ0a3nɁg'0A&JkiDツ$) <4zVw#P`'#G[f Պ r >Z_\e!r.LrǑZDF,2z]곀a쟁T+xRR::!K0(]f@$MPz^HsNNp{p8첅_K{.v~9D<;wȓ'!$u=YMnp z’WG1DsWk+DձsCދuhB\9Kxbs h/W%=TP5";d~&d,E7=~|@.~߉P Ez  #ZK- IDAT$jEbLAɸd,b t:&o) bb㼃D(b,h{9͸IKvF_Rb@7"4`d| /aF&b&A$?3,BNI(d_1B \ҵ4|vB$җhfőۮp+D{Įýqy>cO@e39.<"{0%()T1vEd).@-0"ҫJ0,~] gFe|Έxp$׵Ë[TZ"rmz&Sn -9dG_CA>Rz\9cYdFϥ%)SKbnGDQL1Fʥ[sTuα[7'qt!BZ3\ ֧u 6OӄΛW+fcU֜38H$"PhZ=^zH'(o!Oq*I!ĂnH,tYEcu4#hV/HHV $Z̭w4njxĄIs}/㵴E1saG[0 ^L@{=4cꐷ_Qpq]Cc5FmY̿C%/K)mXϝ YvMP"B E$EFJPpL.ސkGwef,V#rGP<--WGR:֕F g @ۀ1`JoC/ l " B1>~yۗ46/be729'fn̮\Zr% %Gd) ͷ5Cš֣ W?]ITx`@)@u!lYHč#1:3X66Z^#]T?*l6TjXu2Q6%LMNFQG9A `3AE% (m>4 \FXl@N9wv}/f,ևa WG+bUksko7%Y;̙ݴ%BUhpoO8$ɴ+J91a0^W-՚P"$cOiw=)y6`i~'%"wӻs5$ sшpF?up.QYMmqca"Iu$d1oW9NtA@ ȃA:yHȈi@jA\BU+R$[BWoEH5h RϕI鷋)0C$\"ԨS@0YCDҊ SAq H ?Ckf3BlJQ1;!gB45 i(@Ч4\EaEqK-[Y.2wͿ1,Ҍa3 ?z8'53Gy1#J.7^5 b'4!sDT\_ YTDIpOĢA`I7? ?M n^_AqаfHmPzѢRe9Hx3Bf3ۀӈj+EàJ$VfJ7;.TT%3Tgc@EUD]a r+ !`C fdkvMJ l j+:Yw̸t",1O>B}WaZBd"dǛ]B&i>Lӄ?gqs6eB tbK | Ƅd [9b`^IIRDo ꍜ'-i _ۊ\mکJׁzw V6PCj{AHZ:e6zVrB B{ $%,~d*4$+Va3-!'.?O|X3^:*]BRsp%ɟ:Bwb@T޵EkV*.1լ4o( Tͧ͢Qw(@ (I5YwA$IT>EX V"%jsJɘ $|%'%g\\^b 'v.u1_{ΕAOBg@}wc7Q_܍8~ф77?|H!@.q9"Նc!\A<s]$+C v 1uXux1 5.0kZyj*H V >zU,8Q.D-\+@uF,DIy^:9хD D'RƝ;wv'5~~"qZ4;bQMZàeyXrhZB`\y4YwBl\ًmXŹXJIHׅOs [mqe'"@D֒@)IiC0fP)!3鲠SGUdך'~<6&2rݱv0iq-Moj/Hm'3V 0\}D[^Spo~}ehA~XlԿ?V//C$鬿vp^ Y \ HH^8 j'߅!DgV`*DKRi>JNB+`yĂPUھz\@9/ /fcUM䅙HYtPE2~"frk.h9 .n JR̠an1 JķR~7v$"3}/b!iUEl[1_̷c%kT3m7T!vR]a?AeKZ 4;gt]²t R$Q,'t"~9=p;ߏͻ!_|:HJ@]i{Dnv0tql]jRCW5"EQJ2Cl,"s%'S.#o6:質SKfu"0t@v2<-mF.:S'۳y([TW֕rAJtzZLWAR}ok2v;\~wUݺ| CY3 `BD-g'ę݈Մvunp,mmQ by snu:+b9K/*&$} zmYZG~u^u͍ j7Qkk캀z2 Ν̾},ę@NHӈrW#wPOFڏ%!O gOC<GfWo]n1D`E(4 FT3vƴTNJ 6D[$0d% heT`~'WB]6n^,GPl,e%ru.0Mw%jj152+!I$&(Dӗ/|QǩF9wMB]5R s@y`(8&GM=bPR%w=:p '12_+"yNmܜD5S- iRR:I)]k]Kif~Wܠ5HF@.t yN1vmiB@dԘffTe7i~ & Ӳ_ *iZɩ!2š ]% sIR"mO%TкdA DIc -4M,o};|%Z 'I:xǙ7k2Q4\V$M\a֛fjZD=םW 'p@^yrs&xw| ,"Vk]w!Eg K*)l2mf D+RrFgy?DFn&ϛI4!qcyhBnMkޡf`ѲP:_\"(aIKw%_#XUwVey]uj}fuhy=1dLUY /$'$/H!0mE 1B)(!@gr5f]CM A& Vcj6b&,CKAۋJۧyf`VrNY#HDJ`dԆC1bWIKbVR ; `~wd&{0$ G>FoC$>:CB/0,|LOQ,C$_2(H"$HU3 gU,N󱓁`6%54JHBHq?r@J'XVQiYJIR1Wf5-O34G:q5f-l5Ҫ#uLMZGԺ[K=Y 9VW-*uvQl b5?Db\e:=1y(ԟo fak}THz}_r.<(dL<͹}ݱ! CϺ׽ȇ.G ފ3gPb3keVԂ8R n<+DaU&5D8sHvmLђhlX rϷ ][Z淒$`̲؇M!2/|A^x!FeRH:'Y* Ů?-?HUC2361Ϳb ]T)Tnc԰iH\"4=^HG3ͱh(I|twqDG Sœ2aXbQp]a;HQJFgg{ iGN4`wH͂$DI)=.hd%t]_l|OT++>NHߔCt.9c-(q}^ͫd\0P-Y7.1PD4+E2F" V/=ů؏b;G<hmw{~{m2QO4]9P_ =g6UCSBQICao[LSAJ#Ȕn%53(WG}:niI' "r|_-Db~W)@LJGZdQZX_3S 4/>U팪*6v5aa= м DfWM Q%U\mx&@Vt$#sBT IPNA3FTēHjuDUa %g5rB4~:,H}6^Cu:>6mx!z-{> JzJRem"Ѳ,`cڟ SF<=chY_}?z.U\P,Audj=^DIlrh, 7E.m H Țm QlP ຾ƥ0(ѱkdJw ($̉H]_1o|bHTJf`U͒w Q4%  >r&ٟش_?gǾx8w>Ӈ]w?u8{? yDCUp,2B,Is]$&h!DElͩ'z-a٤ ;=ѢA^ŰO#RqA:H uٍڄC9:@'-rڌ y+-dOKJsWR!d* 0 f5M9%pbwm;[KU)_}_x%WOg[.&!>6CMNPυ1+ IDATfP@[dL{K !&,9LLvδtuCB]_IѺn7jE\A8pXf=_9rsox, f_۝PrhPBc.ڃ1&$PdI *r!OxZ"rH Հ"^ڧG᭷ÇlmCEU3P@P/FH·n!&:mWh18eR.aE*ck@yuOj-i=X ӫI>bBG)Q0bb'TN:PMIͰH&|z!fReN\ J7LHMXH)WˋLٱ+U5Y+%T0[%:WDwi$)a']#*\AE"ou)4aĮ( NȬ[M` A‚Նa8)ڶhNj^7}r Mxq>ś5GleYj>*NTǩhV5X0 ^zIZ! 8zG[ί:%@^-?ˈw^F.gdŜu3j"mшE@eDC>$وi#" D6s-6aI DSCLF2mp ׄ*XѢfHL ]ќe O.pg"y!hN =$䙽ߊjGr I\0Dzg{'/UɒkN宅K/@HEBb ; QHB5J} &bQ'ȀB1ż5oo)񼟈+`.U HA#,C%n>~$6+8g{xauȋ`#Yp>$#%uu(0 @|.v_G&nK:n"#>cׁь\wuZkEt:q@rà,E*iҺX4 >X>(#v='P GRA̰H _/*B\}*l"3:/!.:"B !' b-0- TNIf"azSosbgf̳hFj.26cDҾ3Epa躍ۜTyv|W~5޸O|)Q%\1Kd/rdT?r3hu 8k4ӝ VqE8Z_Dvr. %5V E݃=#=֭>s!׳{Bv4}3Hڪ!av7aG:ovA mR_3`I`'>"Mj<6_D .9TMZ!cjno6x~yl"W̠T"r{\ǫcVʏ qd=wյu67%t}WmXwUG3s'5Bm5"Ppm;3o6sgqj^}:$n16 `I>4!{|xi~ PH I_e%5-Aɨ_5GIMxGtU[Ah #k=jhk`gff @ B;+#/V/4pQwu`ȓz.,a.q\hQdI?k%TbL%k+8 XH }+vMK-k^{ wq=ܹs ~ǡkozƓے~TqGp~~xP2nhߵM ଦY D#TɽdvЈq% /VZ&Q^P.66{Y?\xl#kHӀ Fd,]pF2?dNYsh U `YԽEz̀kQsC1N4M mI׾)b1KR363͠$(j,Kfl- c<}Fc6 cu !`#;AK4-~ 1aN IfrN>Ίf!)]' a9K-h-燊Dlm qhdV!;{_gN3( t}.Vd% 7u5 `6j,bg$Z#Čyw|CC*1v1y_Hv%橶5/E=fMQB4b-̬BBbaYuԚ@B#xdq5F?0b"1S"Nli]%# `Ȉk,= +(FBBad@@s9! zM2T"!&&޴*{B9A}Esv{T&6IAn;KL,ڄ!&( ZJ ^x/L??_N-FX.̐ "4ŷ؄ݺD&"/ ͏Q`cX'l*}7_QOJ=ܞcc},hBB}H/}~~_1FܿwJ%1έ=I7hEmy~8999Nqy'Ls'bX|тv|jcc?R>ǂM:aqWOMú|*1c{֢rd {;!4:_fve.>#beQrc_O~=b +ΐwZ %yX<039!]¤*E"{`(W ۧ4VC9j@)@%W.fTɒY(x$+\ $Pk~KD0N3feBaV+HB ҳlj4ML9g|͇|'N焟]?O8]V_ =R i"׀ 32`MpRdعec.4&ٽV)mI3s[mIMe}fNNNpvvS\\\UxnOݖF*EpHs۴ 1:Zkm|>;ǂ牊Q8cH];^`6J2 AZ̤N鲏Duf(%_W;#Q_J#X9aijk,U rdFtбMu|܉YhJmc+cJ"Ee@)fX,U7nB[!sAjPAl3ߪmPߦռY$qa=bh1KVvKX/rY`f$bsƃ`f)%./IFD<'ywXLMK=__>V/0zfJ)'ӄ>h9^}坢"/#ip5y g$!Ax蜁#iO7|~5H'ޚ7~8G#(jNVHl{s4jh`qH%tfF*uYfX!O`9W F)ҡj=9 @6 öh$|J|_r`#RwInǤxAՋfSYtY{; yN2y9%MaĂc_IŇ3hmWn'ֳk\]C mMŸ=k3_E'}"XPϣY)n'B^>]-Q;#2 ,"ae}LT 0+kLk(rӢs-X5}6/Q^koxڵr3{P_ 0"VAafEQZC[` JPPə߂3бNNNpzz "fv-޽o=XjBnqהR0#qyy ``2v+5>WYW #h6q fê6*Iwc=esא+eYܾ;1my3\k9kھv Ni6 4i jmFQ _ BA>~$@-4N'!INڎ?k~{y?k913\9R{\s͏g`]k<E *?w_Pjϡ)~oZ$kO=ۿ4M(#)">L9[  QՈ)Mԅ]N?)1 pl"qiKs$P5CK%O\';rJJ00;pn9NP(v󌓗 3luDp IDAT$d0d-D1Zo0OD#?Fd6ɱۏe9sqɀ'n@5 tb-ich%!KɐzrkoLwԂK\]]z_njA7lս6nOd_T3#I YWHʄi}=Av $N81/ ""0 K^UZBh*#(C7VHռnP_wXNZ *QUID2~*LWm{>3$J9 n 9>2-i& iOՕ Sg,=&+܏! 99s0zsUsO9(fwBs\ڻ{9IWSmFװ~>Nd4&8n{X5g`愌Q Y`=Q8R=Dl _۲7T*k{dFXQ1mD? ?#ϡE_>o +xoV_Tr)JEDpnħN/0J'.CziO0 ~JCEQeFJc@Z\I ~.x;N⻃EG0G{ @r'֏eh<~lb^M0-6a+H)ԁ`鍛D;#x7Ϙ `X(9dmzqG3A4R“x<q:ߜKX}y:e{^;9l~;1jUL)I6pD)Nפ5H8[|iy]\O89o7 c۳y7^ $$tڗ".cCtb5Az~56XbTPWS\ !a'タ/q w}}TFϾ""nUl/g"*fɤq-JDB yʑT/3|sTMgj*JшGM:aH~fzm6O3M6Ɠ}: # P69 #* 777,77QcV]6- Otfb; D6t=A+~œ3.]Go,`C=1ViLmrv4<3vxL6n {voD|iwto-Ou j&A ѰЩ[#)C $p3(tw&YWK+x.6BT `_Je_jN32x\*607`^e@Icdߣ#G;Df웾T7q+R3"pp>R{txcz9|W[iG/ \CzdtOPodŧZ^DՊz!;=~bB }Lߖ'q:ϛa2Yɩ:KI*TۓTw^I)O>1E$4K죍`yʨag6 fꄠs#*]B6*oiV*JЦHs6(6ʤ\Tq8!Cݠ^*\CT4Y>m&q^zRHO)!dj[ NP{lE҄9ʣqd덍Bm%W+ fGq09(AH}d|+w|.oȿ<7㍛g )~Ͻ_x35&WV 3:8OQiRk1#5|n2P##rَct|%AY,_=#8/Qb,"R`L{]]Q7T0ǖ׼H'NdzooY7DG3ƅ8U dH33J=Emu<݁Rj5#tiM*1ϬmeL;vZOٽtݲCӆحy'~[ײ{G^bzmoǗ>Ku|/ԯxcئAu?%3pBf>nD8E{ﲒ4@PCOM!Ӏ~dޞ?qFhS=Aq.ᜢHJMPthL),s2*@(τ*|*i(f`I}n*Q^['\sF`;7a)A7^m=';1I>9k Y4(FZ7CF`2 舾e u3Q2 p0 __}xmPx: A[BWjqGkœ۩۹$3aSDG|h/:] Dz L(6S *E=" 5A:piHhMU}g/> N{tGF"xt/PF)emei!~Yp~V )YTDx!?qF"S^ց~"4T-Dž1mHV"Ȓ,z%b9 A40+Si^Jũg稥b-UfWۡԊk3 2$ы777T!͍gt%EEzl,Y02Jll {|}FsQw]Ԗ >ӫ/TVw ^zhk.05اDƹɕݚfv@ 3x3x ^zP"x>߅| 7po6E齞雾ozCD$c/ŏ WN{z)[L82M9l@HF;^ӚN[F^֖6+ \"'y@LJ9aZ NBv#Q !uI1;@8[2K*#)agK V$jٓjKPIvj!iBќ3ɼQKf/]Dn{9&Ưl-yg|K)HS6`06q1{U#JL uPUFêk^ 'p {`CDe@QB 4ڽ~qym3]!7%0R<؅i3:y<k9":%ɩ neSTQn)K֊{bP +C%&č/F6\ؾ'ol3n}G3H3iVcӮ9fXeC\vl [{õ~ȮF6f^y"x mk  ,Q{aҀV62Ƈ߆/whm579R>dJP9~& 0ЙņUCl\S[/+J22)d͜s9FliF2GZQˢ8;?76, a]+9E?;b3)(i1 X~ѹlhrrc=y2IWH̻ t?'ȔY$wiͫ6s+eR2ւm2ezDF* (cÚyV"Ad`VfB|"k5H97U4;ghr|w`AoI2l ' _ ;[ך%k[} HiE }@/}^K<6"ccܿig|9dEYCÇ".0/g(y 2hXz|a4/·Z94)@s4;hY150m?q'\.r4ri|\D<խ:D`hދp; ԥ7<%"%F$6 4^)n[;k; q N  #UaVe٤,SʨGAI } ^&\^_^0y޽~:hY27=j, u-DR3Bǩcz025 6GGtD + ?`+n ] mqY`qPh4T p@[oQľm}.(n|aYfeQgYi*Y+8jC?Ў|Ws@-FR$(nG _^2ޅ M =7b HR_4=\i2S*&ȭyN7Y~Eiۣ;L9ng48}ւi%"#I/nvӲ̨-UY J]Q< :ҚHb!j0,gعQx8LyJ- =z*F7[v֚9Rf֟Zey Ȗ`LRo!C m5ѣGW0yA%/BH@eb4%'L 0gj6]K '`? . *vWWx=(^2#3.OJ\C|=pT@dxZ$OFB&WB`X,MJ-]Vh4nyOi5nNKjQ yt΢M>yHjLBz5w|U &u Byq<]7y4 y@Vj ZUq9j/D2 ϛ%wtoQ:Kϖ- 0>JYqt-eɓ-T]kE1d[xE YU|3.}Ut}{wOװqL"Nna¨솥jTyl'b N1B?(+4(}4ʢ=B}(#PDe8 #7OW c R0BGH@{ߚQ%+~ɢٕrJ]%/E+T\TvX،u@Ɯa cDa4G k 9QZ[mݰE#6|A G=:sD{:=o㞡wAڀl:# @DD^lsQCԏc<@>L_Kl~tw~]Rx l~o,VX"Ӱ `2XBz5 &`JgۿV;n.g -'U`a8Pdw^И<k_8 u4fĶAzC"P_)[j dST4 /ɣ91r8e1ɢVLsFmF2Fl=UBje^L⬔X.330G8Nx!03V5Z JWk gD #ch©k̳ 4Wׇtᒹbĺ :}U7 gg%{֪xrŽSQam H5ʽW~8a6 7oV#. 4a1^k11=Oze-9h YSM#ֲvUY?;)ب=A=vS̤Lw5k?*s[< S$14RRJ~cgukR'B=K-D24CXKٹ먠U)rձlz X<[E3K=&!HWE)u-\,^',]?ia6 ~m7-}HDxq4rV Do>=m?#` I&M B:a4H>%,F衍,ΑEv2l 609]zZ4*=YCU;o DOѼ a 2,ѱ1:ҩR]6@=^̀GC1CD=Zc06mx&jaKƹl}6^;h︭*IM Rl<9(˶e4D. IDAT.s`„U&H4(Hhhg?c/]lU>0'b"ݡG&GH#(L0Skc AX`Wv{4as<;_}ӡ:y$i]WSSE9Uܽs<o~wG^uGU]Н 9gy$nUr>?2BrmɼϸyxgLlwʐygbH͑V=J y}+jy%h1cgj앧W?c~vU#wv 6̄_/]b{=pHT9S=DtVi.]qJ=, i!#Dä <ŁH}3bg(#G~d gNC#0HoNWb;H2/HEv6m-bc2} _y(j̓hX}N'l=$2*q@'bl 7zXZ3/lOlj!ߺ^kdjUSJ1$/p<! 9'؈iLJq=^ i{b? X7H//:>O]%\6z1;2O fx`x !Ѩ-' :pTH+'FɌ"= oծP$-?e' ;ͧA`B^,!V98[cʛA4" %FLK125lL _9hv' 8FP@*~}ztԮ{c2rcc { 3.5DORV|sg,MJBzORp6ls0#!Q.wц(QM -Az=UZX$DRBKWǃ^y[[e9 { ɧ1lѷ5N sJ 9eHv yf=)e\}ŵmaغퟭBJq&SX%Dh?mpti|^کYz͍T|g稧5neg^z#b=38>/*Y†Tm:B/v&H^M^Vv<q<=Zi\r˩_fÁ[;s_nUҵ@įʣ1}th͛?ST%_y[AMn 6u!b?WٵWy y%fԕ'G4W\Rhs9#o'/n'Zw+n4a:թWu M3*C,R\zr}2[bwZsEhy|nڰ킞6NnI ޮnA-I赘ZnQ잦) QCBZ$i5i()q…#ndB&_ȋ&Œ Ѵ᫵8>BV ÞSC;шq{ fX% [ゞ'<ߩo4I}ģ-4tsHƗ7-PR@nCN}_3C8{5c 9cwoׯXS!  @g!2AY֐ y!;EnFT lryDYqQH8JzD#l+xj{Atm%TAoP#K,4 J(6 "]@k3~{.lsZ:T;`Dc(0-2>a3EM"qXHN`I ؂ vhQEAZ\,T# >򫬪6SJ"("&W?|gM2׫j6 /1V \_T(#N.Q^7sIo&M H[<7ֲ=wAXԁU$DAT "ZYVܙ ~c>OY}v8ZkjC-vi[rJx}Rvs^B3XR Q}Qw8m֪>.$s003... bY"I7<tc;0C@iԛsj{{+|ĊMZ +4Y^l]`>>![j$g_Y?HuUY<'Y=lۿ%p㸵|iVY*W"3/"VvsRfhMk7lj4AB}܄ON3Zj,7U[,`, 8N~&wSvv&Hx'(9cK)0:N,PB6Ž_?(kz"UmNP1%S1x򰬸u'6"L:9ZI܎ty\SRn, Bjr"L*kݻ*.(S>{CHXw}z5B(Zq&©@`#艷Zyk0zwiG`m:< pW#`9կZQr~Nm7 D@y}}P)&,o7cƗcY&BNё{JБ1z b= iSغɵ)5ݬ=zdY hަ7!͍[e8a,35-p7h":-2E􂊀4efXHY[Th44Pd"Q۾A<2ՆO>ܪϕ !#]SR^ JBj7q*n1-!6[G0*eAZV 2-)X&Q %񿿴~{%nJ@P7@0 آ㾞ESct@r]jt  U I`{ڟX}Ƹ’c?<9>Nٿ쒦v5JDn* }>} ȟL)Ν;8Ql&hmQM@1A e|n+`yƲ,XkAnO!%M0>ߜ3XI &e5n[O..0(˔ 8@]NHB=/,96i L* tpԆRY mLDԛX1|C?, Ζ{_9~㣸/yɬ3V/1oןzuD j@PH:݄#wآ x4ژWTĨ"=zwvvVkPPjřRB O9ϛ0m )F8yǢefYW4AK onb icKBi`([n-"16,9 IXjƛ~8|~~OUJjkT-s@Ӵk.)1z:Ab-&Gsj-o}waig=«y#x"=0#ć SڧH6CD/F90u+zwv?zKhH中lXX$<wo.G^Aakֺ߯Ƿ9a ds8~2OfSi*e[767<\Cs~IXZ8n߀%Ǵףy4{$yu:DN?S7DBlq>q;_:\esC48ux#"BbS%ʹhF|)9NS(8~7߅?Ն.MD?2'pk\sMzdq[(Ag`q`Ұ9^FՁV|Ӳn4f--X9A3~W΂*Oc-DꠄDiÛEFӖj$ Û<Ir bd?:5Qy[pmIηNՠQMޙߛT[/R2/@f4w2w؛eF)F6bLj@dZ ֵ`"XNXݐ^|FE]oEvXx 뫟 VN՟~'~vk,j4.Z-qNO_`y%)G6TՆu@Z*gH$jȭ5l>g2_>s%b[V Z+r܃Q^G22D̸ZQ @Y ..quu @p+rq 8h7iwT,EUN  g|f7'~<k@bD$4{#h4P6hjКNM )1- i!RI~ŋEd` &ۼ2{0(kus9 lɤ3PIiɑվƪEōE'M~'Eld`i oUZJйuo|[4{~@/rI8V: K1뇴Mb%04`6bU@M'I?<{P82j)Hiv:AǬkI=2n Jjy)XyК6bLhu]1/VBq8*jLT4 *Gm/] d&} Yp.a#$5$١X1iU:OVqJsE5Dy_XؼLyxGi6ۢ vx:^Xb2ZE 8I_$dZP0?6hY{$czzԬ#z [ymhFrhC;i١ J X5bC4(A = 6Ǧ `^q:`vA#y=cm4>0۹Ѝ dsZLjˌV-ϑdh(N.|;OL+f(Q)(hsed[nnn"r~=OǜTWI. !8xo|<7g-匪-i% AK=f|Ze6Ekdq1zۊ)x߂~&q*D[Ә$aTA|j>!GQf6tϯm  =6T0+LDNҽB3=S:}O,~cfQۼm`r*oFy-VV9 9r七"-Y1cnybiN]ڪBBMӜiT*Y41|0J(P0΁FkPB$kr`@4eErjMU枲fkd@іS{^]^{jz5-,{ADH{ω u88!ޠpK[UQrS($rǨjWzVA+NÒEL o5NGn t)]:0)E{S+0JDa FOl9]#|T1 4垯%\}5O RlM,Z30RZ >:j{rkYWNւ͞ߟAX#0Aj7m7w;`1*<)$Uodd>14Osϑ; 9#3Ja]<(k/nLV:mѦ(>4u7ǣW7zi]5EX u SFf _Vܽ{"r|ss+GSpU7f:Hƙ86_9#')B!lxMۿQv\#E$wކE?x3T\Wߋ//wh7/b#)OYC7/믴i@Z{HqNK 4FIr2г$H-@- I|OټٔJ5L-)@OzOD9 [1F0!=01Pc!q^Ggo Jɨ(a$ ǯ%U],f-o%,{ibF,,@)7USSs޼?JE~*gBߘl3I|Tl< )Tb+TsDM BN.i _+#C^ixk>\phqi0n4 U Tfqv#)y{>2|% G$Ϯ%wuyM#e.)D7 j ,?"g}l?Gc'v;-HӰz2š1a'pwƿ5CDQMipi"SPdTcd_k E&PRؚf IDAT/Թ=%a5?1HSdAN]h;r-`ҫ76*Wk +"qlzŔzXrc֊?Ww^JC0(*yHƱ/*U<4d0 =A[T*X>*+p!e~)c!gȹ>y_ywF};N)G?fwenDmbA5QSY<3t0Ph7E= m{#vkYMaM8i̋D÷Sĺ lp$yӆkX͓QYw4Mx)nnn3ϠԊkȒ."m3-SDԟ5_54(иw3&A##8|6HZtKTQyQСNY {>[4ƆHk@)ntҋ`Jށ9~<-yȌnAyFϳof4ije=@K.i ҝ|>{Ԙn%`sP#"׃K7 (*I0?v2vݘTz-4UFOk"a=<~pB4_VY1JNRa5XR c&E!8ֿKId!DD{Y\E95s a:9( Rm8]^?I[ua vV}<P;ڧuEJsl܎X/ފnZ7K8*O wÏpod9>|}]T$MPa%„*ZWPvkH^AO76yfpZO" WZNM)ז< ӄnց2;1)=)O'[E00Ɇ\h=̼I)yO;Fr ԫyD2JQ7"p6aHuá4Z+CIs"dj#uYetu1i|+᭚X V+R- Ju-@ T()VV,9CٽFiU%Nhj92Z$1aGz]o,"SKԚwr#s?:ńߋjSFKh`8PINE߃,/___2$GʘX`u7+)k M ~ >oE oe RƲh9SL_UM)&P&6)4{nF$쵬ah:0ĨUyWjHbjf<'t[kWN=7I/H$I/7sR&x?by=Z%dQgHZW oE2M ZZ**j~Ij}nsTM2C$C/`sM4!?>W4~pGtl6S9ыPҤw~O v-`|L^ q\0O9HzdUO>wQPjIU"jY N@Fޔ\(9#2FE'~^Gy0IqYTrB%`μSfx?I;# 29(NݴBf]]'9(r(ɘ;Kއq% >7Bvo*VXP!0}ztֶCQLYP}{3 =^Cאy|}]T(VASFDpa]L7<)[L?A3<`NOo7=I.5 tp^: RZixk~ݞÒO}<Ӑ}{SގdzHyuM-x<9uEfW_lS;,+_QDlWuvI ͅ˶VUv˂IkS Z*B[4y 0my2d[R)h\˴7Wf JmkJpߎ7WK| UkcasWX AUsx:ȰN9̳EK,bGԆ*p@$/߉~aye1y^LIB-IE<GS9g &E1]#g=RԘjy!ަ0l !U \xx&\G H{y2*HqNa\gXRo-&lDFLwre$;`:0SqT51G Q+ɔ;\x ^6'`LiŢ%9u5og٨ |QUȧg#L9U[ARD8s2dwR$x@7ti_0I 4pv; [m":ƼF{XUJ8W+RVx""Ь奩Hyj%tZRX+v.=B98ֲ;{xl޺M']L6v5dT\qӀ9Ǘ*${5aٟ!vAiXp:.FGs{"MC9`9ѶvA sn*_[9#=9 vfU|YλJS'[^/ފx ɴɟt/u,hhQdIBC;^B Qvp 7'Tz=z⯴C?׶,Xksέ~n;v0NlܱMHlđ d"@V+@P   YP%Ď8tG~vw媮{9{51\cjk9J$0CRyuUH|Q6V$nGߟg$"e{e@sDYx1~a&ó?BǍu,HapM/~SoHZj JfO' f=iuUȩo|>oHoRfYZ zVҪ:i&SvT#NĄ1 ]FŒ+NyA2 yRыl.v5n|CZDBrBvVv|yR(iEu]C׳8 ?ivELD~\'Hl9)Ƅ_cՆbhbp bxЕO}o&xV`$lvC}Q婖z,kf=%Rr?^O_CcK Ƞ_ǀ1x~/P8 =e<unD|S44<7d63wG/;Q۾Q'L95.@. CB@sm<ʝNظ2:RJII4pDL Y8aA3N9'Up"猐pm5/BszWq-ߛpgv嬑Z*v~N ZQ}@P=8ޢf*sY0o; *u7Ч]Ǥr`'/^n5BOA͘Cc. 6L <{g"Zz >ß;o~Ʒ_:&":|9{"@ 2@A$Զl_ZgVgQ30wSzKfo3g>/nG#N'LE䔑rä#=17,JZ&[\au-AwQZy2p谧j  O>~ŽZVhz^I !Њ;qm:ZD)9(\SX_7} =ܖU7;Pи,WҞ:ط Լh361ҥ@+yE<@}n)p;zY<H4  ܖ!# ~Z3`u: -z"]k?ۼ$t,V3EogoS7/܇ z %Epdd&C.:уsG aG!3U;qb =[^+r1׎FjŚT5c#Y2[9i7u4>5!bO^!lBEG*DkF?hh!eCVhA3ZZXPJANAk-^p\X [oBPZA^W|C ;1CRDΧ't`&;Z*D/iFw®O+,P!B3|7/3wk@m<?h/9rթ͘~ynI˚۫ܵ,f\KhQ|NugY+85:ŋ{簿аzDB9uP~<?n!P|}.^ϋ l{3ń/wA=@qze]e.w]=)=c,%P_͔:g^>lW[4~7~-&(P$/!hp]Ŋo[\v1'=ˏģ ' ,lzuҰ:^V~6mV+BLR;5 lya@t9<g? ^\dx)yLJnXG2^xX4`@ԕΛN{#(Na(Rbلd1` "A=Zz0Ĉn4#sP،vD9dHEAo:u(^9A5ylqT1VMJc3^ ^ۈşПOg,+ÆeY'G!&xWۻ;h{wR*wD،" =hr"}4#YG|(}9cA ȵPˆLTǃbP5GDT^pUzK廏uo3]jW<;lUsw~y{ߍǻWǹ&Cm'Msܮ׻#ZVB 8D휏p@^b# u6h7@݁ubvw,VHDJ)4uxF'߁ # 8??Bu_k6xH*꾍qkސXrf29=w\#ttĂxxxOӀR)fS z2Pshzm"w~dm$.ƮӒ0p8(clةŢ^eENq:IKi Y}Y< `E cO['# VeQR=WLBuԉ:~ut&gζF;[qts8ЏMP CK ^-+hMJqeJVh%9\\Iv% 0/HBy e1ܦn\' irͽ* ƴUwDv؟ j]Hĥ[40mLl]<]\O核ֆX;? G0dH?c-.](,h}\ڌ׽uԖ ѰAGQ1D7,»0i~)4x8[^t[UQO퇻aN(PBuaAMzb#[ bCx{*bs 0j[9IYCS Bh ެTXU ?v89]KLN HU3-<8[R˲tu\>ň X3 .O9FcGm;Z/3kEm6,Wt66tλ;<>>P.zp5C1ڠc1heѻxoOm|!pB=$!CU;8ąW: Ա.ax;vuNj _NO?xfrD+D~cNy+cwFC/W"F ĪH%N"08:>iM]. i]m![f u]@uAD;V;KXΧqz"RCHS=09"_ ug6~,2 nz lf?OTl;GJ)Sl2,9&9%)#8wt˹cXr ^o\|kx!Nndȋ il _d -Zi- ##[0K]vHZDo~! ! d5 lbUOO9Yi0)N’vFkmH9)M3.|M4tEM ηv `5~ΆY(wK]= 6v8Kj C=)q>i9RNV }MĶQg֦0*;/%Zb z1& Ŋ>#Ʉb>GzE玲R^@Bǔf.Ewk濎Mm".Kr[ }co0KOnԪ#{@ԣ۽h>P1VP\/҅{,@\Do O={2WcpF!B9Ћ /L)^g=lFrq@6a 2ߓ;?OaB4GA|g=/$"8ֈ"]G8%V6a8bE2(~"FPsAmFIӛ; a"zåb]W:])\Wnzź87x;h/^ ݝWƪAfkE{=nW$ hZҙhKA8>^;):GY,aJCX;{_ o~G Oi<w/]/r^=޽Bd ;2ч@;vy_udPD)zq8u+ Cⱏ7vay\P<(Of';QaaB^oy$~O k:WG$H ?8$mvb0u\N"j{3EFd7b}Fnw2^9xJѥtGNCAg.vf<։ȤjѠײkGmf?O'(Pw4 Q)}*wx @Ϣ̾+ۧC`h]<q-gag+X@#P .כw1Y?ۿo˸yxĠa1m7 `wsN{bči@X#n[KlxW T˝>́2 nooI|KP36XXDрqI:[^9E񼞴p)ޫVHQ fW>JPǜt$OK_ *(@G 3AB MÐ ^uG%R|QETG@y+0+(Bo"%U$D8}UWfk<qj:!=a*r\&b.`Wo@4juhFV6gz#]䈢Is8K) " ɨ'1 o[ XaF(0It:/L5m:녍ӀZdFRz;˻ χN0S̼YDVo9] !0]mkGkٛ*m{:zy *ɢHi k%@,g^X26Fojh:۰ >ǜaȭzW,7qt[>q1 {qYᚕsFitQ~0(/x)9=̆^p:Řa\A.t:a6mQD4jШ 479"(P(S/ho ʛ#-$к!_i!5ғozqԬwWM`f3Q8Pe'ViKHPsʤCTH6傀ijÚ"])^YFwƌ#xYS0Q9""ǿ(0]gܵQz3SmG]I`5-ev=P R:͏׻K&=Ŀu+":Y9I?GVء^TfiȐk?w|v ZQDXAg@Dui{ $>D`B֜!2x-GCIsD=ܚWI #q̴>~Ό3sŚ]O1Am+XVRTt;JZ-=<ěC4K=`L\$l^ m;H3'pz*zk!q9_xYO } ?-!b t54Ga+\< Ƀ6O/]cVc|2)7>G^헿w;JϡjǣՊEm Kc .W1߸a{vnѻ.no8uGڑֵ[rNf@m Q9@wZao @P)RJ({9wc@j8аHfMHUC 6ZĄ$ 7;D#F!s(qrD*uhntj(Cp -.>!ĴCkSߘ׵=rF] \`{UnDb3:T4Ü5lak^/ѼlFSqdϯ9z#wE<[^5Nn!Fz:&:^Pײ& #fxp6,9㝇 (4)~~ud~jm Ͼ6h:Of!x;rfpiO!BP>"AhA)V!CG~tݝ$kJ98"Q=yHZPkO}O)#mwE06gt0Uض Di\As28Ɗn0r<(;Ejyt:[sy#@x=::ڧ}2^MkYi/ e!O<{JTe/JgGy]Wɭu$m2. yCM:? Gsff661Z;b.;8)&sܒ߼,h"Y7l!#߆ϵ'S&¥jŃZH3_ +VEr0L iNY#~JuWǏaYXZhk! >鴎>˲ Tε=Pd[D3ו'tq~x,KӁω|qH Xr1D`ZVCN9a/T mYиVOC H6Ng~]Q6 f j.K8;E0ML-ŒNӦb[IB^i]]iϜj{bUjQzrIf-JhgNq/!fV8,[f1'& c.H3W8wR( VݶD *Hzs޼,.iWNskAh,:+7>B}cO˂dޛL)Oӂ8!-z;}e$}-l"DFBvBִ"d4߈j ,524KD𝱥BZY5 衏HL9kEi)6,UEna=gbw ܜ(r=VY̲,ő(:;`/4jaRRF `Or/QHs:ԇ8CG*H([)vl t`/ĄΡ_6k_|qKќjn#!@QwБ7w {StZ|o7S?KxAwH^D "{\,G#&k,."V-yBE^~W2R Н zvXyR4/)d@*g'S?􌪶vôvi) 2{e7;tp˽H8vHY9C "dPs@NtBѵ Ze87lׁ9-yFU+#jCJφqF4xvG]ca>IDi"+ #>.}b 67ϡh a%Jܡn߮r=hbr@jr*:te ߋR-H Zu^^@FwvS"6  }?iE wgiz7=`1 Gy u 0nס&&fwbwCVV8|>a52j;4K"2UkK}NkЛ}; ȁf̯Ji8n&p@Aƃhg|fs`w<>>Ydם;y0Y+PlHz.St^{#1btwCbD20f4B"Okmq?0?+W Dha}4 쯔]&CRMGtjT؀WU"|wZsj;_.6WX@Yxg Gl\pEVhmwGG{m̢+ނ BF˕E xܮ&BHKF\$_9uThh/ <)95봬pA.CԮ;~@/bto ~(NXL; 6]5BZ Ǒ;E_/LD{E5HG',q 7DbOP\͢[qTeA/xP7Y|bx][f|I3&̡aP ( =h)b3pDFQ5*!>?RȈP2tKnonϩBNiu7&1l=N|mzmۆu#z˂K_ ~ q7ھu,ts` /tj_eP R*@y =hh4#.H9p̵~_x~c >Ň<9ܶ tqk]+@Vh?bZ,wr Nyax\_ 80ޒQ:um:Y0 ޥwt4ͥ%c~ @ C'|>OҲ:l!^b;o%8XӲuCy$p{ZĘbԵ3Nߍ(@'CX< Ep.% ,9ض'F=!C^Lt뎎_#4.AIi[YhoP3 9|^~XWL2 `:lV&ȝ.CN pk)蕮lRZL]s{;z7ivc`IHNfÇ@VjG c/%!_3j1Bw+Tb&fr>:D~?ris`F'CfEٽ𤷽3t8އSL76Ń|1;GO7 .v/伌ۍ5-G"6qplNy]v(w,"N;]{.w R*y7y:dL:Ũ֛ + H݊Ґ&0]Qa`Nm]Wp_VV!]19 y,ѢMʞ (B$dm팱xUh3B8hcZ6KPg&p}/!|r7Mq.o_|>WY;"i_OV~f+\9v$%$r6$mg7ϼUz9#vJD9pwҧsq{^5N:4!̂׶~YR:] Ycd"Q[,}8g<x벎x}t !~|~??OD{s2Iϲ_y߁l1T@;eި LbBs ۚa'=0x.қ_C X87ҬB &L:5Sh 1b~%7vs.[V:DЂO \稍.w  @/`h|W8"\c(J 8r/ -xyGW4EYN`/;&l^L{ )gȾ1{ʙIi7X8ݥk9 1zHb)rpaw/;?$EhCũ眇1!eYf7nSG:h]J[{'HbԐ 'cboa9fL~عT%G]l+ʸrCd^XN[$>&NeaE3{6]OYw,槸G!QhT۶}guP5%X0Q j٩ b ?,%׈ѕndk!/ˠTb`9F01.o40ZQ0quU(CSF6xnY%FCM{*>ۈȒ'8z/"Y]ԊP谐n?x*_.޾?m|up[ BUZǾt@C%ʋV"yXӯdz>~Gaxy P Kp]!4?DI)I< FMpDg8|Öq`i14{bc#+tߚzyb#8]!-D!fjE[ͷ Qɾh@j(Z>47T:(^7h??˚ю&Y`aG]iqZO8pD?F:@F@Q|>CzC7bG;bBw^Z=?gRpZW"VV\h2tݡ)B0Sϥ0UьFn?7izcHkB|iYrbH9ƙػ,@0L>|,O OJtS6~%gTw _) Zk[zl!qlӈwQy0!iF9q]xka[vAr>8ozDѠ $IWОbYN(U Ň*y7(F;)" nEMm3+hb1CvE4ߔfX-X׌(VtJ+'#Z2* (R@OewfNOG8|.L77^p2^ex6Xte+:͎*uA7۟abh\!F2Œlzy(`޸``O Zpwj@.p1%ltsݶmDB@>>,b,&abKʗr(P$",@ qLr@f7НZC[BquamD;  kĖ [TJC BqE`,E z~G>(ljM10Ѯu$HrP@w*3ݴMjwŒeYwZW(_S!`/DtE\D0rW"_hbkE@JfSOQ_ӏ_OâJ"z]|s|tA HlУ#U#xXgpr($$ό'vT 19tV1!]o DNצ)^<=&~.dD0mh.:Vc|21ĺڎ81׊a wؙ N78(7!Z2 !⚲-֜ʁ#"p%V"BD[jN7A=g<~o赣(D'R$kfWfH)IPC, _Wܜϸxm<ӫ`thCC >:p8ÞOA1UK_5~s Q+_: !AۅԬ#*2bD"(fHZ(^y6@]gQ@;OzC&> džWN_xQ#/޿V Ezq!bOԪLu!7 nD7yPCB@y1srZG'W9cHd ;DM2ahcUa4L7wb§)Dv]HeMﷱB M\eh-k5,(HY>aQpJw8bL׺ҕl\;@)h^}w1}>Ul=NhM~SO:?vFA_`]pfse DZάtw^МΧMV> 7! f((T!$'(5(v=tDu]Pk!8 ݍ`T@W+YIi~-`=UK!qo'7@xch &N!TUvM OY#m̜pd$ 벢n<\ 6ًcvcP^A8_TTeq#θNdNŎ r1^jxt¶mxx|b{,La4C38Û]y٭1 r{v%!!*(j)~FJXS6&-(8P:х.l-hĸj3 Jo mkC^faֆR^֮l~X ᩎv0 Ngix5hӤ`DpcX#gW (5Zs;JEa5 -qfg+Iנ(9\ 5T ͆ֈ̈VإBi4pG})fGQ_'ZTKg :dhŚD)D^rvVxp[$M I 5q޸A1Ӕ~,~fSן79ﵔ'@JnnXx\Gڶh#"M (T9I%3iVO6+6kn Qu{wXI9dMw+Jbq#3zݬq^⑇Ay(,B:}~Ok#_E/9w~e gyRs $YF1Spl3aP`V==m182$^| Zy ux_". l"Z0&2O51ơ,)za2&P{j ^ RZ"V|eS; sCX>::VBͺ;zH_pssB^Q8HP5UIuyA)"Sh^pjMǽb{X翔W_}u\ӡbӕIw}m %en3'oH"DU^iXk6]fg1id]9"蕮YnR/(JUyA{)# K8%%,9m [%Kz(CdػەcA|{{;f Q H-@ߒ[U,KF:4{6Z't+R}~\0CBda $mnZC2Ǣ}/<UXɒ8A^]P0ɬkg0 vUgP5Jp55<<<~k3z\uOH-1^7]'%&6<<> ֌h <ߏ8O+ըEa)t_a(+b KZW@fLr3ig^#/T]ƺ6dVeb;=}_ ckn"~Ώ#\_r3iŻxO BTpLNWNn\8$^z:oąT+`tnp`ެhU)0 YHc ~ow~ ׾/bFZv>:ǣT+4N1CGd Vվb/1޹E@.Ppu0*'yطT@@MS2̈́u RX#"3)X8f {ixhAbu5jBHٮ*ASNHq@]y9E6QeY_Fgt IEZF꽡1VP6:+(((QM92^+`ŞT(:B.jl^ey!eobHQ` F:xҠQ)h]1& Tȕ t %X@Br!q}nWrYm ܾ}$ źL t8b uA ,0;\3M;Mh:tlL(X찻C Q/m}’k4[1Aq`m߱}hu}'y\6?ᅱ7-K~{k"ȬN$QAٲHXL,&0g gd!a@,(4U+2*g/޻^-KdHԑBqn׍w_hc;xg`amaeeӣ gGò:0X- )mؖ&i %jnFxMZU Tdc5B)Ҡd|F񰝈I h G][C_ 靈U *[浹0kh ldzpж Oh^iJS*NC==Wkh$+hiՂZ#z[dIE@4u~wرAP0c F2@SG( /F D9B2W(_@khͧYr 92l% fIgU@ za]54EB %AjD5ȍbu ѣSn |ufs16AЇ6l("-( H nO Xf-kT5א!_cDo 0 [+`^HЁ ;Q,k։c,^jZ+dh0ISe3 q<>>{{e8@B6nWhSZ ~ZX %n@^Y# +5/;_-|+` ~?D~?C[a9%>[jM#!KY@u"f"?<:wCBs[ݼc|HThwq/4auO,̭kz"(##I)=jUf6d:Uk(#esn.Pz黀\{eAΙ±~*kŲ,2\o#7aJw {gq ǚU$V3&}5;7q9GukSQG"|PKU͜9c^eTRw~{ 5mtz(mG( d '!D ^y9#NhD^~R+CLvԒQNaho].Xy/HSZ#Q<~gH#YPėz?sfyv'~J:Ю^ ׻ qX(StBFŧ\SȠ hu7 ѿ  }5wAmTΤ&DѪЛkzgrNovSHjKҎN(jjMQ3Mx=HK*<{HԾwIӜEX^밆2ͮos3p֜a#{h-X$8Nhw_I 94kv8v#b#k4nkΊ{zEl` mEi mC&<>]lv+Z71LO 4j2|t|+ 11he[`O=\xҿpoE?ᳵB*2rЅ4Syrq-yOVw-h o?_:ݹ` ,ǣ~认ͫN#&rN)!ypy.8;ZRH!?ӰitT (!Ԋm+QR)ε y|#_TEh;Z\c{ELYmtbR)p!`_RUY )޶-qQZD[-ڂ%"t-ʠAeD3MڎkU; fJ1+]P;R#Ʃu02gj "sZyǺnN>ynD]&׸fv-"!ecYCO)9dEB)V> Bk-+"y2NJJc c4<CXZ=zc U(7[EC Am CݒuNh+2bd {${ڥJ{m+p!CuDS4(j^銺IaMhikSl[wZ$XC32$%I0>0d{_[ql*uT)~ >⇙^ww'c.Z/+"{Jv5Nja~1F\ FrgYUê{\aL78cc(GAkJ^wG bv,E4AX>ڄ?5A *&c<48{Έ'\@<{!}'=BÄy7_3LVOa8߿6:UxEZMNP9cGP(b(~7~EE2zuj0mNq8}<"%7iӉA&a&:T9SW89 #yƲ,׊ tqZUjTLhB#萤Ep6"FE?Pa|O胯ZXVS={z5xb4=9*%#8i0yC`ZAΕSjhF b^@WI!Υ :i'P<6Q3d:f>{7:1pD՜\ pGZ˶8\7Gڸ?9aGqotnj6!,e7n^%E)%ܿx?r،] kTwq{a~a YMyXIK;= =ȿsFZt__)/Xc< WKiSk{K~},yԇt-tD?d؁V$+tN;{ӰZ'2>為䔐ş~ﻰΠ =XM&10 QQ--ZMƒ;Q956tfc[Q+4X(E:bBɉSەub!q.ͮϴmގNqiri ZZF Ļw>.#M֔w=us‡ mLZ}!pbWjE7`3Uucm۝(tf2)ķ{nZr8˥<v$Wc+ZdžΠw7x[cᅗ zmFў1(9 MREo7)!\X+H;4'+Ε@LN Ns H8 PTO 1#;h*zG @']4"фJh]EBs<}0-'2/@P<%n+|ݎF , ݱ:O2hp64xV; y~v*.l%-PAOJVFYT?: 4i,&ꊖ%0%\0g "@N1]e-H>H]6KQ H:tæ3?ѣFFmvyDn1Trɣyh`"zP'we;&к(E8(n/9I̺g cطqKj4^-6#^-3b&Ԝ )o#GigO{g{ϫ\k45y#YRkD{;h.{o<ҡi"OAz78xRmh҈ -N:LC=nmDm~#\)\:i D1` z%53VQ sxs;-uccd@ϜoOp__s~x6%_2 {l~tz+!"Ћ#胂fokOۅk<^VBH֏Rt}su&@%^ iIO=l :o毥ݶV}@;=4Jj.F^8۶ V ;#ڠO)I DX;b'*S̿ 4C)LBHJaFǁSD4wq0*֊VXD[ 1t%kOg6՜IUD6RiBA jvd@~@(@P)5|9(jc0@; E @:xcP*Ƭ ">> gWBs0&CvN`jOQH+$7plHaݫ_[ 8T:} ৡS@"~X~0foF*x1jbaVt'ŚѦFxĻ;RCءz+021 k%e_Gן5q\xim-qGHhn@aV N袧.r|:>e:|=N#L4殁gA(9sg(Jϑڦ8)"p\FL71FLɶ>ݞQM&tն̥*ƈ0DZrm Ap{qN;ЈAR+Eu[Æ7MS;ݧT=\ ) DtuR( Ct*-a"ӝnd 1L \Bᬲ~-IܚєiɕDS샶tmK I@NCdlx1 :(@6=?AbvtAZ|O+f.kBi$2PIQ L(29곷mPGkRJf:9oR‹O?}S;mލH~}yQhrc&"u:;ض OOLb O|\?lE^1hE]MV!BGQXN8cZw "_W:`l goxK8EnmKBb/1eC՞7NSUt>Hr˜B NO{q*m03~#o|۶agy(=7'rÅBYذp R'XIV9˲Ȧ_FmBRJXuy@"MF4TPSm>dLV$fCSWg |,u$Ij+\.סfZz} xA^#zA(BZ|5xzzƶUjh ˶!.}].ÚT 5Ah~dcTjtF{{0eR-#cv|7qR+C'X ta w:hpl;V)@UړVa$Wc965y(\Zz%`؝84* VT€Leubart#'! εhaO0h@ "x@b&ӍN'ns"i2:Xhf "oIaVcΪ}2Ma LwC c7r(6Q  Bg5 eOK)l@9R4^f3zEFs֍y%=(b<:Z+>x x|Wİxi&;^I11Ukmo(G1l%qh><"'9{c1T5l:=TN+2\ 6"mXC8qY{KeX.%opcYiu]և=\>xC9$ᕧ &;:V}oy YeepKFqhܼX&=Y80ihnRV g=ZН(Z-u&ZBD֠ڀ,6Fν CU[* IDATVDM2 Z7S zzژ1O rXg6`0fCcgn^ ZӏbA`iHˊ24$j7l gŚ2{.N3zo4qΈzYI熰4?Z* 5%<>>=|H² k=4{Ieu{||iWSN_cy8YuZ xe 1k]בzCMDY!<ŭ52CHښgEn f ]bf@3"B{".H# )+"A>7(40ǹl 4bz:ۧVZfz;wlBf5Bߖey@#$Xh&(߳y&Ma6PƦӀ N? }F2AZSk4MizSm>MWh⹭ ^#𑲅Fj"Dc+LF^2K7Xrjk˓Ś; ܐ+"Q/_hܐ.$!zh/AkNs ;m>A(mMw3⣏>o~+Ȱjv8_# _.9;vz f s&E/,TRbCʹ<:! ,JY5vym0&vJ ƹ QJS d"uԇ)%3!tͭKk OOOv ۩sg 6fk)%T<N2uI#Zx{itsi {)Gi89z761F\Y!  ]j7oCDtc2X/WkC(@jV 7Z*u!BYZt\g!}]֛bTsMjveQyiuKKKxraYRt'L^dOx":z_bu@1FraE4ᏦX:I( Dkxƌ4jڄ12ݜsq[(b>FnYxrNK#,жaWKDXFZ*"TNy>֌;ҢH !>]?^K5}) *,}}.>isiIM wwO?y,ۆñwBv껮f[1ZW)]~U{sgg,*2Jo(g|l `-!Aq\탙3ll.&GKi>oq]^yw鏐?.L;b8_EDE7ѩG>)9kŠL,#ix YO.ߧh]݄3Z=`;/_"a>'7՗bcrznª}/eO5Վ7ZEWJ5'\B@mȭ5lX\b4)"Q )u.]`$rE] 6bDZ9PAJ)#jqLVrX ڠEOpez#|>ua:ƣM9G:s"&mP;l<:筑LL0BDBcx<˗ÉDfk$W̢-ǰbgt0ɓ!+Z78VK"@\^3bp1'97n a9;Ta׫^+B 6c{x Q]9.Ìmw(J) `Dl*waD8!px$0Fu;U;QHoCY¿xL)N2<(ڌpX "dOĶn5:Y;ߡ)ΈQE†.a1>G1R)J[aХv`LUNw[3FT+sD:%5b;}Ѩ~BC"yh4R?+Ęa#4\F-m4Px'HV`)q6lDâbT+j<,vS7O Nqx_q.j3Ӂ`{}?]퉌 v5xq誵-JHxuV )KC#Ҳqi:Z$'>y No9(_* AKQsȀԳ x >-Gi42|-88dmBYf5\8&<>>e2Zx?Øi򗿌|Xw4?{΢B#=?A6֌VY|#\yEKpSF2 6}|_W_zLyk 筡'\`\;g {;c| v~@KW< {H3!]{M%MtH)7q.X&\ׄ 4m oR >$w:83`]džO~<\ ~y= TtxZu] yiCac"~c瑌{|@z](䠋xѕchiǓRBnF{zwww'j#RV6> YWG-JQ @5%֘g(ڡZ paX kEikDEњKstxf{|Og1t~4x;c`+dnΦ!LXDVJiddRFKkt05BȽ>&m2A ]`r V iCFPpp)Tuc4鲠S ]8L>P4w{3U7Мw@lƺ%F`Ӥ}E]lleZW 'a֢GJ1lfS)J)uڦt=CRiŻ L椩lcq+br ^%SiQ[CU{ݖABg:֜. iNp(PYA7B9&(Q5m݈>^ @)$&(X{ֵp*$]ƭ!qލ$=Q(wߝ ˵:(K0p㫅ZGFz{4-H-b?gb"Jِe)ޡ{ !BߝP4DdGF۷oI5a=, f~)N|6|hّz 0ꀴn0] 1xSBߺYjgTZ= h7v~ן~C{f#/~;s[\FRE.I}SUX;Ka{zH6ڧO+˿~=~\K?+sG`灚u|1BmQ`,"{M>O^6GӮhj}D9U݄'|-T qjԟ;6I(nIƣwA_*X+: Q@L,^.t,(M)q,yqjY )~,vLlPsz'eԶ1 ]{V]Tf"X-Bc*%kXkE9Z='xxhׄV3H9ä<@x"9}k 250:#ĉk-6H:z.e"$ }ׇS0u]5R}R1t R+Ojz@K2ԻQ |'NUBjuvg{oB?AyhVQ81}uc&+wpL2Jȉ׻iFʜxxW-DINlh DtҖ\"t&oEΧ{SR R(tZ.(tI49i)gzM٘lgBin M(2V]zCaZd-ȅb)&^HnMQm͏JRq8¢V~䚶FA젙L4M)8.Io׫ɑvRÂB~/Vt hE4Mpsń"D833=n-.a{LM/.'cnp w=[,>t)SNԀke3ё"H 3uM!.m8GI#u |4(!%Ym"_ݎSgV!}RJ`"HJ*uxcxhCקq!5[P>'q4Mx3cC$ҙ3)z0ܘStV{9S\r7X?? mˈN+~'?Z0ޡIIُR7=PqN_YPn`zC ?譠pWwm mVoezte 'cLĺcwF^p1mO0=Sl?lжg8ί`‰G3bŒ%v*`@?bDW$twh3(2O`lq*\ȈN|e\^3Z% Oo~_ ,U}@uE(?:u9 (8ty|Fo޼‰,g<==ŋ8xzrcT/__tBҪkKp 4^SF9,X1F\.D)^WZމA2jڛ7h9X[INӘΫ_'-rucXc|ũxց>\Ԭ)7#Q&BYY(4Ѹ9Zkq],=<<^@A(w;nRϽz,*uC7^|#ywK2p0)cX`O6]874!;7VōVud•KF"Z+H)kH>C /^EV^ 7#:h%!qCsQQGUnM 4%:M|o!*, ﵰyn%Ykֺg:pc!S+ڈ[E#Ƚ6ϢRrY10uZw^Q+\!ݴQy%ND6,s3zQo5taz IDAT]EmeXKqOS*lYAHm4pBw8e@Cg ,HlCCKgE9eYtAm}(l4$w"J=OVB(d tB yU*m[ŬcBmg 2[gєa1*r:aYgM3 TW͛7ض _5jeQr.B7e+6 SŶ12żxfkӬ԰2DV{; $Bs )M/^@..|֜m4ӥVDֆ}Q0K]Ltc(a|mؤ1-%<*޶FpBN7$){gv׆' 68,,]IJ\vܿ|EW uT: )%\LwI>c{"!^S֕ a.T5YHli|k ~[qidhKQGJD`.hA -ZQj7><4c+r04p>z^+J#9HrJŲ^ELeb<\B,ipeI0ȵbϴNݬ,6۶0G\`.]mg}ӐA)06` Rr-8M(1NL*jsCy9ذ)D8kO3駍6k7D54Ihq~ׂQ9hȾbl3j [)Lȹ`񓳘xPfeyط=UUݬf7IQR$JdFlK$P H=yS<q1Obq%qɁ%˔)RLQbS9Xꮪ{k)>  @U}ikMҼv#6*B(BC"1Pr k[ЕtoE֢TZ[ aZE=bGѴ-5P03&Q&%Vqj7 J1+'xOE\O ӐDRZPA8yWZkVI %Q O3GpnD(b^)h $D P3; !l:ZghZy h[f͑z٤mCJ`C eX 4H!P_/٘9CiyV+hٍf*E6 N%g->wwBRf'= 9JBAP6Pz:ehMa j_3 M4Rjv-KP^IHaΏps7*`BFC4ђ+;'{&i 'LbH y{3!hh?3#nN[ЗPCP <{l~v*Dx$ɜ SC}"ǰ8` Iö ,M5/Bҭ !Hأi&NdgB@r+3E0!%G0PF@Gw# -4RN1UYw^!vkP:Ht>;{P'T8n KsJ?dgH[HBVJT4&BZ#S`)J-9#V)Dhm[7)vqj8V;2,z2A/-!S a48E<gv;˘DQH39PDкgRz iA.4h]GԵQs>sD Dk ,uJI)Sl "kMc+L̋v gMm[)@Zk4mˍb- r) =(U $ұT*ThJh *M?MyIa4$E |6BlCv<~)SbrbqyCxN}k),2E%eb#, ?;Y$/yv˃lP q.T 6R@))Məm䴸PS0mnsVM7< BʙQmYy2_~:^5e-R 'ǗfX"g|t푾J!n&7bt8M|g#f;E7{088NlMd.y X`ιd?H YOnd{u.OL94q&Q|"؄ bqls#-``=(䒧3wJ]wFb66Pjd i L@T2*k9]Qm^W e/L^({pAth݉u?E{V>o" m[٢e+ױ5 +|M0 !x<]G#O`JIJ u)BBPLBɐ;]ܖKRk1<}T):ya/=o}?=d&: 륈(_U&@hK,,uiABgز h.PۗнKX7VKrW>Q}po YCڞePqCz|,ȑ9p22 U7!t "xhj6&Qt ̎7ywtB*qG [g_pu 9l%',7Q/p)k\ ܿ8;Еݻ'O7$:V`SnTolji}ia~4MX+<.4jZ{dB[ u7k7740BG\\\?7s(@u#\#MvfT}"rA2ը EXW^H>䎵@ZKy;drVn@ԋg(6QiSCl`E1Dtm 1hl - O HB}ӑhUa C!ƶD;͐b [Sa8"NnC@4(HP6Lx+k nļ&>ԫ;jJLgb\>ZӡhÅ);FB<G*`B &*yP)RLp ] ?1D$RRX,XyI9(F %5?_!E(a@g%+}o}gBiжsQ)?Wh̜$@90( h/V(,%2Vkb$qIT5點/ !q!U]aVh9/ΤKJR!f2V1@K&&JiָlX@δiΠPQ6)B` \(T{@0 ]R_0`PSimtS@ ,MM}=2|!q"73u#%$x,uqk{4]7Nuqu} ! f^}5 ?z_ I紊ӅHu@twdl2(~9VM?s:i4" H>__Wj)>eCCGͱ;o$[@4 j eZfB?hߖ373߿7{V@InjN5͟! ٬kDP$XBs* ґ#OPPA4,pߙ9l W4U^^Ce4}?ku7o~G_w3pG9)ly(P #O{JV& ڌa`7L ">}]k䠌3IpnjN5imT(;GTzESe[VMN#4sBE.ۺ Hd/|k@sXe)~G(ѹ<8O`q*L#;LPB.I9(%ϦTBGbZIR9xdE*=L Q͕ɋtf7r?VJ'MbilYJa8 c4ȁmŢ* 'jށy|.Si, u4B$F~F 1d(LKn2 D4M c_79io1;d/,!BqTg+ ,Z+"gTXNsX PVmȂrf[ܔ"71%D\I  1WA>:βjb0,L)_x_t ѪR<0H2|-W\Ja 1FmXgJ=r" J,s&pR5V`6 F3ڕѵ+?!rU$lZW׶OjxŚ8fgMmデWDݨ"P-C: LHIrD}VH e;Hqzo,v6{!ԜGCmLWmiM.q{r@z{ [={vMSB +uI,;jYS뉲db&N#V}Ƙ ! \^]!#M/Y_3b)>cN'v;űAzx>#? \Q%!jh>;$wˑh>n ?&\4qiBr CA9%66!$tݥ!BEGPu4n1;7?S9! 8K9gEn15q +!/uc_G?Zk44rsK?#5uP&({: 2.ZXԂDBp8p` mf])9]Ib I)aִuc(qV*vr~&zj#bl86ƐAxEHÇp&FωJxnJ!^б2E;9Ut.e)BLLA@bsC Q$prT _}Q3)$RO)9 ZW1)B m-!-)"0p^/t g(4HxłsNE;ll2oMcT4ڠhFTi =e.R54a$!I1F5MBXBTC/e 9/X8 slӪ tVdFMv~\d$tiMiwș1D$ijDMzj*b2S3RiTZ"LxRIZl B/1ƚ%Uw4L0M:\B$pNS]kc-ƭ˚M*K ^hJ)U#5!_/Z jd $H%ӴdUYGR -#Æ\ZK#㜃p-)e^ Ľ4?4|B=,\4w;"}ZZcp#E2Rxq<aԧO|5?<BdeRgEF\H^;Yk1{lirDfa>ϿϾHZbի qg3c&!)cHgVG5|ˏ(04/>wQ{ TÔ+ooY>!DB進m/yMtŮ#g!F#p=_ ! RHp'/~w>}S@>c 9m@A:΀ikYMWC)Q'm_8x) p%Rr^2ʍY"lOc $ B_( 9|M }0WZOkGIlhfFw:pNuZƪZ|ORI R͟7r =\c<۬pVa⍥8.=<9RVԨ~yne)EG2Lb4t:V%3-!j x7C%b}5+:Px41pcv7ㅺRPS(/?+.4Zu ZWSZK)mbӨ$H sFR6)1( )WD )@)4tYUmә6$2eGH_). Q/ I$_Si n"w b Efww!ro"ٗ4;8U+MEM+//) ͑B)2w''s[d DZh:Z.D]K!G[ݾ$Td%zQVNBZX'7BRHYh|4fɎD܅"Y\d cILTdXb"xi:"I}6#n?D#q@(3&WXϾEM+jTȑa5?rI@jC) Eae=0 u&vA ԥi麎9"E+eK "zo !д="G)`m_ ^@ www54$2|KgCV4Ȓt T(°ĺ'IIRNde)yUAu8:X50LB/5H֗<snJ!յO,){ vϬs9]]?\ 1)RXi&Ù^nҳo|B"Xo4ĕdw_/#[k>a7>}ӄ~aIb}V#i[zCb !Y+٬)k6 7p%х IDATUJtT@#'#CnW䳀Ü}QΧj+|c7"i\)8nhۖ>Ր@W)%fg )$#4k\H .X+aCp29mRDmZAz &('v)%n"ͅ 8lB{̃n=) Kk<cpuqIEC.~ma@maY㕗?boL_yxw>9bD`RHrj.4PRA)] =rE ^jsg1=wo_UٿXs 6Z q TUSI'kP2ڵM:`F ]~FbH愘Z/oojgU X;҈ EO0:+cnLs2_{]Dɦ|*8瓙s@T޿Xsz^.E _\Pt(BEȆD>д SOJh_)Lq)9!9xO M|+SҰ,У =)_˜&z<i2-!?搦XVg@ش@u1 |ʝ'4MB4,58UQD՞8p: 軮:c+lRp8h s.F, IGqwwW q1 9PAkAqww`+f:(ǹJQ5Gp`e͎Tœ-mףڊJI9ޅZa*ř4MCd#""p idһLӄ٭Ҁ!M ]'Rm(IOQ46L{3M#rNBbhS>y(M*|w`7]4VG$DIy9$Kv*{y.l='XiYޅ@3`:5JҀbv~=<75P-.neS2*T%WA2=h *XLn1.ׂb@,v`*YQG‰]9kW8kW(bR۴3^'؆ R m1xBUԲ"E<S$2ՠFѶ]DTdjjFKa WdP$tXi A5+Us];MYKp$α܇Þ A+r{zz )a5Nrڼ\gZ.TqiڬC0ZKHH(H! jV B)U˴PcJgቌo#%]3ur>E%1v8ᣗ~[x HNh9O,F~E:(eOJd˚6]`P^p-lM+Ѵ|//EHӒ߇/k܈S ?C} V4'tF*Ǘ aVet`_!TIj*b1T^\b{izF8X1v6T٦q7gy2tDӵc@^D9! 54aNU3ϴIm|qS$R3'$jx+l͖~h6 #5sakP 81-2 f evC@(SR@o+sU4}OY1ZJd#amҴ頴p}u]Bf}A\cmj ^m  &@t0If1D9 Dg8#DҤ )=QF";Xw-57V`e*"ZOŴd_Kw!&qS:ESD^3L-M?4 8ĴA+覅6m{خC LkEQDSDgÌIJH;d$y+!B酮J!: Q)H}R!c]XOm[Ç9Gj&+heB/B 7|'LAp*bC)Q/cmB>`3"Hnح(gQ}oδm4<H-1< I<1@l_3...x"AQ 9iETNV\ Ii#n7i;٣Vp3 i)S6̷^0#Cb2P4 эɔ=ھpng18  `ne,Bpqp8afJI4Һb 4@ ̞tUmס_@iMaD6`tBVf}HMܿ<~w _x_BL1HP:CPh57'Xai HE(2HLl-އ, :dBE&WNooѪᄁ5mj3PL3F蚅 sfZ7x'yɀY&y>=Ǯ ݖ5Z@KK<쎐\c5HA+>?O"gNF}Um%~@*Ix@"ʅHIE6ʃ/OnEF)JJ#CR)H~qwk?Vp큜04/]77,*cL忖ֹeZ>цXf&eR6|x ϡq WWWl!˟!(9%ؖ Sq0M…YPP2F7xU87cxp%Σm,$8N5ͷLԨPH$Gv(J]]vnf[ rn+խ 2eZ4a@51a&LnMM-i1xy Q1/dT0N/俔H.viq}uj)h]cFT6j o$0nuQжE9_m"4J#tc Y!E4V+!F8)q ?E F̣Cn1!:?𣣆0Cf?OD!%1 ixјs0;a&?bsk =&=Ĝcr!`禱Bj8b!&dAMBtVw@PBfYeO'@@o V6{ius8{)"qp!"$BcWIbrR5HICq2c#4 (:J-}S 0( sJcE$t!SFdhO RIx-5nh 7hɑk[Hk-jx"JtYQb{j()|d:4lˬ1;Bjp%aMnFLt~9S+x-Z$T*IAi=ZF|| Ր #Z0Chv7Ȉh[gq yV0n "nl"#x8 6 jL.E2gI-$zFB+2XJH@ӂچ\JCF }B߯0F\]\psM~x !3o| 6[Ot_EqJBK@"RZ-f@ּs$u/ +"`^+&ڛA<>>گ#ضm(6/psTJ25 K}k6RTOՈ M osu~` #ߺ{p~iZ'X=BeGѓCEG nHrz7o!n"D_Fj"\|S Lb!$΀2߇m[DF E)O L㈫+ܼؖgМ RȢÉ1"ul `CYE(4M8iuճ^^W[ǔr jIJ8fiƏ5=oo~ ۀB ,VȀDY!(.WB,Ne,ѹVacjBY h,1=~O) Y$M-δ/8~0s@6`Z#1%3ۄZv Af7v{ӛGT_'AM||G,7qt$FO|.fx~|i"G`~^g3O}"9!W?Jc"$h|{\.%EN&7,D DPAB /#|6pS?hn9lq:+fqN`s ǼE3B1ۀƈġtmXx8ppn88F]q$ul6Rmk ^z%9i8U1զp} \u=%nkW_œ'O(ccp@E7]['w:Bj~ fa{}U}Y___Gᒌ^E}/)%v]WMH4 \s"9G] m)P(-h#]i'jj"]ϑ렔~OzHHNt3Qì& qn zwPh~i'>)"RO 1( 9]u;M謡3 <79tmζl`V6ǩ6ɇ=@误qAv95Ӟ?%%he ! P:Պq!#Z ,= Lt-pY6ְ^4apX׸Żヒu^On_g45nww$"<~Ụ]qk2tGSW^PB  粸0rw>d/O_y+489|cCux77|[s4G!3=mCB)-Rrbl8<{ wwwy4JaKhV/w!㏾c-8MGl[bθl?AIcF$Oa~ H4_\ vw;HWqi f7* A}VLjMRP8j;ZZsJ{\^\8KZvw>y Cj%\\MbjZ[(m/nZ uivhaGd ܿ}WXuR$auy2})6MW-~R+Z+i%rEi m@VnѭWxC2Vp}V+J}b?ޗ_z۶{;yQi,j½`~f?N޺7{>G"̺G3ihѓ2ZNr$k\[iD |7ЄIs%Zb}2Qkpm 4iTb+;!D!t&퐃 J9QnE'W}¶h5o?u4k\!xz vJן_# Iή98T+3 M L|*ϑ#t5RzyѣOG/6p~BhT#wk(7ɹc>\w}y4"嵴8lI7jqP\`XtSt]Gy.#`h^ U}u}r)A(YfHxllm jb37*帗w(4("/OI..;y\r>R83bPf11(^R5H9@fYyi XZR LRY>OũU3Ρsvy:s& 3P0% _ko|Oovwi RHr?\iXmY&2;@Q2 Jb28U{9B |~^o>$%y8ZB5Hda3kce^hMݛۖ\eb̽9wTTJH*I 1цm7`Gn#hAv;  `$  5HUyz9{gVfsSD[s;w5|ko BKyF>NN^4Sc$猡0VsGJ S0rLڤl#6y'dTm D ]"`g8n^\.p^/@AIamK"#;!4agċoX+z4I!t؉Jf"upy|qt;$rggG:Xm;˝pt|,5]SD54B%/=wߍ;]X`2B],1 )msN R4(,@ $2ÓSZ錮 %ii2G uUzD [Vʕ~5oNn 1Byi# }|5|pY&˚Z*c`} :ZϤ `5i* X2[^z j23(3Ǚ3`^&2G/EvǮN?㟀߽ŝ5 5%D@pk)1:p |/tpu k@)?X C0#_k<\7(fPdPHSO={{K_מ葲tnřgr5Mk}65"qM9V//X\ - )r@Ju<6"'<5\Q$ 0*Ci5a[C^ws&|%HӔ i5l (D=acNy]30xhծY}F }@)dㄮ'Ad0sں&-shJW?H=> minI##Zӄ.sM W9f@uW$/Y=<۹HD0 rJΟ"¿w>\r\i "1eĜ@,9 \&^b9 H$dmrw!2d8ÅS|#I/B׫%ȉ0 qJpԁ=8BGΌ:n D ]sفW3فXńUdo!G$=SBv=WyoFD1d`H9o6SzȼJf8PF4zpC=V >t"c111EfLpq p^%Anqn+ʘ 0wdȀ ֛ G#XWxgpY8N8񔰁=@J2:RBq5\zdج'Ll&phi3a {p<Fq4kWO&Pfl6 ՈW>??zG׮mqyVB8ID>YSqX!,E$kC@ٞJ@3t `?,bgO~QXr1'1bn܇͸A?&;B9BzdB XӑQlqk/*IkX p##<0.cY[\jٓJ:)7]iH ~V&3}E!猄jl;!BC'_ѿ#LJuͺH-Qd`23b̌Ii(NMihuP|N,L_@ Q\a>H~#tAօÓy*6\y^6;ɞ{2}lN<q  E\o?~'cFx fBxu0Ju{gN+F'u$mlXpi}!:&甽PRZ`8eNe)V;לÅ^^2Sk=#r"/v0ifHN7GH'w-?:uKn᯿g#p2J8F:.Ƨp )OJD<( W:%ەt } r?un_b'؋~Quϗazwtִ+8)ds19'Tp@AJw^bƷ )kESS#bEQ2KZcMjIV<6Mh)2uff].gQvP 53mdFN x)V STPCv6k?m$=V l64k#8ďgkV*h3k/Y/U`1\䜥nJ3"`1Wf+l94(Ȗ:"w\%w<<>bO(`NM=g$] 56;\+ra3kOu:VAi4ڍrۂ=Fe-3Tڞ'Ci,iiιGauZ[ H,Ɗ]l_6H4{ES"ĖK+d9v] aϕɦuEWr.C⺯6uC u2 ƷY`[ $$uN dV̚&ˆ$0v((Ka-glrF|_"Y qO_qJJAKX.;w8{q"t1irD]/Ӽ{C; BNBP賎H.rXH螺w9sN)gDp^#- 1gT-`eYBa=]+Q1E&"0J?ve9 vdCuXFZd<Ro2%[9hO z.2\0i5Ў?8V1]4j7f~6g<,QKҟW*!-!{ZP}'9.FR6 ;iAqAF8.3FvY\^Obw,BFtb;0۳DM6Dr *ڞ"9Iڠ%[qxx'w܍?ym2g6\w >wKa۹{opjD x\'4'Lv=;$&2YXN&"y17zQI"Rv \S骞QA <90.H/^5eM>(Cy CMLyG;6| TyU`_Mf"FGZGbx?G?k0,aj&M)C2-HSd INLI֯8qNp ' yI'1n4abd$vp1#Fqڏz4>4b^׭뀩:!F ֒BD1cBK)Ԁ&Y.R%%3Si`t'P&dD@gAgq2Kt6E1T`QD"G!Hx|1- d`y{*w$uIgi.Ihj9-ƴ\}WpENiԣ:XYuQŰ^g:/w?ۿ %:BX '9Q8;~!^=b4#Dx̐(őTхG5 | ]C#<}]SqiVu:ڿDv`n(9ۅLJgx!fF0*=)D>y>ta#eF&6R4 bSuDaT#u.`-&R'F(5c,Su1 4uدIf'BWzu*ð@\ܥ?t|(T'e:fnή4`,"lךrB`&HVȗ=]<}FG{t)Vbv"5g Y/gn0])1Pc6(r]/s<{}ڄӾ~=w XX?~8:K7fh;i +~" ^2V~㈋'"zQ iZI#^{\rQ@ZCb[Qmug  u)3 V~U0=w?]|}|;8<<,,D흌EuNTY 9 bY6f qix NjC֧[(|XѰ5RHj^07-mfxW2ߞO[;V45:mtJ$OBy6gǴADe{nբֳO¯&#Mw8'Hupsw@SrY{x衇|BPIssRt VF+9A$}R4Δ!Q(NTo׷`R3vq%kIY)0yRS5n&;g0vᴘ/m&}T/յBbvMOe{9'Ty|2E yM A|t#rH:bg)`KtS87cIsrX։AQG օ]ısS"<3[T{Z6?݇ }< g8>y|?n䕯ĕkױ(ۙ3g0e4GGT @{vyz sj](\)21Ή:oޤezMl9k8D^WM/Z Z4RHTҜ+Єvn[N[TR\I>_>'d"GgҘ\.ᝠ։1^yZ)5r@ךׁy-}u X/9c~[j'Y/8 pG aTi뗧QF,}- k ޵.38 }mrXxWq228'Y;|ݗ~vsE:Wg t}yĄt#W&iSnF=J$;CMЁA2N'qTaFp)"*rˉ~Zh[q++?cq:P~,g{{[85nknmE| .)Fx#]|7^?rD@Tcg Va Q%$;0,9[_3ODM1csЋBtְ*ŬD͕6*ky'rX4: `&8g-BԾ)))r}`4h9X *^1N`seOퟁ)89>V$Ũ$l}ri`ZoTÜ6#V:^(D!Gی[RXtd#g{+N_u>`>YHCg~{ ozýX (fnbڸ4Rmemj q GMDDq-v4+~H1;\lGNZtc^L@ey:L\SimCZ@7\:W 2PFcj w^Cuރ(_ PIOekcQE:dFk/HٲuȅsdYX1G=88MH \toxW|'>ífXA7Tڇ9GN!Μ)j۞c9"B^/UM;;'Fp(%G ޯa?yӋտ8Hqߊ]8\Kk;NS%w܎O|!g9zwcW'o)7J1zL^P0Ksu#E94oVdu,8F0'&1ͩ)M!aNȼ" !bX9TN 9M8:_w=>B5fB!g]o6/8s.vߺB_`R-@GeMfl?Z3״&eSvWR"2gNXfUJ RLvN[>/\a~\%ν/(AJa@Nj6kD=M2B'u L1"^fuAY.%)Z5Xvsb3AlP K@Y=g.u|DVXTFxԓ^w/N/z#T#1ԽzfKg2~KơWӮv}PW3S3,k3S#FbaNE.̍C?x){yqKNkQO,4" ]cD|8Dcl?Vy'ɞP<8_+m4[9A!)yBDxa1w۩62UjUw+ķ6[;F:,#)X8g{/|ыĵ_5;; w 7PZ?XUSlWuՙu@ 鞮Hcx\;e;8XkGP?f`op83~ÅZ};P_|jD,:²Քqm#=߈+I~g^[#]܃X?2AR[( @(YmCSJ ZTK:SqfhHC^m1nVcΞu_U/<Ӹ;/LS* Vͦ5m6kr~n{_ml6' \ RP ˦\g.H]XSAטH %- (wAXa=W9R]xt!xk3 x("hL˵R@mCMPw42el֮4F/)D2ڣ[@5,Ve%_" E.<\SDN^4~Gak.4M&INl<F+g:z΅38ΏXpV<]sq#HsDYК3y4))_Y~V@ sRƍf?4v l 2e/tOפb\K9؏/ ̣Y>1U;aX^$4QJOWsMf4%Aud& 8 se.ONNf=ƶ9?k$0#aMp01֌E>^w׿/]\iA:uD9e[w&'sf͒ziѵH@Il%JnVnfנ{S0hӼ|g*,B<,ib6Fص,YY:XCybcabGŖ!WtG%梭 Qtl}&圂88@9 X# xAN cl<2aVr.2n>h_d>r溧#zĵ5{Wvn Hdu˚ئhY=uj!)`˿5FYks*q7)VgFVpP16uPMzԿĈkMeJ= 95IFN'Eg.,ٟ?)Z?<^)$rVeԥ/zK'Vzή>FlFA59d5,jD&#g.ptK'Bšb4ގ@bggvz/0$Ҡw+4!:,з((B+~"2FX*!!Z3N4O;|JM55g^EP& gdE1ptTyCː3ūa0^t lg\tK  ) +zZP~fP5DmGM^<)IR7g/ѐ4[Gb/ nWK:q# 1@YJ/ Ymceھ(fP`5`ZRPM5㽍fʻT}vd] x!!(cp]W݃qEhBkb߾m!mJ]ý#YƀâB,f1lL}Mșh>WVKf$M8(Jnɫj󛉊fMWή%OɦUvsQ-c,\ӘCuFeIfD 'nqҟ[tskHߐ(G:8 cF qZf-wgq΋x5¡E*?|' SRC|"D%f C#ULe `~fb^c6<濏o<6q$`yGxR+gޗެtI_x\xiVxqq;.#}\4"^)D]AYऑ;mDvVCP'8棄tfaU6<& {;z2_y|Cmѵkr3P&9TNCv|Z'ܬM"8XDA`ރ6IsȺ1bPS"=]/8"#69} A+VƤZHZD7_:BZ"h 1H}fsl5QD"4&=>5y ƔR/X.'Ii. ңqij]b^iSflmY.Py#! Ѷv], M-߱Vb3N猅U)ТV~sބ.ԨVN=,JOɩ~\JfXvN)yT3#6>x>+N3: Ƕl ?IUU[_yVǙ^VKB,')%Rf ɺْ=8wt ״׵e#<Ҭ0)X,,]ĘyR)Ab@]+Y;\I* f2SmRfA""' ]y<u술z.1SGpՐ%3SG)F5qfq#N4X٬1kT=B\#˺C1\arJ C54*V hTdv,= Oa]+ތˌ Z%Nj$+`GqY p]͋cٺ>;8y#Qtl)K$ qzU\i4 >!t=,# }WsBBiIƦE!:H1a{/JD))9wA!!Mv nJ\#^E$ Mp^sKF/h,kd,3cGYC3`j&8<{1b16#^_%]U_;͈Ad5O\z%(G =z@'KUXݥ]YM_%k-1> ˏ`(s2~J ٽ!vC.V_N^]S×ZYzODc?=WW\ nM8sbX`>5&TGˊEO]=]lƈWc;,}Z̎3E Es-f.]JmMJ7d 3&"y9XEڔ7 8+ńݻu3WrMkllo?mfan9 bhϮԉX,fTy,Hhȼt0YwFJ#/{q1! gA!Hg+x!usdMLST9l{͞YRw] ȳZeqE۹vV;ɰf%rJ3brj3A =]W=d gq]Vs:EvN;f-s?1OAv_,NFǛo{U'4a]1RR)$ \%XN qO zӸK /S8? yQ0#vHa0`ęe#I󱶼mB iv. o;FmA;IQR0H^xZ :sDZ$֩iUVf@&@[uA\Ś WMrnVll/SDKi 1h)z3̡+n j|[K2yğqx] fBHx 7;?[0C IDAT渐83ʫR1#aT8t""fkYjlsUa']ksjK ԁB'M%YdFp4 qT՜fȹ̉h4؜"b7P8LE?Ν)ZFAf8Ĉ4T/n)jB}?TP|ab)i@qJ$#z%WG)b+c2gSFNI]='1< r[Fe lVzm$i%4{FJ^8W֯+n6GC_a:XRHŢ0?t)48legF>R0-qC9wL>4e kbM4 6akA7O8>QaZRM 4ߢ%@vf6zYXGMΚ!o?DJ+V)29֒^>hn͡ vmG^E*v_KufMn!<19uo>=LP؁8?H H?H&fAq F3}`qW)NE$ٖQCG,}Y]yݷۿu_7no@.hS!!̘cw댏=ƻ~*8Mӷ?}ӝ8gMd,;{_?9=X4dg$Bx׃px$#%01.E J1ý܍^K8{v J4#K~|Ghq-}8V5=7Đ֨"^!ow'{WyiS,y?ktv"GR &#+Gbd\(iNC-nkQHТPr t5"Sg2!'R%EQ{)Ե%5VrHyE-rÚ!g;{{X_,4r0,}@XH:0 o沂Wx2ĕwT TeI:K1HRiz:bNjxhĊ詔33o*讗d}"TA f5]`רXu )`%q0=1oEm9JuTǤ )6lɷƨl{;ava8HJWT6e|3RB6A{m Z@HžEDQT2s /AcyAg1..LqH Na!"`pog?w4:<@aaI %3~2'F'NVǍ,԰@z݆r3;iC8O?}{nsج2aq iN\p*SaHmJ2AՎiѫ1 sIjSڈp:$> CI 3eܭbkϢ T h0<*T~-f[u#P# `+О;ﶩO6vMCkJ^+ i3[n':h0lܔͧ#WX8F'Ǹv~agDKioRE31sjvr ʕ gsl(v-Ϡ)Au:enE0glsN<^(K:cЏmt%L]@p=)"ũ+M4ksQby( REYjX:ȧ&MQ*iElHS1fd Xʃ )a+XT`u Cr rcD}|sd,q4٢'\TQUAٵ: )ֵkkI<.5{uޫ!&'$8Ys~Az"a; )%yfmٌQNR+:&,ל6cI$uPWSgWFK`i~J83sbHHW40MD+rU|I9W5)GJʘ5[ܾlbjlHǵul}?sn/a;vLج59v[Tr犼yu2{͚[4pds6x'}k #y!HWX%J!756~I`6Bi38Qo^.=LŻpW/᳗&/(  ׿ɯя#Cd7M|`_Ro&lǥ" @n/<)3cbN5hkmcŅ%S"6m>vMZj혶@7cfU;'6m?(ŇME~,QJׯUe/+_rp"\$UH EF0yi_ǩZ֧ciu|ڽ{h+A'xy=#9{MeYj5+8 #9kQbB>}9)vtc`9a+-P00G rBq=zT߀ua1^٬PBpp:]XT1iR\fĊ` RuSC"ƃJhs۴ۿ&[yVF\U)ݳ3R_0(Ŀ_ď?œO>oŹ 6 X)Sý&x ]4B5[@qjע920G`;`X4C$]8s5mxbQ8E[t9)k.P7VԤu$ õG)ގgt6^O3Bǂ6 >'?CZP҅i =O %fxꪱ3a(b„)\ Jtn{/s9$$1[g^M,䚦CZthI{yZm=սgnr6Xh-dlulYg4wijj;?fWy@{mYGOM5an\禣Y6䄣qe(J],L4yW9)/bqPLf̩=fIIm! ) 3\'M.XM!xKoßJMa|Yz;_oënp]ՓsRt\qlɔ2p4J}n?g+(KuT̋S7򜊊MqH8, nS4 ;߂;nO}xK-wH ;{vDZdD Ř#X-3FuRoMHao3-g;vKtv 香jb;jFl´¯^H=iqs3o4M35CBOjV,k^z1'L5:o> gezR%-ȉ6 rB07:O[sR%Q G"^kʖ#q9r9Sn9zkzUdibYy$R5yf !SDF/2 17$P\щ)FGwNWXhS $CX~zIp`qJ?1hLթuZÙgIxlGJDsQ88LFe}F*J]9i,v?b䑛<6l}}&}(ge#% cC?]@C d!Gڥ) 0:E6E\ ƶC_PzՂ11~=T8~/EV)!N|W`daXpǪ5[|s>|}-8}']g#An6oP,$@FZ(Z!5% ĸ\ T4cم CkIE,5xލ'6^xyo8}F4A hwV))ٚ}]Fu(?/v4MXQ50 QrFS#+9૚/:h8l$2$0?^թqg׍>NN)ϼӘ)uuz[IDCcJiB욫B5M֛v \馞i0UQy9Jsqc<0$K8s/? Mb\p_K.7֓HYM׭f,kFlTQ׃~.G:(8 (j:׮A Lj$Rr,V:"nk[Jő_B?Ad9IșԴFLe~9`H!͎]!gide14M5*cX}F}϶*e $nJAiV.UںI)e\cL"5Q&ɽk[))e`9 kX.zUj?«_z~W:!&wF1*ʀ6k ^ڨ{@',uF~63z3k Ze\u^w55u=c}5v;3ND!z3k ˫^Jھ:`YK)FjיP:so [?㸱6h2,XMz81&?xwk?? yttiÁj?QleR4߫g~&$lHlk8 C?n .v %`7Mϴ3 '|ӟA/A7_OPL߃.[6|H8cK7#l wfL@1]l(*` YXmf&}ȫ4'DK ǻ4,RT9EVNأcGkc.N /gGǾQiD9ª>R|(}8PŢOM,i۰5bU6U';;p՚_ۀ!Pt1Ta ]_qrGzLK/VTkJ#;1BaуkL)ʕ{u عvS,d<)Z(|JHC Tk7FwVkǗd|LVi݇!1BomU2S;^|gk\WUD]$v1;H Dm(uwKv6ko^])3ĺݦյojSF{A R'Me5k!7kƯsu,4 P97& {Nw\o:mr}M$kTs} ,/R>9r"^!pkx:۔iӲ`-2Fh].a6ð/t~}?3gO)=<||3qy6׼W$m,1lQk-E;neQe|k?DM7^}G>>vO^s%tX' zz?~S0]$o6)zY/{1M{OX4E2)&tY8Bsv.b>Gz30ݮ-!ڜҗFr&! w\L.i)6%D!Nk"0Uo.ںΔH$# @T5#T-1[r^)` "${By CVƅg %/73`s "q ya ϳ! )hpxe'4sB=3uZǐA9Q; \+^۴:A)~~5ȶ,d+\ӏN N:SyO'1m6yF`rAH\ߏu6)_9D }nW@=_'> nX3|/`@X|+0ЬᙨQ`Q?ϹmlJ ,9fPUsbKI|D*,y^|_࡯?xKO~0fQ/͈„'_8FNa!!t4^ j"|dծ>QiU~z>N$ϑA"+ ŋ))'].|ZL(o" Lѯ\y,ٞGg= jCJʵ'BFk=LD@im ǻO/z$@&U $"b }q SOX]mGpK+ńs 8X'׭2V3gL` ؚ 0N ",wvиZ#`Amco fw {A\d-S4Ay՗;I &[jnb@:ml:qǾO<0`[D_I k0n۶ڮm64TAJ=>>.6Mj>s;{^ꀕޛX\Agz@8ؠt-Tqꗞs~\atxF}@s!@3.)l-Ɯr-z=O=>y-xL@Jk8HQa:\x,:wwq;| aq( nY5| bf's,O_<܉I޵H~i^_E"7 ia I?G|҈~{opu0!.l,7H#RS ` 2λh)5?olzdPs} ]"MCF&Xu'qvf?I<_ {#svv,XuUцbkJ@x6V*M|klD= c]'Pڡgy :@mqî^qD>nvMVk눜ņؓa2fF#A8q:YkWnlf+xkWZzQ'kT)|#~s q>vwFv.HH;9m[H]yѵmRs'WWk!)!yq<!FtgV#Z'nv9%i4UQbJQH *I0R"@%pXgM#()F3?H,!$$ ,W+nP1!z$gYHDcGGc5!"hKoogy2JB"c׺$g`bwB7dϊ ! ϽWڷ/\0q51, :LO9#F a! .GwMV`Ql Xwvv+P0#:7?Uphs](oZm%kkۣEbݳJϿW03)b|Lgc 髶YumGM9H*\3VuֿgгOAEf{n;׾7<n*Lc0Br]f i]./E.V(u=էk񪗴p8x 5"6ߺq8™4_iqyj :ݹ݅//t'l@H07v=I$JedJȋ2 )#c^4|0v40AZG";xggއWu7 o_װӴ8XaǤibFm9s C n0X6jm`j㙹="P n]ݎ%"_Á{ Ķ%g}U,E4MsA* 53ELuՈ8r?١ᄒqRI$ 0bDEҷ`沽hto^c(k@Egf x7Lvy"S\5-sH,ZES`gŲ:0sNFqz:\k'2zc2N[%*$LCK 11 ]ul{ R)C+Azt< d͋PL2gZ= 1x B蚏 vvVXv'0dao` & ɔ~]_սП9bXtš8A4'"2q*սb,:-!qi7c=o@)Nk{$N{8ڨ,Ԇ{y="c:']ab\f*~~cy|f^Rp$Ā`Ҕ4eva;Rk\U wZ@Xt*`P>#"k^bWU3CwksiDOR!"yi8}}x?®v|?wIJ?gs?|q: dKz σ]i`N kbC^ \U'?ŧ"7g8R((n)TY~3oYw8Mw1X xԮpX") 8 |>t'RS‡>{;ǗѽN?^YL ;CM'o=Y:z `y'TB!oF wO Pהk\A==w [ٟ)u1$q?8^!nV?6<~i}#Yqޙ>V^ 0}=)gZrSl h"˟h-@؆zʰh&E?olYSۻ;^|o7 u?Fz[qџyM~mjf z%\}=>mĿ(|O{oCAטE{yƗ-'<ٯsz->͋$!HVvARPdhG3*1O)˙m~0,&|`|  bp a`u%nǟx{K3]vlƱGHbB'V!"Ä66dRě.q)L%䦑 R,q1_[^.}_~TuP  2R!}mhMD#_|\>NE^Tx,|¨4"@œDʴKh0 օ\2`qO??q!a=&K7mX?iviwt8D4#gȵ/`|Q O=| D$Iwݱz9ޠcƆOE7N8R`"͗EU8x%şPE"8uٖϙiYK8 )YVi zFu}+x“8sw !Xu 5!cMr!OlHB/E#d4ZCEE1~jp`<#R J!;Ra 6w?Ga<{8h[PGdJIuɧLNofWG֑̱s-Ȉ#!čJϪW7 }O#Q4kA英)u^jPՁjŒ5$vay#@r=)R.p|x<i¢iol"vvO2Ldȴ*QsS$:\p+T}<+g-e>X栠F"B2ZAMP[Ule|h&A0_@k pw m[m)x 4i+LtOmN0LY ^%\S`ira8 rDB>Luyv1؉4ߏe8t]V_g?ԮjP5¦z(rkw3D,ؠYzʶX#jj^C]X]*=\s.BԨMCkK6c_ũ7 o]|{|Sǰ)ڥe*VV6:7ͫeB.%cd_7b졁D7PPU+B$yrF%HqȒ1X6t #̉ IDATgꗍfJp덧˄|n㘽,xlу/!!z)"_orpb % >aoa9 C,wGc u/.Q#Ke,)j>hd!W+t-`"7Q~/B *0Y= S9(HCcvac!3@ע9cO>Ǟ~Kxk ̽{_wߍ3gΠi{tM{#Œ&Ѷ 4%ԠyS3+gj& gW7m)3i)L@27T6:#w4I:b\Ӗv3{Im{v뚚J`4o,"{ws_4Xc8[Ө43(>}>OMSi G%7#|? &LaNK+{y}c|h,IJϠșJR.rfYo?oa^CJQ N8SR@땜ɼ8 $ HRNlJ%|Ϙ擄3L`^#NQ5bw 8QХ'!I@Q]+Q9ĠMYӴ fh HhxRp ԲzÁ8:N?h8[q^ˈe2 XD8-\ AkUJ>u!&:[k,3ǯKZ+R[\S>-N`WBicd'Org'd3B XS`0]kfV;)%,v'ǵ9PF9f "qoiS:ŖՎ+C6g7 , kK0T6YqrHRęB ar}7!&sh A1H7RNkpj뚭U[]13(m3J@0`aƏ؉ W8s o7㎻Ž[ß(e(@fœ^\UDK 4A0?LR?d_R@fT=(. pB:1"L s}=V-!-#n>zqOeiQٮ"'7|m,q -+x |L=O|>&\yUT%"),[ 0bj"v@WrȇG<.ۀ*awۚ30=8~ x+gqiah6h_qdJ4 ül6QFIecgr(\9qӜ2 AJ$ҷ FKT|Vv`;Nvx].9k9u4+*#(64|@UXsw-QiV]Q@WKL8XndB-:^1zzIQ Mӄ|b/:%@T7[nC8F 6>lqi }%CE֦qQs~)1"+)1qH 9Iv|΀i4 JYE!c3HE JJ9#,&FBPbA Hnp9hȴ0#\)q)N21big;OP4P#F ĀÃ}X .DB`(QNRԙę-ZpAՀ.`L2;*KUײ2է>gN?8u!V`ѵ+$?no{'^r8>*Z =RJ²s0R*$% TLb;FsmkyJ fuY&|.kSKWkpytz3^׋I@ HӚrܠS?=~c !^rv gúH6d8_d)h: I4u=M^ f g0OLZW"lu]*<0%4t1 Cc~i8@V gqϞ{q˭p%x[s/7ߌj Oh&a@޳276ړ(0ƈ{4T6ywբڠ8M1DiQġNOh,z}ŭٙfwop%? ܚEPUC$$ )%$nNӄbm1 Ӱ<۶f[=S'I1Z,H%<³Ye߆Dи%@qk ,J$A 1N'倄%F5EIVge1* `Y{1վ L$ӓXʙe&-BNYE%1kycAh 6\^F@DLЭgzǧ'ksXA " ϊR*굥L23{J @b T} +a + 0ދqo0[6Ye+k4];z=AVR9sxEZ7UTmL3|Jy3jGYh6j8[[HP`+xTR&d$1ygy]CG hlV43 BL*R$T.b5䌾>8"BFX8<qùWw.ʽ޽u$O&"Plv ]/KֹC}7B[Ad)u! \UQ9$]/f3`n4,k E0HGCD[)0ET^,HD/NUΈ(%Xn% BЕ/˱0 8`G`puo`xkPdb)dm(ڴe1iT Ȁ'NT]T[|6mli@9d|]!娱Mi0NvvpG_s;_s/ }xOb*0ƈ"1 #B ѳaBJrn罇q._OOҏ>L^EcANLX˵Qp7D νc>ϜSnBMMTW[DXv-4aSGƁ;[)E18\H+WyYI࣭w.{Zu 0Ol>MSXHJFL3B{ ٴ#_#` 4؀x٧q%q|?DZ{$) `_ѵ c}E&i3"Ɣ 1vTH*9[ gϢ|.{~Zⓑ8ݪI"X\W{ !2҈{@ f+. [";j$ ܑ.x￀+T9:KuB(%S t%vy$29S&*TѤ'X؆[ۖ3>׌ZZ B}]2=MKqͥg4W׆ϡ##ÊcL: 6Yz|o*[cBӺgto+*0T[ɒJm,%G8znqK7~{q~$~]&~X_ixJmGU;R_m>:f Y!v=<6@L7pƒ_ ^zӍ[q9 };ΜA\bggmwŲ퐼A\5["lCs5~& > FQdcmA܅GDkta4M "#B(NjG;6aAL>)E$WȠ̇"u)G45JM%&Jc8{8|=Udr=OZ؞np4`3nj׶-; -nZ"%, B\.0x$˗mo~~o?BG+qh")uCDT2+D؆o `5CפΎOSEQ!UbRbH=Ȱ%Qc=0"iIu80J1b K>U \r((B|E b~hFIrhBT)BjΎĢ!J im1F=l6 T Tjc\R%7!DnHn_Q(}D-Q q+?ssGeoAMuIpm=g/ǯal"^{kpM/nٖ9StMbJejT9 B N), HI)TS0jgT1RPrC(,k-,ad;8Yu,%ҽ5+EUE4K QPZ0 fZ,W"RP?PTmff4q=rt~QKH39^1, LWrw]^78X_?'qfsE?`!| EuL\~a6h$Ct~$sf l6YQ.r&ˢ8!Q53¿Q ڟj ` 9?أE^r]iKȋ.)"r( ^bwuпi@!\â"pWP:9((?5=g8" Dt>95M6 H0r-;qng g=_7y|"栀˲E ĿSJ_PL#m0:g.l-P U[\jF0)8€49[OoLr_' ֏53=UD6^7?^ĵЉj@b6@18Z74URh p4GWVBߵCkmy|[듟¥rS:Ks @3%2Y>fi|0 &`ZcQ^biδ ܰʼnS8sξ,V.V%]5pmo lzV[ slDg gqB)k-1pMfoT)_#\TH`'!Ft;H6q<k_cѰal6%8Pm.UV"%Lӄ: C Ez,XQqa&Gb cX΂|D= <8@iFf۶!~*>2Tx߯IVh8 !!CxZ╯|%7x{qfL& b* .;UP(T'No|gjqy}T8  g$I60 }kWv^᫓O$&hK5 H7E9Z0pu>_|nk7y*tYҹ=@jcd|\T98sHHB#dK(%"3Rv BK(Yr8uS`ȽnfHÃ)cڦCW/hDB-JBSϨsbSRkWݝ3}>o ײ3yS:!dxu&&"Ęd9brמ!¹sgpW܆2,V+SgZ$ Cߣu kaSNpzi alllA&U)'S hs~@l,v}^p*3g!{OO/_ k&pr}dAdEaM#ڜIoc$A% gp_@AE5`:(ޏ5~aRBKj``ԉsVҬ kۃ881`P>"-%=q ΟM7/9{LC(DV7f&D<Md6^@`Z]aubq\.RTʍ%e@N^sc-Bzi2 !`ѭ 5,%wvAz^(eaQΊ#>~%V;< 9e,8"V6,M%"tM /r;L+OѺ&o^{{{UFJ MזBGr旣J`gg'+g?N %XK6&nZ,929^_kٔz կ[nk_wnY΃1k}϶ϱ/ cl##` Ex@ )M CPˀ8C8c}/k9U6׼ݣ/U}N77x9/<ܟW~qwyCJ K$D~PRRh^/?(1S>oul켍OnާӍOD!(YC*\$JrFճ~-љȸ@y)0} m!1M~l{uٱٞjf`\ANF i ,Hdۚ"Ѣ䕛*߼|t 2woZDOLjID.s΢8KR>2s5iXHT䖘 #{H68ЀcY;ild?RZx(H=%;>cg}|n۾K8 AjEhvYP:%=솯V u۰lvfH*`U+dP2&l8?<`JTE؀Z%\ k#)6ȐGS̸OǧpM[󷗮sUeG\3i|"ͷE=bZ׋Qlpo@9 Xo6Sud**ldԵ."3ujXYڪ˺"0S ^x[q.+^ɿ W~lH e7 `wQ&~ <*plR"65Gi6 ) wA=@ׯhh6E;hRj)r"Fb~kpůmвPTFzUP?q(_:jh6nnwT`Q6P.6{h}`|]#)qR"i "35Q羀Z $ фI!BufX:~W%lK% cE:@ (hUϟ?G޾iiƜ3Ha-1ޚѠ*Эώ'0|1逛8b4jIpu+nMj-t33P777P&c2/n>-K 2H*Â[H)xxxxxℜs1EeS/_ĶmxMr|/f$ERλ(.M*@3s~7>_}/nm4MKj$"\6qhN<3ܴη><ܝx+՟y ~~w „Mq H3D͙ u PS_%PyZ`N|EtC5;m1!OٓRi祴ӀȊA38s=3Dȓ jpFۛ-سrﻏvn'*9P!rBDSC;<'CDl&N8ݾ_} Cp< k=ܩmC"Ǘ`bAsgvfZUWEyHcnI bPOGu$E6JGs\ {=lˊ꛷o!| ^xUO^"),dp8 0m֖dlV[-Hiǯ`C`-Ûg3]'"f$rR-v)&,s6zk}5Z %jرdj=1%]RaJ= hwӌ|~oׯ~W|vz~J\ SΉ TТ E&Ё-{ʨaL{I|Vq4ZD=Rv_=y187Oس@7,GJE PH\`i*7H g}>9"E,BI@z.#~x`;UEBRvsrӄPݠxӘ5gS蟍oSkr%Cu6Iݹn*ēIYY*r!ԋBqObT:̖ (_TVnsPD*HJ3ŖP @>nD7u S dz[2Sx:ڡ=hX{pSŌj@AP`cw :#ĞZN-p Eq6 T՘*s4+[(mQ! j(9XSb0޾"k7GxqO8&|7,EWXϞPJ tw|o{@ѩ'lQ9={縗 [([ |ډ jm8 u sVKyZ̸tByu X_R޼Co[oެ-e/OPg$lPh:XB.|L6g{`M'pCe7 ֕mYqk,(sDXL1‰ySscG`9AXp~0MS߷U@ 7\E@ec 6EL])A)yد"y6VݠGG/p4Gl 0`[kleK 6^9 Aʞh̺{0TjM xR{Ҝ V^ngSw>"OvkVTOh/G >mGQ"+g:F TQ3^7٭0i )Dj" 7YJ"B-7K@^WTܱK |sO4c] ֲ" I-vW8r6Kap "qRۖQ+#<%> lJHH$t3Lڦw~ Z@`*.F)[o>'#]ULVpW~7 :Gl`qdlgk"M(^nf@}|eಜq#lXTxߜ-5Q (3voQf-tj7M3(n͈/* -6<_>ĉs 4ѩ^ϡNK){BƠal' o3MBqxۚ8 -"7*-2JkP@7O'R}Y;5˼|ux2M4QC oR>A+mb*؟'=c#ENyLZcFx"?栴PHhq*ZJD&[tg͊EWA1+T WNֿٳv)o{Ugh] BR l%ه*˶ |x<͘onps{^/Y1·$7=匷\rĦvQ{d+vEms XP '!y͇(Rum`b4 G*5`6аjHvmCqLZE!RPn֔V7սf+F,i6)M }.} 4?l?{pXk?s<^l" L A0&"@G 9gD`1cFn )(Qʠ"dV&DY.ʢcݼL#eVHԍUxY7rolS7R>htUPPF' @qJ!e5RqU| ieGaa/JB).`3sګGnH_UyEqFA[RcKd]cOȰ3j&Ge+c3JzVO<(BUj.T*viʫl0pm.-8?< -.\֒es01P T+.u*@Gd<S7|B9mP|BĎw3b(S궗,6^iH4מcrʈmle"m?as ٗ@vk{/`6 kF>㔮][b7Ίq6 .5uv[GZDkfe{.בyPx螞> *ɥuMn_#͛S{?r=$HltR-_Dt8Ftb &gD,b7t9(`>G‘(+aG@}Ao^Gž24oo,vJ?Ugm\ϩ%3E"axQOd~ '"挲8`]ϠMW\>~d&x:_| }74rV ^.Aؖ .gHPpvn+UT3j)8եi7z,d Hj\4sM9]rym,O9#%5x\uɌ_D}[C?c?# OC˂tNذzpV7*)LV@T߽ykI*-ON|cm YLc6u㿡&90D]T8 cS+@Hbf5j!+bHl g321ȒDC zYuh/fu5$8"+ku1'vzC Ϭm7doW?bRPLq~8NK ;`XU Л!kK0D!gT£B ڣʭoll^G&T vD@m"6)sSPVii H pXl̗ADEwvrO. fe4*֏dsYjuYic0Ze1+3X愭,~U *%TY=rǖ3&f0nt@s5( sMʀtۀ{7ljD&J-U #Ql9w /8g H!ޱk-49;B{ S{]"ùgLónN('3I10 7MGvqzьeн0Y?} 쎫ݝۖf x>H}lviiO1g4gf-u4ld , ^qkv$DM.A|Y%ZfI^ = A`<=NB=$נ_ -ݣ VO8F]M.tk78Q lc&S& OEwGŒ0'YB0.vŁtJdRVP8[%% yB5 IDATl|i+!Uq_| ] ~}x] e|' N3hrJAf3Q"Px﭂e `RuC IPvYT.˂䌃YmSl䤘5c[[) =[/w/?wU|9A{_4Jhe#g<5jNE PmK4 ^J,Jv3mmn{S>a-)}^\=\58|0#DbQ(HTC\Sh~j=>T`ooasר&_и8hݶQvM& `7lJ gg?S)+EUq[\G@l}\w&ΤlQTύe?]ۇׂVBky\ 9m @!7ҟ5}DNS 4{g`,}AOlD~L ؈oцMl&Ó-_vE}H[Х/1e޽7^6ޯk{>t|A-L+ù,t!dW5{RtҠ4| \ps<(7Gx"ׯ_p,8J* 4g#Ttj" V6zJqn:{=1y)>4$ ?{e̜t@T.ܞ;B_[#:@ڦO_D^˱ⶺm9hb:!)z?z栄6jq 0a~#ZnɕJ7D錶TVdtN0a;X#Y4HFHDÄ'SS5zQGt_<*Q BQess횊@Zž#ъ l6 [פHΉ΢'dhjDnh[l T0yKngN͹*YJG69Dسjtx!F/\!A 'ThKd[C)`l\9LH=EE l']Wm .qmh?jsZ]J;>@|E{G[o|:mh̔xIN 51Z>Qα=c>܃xogU ]ݾχ5z$B44<Ai 1:Nb}ԝnMYL̑Chڃ /`!xWy$ Ⱦ# SW؁aSZ)@Ȱ0ƕ}]}mN؂.ۯF@fϯ5,K̻]?#HZ ۴ ݊qfM%q3JTN*y8*^b[zmFrdԆ'yPa3$'v!F#c`Qz,x3?Q\w8#~ȍ(ԏ0~17>g;OW_Gɟ/⋠Bj;"X^֟6/[D{H }[A*vDA10ݧ두x@(FӮ$P1ٯFIh&Ɍ* Xi4&(YWTj7oտx~\14a l n(I6g57QK-G$ã.8R4 AS\)u * _4ָ(F y85TECy7] EJ]brZ*T+mrp:6}z".Wo1Ww@:ZSK;[k8DѐŃa冱uCbDЊ[R~r,ϸ_پ~ZiFzz ) 8M@ u1noC3t[m GԾoc5ƣQ<׍>5v}$!'삫n]-{Am+Ip<~K s2GƓc|{\QC$قc`+?5"G:΁` Tw箽C%ƪXa@>G 0Dx[͕&}=Po[Ti56ٲA!BmUm #%/!<1hՕ:R2Dbc﹋='.bpx5aХB2dx#$c_m8ːXn$w|z}V]eE,_pM@3.Il6Vvkq9ż9')XȜLs**۹fK ͘3~Jr#p8xݝZ-ngӄt*n}__f ?.|I+Oi/bG}G~ip{T-m5 ,xDU>Gx=14{Gի zT Hj@xyC c\1[[HUhNiE7ESj1^{Aa̻fl<ҥ hfVڏ0n{KO_['Y&@,j.X%FvoB;3:ues$?ooնȟq:z/O\05<gMߕahy= (3aY +b[NA\D@UPE! ؜LnՖc']ִ5PjNxY>dh\R[yR3hv@ySym7~sEoFCg2fUf3&{RIPkșxؿHȧq^(gte'ԭFvIs'V*ӻ\Q* f3s4 tf\U$f #ؽ~ wp#:u?Fd;̽֏|6H@Cn@hЊAPX=@!u ާ -kB}1T MZ1&&NZ8PhAסB5nEU<*N= _;m zUx(ϟpؖu.+.w畨K  4"r:.H !dqTaB Y]6xD E]8'fȽwwwF!`hMkYKjs|x;+/}w#}_ɿ_e,x߇ ?okX^.%*[F*vy:@|ׯ A =Ony+4#xl\Sd]~0B[أ_@Dr` BBFVWdrMu ĉy*if&.їsjy/j}*2@-yc' %I(%LӠUKxVd*XNZV@W3-(fh,8|ndr+(Hϯ-O$>JP'Yd =ݍƜi`+9VܰI>YHx'@i̍i\[>ՇrƳ|-_0Iq&xhӵ:凌d;*(-gNOƎIqm5Prmsj7! 5};t[v wQ 79Hd*03r˓v]r]7ې# nx:;8™1I)|~c <]`Gj{ktjp|gno#7g#n̓׍iw7{8"0$' y(%'ym=IkgjZ z.z;2,oM 0Vi5T( 5Ù"+`"Lͱ,ݫrx]sW}%vU;θC">ϷfAݷ,MJ(@lEPnmܘEP<PT R6hĘGhԭv*5޺=C~"+D="焀},_<6:(%}=mɿ߼ (tbŰ׉Fp HY>p yiUTZ *Vb9[l39"_>F^iyP5EČy!rfC5QKE><k)v0'S M݀l8y[it &_[zX@̧[m gܟ(GF͐UvX%oTة(Dc2Ov/jwyqM|7iS҉=uJS{ۂOmHY"Yڔ_&UI4Q80՞0~uP4j\l\=:8&ڣ@zᰎ{ގp@JEv{`;'/Ұ3`guw`^>kC<)Ix<̟ro!Fu0l{s1Dy`s`w]v>: ] ܘ1>CyO>:j|Q +>[9%7[7j!W|5y ]<*`Uc!Vĥ%U^ E-DbL|b[|h_OBIscCtiB #X) .+m ddyڵTPQ*u=c}xhOU*(ϖ!1Z Vp8!l&Mض :Xq2n.X>ye]0ݞpկ"(DB LG< rY,+D"8~"}2!OqY7:kP5ҩviΌVDF1%ЇJeɰFgP#Ea4*e[tiBC!84Ql,*}Szz>\kD,Ʊ *ƣ6{i7J]~c[z.\Pz,bu)Hb9gltߔ*jSz~(fj'D\aYl>^-P]tR0A%va/:7&N3zy$I,E"c2$d@2ݓ[%e\ϑsc:|uNyƉ4aNN`[,ݶ漰L:Pz'_8Y'=|xͶ(Pq? lAE@HӎaWG9ad7zrvݎꞻǒ#U#w;{o L#}nX r ۙ),"/(bl6bsѝz6=JdugT:>3HrY1C΋֟ `?>T!R-WQ4c8PaN!&$V .puefNl.8(_r{DrlѸ@pBU1u鷶ti`QB'ukϹP}5a#C>''G#uĥh&_m&\Bڤzٞ:&j I،jmd>BzP/-wfdmu"UR\3K !(0Q8ۚYH@3xy2 ŠLuuAb;EPQS]T*(=tP[8a[K3).>g&5gU gVUc˖gU<$ UW6K@!qy⦢EDɢ 0@6>~+sp}%F`BhڥvzMLHy]Q j\=EZm IDAT ֺo:1 ]& 8Udό܍ʛ~~P}܍&j]Aͺx.a7xP&kN a,ޝyq|տO?n\#cWv`cJu CA]D|DBF:7oGa\H`؇ .݀u?8wN_~~CZ֝a. нAWlC;UG4& !׈S3h 7İټU+P\(66ybPW><?(Q~ΠtB9UVdfJb'PX2, xz@S7lӠ EUCf]D8AV0Q$Ą$_R1Խ)ٽ+<B _1)/D Tkce'U6JٍpB`UŪ)mFs<<P`bv=`*hjR Dwvc.udt:̅cxC;C$Lc B3Qˇa_4ZS̪H ~G~VI PhQPюa2 %[ˍ+ "OQu=TQDD.%1 ] d5hd* Z}|̀՟Z:ȢO Ra="h$ 6/6͙D ʘHh@ByUŨno¡JV=AVWS{U˝Bƌm"v:E0-> "6w#u[; %qƖ՟hvbL{j00V gsyi4G-؟ױ]ф? >8nl AJCw֚M~r ˛Qsߞ>.:6ct^RzDt2WjI} i[74|lܞ*Wvbf;""3Է߰ǰqB!91jI{8V+A i @, i)^aw-whJE+6"v %ի^}ߔZH|C$ lGߊq_ÿXi a:AQp ]e[?O;b+Gc(RP =mS R -EHՓѪ|ʋE 9!geR@)hؖ3ǿΉLb]ÔnLޗV'"9F%+#17&{]"Z1>F`=$ س&P"zp !jF'qITCy |mJ z¶@grSuVɁ~xl(iU") Vg6>>He-^E;] btjQi\ BڒCEɌig@=(8aXX6727Ŵ <GdR]5VX3:EL Ϡ p\93g2Uujt)]RT.բHfSbغHș]:ytårծŰ#ONdH1g(ӘXdkK`V9* ͓G;LSU`+&UIsgCH9)ZYq  qOZo3EΆn9K:@#Ix(1~gϯ& g_7Fytp:/Hۥ>op>5М]юh3;\xMĮ#3;# 9c! =7ݍRȁ~ݰ͟8ϯ&4+s @15'ЯWv@o`%|g 1OWuhߐko=aJ= ._O 4@eN5vӳoO`p{| YN79P5B,%IWw9GzWFBZls0u2UdnWx@29u0&O&1L]%ٰd1GdM2xAjnю^ $Ilf0 XC!<qϝ{Z>u?ՇB1. $h[} yvHiYoN{3d2zDAZƣ F~UfĔJ)Bhz 4@lntQѴjTO({b2:rn {I@H^ўK" "rEF9͋ՋFJx Klh`%,k=}BT gb@3&aY$qFV䌁 .2TV|:uC:L ffX&)~#g&"za?3R lP=j'c%u[fFuhO]1ݷBL]a.,W]wFD:ދN ll{5 `Dy%;e7Fk| A@6gS* 6*O!ȌH10M@X5z4٬} ¹ݢx1H6u0ДEn R;`v1 4¬4<[TQDW Z)SznY PEPz$6qpbhǑbT*J;?do E0840GGqmiyhTA ҍJ{Aܜ(>GI{NOѢI2!Мv)|Z;+m p@^9QjO|=X/fu3r̀GlO7=x|LޏW)w ?/y+H>L>V-lCX-Yb?YV> Җ {h;B_] c^Mȶr} ĕA^C>6=!< $A|.F>VjAטO˺u{?uޙhDqg/Ay&ޏQ?(<:.cֆXvcAM st&s8wp\cv4m]MM=UɐiM " 8eκتqʼn~HT%ߵw{f"T͓ŝ_&ChDa7<IRb@Zt>$eԲvbkzJCwh;Uy#*bP{hͮ>wν\R*JU%,@ @ ـN,?+?Y;wY $!$4JR t={%1Uݵ{ Lj|XcE`\ڔ;ה*GpD@M]̅oEGH8a V=y:jR}38B#\rC]lTQ !ጱ\Wp9d}Iiee!s*5+ў,`ωcڻ2.}cb4oEX9>C .򢏫 >|K!W"atp&)o ,9 3&;B#ZWՎYM띗9Ot;l 0tDYLV0_l4GZ8м\qEr:(VYh&-s FFLJH)Y)Le1\ B5%_FOBuH[h)+lFkŦ=y߀N7 Wk3y q1RAJPRqDIɻ Ͻz`6.ƤҀ7xC B ␒Ue̵p3cH>E?ⲶcylDOdV}ZJaPSJΆ!\J x ^1h$E , SFMuf/0&ZtOdNDa+ݐs0\oOQ. FVOëEd>#eĪDV$kbq<)813$Vc$@yH u#4.: ;C3P׌T"mgUilQZ |?K:X|N ,V|,"B{8<jhE`㗔1yr&G{E8Y : 4W#N%c9ʷBl}Mm/oX>k_2>CKLm~DQ=h4`N4S|qMDO3Q>B9L2䱉b>XG1N6xi\ I yϹWKd'9!7p ;jWĬB(લ1ϨECH5Jeҫ|TFƘBoCX m&{5sIn]#PtCI.M3aCjME Md=NB!29hAaTAJwod( _$0˸eg ڍ:+R5L0 5$nțH '֕IAb=7Z^@kD\!`5QuZ5ҿ7350&A1{AŬP[J4"Dz$ qPRaږDF!{M* Ԫtik"v/Z~i3ƤȋPlVPCKߗU64Űn*üF2t&״ir,HUi!6z&+cpЙch+VW9\){+ *spwohE^']lIT߰4ѭl2s~ HZ@i7f^~;-<rԃ%|Gפ]MDy o N\]=ro@)N۬{(4.BT*X DQߩwsYP2¨@Rz@EAwbA&\"VRxqaǠ3ctNa L 5"cV@!)0Yhy<,#\U:f+ } kviU>f/ۉk*0? Fs^QQO0`^No +).o$L ;NZf8b=al t6 ²W f1GIt6]"4gT!HUWEJ#RIZz%zI` T#ZEէ9RXi.3,w^>(4lTvdVLbr~dCRV@ H&"Y:.oQU+|@W:3Lx6 lzfAG9X>c-*Ҟn˛RW-b:\^hEWrX@yRR.c[q9\w;^KU3bt`oio ͹꼡7sB>H҅ز%ڦ.pwS1MzAL#{\ 9Hߡ|ي[jl<ּ@L;BЫ0YE"tH.șOG5gPGЁ|?lU;*rvbXh:Gh/۰k [3]W9"r7w Oz=F4!I5!KJ )/{VrXJ2ND̤=B0!F.26 N9rhW&/ MTj?%[=f^)YRnʰj B-vӼ8O"+*Lhʰ%H1 )V C61TM%[¨;kT1Rva2/oO#%y~ghiN#mMT(i<~avW̎lԾQ]}%co|&sq16"#PSW9D+Gs3%uү+Um4rFƜ"+z6앧(\Z4`$+-gg.(-F1GdLND0F8)SbQ=9iA٣(״_F ubkd"|PS 2ː"="|9Oy=|n`h[ukyKǾ=:0% MsV2o#ˆҺ sOj0g?Y_t;B B G8y,r֖{G߿6,!;Q)ħ/u\뚖$FH08C!\1c-IsDDPKzbBm8 , L28M&iܦ&oOb&x _zFR% ~4Q,knLʛTAF$+HXo&لQmY6 #)":G$Z!c=$lAQ)cR]cC-<nbt y1i*/᪊q d@KsMCX;oAV ~(Q"v=\-~"%Jk] IDAT-㊣>e\[pf}Α /!PZ5LemYk'8Hxu):Ɉ04/s%qO{_,5u&GQRZ39p$Od|q eB3$hNV4I&kmj4+yug!ͨhV.ё(q<` qpcXiX$! WHTu#ZkV2MDnse #6ߚ qݿLN__D֝G=\2rfp}2 JFu!Il;rp.xЄ'uo&y;ch4HpBR06l0*3mL&xw3kr%leQޮ Jx?ze COq.ue&5EHϔj%y2.&ͯ^7pE; +118QZ 3ԉ (t֭4艠Ca 2`#x A Qkw8B5=op!Nb8q(iQHxI8C\9V@]+/)[`(V^kK{VZ,Yˬ`@\a;3$-XQ0L4A~d}edØG{iߤ)~qGD0z .}hAi2`l4:c/7QKk j$c9XC2LN5g]2bhABi$XnTX\䨏Y),#T("S!c/)Jfӛ)}XZ1 nwYN5;1"1k8sqpe,'TRՁ`hѾ c;-q9 ^|Σ/A"2@K+oV[S9gǭPQEٹ͎lz h_6'hM)I}B92:W%V±)T;0W,ܝ?p7[2[8cq"srKS*Dr>^Wِ @p[=xQҰ  4 T(/e}=XQlڋb^Bry>ނX PG輅ba7Z7!#1>8矆xMߑԓrND,_8= LkO¸{2ke=r{d O;g!]^݄w_cY!@w(֥dF =l:pr97!EޡƆQkjrF)<<5Wր%CZ\<^S U962oL^8$輒0` 㷤/\8ɄL1bTSkDqGJlp]W/9i PRV%r)<(G4J9ћ>4ĴBK/GtFK8Do CL UcX5}' )ERv yhHHߢahMR eU>N UNTsIjprڌ hD:8\i11&k%I %'8 ;ӏj#Mh یAGfSÑc0cqQ+ߥgY01 "FXUmVR48!$T;Uhؙd'H4s  ə6>BΈ57PLm @b C32/ u5қxM}KыedW$O{͹ZBp,qOiuzfy @ަ)\A÷J !B+4=ƌT"Xf}FBx SSE@F&2r$:'GgZGq܇- /q6:LQ6t.;%'|{:Gq8D* +3miDvZjNX1^$tyoĶ Jk*i,—d.ສ$^6 zz3>hRAI5bhh=,8M-xSGށ;z?a :r70^J8'U7y?v^Z0,#:/SW +vb2>zf,25a~ S?)qh}ї.) I+Gh2mjPLv~\aWɰ  3M`ʾF&} UP4c&Ex&j7[1rl#I~\ɞL1!hUI!YyIfY]PO'[JF8 2g]ubC`wB_<8^X0}$% +}#+Oʼz27aS1I~b O6Ԩ(HБF5H8%%4 WMTY# StJA ƸKc  [S#$r8Ȕ*KHcFzGf7!vt|`cQWd {bf##=%G<#GHϐ9Yo1.h!h^Jc>ZiL\,C22೼)dV98Iok+=Afr)s I[H1u uih5δs6(#/" #b'jln Hs}gT+ 9R\! Zq\F5(dwף?}yy}b`6 Y VR u8P&VZ+k9 )}?)JEb))@u)pz\t2Ѡ&̾#aey*CkA⦣!#)/4m].GD ,#l ND1EDjF KBw5 ʊ&4݊x)Z0!Fa{oƯo8x o/g~39eB/Þ܋g!\ԯCFYLrwam4Y(+?O?`D(GKZdJ+ @whMeUcYG!d׭ڰZUH^wa#TD1<$qQ:d4: @j1^Zc=&Z@^$8u.Q'K0 YݼbSR"m zۺKEQOLT!^?61 ԃEFNA 29p@5na++u苾+M(kic*8Y*c#&\*T졆, `)PJz1!ʚDr_cFnɽC&ZJm`L*y dZSS#N15rB&osUk %Z7FLބTzx>_G>VS~E42ɎJ\K$OkE3yS̷ŦOG؊2ѯ~cב"l7ܹKz2FSiR« ._`c: ,a# o}fL=.xS?9<CV t܎{g[Wљ1:h*nRWtf;zT cZ:ypYΣ>-1{ؼs/:} <֟K*SߥĺB{~Ly;x/,U(bOatQZ-@9*Fttl^)z٨n' )>SJŀ5rFNy[=p~;0XީR!3Myd)s˗;^7WamX[ R#{^|Ғ )Y 1$(6% hT2^s8a7 UKK0|!Σxû?bm0,)PHl\v+'Q-[->;1"V!7nocCՐiÀR XkD9~Ѹz7#32 KӖU=7ce$O݈q?(o Ȓ"CXlz>9RGYwPpI ԱϏ7K9{n<*os7HH_ >chІ+uM.j>b.oAXϓlu5R-Jɥܽ]_P$1e;v&M"F|[]SsW(u%'Կħqz3ϕ f#; `ϣ*61{/rq8c$:qEcX7">p_DLhיQ"=hz^=Pi/K_{-}M*Ӂ&W#VG43@Ѹ3KQ?qh2 ƀ݃oOf<߻{+2=^ُWᥗ^B|qE7߇N9`Tn{qzϟDv=C#o>|?u4:-,~5Nx{XeȦ6#ְ鞏=ug6p`s om6 .yTok>;?;oSM l5GmϜE ߙ  [[=_{8tQ,-܆3Ϣ^9|vh u2:;-8~ݸso6x߭C YI:ww noi+nv|܁/}s<p=Μ589RCW}hm;[ߍwaߦ5rg*I$x0">7Q^xޢ<V|gy"=cY_H.{H˚F82mlŘnU*" rγ$`=8dȦ6>ط@;d@6M.|o¨"O>Qm-lߵ{ZqQR/kܾ_'Q^; tdE=;t&Ln15\0 ~Ua؀In1 |{3 8FST1jY@0Pt`{tKx' * c$[jP5Ok t'9Ә`Wo9Ă5/p_V.}Xyߠ/ ,c",E5~<3UIS=;~?7IkI+5J>a4ߞF爐qyiȴ! 0CL/sIKc=›ZzkT{:HH& ե}E|"Rig}_A*{(`/ YB+a%E|-P(gUTq)CTgTA uNK]sx6!D`Y1(:WϢxt݁XRnߓ1fMo*US7 2*)Nh礬눏>p/]j@m8ȼCΉ =ғv8b5oO?dPQvnm;ۘ]Ȧ! ݉1ш J6Oe8Vcy-3A[+[n ܡrhs ?y &}-mX{95{y3"cTXYcxYGȯ!!#| P5Mo?w`BV0rv+#RL+T4 P mLi.=?fe LX>}5~9}"*q< *QPyϼ t&9k2E^1bЛ4qv¨UGZG\S5W>򹝘u!Ĉ:0ؽP`Tk5mkw ^m."D`\G1e|7CLǣزaΞcx)L< H9G){:uU;;s]ң6OeXXSgm[fؑQl9GE-h13m2[32:o4;rWu\m 2`ӫI*> IDAT<ס)3nSU[Z>r/,`yq5Έ8yoIc_xI3p`^<߅_fi^/ԑ~=Tlkₚcu#"@Bd~ $fjzt{c̊u6ϓeBT`bԋѱd~x &kh& ;KMv!|y`)#hʬWZqREAgyE9j-$[ɳйYAOh2V"RһZxhzsnx1liza $3ã WZW9뫸~)}YE l0{8"./Rϒ=12=Ɔ.ElTU0U)(H7$_dUAY&{|5Mr8䲦7l6 `x%ƃД_{hΎ@F| u1x"S+җ-Й x)Jp+=ά`3Tۄtdv-}ч2 ^ی8|~*2`eH T!Z2qsewSe.|3%Φ6cS/!;b.טfXexiB1Ȧ6÷GFD-[h%v,[=#)Rau[3t(DmQp"F9ԁzal * D+L H*Rr0!jw6z3tR`S8ނ]5&u6`yAr8 mQ.|y }nԑw>r?622'sA1=ـ[r\Ko9 τ0hM-!3fa'0$zt3%N/ZZt K?U N|rKpq\rǖ):cTZ=?:z-NnA GnĹ1V.)p1d4s&Y _P}")L=^X*y2&ZC+Hm.kJx JZ˲f;dP&/N&Oh^x{2P](!(7"Ŗh8}ugdYDE1F$&ߤCy \]S" X z5Jw&/Y%‚xF>_u _.u:G'wnp*s? 0@jb˃k'VV#Ig~upXɱu:ιB,sBSJ4O~ `>l0&䨇pҀ҃a7Bw\JsRf! %mTC|9 &Y;u8:˜$oB`bZAgGz/$ΊqFmka.B$"p }}_җkyFGL' *ཐ$Mk7E`̇]"%9ԉe=6RY9y^F+*m\Șh+$ i+y,oLއ@EX_">p+'jIɓi΁M>ހ1ᒛ jPCzrrLz/%ȳ@&v:8N<9TRq`ayP uxRKaz>xalٕ ky\tEzg/.\Sts#2kԫ_>n0("A۹los3s1(Ύ"Oؚwv\cq& `M0s5Wg XqCx]ׁw{qE9+G59I$|O-UX$|GO8ՠh;4(ƭMwi7f^>n*pvι-5"Bɒ=z;7 伹5Bȱ,1sJzλ}ZÞ7,l|nng(^;sxE,uZ?ɿÿs)eKS™ ۷o(z?{b?CO1"/)66 q2fu6O8qą5.֟T."w0P|(RMe5<[샾SnrR Ļ㨐Xldnl6KsJ qVؤe{{*cmʯuՊL~o I: =^\39To 8+OH{y'ACӜ1q_|1p&_򘒒TN^y-Je)CJ5.)By1A&2 m2nVl\8Ked1O2\b$b~|%:hYyĘT קwC`[fnJ{&2F~nI<ѕ E 'TO_%}yC|΢,+]tpgsHQ瀹N2DW'|nXtIL'@Xy?^pq5Xe6a\G_h@;WwO\]ƝCk0m*45O^.y .k! W1,XefVGs uyn/F|.9u܌C[[5CQN ꕳ:3@=SK9أԈ^V#IE-5ifvܼn&;5~$ D3hشC?~Y(Y20m}D TJ_g5/G"eUu 9zYceZY½|5氊 0H^ Al<-1LIw/x_}38g0|kȦ6fwz d ٛagTҌ"D0^Äz2@4eJ'މl=V1&.mPs5䮜xOJ=|XyOi&xQaRW =jyP`. :g梘>˶RcC"$C@ W1 ͱkΆ҇qBfG>uprƖ|RnŻ Io{/T= T"*J U1raz+jș>aDWa$KϼYa I>S@Y*8.g]3kc[b# ITmP-#2l^ܥ= WԗXQn,0%â?x'oV0U`pxr/ckqgrs/EU=3aUEsa6cLvNd_}a?Dy[vO]vXX܋nˣ  }|OW^7رes~~o?g>1> ĺ̢^=Xp8m39Dk{tgb|BpU*nzB!uڗChPi%~/tf$c!'? ʈa+@IUfUZBstX(/5 k~"_vmZ"RP}/<6CVQӤ= 7*/el݉UX9QdTFc\G[G3= H٣6KlƋK%FT|V./PTep wck߃wίx>cgQ^~C#|L_ SZذߓ}" R6DF9wjNʃ4'>Ves|E`OG :oezzE3YJu,9ʚ[r/d= 5w,\sk cudh@P3fNQ7TѩVLt)$s;л^:\_1gN8cxoCB 92D ,/.h{8 WZvxVQ)IC$=9WEDqSeXj٩a.XYA0A=ۉyp, (Ip_W+ʤ-sJ8Gӿ0>8 O)L'm*6i,}1~ eTZL9`RL SGp-_oƠl|BS祛TиkPTUJ*& (("'wșbtQ˪P.T·ѻM{{ K%N>8/#TZ9XWy{s; ӏa(/ |6![s M Vzr (4DDEe`?y1XG+$ quy^\P*+Zq;;bA,:3cwm Wf#4wƗ8S [>RH=&ab s7/~t9p/`!C u9D@=٥eӽ.f=c!V4`/֞Pk"4 y9XCv(sa]l#8v`  '>>Pl̽#ފ`ߦnGw`xfC=}ggG;~K gr}nl [(/< p@1?z/=vuA٧IGG,a dhz.RI|>C6ߌOmm\Sȗ~{߳#({`i(KQ^|NQ?Os<Ь#r~Uc栧-G$K!qU`sT 2 3Z" (Up`8};c{:jU霪Hv/‰D֛x{ZV *bXR:s.GI~waq60`tuā3:[ϣ^H$[ ͤ8$btD:TqPtwuz裸@ғiޜ+6қCZ%ܚ #I=k_*Χ7A8/п4TT }}L"n{yؤ'uNAԌd ӧ}wÌE87rw[K>>[m*i룊ʳokd<ʵmw! % N4m'KyX~4ILm@jQbfBBCwN_Aj%܋c8^r?hQ@aN|L㗞wsw(};.c'X$|q6uG…5VgM|~ev_}=\>O}(>Åuj#Xe8G˽>hMwc\SVy*oyN?ĈXѻ-߀9;;B+s#<9#6FT[gs?E̅1j6z[1> |g5݌`Tu/ jL=n`y5h8WSnFB& @lz o~>{ޯ))}\Syg\G5GD"`PEjG"[d=񹧩T3gW#نX:i{n23;^_FRT+ɷiݾRD7I>[`M{5+?C{kC,h{DӼB9x$(0cgҘH?f 9b`~VIDAToK>Xݣ AkB r4v1f^wFy+ lDO.'q58NAAs=M}8leMC9t OgͿCР2$=<|>k\C=GWx}>֤g=8/RE'a#]VpB_߆Ȩ!VŦ=xfr-1[9{7v;-R7w@ɽ;f;sqk]{Fd}AzW+9;Cz-ʰƽ{V90Vψ#Vz[=p/w;pq5_;A5rpnE{QM{ ,XP6I6 8Zcס ]̎{3+qI`\K%^]}E2|{ o{߇Q2X8?dzPܵ;>bӞD$c]O(>QSKϖ9M=~|cfctaX+#עs޵=q_9=+ie,G_c ā" <ĕ *U UK%Eĩ N$؎HQ,$d˲VvϞt9{v%-V*{ufhZõ*b'e wщb+$CbX ]ߐ.^ەqc . ]6ANI6pI:uJ3̉q(,`W`MA>2Xh'h5RM %?cA}X`Ѧn:`H`a 5`4^y'@Hi3#84sm ZK8b%}&_DlD31r8e E%!] $.J%yzǰ,H csM]m;48+nΣX[Bpف' sc:mh nE ['. i:>q ݜ%nܹ Q;|&52?kwf}?knCS1+5֑_ih\Z#x9f rZ ȕAod6"Ƭ7wz#C)b$)OX:N3.Nx~Km'PPxp[[K]m:.JdA ٱ;>fu;Ue(/PIdf<7]R"ԽN\3K#%r3:,$-'8ɔJ]甜XRz|Pgb**6(/ ~n0FvqAX&%5h 3uK1s_[8>'wtKW!qQg1|.Kz掉f\9axYoHS0F8-Y6~/Eko+K3+cB&gge"YSp׈"391|LR{W#:s„`fwĸC. 76a--ˑ,LA%ޛY9 i24ܗ>PNn "N-ȹt$)_Y-;ě͓VjHsVL-̐ MYʏ,4BuFuk3~['7h b%$ js{!#Qr襵!kF3Hi'm\3qĹlScu`20807]BR iIpa%GKQAQiBWS VK]8,mxYn {M(V/BMb GS}j>#Yur'Efr.һȪtoaZF'A&YoE ㄇ?5~? %k#,"U4 mD.q`] ?cA/kWWap f['pfA쟯!R4¿BHXk r+87w%,u␇GB5\rҦy(?M0:P"|RZa"&\L^yKę |u?'ݓf2Yք6 jm" 8*p( !o'[!_$94Ym+H0+1ueW.`[6bw'vPϢD7':\3Aod[`dsC(Fd4Sx})k5. 2=Cg%6"#B ?])BF@̖kӿ.`wH  +o x+ e1ޔ]d7WCM+gBO!tG9iqDyh2Eމ|uэ)0YkU`:+8G3֠(g jK(:m L> 8k;&^l:-eDҰ5S@--KA{IcILYgKWIB$&/剃pHV/n9e^w}qd!u~Zyg"K (]oi _zWqdXi*/ʏw`o7߁?{hv\ &/?o%p&,9UΐX@.n$6ss3v7nc%64R(]vR=fi,S㴲TAԷR9m.EBtWKC=7UpDu |g^Ww&,ƵϟV]AcE@Po#kW*סf3:}xͪpn{?'VJi1cҷOqKlgB['ןiEȠyԆb x( P]=I/5z~}(ϜBGvQ6?;+XB8M6>,O-u.Kj]%(h".^_,44E3% *|'PǏ~ n;.20!9;s  uR,ތQX;Cd} kB#QQ#?b)[?J0.+".9kEί]zKGnrz~f|(8w9ٷES(HZ;1Ͱ O=#P Tx;|5GiEts6oP.N}CCFSlnu۔vۦXJyH _eI__IAF`)}K&k6ohڗqos# WqXUIjS}y]@ZlK7[2X)[owIJ_3aw/k$?8D̳>,kzC,?ni9H*R|˔|Y'H .<_{pd!Eod`,X-̐=;m 9=psMVJ'vWNcxI'mL229Hc.ya>SrR/,/{?i.K>m3- 3 ~va="V9D3}/ pA> 1sfoB{`#voD ն25ֲz6cL&I<8:0◇SKȃ!RieTi7le?ɉvl61If愽)zg gI>r&qNCcU cNV1Oij٨kQq[Sb73Vw\ ~6QƯ&8I!>d2*\ϫixY˛mosjOO= *pPżqWPtQ.ctu+L[PEo=!yI&"[zfu 3 ֭@՚krd8c$0U`GPif؅-cǢ>.}GQ&us0>'?FƟ6a eэf|YP-!_]'&!.G6#"y&"rE^(4_lMxkx( T~ ߗe:|[@T 98cH;fD8{__NF8We5AU^E٨qCevqi|pa"řL""=Y).'FNҳ*4T٤:UI \-~UGgLZ5)m_ׂe<ڈz>?s0m"IJɸ ETB5- H]TU蟕 :K)LN h|UVHN.ab6Qt۴[gY2lz<<<cL$Izxr-tpR>r[ %TƯ _׼׻T]K 7B֫mRP)UJ@n>>~_cp&$L; bD̈c68 MHS߆POm }4ӫj ^k1[)\nt`f<Xrի ^SPZb.qvF${`z46OZM)oM 3z8+ǥl8f4lPjugƑnpyBa_/ױl#wƞ)Yn69KYélA`aUe9b_ܾk) }qtQņvWЅ{= JB c{׫RPVQ8Q[$ J)Toս~L\UFR#:Ö1TF+X,|/ީl.z\9D Eԧ$e|64-J-0ZwV6B>J'wP 5 ?d[VMXM UPfn]( eؐ}_[Ϝڲ~.oK<?B᯿ErZsYu0+|+~qJVY7oqa?:fKp* [mռJCį&Ix11Q+>hrÖ$b0x(vlOkESe!6R3(oRRT-KxfޑJmh)X_ŢFZ޿}~6T5 ʛ'DkM>-Z.:Gy[nQT3nZOE'1rtmY{l]g=rfMsD8HVRϥ,!dG~WN'bs|ωS:[/QD2 IENDB`CPU-X-3.2.4/data/logos/000077500000000000000000000000001341671471500144215ustar00rootroot00000000000000CPU-X-3.2.4/data/logos/AMD.png000066400000000000000000002230041341671471500155310ustar00rootroot00000000000000PNG  IHDR9~.i IDATx{Wu';߽uU.eY.=0_!@H :1NB =+3I9a:NP fe<=YXix1L:LVwҐb:^ d mcdTuw揺|{]t[K;:;{= `0 `06ܨ0 cvq~;ß=0}_Iz;=(7Lwv`ps3gN{݉}3KYgN*4ܾy>[pLtbnz3s3e^pp;WY"l6LϜ imL .O[LϜfrٷw:M涡]37=s.[<89С,Q`vb݀;R[AH,o '9p~p=qܾCAxMwGgfہ〒ۿps[P~4p8=mp8 p~ pK([IY&GΟw[<q~;;G~g|[醮hXGXG~w奻?+ΝxfĶݧN9}^/vӏ8ݥ'&Ƕw{w.<&r_hk[,K{ιpnK,/4;,nX.ϗ9犖+ʾJ]u S9>xkƞ/}؎~9j WeFVre&m#?윛,e}@1VƗNњn?G岿vE}9[2 ;Ek[kk|$ x[ε)/v ~p+Z^ߗ=[meew̵Ɲއ@k/\@cE1mi} l-:/{N;'+K{B{:Nњ,uMK뀢/Ϗbp+4bh;`K^8Wc5\Ϸb?YzIeض\ώɱ5ε_({gNjNMN_/?Ηg;aaA'cwcξm x߃s]8׆GJkxY9vrPj/3.&"`A~ ZN5Ji2?~("ܬP=$O)$@Jڇ9-kj7B/g# ԉ';s, 6<:ca8pZ/A=E~/*+>GNoGBWZO@6eeaNx#?on@(t#_KLfw9'E՜qQP U'#2@l!j%{iSE$:B"-ۖXQ]4wyG5 gSR20IUScnNhLJ԰GSL9<~ g,'nҾפSl 7wu}eϝ K?q˵_w=OG?%Bi}P9\OՍs(A -Jdղc$H烍Vד4Ofg/AݥL?>/S V!@9#_VGbGD4y7k6`!m׺~t<#!(mk6?>LS j^\uo?mj^I @7Hrt^tVM\E\EiY6W7>1=K m*T''ӑ/\WŨ1 %ZNЌ}%52CVٷB65" G[k}NiG^MF~C 06I>i⩐ES=!43RdS̯C ( /R<z‚u?/^; @<'849',$=:HR΋= H9u>"d< YX^-~jAbJJH)ĉ/e@gl/זr?_8_ lp'/KPϏ rgpG4F?#CKgj>5 iɿ uO|1Ot>BU~QʶRI/7Fu]%Yr5yF, D$/S/ R:k? tMm(YA:XYw)@Rw~]5BXsG~sb-_>s/{;⯛`d9%B}YGqhuM>M_'Xs0uIYKޗخeq\;Pv]{[#wMKaBW>~O?v3_0K˽L/jf2x!Fq1Y05iZ5#\| l_]Yu;+"0:=9t4~)!CL"tuM'7^qmjjlQζMx&ɹ̘B'6mb/gc1jvLjY.4d: [QX[ g%6T`} 2ARx8Q?y7}Se$_TV- "E^CƋ(W u <\Pj0QA$ hz~C6 k'qB_4m_m2f r.3s_?䞗ye|QB j!-h@J_tH=Cz?up9Geq ''_:8٤a+B`8B H0Ey4z%d}ТMq0v`/戂ɣ/u4CWZNZlJQ>̩+y;*!Ck'i?&*$R'Ds.Wi# A "3oh~—|vN/e#_VGkM`'CڮuRyFCQΥm6T|ɋۤSvLʒ@Mje:pxUduja _Kva-#2s%rUCY@dh~=d&{*kd)dklʓ:ǥ OgrblCmI۾Nj$}bjm8l=D 4L>K ^[sPLDŀ2T~?5l&cS7+uTe}3b8OݻƯy O}a]h/'qP]' ɘ8_B,"jt}:*C:'^/,ڸ.pÀn+ x {U +Ӡcl7AL:=vOK de(vsú{/'ڝ'^sLq @^ນ{ Yk~1J6[%N3`QZtlel6t4hP2>/_\p DFH#uNן b||d0P6C#V%U!tB 1HIy(hXSljÄ%_cJ=^=+ea|{8o7ps? N2W.qH1 i0'oxDϋNK˼Jd,QN *F$98pB:ᯁgtrmTS#-' [Ư>KHhJȠSkS)Whc|c`jFygD O/g-j 1^vel |'k^[&?]"R2#1 ML);By?d:c! '<^H>×fWJ!𨓅|ɴ 'ɯvRڍ蔘C~T!/S/D]",J3j#"%4x*DG]|32D{i"On%tY _HpЩPE9 y{5w#@2Ru@5z^UV l\Ʃ9%a39Wѡ>[ $|jkiXBH iVrmdj!l잜T~O Ҵ>y7}脂a"K'*',5z/£\Ɂ%+$\ fW=9]0X흉G\/tH)q@;IYrP%.(ؠ n̈ix$=:HR΋= U@!23嶛 RM+_7#\d3 ^)Xd!qnNn+_ T>$?)fVAG8b!Դ{rXDҏa g`5Kzwo} tU8d~2_2 lB8\Eiѱ-sQ:N@6P:lr4cf_N/( e$DFH#uNן bOl|d0P6C#Wy5!tB 1HIy(hXSljÄ%_cJ='0BX [?v|hD/U {N$z^vZmc0opD@%F:фhd`Θ{kvJ`ȤN %:х>2|;ge E'&Iy2@xjᄿ#V{"su u,MqNV(tJ:RJ./Qo?֤]]#9{w>|lu^ė 4Zq 3&T* :,F$%#Izl5D `d+4b?'~x Œ7 y،~YYwL rxnt@X^%uL5vs%bĄ|~ݓCdf YvCp YYseʖqyyACjܔ:QV鑱$}Z/?֏6L,p d?CisJGiqpoC8謤z=92O߄I't`K4l99w$2|siTGU.WnȲI@-/OtO2jQZO&li65vJuпNGm59w)@R{rF [ɹJ7w܌ܕ |8Ĉg_8vO ]Mi8baKjEݶx^R[$yn"O+!KPS/N+:R:kݓSSVF%: M՚k :G r"|'gyRNa`Ɣ8]Y TRnǖE]Y4!K.P،~YYwL rxnt@Y~FHN6"헵&3}.M:QnS%y;ƿ'0BXs_==k?ſvYձy9䜏|N qPVξl\Ʃ9%30E%OOZz"7%dCeKm#h+8vK`.E{>phGT2eƃ:'_:8٤ ]e8Bmop{lHl-IV,`%I M =ey6lЍތ*<ʓ~LF :VyOa *̉G~}޷ :CQ2ղHK90Jb‰Ʋ^Iaj"۰gI|fb_Oo AҔ6 Ųl+xlTtH۵͔m\fCHM:e, ԴqVަp`AU~↛>*`e`Җ銉e{"eh2yH2A[yyA\Z|UK!B65BѺjHl9nz5ex-' H& .BB?M%X搁zF?9,ߓca *̉Wݰg~[9V$A{E=9 J!"k. 5}:Pْ N=!=HzHm2S'ۊ>3=2ׂOe#!؆iБuz5@t|.X]a$hZ19嫿pk>w.jJw9n\y-j` XhyS:laSYdY\Z/g̝a]E3@U?u\udr5= lJl,W* l$n4/ЕlG-/##+igeIrLj|(/s4i/Wa/E=[؅#9Mܿ8ɞ/ۋǞ`2fz<@ |.ǃN4u3FHGDH'5d;-0ASG .2 -L#r|s Ij%/=%@)QѱNK1NCTc,&^<#ZՎ+PPhҴx6 Q:ö g:y㣯_o>$CZt@%@gQWs2MȩxJBzR&Kdt/fvŎRd0Ȓ VٔУ|^6Wi# ACߓ-(*#VPvO9s3}+-HKKl4g?g5QH$d&mOҔ6 Ųl+xlTtH۵͔m\fCHM:e, ԴqVަp`A!w]xɵØkL푸 K[+&WLckeDdb/$xJ j|ggAP(r9ﰺy;"8Z DtV/rUEbkϩu3֫)/sh9fئ@2'mpQ<h*Q'IJ4 34Ja g`XOXcq筳u8ٯ{rL>n!"k. 5}:Ql7zC{,87eNA}fzd *{0G#B6 +Ӡ# 1ُj=9,\"DZR o?V`i0xpO;e*r"?yP)'YP˺&?MYr5yF, D$/S/5J鬕4hұ6jlScd]tVsy .EO H`+907}ٗm]hhasDjHb⪏yQ>d6*kP [!U?7$lImȣVu|oAj$OMie. ''-|`i( A9 rGR_vONeO]ѥ|죴Kl82SvLfax=9.s3'^qM ӻx`>gĪ, hQ"LUW*y1 %߉Csay;"8d}ky^($mS!9+D >ʹZ\# ϡ.Ox*$4CTTKs@A=C:8<z‚ê07=s?q{;a37 :<ɧD*O>yTNfWBP&(MFFG82M#GryyACj ;趢L AezYs[ +Ӡ# 1ُj=9,\"DZ9=9#9UӯϼaǭidaJ C ``FWt`2>.9{C dV=$鴘c{2(c|<[Q{Ǵ,6N ?up^S<̲2|oAj$OMie5HT(:" -DN[%`[$TV!u@E<21xD?  r ;oqۯ֡*@" Ϲ{:' *KǟP/UN:N&G)ȣ#:?#$P]mJ䏃tQg u4CWZN^ )Gx2sK`~LV%(U$-I*ڟ,N8]&Fݙ؛LIO&#VPA3nyn<2#6xӧ>/>WpGJ!ld!QG~ Z1@'3KD\>6Ue8 HL0תF`)*d%g pú'm, 2Vfr& |!'|O/N((|9rl, b&zM+}2Ammu3֫)/sh9*L>i⩐ESuXE +"z5s2*Mm5d{bvq~wa=aAa]q`o7VDh'><N]|'jEHt'&dDD|9\ni0 Ѥ"jt}:Pْ N=!=HzP 2u3#c-HP^V9BmXY@~\Pa DWI?fLΈ`Aa17=sέ;?[Ƕ0! V1O ftE' 6!#qdɭҰt &!KwʠB(ouFuQ^2z V88yYOyd0P6C#Oah_چRGicK_-:9ÚC?TLsH}X)A\׍ż3 eGܵJUѱ39#.>_l۷+Z&]`! ̣ X~Y_r28ٺ?M=g@:YwL rxnt@X^ӣr>1<._zjW9`\.M:1Y=nhON18g]e??طΏ!b R.Ԝ8GϖQ bԯ'rz_.P:)I;TJ6  ivON*ڧiZ <ћ:X $Jږ)5ĂII(W u <\Pj$W=9%U#9_oq{\P58>8WN8@Vq2qpt9f!6ӷ{rcb6$"TtvOHg[z;!tJvg6VboFN2Mx'.?@b[uBvՈ`Aad;}ؘ+MK90\,Nb3N23I—8x"h)m*(eW"]XWԎN/+hԕol:T˰tH۵]*w>Jڹ͆ꏃO9y|tʎ)ZY%xq 8A2:a5`XL?9-վunuE.OTK7:$̵_Vyaz=ɗ8%(a7IW2@[Bb&~D ^[sPLDŀ2T~?5d5R&MǦ6nWZ9)3<!l%0r?S?)n0*O;:nWYYU,+]ZGɃ׋<l=6 0ۊ>3=j6^1ާ'el4MNݓYiqT.O0Xc9LϔqcvPhU`yNqdQW A2q/zr)QrPKQ^2z ꢬOg-O,a0tT ף}:iJcH$QԆ ?K?4z`+ #Afd0\~.O}w~ ǿn[[8 NC!El}M%-'jdU7\,G.yejuN nl.i(;VmWc07se^tPcFd d='|UG=/ԝ5.->y7uHHΕ=-S*k;*QAxPH{ra$`C7}Co҉gZ.s_fU6(V_0";{RS&&xwGZWAxCr!L J6[LSR)l}j&2Icd32&2BBMu2=_MdT-3YOݔAT٧թNR6WѶF[1lX|nyϘ+h# i⩐ESJP-! RsXZPFIx/fw64LϜ] ?z IDATgTNWaC'N@ftry^Ok ,t B88%k8cvFU;l70@O/Gt~GH(-n,΁Qg u4CWZN^ )Gx2sK`~LV-$:I@E UHnE؛LIO w[Kcc399MϿv?+ZٌK9T )7)98#$s>%$Z'|iJGhbY6juHW{r*{1v<#!(mk6?>EmIg$PK7:zدF r Ew@H1 x7S {}͍{g;E*ǧ5  & cE/sjrzGy3j:]#.ʊyYOyI*aH=GRP@mCz 1R~R6<?T!۟0GtIROݓaAܾ/LV8LuC5SLE&u[H~p T 4TQA7=9; Q `0\NMϔ?͏>-Wl+}kbWǝsEߗN=- h9K s(ZgV@ߗ+z`hM}u1̒NJV8^.'[έ-Wte:EknQzrNeN9cEkbEJ{hWhA+nhM.+.{+aES8%QF[yUB{;!0m~/6L'1Rw6=9%53l%p`vq~}\n<åVg2>=9`nz|múUمOm;Cݲ?e*&) B OR vy)f2 W Y=9EfgkM<8Vr W<?y_>s/{w%+:;`Ĉ dEH%ȪyON  W4<'x߻~iʖ K D잜<}'gSÂo={ޝpn\ӟ.8o:aSA =+/klE` wȣϬ,x7ȏ:)S!g5O+Y nWy؍#1\?={ml`䈭` }3yjp O׫~%˒"wjNu8|+0\vJ~g=T`jڽYBĶnlwB0v G=4^n"jx&jMۊ`+9+ w>r[ԟ~d0llpWG_)!4-}FWB';s#K^6vS)eЗX3M =9.O~w~sǟ x@1%Aз{r [Zqv&ti23gP L'qĶ1 F r WϾ ǿn 2Ɛ9-JasVg"nѰX&8{W9#NayJY=9dKxH0r KIP>I+L2{<pH`Aa?ܡ_|!duqn@i~BȊ;ċ2/6K|{r #1lZ.oVUn]ٚ?vs3/:Bq,[QrF y2?ڐUf9U̐:=6r;zݪZ97=c7cؔؿppg, 2Kw^y[1lB-1gihcTyLV_HY*jV k r _;sG>r7dO \nj*M΢O+1lf{l4"m]wgT +q ʪئJj#uLdeKC18g]Vr 秞8s#OSMAr?m?!7l6,{ճ4 "J ?{8HWrHZϻ*ot(V3BD'ԥyTPzR@@;L@lRU.U66#t/l%ǰBW#{r'o,1l.}w_ޯ-ԙY]"?m[J-% aa[gbVOʪ{U\x̬^ Sm̑rTYO d-V;haaU _=}8tk TGZțhmu5W`XG39gԱgxivR&thC&MZ^n?Cw#*䐀ѭ%OyG Mm0oƶF r #>ܡvx98Xr1P'sc_IZ..V.26s{r7=9 k2"Xc)/ęoCgN4Oz'eaAY;ŋ F:,kAI[CIi- 4 {ru,  r #WN}=ǗE.eəh46 ^EKS-buyrgvjl-!'"lŅe:=VO30',1 oԇyMڽl_[ULۯ O9Wj 坢pvOK z6Cjt}Be{/=ǖm/@۠6,.=륧c뎗ݙcΙ %=1L{rzva"LVݓC{E/W.V%<tߜ/IdPDQzN7S+ɹi4O3!]R O/g-j 7XrIq6^u '8`Q k ';~t♇}*G.tܭ-7=9mWL:gas[;U&'D]Ú`vq~?}{ǻmco-]{]{Soѭpw/ŝqi 邔#IZT:zPTPs0u_MDis?tZqPAM"xK>;F~=ʜ-i`x9&]Aqr w޴t?9pZx(xXQ(M*C9's+Jt\ؙ #ْgzNLW圜gT\UpNs7|#_rpD *G":#Xn]"> 9%ΠU9@9FDI7[@o$œ"_ f5HIǞϒT7mOf W99 q2\GPpP3'~lsZۀl|28KQ(ޙP2:Q, ,Fr")9;sX &BA S 4h<*H$4a9G3@p>.'H/$a.-mSyFX[6M+n89&g_=|棃D9%h,T׆r>pݝ c%;+X Ge sܰL+(!lh/ƜmŻ6i9 i圜 ) s|?%G2aD#H&-NK6 <ye)TPdDrSᲕʭ᭞QTa$6 ++҆Y^gQXU]DqrSglsqG!"Nrd~U? HL(iڸLV z~P2׭֖eO@Cc 2圜Fqrx_stu"~PSq}m($C*^'%,*_&9Wċw0)CUf2993 Nn89|g{68+t襆SPp06n,x2"<.s}pmxgU\|4hUpQǭ1?o<: P:"iz##K5iEJ%? dfڑ +H995:}qy];V~NɩO_W(&g7ā,4W*GEZv>'s#pA(-l:^֍bCw(þ)(\1qǁ'q$"щxG:|/SjxgLraU+ےѡV:;ZdYŸsfz'GxoV2\Ͽ N٘AgUQwmt*UVhYN %;xTAAb'ScBV83JPno[/< dVMjyppǺBy];F|`UlMQV)o.98Y;.h@hq@>\aLDAYt=1Ah~HoRKZK9uwg&=Wp7.=OexꉈT t&ije\nz+]}+@VuMcrf) 193[GEܐ 4Ew_MqHZ9X m[9ݐ>p]CyGϜ:,=+7zR$ӁĶ8|,yj4:?\OzaMAG 5%?~C~5vph;ejarfzg?/sp0zHބHiHf(C!cehdPΌf F=&86tTCAOa)ӂ93e"4h$tQ=/GN 'RS֦~M }$gGL*G7cc77W%4EtdDDEDjӟ@D 9+繌2´12, P.ݜJ=S]g=e4`B ! yY&3㑗2,KY\WGPpPU;}|}`lsq@TQV1=NRA}tXЉR[]^ z ׏8H7lZzqi=3H1'K]'fvZj7c9t΂ ɹstW=_9ܭ^9;5q_-X4Ν 9N?DAd 3NMц%DE|1\[29|J9 _rt,*3ꡝdzS)5l%m$֮. s193=}޽wV%hIhҏϫ?ӣN?RI!E:m1"PLt޸ H6QPj1xRD"B6C9r7>KR#}f<2UR5{sr.,W] LLoʱo]$M3$]Ot~$[!b}ykgZmP{PKQe^G-GϜ:btPAEoWI 7q,иKF@g^`]``yiOG [ І: J> Ǿtзlndr.'De c0Wy zk4. C#?NòEYmIxQL3e7xDlK66QPj1vN [o Ik[8!&88j ea𑣇IB#$?rd bSya.Qe ^uɦ)),4e;cy9: NX2b=Ԕ˒6vMk~Ouݘ.GUt $8K\EZL:!~H:bh$Lpe%O9I7>I}F# V-< Ɛhx΃ǍϒT79HLyMg^z.89:1%*u6$$[Jƀ(Ɛ%vFq΄Љbd`1S grUAOu^'jh7h doH8f)G& Ύ2`ƪ+_PyH} ?X&TfC;aɈ >>RSVW/Gk ,KH۵?4]->|]',IrsiiGl 0=H"!눡2QՖd? C&l:o\xG$Q|2 zxcHZc4 doH8f)G&HMXR?r( D/tj46,%*⣌rNNAѱ&|8VcPQ%#3HMY]a+,i#oдvuAWPN$͵_Iy"ꇔ#FRGQV[4Ntq D?hDAő' yY&3㑗2,KSE'S@"DE@F5y``y+X.}7.ޙP2:Q, ,Fr"r隑rNNAOah4hxȚ+JQeH0-Di)$8I$*A%6gQ')طp .)sr1 0%8-^,ЈȎ =0\5nI[esrgjPN=~B<fJ}t`eIњ'G/5=tNNAAaiq 1Hb >s}pmxg0֜rNNDqrVə>27:cNA/QJ#Nrd~KR([S23HA ;S₂ՋkoObN0וeO 0Woƨd:qNּSG}sNe\?ǽ+^R_Z~I8\%48E@|N=y399 jf+(H6JjPF(rs3Qֆ+8¸JZ7o`%$0 G(^ɂ?} 8%::8Nh΅'T2`O$>#Q7c9t+(NN`:3$KEa=:Ad(dsd)3Iir0Dj’9ӣ$2| ʨ>Yjvy V^<;o)1Ec T2fwtV8YBLYu{sj|e,Irsi-g22Kp Ȑ/VDRe%O "opX7<"z6ap.j Ɛhx΃ǍϒT79HLyMg^99u(N 7"YGnNҼNMkAd hj Ybj^GG/):tXX{_@A!d]qh78ʎ1as&'|] :\0Bč0*qL:cL26N>m 94=l)aW2a̹jfYӷH(W9'gՠ89z!ޱH%FfΝOr)M7M' #\+\5"<'1ozG )`6plC>F5Go0' ~Vd~iT.L;@?BjAA5 8~P\Wn[/<;\e"~nOYX99"W]Cqr:/'E(9] R- /#q~Kh7q.Eiip] ׉nDT)Z= G㸪ǵsr jjcR'gshùGG6("w EzsKCI-ϴ_G ɂRN9:JG31X1}N7[r z7rs1JƾeBĶ8cfPKgStdo0oL;K )'w 圜‰l'2ufBE8Ѩ@@ua c/(\EPG"|cXf_903jR5Ȑ$J~AAoSsgDhLјI6 <{_>(NV99"r2ô+ὔsr Pbj|~A91[!u6$$[Jƀ=+֠6DڅEAYk?C'eU\ BU-9;gR2&lpePyE4!c-_I$Pk/Y]ʆ1mb3"2*]Aqr:rN81[W}^Ee@q a̹j&2Qe->s_ؐԞR'S@_o:^Loс.S {r:LpRC[)(0dD[@3[[=朔sr .$BLLosA pD;40ᐏ:xLg>Nu#-Ì"e0%3ӎd?OnP ?qj`b7S̜ 7⺲uz)ؑ-31s{2@')r./' zppEsF9>"f}c}/.Eiip] ׉nDT)Z_Z704޿=㪒זPV3P͐9) OWe$9''^KjPF(rs3Qֆ+8¸JZ7o`%$0 G(^UːN-9Y dN g{y'e4L*F0؎'fvZj7c9tGEʁ@Ɇs3#zrU> d֏sk9,ːڹK#]8+G":5IGQư/p4VcPQ%#3HMY]a+,i#oдvLu Y9漗5rΒpQBҤ<@`zT CCJC#)d(-~HG'QLt޸ H-8'Ջ=ۮ{M"rR yY&3㑗2,K/U]BqrV#9:upuvvj_ `%c@{WcT#ݸs{gBYBtD 2ɉv V/>;?7o]{IS490&$JRA&x6iZIq0IlTfJmj9+OR6oS9gx%=9G5̊h9Qe"IӚ48t?m3݊Λ2҉3D1zqvѧ6 o;9?w'~Ɔ]S?4{7l)^^8{Lsa~g~m|u]UӇFv6}Ԃo 67<0x`_}r;_}skƞ{۳?>vȥ#nxcG^t7=yvȾtp /l׆CW=s5# C=ƫn۳yɦ́/E~jsN]uɦ5m.Yh6{rKo l?pɅ3Nyju]|sŅW?~k7mضalhݵO{tt`hX3v߉~coZ8?r}knٸӳ'6 g_9//Gp56l^3xvܴk7vjaсmC2gbg^7yk?ɿ{}r̭R싈$#[sX=mHȞ.2rF)Q|dKXQiq3Al'MO(y`|;O"bg!ONI}9'Gs;ILU/ bps28k^,%f'Du^DFZNAG7"Ο8%2NQuGD"ӕ!7*?XӺI;%K~`;&⛤_Cn_dkiO/N!"9i -cْ{?Sʚ]%ͦwE<=lHk=E46+~خ܄ uJxv~ dhYJԶ 05>fr~zCQ IDAT&Z*t,f?"]P}*š'Jϊ\EF^\*qrv0Gb&CDWm3N娖-$N09#Zo7L mW/ztϑfn#GBT :r: 6J?"2Za=/hsqQ ~,W+Krs/?:5>}`W^O~]O.U*7V;2ɏz#wڪL&q}38UQ]փƂ]WW+{r'Sj]e첛4cLTK ^>'K'X~WbC_cZ.^ڵP&|˙A=x֓srbޫvd?龜z7%w~Go{^7_E=:j61~B}|hDzVy]"Oծ0cc\׎ L}7K(N 193=K0g89+D  <"Z#hiGl 0=1g+FLĐ2%:/, sςȓz 獾H3r"SϽsNY?K׉{6%Mɷ5Bl+IdA^m4;ywbNxFbj|bnlgƷ\сD1xIVB#>WfAsrDD6#(8?(NNDe`')5i$X83&Ԇpzh9&]fRSeD'Ё|}7)cl1TKi x,QMk}wP7҅[ߴ蹈&- T MYTkn;{zǦL\~#>ox/Yo=i9'h0Llf뗗@qr:o@q6cAL ϢS arTKzX .7Q(b43f ,cӶ`z]MN _-p)v8{p_9CոW:OryrwPu'>TB_s{!7ٮr<_T?㝦UQs'aoruw|ⰭOkS[}%_踴#uB^.VHf6 e5U:GڴxMgV(BčL@i/(ٷa z#]Zdh7-b꺂7!K<ۜ>+(g'oxA 5B9\nUDžr΅8: U;2tmz q'^t}Wsy8ث޴u;nzH{i?qv ]_26yeh xwlڱ2U]Ә7C tёgŜ@hK'^P="GC?gh0w'͜жEL 8+c>@'b9,#K?(hX~~pRc%n;ˏ:ޭv('rQc*cgVI%ceXh8w[.=g<ϽkЗ6J}jo!:J^2sD۔\=~+?'9gu,_^(NN830!QRF-Ed=GaP%A| Q*"od-g?*sImm6ڢCi#~VīacCIYIAdZc*snuc~ն?w|Ջ?{~ }A[h~uJ >L{>HP@n̵?4]->ut$3g&}ӣsvbD Y-c~[C2m2,<)@~;o$,?#'^{M.rP8w9tkq&{)d~oU~'V{Ͼ߶n`hU$m^@G}_4ɉ:t @(9䎏EDMRj'v1=j1䉲={P i_s`MR5.28rNNM9' q]m N'?<ˮ~ۺD#4å{rN`ioWu 99`T t el|L ec1RQfp-h67-99Nd_]6Ͻ-Nh}993e+ 2,]Aqr:MO& 7T2 `RU0>ȑT-^adf4r]Bu]D%xkmN7ZP)}S>Zux\ _sr^z0985>qbDϟbܾ}[ Y.̾v.}g[9xam֦XYvV_Ʋ(N 6:6ԐrA*G>F5O`cv?"c5m\"`'KW&}\̴Ê9OB۬;~vseTVǨ Te8.Q] D753Dt{ B_[ߜY7z"Nd~o=6,pno޿Estҟt=0l:}qy];V~NNxE'Sp0 rRt2 \0)#8ATX勦rNX^v3%K jo‡&-q= P/$zq.dIԉWxڑ4;cb׋?p>[GoGUc]c~Wo }Sh xwlڱ2gdtVy FObL jTTbEg>szYJ>"=,^BJsp"}Pu谠+ԷOh&NTI{KUCѩNl`Q~ǁNkB} }!΂a\yR&߰,qQ+wj?u5_Q+FW]uw<⥑,}'cNgs<1wP6qt._nHAWP29+s24mgF|ɬP<>r#\4̔qrN=ݖؖ8a#-);◑k9@eRFemR&2:[&k4Nܸaܴa;Ԟ;7^-C-fw"bk@ޣԔ=/>2;[qd7ǏYL/V.:aɥd ;&`2r+U"lMfElP]W01&dI:'c|D j=Ds q䔏rV='.jc>=5>qbjϳ犩񉹭kG7e[ kwnfmE ejUm,U]Dqr:kcC ,xcD)^ ~̎l,86^%vtj7ʕL;^O/͚ۈg1WM5juQ5ycdlETV`""qQBoάȉ_z;Ԟ;ʄ5?u9:o"UF$W]dd)Gu(4){^NP&=!S &4e}:yx'H|tx9'tV Q,/] ]seo7C 8qel=I82$+Wx6K6-Ԟ<:0E 5/C߼6>36׵cue drtёgŜ@hK'^P="GC?gh0w'͜жEL 8+cNL&9T;2''5x^ᶳۏjrb-[>2vfUT2Z;|w5]ɬd~÷o76#K3 ;DGɋXku/m *'qs~n<ֵdrr`83a"h`rcM0!gxAZT,^Ӎ!cehdPk)exDj;<3&p`ȷ;K7KGe >~C?Dd@:~,Pg>_7:۶]:-kGu7ݑٹD?}s>pi1`gY{)o{SDNfgL 193=-cqb>I ZΊ1bd tXeڂdY\3e7xD&9C"d7J-:~ƙ,樂1sjXcj|b_x5\?v{2ˬ1hNNAQ{tNʁ Iz,"jR?偄 Gd&D؃VNAwU1@]fRs"9WwR၅OLjdLl\l\7L2YWExNNCܑ{qQb׺+>/M\t{4]\%em\c{dcAP61LmԞB3qB9'axӀΘS2Oۂihch>6'N>"L[::!moV[-ז%`jđ#0/G|/v.}g[9x˶6kS,Zp,;Vo;WpPNӰ 5dG⑏:x&L1;Bsz6"c5m\"`'KW&}\̴ÊB۬;Sa̕ySZbsNFBCsFqtY-]ojfF %{_i'^6Y|Mf`GBHue,{h=Af`tLL8{Bx?Lhjdy SE9Y5@GfKv7t9AބM0[{{^I"$\ȌnN =xǮ89f3+x-|w}CKKecBF}ZYxvl dgۘ,]Aqr:HbN 4%pni(Uk!Ɖ Q4ܻfB^hۢ||t b'&`Y*E@o?/ipY~nC9ǖӌ-V9}at;~f <45~ǂtSw,\?^ܷ } g7쨘ߘhe䈔ZB̄H\f|ˑ5„IJkQzM-uehdPk)exDj;<3&p`ȷ;K7KGe >~C?Dd@:~,OĹ׮~f 0,Qoß? O}kmrNNAtƉ>xs9i-gŘt12JCD2bHd1`f{D(nq gkE6&Fr?8uE8\,9wK6smU Ͻz ]?^K?2k ə8]KPpPNԬ"&)5;\H DY= QmtW<MDdU;Q§}}K&}m2&vvT6.6.Q,YxNNCGq7ѧ^ZGsܖy=:8E1~o>W-[ߖ2qU-{C0Ơf\pN18 2c2D89.-qv!rb5:y|jGr9W*V::F:֏ QNb$ O-+rPoѺjz!f÷O)w$Է6-vc>:5>Qt Ss"}ɳs/T76 RCA^bSon; "P>j\t%BLLƐ3ÿ "e6j'p6)JղD3[F0+.Ce(tj WWPl9wk!qV2AN(kqa({c~]򷯿<:0ʑ5BnfmEKNFV9'gՠ89+đEߜSidžItJ|2ц5{O 懓;kG0,&-)v$rede IDAT{I~rSa̕ySZbwtS-YV88mLj]ojfF ĝxe>1G .4o^ޱn`ҿ^2fe: ~nOY(4)8&GUN7 RHiXMhsr@g$zi~Cלc[M[ܓL'iB> iyxW&,Xu;noF!o me|wlڱ2U-R=9Bz\\$?ga/#8P.JPy )A '@%xREG3qb2Yt8j?to)iFRՏNt2go;t][ScqJ,cZ}Νz+>v~dzZ>~}óO,dK7o|̷Tiey|A)smP29̈\O?[8!&88\p9z 2#@ItAÒ]">[dŽņu.oUTNϴ\f %,27*>8 v~hjC \Wn}[7YJF[ehSĖ>mg[" K(NN'{R9# &}GU,RI!Ih 9FDꖐP?o]n93Ӕ5y9@^c_?8~Y]ڢgAϟ%9wѱw];{As܎ pDd3C5{)ԡ89:1%*R;YEDMRj'v!H2Dǚ3n"_Amj+os{gBYBtD rx0 !Z2=OjdLpZ>i?0#*oxخ-{pzSGD9?֓s7}7KhSKl* aa}gA@[cG˂ndr:cQ0;e*FtxҎʳoOlD9RЕea9g&D eЁ\]B ,o AtLZYQB9\nUDž|5yV`Ⱦ_w\ڳeܥe|]g9؉RmiN8Ft _dž*A>hÚę`~8YyH9UI(W23HA %ΛØ+:FE(鈧Z.p8ThTP] D753Dt{q6 7\yfrA/aj|bcz'tK޺!g9{h澟\`.89W?8@p~ O .8AX勦s499jXeܻzi~Cלc[M[ܓL'I7\7]]/<0

    Xz|, aII7ޟ,?{ڡXciFhĆwlOOO*\óS ~wuÚDrw<~7쨘ߘhǁ'si*.89+g"wӨ(8" d7h!JpM*?*sI]Lyߞr}eZAO\ѭScY-kG|޺ap0V`@nIyD*O[MT%E'Pψ9ʏ@ZOUu f+DZ=AFY@'K7>HOS&eeEb>?L+9wjqsǑ\͂gqɆf xYȎptY!ԿB,NjcQ.$L9"3&Ԇpzh$LN #E,Cop)MR5.28yN6?ov>_CJSs[׎~a8[ߖ2qUD Z O% :klfGqrVjiaPƁGBtTE=B49%V=jKCdxӀΘP}^Ee@YΐCGstԔ4C3/v6ms0Ah[*g}.ՇNDŽ9iz~A'N>^ =(_/fv*B>n9:Ad,#K?(hX~~pRc%n;ˏ:ޭv('p\Ѝ뷾chjoQ;>1Wޯ[KzE圜Fqr:ę Ym%EGUAL 5D}.ɨ+f99\v-E(򷧜Ci#~VīacFߡGzhj吿Z8ipn\/qBD$Rlm t &'%#so]t$ԄaDG -MC=86;\!wĐʍ\af{DT.l:o\s?#=M ǾʽpE8彬sr;mT =w̽pӕxަ߼1ft;T)a1:+çBY")S"XD$&~b A(kг|!<޿a-+)Z0* -ӡ2H.hQ>>k\ʩclԥj\7Lcepg]8'!7][Ǯdqp {Lt99`TpR$rd`'%$4IK,)I) };99޲i;_yoS)xfۼfs|?ҿ"b-ZIP𜜆8ٽt} 圜! D#(TLlZuջ $O% ZP)}`+?ehxbj桑oXSm֦X`XvvМf !Ӏ$ U|(%k#ԙ`~*SA!m\`'KW&}\̴#+HӖ8oc̛j#Pv2·bءEX[b-5ĝ򒍟/zXA9cj|b]{7l{{\23&!D@H4V;{NXǯ_kUkETJUjh)rIḬ=C3~=Z̬~#͘/Ig]s'g "'Z3IquhU $xT8'y:cgY | 7dU| %,7(EK9?Oo9 u gjr'6PhX} ,>/?L7>hE[h8/"&DCYI(?'RW2]2Kd3;%}MQf4o\] JQ?:L" R0N4(M!*eg(طPRةlxA,;N7LȃϞLJ!(WWT gfd>R(o7vg@hoLnZ^Pu_ɲsϔM90L;F` @DN%CYO@@D] f @H(lvHI:~Ev@P&|:nPV))o +r?*Aix,C!x'9#Z|eRp[+ۆ |$v ˥2Z$#뚛S%ho0)i7ڍﺒ }}VFR)@-` Jϣ@E>9DỠ9"If.Sy ''O:TE$ڵv$k e"eTCy-/Lծ+i (w.)JR_eO\$^}&W&ń2?YB!xiJ%D6DVfz'\!+D[xW P$U7pT+@"YW4Q jEU'9+>숈bg9&ߚ7<8@x[6WE+d&?Gj1p>*ET<|P!k(a/_A("]Q|}z m?]@Ӓ!p7wx#&A됟q,:?%ĭ"9o Nv /(z\#)W-eAE8×+eAb_`yy|eP0E(ڊG7~_a^DORWYI(?'RW2120Č̢{U6I57*`VmQ|>99"Hpl"l(J)Ն i|UE!ed"a(?SQ?4!;.QoW#SjXvfRPT~dP Q/D܏ '2ϟ-mƾۦk 4 B>8S[<hDN[u00Y9|Ed]J./k/51$\BMŸyODOconN k٣R Sصj %30Y>P}"pgI9FDN|ҙO̔?EIW J.[!:TQ>I}r Q8 _ۗL 0j(PPۼ\sm`C)Ȇ Q@\MVh oJꜤFXysçS).SV jEU'9K$5/77$ %f;&0dD5Q ȉKsr@~Nr>r9#qVc@q \ϗOtL>9ϲ p.5e(nJXWoP>H$AZOp6Nܢ96 o|yg;j1W5"''VT;E=QDBQFBKY~|NJE%".}аX|^|(_>o|>LQWATU/ksRGbN|ADj*OQ]Y~_6,p g.ytnNO qf4oZQ0,sكe ȉAbeGidCQHt6_mOR,)#;?G)+E&g sfVõ~oR aMۻpCY);/~Ǖ[gcA r"%h> %:yQ_韤vsO2QBFH|[ tcH$H10#ϒU?67v8 @o`oZ^P`ɺ9Am.aZ>4"'BOwnԆditRұ?n? S7#ِ, Ƽ8'V '0I##:S(%=$/S3 b_|I w;˿1&"+D { Yp=1 )x:P㿌P>15/*'()Ⲑ "Jal&]Q#\S(٪]8+i:O}#F@D L|$F0>ԠNɒEȍjڟ?΋ a*˗9)W#iR~P9(}u72̬{>ol!@ۏNn[W2ۆԾ\o$o1>,fY6yTFm>):Q:=*WIR, 3WOvݥ2RCȵ9/d+ D[t/ )N`^1VS܉ j`Lx,t{f7# |7 AŁ\xE3m5F&~OAgU^V>_|"ޝprr%,\Ο)s~2](Q(*,RL*JTFmP,{>h|X⼊_m]g_jxo? n}g>I|W_N2SxfC -&28hB-eP>U:W 3Y('ldUi\(#&jGVfz'$dnADYGCTcQR9nt* (T%.W_CKN*܉ : O}~gIKg g5r/ȉ& =N<v+y#R4_1|yRQFKY #+7SSBEi+x6WYI)'O3ωTtDl#O̿wc<2QS8e畛gdZ`];I@D 1uȲɣ4(R>ݫ W.4#( Bh qN#V'Gqr_>6(ǧdW79O}#&>C<}&=oI o#b4u.ȉ&HW" .!Q+()2TP%Tć(h> ?<B VtMy`c ?UTDe ]#ms//q Lh̿>9`\7iw3 H"Dr4"'BOwnԆdi!tR?GdדTeQFɽ|_*kHrN?(ן QPkJ_·k7eI?Nqe[H!O#k%| (STW~ -r&~~{*Ɵ @kGDrRF9[w ]7c-&1xT8˧`}r8e@|Q M_ND !gێdm;$85ƈfDTFDUHsi(H$ IDl$R_,1euID'c$T;)W"HNc$FDr ڽpQ_hi5$"Y$";#:CD$Q+1i`N,5mo~Scڗ1v" $l}xc"ڧQ4}䦛n:QXX8@DUk"*))Yk(:uO?ݬ#ID _v h"#G9v׵e75*{9=KDʏ[RSSO0 IRkWWq񜜜㕕?쳝}-5kVi_h Ifv+Vě8G o",?(ĺ(ۉ41lOƶaYND!.Q;O^'Gѫz]ZZ3777_EHoH֯_?d2#?ciӦ-A99D:zv K.X,>A$] fpNNVk׮],Bi Z}1f{^EDsbDѐq:ΘkX, |;;YZZ{":ۍ!dBEcsY,Õo!;CD, FTVVV|J "n":fvg >}2]qQHDtQcYyD1FCZ "c!u7CL̜9Szt±f3gVD@1vg:(E!r`#~"h0>|t)k%?dѲ ?n+݊!S\\H HE{ii# r`~AN~ƌߚ>}:@+( yyynCU3F"gؚƬ9GHG"Xdv!%%ÂM44}3{lGJJޖ|Fl +--r"gj^j옵BcX)> r`Ѱ #+[V &Lp~' Fbiii/AHD$YZ(ruͲl "M &EmIOOA8t:Eő!:NH*VZoG"Xldl„ .b.1k֬ZJ J|5k`4zĥ!"1v6%%X4J""-D9q6l۟k?nl0^$|.:C4'jĭȡ333WFYs#DLOIIy[(b7n816Ok?3]ގ_z5jf<|]${1^xq_|͛70L>(ddd\EQ+cH7Vk3-Z8FM^RQdھril,3iҤ&"ccO4>\1EEE_!Dq]\\쎰ID9 nHv} }Nڷ{, "kc(X1jKL&v툰iD9 }뭷VDǭZ6%^8 "v>?? wyg&3о`#k٤%EDCB]ә;}ݥiiiR  r`c׬Y XKDQ4>7&6q f۷6"zAk_.Ο??`0<$}g@kEeegy3*]{{GXPZZzࠝԩSU|dʷl]f͝jL\p*X3iPug 4WWW~$C$G"ZZ>}{e\EnΓw uklQnvͩv"J'u-8q׉A_ۉ,%'v[; ZOӇ)''7YICD LWnKuu= J rԭtQ-&S$GSSS!ڦѲOĜl:itk(&J(T"$l6GQ-UUU SgQ7]5^`zj'}#2ANO<:a~ ӱ N2姢(&t"SRR^wuqԕ!Y!r-D(ŋO: 1JmRA8UZZ\q=&(bꫯNsc'(r$"|K_R\--OOOGD):QDŵE8qĺ,l>HYx}ŊXPVVVm6}hYwaa7IHkv3f=v3335JD%Ejʔ)XXXQr3gοEŅlNg;Hf#ЮȯGތE  r-!EQADq?ў1vtz#+.+l6F:9qd_ ck#EDD}kee"'gXYxLjic7EQIJr"u ǣ6(\zCoadQ?& "GݒB}_|f}HڷXm0''nd #>Ck_LSsDΥə3gvuY(Yf!IA r-iDUVͲZ~IX3 WXQj)(l6?v{Ha &.6QӧO#2uK:CDtW'c,wQ8q%'?"}N8n2euDD/.l 3 獩[7W^패U#f-6_nI)r6,++ q'tL&ӱ3f\7z82:uj"]$"++knh̙'c;ȧW lezgt… Km5kJp`͚5 jQ>Yjt:ڟ_|VX|GKJJV1ΒԦUxʔ) c\g~zo@Hn1n877yJ=Aba[Frn[EEŏc6I\UUժشIOO3p1ַ%{Ebٞҁoj]VVvh>ɀ mGжBEGNN΋ r-EP_tW{TjvgaA+l0--m˗/_K:ݻh4vgv6//coޑ FOn9øni~@Wjv<9v[~#cbiiZ5+++-GZº I'!91AN.XX5''߉Hz3u׿n~YIIcn&)))fptJ(N5np8MkCY~~(&O8p@ Co$vQuX*>bQ7`ҭV{'Q|fZC7L>}p<niN} Cŋ5D@ЌFA8k DE9snRQDA䨰| $HB^^Ob֖dHΛonppRk?԰X,Ξ=~2e̽/X۷BEОM6Z{HL3VuҥK{lٲ-44<[N>]Oħȑ$i5sc":uj[2+**jcm!~饗ͯ ƍwL jݵhѢ_{x "|}z/KKKUw׵ȩ{)n6eʔ(++3Hv(}|w.}I|a]]yEm' "Czjjc݊%9rECuGnn'wk󭫫;h%i---z`o'ſЉ X'c~bÇwke0ٳJ9{tvv.%}'¨8>RVXg"E288sok\f̓EEE%`[sZ;L> ZƘ^<= "":y===NP1vkwڵ#==}OËEQ,ytr͚5455bɒ%{~#;;{}Ynp\HKTl0===&Qӹtl/;;'n["9~ y(暅:3^nrKn*Ӻlii /c =XzꝤ2w:tTk?婪ڶ`-KěV&eJJ| cuCw"r%IRS? ZtixK?aikk[3s̠&ijj͞={˔)SG:|2}sΝ־/Ht; ]_|o.&L"f:dXvjC8+0z<oϞ=[vchai+3w-X*ijjjBT^-IRhLgnnj:wm{uu(477vŝIߚ5k~YPP %Zؾ};DE c,v\444T9sf-t±ncXts8v!EWWW^y%hI<3g֭[(N_^^ 7~I:}U :4%%%b59nsjG|O'X}Q[[AD:::Y/ocl%s8/|xn ,zA$]Λ "fGΔj6X6mDjW_]#`x<ɓ'`0$D>-@X9Kk?B~̝;@AAnI2F-Z"c,XmxDk_"h4())ofulH4.xۈH=ihhxM Jc~;$:th힥# 2ʍgdk'"M7( >ZhN-ZW&L4s_{< @0iҤja|>_;Mnmmmkk֢0a„wޡxꩧ>~1ъf֎yOX{IBg`„ /X{|A\ wNǣ!\۝/.\q9}}}wu@ZZ~?^ ɩ-[={gϟA;1 'jkk$ODdDTHII,-- U\žkHk CgzzZ1fϞh{#GhNb1gΜ$'3g~MMsZ@"Bϧ8d6ohhvϲev"h)))w\z2dҤI?#~Aj"M0S$3_ϛ7Ϸs·}>_cgjjjرcǮh Ϯ]ԩSzc.r\.׬gyfxDS)}auu{3 6̟?͙S^"Bˌ3?ow+Hӏ;v~e˖ٲeɘ 7xcޕ@ $I}a8ߩ󻻻Rd3mEEE/\ppql6?~~/b[1].Wf[[7Io.ֶLEݾD2337W\ X7;릦h:(#G|"&L[\\:("ѣs}[}/EѳfӦM,X1 ?͛+֑QOO_JKKC>Ŭihh0~G~ {ǎJϿ2_FFƖ ~7uEb}{^oȡ옉Zֆ*_|ŭZbϾ}16ҥkA0lܸk 4؉3f:%f"磏>GDz hNӉHp?3k֬CO]?پ} kގd_YYٶ˽o2&""ܹs hHOOOɓh=MMM .9s~HDYQ9s~x?7yGg```˥ȹx⺮.{E[`~p8q8ӧ_WW+,`E1wIcGTW.=yģg͛$ĞQ%"$IDD#I1֋ /u'O CD^%yv 1|w=MMMZb#"{ND/cs``pǿ:887Mbp^{m֎@!ȑ#wVSkٲeo$mT+|(6appБTk? ;l6mwP}Ns&Q9GY[b\ڶmۣ===)NVR1L333 2N5R?seDoN>=f~@vxzzzR "KMM}aѢEG{au\oJON$xDQm7nɓ%"'ş!xzG#zĕ=}i "Μ9fӴvQ79rMg۟={\0ٹs#ݻE1^6ؘ{)QVCCcE(r\.+?;%8g٫!Pͫݴi>ۺt:^~#c "}6Fjtww;`L:uqvv;vxM𥥥9pKd2fSUUeimm;<_ggg~޽okk[GDaҥK#^2aɓ'۷o^===7oŋ'NnÆ Wwww RM-==W^yeKƕQ\.W_m "=O8MKK;z~|o4q(x<Z;ZQ]]]Qi6{ˆW5k6yވ3ٹsgq鱥o18 I)&1D'N=_D/cWv-Ӊ.]bF恁ݾ{wZk2?C~DDޮ zވ<Q={veFՋ[PPmڑxҶQ־|…%.RkGD)S}DQɴŋ~6L{RSSiG=p8޽֎#-mDڗ0}}}UO#Fca;.##9W./~R!"4LokDz{'Nc־7jcu|83nS#F$rvڵnpp:DbٲxjG<3w=ڏ >}+vnv-… ްaø^A:ᘆ^ƹw9սlhhxhH1cƌ]_IDAT1]}XYxԩ%ZIF ̙իW}رwJ%Ur,~]D ڏDN0 "݇VASi$ }Foo6xZ;5Z ,I:A"'V \.W`al6bZZкav60iCٓ1XND!ů]HIIp力)5N^zN$2^DYY߈HÁ}}}Ν~@cZ?v8Θ1kA"gڴigΜi$"_IIɎW_}u֎$:iӦHzV랂W\{?Z^_Drټ… ,c]/kG2pWö5Z5D־@c0:-˖ϟ߼DDڷ1!_ד8DDGH2!z[Wk_.rٴvf6055u/p'3_\ݿv 6mZld٢1jL<08,x7 gF)S/Σ9$e;wNt\x;9\b1'‘oڴiϾ^oNƂq\h0z jjj_ta۟X,ZqYo*Q [nk.^8СC裏yބu@lٲ冾yZ:3zH73 Ctrt-g577̚5F5 N:u_KK7lؐt@Ԧj"Mvtܹ;r֮$^{.'"=[8rH9s @#."$ԩSwnٲeԩSNgٳGcwHD4mڴ}Y\~jjHVNFDav`gMd#0R19(jAɟ !+DLI~zyu] !V}Vi28}}͈hzweyPUuusu4q}Q۲,e0BUU$I$wRWж8O9ɶG&ٶm`OMl(RsLsm.$I$In?DhL|1 CȲ| .˽/!s5mllyŖd˲-[e[ٺ{zzQ}=ьzX3]էN緼a8x`Rm!DJ)́3l;jZ Q!/ˣgz|gY29 QNC&i2̢EJ&ۚ=J®RJIy[]WmaBa](־ y^T}E^n@ݪSQJGGåRTʣgS4Mkي2)#2Ru / /PjPJi@ !83PǬ9( PJbKI0#C) ;xd8?(5xoX_۵e; =)9>x`ؑ}fdf awyuwwvZ]%LK)3R)if`<(QԌV頥=#|}W_;zdittq*eܓd,Yqޅ+V]p>!Ҁ g]t%@)c1FJJ(%E,H[v(#+N VgPǞ@(! (9P Hvjj`R@*H9{R5LÐRJ()R葞G6nXp8?YmM&]]]K⊿.70M'!mc~FysLxU;vS(@AA)(,Fȶ}'2Xy~c¶m GIRyk0uϦsXlŅ7ra?{sD) #J?"9P*TPP!0 PJ)p!@ @*H((|^A? 3f+Jռ&Bz_ DMP,漶j-tu,k:k+ ?} }mhB\+VӜs#AJ !tHD!Dis0o՞6s`,iBA´L8U[֯b¯X,H4/w% ۺi/>GR Zuf|q@PJm™.fVR.wvϹDGלJ  Ym@AI,F!5fm@)( %K A["4B ,)0\"% RrŌ(Hÿ@M:R#FQ#==X'H4\\(?5?~8e)(#s>g$wݟN&_1!b(B݆`!2xPa1JasLce"VPC F(e0QEW h*Ժ<=ksϻ?[OHᙧ+;7T)OWL4Mkn8Ղ;?+aLPJɹaڡp$'Q=k Ԍ^M*~ixA iG HA) G&@B9 a'fUB߀VRqB?_d J4emG&W^y]X웅B% ^0Ru2j7p8 r}xHiF7SH%)KrD<8g}l;| f-!䆛nH{;mYWbqdxeۡV_'Ҧi(5LsozE] z:7uwLƙ,$nyϝFRVU2N鸇>7MoxC ,[_qV1%K\rw.kd2u7E9gMhB1JJ&T*qpp`>/RJ+C PJyf@QH(I) &.Dbtt!Ȓ RYBB / LӴ(3 0E|׻onŌPoϾ~|ō>y^!0L PJRj WUX<5kM*xΔJT$VR*ɕRjq|wfh4`@Y=G)Ԭ`PfP%%Dҽ>~y#';03jjRp.]}7: MVLbX[nX۶y(` 6BJ 498sÇ.84jNՔDyxp`eœM{GY2¨hj!-I BAJ!<{4m()a._[Hݻ{C{lim#( ôA@V˾﹀RnZ9|i{֜x<2L6 Ӗg]㭿tK9碵sN/|څBH(BKW{ŗ^uU9ef\EȶA_дĠR pAA`C~K_Di8rd^CCCCPZΝ;^{Tu*4F 0g]tw}be:d)a1gZGȡOXg˲ ,}ߟ;o[[ƒe箼g?78liP`+}G߶w.gYe_s{>l6P$P 0 )# ((P@"?p7?ܳ9%lKj::˄RR>|S8IRs/\2kes/\~޺x٪ HTP;s\._ް?{wrǔdI)j$w 62ƐJa6!^/N%%%y"W_xv=_<JP$zRJ( ګ!t\Cc0&X <?/0`Uq˕2t:Ӷu󦧯Ͽp<!7 Eb XJd:uu[6Q˄R|91QJi= 5%E\mxgs~Z RLU׾w|,ZJP$(3wwm/ݓ9x:h4~-{ȑņaԖ: UB!"`J)Fa(1RA1i,YBĶ,(%qA DiQP2ITTp @BAAAHu=KD㕝;\Ckk;H^F&9{C g$LƐL%dIKK˜Vj١P$vΚK3/Yq{?5k~&I1J!{gڷo.!8:ڀ4MkΜ9f]8}n̚5j RJ.T p. ոjI` %ePk&!BPbJ@ i  t8ϿcRoaSoyo'Q\AI@(4"ԊD͠@NA ( 1P88dFskD1pPQF@NR< #LKKSkn{d3 jFÑA@R]~D/Y]jZm񘌴uŵc[1ޅA-Ú;Bի¶mDBT"j?KH|߃) qPJ)}82W|Gx>h2(RA*V2 ?fXRN cuL+aT*B OB&Z\F)+[}ex׻n|G>aTd 3Wd&C(B(PތC3" #%C>#H$dj$h[q ǫj᭎2LôXyW_wYsb d+rY?|;iYS6iڜs/X,Ϛ5H$rΜ9iG\=zW_3dkRVPauA Lӄhkk;hj*fA)m6 0r8}͂y_=sVW_>26L+(JTߙ7SrP3F&D"J_6Nh4 q z{{a#x{gלo.[f[xK {hҳ~xX-/=.S  ֟پ}lJ)^T^9:::[]y^6oB KBȿg?[ cHRx|6!dY]]]~PV+/o|%KϽcV;% `cW9U TIw#՞%g:Qg M<\AJi[{^qMÑD{@, w㿼wK/fWM`X>|N΢9RwLH[d.UuO=qN>2inn^f#3J4XVq\6{\7-0˯~{x w8kZڻ I-;#IDRܪ=<Ԛ?t~WҴݦhjjjfButee[v EARd &{_-/9ͅx$d2v5Q'y^ƳS $ G2lHAK J 0lhCF$$R۶jU, ǃNaCb߫[v}k_]lLpX,k10gDAB|OLQb8!v.ժh46T غy$S ř²P4]V*=OL;ͦ&k׮\pS1 Hp> u]B.1 IDATԶL^6("pV6R!!"R`Ww'^ٱINy:dH$Zl۾Diz5N` N2- @]HUA)H'm xŢyA޽Z}H:J-FRnA40ȱ`Q|gCH)f=}>&?J$K)d~zݺuKRs9Λ7oN"RJ\.fw;-M& (׹;x&8ģJex V\yɧ? b)ZݓD?UV)ؿss /Sp\pgٰdcr֬YhooyO<3844;.Ӝu]0`Y7錌`޼yBK&xћ|X`[@LZZZn_fcYȑVKHDp*^޴##%_L E (iXt,u ܃]Wʺ֭O+T*;R cdZ 6!R ܯ][7m?_`ao:쐉d< zG|O' ]4CTݻ.\vuqeuHB!L - !L16P(|СCHRSƙ&j'@)ts B|Wzᇿ6D!mmm˄p8\!g)%ؿnbDb1Q/<D7t+Jm7^s5/O7=!*: !H$c:5vfxrttta)H~KJd2 žG+E)ESSӘズ1q(D D߱`'@!M԰แ )$qgonyOj62Ҧ%j5{dLB , ӰђiG: 9!Y  ^y|*_qw -hm QT@ƬຟtܯC6 T Py>9L 朧 8RaE$IA[qu122&$I !NFS*&cL(EJik眮>ZZZzs ,ԲꛭT24;S_,8ǁ?**aUXlQJ.6]|>ty:::Bn>4Mm?!dP( 2˲ȸ{v\.w+eYsq02ds*2IRI4gAOHqݓP]]]Q B[\m2QJIX$L.$5}BV-P'۶H$B'&m6ae"s82Rj:p1q6۶GF؅. @4@9BW405V*@)d3hJ&Qye&Q B_m[6L7p$H.buf֖k᠙0c6̞((|^c@9zZ{~hFFiht8n@I)ESSCk׮zCj:lK.L&RԮ0RJ4[0BTזJh{X_[IoeY;P9AӨ}=p_۷lSbf[o}@q8Ƙjf?`զi&*J}AНFFFN7 81Ŏmۆip]>O4B!(mmm+q[aK0 P QۘP(]x^Պ ZeA5p;myvaLLtg*JJIWh|TsbI47¶lxU pv(k?XgJn+eC`U0@"i 477#ilv:6yƬ`---KRj4Z{{x<ƣP(wuu9ÈD"Yq !4H8N&ƾ$A^"Ub:AÇMxRj OM&CeyuH:^Uiu7 looo)vaYV=6XJ)眏hP(i j( L篺e=v8|slN…EPr9L wn{a7d&D&2a"tUW&~/kH`0]s!.>_aM-J'kj? Ƕm1]WOOFGGFu֯R-T*=x\"8\=9Wz܄鎧B[{]cR+ 0 +L.riM'z\G,;߿Ddr1o޼Nu.rms80P.Ǒy7-Eo:Ů.JT?kBxGY9/ry yqu7%! (1M!P܇T6(P9"艇gco ZIJP$fFDR'RL(UhͿz_|ͭ2L["*GiZ  Պp8L&;sFN B"Rpٲ,T*xW:xSǵ}?6U0`|>\D 0JjupR 1QVpضf& G[#\nMض0Y-%… oF19<;0<<\x4=wqaYVPxy$DGFFfi`7ƔtX<b J*NMwu"JaT[0 4&5RJqTAPwpO=~ti"2I&X uɂyƸ; `D) Ll\}o\_C1AzBڮLcq$A,"07Rhoou=zyߘԍ50G Blbdjʀz*D\~qi5D"xOLdlo|_>"LusC!) yao,`+@"@\GGG%敥R)bYV}l@PV71dbYY, !Bk3ݕmhjiE[k+0(}s$M\x{vkD.e)͝bukk?}*JnO ,XyK.[ZŃ=ZM5f\ׅ^uigOOO]iY2;MqPJ+qIoHp:ô)7R3zRL)e}>3sWAQ*C0- CB(U@"%(eB _H_@((zlO|5?(ʼn,┓af2 htLfa2h1`c>r?ȣߩVʉ;H̳yAS]=Asd4m<򗿬޺z[BҲmP({{{5PT<0:+g]nRoJ}F#b &*-MMMkt/,tqIu,t}__yuqT*DѺuhB\VVz0Z_ L 39 L\̉cYRJDr__+#&C<1ƒ @Fa@pd2}c2K˲j]N`(iH6CJ\*0A]^~?=p`S=.N9,p fTk'e=H$J2.hPP(̝lV, i===pVUDkTFtP9cTjt֭ ۶meZ <:mۆyǦh&qɱcu^#os%yBfOvStkǹ^\7fLf:t}⪉\bB8$mmm|>9}i2tttܕfXNPk."2̌x})H@ qS}\.)=gr(D@`[Ek2nf@rY߶JB.Aꎗ{eُrw&8dB!ammٿjad ϮE,dLecQgKj>?w4M\fzF(VyJrJ-R^]ՉXcюh If}c‘EHD#"( EH!$b(E{%P\a/ؽoo'Ta*2!Ӳήw};> Qy2:eY- oUJM+N###V6nJ4}r͚5s=) cF:n@2<.UUXri Lvض}dU /艺755%]]2h P(W>|ts@\Ӧ>ϸ}$z,ѕRBR5nT*!Ɍik6CCCC@[[϶,Fo_l PƘmY}wmYpZHB lBss+(eQ`*/c$ ;o׼+~oU($#&zz#j[tdXYVo۶gS)75!dWRJ-mL$rܩ&mLfiXgn5RJjR4鞷kttFb^XR={s)dDG[L&5okk[d%ڝc6Mm#Jx gՎ; veZsi;vcT*5OJAԆJR/q?188x\@ R [fBޙ@(+Cd]7Ȫ,\xeW\}3:ZDSҮ^ c6Κ ) mZ~%LIJkBHy;EAEFyv-@'c BWS$ Nqґd_k]6J>VH&aHudYeqIS̈́dn,JL\ ]>dFz{{'ձ ``&tLH$v)^qN$R#^)L !sžf@bX5;˶B=mJNI)E9 >o7po} lٲD 4q[#L@#~}wgb+۷D&P8rLJ~ӗ^wˇm a8ػDy t~N0IG]}~Bc' qΑdi1d@VwrǴbhHGTڲHgg筮NIcǎ=_,'(T8(͒ N-??88iBZ BBY(&w1ڵkߌgjA=)H$4MsaWL=5RX, L; hѢ+ UV i%S)z_/\{í{(CCVL !7.P"wt_޸G{8S{bi2c}tB(K,P0M8!bZYH 1fRʭbq.`' TP(WM]jj-&m1*-ydȑ#SVy|&o5ue6bOP4j yBs:Ea֭2r\*kD\X,Ňx @L[2|,˪8޴iӦG;|>zZ IDAT@Mͭm7ĐHc(L˘f|vF!]—Jq;1B^zu7w/'2 N) B )9Q- jlk$j=LsDHӋXHlx3FL.i*fè lhTOL&kAƉV690mŷK)[O{b!NU.D"u]L^سgJeK$#GtOR !j U8mۣ\ng:>董0I(3o\r  ";yQ(kdhMRH&O?_zf7`dby׼~8*` Czo=k}ιV@D"rB 4(A%YesyF'͚/dl/Ȗ,EqQ 97 Օo<̏[IPUuOݺ u\P"9Ob:Rk79a D"mje1sҥ!䚦i?!j[[~СgϞ=43J&0ΓL4M9<<e K &̦&躎O[ht R(Ǔ` CRP8&l.JQDOcL?ˆF(8*j\(-A 1ml^MRp~(pȎc"G(H_-|rW*466>|xZlvx``sN: jo7ڶd2ާǩOb-,JLLL'_̳$JrqBȪU>fo SeaY\|KZ홬:ImYB˲t>8ߌTz?;wgg͚1JͲm;3cRJ}.RBB;O<#Gl{f͚uBG@QW(B>\@J)^}\xȲe>ik:@fMp={={葿ؿ`+Sdj w5\v$*@r3pho@K74 5ô#H!B06!;v]}3\6Xd1ʤ]!־BW!U V˟=^FLc  1<'ƚճ>WSa^ H$jb7ܕ!YU 4S1sSJR렔*8~j:s窪圻ssQK)p]z)Fiɍ7~P(<^8z)_U}۷oT.aD"X-znɋ RJWJ))BpmvSSZ!a$$xMScJ]Wim.ڶ]|W^B>>> ms*JRe J)4Mga%2m`Ԭy3zDkUy|ʥOod.LTUz}?ˆtr`\Z0RRt1,:=VTpp!|w+H$S /Y}|{shk`$`Z)z\v쵭/9~ $E S;6?7dl_iZ@xv₷I (TU0< E{-7uQ._k BmjjZ8N,,pN{mZNkyhhK{?x"$J`E$bS~/~Gz`r͂+}3ؒ"%u4(A2ip+`L-\.+ t;4FJjuYخ~3dӰNG=3/BD"!DB(U۶ǧvA)kq?3)a*<_@ ZÌ`(J.72NTUn['3=(4ГKRjx6MHd/K!t)x1?] ,C!D#"(!k9sd2а@\q,$˗@~ѣS/擿oYjAr@ /o$Ux*,AUwu A o!D$bZ7o̦M߮V+W@(Ƙ8NVz hJycbZE%(%e>MEQ[|MHRB8z^{;7t74M"cSUu]WPJ`Dbs#sFGGuS"UUc]$Q"mH bŊ'Νb!2E%BJjDZJx0| F H44hD"m뢥Ucwݺ[]F>=9*7n;C?+!B_4(!D犐Rp ٶGiVZm_8nj0|R/Jڲeo}[i&zvTㄐWRGG5iOBi>!ľb2Ʈeý7y߃z$P t-B:p`zTHFibd idA̮K8O?>Ǐ[C;\ZgC[[[;u]6Msmx/g---Kc/U$رК>GP.G.Ů|~g>tG=!L& gϾ9=822DH$ݵk׷H]cBT*lUU׆jέ_+RQ0ư~%$ Rg2!cׅq??5H,W_̦gZuI>!0q$ \ 8J%@d2Bgc-_[l_$zaE-ˢRJVVP(;I7rSRis_Px%h-QrRŝK9w@,ҥKq?uǡ*DQl4M(Rz?E>5666òGN:Yw'r\p0F(ll5|^ [H  +W@0ˣ\t 閗w=-B&J)k#>Ѩ;af4j+E@Jx4]ϳl0MK.Ŋ+sh(V[kfMH(?>֭[D"((Hӥ'{GhGGPFA@泩bFK]dD8LȮ98:aB@̅B0M'B(c$D@Y,3a޺] ym~}!L&GFFH,;$@(྄eT}ȑ×<Lcm awhpp}sm:RvzULH[[[[mQ)F;QUlii;}3ù1l+Tbъ5Xt ʮxXTQ G 1ddzD=465"j#OX*q辶ֶB[5Md=RMڊ9sSfH&p+VvoٳgN(0|$zĉpJ,J:`pS\(JFJyjz:_{Ӑ6sJ%ط{79Lw-06ݎVxRBHB%8z.8TC 5EVS0ZL&4M7]TMcn_R sѪU8}4^z'\E4K˲ܹs|xg[PT?::zQ2iL&sK6U(T29ߩTfAE[k˜a>( GNBe*:B t]Gkkry8Q9=dɵu , F b1R.Dgժ4f/>cRYP.܌ٳg׳'O{T*+C䖖tvvֿeY8v*r\]`j5\-T*.a81_VVS2{ B~ڞ<5iGp7њe8 )yhomǍ7v/Z =0 ]! F! @΁4tT*"׿\.wRa۷o\TS[ZZ-9Rr)˨=4Md db|<7r{ƳD 2)wt@QT覂A͂ &\㽧zWVZWtvu*044rTksXusG"M4|swuu-m;B)E[[뚽`ll.=H$>|ɓ'xORBssstЄRJ?ˍSUUytemT*4BDkVZa.g\7f,H4|u5ۻ'`Wr(J(\KP B$w}^ql}BJQh AX1u#mB, ƘiZ[`mLYDJ1 YE&$sRtuGt1J!EkkۜjՊ:38N:~4M)d϶mbfqddd2U,ຮu8K8RjJ:::8N(c۟-=rz ~?5bdۓlv c3 FDWD~ P]3`U__aN(_34 yl = DZp !Httddx5ݒˍ!5`#t]ZسgƠiqرP ?~?oD"k\E6ŦMPTi^{57/JΏFM4)8@)"AL!W>%ub+vLKUsT@BHp466Hv=IDAT/}Oy^ڲh4RJRfC}Z;vG;>>N|ߟ= kO !tuumߴigΜyɓ' PҶmܼkhhe۶ BTrl6O$XR(3ڥc1Ʀf6e)72k/86:YND#"  ql)+l#;wƋ[¯u^8SHSS88ڵkmǕ]O>ivT*jjj_(bw˲`fJJv?w'.x 97t]H@.} #Ooyi߽e誦_9bX,0滮CȐ(7Zfw9=1y.U^lUUT*P}_L6ziUUav_hFx|pMMMs-ZוJeaRas}!~7,ۆzo:sdh}ض^B(666^>1H)/YTj)N{gϞ}ha8cmOXe)ͫW;!/zpp]`_a"7 aɑu&+dW1Bd3HX$%PEF(M!!h٪Ys\{^ϪVˎs]W;"ᡡ!D"z{2Ti`UD撕knλ?uݺnRmp[޿{-zb!?V*XKJoyTU=U "*!D5l6iLzȑG]}_2ƲBRRJ:|>/t jݜo}|oo^ -sT#zamӾ\)A- < :1\P 0DJK DBPE1@U]i=\}únݰ>jk^h4PE#]!;w)ma9bHC?Y*z!SA"Ha>?tC0"ǡ}{^ٿ-glFG+S@!8gEaB.d,pcal,[yWX,f:;$9w>j*:J3g<+Nn~}HJE  A@M Ssmo>T\c PRޡ7@ Id0'T;X N8|_=RE|DZJSN7MDWQ3P5t=0ESHvꜹrǝДʨ|mۺ%Rᜎ0 hjn3ϽB8e++s_JgZo]Ǘ-hG,I<3UUU;}x``UEF際$P!RM !|=۶@DcLB5I/R&iok@ m۪>=;_嫯 !e0kSo^9X$EUBHzYoe)-;Zfk잳d͍w0.WlꖧvڱB=9efϞluBʘ3ʨzvkG[ 0"( JSh1"IHA`R`̩]3pP,ͩK487205Z !lyOg[j'>TcsI$j'|?YVׯilyxrw%)X ws_D$!A$)Rkv*tZl qsdhfH!< {k !\˷?+kD@Fjz\XuqJ)! eL! PBTJ}{s_hyp))BQ5U#YG F\.10w=*wR{R!`[Zmtd9scSN=_{7wLƻ>ԗ;p)ɮ_~P~{綗U[myB>?ӿO0_of<&@YtI>Pspz@TG%V[b9%p!s)\2H;~Xg)e4]>&)Ȳ  PB_TUYsze[:&+LA(%Q+}f1EQA)}t@xu O8rhȫ[~d֊R:Q7eR͉ I \O ԟܗ9J+ʓ4㉻߽Y=ږ7ٱ-/:yeY]%/D2~Jy)B@f0q)Lt%? 8OI"E.vdJ!*j$P%ϝ=jly]ױc#3;oz*&EUs'ә&F cBÛQHyC;HI r@9w ڠ$ drKrPu=\Ӆu/T SUulLr10䱃;u]2<DZQ~=TUTM-^j?it/?yC>J[~[e]b Z,^F]3R05"ߔAp3Zq`8\ )S]$v%RRblBDh.c QKMFeRJ׶@ՒJF |ν?}2cOȍ) t&Ɨ._}nkMw|hx`cw͛~{Lok^?ݐiu]f*&QANg2́h 1yGp5RB!Eav!Dmdhr\+:4!`$a﫥+pǶ)Gܾ{+.mWҳ}' eәtCu޵l;+rq"71|vhē{!+u2d}IXdu+x3FjJ7d[:$ ,2qJ%jmPBA IP)ւ9}(P%3B9;:_T]ӄR B [^F8]ι(};} PJEK}.;xϮ_jnmo=SO9pnz]vQYG}R} _.SȇtF6a4*L8ݓoN:& -%6]lԜ'p!QRb`blhX8a.CTG{i쾥Qg *8CULV~d7 }ٕs"P|e2j .=3ݏZwÒSTPl͈-ꂥEm=T˽̓}GxǺ;٘ H1x-;LFȧ0Ug,1.#+=d^erU'rM܆Qn" c)|s;=X]:qLGC>BF,`TòpY0Mv䡖(}rf CNYV!ӡ]y?X{9I;l^ېܖb` <3ћfDm8{؏G{\6R.(,bE♏EyMZDD$K9.n;KURw{a~bT,-Aȧ#0$!n C10|:6~߾?ICEZ%{We{6p'9r?29M]8;B%T:=)żmٵ__~1/%-;ZGui#?3X&5' .[T.N.;U*hrb=_ʏ)D,upFށB(B~&7چ"d%dɺ*V 2YW=^u-bdD'S(ұC5bĬ'8#:* ?b/[@MUu蜹]"B2n6Rs>}ݢuĜLe撳<' ^w܋ΙsDH]Pޗ'Ta1p7qr3T&iy&u1/Q܀W\F=U=c;xȧc"s@J?zZ0W(#_!=2Dn剁seڹʬG*E `AՏ ;*|yndk I ?b~fХ1>ж+N 0%"u'uX{#VvN awmoy9~<~X\V$])]pPmotD8fqf6 #:k=CAa3ҳZ$0u5'p8fϐӠ Fv: =?}6S oRn_l[yp6}v1PL ULh{p_XTyALN2*<̕`kU^%W^ +ڒq 1ݏYM00r~o<kJ?A*|ba>z*JIN)ՅjD/?L=mPpUd'#jd!:RyxX.lܷ={xe\|v't&nl)S%c5=ZnsH@F*;p$~ l^pMp3{J3,E{lo~v0fT/\oLTd r".% ޸vzW?k&q Ҳ JԤ ڝ=a鵏iu`Lse>;Xjpcb;r?3mB\'R6ϲ|N'21g}!8+_/D`o[-F, ៣^zK0mOnͿAF!X=t0sڭ'=lu_Q/!/Qp@`6f_~v:[RR>ٽ읝| p^5:߃?1:/lt_wuim$C+O9{$tD-چ< 2^{UJ_2d%hYJ˲f5…mG:Q`O[?fD6+8d6Վ"NhڠfWfl ޒ}޾#k3Y(W( liA;>IxzvK|tٲ}j_'c^U-dO9Ynnbc1̣c*\*Y1H+_ T'.!f^X$AmcR.gvaclcH75ڼ8]RlK|5]9zծNt$#{PXrP[7ni~c6&'GmwNُA-fFl,<7CM _-?3֦Ւ76-,+ ̈@fFat GrcI\57~ٙ]5,سCȧ#ՠ?F{Y|r-;EٮH.s#V={q-!ߵtn~4Ђ澀Dda.F F SBzz(ao/>JC@zp~#]\'.å$I3t#X4p0J2!߾5ؽ)ib3g*|"4XwbF=>#<1pQn ,|P;`/庱AW(zs C'@S*^fD|洽ob&բ~%(*ӻݚpyNi댍E>?}%vN`v\Cȧ/?ąؒ#1̔x5=ƣQ_E\;Ay#wTXH%b5wq)g9eEuUha7;LlJ[xuD"m6QVND0Dv\? J".l];ug*+_!\r),9*-\Sy#S(`Uш>u_R./9Ԯj{Y+(,b{8/qp)1zp X̼烆W7/`_z`f^s_oKw/yRbIy1L-eɆw㠈Oa=eu u}1˺b|!PRd2F ͂٘qB )ڇ`4/&\Mղ=_}m=Ezr d_{}RQ;P>+ئ0DPDC'+/60؀6F-|3'9T糬ӌ(9̙jK̏F{zh/ќ0vկ 77xcĝVM'XF'X6HPGID#e{9$;%HL#vb}PQ :V5 )-9r?C(4tǹ1]ϴ[yf_Gݜ[QbcX{S9 ,ET'G>Rl,~x KI4n/ƙظo7|Γ]T֌(|.meGqٗ* yĬ? ֚)/O>a9D:6*;6^Ler<`TôҚrG/b e$f9K!yC[~g݀Qk2,>@mkewb$ax]<:KWI1s\m%CVgP~ŵfc\@Ž"K^򳪣G&H1nn4Ծ <.NM:ss9;"t}g?G݃ƙC|dsbU#*:|>ݵ1\̙x"|q$'KTntr{m`VI!%8锁DF8-b;P(Vv2-d]vOwmdk wT S5.1X,C. _e S*[qbC%6b |а|fl*'+ ە% 3u ]{خ?l&e{h^NSVLe.Q*9Q*a9l- ^FށBLĞ5%e@'8r+QJe2VO9qC"whw넪؇akrnb-$$#V`400wRɍ'YdnfE0ݯ$A"W`xgqŜ'ᆘQs *- w7܁5mr$RWQsHNvϱ~;֘{ R.oʯ'k*Ex_~>~VMv)Վu$vn(om; q+>t?n6,:e52uHDLIuJs"o*>v+;e֟0yp{2ET*5jXeQ.&.zLxw2द&-aIP Xy4 ,H*I_oM%n>(a 'Ɏ>DÒ]M2fn)&9 UJjI;Vʬ DI[$Q",a'%MDR"4=@vb\'>\>Iۻ3!Owmd8v)23tW]PI"E/[Le~Ye#iNBC3p[\êp3+K*}25_!6lBRڙ|P;8ݱL";Pݏǧ rY0ۖHݚhϰd7Iƥ]F:3ݟ@*]0סjz:aĢ`CnT+fnO^&G!xu3jo N8qb?Rp[rؒoYgo>uoβN|h d))L3?RaHdD{uJ"C#Qp]B$2gU"k:xA-+8RpHnKўTdZwQI*E|RV9q; qWKʷJ7T]SMRuF*=SG+;w't_?=+NŊݛؼmҒ>I8g\z778ٔbv*FZrǫN*6-@&C&}k IDAT YKZ0R~Oz"TYh!J'eȡtnF^8r:!뢝 y|d >}_4Z+w) P),-u%7S=a%2Aev+%1lC #r^Xu:!-)ˉJ]R}D)Qv2d3B0@~yqz} ק̝QQRjWf֞Ce@o7d'Q:B%M+|:~)?c5??&;8̾s_oAInO +S9N@\ C;HjD㤠҉{6`lYfr: y|#/; x}­=rnn_?`go)Щxĕ\w]tZ[`4VV: ~.J5!w,sT\Na T$4bdw3'cR˴κԴPO5q32Qݓ]Z T^\hGLr> 4fY9F9F9~>ߴ6]mHKe|҃xZ|9؛}HI1TAäFu$IVInFIO.]*+!7u>?|*8풶=a"v'FXr>Tߌ:!]q+k޸,-(X,uae 7wEB^'Be, QrAa[z߫L8KI$rw+=m7Xe*$J=~(>r9{%KNHpP_%#W6iW5pJڷ />56n4aĴ}.YuhڠQE4ˏ_mUR25jZëLhmYc'שq;8ߵV}=::pp +{߮2\urԣ$yxr9?LGKuq#8HXL*()t̥bsΚC$IM6o~m uE;9e;%9ء!U,-jp2i)`'!'C {ۊ Oq=ĸ܁Zƭ;@c+IV\RfYr?"1s;/EMxUH̃T䑌ajd/(ta7U,~͎X J]!KJ#WK_W҂4j0DZI$~CedQ|UGZa}}n'T+JBڢ-vBġ(=&<@In‹ax~)b<3T}d}A^CιO/_5*qR0 o]v76oV)9] .8aʭsZh\gfNЌhbq>$e>չ㠤N[9Jf %꾝XV;e!6Xy" YmԱRX>(ۈq$%.Y̾rֳIizΙZ$"k**3=rQH "j-n!6xYram>T~`Ւ<=6O)h߸%߾KgTG'^SuB\a7bpZ"_n=0S.[m H:ֵYks?4*an!n޲Paqi9+՘UCp'|R cε NVDJ+}rVyjȀ۞Jk'=aܜqܨ!\f< 8?9|RQj8&򞬪; ՄsVuJ#LS`=Tͧ[$cze2ߪ89}ӧn[:6)OM4aߖqnlfRԐ]gE͈E0$kc9~e))$*/ݮZP)aGcՁ=kE/~v7*XA9Tq #'Hհ;#Uޅ>>HNH >v])axĸfw$`7© &%mKU#dˇӳL'En%dy#AqUu<1:[\תt29 C&}2;s]pd3ֈ҂BBMڡv7}%\E*eѕ\?_ѧUGm̜k\%RN\s>,R㸤#Q&38 g eD؈-s>h'g4@y$bJXT){X/R3"IX\&]"a]N}`uW9,|9.@0u7*}T֝1w괭.hjXv+`,x]7JU=T|Usݙ,Zugf[ SU/Tg2R$+UϫvK $)͂WuV²øuߪg]틦)[.vmFWf.TJLğ`̙ElȒ܀u_u:7%%SfCÉתc%[o}Ґ[N_HgUB{r&!#ASʨ$hL9nڠ!e<ܽBZƆJQ>i jGQ ]WC: d\E[pSHA}adN:tU)9erU;HJ\}2v@{tXd!`$dӲj1Nj"P,/M9jTʥ=Waaa|*ہW>^siÈEs&r%"Y\&\pݨ]7}F?o}FJR%ˋG()Qo>'cFtS#{JݤdF赉]G`RB]]$c9>byq4.(IyLsN[%UbrNH`̇>{^}N7+ŷ~͟y)2pEZvRT PurܔX|g]|J/jTcGocQ4jon;=~?=:뀀Ds@~O-xXu8ՑîCEiw2]?s&z⑹m:W[ -W9RMr@nt@ex60eLUJ-L(FPJGᘁR#KaMVX|uqr 3AP'( OF1m"6~K /3͈mtF2m9n9T+uuSd1[5;sTyPyW}H{SjyR#oܲFJQ}QuBb袺Wa޶Օj< %Ӳ dr"u?+ jwlIk6ڨN}-2=P-;Vąib7tLmsZhwmsjv%oydiVŽa*m) ݔ ƝΜ~rNU~_ w,j$nKq>߯[&3v"z>hkj$j;b|49v}Z :}M5 [ S! J5&~ 9Qh&糋g>ž߰$͈VYvvEށB27,K<8ρa@\6,{10RF4۳XTy'Z3eV9ɀ~GNeD~;2#Uʃ($jZ͈b b H}ZuԮ8C\JR Gkz5;p'0u:A/ ,۳2YCU Rc#--oRsol;6A(]0A<+TGUE{jg޹BxJ;KPQՑP窼rtm6^e#PF |6#n\ (,; &5P׎GTY0b|/5;p#L[ }kCgNa.Oliz1#U*sV-QIhwb3 иb"',b$\e%,+d!! -0MNEE;xT,T#wQB4U.TYR*9Yzo|fZ9eR[ GDnb)U;?;ySSntF6>T8s8Uj _5J9xZ8_yUFcrV+jX|]SakYs|83R_Z1׋{vN$WSTuݩé 6M/fێxEH#$ 8eU)PuΏ*iXUj#_.P=~aJ)"mP>OSZ(K5NwIR)EU|_*|FBP 8N6TX7ߚp*J֌(%Ӑ.giU&e:s%Z6|UXԹJ/"Ƕ-ڰvM Ϫtt+CUT)\Z&*PţY"w*Wjȅ=T}nKNBj;PȮEas*"|Tx7vB]SЌ(BOi!excĝ:'鐴qsjF%CdW)㹺yh #HƔz@QiUI&5 NPJ* Kʞk5Ԛ2 (ꛈ9u_s¢W/MPITxzFT80߳p!.H崑2}vi}MUճؑg=)} Ʃ"N)-iQڮ2MTn'UrUzD>U ?eyguQ [t,'c VzefDv!کIHh2G#ٶ8m"D!3"w.IDAT KNw(TW7]Ns͈/?Ҧi'e .1m9,3V͠Aq[PKu.w e*7}ZuԆwEvtbZvF9_aWuCd!s7`CQS'$J~70닕[kJb\]aW?RcqRSߝ<=֝|FʛV )+O?kZ@#(7iIҵRxMC^ܨ>)7/#ai܁ړǙ껜V(P}k\U#e }k>mY Uk>pErj*iRWC2NŸιKNܮRؘHT/P6ՐRk7!'Ѳ=vFd/#pUCV7ay]^9y\}!O& M_hFT9ppCvd}< hם|`rD57ӈڈEpבwБk v±k^|ڟ|ҟ1ZS#INr8QU9U DlX䜎cĔ NrLjTsbGuK z!Z_pI?rd$4 >!R)3ݟи,Sv> ܺbR(JMSiG<̈\qmƈ;a'{5\VLJu!#;EW߭ #^W}/Ay|`),֭qk4fw.W B?~?|!*)]2^v {ohN!jYf<yBaXy&(L_(C\H#Wչ0Tě,e|%nUQmièϊvLS;#]g\z7r2)WT9I.w6\: ڒ= YVCs7.PjBqQ:?9,/]?O:4Im[͖liVT n#W'TˆnS5,ܩq=ǭLkC"ީnU[ROYV.x3T[UGnJ08x{$e{J;|Td>,z_ qZ[gHO'hk7]p z6ir.!NpP$q]Od*^:4l;κ_ 9IӪc/f3T!0ΊRib1ݏ_X,T ~2i T\oj QEY|1bVOy 1#P3~:|mӥJ͸܁f6>M$53 &C=Q a;ኍCxZBz,)v?V,ٵ[~ ,YSԑC:o1_ʉ 2wvж>:jR_}-ʝ9PY. Z:ȚF4CAJLTayxr?CY6'ĺX.EჇ/ljKh q9ix`ɵƥ݊5D!Gt;qh/o }xEشט rI lIDໟĈYW=h^2ǩ Z>lMN|^ cס"+/W i-l$N|R~ j%hgtWöhB[XMy|&{t]%j ;I<̓٘kVSݠmf8a;TVp$P `9fCƢdD@Iy5m,"[@`6 ?/* ٫U4M3Cp=" @,l)ݛ`1Z{XP3mS|bAA'>!_`xxX]db#csf'Uxym̜M@ecH'KU\ZG|4}~ߊ2Z[EO"+9e%8Tv $| <ELf ]#K!+BPgfqIhԴrN:$t ՙ ~KQ%*UJU!^Q}.ƳCWu."@! īU4bP8.CQ~ a$P>-N 13q0#2d+,[4b,f- Q3)X$@zp(@6~1P_-,ï#[&c1yOP╄^meL\ {uRYlxݐ1E@|79:Gڃ)8@yOH$a8f EZ68c/{jÈE-==CG$̽s;{N!TP5p].Y W0mļ S1_f|qW#Qq7Og}\w<miyg5K5dcf{PW}oB!2HhU+e|LUzY?c~<<<$P W!36%Pɼyi<:!PѡpgSQf>|z~`\хp['4lży1sH B!/V]jkL{m9k|%a,a# UP1D9'o0?eP  Q'yY9&[yy@!XPo}j1 y/RyS/ 0P~JBBM** 9yDUp"""+AȜ!7!J ][!{ʫ':AhSNO.%B.z(b}աK"8OVg>ּS; !SzN`8Dh1z /Y['z1XN^+EpSv>B(`xy6%oO 3EpGsPц B%u:^8yk%? jHw*t^`$֢BQ9A2H.6-^'1懕t:?5?BEz4WZmI8EbIֱ8cWS_ZmUsj{'& &*vRѹ(W9O~IׇFg~i'teF#(|Zn1=a^cX=9TYl/~$a o1KPϘYUDLT,aWJߚn*OTRUw5|KLTz,CyuP Q Gh}x?h=z^*ūR.L/Bi.Tu.XqPYZf[?w7d"Pc^LosO!*Q*Y|Pu@}[WẄ́Z;Nd6L(h].J{|Wi9EuJksmfouiwmOז}1"D<@[}t4{ ԣuϽ9Aݖ!{3ll#NX}??*Gb%-c!7+d6maU@>A8 Ljy|Gi-ȸZGW',hn̻kc.mytd-3Ҡ%OH4:Qk|<i-u _/w&[ȼ*ԹrZ 0A(uAW\5 HQnF1PËm`E9QyvK ϱ/[JfZ;3e+Dm6Ck5\JvaLm?@Ź&+^YJLYw}KJ12"!:7@cM,#(: K4!d/ #RZ|xÑvtbP@R\!hW*CgdBߛGF CV/и"˚Pع#RM+қBy|5W#`PB]_D|>!J j̭/ɟGx֡cF јK7G5A$![7A$@*$/9Ǽwrd$B9`[f9$(@cE 4'*غ:P #hnt)@451eE`-":2g"(ѼN ͸ż"*Z[HHcR;!:Ih /Gtu/Q^xV|4AMT4;! s,z Gg⪬(I|yDьR^&!45 =x<؝O1,:GV4,R2+=OnM)OCq7Bk#"8.{'WP['{&Rhd0I!TY('f a#yk5%񊊂 (BYG:>7/tMy$yN P1@dDPKu*?cMB(:ϊ 4N& .RHm wV,zj h Py75}2yfF%MJ.zpB(5O>Q3ZA^7!=:Mj+p{ɼʜsB(uݽ sF8ճmw !rK߇Z:O;B]\i@́c6 Bfm~2íI E"Bo_EFyYFDY@2DA:2 !P+ޒpPF!*tm8#1 !P9c:ܵBόB:28ƙ0!P9|jF770 !P9û~p|c^@!˰[ wxmzR_YBR,c!P >&5y_E͇0g>ټW|^8<ҟB(k8" O)^K,l<o-P 4чsPtݎ !dA/֑{5<Y)oW2rlO~0w '24qy~Ap$1 z~ ܏TE{{Eq/;~xn 0]LP8O>x#OE*ټj O07W6+`5o/GtyiY_oj{fw pd}ޫ(ziRhFepD+֘VQP7Dŕjt -:0\8Zuo/JK`tcߊ_9 G<ɼ1 s8]uO$^b$l !9lCb_d>dAqT?tvζѝ.C"}^81}ǐ8]'7OfT3Z~'!(sţܫ7 $eҼeךuA paNw-̽m9yT%͋Z<xbuZ8~sZOշڲ8xo5Hqx5 lODdpa$޶\_I{*pdޚYBթTA |]|`!8p[;xrWEC\C 3ڧA d'pඖ p-`yn=Gf8fZ/Jp,/( H8hx-Ca?w4?"7y_JGacmcG}&ON਽HFJhoh['>Mxkp(HtF_G[X/UvQۿ6%pdLאvY̩?'zBO{L{!p$b VtZ 䂗=Wi8Pa$Ǫg;cCz) (ڳv\$h{iE9LWtZ.t#Mz;/ #1%xթ f7,p\3YИ`2KVBSF׵3Q8X?픯Qҋ <?GӐZhA?H֖YeH9ߡzQIsRѶwḩ3ܵᩖ>8_oUY ^t2NE75mLav6GacӜXsak +gmz%rܒtuH#rd)h,d2}A9H#Qu褼^ _GC"Y\op8sD7>1NtaB?Iu/8d'U5]l }%y,|2pGɢ)uI]JGyћr:G1꿄Sr,p1loX1#+p6:\'6K2y^ 9L}o 5-[|&^}N- p8QKq}ynv8xul; >Kk p:OFߠ==;(4LXiR1 ?hsC/n pq*`ϒpz0#u_Rr>p9NO,S^)8rnatҤSқ (A8 ׹^!מɣ8rݸ̠-W&r\Ga?J8h5(grs$\ӽm6'r\z/"lzNksp̯u Hmx3n<9VI\Hv-{h(PY*'k{@UIMnh2 pn~%,s-ߩ+H9`٩ŤºL=k>8YPiR9Są<0#;h[ddP1l8Œ j+嶌-`a?ζ pG;o =,?-T:U:8J eOχQWKf|*Oᚗq7w pǮ&GkUn}ALbX80?/(:׊OM%h`h)L]8ۗ=QAj{{~i] Xqpx};8 [W 6ƚ?7 yͣ&p5^&t8 FY<*qv8 i^ѷ%Z$8Ǫ347??H;42p?n[g(pceˇo?s#؜C60/w7W ,8I1m_GԊ.0>dp$p}=pyw" >sй}W%8L#5z/ Qõv҉ё†.O}cpv8#u݀_~v^g#r݅=3W ,}8cx9yGϽۄ$mxV`.<<pyj2ׯ^3s?okeoE pu~D9VD5*`RtN_8~j$:)~hTe b;A]$89pGa,tcUCdƜؘn 1LKRxHw8)4o8!oyM,2ڝ#].$<r;pGdV_K2!^{`cw͇ɪ"9ߖ[PTc #85 (p w{n U] [p{Q:BɁտ^:1plp?M&Kp8Lxvw >s!4w=2{8lϏi;FpGOo|x>ޞU{>R)ҡPZ.[32G%)p8<:6-蓴`6*9tD[3eZeIj%ci8Z2XFja]c&fo+UBmo1߽\#u(Qj}['p2pt 'g}DřBF;|[|mƋ7v,tKAI~25* p|\thO8,SXJ p1f)4al3w2f^< ׼yL y>r|gǟxlWġw,"mw8"3O1-0X@k}l[#$*-}ud*ݻT8]?S6еoc؊^PmŔ?8l5'Qs#xHg(pWv>pdߕ8|^0$O̫8GW EW+"MA8&6G >`<pZe]{ C"ܔh'%oxy@^#RQM|Hz'G$>^\/Kv1)_X7 ~j+F$]!/8o 8cEhRVH8z -Sɷ%]^pTzL(pTH"\3*\o b])ݼ^kpT_UFwTaDQkܛJ~/jh}_t^Iýec5{GU؜EzjD멺Mes*]) vpDʎ_8tԓh V? KO}^.p4iwaHыd6iCM w( p1GtlGW{Ϸk{=^=^e!^8 HQy`g7*ٽt%p2/q');i6mX`2e]V)NFpJ{s9pTp7x{0J=妒']y"\?)og^I8+OcdfGR_8tT»G^וox9IZS79x#x,>%u:48b*#Uϧ}ה^XaX0=94>޹'+h];.<:I>,%[X}Q'!p$y͝Lj>x_ Ԣ 'y,SyqG4P_c*7'|US8/x*jhz-R4AB౼/7Eϙw.F7!}wn2*2X!m* p4] 627vNu.OSiDlw{e|^`|h0Dh~" II#TtۡHq ~,'!zf^/ (}?%pLVnr^BZuSエ|:ζe8G9ۿ~$WӖy>~[EB>"/D=~g= ~E G]Yv37L9pt%u\2%z{Sտl bIb1VB]{ tUX{Ep܃N?|ume!%~QCQ'Y[X@Ì.܉dnb)k Vz gxpQKԟa`~^_Vtm 8=oǍGpx5,w!TD-MG_2zLT؇mJBD}ER^B! ptPܴF! CTػD!PcMϞ=B8B$z!PyG/P%ϻ2v#B兎L@(B!TnX$P`!B?xf&erBrq\E! oqBr汁"8B!TNd~!pˁB8ܧƙ;B:Qo߬]G!]r/ pxayB|14 pT:#J54n1 =I E!{= \z-!ܕx6IB%}͇?f< -A UB(X7W8"F#}[+!jxyu'N=pD6`'6B6KoN#iQ;3!Ẓ[8" 2ӛQ@!4w{N~8"Хh-4pV( jј|v_H~TvO\B9lzg3!T^'^8".G3 *hc>Q&~c %߳c$BO)g8rx2Cp܏@‚_X |"7ʠXs{k/F! ~ +ot*IጁIUсBpdቕjܓQAܽGf23?7^'qtΰ.G=zWB(\N!#Gt뿉:ZdGA'b"Lߙ5B%V[T =C"PNWR !j^̋H8Џ'`yڼBm^Q%o#9 p|Rv^Y B{nƪji'MORZ#!^&bgBo 2n~%g GI'W6kz2F !T^vіɘCQI'擽#*͛g8J8Cͣ#p=K!Tuy]JepI8<3#*:]MӼ;8 piNNs2@nڌB(뮗(X|m (e~"GÌw4:B(kl]U$8J@YW ܜiZPW92&ǔ$!/r8)p3Q?:N\aHM[w:!-MPu+~Ϋ:(mDA~(BiړUP kbmٮWT (8PXgx^T'9VxoU[%pt҂P_ûU֝jhP9u̧3o -σgo*PЯc\^QFk'P=w(x`.lr=7pO[aH#TѼy[%JM#m̿(;7ؓtXZe*ĺ4odg԰%qFcޞDT^MZ/:BZ*6P&E =aDF}+q0|y(5=0f``c j)Lybj? OUTS.]wꔃU=7S"eD=Q<~9-^kRYc:*vWoմ[n>@ gnӆoIy]<;fBm^K*۵޵z}%pߥ9c܃K߱usa~D|lͼ!M3zှy/B5{Z 5{(ɯջm яvl>"[^_MTX\7pck2mm֙+揵5BrgqxN5 _9B C izDAP>.s'F~D_б D.J/U>` &!Ar6kor^gYerwFEG\:*v}R#jQ5mXC eX ėNϩ Ov6pufJ!29utAyiy;N2Sq [,@8QW]oVG6 pg "UwĀWؼ^{ w@.7[h< T3= ~(YF`g2YF+O9̇PzJ0|)t+_KQ̞Ho^N[d;+JuߧO#l(p inТ,QgOs%>eNxg΃r@#Ћs&}^o5 ^q'][WEfE=H0*YeԖ8"8&_^Pю]ß$W啼Pߕxn0-+`s-|酽TV{>ݘj-ķʟ5$~w;o}~9ݞqZ?/dG\o@hmKKœ<~*^p3=;ٟ.G Qm^@I_0`qb[&(<+ 4_ݣY,0Ƹ]'^ԖP yo#̍1ƭp%&– Bmv4(ycyWiujn ƸfGa.x*)`-HD(l~7:Ƹn1oo@([lXͨX0y /"2oA/QG.q )]7R["9xԫ ck*zs;-gm_sX& J1udF!T cY 1)[St"G'BcdP,Zz|S%Է+BQ#g{acJV.Ʊ}9Uj-|4e7x(龊>w6<R;k̻4C 4G1ų'kɼv#!Eԣ\d~UX1Χ=rZ^eͽ PLz۹>0֋+̻sLeOPc8x3)m2[B[.uvrk{<Ɓ::@v PAG5_@v!?ͼNt*K :mT藗C5q0_bͼ P+GL݋>SK{TLB D^D'FHgwR.wB_:i]]Ip^mpN4z7T1==@" S ;]y 鋑__6l>ɼy9J$!r (T=)lLR}c7U'!#u0_,TT\EP)a9 ;BFD:Xoɬo|P8|Nݑ0/깝+B()/FED4o"|Y'ќLLEC;2֑F?PB(3^o3m^Y@ ߯ι%j:)TGѩ%/uUlM &(BQ)ByT(JXV`Gy:D;'kɖ'<}+'Pswy=t5 `!P?0DL*KYB]A KPA;]_Wo60oXZsUу͟N{~Nww\uT͞`Ȯ.hkQ]':A^~%є/%tEXtdate:create2015-10-24T07:41:44-04:00_N%tEXtdate:modify2015-10-24T07:41:44-04:00.IENDB`CPU-X-3.2.4/data/logos/NSC.png000066400000000000000000001126171341671471500155620ustar00rootroot00000000000000PNG  IHDR:sBIT|d IDATxwx^I$R^]S^!"v vH{ -$@zf#fɒ-swwf6p?ݙ#3w=(((((((( $;ʌXٻ y=J PU\RwxEQEQ\J$33|{óm'8G h3hd8;".V5EQEQgh8E2m{=Yt7 [V GIQEQeh8wĄl\Lz̤C8jRϚEQEQ< b́҆ )Hڱ kػEQEQwh(8 n+*Vv]83n]EQEQ,m 3+X;rڊlY4 r}((_A] kɸqt3ߡPEQE&ʭ@ؑ3쇐ZJ^鉜S|BQEQe(f`5FU%cVW EQEQ)(Vaq{NiIXr4(((Ďo ߡeE.((3ʭH,@HБ((53ʭc>!P(;\WC((b&ʭ&|mu;{#Q;((&|@SWk`C1Z;((茲9s ɃPL,6ߡPEQECes ߡH,;QEQ s'>%8|AQEQ4& J&Krґz/$B󨯩D]U9ٶ3F X"gF,@D)u%o1PEQE1@(HL0QT*pf\زYWJ~jڹ]((( [WoLYyތߓ~r; 3.]KbaOt/(MChn)/EQEQ es إ;'e(l^88IJly{4Jr҉k  y6EQEQC4QH,Ũ750!F]~Q0F`PޮMQEQMy%`мGк Z4v}<&ݤH?$"ՓREQqH,;O]~S+Iqupf}=QJ7(C]ˤjM/xj&| :lu=եX#QTρsVίgD{Lٺzcv9.j u_<(t&<V.uA´w~?y)gY2У({U|[H z1g7|yܤn 28"/%3I2TOǩ5KK-IgVvq^R(?Mo$rt(S ( ,Geq>v-{-8rKȣG?ًm2RK kؒ}C߽aT2Synk(8s%5}'V/ "Q}+H?_ǸDzFfԛkPP㩺jSQȬ0fv8z+tCS;{|´O; 0ΚFxD L۱9zFWSyy9bs)V/݀i7Ayav sva׷(r,oe֝( " []TRe#{ 8OcI'|>DT"'$rOB,mDo>6~aTy1y1+^(b)u֎;{9T!9<#o>)zSF/XѺK/Y-^g|CD,]oZgafQW?P+7^kB{V~Y7ZvWĥr8oЂM6X:/LR$j@4>?,EB&ʝx#^z<~Bt;ÈZ7{DFUI!QiVSlЮD7{%k?ޭtԏt,EBQ/gD\D9 |#"M Bx7jpWM dk>yFj-( niNAZewq}ߟ,FCQ;7_F25 QzD+@(?X i,`WAFdDR C " `OSe9 xlInQrʶe4Nh<yQc&0~(xsѦZh]?FJiOt/{H>ӺH꿿Ҏ9)-/וZs]C7KK@{Gu}ؾ_gݠ,'I;he]9 [WhcEEQDiمYkE?;U"[NRhZj /atxHOicWdww8=$V[ X;3eؿ|6v.{P*q7 Օ3EQ̉؏"d_;bDZO{I󉷃lNfmX ;{xpš붶 REb?qS֙vIUIg1]ۻ HQulSԣȯcH-muf7a)ZnjwdwtX9O֕kCfhaTbײQu_2 !|cx~b;ҎMt[7xwH4g)kuA硴8 `MCmflUIR"q$SB$oO(5?liaoex;w?]^k/ P2 vdWGnjNlC]uq9EO"Ӏ$׿Yk'hsz=b7ma1غ7P*(ͻP4Xf gX97 PU{bC$"KkgO.SFmd HȬ FQ SGA WqЙ;3OZa`HY_cR8Xٻx8&˕r^k.UnDUI)=bW3P_=j۠>:?\!Yh{T8{nuUesa?0a!xJ pzI(77//|BuNgs{rp:o>ѽ3ev]me)}:.#ɬ=%0M㚝t\W͉_.n lx[0վwActgLgމr o Vc>܎7$߇S.EIA]˞󳍯D[7iי>RGٌ#q@`!Dͯ ΚW}rj m»3NZ٢>R iw8 fޑ0i}^F+F_CkGwzS @{)Ygz\$5D9z;1f"yi!nH8EY_ ׾GIN^<"@?A06A#-ehZ" xOGΰs$֨,Cy9|{m z[LZvA] (E.Yߘ>l_<$G~ v~~\ܔ3F vn>|`djU;%]C(/偪_WLv AMm3:F@iN,DV`/3Cpвω"߼i[2Kč ]&׹V!'6rS@$"(ZЎl7IŲ'Zg>5SglAHM!fL$4M|z"zKNc}4 -6?; >h| ?0DY$aȂoYsjʾƞ/_JNTbg+"'V蛒sC0kq7 M9⬛pa|8DXX focϪ\#qheqqר*C̨Yg\fiL&Jr3PuK^-\L :ǝzC??C,-h7`\;`,3y" x[t\;h=1KkͯK.Qjg۠..mi배uH"ct~EEwSXL<nOGba窯aa ѱO$!l >SMۍ&[nO3Id1WvwWnj3ny|,Z듋y%Z$ĖFf_=)+ ,EUjNɽWͼT"NOJso.Ndw3-76wɷt-+p5K9Ըa[p4k&r"`?l"2e@1f=_akTS| zC$И| 铪tZvZ_.'hpdSIQ]zg7|jJ [U&}fTJ:7t~P#iD𰈾%.Jng75GPz3\{46_m5ae׹{77/xgqvtT!1b_V[aѤ ԡ1"YbsޱOзڿu(̀]#1KD @W1(I4OuQdU  &ʞ]0ݍz槝؆֡d᳃DH7 ZjWe5 y6\Xkhq8; 9O' Z ҒPUR@tS: O~{Fo\ hyEUyh(X&ȼ|ňZȬ0fvU\u_&|J"w0JkizgAV[u=E@}M%. 3><?AT02jʋR4QàM>I_֛$神ŎœZ1Gfi=xыj]D!ǎœ4>MqbRS&~}a67lv'-]4į~ RA(M,d&b)HDb)F-ߘ>8 FL:t{]<2],xL(/R3cZX{ kfgiY}}q ^3Oy⺪2l{vnU種0?)]:ՔfRf({š9|Pl`(`AĆ2ޮT`wiM\GoNվ^=% d 4]DնS8H48fޭ4jhMhFkl\MyNy㦇Y;ZQFvȂK= Dt .hyFX92//=)7A3-E3KKZkns~o\H.4Qf<eH}[DFa<^TLH-mN+.GG/BuȾvƈ7~hFnAyMnO$!$q4\]G>v;cP]v_udWHRӻL.q^Eǟ%n֎ 3k>38f\Qlۙyo4R?/,5RܢMD{~OD]XڻJEo9(G75.Ȭ1v?p;VY:ΣN^\,LDV=6lջǵ%Ej}S^֜OTO 3$ M:nO7\vǶpZv[)S(κ:f̟|奞㴾50=[x|}M%.lYhH"c9l?V/:FXłg;=8(0EDS9NuSQM Xʠ[ET#mLDg=,ӹ)_l_f>y(j?h/IZsW'mZ..Y9bgM9 ۦMU/L#Ѽ"a]'ov/6]6-;/Zx??BYC0JTJ bF..#J+ע]DDv9@(cCgpE̺6Y;{ESq02Zڢo4ސo{w|Z6AK 2 71ߘa~L{Q$vx(KO|V| ^MH4od 7n&5m^vyB.q_ ճ%rxIΕqz[K,6*)]Åto, '_$% rpIb"j p &zVMH&h>ACR?Eϕq\\- |hf&琱$2+x{$֌$=k=.Y2^$W)Y?l[Yb r`P8Ř%ۉѶ^M͹ߴwNKiǘ}]7`',MݖsH9k >Wѹ-{H,8\% g4&\]qVj'߶ϕziQ#=;@@Ǔ jDfvVx9ƝJkUO6OnǥZ %0k+wPR*Wnm{OP-jԇp~>CJrQt7ň(($2y ޮO3 Fm"A |m~DŒ+(+}w. ~ svhnv~6}oۣ75ѹܹm=exDSR$]<=\oq=l2IS1Np\G3֎;d8+x:~ZcctTբbEBf\ 7Ϋճ#,?ʮ_PsLHf5EK=ڦDJ]J%q^wo7oLxgt0kP[RрB3N]V*r*g IDAT1 ;?4PU}f~Ip엷usf\vѸ%qhQڢ eH,jJRm`1Db):oxG& hٍOqN2{7&@"k';i"iRlXf8E{5 ]" _ DMH7_Ѓ\")PQ*qW$@6HO3/גVP3(>{%m~n6D}w֠y#̊R3N˺tX#V} IdV6 1j5lkOpfQÞg9F lw!ZX]z5qwTwa1Xj g?N(D(3=A?EN)Ǥ6h7`8C$!*LS2ngO.d?>>QGlz|ȼ bR&m߱#A @Waݜ4_8fyHٹ2CYd]=FؾU%zgoaDN)_M: y6mCZl|.!Ӹk:Ԛ%e>z@jeG[WPW~!eٝDݿrvSMͣv&M,_V-楜tWLʤ8Lx>L a[7Vd?[Hkx& Sc{.-Ej#9M8B{SkKŭ+uZ!~ʛ'݋7~7ե8Osg|Y]ܽ]ξsa?xv\p" a]( ZDqNp "9!.Q `ZG֯uwm۸ C\l5ex:|ʬp(D25dnH) eq8TchP}sCgW͸6^ {<֋EƩ:ݹMQI͋Ⱥ|D瘾"iB(qX7P$Fw Z#5,xg">ҾJns 1{:_MyJΙ:~'߶8fQ \XId^fOمDf3J%A]btSsd<-8vnDר,4]t?K;ZDje}::v?t)lƻ}wq>g)&Q?L.X9bG?̹fr lj!T*pӴ m"mjtF2δ\ҮؘDLk_?A]C# ܬ+G5.&<cl#z͔ yc$aHŵ9ݖp_Y]dکxpD-T+v嬥+{S*H=Qq_ ly7]h(&.8~,E_\غzP4r0Y{Fj߸F3VW%9: Pݔɜ3^GP(A1DߘސY3voxawW O'Ú6pAɍ-- 3.$D)@@A^˂vo:bHWO{6iLw%I3/y?u!=y0+^sE`7bBbeD6m)α(G @֯cN1~ٿD_\!`Kލ|QMrNy] nD>'7 7 $LSYIBfи2ak=}B4.0UH;AP" A]1_W][" %ċ蘨)%̻aQJt=5G7t,s&T*"ށ/JrM>NMgwdwO^ RZ~vzdov-Cbo!Kn|QÞu9 n,u[^\`-[t-i6p xs]w4[ZUW ]_g拯jpC aaa눺21w /Bhfu%Č X(8 O+De7ol1n4US?`e"IPUI!*2aDTدPm{1_ 4nW]c!sH$7C5gt3pe歱 %KJ)m#q!P^󛾂š9oS< #PWU;d)v D9WO(AԅG6;xn&k5c/Cvy 'S*GI6G U!_GKGP^I00۝uf<0;Ox>ѽ{x ތzPAoHk{V8;qlL8ŋ̤-m|8c15k{W}f6&n_kqT*'n1_diL\zrϏPq/="|2ug7%2{7봶?k{Ch%Sʰ^eQ o]U^jizun1H4^S\SJ'2%Uol* #0~5#;\b*HկJ M) \?xAHl~&5m0|qd6$7Cmo#,u8Bq1Ք3.ZM3R+;U/o0:| ZQՔzX:Ahg._͑th7`.7/e/ A!ED5e]ڒOQ]z yQ[Qˤ;prd]>_F o]Q+3+ع^6άeݛpۋvDܸW)^2[%F'&dzMM,@d}Xْ! YmOP?TnٿY%YZuzZrU[> o|v=`$Ԛ%ԕF"n].T%}U%&L7{5W?H 3Dt^ )gJ%=yks40@Zvqf=$w>]݂Ghv-f;}=@cPx<CSMZ5Uc#%ȈZVSUU"y?C A^[??e{rڹ[c_!ڱB։7{_;Xf}I-_0 n'I@ȗ4~w{]^j+K1XfɸJS}4F OOG"QVJDИg~Zҙ^$au(NS㛜|FyW?iG {eM3L5vw76ٿr.+`v_ 6Nrpy4 (+LRG`l;f--d/hw̦ jv-C$|zH|f jʋ[ίMM&aJqekuuF7z$,TTgиǮxX;{6SSNc,ѝh@E"'EuSmBZ}4+ynIn~gQ;D2T*pf'zh] K-ZX)3o,DV"]V$e@zw+peOuad7g%⧼ k'z*XՍڙxycjʢ< ߎh|OR NN)]kIh$ʝ'y@mE QC=^6Jn[7ƅ|6e4'~tBUժ gbBȾvZIKe6=[$7;cLчbqMRfDb)F]XXfCa:Le_=w*"  vǼ%x}>sFmeɯI.ƅ(l}GK-NDѐ!l_M~Ƶ=Ӕi"ƈwR[3|4dqBdzYd^DnDMqme)7DL^[|6R*gpid4^eF~>\WMe67դ|TIdVl7qM }M4q hnOqvc֖$>Q҆l1-pht :ϲǷ246 [VhSŰ%/3B Sis^ swgoXbMc8 oLtZɓWL^q\gڊ-iwl1 Mק8&MTͶKW1/H/\\Ch`ʹ`?,/,{*a68aDY "zK&;톕u% W6t7,Hh0ny\)иHƐGS*u($k/s:@czVTbpW9Y i{46ڤoџSeq>v,]˞f>Rрëak5nw/I_bY)/ƙ'CpjNntq`<֕!nۃ[gv.#v|_[)T/oc]޸ղusy׼A妜a~3T([xSj[MvMah)+O60~7}=3j&$֨)+Bme)j+K!YA$Aba -d: nۊI[hes>cA ? n>XX,.Cʡ w&qrgڊ$m_3떡ؔ375xn)DbN▕H9ެv"^qkL$m6/7Y#] r vc}M%nۃ#_n&Aɷ--+eK-m0hVqf^q Lhw6(@Ńyl ѿefeQ.lYsڔvwh}(Fʡ eL([N+ǰq@|!ǔag;p "CbQURBU.@t 5*r| I"ѱsCHp Xj|e"35\GhqpmjTf!䦜iuDQ<ѢL̨HxwdՊ+ df((L(w 4Ի2{XR4K9H,R((b\l莠L I9+o ~lϗSEQEQ)}&D@ y?!nb"Ae(ZMH,ë}7c϶99O)>EQEQ O21{TIdVF8&S͜NQEQ(G҄qPLȬ1p V{=a۰v)*Rl;((C(Ӳ ~X;cGT-|ۢ9 JeX9"h{ ݻuUU'NQE^!XZb%< >qn6>?DxgC(V'[汭,FDQ efܱb?@ͮw_}&u(N];A^v]&/@1s@[P܂ya{O}|I=Z"1z<3ß`(6:f]9"(,Qrd2/6j6맱孑U :v WVs8~yg-[9y4Q~u/Ǥ6GCQkvz$2t6AIse"3=Z'H98ec;aGOa؛kS̤\|c>ܮA^M 2Npoaë]BcEy&j|czk=VURa$e8H Dӎa41FA]x_q!G!8p 3EH?M96yIw*^HijgԳGNm˿qH(paqZiQ.yew82hyO}{>c6i۷8a4W9ɧLVc,kGw|oS$9i9 -^ϾvI(-#(w좵6-hj6=a'| [WzGIҶoA׋ڱ#mtsUW]^)/Fa%cZ4eGCQ 6J1Zvz'Rs{8摧?Qjߍ8kkYs֯UEʁu|qֈ~SZT*pӈ/li3j!E@Gk–-ĎέIUqj+J >oY]ߥKY7q %87b˝Qq(:fO" $2h+tw0gpРA^m= gxήZUW࢙]Bh0CO0HLwc cc(Y;yh\]vYreXUA~E#z,N=v(*vb/׮,ŦCPQ7/; H}aadUξr JE(Cpڻ$N?Z ߨ^Zf (GXО($20 y=o//D7Oʁu(/; 'OBBG|>(@Zzw2NӲ hQv P,0a{4FLя[3Rk?; 5"m2n4w%~?)5C;6΄8B(>Jn#7'|«]Vv(κ[gvu%Nm!QC^WcP<6m6mP_SM9 bsvb'wtu[p ] uA-HK '܃c`i [G( f07/2kiؾrpCINn E.vΐV#/rSΰ59gp8d.)D~z Ғ _LVM@(G H?7"GNv򀅭Db j*JPg+Iim=C;X\d" 84y}y)g|D-<䥞Cq _E1fZ<.Rn;CM}u㮁3 I|pi*T>m{O@^O-8Z6Uyt Nn_3i 1}̒u9'z舥='΃ڱ88txd\OG֕cGݧ>& nbDTv "Fx2ڟkq:s)njg|:@x<ZVA 8+f5.Z3K SXZoF7nb%bGFȗax֕cT1iZhޭZ'ndXf33j&=[󱨫*#:gD)-<( رd g=]#$t g߶;,5 pvf ea=7/MAME jʋ EDϣ 7mŅ-+977T5iܹ_t?$<6N>h05oC߽4o%̗f ͣJT.Q?C9^6~z:uU:qſ⧼',UGinVvpi(*88Kc%;+DQΏµ=hRy y{%H:Mx]kM%xӰ&aڇfs'|BMEԅj[hgDUICb!Yj|o}mv-Tv Ĉ?S+u3o6.^-J-\ؼ~>~|u2cz7;7_o:s[] @X>8ՠ(3 yQv}<WwjtXѽ1x:7'҆7M~17J77N[ު*P'P7(@V&~9{>i5 2]\bBE!GInJ `eDT8[4I,ݟ@ƍ#Z.0t;1y] R3Em J%Rw-؆ݟ<~~gJ9d(Z]O "d>c1bFTGzWKT^0MvP3 YQq|w#:9NWc>ܡI$-$2+x/v;|~69LX$>|->Q=1UjP֕ؿb󊍋&/?"|L:._~jW/o#yj>^/|VK,gpŮeM[3"Ж :-t=F?i\#1[$)եprgDH,E'B') -㹏tnD5I.j"{Rs ؿrҎoRH"Èw6 8asČ\Zu"f_=n91?' 8c\S66:mQ ˗:}m"bM>a:k{o I2/9'5` B/)N{'orpC>;N( \ahtuԔAi?id7rYKz`qnzҶo%NЪ74Θxn)\؏rpń0ZC?nF-ޢS*P4@$j|Va;*{0C H{;&jbƒ1DQclѨ^1;EEDAf~e{ngw7sg=sgg?{hڪ0wajve-lPVoD"zηb 5#`F paz\CYn^«4aNzܿS7lق'٠d4mGD`hlVZ8pڿ!}A [q-,\2cS]oAfrU:'ڍz7jpȊ4;k_wn A+aaI~zMsq̔2a>ڏs.Ilׇ_/i)rk:[ڢ {*ze&/T_96gpw! =Ome|Z#y/qqcK l@τA+eݹZxL52#(*quCs32Kc &7HC)&|~'\{qmQkkNP 28x L썵RQ*S lFF)_-''2WIR`dlaQKvãfX0\-\R ³PNmӻ[0{J%Pۊbfl+k䜤h\u>nR@׉"$ݨaĢێkJdƆeH$_j R*b b _9(h,>HeFmGR{=+>|$ 71l\[0)32Fx?{k^g'k[mTfmF2s8;VE n[q寯tOqbׄWXyؼx0j[o[1P*.sEᛡ4$J\gicOg>c [zw:H$N#HΊϩc+/'xv#P{> @+Y$Ǩ7~s@U<;]kPQZg@UءEH0rN4gMvl7㺒m2a>:(u ~nǗ߯]|M#HNs?&> 2Y3kY(&VcCǰ53HK׉~Öq8\_{>yҶw; >DmFh_!Ar8f*1-?d*$Ϸ[buR@Ƿu#n+J Dwx0"h1 0K@AFB%'LRQt>RF/$W࢑vjF}t5[Bq/Uקwך &7r _Y;́{ϢX(J%n|4Gnj\cOȫ]\Fw^ `zT򉼶HxRC9{:'/wѨ,/E#k-<[3X-0Y!h1ͭQݟ&0i8V`ߙTޠJ%lxqiلJ\FY!ۿEUE.Yd?m{xPE8j %(fVylP Օ85>OlE ~J%άGiA6ʋC!_dCwu34\1؊ff3^I8v:"1^g>PBWagM3bn CҦ91Q- xmxtq܏sy%#56R@I^H1jgٍ J0٪JeF5m9ûyQb rqxXfϢNIó6~ P/bTTבSBmcOW^̻¸u=Hxռ XW>nԥR+R7kȫje93?P#hb+YOq.Gɿ4>#.ti|cbi_턁T[ #gO52`׾;͘u ljR|=).?`,Ncݲ'af猑wBb M-HP..H wvO-*3v`q,SY:/?u1N '8WՕ5)<ǖO T@f/WcRڦƱdA]}=:]@k=s //-юѻhb&΁kPTW䚩Z ]zJEmBܮ)%բ䚩D甼'5ZmhO*pxIիFؾ  !l1BcWbILڎEԯd$ Fp;$R[ثjI J:v#Ej=L4O 0 N`nf!4^',}:yJ*=,ݐ ?~XwvZG{" #G~5S2[KK{I*lҌy!3['?wErm*+Aũ@Qwq׏s2z%%HeFl?=4wxU8LkPnQK@j(Gnc^T$ͭѼ(gnnlܲ+㱊BAcqxJ!=I"/Ku.d(v7>1#cUe8Ccl( 2&HeFh8Yx3Ce,psך ͗}yƒڝ>3Wqpm2 q\ckœW2,/ǁ_z_s3p{ƞ B~ #S ^W/c|;#p34շOqBόppEk"[ k l\[`lU`ćgzTp(0CTX9mރlq> 6}?Dm[{{T(TUQ?*x^]k_ݺD慠2⎏g! =F!')6RC9\ N)Ρkõm_d<߾A ۻwJ/*\ec `m046CBb@fH|ȗj9ۏzCQU'j[ $gt Hpk:E_@P2 5 jNó t{*x,6| 8ndjaEΊģ]ƬAj('ׅ8rS|JE5N8M\&З5kWVɺ08o1w>NCvyycͭM>Fva_[0ya\ U+[ŘK{=۲=Ӻis 7cU׋qdjtY?Kfinm bZJ$`REiBwzxtɗuFR3g ɚdO)_C"1@ĉ?X~W.댥id^Ј{)L1q}&3+ZkvE3|2k9!m 7w步6i^dάHdW]VT39:EU%:0gI{V=7ڤ{T*`f猾3U7wa5w W'Zzt '7U/(rog8&J6–5sskZۿE؞uuEq^._LEvwҖxINHy;}3;g޷AMo\Kv:H VȌqv{ IDATuiEMT*$L`ݴ9~H^aثeY q׎htq/g kҢ&qxL-E\p~~6.P*K[OBE෉sV2BOSkX6iƻ_FyʌpfPDJw Z BeY=?ڽ~#/@ٲ bOWHX47ek_(W6[>oގnBRx;-Ø)TmFd-Z9yD_܃;45r| 5 lp@]S 7FncN+[#g1KBS.NO.eֲtUEغ=o8NlrSXػp.U+/fƢQ?d1)2caPݏhR0Uq9̅RQ-j/$>@x@uxH 6>}ǣ 3 W<kY2cQnDb5Wm@qAz-3Ϟ6J3}&=Wģ]o/Օ85ޅLr3+ _k:ޙSkt0x8w8n`U刹+ۢO|Jo€`djG93:$K{:/`RqYTMo6&Vvxz,(UDd׬ gbmuJ!~xnN2S+A \5k2{?=ٸ06+gO-JT#=bXxjC3ټr\sA58~pOn^Gk@"-i,%nwށ021GK[Tf3 H>yEgb儰3iۏUnqY+RRc>qlD IW7fǕw-jҢBvBGi{@/OoũyeE= Q'VFݼ( xCyuA6\-|Ew6_> Cc3\kDB *KD'7F?'zTƄ6agT? E"s@4U# Bcv#emqW!-27ijʌXߣ$/ܜD]rn4,:ͅT7kHדU_$91yta']kg2$$j׸:=si/lֳƄGO{9p#ĄCD;pn{vJlx (K5._Q]ŘU31Z!b׬%k#Fkn们̸{[ׇqI] AHr^{GHȓ-NtzrkSts!1VUQ&ʵM5]U^URAF\vbo)Tf Z;` $=ZQU(ߋ>1=&1:V3xEHF Ҵ%,+FV}>E{BŁfց!_(p//}ѭJeykLu5 GT LHe/\ NԚZUk cpT*T | ?=a 4g EBʵmjڂfSTtY]Q qZd@b %jZkЕ@]껱M ~.a P*8^򧖁S;nZ;9'Ɽ`6[5aE|a}j .^GhtKʃ(/Xɀnu1{Cε@֦!R]HϞĻ1#TWUI쐗}_ M .aBnnM,q񆅣Ңn4c WMAԕ?..ʿ> ^݆] fAuc{fйQ> %"{y0Y_mFK<{堠\"1mDBvC=vLڨb_LY NKI}(ՍϫV I$\ޓ},ԊO ( qFŽ޿4$F(g=&עT0gWfzCS !;1!AQ >}yz+q/0uB#ѢkEuoW^Ӿa t"vXhd #8 d6)l[ʶlv6Ӈ:Wb/U*u҇n2QQR MvvAscE LͅRQMg,+ACBb!H"T BR ݰ]XX X3Eur')zeܮ)>9,pii WCis݋UQr3cŠ0+Eg~Cbj[FaV }1onΙ1}[ck[؊7tj[VkGKjYً4=.@ [f@.E&1鬗cMv{(pWYR&Y '/H cxe³0&wn6v$ݙNju9x,=:wᑁÿ!kE­Ӣɷ|xOqmπ/$Gd3x]7$J2^r# [Es2hXsqeeyTm1xY|MƏWT"}_iЅƒ3{POWYPw&x OT)+WYCVCf=]~dCsVWUAۯ~'3m j]&|Ak|̈9B wB{>wPEČPκ i]il@Ei0ʹ03 0`gA2X6iz4(c=1z^FdzGzt̙ԐbDֱl]ٞcJ&y(KX %HYk`6fKD) #[=G s~3ela!ƺ`7\w0 gʋtM[PsR=.l[O돯ɷ3O^EU%N}(R*c9cƋ$< aMq. 2\FZ;q71JlǔŨ(uͬXhRA~oy%Oʉun|>g8;եCkrǮY+82}$\?& yUe8NՎZb ȯw\c'KZƩyd.8uB)Lf=fИ[Ϸy[`hls߀IcO"ƿۊx!%oŖM>ɜM6\:s`Aܝx|C}fDisAeZx1]&·%9Š.M;9#*J߳Pڝ^hڲ;㱧wΣ8]'}#sZHlrEIqȌ1` !tjuϢ4 =Z Cc3l~IH`? [vCҽ?3c046S-\x_e1:µm_TWk Öx`;GߙPQZ$H </7ſwa-(ˌtiK+(ͬ0˭j[rS<kU]?3қ+3e/32CѝA*X|S|uփ߆ga*/َ-k]-~wlۄŹuH$!EU%cdSk{o- 3)..j]|{ Lqد2ۋ.,k[?}ulmXʻٷ q$8cO~#.Pkf[qAq(w {58;q< ꒟O\|  huF`׌_ ~w_tڢ7iUxlĻǒOYʲb$+`k\>sǭ}b~3Ѽ('Mŕ)Un p5\]'}N @+qb-Z!..h@sw̦ 窂?T϶(b[t[8a̲ʌ:Bw!y>V1LXwϦ'~uc탍7R^Go_sE~&0`jpmArh㤠D-Uj6wd&:!umF,X9=E<.oĢl8,vk tD=Pn<O}HR"'3['RUҦ7QKלjqm;9jK;6$ dN!0$VYB +{DOp;^ &~(-oߨ ]07:f?Gkdժi<ǙG&; 75vt#|-3b׻alaq侮E}nj뮎MN/5?ΐpoONbsh2bC"1-i/x6RG!k+c@"X8zCe-* ~ѰIZ}>\۶LI50vV~ʌmJo'(ਪ(C:P]| L_o/e䚩:k."f=:&fcK  2uR.?*\9k:2??{|68H1십0Ń39]yB$ѝUX3;gL| ͬ4_5d>~wgסOO_֫*8oW0y0\ݺDrS,"-'v~LsNfefL#S(k}@7TYl}eZhLGo'S~U|\'7}枓 C)F~2 WĎarSbZ6.ޘCu DUy)/ BNޫ qP7x?]'\2Od\; >\ebiGk]*J qlś:u4΃Y\YVf}" ,a(Qgdh{Kk轂vs$xuc6``3WTV̦ Vo (/o&|3tjC̔Heʌ0`t*KpxiVAQ]pض9zeiF&=[L%6xI#tnU2 t۸`;qhQHPJ%4)HTG0yˍ@/xG;):[7_L>}vc9P$:W^~QDeY1F- G7jMum+gO f 8vFey -øjV )Nȯv "FS+Y c'c?Q.j})E\ظxɆfpn}gA+Q]U#KNjŽ{h3iǍ #sYqᓝݟ9S[(f7:ުSbR!qj5nyhKI^}>ox~F˂ Tq{FAYUveFєȫ8$HxeY1X Wã{sN{ ^Ɖo!wcQiڑXey ẙww!2CTWU2S1]QZ3fPIwј-"-ʋa .7`Z1/ 6xl}Q 9vl0#jqjt'ǩEg!Hyp #5vğsfl8<4)/2l~!ȀLn'WO)iv.3ŠVrSY^ G=- 䣣+:oW3c%M㝿#̿xz,s3`fGh5x߭&X'{+" &,/ş?U-HBX1z^ƂȔ+8th(YpPKQQRN3K ,\1~IburYa[:),IC _%Ҟ@XZb ^wFa]=8n/?d6~&  ZZa_QZ$[­m_cyH!h<6[agC6w 5Yǿ}Ck~}-w2J󧂳lq*0sFIىQ8hLn]^pӭɷ :wƵVxXVWUʟ_!lӫ;eug[c8%! l>P",9d152Tf5l 3/Nroakk_!i;8/*-VmGD3()ıo'!.lp8I RN1Nxvփ߮}s7t# ^JY#  ;Ds;V5|p9+_}5ua˼FjȊoZ{GiYgOq|[w]721G a濏Ղ<>};I PYYH|s$*++l|km./ǁE#:&B>)sDNR4.MA,хBb#ŀ֣voF23 YLY  ۊ)*s#OcN9`'>D~?kߋu~TWUޝLmud ZP>= Թi Օ83+> 7O2'$J%.l.u9vzu M0UdLF_ M$,z]3ʀACcݽquUr̥E8t<ƭ8R:C/H E)_7մP]aqHu 8L,`f&-:Y@״;}Kw~ /,ݲS^[{Guh8@ *JjlC,V<qtgΙxNr / ҹS}XTugj<4"QYCCF^z BP()㫊Jx> 2# On%QuޣP( B4 ́2*|!qix)n8G+;(7:LQ( BPĀ(?Gp.uH{,*J 6r _ NQY^_EVBP( ? {0owħcͅ[=GYa1oV'ýc$f5\4 IbNBP( (w3~jpEyD&`bOZDey .{E!BP( @Ynn 4|$S( BP8 k 6>pn@?%8p]jP( BP^^5a{AT4\OYa.1 BP(.3ʀ:ν%=`> #{>w{* BP(~.׷/ʙNjP( BP^ 3ʀS~]<I; BP( ByuהLևtt|DDDؾ ({6 BP(W ~e@(4E<_&JKF( BP(@P5õMo=Gw2H mP( BP^] O5khR݃p|(ӡP( B(Pn֞k>"G;#qf,?SP( Bo < JD_ {ְsyN*/ŵmp(LjyP( BP.PEubBҮmJb.w ZGP( B=? GD+qosQ( BPF@Lk7h7]He J^;V"IcS( BP( (`NAzT4Vfl8/87CR( BP((`djGX s)NGHw aQ( BP(,/P3l\|`a#SKPG(-nP( BP( BP( BP( BP( BP(}wfIENDB`CPU-X-3.2.4/data/logos/NexGen.png000066400000000000000000000020751341671471500163170ustar00rootroot00000000000000PNG  IHDRUsBIT|d pHYs+IDATX[VU /YXLEv}!]͊²* D,B „pȇ Z$b5EI5e۳|3CD6k묽:} /#6\^#ЍcAhcLDL>"QS52 LGDBA-% tX#n˯o<^uCa`M;qXgš~0&|oȉc0з=ONhM= /yLD 1:#ٷ+97އvR*/;*h7gͮh,^xp/(W&c=W56':lLx3ElN6U'i/{p=>*蝘ᲛTnn⡻qL?N- EFn%AC43 3-|t=Zix]p[RU5v@x?"_-$"xwiԘLjR]JvPȁ#ACq_\~5ȗb$\*FoBz.sT;B {5j׶=jI5 zphO9!"Qw3~MM5Gю0-ibV!4DYypU[,Ŧ1}VH\%xn$U6g$ cT5z[{^ڙg_&NFg`k U3%žL8Dj ;<~6kԞ1t롆B9|AؙJTne7L:x{e2AHo3tԍ8:`,ٿ9Zs_(o*B[ܐHNH,#z.Φ*~kyJzf㸴\5_ Bg>h5Re18?@HmxySIENDB`CPU-X-3.2.4/data/logos/SiS.png000066400000000000000000001472431341671471500156400ustar00rootroot00000000000000PNG  IHDR sBIT|d IDATxyXUǿ"(...efZZjZ.eZ.fif)(f  ^",rz{sw$̼39s; 0 `0 `0 `0 `0 `0j `0 Ef@NqAVRzv_-#ȣ-:bYxP\@@VR/)ӿ1(?Aѓzr3c=;NT新6O `1қdSaiaۮ7& w;SLY)A#dɐqJ d%+~GJK83Isw;g8X mñ\m룅;:^L e0 CDg$9'eir1w;glM7DWؘ[AVR%37)#}{`o]{MM߃ ʗv~6qSvOW1"M7 sui ?/`0 L9=wSeݎ/aoڹ6SJv%MG_ZK9fuy+^|[m]7"fқ&HPii8Z٢sа9ں65gc`0 5g!#)/vX{&~.?,/]g/kq5+f{INCBn:Wkd,*U+ҙhdę1ȴXҟhtCwE4h {Kk4u ,$pkFpg7['X[f=(. UKBGe%/)D~i! JPXV[9EqHiQ> G?@C.K1)b-ZmBt:1D.lj۱竇&Q[`z89w~- d׍3<^ٳݩӔȴXL;\HƴQvSxU%Ny\|ks+sFN\sJ`%}IgɊsk^M\д~#4upEм~#x8p,,+h{~ iYwiNLô?1dvp,1NMXBT2lJ_'>|LvYg-.Nvl=ƀ Ls8q_[*y'S:Q6oV QSBvQ>Ɓ8y7 i2, Nڿ]y/G7:7ASkޱ2W"DCwN[*}!F9 LTA+.Ģd̂'ReYdC SG^ Ƕ'ˀ z6\ Y 9M]*U|Tʸ5Ƭg R> Ɉ7h?4mӣ-ۅLIjJ`~Ͱ:ܢ/f S։q`0RoիL^bJTq ucNv,:mem1:DO wp\ィrN&EpJ .K֏tZ V/6ahgF7NhK:Kȅ;3N~/K|XD.+k/6i؜6V-FNC;,;y%es *eT,?Hv|smzct^\(#T-2hP4Ke 'zN}20h"?+Q񔵗k{Թk]Nn>V%_ٳD\RY_™}\qk.t#:i2 m\/J%_O|~6 _ȍnӋMF8uִ-܉q1ҷƂ2[gDg0S#sNlֹR)*JUeZurS^_Q*lCY =VM~iagؘb0fcWԖ|fMgn)HC9/U;="ɀ x-R,%߶N[䩛9]slѯ?6|!fZiYu,)Us!czik@^Rpfۈ6դT`lJ~ļ2 cP%e4 Weͼw;gyZ"ҙ󿣕-.tҎd[]$#w=<VX|TA#J Q\4F`QY)*8&ּʸ35` T$'1GzvX޲lQM˱Q/"dGuU52ys`΅חg}C?!'nF%(@ڱTՖݰ@;pf+^֋7fn`0:!" 4wػ -? UY}a`d;x3dZsW(TrRw;g| s7k@!>MGZ~!8fenoG7xػ m\·A8Z٩ƣo6\ .IzIw;gi]]CKVLEQA֙Dp V' >!xzO )i$x"9*EK/G7ܚj^T%;5_J<&x9㓛Z)'pv'GaNܜgڷGbo!>6{yŅj'9)vZ:@{KVN]~xj\vvVwJ ɰD]һR 7r3(*\!wg/Y?:r[?"1Y7nf)#̂\Rsmm(cJ0A2b2qF@M +d4&!)/0l,>`d}Z'V2=1 9L5%~1E)=wlWBs\J1XU~1GtFι7(-c.I@c{g\{GAŒQxTK:KF_G+[\{j^&5%䤓}Mpfe|4 v=fR.DڿHIi,(. ӎޤsZq_ ^5EY:sm&h]~n7Ytz{UHPIߒ߮ԤKnaF)Z978jV a9ׯZ{&3EŒq_ ,Fyɻ37Ye(mxMQw!PMZl,0Ļ3^iA 3cǺjE 5u 'FoK/!3+c*CnhOI H8r=S53p8}uscSaF88jQipf?ޗtlS„v}1v`gȤ8* (,%<*f*KIඏ#Rb~e%8ut  oG7gboO?=kGʈJ[Y |=px̒jX El`VX7hVVb\ ~0r#YVd85Ư/3e#!'ƟS/,z|yz9aJ0CNgi,^Bϛ<-T1lhf 8IdZ,ZΨ9ύ&|ބ7N4σƋB3W~-5^c@SO׊w;J|x%үՊLlcaCE"++ZՒ)0ԯ #$.ж+ôs< a_Y2JcW' {w H R.bK\$r ']釴zzŋ1EgQFڲTbB{, !KVZ9*"×keiT,Z<AqK69BS0vAfA.yXZ28ֳe= %`4?xɶk'x8n)1j5LXv 6VeV'1ocH߫t0LmIVP6t0>3J>8VrtÚhmdsVm2VxEwm'%8U oŒ!=&aՅC׸X;"^>N_÷n= ȳ-lp3\c:u#0hYM;3- C,ZOn&_>:3@<^n\vh4KBrqo8kΞK9N[cc?lmKS:jHUtrkC(]"l˗ #5_J^2yeyÌj$ QkKʥ!X gX2"idp/K ' -/rRWXsq\nՑ;1n9DƆDtF&Kx9;|! ӹ;o)1Wc}uӣJv*Jh` ^n*e6M1"|vzQd REܢژ~zhCmb0&:#s{d'l:=K4܄*j̍ڂIk5َ;9~E(cLɆ&:#qm뗼; Js!xs f֙h vtu|Ym9lF1vj2pBYk|Aܢښ~z6PKIɰ_j{cjPHo6Z0vFh40hj-o=7a5X]௶.ɭs|ܟsvPz52B| ߧY{Am!] י| ڹ20gNoGXZ\ѡa_ J~c+PMFAzÚɜE;oGwN'e"!?'K&u0NkQqo4ߨ2Du\l:q.ߍ!574w] ,)RM"`VF 7un|eɲHZQ*'E|KFmA}217j \/FNK!Z+pEB(,+\V_"<6rP+}QOrG~i];6 C{HD%4 5R*H֙1wGS `LY+ZppnK:wAq٩f6x7Qp??AdDUȴXAmbsMH1c:o`mEg$/΄򖱔^JeMc5If鬛eo#)ZvtN_U}Bx5HI׫r?Zͧl[ IDATs0hSظ|徹Wmq*ϭ9 HƦ#iBR^F`0ԡ2HFƄTBRuǩ1lBdZ,'qf$x:y'H$%%lE#/ۼ(6gWL=,y ~*srIy-ȴX}*ϟJ6Ԗc0(^Nu2^IkE+t.86KW%!C|'bE0I)^FKҝ|ZH[ltQ;x|)n(n=BznI޿([^sqrRQ[0:]${N~$S g7Z/6HF&E|\a͔`06:ߑ)vUBwL=62tO/}Q3dlJ#3sɢuلJ:@CGId{+4spA~cHoRoر[puDVQ>.-Rbޞ~pAzA..K]>6؎lut:d?kU'yLLHrx *LkW^=Ӂ[?"1Y7u%Gg2Œ`h.{dڥ*UJa)ag~[f|` bVKZ~S*k QKљb)9zETޞ~Xh2< C ǃ 3n-ŷEU? bb1" C2kdQJ݇D[2UYJ0&0-9io/2QZDǞv7Co"R.u zP@smeHdZ,.8 3vr2 rɱ+X~. Bk36}.5_JL:w w.-։J&F㛋?)Ejx; CkhuB "oW&C;fIC׌n]5nǑ;j>obA1?㟝NG-V64>LX˫XX; rJ&+! _gD[2 #jgþ AA;uJKޝqxR3 r}_ .1_yS|)s`%WY%!SvźT3Cų{nVŒ]A*`fơTQ([QeTYkR_]yeW~_vfiipQw4{bMOk]0|ڿ\/^`)1j;9] Ʊ-G_F&#DaY;Yr/Mҩ VLhcakl:\sUStC{U*S7s|'E2nTˑ=>x:լCfCWMֿA4INmx1!d.4&)([ [fA.y[CAmx*ڊȴXQ~OR{Ds*Blq뜪#}{HyCC*DzWƫ6NAMxC0O[|=D緮I^? M aװODm9z mI{(LPϡ- Ң-vtzzUzn`A8w;g&c\>JO + h.lC-)=;rBeҪ*IλGU^)2)Yy~VdiM73cw]柌xK:k2qg3׏iKyU smn>po}ޒ B"Q w?\ 9UK @VR"7ur>HE]Wޙ醷Sl{ػH ˰V.pvNPfmlmRvc k3bPRz96B@x ,ʫvh͂%^M*(Z }PnbUUgmZъbgTuQm,fbu{1қ$pG"6Vh:oGw|>z6VG wß畾*rRI)S|A1YkOF<"R.@6d*ϩz ʊ-V,ݚWȕ/d%|(+)\?-?isQ\OET#I6[c9 E)1)u3uGA6\ w1z_KagDV6Bt S 0Ы#6sF/AO E&~ݝ;8j14fM9'7#E&^hd-=AT_ UOF)8E::CT8wW=2Jυ'tn)-W\(8P*k?͵8/,d,ˮp- \B5cRtpE)9NhU֥heفÐ86+n04O+chqZfm" -fߨ M-^2>E}ikÕQ+^D#rv#0/Wq4/̚XXaqh7iQFL֤toOpG,!eP>YԲF'7KˤZʟ/ҎttmҥMGHO/$vN\v>i ڹ\JyNSIjc\AROdudn2&E'7Vظ=KnD,#$ k\^VG83t1L^egwVFf&B2* Y]Qrg mZAX W"3;nm1j[CfŜ\w?!Jq'Uy 9B9KS4Y<]P92$|YE2$f\trkz(E ņTE:3T LrKR͝ !!׆< g~N*ݩɜ8׳G]; >N!x:z g*<(. ڊ-q #6ؐ[G-[⎑)5^0 NWQ,%%/U &2T;3PQmm=BsM_$淼վ?njR <^yȇ?Vչ >N,n#heK]k@V jڨTe\rwA&Q` ,(g(%!'e:UK9&j`ca߆ߞNT_Ȟ DNo'Dg*yS^xy2|WcᬘHrUe"yTV/ AN4e(./7ksKXXU[}m`n&yIyqk,z~roOQJeh|y5|=wsmA\ͺ?LzpgF6h^};C_mAl [d^ԯ}8 ?O]wYE=1bZ8 GrYV*<ôU(ƬP*X|3[/  Ƙu;e\6i]vtF9rqo#!\GUnpҶASn=Ě~.:# ۷oIUnB ,%>-3 FmZNǩ1nnK:^Ue-"9|/ |͇cDPfR2p"vww;gܝCԵ[=\epU,1_y=Sk>W !Mϖs׎Vv!vд VQjʐd0 Ӂb3ԍL2fn9LՇcT*gjm_{9 T&/+8zvqm.ôokQ_}~V+<NĄ?ct2 iRv q5+w\pVk9\H \ g y8 kսr)2-i z68E}IgɊsq5 ==ɑ[1X){db^l=l;8Q琗 8Yځߓ`0~8vrI-':T[J^l=FF qoo.'%Q^wvvR_mJm>t&mbPB;]pxRa"R.F/RbiGGV8Pg0 uPiGnѧ {Uw:%.RTSwا2!' L=JU;8P'L^߮DMaK1s4u⎍ |/aSg}}uT5Z:5ӣ SLoGn#)SUNC}~ >>R]uc;x.>/HFnFJ+֙'#^Pym*BeauFK'wnO DYmk0:7kurk!rRVw~ M+=FN\VJ{w$ÿJϚYas5ǁTVPPUNn- H5_h%,`(TiQ0yQb8Zɘr{2O*cM:?լeg;nC0]~mz(j9˂Ujhtꃇಞ˺X;DR؄4W}%Y\l  m"xػPwK !eD%B6ا u eQ􁶭SH>-?nb~,}IgE+w;- Wn!vѦyLCtFʶ:Y,s _m*Wz\V*|V^)= U+$41 ?w,\?V~U$\Rb:`-,5H]g_Yx|D֩0M/JeuSk7b+58x&W[7wLTW[u'X{KJs7=xUQrBNL2eqdD*~XZMAG9ܿӅxc`0`2Z @v΢bY*&SclFJ%}\N*0:l="Z4ٛtb|QOVD *AO. Rv82DhHo*%ѿ\IY#,Tj 9*UYsqL^]$#Rlz¿`04ApYL%xo^0Xhm b3 rɀ uT\ zd c?",(2%7hmw^+U,^m _̂\b7G7I)ފXFD%j~Q>^ٳwLm=JuS+c_ _IԆp`IS"jF8*fM A Y82`*:Eg$ޡکg}sm*-E2rm$ű+J(\.ښ40dh?Du_הaRj<;{''OmCR^~O5!YGүWKվ)gՈ|f9erU* M)?_YUW5+Kdŏ`fsW|r1U;lEQ}^wIP^!Nf>3Qm vE-WuHgRڎUPi2X[ִ-vO8N<фȷɭ&0whK:K~="852^?k\| ~hm~3a$Nq€YJU rR;Ev N\􇪮xevpsB,KTV, g Y>eRhb]r`CS,9]N$L0y:R NF[E'N 4yfu&lAfs7Ɗѯ?uۓfe֛T~xeKZuw-]g5iڌk=b i+17E2j|R*C^QAeMSP!?G3'sTzAiau^* ^m V w;g4#|{rV#YP- O>OEei2xmkDf|^T/ pNN*qҲ8R3k Ϻ)n~cXFNXAm_R1o˜6%xGxUL] CGv3 r#IA;Mh.};6̐ 61 "Y'~W^Wi]%Zu璧n ԭDT<|;ך] oִ-~Z}ܹsS6 Nok9qY#1k[UF%P™_sB[<|H83Ll?@* ¿O/} j][LN[.:\yz{j}÷MC=`` k ϥ)#9 05ﻯ. z<>th3{i}-ڰ*S6^ͺ%*6PsP qj,#WulL_ &4sUV-xAM:6x v\@ET`mQia .UՉ <-Nn+b)1F1U%4z1ZJ5he /G7kr|. 㠋{+DD$b׏4{s0u&!B{- GJ82EvOBh,~o=B'i voC爚 r 0ԯ UO nLݞ1#4EaU^nх5>2ZX휱};ݝ˝Ώu ӿ[ӶpyøKHetqoccBɼ2*#QO .Myø[Ӷp%pG-KZ\n!ʝq[b1u{+\]>N\̤uKUVCh)ukZL %ݥœ~T.^@-{IrbvS=5)zB3!<\s_ǯXNu]d W^~c\q?Ov H9Ы#ܸޒ [3LJ83o'X~0ynvzE{a188j1WsfO 3iG*C\4ul.L)-MD1o:{~Y).SM^1HjGGT;SwluÄb)1=,Brv֐YC}VoB/-šc]~@VUA7Q}QEgRb|ݦ7jzUL^ FRy,YO,!>j}Æ/A™a~OaLv.6~ , Y3M=y z 9ReɦCoI 4> F3bk,~r&u19?Cox\$ѫi{vs9Do'ֵ/ɩZ sWyn^>>JyWevk*i"0E@eYuDgkԖ.1%B7rаq AVg}rpbϵVd55 UqGx=M+&uL& e},"O hށ:7!hd}7]z9VƵKݖ9i~S @-WR ύn\jLpWGA2B|*!4Hq k>PP /C /}IG6r?36)0K[Pߋj^;I83x8P{FuiXLY_}'8Q3q[gR[u[/ywܨ-"fh2ȳWoիTf7wZm돧 uN,G+lhPix~" s]mC3;ge/[M{Qr ?O\`hɝK"E115,$ZXT *pTzPyfVFóy(C*ET:nSRY,5UtK sy ϐ+мQO:Xsei2RdR.sm٭.j#Ɗ.R]z][&5i\W8/'>㮊T& .։kdčh݋c檈,U(b 9邞 aenA'>vG R˕>b"X?T[uaQyn݂d|{OAA`0L^-TJX( gdLh݀>gBn:UA7##|{RCu T#:9l\L  ε8j|1|ߗzdEʘ¿mg=$hs1* +v^Yj*CfjU`WKqW@ej4wlDU>!'P™heTkۛΡ[ c(q"_Uv/9,lQM)KI'"%X)'8q_ K!'e:U=6|!oJZ& 9@A7h173%ffpxvR@{t zmvrIfQC7uDRU;'tRbxXZ$  WK9:Aq֯Է;?`0L2Փ %uje?2.X<Ro6ex/I|p1 Z7b/ε%rxmxQ<ʒ1gGUC|Ld0GX,TKFꋄL]BrY3B]'I`ȡx8p,˹A۲{==Ld0FVg=1eIXLYs3X%F N'nwmGe>3[FJ>ܠy{/i Ax4~9IÂIf.P/)R_DxAaǃj)}@zu~:G# 85Fe,e#0*xMdsTA,)m-%/Q:.\ӃGT卙.tayF ?McA1&Ѱ),kV:mD_ٳ'd<);޵V1ūXژ[Q)5_(`*/>\;*WeJcɝ[=\P!HzKZ(A 2-VG>0gA|)a82-V8q_CwCornDZI ԎĽBeVM׶ *wf;$DU]6̇ : >5$x zŘմŠvb9\.m2cj&8S-<妱Ӽ+bn .Wesgڌ3wU BTf0C' +)R:&SY= {(+ΕUI5sNlb !ahqΘpoəx@L2y9dD~ټUe^^!/1X;PQF1̲{9qVJhO֢%NT奅y{滣 cl|ML?(=>f'2u.ҩV6Ɖ⦈8MM*DŽ6hPcj:>}!HV+,}j]kF-Ἷ9.<{;Mp>woO?Δ_R* +@kOQ} i^v KVJ!4>V6jߩC5>%t[}\ M wUvu1 uÓ/RӶw必MGjULKQ70 ]St.T>14JŽ*?m kΔEX9#-_XNe7ߘDR^&rI;fFM~7a3}R1 u+XJE iL'ZejkBا_ L9uf¾doOMXo552X{gPU=3E )ZFj[d方_e"B+j" W (*Oܙ;w{;3Ν{33X2CKR\V8K\f|`IהWh'!(!Yd@듍R0`͏LUCbrü!J [%GbJW .6viF45QK Eyq1a0mO8C^"p8h6;Ui18FxOX۵b!(IF*#JCiXZ2 \6u]WkɨxQޔL}z6\k8a.2˘'ϋ`p8\::8sHB., kL1hKXگ _%DY(}x_TbN /˵k[C]l◜ZrB3UyylJ>Sf}srX.0s2Lآp8`uudʣN#ZcWrת(ssrAS"ip?G3eƞU&#k j7j5 EPk V^&5pYڙS"kwG2#3%^HQ~j *]^rv*W5/l??- 298{}.LM p# ]&p^DzeDT}z/o_Ry-[@6z`Hr` 7.9 2Vp!ap2%@;ez 2BMk]HW#z>@Aa709|)p8`հviF;~" uUim/ГE0"CN='g\Q{%+mqY{p8u h}˳+\}J^%*Ž@{oECDZ,s!:- n;q.t1V_ 3ৰ+( 5^(<z\OJ?5!feosXWz(v0<76,ݟIO_R 98qΑe- K=.cw\5Fm}&[77?:[4:be>)-O|`)޵/}{x4Ɛ5kwmX0fȁ%c3AP%2߲=jdz$,F 7-h99u:L~aǾh!Idh})1bx:jhY@,)R@ uB{'hDHsoi#he)ى6jE+"jÒ=Px9!4$)UءQjΔ2U%?x}H.OWC ^N;~*t }v/1rdU I!![RiL=7S.r}aݏ0[De jӓTȥub _K:-;]C@_rQLy,-xo*Q ! 7$1$erE {꽃aw1DoE/׶/Dݦ7U9/M,e\v49؅p13X ׎;<4A V5k!d1@#׵;0pbQzNQE@3H=4B$-{*g Lz0^ea6J ] D/vMK?g'e/*܋2;) -/T(,a\ϱL~Q!,֍+c7}XBXw5)a qL-c)/޻0أ'´XR/+bKjr# ա(c.Obb/sl*7:gzKWpM1Խn4`e} yL*b~ZHSgUFV͡o?@ygl9te='/*ci>d3z@\cY} 31zUBˈ!1'f kGX)xvQoƖQ&A]X%s-i|wy?<xj b\۾/%̕T˺]!r;8NFHKVq ?}|f@='>5̂8 zlO<:=Y`lZ +;ѺQxdi^"8@ )?[$UYVHt nQ$1<4B+{C3mڼhEKaq_w)sk (j[REp8EFԛx -sI/Q0H:}1,׎ˆQص0THT>{kC۠< ccZR8wH94p%á֣=T3t ukzO(󷚽,e?@v <6A?>N3Onײ0e8"-0d9N*_7=KC  ċ\bNԼ3v*] -9[]J0!5ֳmj;G>ebJit[/,چ򲸑 g1,YZPQN}Cs$

    p80tuB) .Z>*TҘ=xa6A '` xH.fCs -O⢱GvV'I!רųq Fm1{`±5xwӈِ˵-iޝ|okwnd°q}'˅H"I ,U+N/XbW @-% ?#Wc@_"pl\+,4eX?iy{;;Լu Kh~͖I81' =?p&~PfC8m@b4yl GB=oeUݱ;<>{$ueH]AٴKyRY,a)KjxY՝1&'c?}NC5Մd99s=ncm忂j-.sWa7 eY*6_8c7=`.M56||CKRz,d!<"JޗK34ÇЕj]>-Q۠aXz]-HF6@c={S퓻 OR?`7'tth^OۜXX+_2a/,O( 9Ett?E]>KL!>{vB#0mK#R#wK+Ҳc, 604ՂlyP#UU &g&rKJ\+R)_=.X|`)_;Dwey) ~R'*r'q.L=nkSץH(R<%C)4}66yHѺZ  ?׬@i$;MM.џ@L\EϺMЉacU⬗TJ)RƱ/,^9h1Ï5H/=?FZl/=Kiif ߏR6@;|h{Mꔸj38O J4D͇:ƤN_ }|b;{i~\k8~&Rl8 HT3"-_ ֍;pz<^L^~(n?v-@} /޻H"b2Y} jUq9)++g'W@Zv}&Qy:8@'gw`P~R{)Ydepo7݋Y Zsھ?u:xOygVX%dmRF 4%ͳ m(Zz^j\rJV*t6  G*-;ϡ' VT kG\ۊJIuV݉C cQd}9 ~L E]>. 뤧IkUVNl umӒX!(xlA jA6- 6T{9l1uOY*%)2ȅAlX\CL'h' Y/ȁaˡX̖֐ jȉ\<%CmԼbp8d5vW|ۓ dZА7|˟L~abL, D5vZ"b_X_;;UVp珩aۣ,ۗ'UĿ4XjaHZAv85@i18Y8?OTgΣm臸{\xrUUII]-6}])kZ܎Qvn5,&x.5ǹ}`KavMU CQDK8iLŇu4@ VKbf2<\5O8 9EPѡs}1rJeuΕ.4W8 #~xnhi|. !c\qcT )oIkM],ҵ־tP푝6-'V~s;SA"fk㏤3)=BQlGoCx ~13#CD;ݢTmCiIɀ9``2ߺg'%\"K!1'i3k ҆VyG{5+=s~6?9SD*-(ߪZm:e߁. n`'oE-q Bіa?;d93#z/*+lj ElԶRjL{p8>,|6A o@/׶ژ5DK%bH!3{,~R'5:0{gr2I=Ʊ]cRIVq2+{C[v3 #x{W"K='9l1Z{1V)L/=3%r~fnڽovubNt%H>*ch/i(ɖp8 2f(&'ϋ`J8Iy:z snʢ:Hi1)ikG'd:2 ~Z V gmjh}_TTSMri$áA5%ށ <0f Lukn#Ey/I& {1"bN:׎$bzm~mxw Ԭ z.~a0(H7)x)f_EupAu$*<~:`z~5еa+& ȥفN_ ~|BOt,UmCIoڔH;BfC2 ci)WH5u*jap*-sys%+|Bf@$fsߡӘzX+r'o5QooøkՖ c98` te<#t% r>RMJbp8jDHL4_l%X>( `N>!Qjǹ0T ^= KD뀅]/ǹe~$j8խ$ZT%r=JŸ*k1! %j[xo9hJ6@GVuV_J7&Kq0cvDp̺RX/C@kytbJ8-6uW#?74@T=z\#V1sQ!eLH," (9 ~a8"-Vt}O?C >Kgd/?W^>),XTk a bxlvi&zxid|"2N!uRNW=SC*ۀ"KXD<4s;fjȉڃCyg.gRxx3h2<@tg6\Lf,%dJv&LLwv+^} 1rh"4t ^NTθtb'a߆PF0JݛN:_Az~Ңp8#-"^Y} ,fRLg9Ie<klo$2#+{C?3XcQrrcjLWTӠd^~'_Xs2_Xt%cѡߢ!}L&Cp0,7`NB }:Pm}Yϵ9ƷZ Qn#U'Z \sغWSR;X7 =P@4ֳhdc. OkspB: DDqDjמ)'k C7ۥ:1|(姇0%䊭*U#rNCѥOWӘ ""E0:b"MkŢvC" l=Kоj{JЩ8fޢiIo?7ג<=.X w-'e5->NDWLбN\JcM12Sd=΅wv͇7/wF~3帘 ;^,'1UV"-.r@3Ƶ^hgAN; 98C NoM;u:ٽ|c6@+{CCЩKaReSn --O y!iS/WN9e7XwCm%z1"@j&DeLA즴(TharGK`*j4o9~ KT0Rhi<"5z4D?E[ c={ ċ2SҀ$׳b@UTP` jl|ںgxCZ xnl<6HGRkG`#ex oM\ۖz yo_BIaD+ph9{Y'qECi%f*2w-S-;"̽xpfzM@qY[DIۺ 3X^ߪ'xi$i0޼<G^'ϋ̖15iaE{ۙ%ʸUeI,cGu6n#- r#0i+Ppj5Ñ"vi}0d >-.[&w4J8V*]ށ жf6UIv&Gۥ OUvp,xhm-=k)Ik '8Gެ-V=P[ގ.i<)ײS`Hk"~  ^NwxI>) B kGDi(ڰq'ϋ`ŝHiɐ:cErqé(?êeǠ!}d3BNݻ VC,=lZX>oQmDܠ4@Ĕ- (7,Ҭ\yyF+M7| _de"`kI/*[ *2̵8/w#arlAP0SBVm }%oQ0A ωR]C7oMfZO=A tsrA+{C3'kg_>+޹kw jޙ IDAT+RZ33 W!pᰆ{,)1,?(KcPyy H̗W=yB`{@r0OW\WR#H^HrL/A\mlH:GTJz*Խ>^ckq,9pR$Ƈ[V_ !ʊzy"b!"-&G~aXn#Ӱdz<>8ukg< 2lYMUַkB7mp!}1%U'`> cp2dF(uB >jI_:}1D¸kw78(!@%^mщKP`nVpbNDz>s;a&GyHsGZbiuH XJ!؃<1(lM8 rI/wWarz߽#|Fg=H ײhbƒC5R;~pH6 !â'᠄Hmr TsbED>nXtI9p $LNݻ]qo d/??9BpK95/ :}1xW| a& pkH|6M ǖ^guW#pet:E憥 162[pE˾X υ⋻`JzRƧʣ'Qk%M9uy%ùai o٭T1yy^6#S/B͖Ix}ɢh?JDbHKt#K31-ڀGm72ScVYANK}xӴ#ED޽F\F,ܰ@rK<95tL\3Iq9-Yh,.OWcO|]^R 1F9pucldeGJ\]Cۧ7rҩʉSŷ%}ay׎@-_:3`4VTr( ͇!)'ݻMNk  qܻg3nXCܰoHŻK*1'0eǠ~a8b U WKu pc[ŞNc@?<$-'G=i>v'"n%@G/\oLˡ/i!ui_h٘?꧅R l᠄)/aގN_ SOl4~h"f$TrOx F^{Od,ih X9٨BJxBb$m韋oog H;U{4PRVJߕr2?80^*ߟrrHĐEԃ~{ylJM5oÃmݓki4fۥ2,+FEj.嚌%yRGʁ-HKGaɑ`hATe I9圎CdFN_ iyYڥW7M0p8-gHD:}1\%. um؊Mm]ُs4rRFiky`kp*eF'ᤇQJ٩dgϊL=QێU_-i*d/?4V_K s/%'a\SΏe)Gw_+J6 5]-áaؙ”XhCm5,ZÙX/,G΅7ygqN55Aa>qݯT}J&~:BDŽtdp8nn9KET^$Ɣ9X#;~3'dg g%=އYn㿉8;a}Tp%3xC6E=5-98Iɏ jj(-5;Kxe7^ .3Us:Hs/kP'7H|CAakcic68AVeŸ(?~Q9:*]#54cgH";.L;v%˧4Re=CZX@}k_Ԑ-207gyOq\]IA[jXTwZ@e,gVJ1ÓE[?a`o}5:}NoXHеb' qF;>X Gt[|*\F + (4wZ@=pE/UJ͐]i/9SLV\UP!ԩ+RP M4fe]4ƞ#e!-|H)Ѹ1g@cAJtW?lLq]FRH>IJOmc 0g2nӦ^2JcMQ=}D\gꎚIڪloQ,fLQ\>wExVE(@٢Z%awXc@gj%=?O%-Ȣj KKd/6 ^4,it6a+%g!JݲQDsPP ofQN_SFJW/BzRl\v/UG e KyPT-pFV$s2$H~9 >Y!q[ϓ-5ŐQ{Z3ڐھbW ]ˆ^WhX!CUf3UA45]=;M"Igz"'jƩ+ "~M9G*h2jaE B2{UR RdrAIWYRe"B#F?Ñ2cm m4ՐLxPg3' )Jr 0S1rDP:\Z{uCp8Z"+i7,к+qH ńsh*)Q D3u2Q"9R~C^H Y2  HgT^iㄅ*VmSJ^вp80pZxe&>b1OW*cV?y*ٗ7CvPKJ?3mzPRE(:+U PYѨKK qH.nD{qz<|, [ky,>B},ﵹi2q^FXÒt"3j rBŰ+PJV2Ax%s"]܉۸} $%̌k4~]-թp9RZ%p8 L7IQNX)zRo\='ԣɵ^v+4Sۯ&n't2ƙz^\8&p7? " /ks/!ñL;օ4^H9!nط[jlBR ޾L]JT/%򲰛ZnzLFo24ƠGvФ3ܠh/q.E)2H~(}nxiE~q.,Z\xVWqQ+Ud'>r!8U{U+6Lom,Ȱ4(S5ުN#Hɠ*kw}xPIejs="i'6V y _NTvuGؓ˺}BfiLlXX4:@RV $3ԝ υH֎X5_žS.C-mx;xɟuUB—ؼ/5z\n]$.7]_2^7/h 2w$.sJC/ m@5R-i!e5 55կ[%- m]z%1I٪N>4!ڽB/)fTqu6y,b>ӾwΙI,3u k"PyuwhBؙpZ^()'w>h=+z!.s7/J&p 5 * `h3֟;:}1L=A)=v|djv4תH˓Н<6tbʯTuB<et- ;dSD/杉_UL~dnht*ju*\i/JBʉ~\Li8 "q4B% IDATtB,jCh X`qmK\q^m4N_ sSa y'r ㎮kG0)v%Gak&:7 $0 ?\B$eLU+Q-i2)Z('4VHZ@Psu64qGjJӽ'#Ic'ڊDގ÷oSoؙEU6\g!.6+w< _E%q.?υ@_ot~PO;qp?'WLTKp9e\P>]!8H\.5 5.l)vOJoj;=H;d%:Y^mo,u6 pǹ8IV44~4QO)OŌ)bH{w,Bڽ\<ަ6,tX׭%09r=u#C׮L.f&>皫f5C=Pϡ#z"CVa>57&^8*e8\k圸Yo9yXd S*lͨP=v8O xuT# amZ5,~5aî(O,K3$LxiyˆC+Esh"4Qu(=w #G;Ry+F*R p: xFt!$16x`0J-%}v2p.áEx7Q~JўʩWaJzQ!~5Po{^~)XV{ٺU[RLAP'd6GiiN'6+ᢳ& iNDk{OTM nOS b=(o΅ǹDQ?&,a`vATe&`,(~"9g^mQDg=΅7/InN.车޲ɓ!r[k֩@fy_'{?nGk{O$`ف_G~<6eTڵRr3jXԼxiD_i8=?[ 8Bi{t#n`mi~* FP.٧{R'a͇Pcߵ3 /BBDZAac.ӌCjT\Я}?ks1*rjLt/Q" 2y,}?@um؊=STrbá_X3г9s=fWL^k,:`8L B+{C47SH*]ρĜ +2)'G0]rKܤ}ISZzV(ۥ o5ItFB9f7Ng)%E)uqDBM!7'y[RZ_RNNztH+n 'yQi{ꯀCjUrMpQ:o ENc!#P'ةb_ =*3MKxjpl бod(xP98F =АK+} @ GJn&4"1Mh!grǺ`NʾcyQ8bCbM׹| XEjX t祫#7׀ϋD!"U3|g%0ƥu]C}6Pv,'ݔ^\L_?˷Ks}rjB1MoW3fχ@꼓 m|ly{S1*g&ht* e&bnٗgDHŭ'çJ")/> .HR2g;CRzQŮ<azN/dv9snJ퐐S{%tbw4 Ǫƣaǹ0gBp<(ã#V~abHI׆vÿodЩ\XkGi&wb 7d,WK!aļNC TݣN#$DBfCbCȵ3P~)dz]@2 udcvTبa$GhQnYZ6)}['b۟.);9pnjkݻLR{kY_H*ϓ‚(DlO %Cy}Y@M_kZGĦbn~Yj(>~ ?DÜ.#~[J&a׋^:aEU+=\:jy|e$v&ļpޒ=Zq/sXWĴ]GkR8(Ú Maqɢť'ؔ6E?~ U-ދVxRS)p*ٯ1?hQu_ O\:AYFG'-xG} ^GU4T1}s}?,9_s-= i戄Vߧ9sJcuz -cOޮTU5J`v 1 .)2w!Qs{4V$4\6%d[T%02R#gS0Z#6cWHjg+;8cza(3[ z*͢!,=!JKSJ@KM: =?$[CS x>Os)βPWc?JϴNooW[Ԋƻ1ľ71X10nuazA6FnTEj,TV Ԯ9QsJ6LK [aR0`D4$k xYz^nqUJZNUv\A7 ͻqPnP!b,%貑,%>>(R7S9S1Q|!% {gTvi舥RanOQ5ƍpKJx>ry#v/+#٥[,PZ>b*Z>{ <F!Y(l;mRRٿ!+W6xR臚8Tll"9 }"?WOarmmˍ3X~gɞ3&]-nEk Ti9x :b򉙩lLbNnXg,MALKC@+LZ9OA wi7HCtEr`2R$)^B鰷5zh(\R▼9P[<˭"#>6>ʄ68jNc5YxA(Ú TIA>F͕<8KA,#R,nWǮA{fg^>CʣtI[zǷ="+l_W9:~|nwj "R{D­J5Ies֙.,9AqK!{G8MR aJbͯjҵ+R+DVN P-GWaMC¥[hfd% !|_A^qBUsX {Bw,Ӻ$ :'|2|\ YG_Q˟J!KhIQCk֠,Jp eg!v4ZAL%Y,MZ揚棥K lxvB/%Ðe)B̈Es-Т0Z%7ͻ.TzmLR欣%G {[)AUڭ=EyKw R.\=oCOj$DݥkKY Mg{;tleg$q4Ox}[-eAfV,}\< >\bՅx Ye-GWaϐ/YUsX -gd+6}v'HK.6`*j9j.kSxߏ9 (ߛE!|%gv{U;%<Daž̔*Ƙuu8{!2E%a_?}zlGRX'9R,6~xmI GOK^ Q'~WkEn7C!+O-終7ߗw/+8ڣ (ov:8C/QJi*ċ 467kX}Yy9%[.Z}"+V1b < 4oؿ M/=PKװʆDͅԜ̄oVOba*ۗxNVHIpc, >o7 lcUd.*Rǐ*#6*J[Y]w Yupl.k[xE!ͺ(j1WmKFŗyуg`o\Nozc|P(ncS\)u(վu*:p)\]9*Vo;bY\vgYBD+>w'ĠK`[aғܹy,kVN\ -fg+#ey@`, +?ǒ&?rۗv ec9*03d"uSvUԖ("jƗVT*+1>.ʔoG5 f+w _ ^g])մ 촞^S/t~0.Tq16k}H ~n /?] iңj 7`8$LZCFKAx=y:7砥U+K/gwa,S)~8zyooPkui}(}ЙG=<0{ eK<Ǻ|13SeqHŷµd:2I2G0GmHZ5<SA{^C^4X@}o̒3S?†ˇ(>.B}? P%?cjI0QR6SQq?'KV==bϐ/ $K KSWMfw)D@H cB,ja) ޜk:ePWO3ɯ\PuM -Y'b{)q}*Liӟ}6lGV pt,O ~jv, +܏{Z8=*,rꖃ2UTDKmfihjvT?K.[gt '93d?n%>j;@!UN 'G4Q~2RXǫGdң>vELЫ1e KY իj/9󻎖u,LZ~e0U^_0NbIhndvT9hrwB }7Gb)]F cW!k&MK@BdPx\kcm)R!;ۤw$Ix[id50>Ĝ-?VƛҾ}Viwg6yOҲJ`kуxKCs%L;TKHȸ.ZM9}#R[6]M-EiSug 6v0Y(I?:zK._ ᷾ҔPәn"-kZBK;e1>(\ ?P̓^QX]MosY ʳːf : mLf\L_WaQX!~J|: ukIKg䆯1=N#IlՅ\hуgXP*+Z$Ԟjoǁq,+bkjkJ!\[*4,F+BBF 3$dܑ\a:&973AS~`<1̈VxЬF=|v 5 &cyh-S.fo7&iB( r-JV}S0Gˊ Φ&ޛANb>.'"F)hZ?WOANef&u+`(((ħA?MV$a56[^)M*+WS!j/'[A_0 K65e fĭΏ ;rލ\/O.޻vWBZz/a\h^[#b[⎕Mv {-cĶ_=R)kB0*"tRE];ΦX);Nq<ܰcg] kwwD{?Z \_sdAXa,f#Zǜ"1:Z.ex)֩qGG7 -Vw mw@-GWŬuEY[ŵQRң>~U3A`q%D4$\w 6[SOiΦ^G lf[?Q6.ܻ'ǁߤKg^e۠OK *R&pXoރѸ㳠#=YͼP5A6H@gt;!kݻb;!fi-q|iE ĝ8q*Τ&ēʤ9Fn^ !'P؉ Is|3b+x뮣1>(ı$ΊC,~9hmlPPXUw [a6̦`(%##NX\wop>/kGMѱN3t+U笺8{ݍܼ}( 7|Hs j)쭝\RtaہXfۃ,vn"`W|Zu16WOzf Ҳ =R3 !eg})t_VqB-GxQu/sV nFKf bCwcQECqku"JREosAXVXX6V؝&[54Lq&_˨m62 攇MMӍ.>}Ϝ;P<l`puQѵHq2_lĽ2Xn/~x1e+ B.VX@_,e+/+"e")+ /lDĶYlx󰢶- _W췩Ng+ჃD7Ujk]Fb|PDCZX!T, |#R8",t~Te9-6Կ3EDI~r< ̿<_eNtcq,=>Q1 U+mb3S3OH^v&DaALdCCзA[{WfNij5abHX@]13d8 > k牱pR* T*envǡXsqFn^xͯY2"13m|whd8; `NxCQ+ TJq:%M=%S}O'7t x ^Elj nkDZ+$Φ^7kۭ=bIHH+6> t kc uԂcwB J*#+ 89vz~~k:OStr.#0YE#Xƨ,~f/DN~txTe[j cůaAEkʪCk+_^ltzqlt?yϮ*jt]uw@ f3ͬ DžFn^hr#l> nn$ŲcyJ&_vzܺf wAKE%X~g,9[_\1&U0z0%^С{4v^Vl&d8q*.RE4tĠp=u$Œ0FeR,5([u~޺!o7FJ @/ eɗQ<ս2z" vM\KݻIr? Eգ_c{⃶J4@KU4u> Y1̈́yVnoU^e^$ŲoNEaxS'9-vzTwpW5wrtAm'WxVwZU]rܝd<|9H̼ 13q7HÍT RN]4AN"X %],ξs_+>Fuew`ư۠_06錈&hjz)&ʖم5.XxcPB:[O9O8?OEUǹĘF[ -jj_{˲ٝ6L-Ѥ;NVdlɵ(ڳ!_| h^ȝ7r뷴-gH7/1Sf ZQH@>o <6[^,gprۦ%S; 5h cB%1 wȭWc (Rv2R؞gpyyٚZC/Pa-Pa'a#DCDh4qb#J@)mjYltΨ,l'jwɪQ#/KZzNgc 8q*d5McHjVE1OvYbɁ0";!mzcVs.Fatrf]0YW4QO8v* j޾YBKyu##NXMش[/!,C#V}M.^\s /q8&S%KKz:зaJ?+t((4M>cEԵIHa;.?HT<~vdVը_+5}Ѧv#MK^M~G/UxhKW\kc@vxͯU'r2Rp-6R#13 }~x,!6/SZVWGj5R u M뢉{JY(z*aHUx42tIVG:й+\+A5ve>Ǚ8 r0/sGIN-n%;N6:={;TC[{8;]Q^Iy$ʅF0>|Rv4mk7FZY% BQfgS)x/SpMuOӖM^|\<AGR$ 8Ϯ>HB܃d=HEe].u@c7/zyMr   p+nvO;^v2#5;wHGi.%Ԑ2e~TM%4QתqADeJFr} d>BZN V'%~6d[`㟇ZurtEm'7Wu&ő                 B?{axЇIENDB`CPU-X-3.2.4/data/logos/Transmeta.png000066400000000000000000000553041341671471500170740ustar00rootroot00000000000000PNG  IHDR^<sBIT|d IDATx{|?e%&5$P$CjY(h@R+@T4V{N8ψZA[5"6K%|E J>?gٝl~~0 `5 FNF!9NKK Bss3:;;r`6s\r $%%!55iii0L6ld3 `?"D_W MN 455̙38{,ڊ .> ˲8,b̘1HMMERR.̘1 `QYYI 0I||),>>}0 `*j)c/>>$''aH^^0C'v^BMMM=˲'8.hW|0S!_ff&jsh0hi֧N j}8-K0 ZA޳gO\8U”N'QP0|¬9sLeY63E71s1t2 foA)?O{11 `0@G!ǔR8}-4M,Mf l  <`J4H |'!&j9^oVf)S`ѢEhjjBBBZ[[q:;;t:  )𖑑( ~غ:r=P p/\pUv5p8p?UUU?(--j{n={`߾} dM?NV\)[?LRXXHHuu5`(ߛ9j$!Z uuujLbElP|d 'eee$33SJÇdʕ$333H_^^&IM(*`{g.]mNrJGV+iqGPYYxRXXHǯyF'd@R:ZWWG(W\)ɠGnMNrrV k럘TVV&OTpN7neiӦ]sm6E///ia$HD0OMFmۦ0p8D*"5Ҫu fQ̺F$֮0&*I_ESյ?VB%{ݩ*^z9bۉf Z _]]M5+WFdj v{!Aj%ׄXUUE#גVݟjsBI& Wjʎf):=V__Oh_)3S(԰0kjaSnӦM_{}gJ4X2,5FyyycQJ~͚?v;$1[Xv'3T6' ݇mdWYY(>h_Q[[ti-'?pi{uohhFIY?T@嚱:ϟ/0=0RRy^^N!U& ]jo'+W$arUU S*P'׋hʕa&HV9ȷb)mjsJ2|RXXH***4_yyyuL*L_+jGMJQZZJ& J333>GEzv2a„ªdÆ Z#x-~X1qqA+LQ8q|IL6l߾7xc>~:yJs;GɓG.yZf#:8~mTUU3f<@,tv٘*x1whrS__O^z%?Z8X,}$ebŊO䟛~DWm-7… gCCپ};6m$6*gIӸ 4\HSR{9Ccc#n<ǏǶmܹsLj9ࣧ j ӣM|=0u E}=s{)Hd冉 7wubјu%Up;{`Bpy8$ GGW7<wϼYwttH.5jTTjii hoo2lk &}{{;9n ?xW;x y 8qV[Ov]]))) `6l FgddTK RNd8qℨ@Jp\3sLlٲ VNPZERecѽVAii)yb.CFV~5_0@5u)J"Eyy9{d)1.^>lDK _R%3ev,\'N_Lm8V/z 9et?#X|9L& mkJksӢ.DRR}nZL"6! pATTTa㒲!<ގ]vܹs1[(q޹s$9s栺:!BjD IyhyW9"v}aXn9"=Gyy9>јbGM7o2j!3LKj*Eeee"zbѣD"-- &)q\)&CΝCkk+K{൥\}RRrssq7"??8wu^{5np8HKKKTHoߎe{̙3Vy=[z/^'HHMF΋Lp=0i\6M{&:a4ׇ^^`{]Ag=8AQx=z]^0x 0CvwFb,,Z]f$_{tqnL.Ό!pw_dٶNpu]%;}j> njjR%Ê+QFl6rѣhii =909!DQhJ?&$$0d9!4`j!cǎ^;XŜ9s4r̉e٨%ڜb|'!L8CYY_OBcƌo|Ңq }8)AzP}7-w7X-[u$ ~1bAvv6LbĈ0f8Wވ8!H`y`6^5"/ĊBG.Fv(0 Czxf\Ԃ$cŒ{W3f-)Ƒ˰,y桢BhSNɓ8tN<)%7mڄJj*ɱe]mN2ƒԸCǼk׮ks® |_֢a dѽV=z4dbloYf16Q'.7l2%Գ&zͫŬi0h$"fYŋ/gIm(\GWyŢE<(//=gkk*j8q8x Dy7w槷)yՁ \ 8#&FK gF{`б0ƀ]y0^=^nMH0'~ѿ<Cq ]=xxøG7ܗ>aRx㍐j bLK.?ݻqIiB裏ipO>șł!˖-Ӕfn tZv[qB|t/``ҝGYfC `qauÍd6\^0оݽqA< %|0|H ixZUz=HF f{VY떇A<=F@/777k1kRM 4k[,1J46oެz/DAAAR0djjs-[ K!&Mw}7ȨQ|֭[qa&-Io@QWUU]v)"cǎU|_@ }'I2wjjjE!Z" 3gCC"9-T)nY@ 0.'kA1ѣ|'EFF~K'|2,yڵ8v0hLZ6d7t iiiabKouu5پ}{X>msf1ܹS Th";v,LSssEFFFHH;vlY+|}aÆIIIsL:U͇ 'H8|PO>dHoPάO:LIЗ&cp8رcep}:tH&PF"=yF%ܬY]N"~HՄ##f}Y}T286I=mXp۔ip VBM8Okɮ˲HOO سZ̋/uq\BaWt9] ntv:h㉵[chQuR_s]{pH6^&^C0u{A UK͙ڀXˀ qN<Lɵ`FC6'~u#(+e8p H֭c=0-&|Ν}zO2PI~( 5Q/5M(JJJB: \i$8_ H1cF O*:,hY[[KhXd=_TTR> ,`^|EϽD__3fLcdҁ8$,/Z3?L2ۺ=2t(SQSq&8 IDAT}1%Dt{|¥K-BɽF̚JJbXѸb61_[oɲT)P=qDHIJ{nO*Xrs1bVa M?QsF|v25% Yw9QT#D?^ÑbʕD>}5'J~*/tMӑ9n_ʒ|ah֬Y պb 4뇿qz!t2Q/~ YM8yۍK\Bxnx&z}xdK1G\O͙&tc\&\DHC%A,㸰IJQWWG=rL̄APO8V!&rXS9s&R,̙RN&;!-- CAɟ߽IbTZ+MͷmFv%,p|J#Ξ ع6>@iv5yJaۉt.B~zdeeQMjܒ,'hk3Q烇ZbؔFnl!YL|:$c -- ^?ftv_ hwb|O2kNl8jwaa޳8b}@H8 )DztҨ/Gc͜9Sp|Ҷ`I8|3LTY)-/m!\3gh:g}6bLOO 3]?v)ݰPYRDJ {쑌3==k֬"rH9ÿLቲp]ubqc'veNDEV`[Pi){XdOhL"zh$5ƿ\]o|yjn'盛a;s>smƝŸqǹw ~t&L&^fS<.uwM֤`BɌX~?qѢZ|[M5k%/ϵbڨbo{%FtˍR Q]_J/:f(3j(Ѧ?-9k)q\Ľ:Ze5,]T w}7V^-wqJpԩ… Zs5eqkza'z-bx.*IA ;OE% YmGKao>_46^pOn $AEx)·!fܾn:k5x kdn\t70OX5ej%>b1%)++ a@6a{Gyӧ+Io>Yi8lٲEzf DM21;w4_Y iٟj %!|ׅ Vpnb|?uTl޼Y Tc;yAтTܤ+bjo߾B֯_#VWG>A8yC=~xI.!1Ju4 AC/#K@zCI7 7Cm0}`d:Z---MSJ׫'wuR5pE"]bˣbԵȑ#bQ&MR݌/>Ξ=6N5ףλᆱ٘̚?HAKW5X$F{S ˖-Tzł۷#++ WjR'~zѵVcjaɻ &==]VǵȬiYU+!!)A:# Ll%sa ?ئw .u91u-x:_jʬt9rd̛I0X˶mFfϞ @&o1?W_}51,Cn:ULJJӇc8Js RÆ 6EesυDĊ.359p@T砌6x L>q8DȌMOOWRr[K-䢠ckx5UWӦ0xMv_Nd$$%vث ϐ0qkz>0a𳵥Q_sRh<ħDҤ̘lڴ)) S[nZ.5MԩSq׼kd5Xy6T5Bh*a(YYYҸ p-{% q9*,>귫W#+ <{\S5{$8͋PW NMZpi`TX`6ad7op蟡KM td#8>[4j !B@8g+ϙNj]5f t*6,Q@GvRVVF,Y̵3 ~O>$DkWV:49ČcaTgMKłpS1>*IeY/&P#LѣL]mNR\\LjjjB֭[j*2oΜ8F{CCQqu9NgM%S@ * 8E,o#rcH6f?wàcffz=0ZHV-etPǯ)VZHn[1JOOW, TVV<󢑑@89s&كUVT4E1hr' S.D_L:vbm#TLcZZ"^AA"S8?p!"LmMp)+ qJ(yo׮]V)1曭Jϟknhh '夬XVbZIYYYY̦5D@ Zb9aʔҙQ9kB0L:n.?l/8x\ab53W΄EKpaQMŴ|ۑ#Gjv]%)6lC=v^1 ֯_R&///j_D~7.b>z5sדo9 Eε\Tl>}:S\\L JP؈z*Y_hFk.,YDs ]b5_@y桢"lgJi\Ek 馦&|_̙30ahZl6e[^NLL4L_S3gNTZB(q59=q.萑=mk5x`<:?z`AGx2fKF x„jܤ`b♟xK{g9h^n/Im7R4ǏJN9rD4[+VヒR*B %ތ _@ j1#Oq>.V,uLwijhʬ;yrRV4Į#t#Uf7ϙ{'EyO***C=&|e4?Dj̷j2LOj\pQ3<|\5YYYSO=/\q^xk1fLqK tRFl6"?1isQFn'_|\XШf p8Hee%)--%r͸ud<=BeZ"8"DX`!?X"c/F Dx-H"āP\IS.}\Yz(6Lf̺1,Tp݊kɶm… 3H6:u*yLNPWWGD? R{ \j4\7Kq-)ŤI?s8| [I@ҨQtRCoɓQRR;vZ_|1hs\b&/F;i$LAj%&L>;vj2&8?XթV4Zv.ԜL_+fM={$+ުc&[B&n0`a;(f =\fC|"9,rIqł\t9Iyy93g6m %gI&7ÇEH y/ל9sbvf޻h#K@!-- ̔)SDѣGC@NW MNb~KHOOӨ%Oׯ,oBA̢fՒZ,l0 7:uT˲.-Z)M2E bdY. 4q=`޽fm?"|dvj9UIHH7@/ǎYp@S›|kШL2roih Mvx7 ЌYGfkU^ɋ!cO!ߡHHЦN7|*WJڥc"QJ/*Pm @0#7&et:Ä>qLf{F'G 4kĊŲWMY&h֮>L?ȯ\&fщO‡\ӧk׮0 ZL o5[O%Z8@<27-wT^ |afw ^Lb# @0`c'IW\}0f =fNPJ%8. LIW=2{?Ʉ6Ϙ1yyyD[I/ъiy6y555)Ejeƌ@h5.l(bjsUV1/BG!԰ VU]8NYIJlP;1bC]>3g/?ĈnKKh@ĉ[ҶEtbH?t1""]P %ZN \ JzzbHJJ dYMMMxη!w"2F q{vZޗӲ7H k|/-„tMUJ~u#Aŋݽ58|0Ik ~}^1.Z(佒JJ444zRUUE***Ϗ8`ٲe o((WhQK,Q8⋨ HtZRԞ.HT~_1k׮yŎ;PYYIbh ZVZ,^8b…~;Q+Ft,=$[*ƌL*U]h_//*p8IEEDĉ())AYYYapflIA0BӱI;cfsCX^7C&܄-tYI`2BS֤U$%G}mX{ fb5Zbb`…XjUڜVܹs8{,)m] ,HM9.P4|ʔ)!D~͚5عs,cV[~Ipxy}e;w.w,vG,ΧWصGѣapr{8][oh6tM!c Mr0111ȷF 6 =^}U%>Ze+ ]w݅9҂455ЙN\tF4wd^x!SU3|Q@`.;jѴ-K/;kFW'+0"qʞf̚) =ZX,+Vh2LfbHQqĉHnn.ZZZP[[KΜ93g7dJ|D"jذaF+jQ/ 0۶m#6m ޽[xE1Ύ )))n'K, 5I1DsI+M0B3++$7oaR[.Bm^MO{* >h`7vXdgg#)) FdBRRR]-5 f@hZO4 :gΜٳgԄcF@PD8ﳳ:5Exn1{Jt2`u&t? ѫTWS&>1G98/ :. zxX@l!M+)X"sXd -Z"JBb̙3HYŌ3|r MNbv;$\Ăqchoo8? RZv(11bDj|b{{;֬Yu,%]*=rժULEEټy3ۃV:I&aÆ xUIp) ȧIYFlL=iÐ#F0ZHB>vXسߗ'N G-[?ynJ0xdr">y=]01@ o7%`00cވ]p`t&Y`d_ Ukы Eɪ5ػsG)*߿0 jؿ?)--%IJKKIi@Zjs:R^^N.:^;bE<GpRc'ӦM+WjJ rrr"LbZIee%l##K pjiӦ)BINN&񤴴W&9sD?V2dʝĐ7 r'|?wCGRp\Bc>?>U{ekH94(؇&'1%3L}}=3oSZZW$Ν_i- `… {z^۶m#?σ|DRϵ \ FK2fa|fޔ)ĵaQ3}M00@ދ:{7=0.d ]=xbj KV/!݀J6ɬyAͫI)Emm-ٻwoH&D~6~x<SN᭷bXʧ:j(UihFFF")" r9ZUZ}@J^xvbD:RJW}~u1l(>_#GԴ#U*?NhYC t,**›ocǎg,3Wu֯YDx@>kCXcIDAT^G^8F,Sj5Koɘ7gV5k-Ҷh$\j;555Xp!SP&n"%7j׿g}Ɣ3 ,֊bozz:^՜"Xs\Ljj2T뗋Zpޫq\R -))I<@ b RxG(QU,D677 j"05/ÞM|UڢP(_KkI#fv~yhw1&TXŸqkW_e~VYp5V@h0] W^a Ro R|0yu_D|J2֬>>Ykc=w\Erc8q ݯ aLj3 !cx7g?fʘsyiΨ3ͪm|HhN~9ޓ$RPIjZ{FNeee1zIZS4{**aINQ0.BaI4K   Wj3hrbG;3fOrf֬Y&!!ATX5s?AzWʄg-3jbt/wà7Aodq[1w>hƬt`ҥXb&ӣ {ҥQUƊp|RDWΗ=f]:ji)E|hbsX,1cs=JdddK555puuIjmVVe@{^^kIg}6th0ak ~IK ܒ0qDU6.BV0R/{ N=b,ł gJKK~c)șf3Mq0m9zΟa ~MC1:a4}ҙF␔.F ,p%myQ9,Vlذ[nU^~nX؈e˖a  Mb~I&aڵal6ZKJiz䐛$fɒ%cbϞ=^ԪLf??d}gΜaLc-ǵ-r[mH Tz^{ !3BM<3~xw}xwp[o1Vb*uJ Mw.g+~lAſ#CBjLEEӗ3gHF,i ˗/qQr~&VbyE߽pBF*Y Szzz6n'ra٪;HiDsIb4XV]ә~-R8tz-j20T) q-0!#Y񓥈OIF&<6M{YM::=.=~.t]rcđ?Z5f͇؆Bcr)bZ- ~qF& ZH'O ^?V1mk裏ͷOKb~Ȥ*J#ɬ,2xoF҅!(YӽaL4I`RUIMMQΝMVӼlIKKf45j0D,#|M]wEZ Yv\\lkP`xz.vKuFzx<~7AqނEvf̚.ə/C,uMhD~ 3k)8jo+V tA"EZ\m X ^\&暵& HAP?r/_.Y"dee1۷-k׮4?>j&rj%^WepBua墁v|4A"ƌUkF $FbB T|&U "YF_Kcffee1*s1׿TXVV鎕*;n`@i.Nýs_7` ԭ3fH~;<Ԯ EǂCI MȷrKk4ZT5N8)-Xa1o&$$\U潋fĈh5Ų5#  cUR #FˢFfee1B͚)S oj!ǵ켨%F$bJy.^΄K0L04,! ?iU_i#q6l؀}=Y%%%(++ӮA>k/_\KBq ſlQpI槞z*86XO<|!\ܡIL~~~/j64wdz, -11{f} &?`C>->3y$@ҶlذC P8_ժI':,C0iҤ>'RNRR*JͱR_mįrss1uԈi\|||uAԕ Sgey4Ĭ5Ν;'^E_+y}hfHssZX,LTDEk\wE ܺYcFsac.A3g|~% gfpO-*NP4222y)))̂ cǎa޼y>m):q9sBhry Wت5%J, ło}S1)**׻ 4;y򤤙?# <ϟ4M.ZH6!9|-sUS Azδ~KUۿ?)--%v;v,D)? v}zϤ,rUF /z' G{ݜF/Ȧjl6R\\LVk𯸸̟?:R^^N6m|: dƍP6xbb\ȑ#ÈfVVS]]ͼ+B3# oePYYz1IM/>(j>ZH … CbפyԩSgfUUU!8.PMbVoԨă蘣 kBϩUd{;v@MM 8g-RRG's΍n`{0[ σsnCmC&)X}޽p:6l}aǎX;;v_SYY)lPӍ]]]-|ʕע7XVfrI4~솆ϙ#ZEkf??ZG=1m6ٽ0 !6H/>>D*+HUU)//Ӽv; JEE_"Djs ɒzcEmm-YreȚVq,refffJұ8rJ9͟?Q(gM%CI嗢j(dHff&66m JV\INrrrBfm2d?گ$W0C_:49)e/1|UӧRs\SjVX,bRҥK$e8}4l󿛞g7N6nH PRR'x/rȃ}v>}ZԩSaÆ׉u-hRUJb%Z͹TUU+WLrw`׮]iVR"RFgi'^t9\H5>YB,=x= ,]>n7nv={ dhrp8ȟgL2%%F 5!+!WVZ|Xxq02Dkjj0w\*ҊiXr@꾩YNΝ;|ϿO&MRUYYYLQQlAػwoO'$vl۶L0< hJzC6')--%;vpEտr׋jhhhϏJ f@jkkIyy9Z$//vmxk׮"+dv@2V њ8 z~w\׬F <O.W]Z\.X,ѵ5jrss{>9[ʱ%ZUQ#Q)l߾=L2؈;[nxSNeF&RZ#jex$ 7_8NS"aK/Q^TT_WLW=P?/RpFoJNw )\bGsϟ?&ttt/DKK Ο? & R83gfV0A/zeوJ)и1AcQ3կ>w9 j'*n6q\u\HJJœ9ssN{g\ 6L6T3TWWG>-ƍE}"yyyQ_F}r~RV5G?7G8Z80)0$99Y֚a>---軖Z MUڻ~ж(~/(S,D?1N޽{~g g|+'+qn Iqb?+1aVVv̡~KO{t:8QP]ץP90`0*A0ϷqTU\WYL tͲ6޽{x)InݺU$?ϟ|߿'9\ X~}'>}"Ϟ=+rkkKZJ>{rI̾ {{{e-ۻ۷oCr B)mfpnpF|y$~^ͣL8!ˉs$7p~ $sPJKh-IXct:crttD! XOo.u^|IlnܼysmZFS~lb_zm,> ,y {nȹ-WǏ{R2k⫀03{Ay.Vecӗ?p8,!wJs~6S4l\ܘ, E,@$V{.>WUB2uhq>jk\6+Ko'CEs4M+C(C4ޟ_-Po~2U8?8^TU5\q&Α ~%5꛲%F$U@EVvwxŎcܭ-[e \0tWv$mCRԕmi L&cd;0rW *X@cIX( QNZ,iZm0HeAnm j dh (m2a(uSU ϧ&~7/lnj<>mt:`YV]]E⟚^qiᆪnp-c Lu+3<`YVp,lƺ\Lfy!a^F '!Xd2"iQkl#^֝IENDB`CPU-X-3.2.4/data/logos/UMC.png000066400000000000000000000473221341671471500155630ustar00rootroot00000000000000PNG  IHDR}sBIT|d IDATxy|T:N6dH0 hK]i{?ŭz]*-ڊ\Ūz[-Ӣb+".(R),1 H $d2YfLN899|:̜s>3|y/LS8J@^gcu.{aϟ`0ow8C { V{I>$4'HNO݇Raק%' O!3͏d|ғ1.'- ph G tPvt}B~Bn53 C/]-ҋ4=ڋ=wm]}GGO?:}G!CqT^vz22RG^f2ҒGAN*r3R0zT r2Q'cLv*Fgxj^t$ߩ*2`ڏ׆Ȩ$dnzig0"yMjHms'ZEp%=h 1܍P-= I0zT &NG ' i1Y8-]1Fr˻$Ob)~kSܴƆEYu`4\A_xj}%yu{%Pڏ_Ի^l=xB֎?y|>c@WO ]=1N<_ ;KrGv|E2iS N~(!W e XAKGZ:zEEc31PYEy{j0/($Ɉ'z9I>QA"!V6Y8;߼q9p3賥d`Hh0<|~_ԄXMks]cpG)N:P11mbLud;>l,[;1?MUC+!,>ư{*0TݲǬCJ? =M#!lj'ZT9h4ڽ]q}q0.CՓ7"8%SƏBYQ.0u|DŽɧ=Bpf`@] DPMX@dU_ X"<$r_G~|[4_N?lX@ͅ6s;-yڌz(ձ_rɶe Fe~TטM wҮ6аOr)%4؄ݏ*vf򤟪0ywOn~sd/+vo݋f'S'da`(B0r'D`zpO$-)ƾׂĭwBg}U_1Fx$zs$Z5CFEXH3^K9qb;ЗNzo̅?%M7o qtL-oBu᣽Arr5zx22iӜY_>M(yj}%){=&)Ź[/;F"J EګJ [E9~[PEYqxh8Q(}i+7 A%mvWGD ~=JWڟi6ʜ])7$1'sIDBQ梔Cj=I9 G/W1D0!~\vܱQUk9*FƉJ tLɛ䞗v%2\GkʳHoK1L ?iV*hl2'TISGw %"ԠOLBeB|K[6ZI,y~x%7(`n]|X^OfO;ML? !Bk]cxVy2HH `X}ol%([* E<=^]uWwWՇe?" '*g  a).S|Xu "^X=:5-BUZs]2ߺI~pn2waE8'6HcV8ɫQVXD {;S/W1_ ɩGѺSaS3׺a^ho޽xkީJSi;W5Fk?0#$s߇)el@#!:+V?@Xt#6o3wғhV_%|u4w*{i'`(BrɣVޭ 2s{rLMV2bBO76ٓ͝P}NsJ$GWbJ}^VşkYL({i1ꐫF,ɹވUQ/ێwRsJNOJyS6a~|QjqX]PB.rAym<΁pjz7 zq%-ۄ-a{/|mzR[HX?q]S>g"?+JJQ[hw!6E _\Uq S*5 ANJõyz̞Bms)`ʹn䖠SCrOU}z)J L7 i~NCANf ?+cR?*cR IK~Т^ i!CGw =ۏh/m8уphn=Μz' Q뵉cJIIePY69eBI"|g5~<5ºώaiT[pXՅAЎwnBIoVmsR~J'dc,clPVp]1:6wۢ=64FqGLmJ Ze$azaBD߇  2eANiB-L""n'G`3`X6:5{lR>C?/\_5Ўw=l S2_sǬyGm:NjODx;QЉϫ[LͶ.~`=P1Ô sI˷IRUahHW8.ܹ] ],,}}uW׆Gڰ.Hy 3OM\G_} Cr&Mbv^zlRL{0[tg?!+گ|tUuR[̐Cͤ\Ox&g`AYq9N+³ll?LvT|r5ʗjeEPx%-0E.ԉO(gkrʀРŗBir_:KvDH3S菧\*#vWLVoJuZ}AuޱVJ\wis 10{f6df|~C'4)s*TwΚVeM2)~seʸ4E||V0 [ʈ-V'Α;sUh(CrΉRDIljό|{OS+S5qCoªL>sJ )3l^Y 1}*.13upZqCYjjٮv&f9Λ<=F~gY#;IPԔN~V*~1eY] lf[//ܶe*Ű/(ҽp;DL8]Kf;e[̮q' JY㩖-IZ?k5%HF\oG{ <26D9e3Qz VpcHI=ǝ[jثLQX{@Av*nteQ ș(H]LBvִK6FxeaYmd}cJ4KaZS8J>124)6ru.ntjo2i1ĈVUC/$ ^#a J!sʎ4?|cח!]g1RJ{-ʂI〇Z!ynpݖS=K11RNkCjs\$V2݉ӱX}m l^^dx=ζl=S6OWO 7^,+8kMV')Dl-'U¨bI ۵q--5d'GU  } Oj–e`N a nWYQu[;)lZ-+O}P$`;yvWC];S;#uѳ>z2lu.=854zdxyX}ӂ0ŰV@[?(C 8fd~0-6xMDmVX~c_l_V%l. 3H?}ljπdd$T1BHo?|K{^娰RyIOJ,f_sDaSbexQ#a%I8¬hoMR[V8e +nߴڻw'S%ݬ&΍I)aduOmgA.LYVK kC 1m,'o﮷Oϕ=o} ΄fD2yS`C() Me 6L0qYivWO)[JZp7V]]}R%iI:6kّ- ȵ_]_`(Bowzc<81#6M  1ܙ?qZ7^-c֜4Rs<X["<0(OjVw+f,r_)$I?2*aUQcf  J4D7LFhhFS8Jr-S}gbEB-9uRrVkymD'[Yà՗depYi~cvY=VRMFbUXsFJ޼H)ba&OfOjpNd7;ݏ@^'S:wza.w%%#0Vzbwߨ 5vW w9x4s`;9d,2LWJ\YQ(y(PЇEK ;*B.~mH'$䕕xl:V6h~ vl>f]>8>Ʌ?-$r7]Ej?t`7e8=*uM|JWhT0y}{ _o6 u] SvgJolTs+vN̜˒1LI2 ,vjٮdI|#y'xwO=6;ޗݛ3C ݔU=G?a_?͖2Pv(g3v*0'[I̐I?t<'ۋf N&d0dB7%A~Cu.H@iUH;"֍oTkCuKV*&* '#y>-M<Ca6T]ṗ5}n<ņS:!ŷJ%z)e¶S|mUwZSBOΞ;Z׵8;Dhϩ`H1lVKf It¸H՞K Ok\ TXc!6MR%^=bd~<>ӧԐmOv31;IPbFh5*hLU`$921l%Qw$tרzjM nT4"pys v>aJz=vuie'^*# `bw S(0sv$Nor$SS ^a"p,yKS!Ńkv`[y:1ƴCK8b/WK,K r#aK) g&KS8ʞG + ^\0jMV~ge>Lݼo(3sȖ)S`tX *^i§I~jY|} ǽ{gY[H@iō=3N9eNBaA3I"̴SnBi[?m'l :*GducfO Ld` +!m8+jade@#MU&O?{a?>׶ H2O*^ .P0Ǔ /nu3`wy_FJLv$ɓ+*rį.)6[+jO^\V )~Hpe"RIU 'FGžH%)RBĪԒLVsv-Ƃ;Jζ^*:IHolvWxRЋ0ݫ C"2MFV蔭NvSChkgZfd'v&x S29!Y$h#@@s`ZpJacݼ:l?Lo?L^VqbNhS2bAhvWqT ]F<BĂ0{t~GOfruAs >{UH# 0?Q[9}e[ϱ xmr쮂s$dw Gm`ÞydyP 7)~syV Hs59 8b3af$> #f,/ zr+lZm EHvz2ʩLIX/aP/.;b!: d']ޠU`xg& !:%3NCw1K#pdrT#9n!}%^Emݒ8mJGl!=}v c쮂x_GȔ핕z^ȃpUavh`PnfrEc3֔  $49`F| FtĦ UVzcx/ړgBb<'Ǯ/S?a FKgVãCr6L0`=WF|8aEv7 Rf̝w㣽AoTNa'v9b Q2ylčݽB6U>v)1ypgu*(Ou+q2S8MaNp, ds^u異;tLCaQF}Y9]msywݎBz߱Wxk-Ѿ~. z"ENGꉡ=gw5.By:6` fq9}Pڵ! ]jه}K;`C?;GM%Z[>?,1l݀kDcX =xQCao]ॉ*BhHlJad}*`>WDuɺ4!;b IOE@7]<([t"l5 BZOj;1{iV+8fI88f3_:S< HKe6BE"zb8|Y\BGUʟZP6%'kqLR6mnUv/5l"󖾏L`2NcG=L4V[kdVΞ~8(*x5R!Wv ȇӌD0JH!wśNg~V*_w6B}tB䍳4R>jm ֍n nOPdD;x gg*A+]=16ȹLM/D"^ r99Ӗ:YMC4sYekuWp[FlZΝ*官5jFolj j0'oWaCyب:%'m)e= xn!֙Ε6UcgMNHqTzV"mG*ⓓyd&RDGlaAwnG8b=pǹ(oFco?$;p(̰-c$WLFѲ3!l.$OS8J#OowUˬxk?&--&.كJnՠ&̟N~g){]tnJ8ktTEV= ?aUl{s }GS׃B^VJqwFl!nQ} s˯ikhPjAϼ W 窍0wm"lpGzJ(4jD}(o> >;'6"}rp&̤&>,W_бNELЂSr^ufOs#XCi+kfrw.bɽkJJolkb7bW2sA6nH5Dqʭ/Cm?pjjɉW̛+knjs%l+ϴn@8Xu9m&~03M; ֹm[v?=|VGp_`U+6D_|u3[*U݈·[<ߙ&rfPF̣^н[jȬÚvW5}EM7pʔIaZ|ܭt(uVD2w֋-ğ4|>q\/4#cU*{5:Xm ;{pʭȿ r˳k]<{Y~>%sKRF?IxXq(񛮞Bz7sK7bvWu\5k<6,ZdK3MhZaWtB+Y0!iaIЏLAVfד'?+ҕumdHAnFMr,yi^P0[oTZfG~y-ۉ#\ݜ\g!\u&jbq[6zOu.v}_6n 8|}J>.( TIuc'<چ}Sۆ=!=2DK*>-.PG){=q'TՇ:9dڃ~2Rpy\BNy*nZʛfc#L+ʰ%$jّSnG^VzN]1K-{-=]K5J :PЁU&MrԱ?m-ITIym*¨iDym׵䮷.[=Ml"NgG\ll$TΞz*4=S"c-PjlHH()wʊ׏Ը[O] ۰RܾrGZqvWc?< ) OocoJ sKFcڄlLr00׵!rx;j:p(؁ƶnT X954X4[%/:N^)aWܲ [72nZK.>k.$z(Vp=}l, !.2 KG8G]Q46{hm9yt>iԽͬO~`Fl-G~0vI|M]/mUɷL =zo};kZ!盖52yl&&D߇@^rSQL!+=y0RVjEc3p)%P|O DEw_?B]}m]}h':zl"֍h~uxz|mhcQEɉ?yW)r[r䡴NkK+XL\1k]r)*M4yݜEϸ6n03`=n[zgɓ`;?MhnEԞg[:> U_(5y~ mJ<x1e'c7щ0F1ޥjb]wsqF) eǻZ %ln۲f&\Dk<2{\s[҃PI^8GdeC؋vşv\ 72R $Jn<]׈9fU՘VVHۭkfr{󦎱*`] _[ۖhtwM d鹄p=Fǫ-4}ZBؑS;}Yu3n9GJRխެn͈m+= ^ʊmpn9YvWGE+ eRQ^\z ?/IX% k@C2=sGO;f} sߠ=BK c}I߇ ̟^96r;rJ3KMN\ر4?U/[HhjσjkbkW7xJEqanjz}^"]-=^c5C&(gp]}V_<;Lܢ }gdR+UGl!})<,S|,SmXr1W+pŧf&f$"4}8q\i@ (eEy\r?W~2aFWR>}xYXw|]֣WaP3~/~w]*;cߟF&b Z{A#37Z!OYQ#]| 3'.v\r~wG֮]Z}I|Nge]~}hcq>;J~ 8 7qVat\8ꘁz&DŽW)r[ދYp8j}Yip[q"E67kێ"ۯԮj0pCNMS9>ogŷq<=3OFJ_7sCTPبm\t'qDX4˔0R-0%?++\\/I>n`.:[}\~r.Y^#0c49¬DvQh DM١T6;_؉mfގOc?%l(NAeUTXl,~38q֬-:/* ^Tw:9iÆ;yjrGf+ʯkEaB'zn!?Ff }i?[{}OWZt]6_\{x#vq'S<*03$!Tkۻuش784ZB2(ۧZLrz4ȸ2XP~!ۋ lCc4oXP6[{`'f ZlvyS(MNl%O. @+e@wpspɭΤhl E]Q 7%3p#ѨQ\XK ^xyK 뫐8BgZwne[򽹅?[̺{ O@٦&xqԱܢg5[kGsP=7_tmy_Bnma+Jm,'˃ش{jCC[k嶶*f- M9`0Uxe[!CvNBba4?+7??YpJܺ{<.h[M›׍XyL$ReX}5R6f%7 & =`;ri'U'pE x] 59P8zg5vք.a;2?^5{tP(YO+Ⱥώ/r9y3ob\N: y-2v$kfr~wFSr#T.E 0>;܊O- F_UaR:!gX[rB30wumx<Up bG&N?nw(2\Ć7pqYItt3jjҩӯdUGa!OD+Zs];3aOe3Ga|T_6:7g.R~; W.O`]t%nY gqFalD+W|}vlۈ-%s[0"8k\si(9,(6wī  EH%1amݔ׆VoG6T ;#,EoHI 8}\&ǎ0%0 %4D^Q&cu"z2ו SyR3F)cpXP6 "'КB.`0bKe#9Ў`'jNj@(:mjFG[_)~&DIA9()(.Yqyj$^ C'֍ޮsbB!|0mBM31{r*v0!+LpL`0 `3oG]kPԉM9ȼK`&)~ 3P8:sMi(ICIA&?COOvzMˣm8De]WFkgqa-l5EALr^>^2qUr0mBNY s`0 SYFN(ۢ{F]khMh";=cS1>7 QNA 7cR1iL& S IuTH=`(Bjp% v;<堭P) Zӫ(]/H)jӓK4L98`&1(+t[d0  ~:c-zF{4ho ݽhCkm]}C߷GchAG4fٕYHN␑!3Տd}N#;=9~''!'3)dJKFf)&*p(vQ :NFQԉ#}8}S;OQP[׳ u ]JBa~䤡 7 0%dQRq8f`0 rxp\N:stugw2`ɨ}H?@R,56x! T%$l`H/]G~41<9Hc[7nr K'K(GWϩN8)܋ asBIT|d IDATxymU[{{sj I-U Fj0hF1Y f0m*C9J%䏤\$U1QW-%4  hhGu[^y={}}-]߽k&+R__w;8}&m޶`Kg3> v4^,)_΋K:*~ [~dsJş1@@k#2 Y& v>ﭭ)ҕ8W/}{9އAocO]C1>T*P*nx{ލ|w?wMϹ4#ܸm03x>o K0vAN)Z!c;X\3)m0w Z"p {`<*b^HdMť4d {׿I, eBYN~1O~ \9٠[߀##B(n3;p+nkE;$Z߶B$*"t|[dMTbbf32RQsq]y|%aE#*IAu.I8# ;w0h+ ?=زpӨD̸㮻s? ~ކ O>|b0my;tv,ۄK%_ s+>O7kJ:uus.(Ϙ"|,pvi '6 3[hcBVsLjh2 t'~_/#0_܀&Oc& ԉ³n;nW3Ж*ɄpzwRD͌zD 9 -I!5&: 3&转D&~c9&0^Zeth>Zt>ō0p cEl M{7+/~7_Uď2X:kHjQ{:H5vdr$cV2 N&@$A$ S3-ӚLp s*.@FWmPO̾>*J  esk.QА؛v Nk @7"n[|c}OE p Лh/D:7`0oq]RBI-L?ZM#&PBB "QcfT2Ktn3D؉(5t6SӜXmlxɀk5DU7!!gLw! /nGsܛDrꄲۮ_|Y͵q{J=ߗ"}ZDI>Jݼ8 3dh u;jk}m,&DW`0} b}R;}Hg?u_<ߏ+G[u) Tyk @FA}_gbn@TQHuQgn1w;6ⲇvL&`F RfT/;}w@YT3Xv&ȅy2E!xqn\: qXfԁ;_%cd`u޻:e&0Ƙg\|[GW Zb6Ck`"}D1J܇R5Yl`8 {/S0MRQPA[:Z1ϳ:aVuwOwxKm3M{b;3 muLu'NO1}#Y6pJC3khʗ5ܿ~}'R)YEYf"A,~$ƀha3opyض!jcǎ_MG?70RkO"HQN,;kDQD_w:Ew&&|&|Es]->ynh%)~*h2vCTUufͮvμ0fZ S;;h%4݇6k1ha;o13Zq݉p z\t ]w j-8<<5,cr% 0jvbEw܆ Kԗ'G)Evf{6o( EE)`1qzerA01 )in}1N@R }-ppg4jBh[\XXר`Vx +"!+&_=v_$1<9lOVkDۍ"f@)Oq|J I5Ii\/DbrZM,&4#!!l (:WįJc*5\v5uJ.hbQJ D{=/Ԃ޶nW xM(}^Aenwcv(B Ǯv Z`w<ę`\iwIõw̟*y;;VIwo,LrG]^!w?ԴNX~PS!P`W&zO,GW튫zA6 M3TPkz҄ +_hP]p3$yV)UmLMZ`?3(]f!;NdX$Ⅵa  UӯQmI'l2@Bf`@`ETd%]͊ \ur=z3({eZE9`*>7 <R|Sq !7;KZPCV9kͼ2%sFTwmtK3`cQ@0\`O㜽9/:MPOŖ[DgM(y {'S5laݺ. 4B4^{- b;(iI)!eŸE>k(BJ0 NBM:QU&A4kǁwy$!fҥR$=Խ 72a9 }cC i2PrdZw5=dC"HsS]M00C]V HC8Ra0Zdž?je2fb `LG.ВC*":Z'l[ P4VqXD +@<)5@n5JvD,u j4 kӈʻrԊ~Z+E4(ꏃI q$K @l)cRkR8كVz-RX"IvհvhN[FN).Bޯ.D͇ML JH%1D' (K$:~O\ˀ[tcyfd*Rö sW+ Bz'Jr3Y̥i ̠E;TOj=UpGN`&-xkVߤUl CdflL2MrF1j7u40`AOO] @Bp Q}dCq*>LH4F{o߃KPRPz-B6h1%ʀSx1,cxZYn|X3.i}2#bp dg Nٵ(qɤ6]@4Hvڌ`)r*$/_ ur^rDeuLiL$TX!;30iG3VBEpHxntB X CK$VfKXUƗ42{n[Nz#6~xa3aPT:!gy WNo]aۧA:iÈZv YrNj/nEh^gh ă8RAhoL`Qua++%q90ՊLK& < h7kE@)= 7^:_9z7 S߸}s|˺&&m2X-[Ynk6çP,U((cf Ңv${?],8\݁dhe>eop7*> R-u]ǐGC`j[2(o}!nO~׿_/tQ>}c[o|V'igޱ6ّ5_j/5+ u:˯.k]+:EP-A$b8b*SVʽ,`.x>袙EMKc{ZuFܧ_2FAȹ'n-=r}^ x'zlT mučnd\G@; 60G.#|r\] ,ݾM1R//uP8\|]9#' mMX8#ps|y`;WQ;R g067FeD@YbvvO{&TsW)CW(zkɍqZ{!4$KbU-86-/LSżZ!3x|ŧO%GZo۾_x44,SuL 1sK;&``~ڮF3pS_8f-/G$%c,Uc00m c4fSvp Y;Gq7G>ϝ$0-/_ms_ B2|J,h7Oݩ!*at{YnH~.TWgkړFds)enk Ma)pVT{?D`c}d? C*KPkbἽpn?;_̗mZ-Π]: tEb;Y\l4KdkB…1L *\U `I%R&(Zbe7--hjom{LY8t ZJ a1I̮fo|tum#;~dzt")JVƉm lmS;>b?\2ٯaYhB u[`F6H13& A^GcnM~Ҳ:vGtu}{uGHw'D+, 5I} F}\D3)=;Pu??(^{pNW Dȴc1 I

    ^;m6Lc^Lp}SX s szִEZpFR<#&HYr #q43PhS[ YW];%`]j7SMrLZEEɳ -w ]nf83U.DT5Vti fx0?'Q(pa~/f*Œ g̠r"Z\Pk?kE4Ozf%*PFWepw`RWh+Xz:Azʐt 4X#8r džcnE7( /4nz #)5Dh#q7 tH>\ UGsJL1tmdbAV{-~j暡˜ٲ|pubI\·EQQ-07E3 "B6wyrj?vL,Ё Ϡ6cXy[}Nɳ#B-tAgF[( SYsv`1;H9ߟ2Hht$I+0\ƠX Hhq\HA]:j~~䡛*Lu"Kʘ@Ypk?Jm6j&"Hq'从&$,審\<[Fu1e;u@ Ra;4`& K[5Ͳ$a?zDM>MZCOgAHǮ9۳06}0O;ů) j1Crm#av3t{͋}fYu $ ioE C_RnS,F(j f[k4/0GYx_0` טŰ_lrdL׍}`N*YvrvN{%&ߺQc1<y?w2삒Ug*7-mdęUWM,ꫀ;VNi'Q{@u62tP 5)gk۲j-phX/;cr|A,,](c^nIȪ*hAg{ʴ*kcj-(/@T軽܂ vƬZ=eL3tti&^6 ff& n80&yy X؜C7AZXJ6R[ $ µA a(cc! ضpiL$09`H֤p]a1CKJ>x: 9CJ4$Zv)@OTC; A2+ýXVb s wx'"7#nKf<{P1y]mZ>1gaK",hR$}4p ;50{< 4 dx5 T&Tw*b*]`\P‡3,Ͳ1}OY=zIIE1b^Cv{'ܒ{aӇ=䀬؇wf)Hܒqf*n!J@|I'Pd[i"ȆF,YV$u0@ 'xvRsgYSk-j{Hf>kYako̺~`(y(o_in8p9!&ߧpFqz)0 a Q_\= 5m6h QmЇ[P?/  zdg /~%0ZяS$yLj-,: q}Za*gn6WTSfXHVOF~`[n_;]57pMf YϋB\l5mmU:nRlJ'5N4{º$ܚXi;V1CCWs{B쾒(~}8ATgcYbȓmQ'{tnq>"Z%+˨TU׵-@J3&yA>HVބrFID}F; Znŧ:Fg!P$ "?v W&ƋklRn'.8HV`VrL&Z@/[1]46B V&n)9,d+7 $WE_R!`µYSQix${뵒a)[6RJlAҙQkb3; e'I t; ~ I0H>}F`+|mAĔޱ)"#c>u.X4G}΢B)j Q4'JT`e:&MRQ @S,i?Z"ULm@V11 /;A Qo0FF lnei]sdN(vyx7m YݯJ?Eff;c+᧲ϐcJr%(7a"[Ŋ]כȌV3Tgb2]-Zԯߎ׸)`E>h.^q٘_n#j(̦cfd+H![P ]=UIL.HMx-ҏVU't+"zx6VWлnnkJ "bÄ-ŷSNu U N;cQ+)Ϻ f-O'dz8YBgxWZoWSX nRJ{eXZwhe [J#,@5s\ѬmQ"+&8zK0ٳXA{đ@f Oþt>?n6>-@~۽a0kf-_Ci4pfK[GX83pƛ9ql@ wTG [$Ov5%]݂ȆƚdcEY۷T~{K7MA{h[5d]zA8x,j}?TQXwFYQܡS|d?u~\|iݻE*i@J0PgMCp8fesf]y2!KdGux'46R<'Gpb8'][(.vp  R[:)? _(Z,{p?D/vM_m^<τsf"Kd0\ 4u!tܒ<уEam2?_ݚ^ˮȅ C5_`+`=.kuA EgN=4yOdnж.B'H_rόU"tȄaE +~39HiZN`JSvTR _kqo%KIcz )խIgTWw4-Ͼn;׵|`L1d%'`?ް'VТYiKHmwE"? V=!;@QQVSJ4e yFF!ܰ!5$N5gxxI"#\R"ݤ?/f=TU*g‘Z+6G5`0#U̖ p-{?߇pS_AI|dlSpWk%^ŐlkeBe sݭ22m^JdJ#"i{KۈXPA%6;= L_T$"ehk($Gh)jQS,7Rgy9 }׽gxn͑'^ ty}+&j\dM *WfYCLcfT=N^C(nLq%UkjmXVO[eK#Ea] ̈́+!CpB֣"2 O{>g^B=[YJ$8kpST[gi֎dwydڬ =tt݃cgT*Msd*)%R.]a9 )+@!d]ՕrbuɼnholI5efadW;g?oqfH1ߊ7 ?e xsr]9|DγZģ6 6#ݠZm:~rβ$;9#tf E/#[KA%UGdlk>V@N{ξo[*,b6 `\L{>:OnjO=.\ٖ{qzU-*PTMʆSB v*"P 1Y(T-:L^MCr 6%!j ftZ<<% ڊ()@XdU Г%r:q |O1Պ*GWqoYkpǽ3ޭw⹧G|+/_Ϛ1ލգ+hmIe¹ Oܹ3]m ̲}U3V$Z4a,;MYsk4M$Wȼ?6E;f]Riҙ: {E7h,hevPQWDbf̳œ~Z8EǑU]z[o}>8\pS<7=s} Wie6|[_j,+8*[нGZ=W*0^~.qY J\t[ U#4s51_jJ-,@`4|2:4ZYMijIPaK ZEڣ?#j)g)Ysxlh-\,gjNV MMoRfKa}x~>x>>˗ACadE&wo_) >D[GE@mB/+j%U>B$9զ"H{qʑPkJpbx8^NQ"`}xD6GWbҡan _c}d!5X̲O4\0kg @)"}*q^ Zzkxu IDAT|pJ^ߌÏ3[[pl==}/M7>?;rzBuV:88;<۔쐱:"!qG zG¿w,鲂VO;NݤVV!Bo25ڵ߬fw#x?Si$4[p=ChJ:skhj.ÿypRCYWP]PC| (V=eB=|J|n&:T6^-:)ܲy45it5ٍew/|Xľ<3.Ы1 .,2k̀tKCUd'\=AO%2V2,Ia -M3hx{c'PCx w1jW_u:,Ngۿ {}ɛ AǞw#x?6k_:~A$Ó3{ű]ӷ[sbE]Q=uJHV Y۴H`-YQ4|I8a`Ȟ|7Zq IΤR)"uũI$ [ g*&TWnijk 'W.]Y?.5bOG?q>{'z!R+ǖ2>Gkߺ"6YIyO~wq%5J8$rF@'-E9rDEK`ٶ!e ]4/_ųo/x A߃a-5AF9(& )tU~syPx PRw'?y\~ߙϟ5,p)O_g\8TJ҃&\87x|~^vxs7߄jbZZk, =QU$4 x*nd'_JVAQrjTl kJA-C+ivno«TFE5jAҔ4Q }ޢkh䩳Oⓟ=~Z|*xQ*bQ@' ~XI/b XͿiM`67VX 1 PM@%3,6ϭתbm$ \rӭ_8 uI~RA@QM g4+ȣ γ曅`+iZހ܍mW7o(|JtA t:`yC^vsm{Ժ&&LǏp͸/W?AЂKyWzs@#iX\B},UP%ͲiiV#4K $o74NEuy|_ !"-x{` !<'OރZuJ6Re.Ɛcr` =TF,/PV$PbcƤSZ#Yŵ;;oW5݄T+MC[CW7܂^q&; O9*> +<}tSOcZqY/=g%)eu/u{-~KGyAUf4}} :0{Mu (o{huR(c$=۽~[VPV@esz| u߯vJ-ZYkhZ,yv^L7ޡ&i&p<|,I\pJ#𤌋V2ɡ=qy_"+x{Ks|}wТm_|/qpx W._x=GtgN='\S__>=Ǿ?GĦp%]Ϣirc ^Tٲ<IENDB`CPU-X-3.2.4/data/org.pkexec.cpu-x.policy.in000066400000000000000000000052451341671471500202320ustar00rootroot00000000000000 cpu-x The CPU-X Project https://x0rg.github.io/CPU-X/ Run CPU-X as root Spouštět CPU-X pod uživatelem root Spustit CPU-X s právy správce systému (root) CPU-X als Root-Benutzer ausführen Ejecutar CPU-X como root Lancer CPU-X en tant que super-utilisateur Pokreni CPU-X kao korijenskog korisnika CPU-X futtatása rendszergazdaként Jalankan CPU-X sebagai root Palaist CPU-X kā root Uruchomienie programu CPU-X jako administrator Rodar CPU-X como root Rulează CPU-X ca root Запустить CPU-X с правами администратора Spustiť CPU-X ako správca Kör CPU-X som root Chạy CPU-X dưới tư cách siêu quản trị. 以 root 权限运行 CPU-X Authentication is required to run CPU-X as root. Pro spuštění CPU-X s právy správce je třeba ověření. Il est nécessaire de s’authentifier pour lancer CPU-X en tant que super-utilisateur. Autenticação é necessária para rodar CPU-X como root. Для запуска CPU-X с правами администратора требуется аутентификация. 以 root 权限运行 CPU-X 需要身份验证. auth_admin auth_admin auth_admin @EXEC@ true CPU-X-3.2.4/make_builds.sh000077500000000000000000000147661341671471500152210ustar00rootroot00000000000000#!/bin/bash # This script helps to track build troubles and make portable versions VER=$(git tag | tail -n1) SRCDIR=/tmp/CPU-X DESTDIR="$(dirname $0)/portable" VMs=("Arch" "BSD") EXT=("linux64" "bsd64") ######################################################### # FUNCTIONS # ######################################################### wait_for_vm_up() { while ! $(ssh -q $1 exit); do sleep 1 done } check_deps() { if [[ "$1" == "Arch"* ]]; then LIBS="/usr/lib/{libncursesw.a,libcurl.a,libssl.a,libcrypto.a,libarchive.a,libcpuid.a,libpci.a,libprocps.a}" wait_for_vm_up $1 if ! ssh $1 ls $LIBS > /dev/null; then echo -e "\033[1;31mMissing static librairies. Aborted." exit 255 fi fi } make_build() { wait_for_vm_up $1 ssh $1 << EOF _cmakeopts_install() { cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr -GNinja \$@ .. > /dev/null } _cmakeopts_portable() { cmake -DCMAKE_BUILD_TYPE=Debug -DPORTABLE_BINARY=1 -GNinja \$@ .. > /dev/null } _makeopts() { if ninja; then echo -e "\n\t\033[1;42m*** Build passed for $1 ***\033[0m\n\n" sleep 2 else echo -e "\n\t\033[1;41m*** Build failed for $1 ***\033[0m\n\n" sleep 10 fi } [[ ! -d $SRCDIR ]] && git clone https://github.com/X0rg/CPU-X $SRCDIR || (cd $SRCDIR && git pull) mkdir -pv $SRCDIR/{,e}build{0..9} echo -e "\n\n\033[1;44m*** Start normal build for $1\033[0m\n" cd $SRCDIR/build0 && _cmakeopts_install && _makeopts cd $SRCDIR/build1 && _cmakeopts_install -DWITH_GTK=0 && _makeopts cd $SRCDIR/build2 && _cmakeopts_install -DWITH_NCURSES=0 && _makeopts cd $SRCDIR/build3 && _cmakeopts_install -DWITH_GETTEXT=0 && _makeopts cd $SRCDIR/build4 && _cmakeopts_install -DWITH_LIBCURL=0 && _makeopts cd $SRCDIR/build5 && _cmakeopts_install -DWITH_LIBCPUID=0 && _makeopts cd $SRCDIR/build6 && _cmakeopts_install -DWITH_LIBPCI=0 && _makeopts cd $SRCDIR/build7 && _cmakeopts_install -DWITH_LIBPROCPS=0 -DWITH_LIBSTATGRAB=0 .. && _makeopts cd $SRCDIR/build8 && _cmakeopts_install -DWITH_DMIDECODE=0 && _makeopts cd $SRCDIR/build9 && _cmakeopts_install -DWITH_BANDWIDTH=0 && _makeopts sleep 5 echo -e "\n\n\033[1;44m*** Start portable build for $1\033[0m\n" cd $SRCDIR/ebuild0 && _cmakeopts_portable .. && _makeopts cd $SRCDIR/ebuild1 && _cmakeopts_portable -DWITH_GTK=0 .. && _makeopts cd $SRCDIR/ebuild2 && _cmakeopts_portable -DWITH_NCURSES=0 .. && _makeopts cd $SRCDIR/ebuild3 && _cmakeopts_portable -DWITH_GETTEXT=0 .. && _makeopts cd $SRCDIR/ebuild4 && _cmakeopts_portable -DWITH_LIBCURL=0 .. && _makeopts cd $SRCDIR/ebuild5 && _cmakeopts_portable -DWITH_LIBCPUID=0 .. && _makeopts cd $SRCDIR/ebuild6 && _cmakeopts_portable -DWITH_LIBPCI=0 .. && _makeopts cd $SRCDIR/ebuild7 && _cmakeopts_portable -DWITH_LIBPROCPS=0 -DWITH_LIBSTATGRAB=0 .. && _makeopts cd $SRCDIR/ebuild8 && _cmakeopts_portable -DWITH_DMIDECODE=0 .. && _makeopts cd $SRCDIR/ebuild9 && _cmakeopts_portable -DWITH_BANDWIDTH=0 .. && _makeopts EOF } make_release() { wait_for_vm_up $1 ssh $1 << EOF _cmakeopts_portable() { cmake -DCMAKE_BUILD_TYPE=Release -DPORTABLE_BINARY=1 -GNinja \$@ .. > /dev/null } _makeopts() { if ninja; then echo -e "\n\t\033[1;42m*** Build passed for $1 ***\033[0m\n\n" strip cpu-x else echo -e "\n\t\033[1;41m*** Build failed for $1 ***\033[0m\n\n" exit fi } [[ ! -d $SRCDIR ]] && git clone https://github.com/X0rg/CPU-X $SRCDIR || (cd $SRCDIR && git pull) mkdir -pv $SRCDIR/{,g}n_build cd $SRCDIR/gn_build && _cmakeopts_portable .. && _makeopts cd $SRCDIR/n_build && _cmakeopts_portable -DWITH_GTK=0 .. && _makeopts EOF } stop_vms() { echo "Shutdown VMs (y/N)?" read -n1 s if [[ $s == "y" ]]; then for i in "${VMs[@]}"; do ssh $i sudo poweroff done fi } help() { echo -e "Usage: $0 OPTION" echo -e "Options:" echo -e "\t-b, --build\tStart multiples builds to find build troubles" echo -e "\t-r, --release\tBuild portable versions when a new version is tagged" echo -e "\t-p, --package\tMake tarballs which contain packages" echo -e "\t-s, --shutdown\tStop all virtual machines" echo -e "\t-h, --help\tDisplay this help and exit" } ######################################################### # MAIN # ######################################################### if [[ $# < 1 ]]; then help exit 1 fi case "$1" in -b|--build) choice="build";; -r|--release) choice="release";; -p|--package) choice="package";; -s|--shutdown) stop_vms; exit 0;; -h|--help) help; exit 0;; - |--) help; exit 1;; *) help; exit 1;; esac case "$choice" in build) # Start VMs VBoxManage list runningvms | grep -q "Arch Linux" || (echo "Start 64-bit Linux VM" ; VBoxHeadless --startvm "Arch Linux" &) VBoxManage list runningvms | grep -q "FreeBSD" || (echo "Start 64-bit BSD VM" ; VBoxHeadless --startvm "FreeBSD" &) # Start build check_deps Arch make_build Arch echo "Press a key to continue..." ; read make_build BSD stop_vms ;; release) # Start VMs VBoxManage list runningvms | grep -q "Arch Linux" || (echo "Start 64-bit Linux VM" ; VBoxHeadless --startvm "Arch Linux" &) VBoxManage list runningvms | grep -q "FreeBSD" || (echo "Start 64-bit BSD VM" ; VBoxHeadless --startvm "FreeBSD" &) # Start build VMs_len=${#VMs[@]} [[ -d "$DESTDIR" ]] && rm -rf "$DESTDIR" mkdir -pv "$DESTDIR/sshfs" for ((i = 0; i < ${VMs_len}; i++)); do check_deps ${VMs[i]} make_release ${VMs[i]} sshfs ${VMs[i]}:$SRCDIR "$DESTDIR/sshfs" cp -v "$DESTDIR/sshfs/gn_build/cpu-x" "$DESTDIR/CPU-X_${VER}_portable.${EXT[i]}" cp -v "$DESTDIR/sshfs/n_build/cpu-x" "$DESTDIR/CPU-X_${VER}_portable_noGTK.${EXT[i]}" fusermount -u "$DESTDIR/sshfs" done # Make tarball cd "$DESTDIR" tar -zcvf CPU-X_${VER}_portable.tar.gz CPU-X_${VER}_portable.* tar -zcvf CPU-X_${VER}_portable_noGTK.tar.gz CPU-X_${VER}_portable_noGTK.* stop_vms ;; package) DESTDIR="$(dirname $0)/packages/" REPOURL="https://download.opensuse.org/repositories/home:/X0rg/" COMPRESS="tar -zcvf" mkdir -p "$DESTDIR" && cd "$DESTDIR" wget --no-parent --no-host-directories --cut-dirs=3 --quiet --show-progress --continue \ --accept "*.pkg.tar.xz","*.rpm","*.deb","*.AppImage" \ --reject "*.src.rpm" \ --recursive "$REPOURL" find . -type d -empty -delete $COMPRESS CPU-X_${VER}_ArchLinux.tar.gz Arch* $COMPRESS CPU-X_${VER}_Debian.tar.gz Debian* $COMPRESS CPU-X_${VER}_Fedora.tar.gz Fedora* $COMPRESS CPU-X_${VER}_openSUSE.tar.gz openSUSE* $COMPRESS CPU-X_${VER}_Ubuntu.tar.gz xUbuntu* mv -v AppImage/CPU-X-latest-x86_64.AppImage CPU-X_${VER}_x86_64.AppImage ;; esac CPU-X-3.2.4/po/000077500000000000000000000000001341671471500130035ustar00rootroot00000000000000CPU-X-3.2.4/po/CMakeLists.txt000066400000000000000000000066141341671471500155520ustar00rootroot00000000000000project(po LANGUAGES NONE ) # Config (po) set(absPotFile "${CMAKE_SOURCE_DIR}/po/cpu-x.pot") FILE(GLOB absPoFiles ${CMAKE_SOURCE_DIR}/po/*.po) ### INTERNATIONALIZATION TARGETS if(GETTEXT_FOUND) # Target: genpot # Generate a new cpu-x.pot file set(GETTEXT_FOUND ON PARENT_SCOPE) add_custom_target(genpot COMMAND xgettext --language=C --package-name=${CMAKE_PROJECT_NAME} --package-version=${PROJECT_VERSION} --default-domain=${CMAKE_PROJECT_NAME} --msgid-bugs-address=https://github.com/X0rg/CPU-X/issues --copyright-holder=Xorg --output-dir=${CMAKE_SOURCE_DIR}/po --output=${CMAKE_PROJECT_NAME}.pot --keyword=_ --keyword=N_ --indent --directory="../src" "*.c" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src ) # Target: newpo # Start a new translation (new file is NEW_TRANSLATION.po) add_custom_target(newpo COMMAND ${CMAKE_COMMAND} -E copy ${absPotFile} NEW_TRANSLATION.po WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/po ) # Target: updatepo # Update existing translations by merging new strings from .pot file add_custom_target(updatepo) set(results) foreach(absPoFile ${absPoFiles}) add_custom_command(TARGET updatepo COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --indent --update --backup=existing ${absPoFile} ${absPotFile} COMMENT "Update po file ${absPoFile}" ) set(results ${results} ${absPoFile}) endforeach(absPoFile) add_custom_command(TARGET updatepo DEPENDS ${results} ) # Target: potfiles_1 # Convert .po files to .mo binary files and install them file(COPY ${absPoFiles} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) foreach(absPoFile ${absPoFiles}) get_filename_component(poFile ${absPoFile} NAME) string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" poFile ${poFile}) set(poFiles ${poFiles} ${poFile}) endforeach(absPoFile) GETTEXT_PROCESS_POT_FILE(${absPotFile} ALL INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/share/locale" LANGUAGES ${poFiles} ) add_custom_command(TARGET potfiles_1 DEPENDS ${poFiles} ) if(PORTABLE_BINARY) # Target: convertgmo # Convert .gmo files in a C header file add_custom_target(convertgmo ALL) set(vars) set(moHeader "${CMAKE_BINARY_DIR}/po/mo.h") add_custom_command(TARGET convertgmo COMMAND ${CMAKE_COMMAND} -E remove ${moHeader} ) foreach(poFile ${poFiles}) add_custom_command(TARGET convertgmo COMMAND xxd -i "${poFile}.gmo" >> ${moHeader} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMENT "Convert file ${poFile}.gmo in header" DEPENDS ${poFiles} ) set(vars ${vars} "${poFile}_gmo") endforeach(poFile) # Add variables 'lang', 'ptrlang' and 'ptrlen' in header set(lang 'char *lang[] = { ') set(ptrlang 'unsigned char *ptrlang[] = { ') set(ptrlen 'unsigned int *ptrlen[] = { ') foreach(poFile ${poFiles}) set(lang ${lang} '\"${poFile}\", ') set(ptrlang ${ptrlang} '${poFile}_gmo, ') set(ptrlen ${ptrlen} '&${poFile}_gmo_len, ') endforeach(poFile) set(lang ${lang} '\"\" }\\\;') set(ptrlang ${ptrlang} 'NULL }\\\;') set(ptrlen ${ptrlen} 'NULL }\\\;') add_custom_command(TARGET convertgmo COMMAND ${CMAKE_COMMAND} -E echo ${lang} >> ${moHeader} COMMAND ${CMAKE_COMMAND} -E echo ${ptrlang} >> ${moHeader} COMMAND ${CMAKE_COMMAND} -E echo ${ptrlen} >> ${moHeader} DEPENDS ${lang} ${ptrlang} ${ptrlen}) add_dependencies(convertgmo potfiles) endif(PORTABLE_BINARY) else(GETTEXT_FOUND) set(GETTEXT_FOUND OFF PARENT_SCOPE) endif(GETTEXT_FOUND) CPU-X-3.2.4/po/cpu-x.pot000066400000000000000000000404641341671471500145730ustar00rootroot00000000000000# LANG translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "Project-Id-Version: cpu-x \n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: core.c:147 msgid "could not reallocate memory" msgstr "" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "" #: core.c:175 msgid "Finding CPU technology" msgstr "" #: core.c:194 #, c-format msgid "Your CPU does not belong in database ==> %s, model: %i, ext. model: " "%i, ext. family: %i" msgstr "" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "" #: core.c:512 msgid "Calling dmidecode" msgstr "" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "" #: core.c:539 msgid "failed to call dmidecode" msgstr "" #: core.c:554 msgid "Calculating CPU usage" msgstr "" #: core.c:604 msgid "Calling bandwidth" msgstr "" #: core.c:634 msgid "Finding graphic card driver" msgstr "" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "" #: core.c:695 msgid "Finding devices" msgstr "" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "" #: core.c:969 msgid "Identifying running system" msgstr "" #: core.c:972 msgid "failed to identify running system" msgstr "" #: core.c:1013 msgid "Calling libprocps" msgstr "" #: core.c:1035 msgid "Calling libstatgrab" msgstr "" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "" #: core.c:1120 msgid "Updating benchmark status" msgstr "" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "" #: core.c:1134 msgid "Active" msgstr "" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "" #: core.c:1168 msgid "Starting benchmark" msgstr "" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "" #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "" #: gui_gtk.c:103 msgid "Ignore" msgstr "" #: gui_gtk.c:107 msgid "Run as root" msgstr "" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "" #: gui_gtk.c:129 msgid "Not now" msgstr "" #: gui_gtk.c:129 msgid "Update" msgstr "" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "" #: main.c:62 msgid "Setting label names" msgstr "" #: main.c:64 msgid "CPU" msgstr "" #: main.c:65 msgid "Processor" msgstr "" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "" #: main.c:67 msgid "Code Name" msgstr "" #: main.c:68 msgid "Package" msgstr "" #: main.c:69 msgid "Technology" msgstr "" #: main.c:70 msgid "Voltage" msgstr "" #: main.c:71 msgid "Specification" msgstr "" #: main.c:72 msgid "Family" msgstr "" #: main.c:73 msgid "Ext. Family" msgstr "" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "" #: main.c:75 msgid "Ext. Model" msgstr "" #: main.c:76 msgid "Temp." msgstr "" #: main.c:77 msgid "Stepping" msgstr "" #: main.c:78 msgid "Instructions" msgstr "" #: main.c:80 msgid "Clocks" msgstr "" #: main.c:81 msgid "Core Speed" msgstr "" #: main.c:82 msgid "Multiplier" msgstr "" #: main.c:83 msgid "Bus Speed" msgstr "" #: main.c:84 main.c:157 msgid "Usage" msgstr "" #: main.c:86 msgid "Cache" msgstr "" #: main.c:87 msgid "L1 Data" msgstr "" #: main.c:88 msgid "L1 Inst." msgstr "" #: main.c:89 msgid "Level 2" msgstr "" #: main.c:90 msgid "Level 3" msgstr "" #: main.c:92 msgid "Socket(s)" msgstr "" #: main.c:93 msgid "Core(s)" msgstr "" #: main.c:94 msgid "Thread(s)" msgstr "" #: main.c:97 msgid "Caches" msgstr "" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "" #: main.c:102 msgid "Size" msgstr "" #: main.c:103 msgid "Speed" msgstr "" #: main.c:105 msgid "Test" msgstr "" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "" #: main.c:110 msgid "Manufacturer" msgstr "" #: main.c:112 msgid "Revision" msgstr "" #: main.c:114 msgid "BIOS" msgstr "" #: main.c:115 msgid "Brand" msgstr "" #: main.c:116 msgid "Version" msgstr "" #: main.c:117 msgid "Date" msgstr "" #: main.c:118 msgid "ROM Size" msgstr "" #: main.c:120 msgid "Chipset" msgstr "" #: main.c:125 main.c:141 msgid "Memory" msgstr "" #: main.c:128 #, c-format msgid "Bank %i" msgstr "" #: main.c:129 msgid "Reference" msgstr "" #: main.c:133 msgid "System" msgstr "" #: main.c:134 msgid "Operating System" msgstr "" #: main.c:135 msgid "Kernel" msgstr "" #: main.c:136 msgid "Distribution" msgstr "" #: main.c:137 msgid "Hostname" msgstr "" #: main.c:138 msgid "Uptime" msgstr "" #: main.c:139 msgid "Compiler" msgstr "" #: main.c:142 msgid "Used" msgstr "" #: main.c:143 msgid "Buffers" msgstr "" #: main.c:144 msgid "Cached" msgstr "" #: main.c:145 msgid "Free" msgstr "" #: main.c:146 msgid "Swap" msgstr "" #: main.c:149 msgid "Graphics" msgstr "" #: main.c:153 #, c-format msgid "Card %i" msgstr "" #: main.c:156 msgid "Temperature" msgstr "" #: main.c:158 msgid "GPU clock" msgstr "" #: main.c:159 msgid "Memory clock" msgstr "" #: main.c:163 msgid "Bench" msgstr "" #: main.c:164 msgid "Prime numbers (slow)" msgstr "" #: main.c:165 msgid "Prime numbers (fast)" msgstr "" #: main.c:168 msgid "Score" msgstr "" #: main.c:169 msgid "Run" msgstr "" #: main.c:172 msgid "Parameters" msgstr "" #: main.c:173 msgid "Duration" msgstr "" #: main.c:174 msgid "Threads" msgstr "" #: main.c:177 main.c:182 msgid "About" msgstr "" #: main.c:179 #, c-format msgid "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "" #: main.c:183 #, c-format msgid "Version %s" msgstr "" #: main.c:184 #, c-format msgid "Author: %s" msgstr "" #: main.c:185 #, c-format msgid "Site: %s" msgstr "" #: main.c:187 msgid "License" msgstr "" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "" #: main.c:259 msgid "Dumping data..." msgstr "" #: main.c:301 msgid "Freeing memory" msgstr "" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "" #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "" #: main.c:362 msgid "wrong write data" msgstr "" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "" #: main.c:374 main.c:467 msgid "No new version available" msgstr "" #: main.c:375 msgid "(up-to-date)" msgstr "" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "" #: main.c:460 msgid "Network access is disabled by environment variable (set CPUX_NETWORK " "with a positive value to enable it)" msgstr "" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "" #: main.c:488 msgid "Downloading new version..." msgstr "" #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "" #: main.c:506 msgid "Extracting new version..." msgstr "" #: main.c:516 msgid "Applying new version..." msgstr "" #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "" #: main.c:529 msgid "Update successful!" msgstr "" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "" #: main.c:553 msgid "Set default tab (integer)" msgstr "" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "" #: main.c:557 msgid "Disable colored output" msgstr "" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "" #: main.c:559 msgid "Verbose output" msgstr "" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "" #: main.c:561 msgid "Print help and exit" msgstr "" #: main.c:562 msgid "Print version and exit" msgstr "" #: main.c:573 msgid "Temporarily disable network support" msgstr "" #: main.c:574 msgid "Enforce the bus clock" msgstr "" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "" #: main.c:586 msgid "Available DISPLAY:" msgstr "" #: main.c:590 msgid "\n" "Available OPTIONS:" msgstr "" #: main.c:595 msgid "\n" "Influenceable environment variables:" msgstr "" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "" #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "" #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "" #: main.c:772 #, c-format msgid "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has " "crashed.%s" msgstr "" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "" #: main.c:846 msgid "an error occurred while setting locale" msgstr "" #: main.c:968 #, c-format msgid "Sorry, you cannot update %s: 32-bit portable version is no more " "supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "" #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "" #: tui_ncurses.c:387 msgid "\n" "Global keys:\n" msgstr "" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "" #: tui_ncurses.c:393 msgid "\n" "CPU tab:\n" msgstr "" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "" #: tui_ncurses.c:397 msgid "\n" "Caches tab:\n" msgstr "" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "" #: tui_ncurses.c:401 msgid "\n" "Bench tab:\n" msgstr "" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "" #: tui_ncurses.c:409 msgid "\n" "Press any key to exit this help.\n" msgstr "" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "" #: tui_ncurses.c:434 #, c-format msgid "\n" "\n" "%s will be updated." msgstr "" #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "" CPU-X-3.2.4/po/cs_CZ.po000066400000000000000000000606471341671471500143610ustar00rootroot00000000000000# Czech (Czech Republic) translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # Pavel Borecki , 2017-2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: Czech (Czech Republic) (http://www.transifex.com/xorg/cpu-x/language/cs_CZ/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs_CZ\n" "Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" #: core.c:147 msgid "could not reallocate memory" msgstr "nepodařilo se znovupřidělit paměť" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "Ukončuje se %s" #: core.c:175 msgid "Finding CPU technology" msgstr "Zjišťování technologie procesoru" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "Váš procesor se nenachází v databázi ==> %s, model: %i, model podrobněji: %i, řada podrobněji: %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "%d x %d KB, %d-cestná" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "%d MB, %d-cestná" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "%s asociativní, %d-bajtová velikost řádku" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "Získávání statických údajů prostřednictvím knihovny libcpuid " #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "nepodařilo se zavolat knihovnu libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "Získávání dynamických údajů prostřednictvím knihovny libcpuid" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "Přeskočit otevírání MSR registru procesoru (vyžaduje práva správce systému)" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "nepodařilo se otevřít MSR registr procesoru (%s)" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "Získávání statických hodnot MSR registru procesoru prostřednictvím knihovny libcpuid" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "Získávání dynamických hodnot MSR registru procesoru prostřednictvím knihovny libcpuid" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "Výpočet násobičů frekvence procesoru" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "Přeskočit zavolání nástroje dmidecode (vyžaduje práva správce systému)" #: core.c:512 msgid "Calling dmidecode" msgstr "Získávání údajů prostřednictvím nástroje dmidecode" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "nepodařilo se přidělit paměť pro nástroj dmidecode" #: core.c:539 msgid "failed to call dmidecode" msgstr "nepodařilo se zavolat nástroj dmidecode" #: core.c:554 msgid "Calculating CPU usage" msgstr "Výpočet vytížení procesoru" #: core.c:604 msgid "Calling bandwidth" msgstr "Zjišťování údajů prostřednictvím nástroje bandwidth" #: core.c:634 msgid "Finding graphic card driver" msgstr "Zjišťování ovladače grafického čipu" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "Neznámý ovladač grafického čipu: %s" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "(ovladač %s)" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "nepodařilo se zjistit ovladač grafické karty (%s)" #: core.c:695 msgid "Finding devices" msgstr "Hledání zařízení" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "Přeskočit vyhledávání zařízení (je třeba mít práva správce systému – root)" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "Neznámý výrobce grafického čipu: %s (%#X)" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "nepodařilo se určit výrobce a model čipové sady" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "nepodařilo se určit výrobce a model grafického čipu" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "Zjišťování teploty grafického čipu" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "nepodařilo se zjistit teplotu grafického čipu" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "Přeskočit některé hodnoty graf. čipu (vyžaduje práva správce systému)" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "Zjišťování taktů graf. čipu" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "Ovladač graf. čipu %i nehlásí takty" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "nepodařilo se zjistit takty grafického čipu" #: core.c:969 msgid "Identifying running system" msgstr "Rozpoznávání operačního systému, ve kterém je spuštěné" #: core.c:972 msgid "failed to identify running system" msgstr "nepodařilo se rozpoznat operační systém, ve kterém je spuštěné" #: core.c:1013 msgid "Calling libprocps" msgstr "Zjišťování údajů prostřednictvím knihovny libprocps" #: core.c:1035 msgid "Calling libstatgrab" msgstr "Zjišťování údajů prostřednictvím knihovny libstatgrab" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "%i dnů, %i hodin, %i minut, %i sekund" #: core.c:1120 msgid "Updating benchmark status" msgstr "Aktualizace stavu výkonostního testu" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "%u minut" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "Neaktivní" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "Není spuštěné" #: core.c:1134 msgid "Active" msgstr "Aktivní" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "(zbývá %u hodin)" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "(zbývá %u minut)" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "(zbývá %u sekund)" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "za %u hodin" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "za %u minut" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "za %u sekund" #: core.c:1168 msgid "Starting benchmark" msgstr "Spouštění výkonnostního testu" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "nepodařilo se přidělit paměť pro výkonnostní test" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "při spouštění výkonnostního testu se vyskytla chyba" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "Typ pouzdra procesoru zjištován v náhradním režimu" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "Patice vašeho procesoru se nenachází v databázi ==> %s, krycí název: %s" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "Násobiče frekvence procesoru zjišťovány v náhradním režimu" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "Informace o základní desce zjišťovány v náhradním režimu" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "nepodařilo se získat informace o základní desce (náhradní režim)" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "Teplota procesoru zjišťována v náhradním režimu" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "nepodařilo se zjistit teplotu procesoru (náhradní režim)" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "Provozní napětí procesoru zjišťováno v náhradním režimu" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "nepodařilo se zjistit provozní napětí procesoru (náhradní režim)" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "Takty graf. čipu zjišťovány v náhradním režimu" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "nepodařilo se zjistit takt procesoru (náhradní režim)" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "Spouštění GTK grafického uživatelského rozhraní…" #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "nepodařilo se importovat definici uživatelské rozhraní ve formátu GtkBuilder" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "Pro správné fungování je třeba oprávnění správce systému" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "Některé informace nebude možné získat" #: gui_gtk.c:103 msgid "Ignore" msgstr "Ignorovat" #: gui_gtk.c:107 msgid "Run as root" msgstr "Spustit s právy správce systému (root)" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "Je k dispozici nová verze %s!" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "Přejete si (po ukončení) aktualizovat %s na verzi %s?\nTento binární soubor (%s) bude přepsán novou verzí." #: gui_gtk.c:129 msgid "Not now" msgstr "Nyní ne" #: gui_gtk.c:129 msgid "Update" msgstr "Aktualizovat" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "Jádro č. %i" #: main.c:62 msgid "Setting label names" msgstr "Nastavování názvů popisek" #: main.c:64 msgid "CPU" msgstr "Procesor" #: main.c:65 msgid "Processor" msgstr "Procesor" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "Výrobce" #: main.c:67 msgid "Code Name" msgstr "Krycí název" #: main.c:68 msgid "Package" msgstr "Typ pouzdra" #: main.c:69 msgid "Technology" msgstr "Technologie" #: main.c:70 msgid "Voltage" msgstr "Provozní napětí" #: main.c:71 msgid "Specification" msgstr "Specifikace" #: main.c:72 msgid "Family" msgstr "Řada" #: main.c:73 msgid "Ext. Family" msgstr "Řada podrobně" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "Model" #: main.c:75 msgid "Ext. Model" msgstr "Model podrobně" #: main.c:76 msgid "Temp." msgstr "Tepl." #: main.c:77 msgid "Stepping" msgstr "Várka" #: main.c:78 msgid "Instructions" msgstr "Výpočetní instrukce" #: main.c:80 msgid "Clocks" msgstr "Takty" #: main.c:81 msgid "Core Speed" msgstr "Rychlost jádra" #: main.c:82 msgid "Multiplier" msgstr "Násobič" #: main.c:83 msgid "Bus Speed" msgstr "Rychlost sběrnice" #: main.c:84 main.c:157 msgid "Usage" msgstr "Využití" #: main.c:86 msgid "Cache" msgstr "Mezipaměť" #: main.c:87 msgid "L1 Data" msgstr "1. úrovně (L1) – datová" #: main.c:88 msgid "L1 Inst." msgstr "1. úrovně (L1) – instrukční" #: main.c:89 msgid "Level 2" msgstr "Druhé úrovně" #: main.c:90 msgid "Level 3" msgstr "Třetí úrovně" #: main.c:92 msgid "Socket(s)" msgstr "Patice" #: main.c:93 msgid "Core(s)" msgstr "Jádra" #: main.c:94 msgid "Thread(s)" msgstr "Vlákna" #: main.c:97 msgid "Caches" msgstr "Mezipaměti" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "mezipaměť %i úrovně" #: main.c:102 msgid "Size" msgstr "Velikost" #: main.c:103 msgid "Speed" msgstr "Rychlost" #: main.c:105 msgid "Test" msgstr "Test" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "Základní deska" #: main.c:110 msgid "Manufacturer" msgstr "Výrobce" #: main.c:112 msgid "Revision" msgstr "Revize" #: main.c:114 msgid "BIOS" msgstr "BIOS/(U)EFI" #: main.c:115 msgid "Brand" msgstr "Značka" #: main.c:116 msgid "Version" msgstr "Verze" #: main.c:117 msgid "Date" msgstr "Datum" #: main.c:118 msgid "ROM Size" msgstr "Velikost ROM" #: main.c:120 msgid "Chipset" msgstr "Čipová sada" #: main.c:125 main.c:141 msgid "Memory" msgstr "Operační paměť" #: main.c:128 #, c-format msgid "Bank %i" msgstr "Banka %i" #: main.c:129 msgid "Reference" msgstr "Údaje" #: main.c:133 msgid "System" msgstr "Systém" #: main.c:134 msgid "Operating System" msgstr "Operační systém" #: main.c:135 msgid "Kernel" msgstr "Jádro systému" #: main.c:136 msgid "Distribution" msgstr "Distribuce" #: main.c:137 msgid "Hostname" msgstr "Název stroje" #: main.c:138 msgid "Uptime" msgstr "Doba chodu systému (uptime)" #: main.c:139 msgid "Compiler" msgstr "Kompilátor" #: main.c:142 msgid "Used" msgstr "Využito" #: main.c:143 msgid "Buffers" msgstr "Vyrovnávací paměť" #: main.c:144 msgid "Cached" msgstr "Mezipaměť" #: main.c:145 msgid "Free" msgstr "Volné" #: main.c:146 msgid "Swap" msgstr "Odkládací prostor (swap)" #: main.c:149 msgid "Graphics" msgstr "Grafika" #: main.c:153 #, c-format msgid "Card %i" msgstr "Adaptér %i" #: main.c:156 msgid "Temperature" msgstr "Teplota" #: main.c:158 msgid "GPU clock" msgstr "Takt graf. čipu" #: main.c:159 msgid "Memory clock" msgstr "Takt paměti" #: main.c:163 msgid "Bench" msgstr "Výkon. test" #: main.c:164 msgid "Prime numbers (slow)" msgstr "Prvočísla (důkladně)" #: main.c:165 msgid "Prime numbers (fast)" msgstr "Prvočísla (zběžně)" #: main.c:168 msgid "Score" msgstr "Výsledek" #: main.c:169 msgid "Run" msgstr "Spustit" #: main.c:172 msgid "Parameters" msgstr "Parametry" #: main.c:173 msgid "Duration" msgstr "Doba trvání" #: main.c:174 msgid "Threads" msgstr "Vláken" #: main.c:177 main.c:182 msgid "About" msgstr "O aplikaci" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "%s je svobodný software který pro vás shromažďuje\no procesoru, základní desce a další." #: main.c:183 #, c-format msgid "Version %s" msgstr "Verze %s" #: main.c:184 #, c-format msgid "Author: %s" msgstr "Autor: %s" #: main.c:185 #, c-format msgid "Site: %s" msgstr "Webové stránky: %s" #: main.c:187 msgid "License" msgstr "Licence" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "Tento software je šířen za podmínek licence %s" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "Na tuto aplikaci nejsou poskytovány VŮBEC ŽÁDNÉ ZÁRUKY" #: main.c:259 msgid "Dumping data..." msgstr "Pořizování výpisu dat…" #: main.c:301 msgid "Freeing memory" msgstr "Uvolňování paměti" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "Zjišťování dostupnosti případné nové verze na Internetu…" #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "Nepodařilo se otevřít relaci nástroje Curl" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "Nepodařilo se provést přenos nástrojem Curl (%s)" #: main.c:362 msgid "wrong write data" msgstr "chybná data pro zápis" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "(je k dispozici verze %s)" #: main.c:374 main.c:467 msgid "No new version available" msgstr "Není k dispozici žádná novější verze" #: main.c:375 msgid "(up-to-date)" msgstr "(už používáte nejnovější dostupnou verzi)" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "při vybalování archivu s %s se vyskytla chyba (%s)" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "Síťový přístup je vypnutý proměnnou prostředí (zapněte nastavením CPUX_NETWORK na kladnou hodnotu)" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "nepodařilo se zapsat do archivu %s" #: main.c:488 msgid "Downloading new version..." msgstr "Stahování nové verze…" #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "nepodařilo se stáhnout archiv %s (%s)" #: main.c:506 msgid "Extracting new version..." msgstr "Rozbalování nové verze…" #: main.c:516 msgid "Applying new version..." msgstr "Nasazování nové verze…" #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "při odebírání/přejmenovávání souborů došlo k chybě" #: main.c:529 msgid "Update successful!" msgstr "Aktualizace úspěšná!" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "Spustit grafické uživatelské rozhraní (GUI) – výchozí" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "Spustit pseudografické uživatelské rozhraní (TUI)" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "Vypsat veškeré údaje na standardní výstup a skončit" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "Spustit vestavěný příkaz dmidecode a skončit" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "Spustit vestavěný příkaz bandwidth a skončit" #: main.c:553 msgid "Set default tab (integer)" msgstr "Nastavit výchozí kartu (celočíselná hodnota)" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "Vybrat jádro procesoru které monitorovat (celočíselná hodnota)" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "Nastavit vlastní test propustnosti mezipamětí procesoru (celočíselná hodnota)" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "Nastavit vlastní prodlevu mezi dvěma obnoveními (v sekundách)" #: main.c:557 msgid "Disable colored output" msgstr "Vypnout obarvování výstupu" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "Vypsat potřebné informace pro přiložení k hlášení problému" #: main.c:559 msgid "Verbose output" msgstr "Podrobnější výstup" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "Aktualizovat přenosnou variantu pokud je k dispozici novější verze" #: main.c:561 msgid "Print help and exit" msgstr "Vypsat nápovědu a skončit" #: main.c:562 msgid "Print version and exit" msgstr "Vypsat verzi a skončit" #: main.c:573 msgid "Temporarily disable network support" msgstr "Dočasně vypnout podporu sítě" #: main.c:574 msgid "Enforce the bus clock" msgstr "Vynutit takt sběrnice" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "Načíst nezpracovaná CPUID data ze zadaného souboru" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "Pokud procesor není v databázi, pouze vypsat hlášení" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "Použití: %s ZOBRAZENÍ [PŘEDVOLBY]\n" #: main.c:586 msgid "Available DISPLAY:" msgstr "ZOBRAZENÍ k dispozici:" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "\nPŘEDVOLBY k dispozici:" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "\nOvlivnitelné proměnné prostředí:" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "Toto je svobodný software: můžete ho upravovat a šířit dál." #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "Viz licence %s: <%s>\n" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "Sestaveno %s, %s (pomocí %s %s na %s)." #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "-- %-9s verze: %s" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "\n%sJejda, něco se pokazilo! %s obdrželo signál %d (%s) a zhavarovalo.%s" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "Tento záznam volání funkcí (backtrace) můžete vložit otevřením nového hlášení problému zde:" #: main.c:846 msgid "an error occurred while setting locale" msgstr "při nastavování místních a jazykových nastavení došlo k chybě" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "Spouštění pseudografického (TUI) rozhraní…" #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "Nápovědu zobrazíte stisknutím klávesy „H“.\n" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "Vítejte v nápovědě pseudografické (NCurses) varianty %s!\n" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "Tato nápověda popisuje použití tohoto textového uživatelského rozhraní.\n" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "\nVšeobecné klávesy:\n" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "\tStiskem klávesy „Šipka vlevo“ se přepnete do karty nalevo od stávající.\n" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "\tStiskem klávesy „Šipka vpravo“ se přepnete do karty napravo od stávající.\n" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "\tStiskem klávesy „H“ zobrazíte tuto nápovědu.\n" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "\tStiskem klávesy „Q“ aplikaci ukončíte.\n" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "\nNa kartě procesor:\n" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "\tStiskem klávesy „Šipka dolů“ přejdete na monitorování jádra s nižším číslem.\n" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "\tStiskem klávesy „Šipka dolů“ přejdete na monitorování jádra s vyšším číslem.\n" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "\nNa kartě mezipaměť:\n" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "\tStiskem klávesy „Šipka dolů“ přejdete na předchozí test.\n" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "\tStiskem klávesy „Šipka dolů“ přejdete na následující test.\n\n" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "\nNa kartě výkonnostní testy:\n" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "\tStiskem klávesy „Šipka dolů“ snížíte nastavenou dobu trvání výkonnostního testu .\n" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "\tStiskem klávesy „Šipka dolů“ zvýšíte nastavenou dobu trvání výkonnostního testu .\n" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "\tStiskem klávesy „následující stránka“ snížíte počet vláken, které test použije..\n" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "\tStiskem klávesy „předchozí stránka“ zvýšíte počet vláken, které test použije.\n" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "\tStiskem klávesy „S“ spustíte/zastavíte výkonnostní test počítání prvočísel (důkladnou variantu).\n" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "\tStiskem klávesy „F“ spustíte/zastavíte výkonnostní test počítání prvočísel (zběžnou variantu).\n" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "\nTuto nápovědu uzavřete stiskem libovolné klávesy.\n" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "Pokud chcete zaktualizovat, stiskněte klávesu „U“ – v opačném případě přeskočte stisknutím libovolné jiné klávesy.\n" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "\n\n%s bude aktualizováno." #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "došlo k chybě při otevírání souboru „%s“ (%s)" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "došlo k chybě při vykonávání příkazu „%s“ (%s)" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "nepodařilo se otevřít složku %s" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "došlo k chybě při sestavování regulárního výrazu" CPU-X-3.2.4/po/fr.po000066400000000000000000000602361341671471500137610ustar00rootroot00000000000000# French translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # Xorg, 2015 # Xorg, 2016,2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: French (http://www.transifex.com/xorg/cpu-x/language/fr/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: core.c:147 msgid "could not reallocate memory" msgstr "ne peut pas réallouer de la mémoire" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "Quitte %s" #: core.c:175 msgid "Finding CPU technology" msgstr "Recherche la finesse de gravure du processeur" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "Votre processeur n'appartient pas à la base de données ==> %s, modèle : %i, modèle ét. : %i, famille ét. : %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "%d x %d Ko, %d voies" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "%d Mo, %d voies" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "%s associatives, %d octets par ligne" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "Appel libcpuid pour récupérer les données statiques" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "échec lors de l'appel de libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "Appel libcpuid pour récupérer les données dynamiques" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "Saute l'ouverture des MSR du processeur (besoin d'être super-utilisateur)" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "échec lors de l'ouverture des MSR du processeur (%s)" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "Appel libcpuid pour récupérer les valeurs statiques des MSRs du processeur " #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "Appel libcpuid pour récupérer les valeurs dynamiques des MSRs du processeur " #: core.c:469 msgid "Calculating CPU multipliers" msgstr "Calcule les multiplicateurs du processeur" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "Saute l'appel de dmidecode (besoin d'être super-utilisateur)" #: core.c:512 msgid "Calling dmidecode" msgstr "Appel dmidecode" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "échec lors de l'allocation de la mémoire pour dmidecode" #: core.c:539 msgid "failed to call dmidecode" msgstr "échec lors de l'appel de dmidecode" #: core.c:554 msgid "Calculating CPU usage" msgstr "Calcule l'utilisation du processeur" #: core.c:604 msgid "Calling bandwidth" msgstr "Appel bandwidth" #: core.c:634 msgid "Finding graphic card driver" msgstr "Recherche le pilote de la carte graphique" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "Le pilote de votre carte-graphique est inconnu : %s" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "(pilote %s)" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "échec lors de la recherche du pilote de la carte-graphique (%s)" #: core.c:695 msgid "Finding devices" msgstr "Recherche des périphériques" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "Saute la recherche des périphériques (besoin d'être super-utilisateur)" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "Le fabricant de votre carte-graphique est inconnu: %s (%#X)" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "échec lors de la recherche du vendeur et du modèle du chipset" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "échec lors de la recherche du vendeur et du modèle de la carte-graphique" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "Récupère la température du processeur graphique" #: core.c:786 msgid "Off" msgstr "Off" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "échec lors de la récupération de la température du processeur graphique" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "Saute quelques valeurs pour la carte-graphique (besoin d'être super-utilisateur)" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "Récupère les fréquences de la carte-graphique" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "Le pilote de la carte-graphique %i ne rapporte pas les fréquences" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "échec lors de la récupération des fréquences de la carte-graphique" #: core.c:969 msgid "Identifying running system" msgstr "Identifie le système en cours de fonctionnement" #: core.c:972 msgid "failed to identify running system" msgstr "échec lors de l'identification du système en cours de fonctionnement" #: core.c:1013 msgid "Calling libprocps" msgstr "Appel libprocps" #: core.c:1035 msgid "Calling libstatgrab" msgstr "Appel libstatgrab" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "%i jours, %i heures, %i minutes, %i secondes" #: core.c:1120 msgid "Updating benchmark status" msgstr "Mise à jour du statut du test de performance" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "%u mins" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "Inactif" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "Non démarré" #: core.c:1134 msgid "Active" msgstr "Actif" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "(%u heures restantes)" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "(%u minutes restantes)" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "(%u secondes restantes)" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "en %u heures" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "en %u minutes" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "en %u secondes" #: core.c:1168 msgid "Starting benchmark" msgstr "Démarrage du test de performance" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "échec lors de l'allocation de la mémoire pour le test de performance" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "une erreur est survenue lors du démarrage du test de performance" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "Recherche du socket du processeur en mode de secours" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "Votre socket de processeur n'appartient pas à la base de données ==> %s, nom de code : %s" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "Calcule les multiplicateurs du processeur en mode de secours" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "Récupère les informations de la carte-mère en mode de secours" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "échec lors de la récupération des informations de la carte-mère (mode de secours)" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "Récupère la température du processeur en mode de secours" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "échec lors de la récupération de la température du processeur (mode de secours)" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "Récupère la tension du processeur en mode de secours" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "échec lors de la récupération de la tension du processeur (mode de secours)" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "Récupère la fréquence du processeur en mode de secours" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "échec lors de la récupération de la fréquence du processeur (mode de secours)" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "Démarrage de l'interface graphique GTK..." #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "échec lors de l'import de l'interface dans GtkBuilder" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "Les privilèges du super-utilisateur sont requis pour fonctionner correctement" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "Quelques données ne seront pas récupérables" #: gui_gtk.c:103 msgid "Ignore" msgstr "Ignorer" #: gui_gtk.c:107 msgid "Run as root" msgstr "Exécuter en tant que super-utilisateur" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "Une nouvelle version de %s est disponible !" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "Voulez-vous mettre à jour %s à la version %s après la fermeture du programme ?\nCela va écraser le fichier binaire (%s) par la nouvelle version." #: gui_gtk.c:129 msgid "Not now" msgstr "Pas maintenant" #: gui_gtk.c:129 msgid "Update" msgstr "Mettre à jour" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "Cœur #%i" #: main.c:62 msgid "Setting label names" msgstr "Configuration du nom des étiquettes" #: main.c:64 msgid "CPU" msgstr "CPU" #: main.c:65 msgid "Processor" msgstr "Processeur" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "Vendeur" #: main.c:67 msgid "Code Name" msgstr "Nom de code" #: main.c:68 msgid "Package" msgstr "Socket" #: main.c:69 msgid "Technology" msgstr "Technologie" #: main.c:70 msgid "Voltage" msgstr "Tension" #: main.c:71 msgid "Specification" msgstr "Spécification" #: main.c:72 msgid "Family" msgstr "Famille" #: main.c:73 msgid "Ext. Family" msgstr "Famille ét." #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "Modèle" #: main.c:75 msgid "Ext. Model" msgstr "Modèle ét." #: main.c:76 msgid "Temp." msgstr "Temp." #: main.c:77 msgid "Stepping" msgstr "Stepping" #: main.c:78 msgid "Instructions" msgstr "Instructions" #: main.c:80 msgid "Clocks" msgstr "Fréquences" #: main.c:81 msgid "Core Speed" msgstr "Vitesse du cœur" #: main.c:82 msgid "Multiplier" msgstr "Multiplicateur" #: main.c:83 msgid "Bus Speed" msgstr "Vitesse du bus" #: main.c:84 main.c:157 msgid "Usage" msgstr "Utilisation" #: main.c:86 msgid "Cache" msgstr "Cache" #: main.c:87 msgid "L1 Data" msgstr "Données L1" #: main.c:88 msgid "L1 Inst." msgstr "Instr. L1" #: main.c:89 msgid "Level 2" msgstr "Niveau L2" #: main.c:90 msgid "Level 3" msgstr "Niveau L3" #: main.c:92 msgid "Socket(s)" msgstr "Socket(s)" #: main.c:93 msgid "Core(s)" msgstr "Cœur(s)" #: main.c:94 msgid "Thread(s)" msgstr "Thread(s)" #: main.c:97 msgid "Caches" msgstr "Caches" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "Cache L%i" #: main.c:102 msgid "Size" msgstr "Taille" #: main.c:103 msgid "Speed" msgstr "Vitesse" #: main.c:105 msgid "Test" msgstr "Test" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "Carte-mère" #: main.c:110 msgid "Manufacturer" msgstr "Fabricant" #: main.c:112 msgid "Revision" msgstr "Révision" #: main.c:114 msgid "BIOS" msgstr "BIOS" #: main.c:115 msgid "Brand" msgstr "Marque" #: main.c:116 msgid "Version" msgstr "Version" #: main.c:117 msgid "Date" msgstr "Date" #: main.c:118 msgid "ROM Size" msgstr "Taille de la ROM" #: main.c:120 msgid "Chipset" msgstr "Chipset" #: main.c:125 main.c:141 msgid "Memory" msgstr "Mémoire" #: main.c:128 #, c-format msgid "Bank %i" msgstr "Banc %i" #: main.c:129 msgid "Reference" msgstr "Référence" #: main.c:133 msgid "System" msgstr "Système" #: main.c:134 msgid "Operating System" msgstr "Système d'exploitation" #: main.c:135 msgid "Kernel" msgstr "Noyau" #: main.c:136 msgid "Distribution" msgstr "Distribution" #: main.c:137 msgid "Hostname" msgstr "Nom d'hôte" #: main.c:138 msgid "Uptime" msgstr "Disponibilité" #: main.c:139 msgid "Compiler" msgstr "Compilateur" #: main.c:142 msgid "Used" msgstr "Utilisée" #: main.c:143 msgid "Buffers" msgstr "Tampons" #: main.c:144 msgid "Cached" msgstr "Cachée" #: main.c:145 msgid "Free" msgstr "Libre" #: main.c:146 msgid "Swap" msgstr "Swap" #: main.c:149 msgid "Graphics" msgstr "Graphiques" #: main.c:153 #, c-format msgid "Card %i" msgstr "Carte %i" #: main.c:156 msgid "Temperature" msgstr "Température" #: main.c:158 msgid "GPU clock" msgstr "Fréq. GPU" #: main.c:159 msgid "Memory clock" msgstr "Fréq. mémoire" #: main.c:163 msgid "Bench" msgstr "Bench" #: main.c:164 msgid "Prime numbers (slow)" msgstr "Nombres premier (lent)" #: main.c:165 msgid "Prime numbers (fast)" msgstr "Nombres premier (rapide)" #: main.c:168 msgid "Score" msgstr "Score" #: main.c:169 msgid "Run" msgstr "État" #: main.c:172 msgid "Parameters" msgstr "Paramètres" #: main.c:173 msgid "Duration" msgstr "Durée" #: main.c:174 msgid "Threads" msgstr "Threads" #: main.c:177 main.c:182 msgid "About" msgstr "À propos" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "%s est un logiciel Libre qui récolte des informations\nsur le CPU, la carte-mère et plus." #: main.c:183 #, c-format msgid "Version %s" msgstr "Version %s" #: main.c:184 #, c-format msgid "Author: %s" msgstr "Auteur : %s" #: main.c:185 #, c-format msgid "Site: %s" msgstr "Site : %s" #: main.c:187 msgid "License" msgstr "Licence" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "Ce logiciel est distribué sous les termes de la %s" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "Ce programme est distribué SANS AUCUNE GARANTIE" #: main.c:259 msgid "Dumping data..." msgstr "Vidage des données..." #: main.c:301 msgid "Freeing memory" msgstr "Libère de la mémoire" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "Vérifie l’existence d'une nouvelle version sur Internet..." #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "échec lors de l'ouverture d'une session Curl" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "échec lors de l'exécution du transfert pour Curl (%s)" #: main.c:362 msgid "wrong write data" msgstr "donnée en écriture incorrecte" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "(la version %s est disponible)" #: main.c:374 main.c:467 msgid "No new version available" msgstr "Pas de nouvelle version de disponible" #: main.c:375 msgid "(up-to-date)" msgstr "(à jour)" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "une erreur est survenue lors de l'extraction de l'archive %s (%s)" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "L'accès au réseau est désactivé par une variable d'environnement (définissez CPUX_NETWORK avec une valeur positive pour l'activer)" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "échec lors de l'ouverture en écriture de l'archive %s" #: main.c:488 msgid "Downloading new version..." msgstr "Téléchargement de la nouvelle version..." #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "échec lors du téléchargement de l'archive %s (%s)" #: main.c:506 msgid "Extracting new version..." msgstr "Extraction de la nouvelle version..." #: main.c:516 msgid "Applying new version..." msgstr "Application de la nouvelle version..." #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "une erreur est survenue pendant la suppression/le renommage des fichiers" #: main.c:529 msgid "Update successful!" msgstr "Mise à jour réussie !" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "Démarre l’interface graphique utilisateur (GUI) (défaut)" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "Démarre l'interface en mode texte (TUI)" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "Vide toutes les données sur la sortie standard et quitte" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "Lance la commande intégrée dmidecode et quitte" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "Lance la commande intégrée bandwidth et quitte" #: main.c:553 msgid "Set default tab (integer)" msgstr "Définit l'onglet par défaut (entier)" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "Sélectionne le cœur du processeur à surveiller (entier)" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "Définit un test personnalisé de bande passante pour la vitesse des caches du processeur (entier)" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "Définit un temps personnalisé entre deux mises à jour de l'interface (en secondes)" #: main.c:557 msgid "Disable colored output" msgstr "Désactive la sortie colorée" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "Affiche les informations nécessaires à coller dans un rapport de problèmes" #: main.c:559 msgid "Verbose output" msgstr "Sortie bavarde" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "Mettre à jour la version portable si une nouvelle version est disponible" #: main.c:561 msgid "Print help and exit" msgstr "Affiche l'aide et quitte" #: main.c:562 msgid "Print version and exit" msgstr "Affiche la version et quite" #: main.c:573 msgid "Temporarily disable network support" msgstr "Désactive le support du réseau temporairement" #: main.c:574 msgid "Enforce the bus clock" msgstr "Impose la fréquence du bus" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "Lis les données CPUID brutes depuis un fichier donné" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "Affiche uniquement un message si le processeur n'appartient pas à la base de données" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "Utilisation : %s AFFICHAGE [OPTIONS]\n" #: main.c:586 msgid "Available DISPLAY:" msgstr "AFFICHAGE disponible :" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "\nOPTIONS disponibles :" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "\nVariables d'environnements influençables :" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "Ceci est un logiciel libre ; vous êtes libres de le modifier et de le redistribuer." #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "Voir la licence %s : <%s>\n" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "Compilé le %s à %s (avec %s %s sur %s)." #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "-- Version de %-9s : %s" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "\n%sOups, quelque chose s'est mal passé ! %s a reçu le signal %d (%s) et a planté.%s" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "Vous pouvez coller la trace d'appels en ouvrant un nouveau rapport de problèmes ici :" #: main.c:846 msgid "an error occurred while setting locale" msgstr "une erreur est survenue lors de la définition des locales" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "Désolé, vous ne pouvez pas mettre à jour %s : la version portable 32 bits n'est plus supportée." #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "Démarrage de l'interface texte NCurses..." #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "Appuyer sur 'h' pour voir l'aide.\n" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "Bienvenue dans l'aide pour NCurses de %s !\n" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "Cette aide décrit comment utiliser cette interface en mode texte.\n" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "\nTouches globales :\n" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "Appuyer sur la touche 'flèche gauche' pour passer dans l'onglet de gauche.\n" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "Appuyer sur la touche 'flèche droite' pour passer dans l'onglet de droite.\n" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "Appuyer sur la touche 'h' pour voir cette aide.\n" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "Appuyer sur la touche 'q' pour quitter.\n" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "\nOnglet processeur :\n" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "Appuyer sur la touche 'flèche bas' pour diminuer la valeur du cœur à surveiller.\n" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "Appuyer sur la touche 'flèche haut' pour augmenter la valeur du cœur à surveiller.\n" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "\nOnglet caches :\n" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "Appuyer sur la touche 'flèche bas' pour passer au test précédent.\n" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "Appuyer sur la touche 'flèche haut' pour passer au test suivant.\n" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "\nOnglet Bench :\n" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "Appuyer sur la touche 'flèche bas' pour décrémenter la durée du test de performance.\n" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "Appuyer sur la touche 'flèche haut' pour incrémenter la durée du test de performance.\n" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "Appuyer sur la touche 'page suivante' pour décrémenter le nombre de threads à utiliser.\n" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "Appuyer sur la touche 'page précédente' pour incrémenter le nombre de threads à utiliser.\n" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "Appuyer sur la touche 's' pour démarrer/arrêter le test de performance des nombres premier (lent).\n" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "Appuyer sur la touche 'f' pour démarrer/arrêter le test de performance des nombres premier (rapide).\n" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "\nAppuyer sur n'importe quelle touche pour quitter cette aide.\n" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "Si vous voulez mettre à jour, appuyez sur la touche 'u', ou bien n'importe quoi d'autre pour passer.\n" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "\n\n%s va être mis à jour." #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "une erreur est survenue lors de l'ouverture du fichier '%s' (%s)" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "une erreur est survenue lors de l'exécution de la commande '%s' (%s)" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "échec lors de l'ouverture du répertoire %s" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "une erreur est survenue lors de la compilation des expressions régulières" CPU-X-3.2.4/po/id.po000066400000000000000000000375701341671471500137530ustar00rootroot00000000000000# Indonesian translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # Aunur Rofik , 2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: Indonesian (http://www.transifex.com/xorg/cpu-x/language/id/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: id\n" "Plural-Forms: nplurals=1; plural=0;\n" #: core.c:147 msgid "could not reallocate memory" msgstr "tidak dapat merealokasikan memori" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "Keluar %s" #: core.c:175 msgid "Finding CPU technology" msgstr "Menemukan Teknologi CPU" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "CPU Anda tidak termasuk dalam basis data ==> %s, model: %i, model luar: %i, keluarga luar: %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "%d x %d KB, %d -arah" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "%d MB, %d -arah" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "%s asosiatif, %d -ukuran batas byte" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "Memanggil libcpuid untuk mengambil data statis" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "gagal memanggil libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "Memanggil libcpuid untuk mengambil data dinamis" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "" #: core.c:512 msgid "Calling dmidecode" msgstr "" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "" #: core.c:539 msgid "failed to call dmidecode" msgstr "" #: core.c:554 msgid "Calculating CPU usage" msgstr "" #: core.c:604 msgid "Calling bandwidth" msgstr "" #: core.c:634 msgid "Finding graphic card driver" msgstr "" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "" #: core.c:695 msgid "Finding devices" msgstr "" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "" #: core.c:969 msgid "Identifying running system" msgstr "" #: core.c:972 msgid "failed to identify running system" msgstr "" #: core.c:1013 msgid "Calling libprocps" msgstr "" #: core.c:1035 msgid "Calling libstatgrab" msgstr "" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "" #: core.c:1120 msgid "Updating benchmark status" msgstr "" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "" #: core.c:1134 msgid "Active" msgstr "" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "" #: core.c:1168 msgid "Starting benchmark" msgstr "" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "" #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "" #: gui_gtk.c:103 msgid "Ignore" msgstr "" #: gui_gtk.c:107 msgid "Run as root" msgstr "" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "" #: gui_gtk.c:129 msgid "Not now" msgstr "" #: gui_gtk.c:129 msgid "Update" msgstr "" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "" #: main.c:62 msgid "Setting label names" msgstr "" #: main.c:64 msgid "CPU" msgstr "" #: main.c:65 msgid "Processor" msgstr "" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "" #: main.c:67 msgid "Code Name" msgstr "" #: main.c:68 msgid "Package" msgstr "" #: main.c:69 msgid "Technology" msgstr "" #: main.c:70 msgid "Voltage" msgstr "" #: main.c:71 msgid "Specification" msgstr "" #: main.c:72 msgid "Family" msgstr "" #: main.c:73 msgid "Ext. Family" msgstr "" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "" #: main.c:75 msgid "Ext. Model" msgstr "" #: main.c:76 msgid "Temp." msgstr "" #: main.c:77 msgid "Stepping" msgstr "" #: main.c:78 msgid "Instructions" msgstr "" #: main.c:80 msgid "Clocks" msgstr "" #: main.c:81 msgid "Core Speed" msgstr "" #: main.c:82 msgid "Multiplier" msgstr "" #: main.c:83 msgid "Bus Speed" msgstr "" #: main.c:84 main.c:157 msgid "Usage" msgstr "" #: main.c:86 msgid "Cache" msgstr "" #: main.c:87 msgid "L1 Data" msgstr "" #: main.c:88 msgid "L1 Inst." msgstr "" #: main.c:89 msgid "Level 2" msgstr "" #: main.c:90 msgid "Level 3" msgstr "" #: main.c:92 msgid "Socket(s)" msgstr "" #: main.c:93 msgid "Core(s)" msgstr "" #: main.c:94 msgid "Thread(s)" msgstr "" #: main.c:97 msgid "Caches" msgstr "" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "" #: main.c:102 msgid "Size" msgstr "" #: main.c:103 msgid "Speed" msgstr "" #: main.c:105 msgid "Test" msgstr "" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "" #: main.c:110 msgid "Manufacturer" msgstr "" #: main.c:112 msgid "Revision" msgstr "" #: main.c:114 msgid "BIOS" msgstr "" #: main.c:115 msgid "Brand" msgstr "" #: main.c:116 msgid "Version" msgstr "" #: main.c:117 msgid "Date" msgstr "" #: main.c:118 msgid "ROM Size" msgstr "" #: main.c:120 msgid "Chipset" msgstr "" #: main.c:125 main.c:141 msgid "Memory" msgstr "" #: main.c:128 #, c-format msgid "Bank %i" msgstr "" #: main.c:129 msgid "Reference" msgstr "" #: main.c:133 msgid "System" msgstr "" #: main.c:134 msgid "Operating System" msgstr "" #: main.c:135 msgid "Kernel" msgstr "" #: main.c:136 msgid "Distribution" msgstr "" #: main.c:137 msgid "Hostname" msgstr "" #: main.c:138 msgid "Uptime" msgstr "" #: main.c:139 msgid "Compiler" msgstr "" #: main.c:142 msgid "Used" msgstr "" #: main.c:143 msgid "Buffers" msgstr "" #: main.c:144 msgid "Cached" msgstr "" #: main.c:145 msgid "Free" msgstr "" #: main.c:146 msgid "Swap" msgstr "" #: main.c:149 msgid "Graphics" msgstr "" #: main.c:153 #, c-format msgid "Card %i" msgstr "" #: main.c:156 msgid "Temperature" msgstr "" #: main.c:158 msgid "GPU clock" msgstr "" #: main.c:159 msgid "Memory clock" msgstr "" #: main.c:163 msgid "Bench" msgstr "" #: main.c:164 msgid "Prime numbers (slow)" msgstr "" #: main.c:165 msgid "Prime numbers (fast)" msgstr "" #: main.c:168 msgid "Score" msgstr "" #: main.c:169 msgid "Run" msgstr "" #: main.c:172 msgid "Parameters" msgstr "" #: main.c:173 msgid "Duration" msgstr "" #: main.c:174 msgid "Threads" msgstr "" #: main.c:177 main.c:182 msgid "About" msgstr "" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "" #: main.c:183 #, c-format msgid "Version %s" msgstr "" #: main.c:184 #, c-format msgid "Author: %s" msgstr "" #: main.c:185 #, c-format msgid "Site: %s" msgstr "" #: main.c:187 msgid "License" msgstr "" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "" #: main.c:259 msgid "Dumping data..." msgstr "" #: main.c:301 msgid "Freeing memory" msgstr "" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "" #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "" #: main.c:362 msgid "wrong write data" msgstr "" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "" #: main.c:374 main.c:467 msgid "No new version available" msgstr "" #: main.c:375 msgid "(up-to-date)" msgstr "" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "" #: main.c:488 msgid "Downloading new version..." msgstr "" #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "" #: main.c:506 msgid "Extracting new version..." msgstr "" #: main.c:516 msgid "Applying new version..." msgstr "" #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "" #: main.c:529 msgid "Update successful!" msgstr "" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "" #: main.c:553 msgid "Set default tab (integer)" msgstr "" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "" #: main.c:557 msgid "Disable colored output" msgstr "" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "" #: main.c:559 msgid "Verbose output" msgstr "" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "" #: main.c:561 msgid "Print help and exit" msgstr "" #: main.c:562 msgid "Print version and exit" msgstr "" #: main.c:573 msgid "Temporarily disable network support" msgstr "" #: main.c:574 msgid "Enforce the bus clock" msgstr "" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "" #: main.c:586 msgid "Available DISPLAY:" msgstr "" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "" #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "" #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "" #: main.c:846 msgid "an error occurred while setting locale" msgstr "" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "" #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "" #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "" CPU-X-3.2.4/po/pl.po000066400000000000000000000454741341671471500137740ustar00rootroot00000000000000# Polish translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # Michał Głowienka , 2016 # Xorg, 2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: Polish (http://www.transifex.com/xorg/cpu-x/language/pl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" #: core.c:147 msgid "could not reallocate memory" msgstr "" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "" #: core.c:175 msgid "Finding CPU technology" msgstr "" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "Twojego procesora niema w bazie danych ==> %s, model: %i, ext. model: %i, ext. family: %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "Wywołanie libcpuid w celu pobierania danych statycznych" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "nie udało się wywołać libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "Wywołanie libcpuid w celu pobierania danych dynamicznych" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "Pomijam otwarcie CPU MSR (musisz być użytkownikiem root)" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "nie udało się otworzyć CPU MSR (%s)" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "Wywołanie libcpuid w celu pobrania statycznych danych z CPU MSR" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "Wywołanie libcpuid w celu pobrania dynamicznych danych z CPU MSR" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "Obliczanie mnożnika CPU" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "Pomijam wykonanie dmidecode (musisz być użytkownikiem root)" #: core.c:512 msgid "Calling dmidecode" msgstr "Wywołanie dmidecode" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "nie udało się przydzielić pamięci dla dmidecode" #: core.c:539 msgid "failed to call dmidecode" msgstr "nie udało się wywołać dmidecode" #: core.c:554 msgid "Calculating CPU usage" msgstr "Obliczanie użycia procesora" #: core.c:604 msgid "Calling bandwidth" msgstr "Wywołanie bandwidth" #: core.c:634 msgid "Finding graphic card driver" msgstr "Szukam sterownika karty graficznej" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "nie udało się znaleźć sterownika karty graficznej (%s)" #: core.c:695 msgid "Finding devices" msgstr "Wyszukiwanie urządzeń" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "Pomijam wyszukiwanie urządzeń (musisz być użytkownikiem root)" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "nie udało się znaleźć producenta i modelu chipsetu" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "nie udało się znaleźć producenta i modelu GPU" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "Pobieranie temperatury GPU" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "nie udało się pobrać temperatury GPU" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "" #: core.c:969 msgid "Identifying running system" msgstr "Identyfikacja uruchomionego systemu" #: core.c:972 msgid "failed to identify running system" msgstr "nie udało się zidentyfikować uruchomionego systemu" #: core.c:1013 msgid "Calling libprocps" msgstr "Wywołanie libprocps" #: core.c:1035 msgid "Calling libstatgrab" msgstr "Wywołanie libstatgrab" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "%i dni, %i godzin, %i minut, %i sekund" #: core.c:1120 msgid "Updating benchmark status" msgstr "Aktualizacja statusu benchmarku" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "%u min" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "Nieaktywny" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "Nie rozpoczął" #: core.c:1134 msgid "Active" msgstr "Aktywny" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "(%u godzin pozostało)" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "(%u minut pozostało)" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "(%u sekund pozostało)" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "w %u godzinach" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "w %u minutach" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "w %u sekundach" #: core.c:1168 msgid "Starting benchmark" msgstr "Uruchamianie benchmarku" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "nie udało się przydzielić pamięci dla benchmarku" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "wystąpił błąd podczas uruchamiania benchmarku" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "Wyszukiwanie podstawki CPU w trybie awaryjnym" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "Twojego gniazda CPU niema w bazie ==> %s, codename: %s" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "Obliczanie mnożnika CPU w trybie awaryjnym" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "Pozyskiwanie informacji o płycie głównej w trybie awaryjnym" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "nie udało się pobrać informacji o płycie głównej (tryb awaryjny)" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "Pozyskiwanie informacji o temperaturze CPU w trybie awaryjnym" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "nie udało się pobrać temperatury CPU (tryb awaryjny)" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "Pozyskiwanie napięcia CPU w trybie awaryjnym" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "nie udało się pozyskać napięcia CPU (tryb awaryjny)" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "Uruchamianie interfejsu GTK..." #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "nie udało się zaimportować interfejsu z GtkBuilder" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "Do prawidłowego działania wymagane są prawa użytkownika root" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "Niektóre informacje nie mogą być pozyskane" #: gui_gtk.c:103 msgid "Ignore" msgstr "Ignoruj" #: gui_gtk.c:107 msgid "Run as root" msgstr "Uruchom jako root" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "Nowa wersja programu %s jest dostępna!" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "Czy chcesz zaktualizować %s do wersji %s przed zamknięciem?\nSpowoduje to nadpisanie pliku binarnego (%s) przez nową wersję." #: gui_gtk.c:129 msgid "Not now" msgstr "Nie teraz" #: gui_gtk.c:129 msgid "Update" msgstr "Zaktualizuj" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "Rdzeń #%i" #: main.c:62 msgid "Setting label names" msgstr "Ustawianie nazw etykiet" #: main.c:64 msgid "CPU" msgstr "CPU" #: main.c:65 msgid "Processor" msgstr "Processor" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "Producent" #: main.c:67 msgid "Code Name" msgstr "Nazwa kodowa" #: main.c:68 msgid "Package" msgstr "" #: main.c:69 msgid "Technology" msgstr "Technologia" #: main.c:70 msgid "Voltage" msgstr "Napięcie" #: main.c:71 msgid "Specification" msgstr "Specyfikacja" #: main.c:72 msgid "Family" msgstr "Rodzina" #: main.c:73 msgid "Ext. Family" msgstr "" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "Model" #: main.c:75 msgid "Ext. Model" msgstr "" #: main.c:76 msgid "Temp." msgstr "Temperatura." #: main.c:77 msgid "Stepping" msgstr "" #: main.c:78 msgid "Instructions" msgstr "Instrukcje" #: main.c:80 msgid "Clocks" msgstr "Zegar" #: main.c:81 msgid "Core Speed" msgstr "" #: main.c:82 msgid "Multiplier" msgstr "" #: main.c:83 msgid "Bus Speed" msgstr "" #: main.c:84 main.c:157 msgid "Usage" msgstr "" #: main.c:86 msgid "Cache" msgstr "" #: main.c:87 msgid "L1 Data" msgstr "" #: main.c:88 msgid "L1 Inst." msgstr "" #: main.c:89 msgid "Level 2" msgstr "" #: main.c:90 msgid "Level 3" msgstr "" #: main.c:92 msgid "Socket(s)" msgstr "" #: main.c:93 msgid "Core(s)" msgstr "" #: main.c:94 msgid "Thread(s)" msgstr "" #: main.c:97 msgid "Caches" msgstr "" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "" #: main.c:102 msgid "Size" msgstr "" #: main.c:103 msgid "Speed" msgstr "" #: main.c:105 msgid "Test" msgstr "" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "Płyta główna" #: main.c:110 msgid "Manufacturer" msgstr "" #: main.c:112 msgid "Revision" msgstr "Rewizja" #: main.c:114 msgid "BIOS" msgstr "BIOS" #: main.c:115 msgid "Brand" msgstr "" #: main.c:116 msgid "Version" msgstr "" #: main.c:117 msgid "Date" msgstr "" #: main.c:118 msgid "ROM Size" msgstr "" #: main.c:120 msgid "Chipset" msgstr "" #: main.c:125 main.c:141 msgid "Memory" msgstr "" #: main.c:128 #, c-format msgid "Bank %i" msgstr "" #: main.c:129 msgid "Reference" msgstr "" #: main.c:133 msgid "System" msgstr "System" #: main.c:134 msgid "Operating System" msgstr "System operacyjny" #: main.c:135 msgid "Kernel" msgstr "Kernel" #: main.c:136 msgid "Distribution" msgstr "Dystrybucja" #: main.c:137 msgid "Hostname" msgstr "Nazwa hosta" #: main.c:138 msgid "Uptime" msgstr "" #: main.c:139 msgid "Compiler" msgstr "" #: main.c:142 msgid "Used" msgstr "Użyte" #: main.c:143 msgid "Buffers" msgstr "Zbuforowane" #: main.c:144 msgid "Cached" msgstr "" #: main.c:145 msgid "Free" msgstr "Wolne" #: main.c:146 msgid "Swap" msgstr "Swap" #: main.c:149 msgid "Graphics" msgstr "Grafika" #: main.c:153 #, c-format msgid "Card %i" msgstr "" #: main.c:156 msgid "Temperature" msgstr "Temperatura" #: main.c:158 msgid "GPU clock" msgstr "" #: main.c:159 msgid "Memory clock" msgstr "" #: main.c:163 msgid "Bench" msgstr "Bench" #: main.c:164 msgid "Prime numbers (slow)" msgstr "Liczby pierwsze (Wolno)" #: main.c:165 msgid "Prime numbers (fast)" msgstr "Liczby pierwsze (Szybko)" #: main.c:168 msgid "Score" msgstr "Wynik" #: main.c:169 msgid "Run" msgstr "Uruchom" #: main.c:172 msgid "Parameters" msgstr "Parametry" #: main.c:173 msgid "Duration" msgstr "Czas trwania" #: main.c:174 msgid "Threads" msgstr "Wątki" #: main.c:177 main.c:182 msgid "About" msgstr "O Programie" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "%s jest darmowym programem który gromadzi informacje\no CPU, płycie głównej i wiele więcej." #: main.c:183 #, c-format msgid "Version %s" msgstr "Wersja %s" #: main.c:184 #, c-format msgid "Author: %s" msgstr "Autor: %s" #: main.c:185 #, c-format msgid "Site: %s" msgstr "Strona domowa: %s" #: main.c:187 msgid "License" msgstr "Licencja" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "" #: main.c:259 msgid "Dumping data..." msgstr "" #: main.c:301 msgid "Freeing memory" msgstr "" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "" #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "" #: main.c:362 msgid "wrong write data" msgstr "" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "" #: main.c:374 main.c:467 msgid "No new version available" msgstr "" #: main.c:375 msgid "(up-to-date)" msgstr "" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "" #: main.c:488 msgid "Downloading new version..." msgstr "" #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "" #: main.c:506 msgid "Extracting new version..." msgstr "" #: main.c:516 msgid "Applying new version..." msgstr "" #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "" #: main.c:529 msgid "Update successful!" msgstr "" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "" #: main.c:553 msgid "Set default tab (integer)" msgstr "" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "" #: main.c:557 msgid "Disable colored output" msgstr "" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "" #: main.c:559 msgid "Verbose output" msgstr "" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "" #: main.c:561 msgid "Print help and exit" msgstr "" #: main.c:562 msgid "Print version and exit" msgstr "" #: main.c:573 msgid "Temporarily disable network support" msgstr "" #: main.c:574 msgid "Enforce the bus clock" msgstr "" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "" #: main.c:586 msgid "Available DISPLAY:" msgstr "" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "" #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "" #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "" #: main.c:846 msgid "an error occurred while setting locale" msgstr "" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "" #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "\nNaciśnij dowolny klawisz, aby zamknąć tę pomoc.\n" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "Jeśli chcesz zaktualizować, naciśnij klawisz 'u', lub cokolwiek innego aby pominąć.\n" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "\n\n%s zostaną zaktualizowane." #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "wystąpił błąd podczas otwierania pliku '%s' (%s)" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "wystąpił błąd podczas uruchamiania polecenia '%s' (%s)" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "" CPU-X-3.2.4/po/pt_BR.po000066400000000000000000000551751341671471500143660ustar00rootroot00000000000000# Portuguese (Brazil) translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # Lara Maia , 2015-2016,2018 # Xorg, 2016,2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: Portuguese (Brazil) (http://www.transifex.com/xorg/cpu-x/language/pt_BR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: core.c:147 msgid "could not reallocate memory" msgstr "não pode realocar memória" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "Saindo %s" #: core.c:175 msgid "Finding CPU technology" msgstr "Encontrando tecnologia da CPU" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "Sua CPU não existe no banco de dados ==> %s, modelo: %i, ext. modelo: %i, ext. família: %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "%d x %d KB, %d-way" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "%d MB, %d-way" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "%s associativa, %d-byte tamanho de linha" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "Chamando libcpuid para recuperar dados estáticos" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "Falhou ao chamar libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "Chamando libcpuid para recuperar dados dinâmicos" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "Pulando abertura do CPU MSR (precisa ser root)" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "Falhou ao abrir CPU MSR (%s)" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "Chamando libcpuid para recuperar valores estáticos da CPU MSR" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "Chamando libcpuid para recuperar valores dinâmicos da CPU MSR" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "Calculando multiplicadores da CPU" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "Pulando chamada ao dmidecode (precisa ser root)" #: core.c:512 msgid "Calling dmidecode" msgstr "Chamando dmidecode" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "falhou ao alocar memória para o dmidecode" #: core.c:539 msgid "failed to call dmidecode" msgstr "falhou ao chamar o dmidecode" #: core.c:554 msgid "Calculating CPU usage" msgstr "Calculando uso da CPU" #: core.c:604 msgid "Calling bandwidth" msgstr "Chamando bandwidth" #: core.c:634 msgid "Finding graphic card driver" msgstr "Encontrando driver da placa gráfica" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "Seu driver de GPU é desconhecido: %s" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "(%s driver)" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "Falhou ao encontrar o driver da placa de vídeo (%s)" #: core.c:695 msgid "Finding devices" msgstr "Encontrando dispositivos" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "Pular pesquisa de dispositivos (precisa ser root)" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "Seu fabricante de GPU é desconhecido: %s (%#X)" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "falhou ao encontrar o fabricante e o modelo do chipset" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "falhou ao encontrar o fabricante e o modelo da placa gráfica" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "Recuperando a temperatura da GPU" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "falhou ao recuperar a temperatura da GPU" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "Ignorar alguns valores da GPU (precisa ser root)" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "Recuperando clock da GPU" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "O driver para a GPU %i não reporta frequências" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "Falhou ao recuperar o clock da GPU" #: core.c:969 msgid "Identifying running system" msgstr "Identificando o sistema em uso" #: core.c:972 msgid "failed to identify running system" msgstr "falhou ao identificar o sistema em uso" #: core.c:1013 msgid "Calling libprocps" msgstr "Chamando libprocps" #: core.c:1035 msgid "Calling libstatgrab" msgstr "Chamando libstatgrab" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "%i dias, %i horas, %i minutos, %i segundos" #: core.c:1120 msgid "Updating benchmark status" msgstr "Atualizando status do benchmark" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "%u min" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "Inativo" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "Não iniciado" #: core.c:1134 msgid "Active" msgstr "Ativo" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "(%u horas restantes)" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "(%u minutos restantes)" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "(%u segundos restantes)" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "em %u horas" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "em %u minutos" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "em %u segundos" #: core.c:1168 msgid "Starting benchmark" msgstr "Iniciando benchmark" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "falhou ao alocar memória para o benchmark" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "um erro ocorreu enquanto iniciava o benchmark" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "Encontrando o pacote da CPU em modo fallback" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "Seu socket de CPU não existe no banco de dados ==> %s, codinome: %s" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "Calculando multiplicadores da CPU em modo fallback" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "Recuperando informações da placa-mãe em modo fallback" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "falhou ao recuperar informações da placa-mãe (modo fallback)" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "Recuperando a temperatura da CPU em modo fallback" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "falhou ao recuperar a temperatura da CPU (modo fallback)" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "Recuperando a voltagem da CPU em modo fallback" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "falhou ao recuperar a voltagem da CPU (modo fallback)" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "Recuperando a frequência da CPU em modo fallback" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "falhou ao recuperar a frequência da CPU (modo fallback)" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "Iniciando a interface gráfica GTK..." #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "Falhou ao importar UI no GtkBuilder" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "É necessário privilégios de root para funcionar corretamente" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "Algumas informações não serão recuperáveis" #: gui_gtk.c:103 msgid "Ignore" msgstr "Ignorar" #: gui_gtk.c:107 msgid "Run as root" msgstr "Executar como root" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "Uma nova versão do %s está disponível!" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "Você quer atualizar %s para a versão %s depois de sair?\nIsso vai substituir o arquivo binário (%s) com a nova versão." #: gui_gtk.c:129 msgid "Not now" msgstr "Não agora" #: gui_gtk.c:129 msgid "Update" msgstr "Atualizar" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "Núcleo #%i" #: main.c:62 msgid "Setting label names" msgstr "Configurando nome dos rótulos" #: main.c:64 msgid "CPU" msgstr "CPU" #: main.c:65 msgid "Processor" msgstr "Processador" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "Fornecedor" #: main.c:67 msgid "Code Name" msgstr "Codinome" #: main.c:68 msgid "Package" msgstr "Pacote" #: main.c:69 msgid "Technology" msgstr "Tecnologia" #: main.c:70 msgid "Voltage" msgstr "Voltagem" #: main.c:71 msgid "Specification" msgstr "Especificação" #: main.c:72 msgid "Family" msgstr "Família" #: main.c:73 msgid "Ext. Family" msgstr "Ext. Família" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "Modelo" #: main.c:75 msgid "Ext. Model" msgstr "Ext. Modelo" #: main.c:76 msgid "Temp." msgstr "Temp." #: main.c:77 msgid "Stepping" msgstr "Stepping" #: main.c:78 msgid "Instructions" msgstr "Instruções" #: main.c:80 msgid "Clocks" msgstr "Frequências" #: main.c:81 msgid "Core Speed" msgstr "Velocidade do Núcleo" #: main.c:82 msgid "Multiplier" msgstr "Multiplicador" #: main.c:83 msgid "Bus Speed" msgstr "Velocidade do Bus" #: main.c:84 main.c:157 msgid "Usage" msgstr "Uso" #: main.c:86 msgid "Cache" msgstr "Cache" #: main.c:87 msgid "L1 Data" msgstr "L1 Data" #: main.c:88 msgid "L1 Inst." msgstr "L1 Inst." #: main.c:89 msgid "Level 2" msgstr "Level 2" #: main.c:90 msgid "Level 3" msgstr "Level 3" #: main.c:92 msgid "Socket(s)" msgstr "Socket(s)" #: main.c:93 msgid "Core(s)" msgstr "Núcleo(s)" #: main.c:94 msgid "Thread(s)" msgstr "Thread(s)" #: main.c:97 msgid "Caches" msgstr "Caches" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "L%i Cache" #: main.c:102 msgid "Size" msgstr "Tamanho" #: main.c:103 msgid "Speed" msgstr "Velocidade" #: main.c:105 msgid "Test" msgstr "Teste" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "Placa-mãe" #: main.c:110 msgid "Manufacturer" msgstr "Fabricante" #: main.c:112 msgid "Revision" msgstr "Revisão" #: main.c:114 msgid "BIOS" msgstr "BIOS" #: main.c:115 msgid "Brand" msgstr "Marca" #: main.c:116 msgid "Version" msgstr "Versão" #: main.c:117 msgid "Date" msgstr "Data" #: main.c:118 msgid "ROM Size" msgstr "Tamanho da ROM" #: main.c:120 msgid "Chipset" msgstr "Chipset" #: main.c:125 main.c:141 msgid "Memory" msgstr "Memória" #: main.c:128 #, c-format msgid "Bank %i" msgstr "Banco %i" #: main.c:129 msgid "Reference" msgstr "Referência" #: main.c:133 msgid "System" msgstr "Sistema" #: main.c:134 msgid "Operating System" msgstr "Sistema Operacional" #: main.c:135 msgid "Kernel" msgstr "Kernel" #: main.c:136 msgid "Distribution" msgstr "Distribuição" #: main.c:137 msgid "Hostname" msgstr "Nome do Host" #: main.c:138 msgid "Uptime" msgstr "Tempo ligado" #: main.c:139 msgid "Compiler" msgstr "Compilador" #: main.c:142 msgid "Used" msgstr "Utilizado" #: main.c:143 msgid "Buffers" msgstr "Buffers" #: main.c:144 msgid "Cached" msgstr "Em Cache" #: main.c:145 msgid "Free" msgstr "Livre" #: main.c:146 msgid "Swap" msgstr "Swap" #: main.c:149 msgid "Graphics" msgstr "Gráficos" #: main.c:153 #, c-format msgid "Card %i" msgstr "Placa %i" #: main.c:156 msgid "Temperature" msgstr "Temperatura" #: main.c:158 msgid "GPU clock" msgstr "Clock da GPU" #: main.c:159 msgid "Memory clock" msgstr "Clock da memória" #: main.c:163 msgid "Bench" msgstr "Bench" #: main.c:164 msgid "Prime numbers (slow)" msgstr "Números primos (lento)" #: main.c:165 msgid "Prime numbers (fast)" msgstr "Números primos (rápido)" #: main.c:168 msgid "Score" msgstr "Pontuação" #: main.c:169 msgid "Run" msgstr "Rodar" #: main.c:172 msgid "Parameters" msgstr "Parâmetros" #: main.c:173 msgid "Duration" msgstr "Duração" #: main.c:174 msgid "Threads" msgstr "Threads" #: main.c:177 main.c:182 msgid "About" msgstr "Sobre" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "%s é um software Livre que coleta informações sobre\na sua CPU, placa-mãe e mais." #: main.c:183 #, c-format msgid "Version %s" msgstr "Versão %s" #: main.c:184 #, c-format msgid "Author: %s" msgstr "Autor : %s" #: main.c:185 #, c-format msgid "Site: %s" msgstr "Site: %s" #: main.c:187 msgid "License" msgstr "Licença" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "Esse programa é distribuído nos termos da %s" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "Esse programa vem com ABSOLUTAMENTE NENHUMA GARANTIA" #: main.c:259 msgid "Dumping data..." msgstr "Dados de despejo..." #: main.c:301 msgid "Freeing memory" msgstr "Liberando memória" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "Checando na internet por uma nova versão" #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "falhou ao abrir uma sessão do Curl" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "falhou ao realizar a transferência Curl (%s)" #: main.c:362 msgid "wrong write data" msgstr "dados de escrita incorretos" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "(versão %s está disponível)" #: main.c:374 main.c:467 msgid "No new version available" msgstr "Nenhuma nova versão disponível" #: main.c:375 msgid "(up-to-date)" msgstr "(atualizado)" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "um erro ocorreu enquanto extraía o arquivo %s (%s)" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "O acesso a rede está desabilitado por uma variável de ambiente (defina CPUX_NETWORK com um valor positivo para habilitar)" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "falhou ao abrir o arquivo %s para escrita" #: main.c:488 msgid "Downloading new version..." msgstr "Baixando nova versão..." #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "falhou ao baixar o arquivo %s (%s)" #: main.c:506 msgid "Extracting new version..." msgstr "Extraindo nova versão..." #: main.c:516 msgid "Applying new version..." msgstr "Aplicando nova versão..." #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "um erro ocorreu enquanto deletava/renomeava arquivos" #: main.c:529 msgid "Update successful!" msgstr "Atualização bem sucedida!" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "Inicia a interface de usuário em modo gráfico (GUI) (padrão)" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "Inicia a interface de usuário em modo de texto (TUI)" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "Despeja todos os dados na saída padrão e sai" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "Executa o comando dmidecode embutido e sai" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "Executa o comando bandwidth embutido e sai" #: main.c:553 msgid "Set default tab (integer)" msgstr "Define a aba padrão (inteiro)" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "Selecione um núcleo de CPU para monitorar (inteiro)" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "Definir um teste de bandwidth personalizado para a velocidade de cache da CPU (inteiro)" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "Definir um intervalo personalizado entre duas atualizações (em segundos)" #: main.c:557 msgid "Disable colored output" msgstr "Desabilita a saída colorida" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "Imprimir informações necessárias para colar em uma questão" #: main.c:559 msgid "Verbose output" msgstr "Saída verbosa" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "Atualizar a versão portátil se uma nova versão estiver disponível" #: main.c:561 msgid "Print help and exit" msgstr "Imprime a ajuda e sai" #: main.c:562 msgid "Print version and exit" msgstr "Imprime a versão e sai" #: main.c:573 msgid "Temporarily disable network support" msgstr "Desabilitar temporariamente o suporte à rede" #: main.c:574 msgid "Enforce the bus clock" msgstr "Forçar o bus clock" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "Ler dados crus do CPUID de um determinado arquivo" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "Somente mostrar uma mensagem se a CPU não estiver no banco de dados" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "Uso: %s TELA [OPÇÕES]\n" #: main.c:586 msgid "Available DISPLAY:" msgstr "Tela disponível:" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "\nOpções disponíveis:" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "\nVariáveis de ambiente influenciáveis:" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "Este é um programa livre : você é livre para modificá-lo eredistribuí-lo." #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "Veja a %s licença: <%s>\n" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "Compilado em %s, %s (com %s %s em %s)." #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "-- %-9s versão: %s" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "\n%sOops, alguma coisa está errada! %s recebeu o sinal %d (%s) e saiu.%s" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "Você pode colar esse backtrace abrindo uma nova issue aqui:" #: main.c:846 msgid "an error occurred while setting locale" msgstr "um erro ocorreu enquanto definia a localização" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "Iniciando a interface de texto NCurses..." #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "Pressione 'h' para ver a ajuda.\n" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "Bem vindo a ajuda do %s Ncurses!\n" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "Essa ajuda descreve como usar a interface de usuário baseada em texto.\n" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "\nChaves globais:\n" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "\tPressione a tecla 'esquerda' para alternar a aba esquerda.\n" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "\tPressione a tecla 'direita' para alternar a aba direita.\n" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "\tPressione 'h' para ver essa ajuda.\n" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "\tPressione a tecla 'q' para sair.\n" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "\nAba da CPU:\n" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "\tPressione a tecla 'abaixo' para diminutir o número de núcleos à monitorar.\n" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "\tPressione a tecla 'acima' para aumentar o número de núcleos à monitorar.\n" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "\nAba Caches:\n" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "\tPressione a tecla 'abaixo' para alternar para o teste anterior.\n" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "\tPressione a tecla 'acima' para alternar para o próximo teste.\n" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "\nAba Bench:\n" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "\tPressione a tecla 'abaixo' para decrementar a duração do benchmark.\n" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "\tPressione a tecla 'acima' para incrementar a duração do benchmark.\n" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "\tPressione a tecla 'próxima página' para decrementar o número de threads\n" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "\tPressione a tecla 'página anterior' para incrementar o número de threads\n" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "\tPressione a tecla 's' para iniciar/parar o benchmark de números primos (lento).\n" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "\tPressione a tecla 'f' para iniciar/parar o benchmark de números primos (rápido).\n" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "\nPressione qualquer tecla para sair desta ajuda.\n" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "se você quiser atualizar, pressione a tecla 'u', ou qualquer outra para pular.\n" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "\n\n%s vai ser atualizado." #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "um erro ocorreu enquanto abria o arquivo '%s' (%s)" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "um erro ocorreu enquanto rodava o comando '%s' (%s)" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "falhou ao abrir o diretório %s" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "um erro ocorreu enquanto compilava o regex" CPU-X-3.2.4/po/ru.po000066400000000000000000000675461341671471500140130ustar00rootroot00000000000000# Russian translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # TotalCaesar659 , 2016,2018 # Xorg, 2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: Russian (http://www.transifex.com/xorg/cpu-x/language/ru/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" #: core.c:147 msgid "could not reallocate memory" msgstr "Не удалось перераспределить память" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "Выход из %s" #: core.c:175 msgid "Finding CPU technology" msgstr "Обнаружение технологии ЦП" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "Ваш ЦП отсутствует в базе данных ==> %s, модель: %i, доп. модель: %i, доп. семейство: %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "%d x %d кБ, %d-канальный" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "%d Mб, %d-канальный" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "%s ассоциативный, %d-байтовый размер кэш-линии" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "Вызов libcpuid для получения статических данных" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "не удалось вызвать libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "Вызов libcpuid для получения динамических данных" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "Пропустить открытие моделезависимых регистров ЦП (требуются права администратора)" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "не удалось открыть моделезависимые регистры ЦП (%s)" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "Вызов libcpuid для получения статических значений моделезависимых регистров ЦП" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "Вызов libcpuid для получения динамических значений моделезависимых регистров ЦП" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "Подсчет множителей ЦП" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "Пропустить вызов dmidecode (требуются права администратора)" #: core.c:512 msgid "Calling dmidecode" msgstr "Вызов dmidecode" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "не удалось переназначить память для dmidecode" #: core.c:539 msgid "failed to call dmidecode" msgstr "не удалось вызвать dmidecode" #: core.c:554 msgid "Calculating CPU usage" msgstr "Подсчет использования ЦП" #: core.c:604 msgid "Calling bandwidth" msgstr "Вызов пропускной способности" #: core.c:634 msgid "Finding graphic card driver" msgstr "Поиск драйвера видеокарты" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "Неизвестный драйвер ГП: %s" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "(драйвер %s)" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "не удалось найти драйвер видеокарты (%s)" #: core.c:695 msgid "Finding devices" msgstr "Поиск устройств" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "Пропустить поиск устройств (требуются права администратора)" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "Неизвестный производитель ГП: %s (%#X)" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "не удалось найти производителя и модель чипсета" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "не удалось найти производителя и модель видеокарты" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "Получение температуры ГП" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "не удалось получить температуру ГП" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "Пропускать некоторые значения ГП (требуются права администратора)" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "Получение частоты ГП" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "Драйвер ГП %i не отдает значения частоты" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "не удалось получить частоту ГП" #: core.c:969 msgid "Identifying running system" msgstr "Определение запущенной системы" #: core.c:972 msgid "failed to identify running system" msgstr "не удалось определить запущенную систему" #: core.c:1013 msgid "Calling libprocps" msgstr "Вызов libprocps" #: core.c:1035 msgid "Calling libstatgrab" msgstr "Вызов libstatgrab" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "%i дней, %i часов, %i минут, %i секунд" #: core.c:1120 msgid "Updating benchmark status" msgstr "Обновление состояния бенчмарка" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "%u минут" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "Неактивен" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "Не запускался" #: core.c:1134 msgid "Active" msgstr "Активен" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "(осталось %u часов)" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "(осталось %u минут)" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "(осталось %u секунд)" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "за %u часов" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "за %u минут" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "за %u секунд" #: core.c:1168 msgid "Starting benchmark" msgstr "Запуск бенчмарка" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "не удалось переназначить память для бенчмарка" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "ошибка при запуске бенчмарка" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "Поиск корпусировки ЦП в fallback-режиме" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "Ваш сокет ЦП отсутствует в базе данных ==> %s, кодовое название: %s" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "Подсчет множителей ЦП в fallback-режиме" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "Получение информации о материнской плате в fallback-режиме" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "не удалось получить информацию о материнской плате (fallback-режим)" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "Получение температуры ЦП в fallback-режиме" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "не удалось получить температуру ЦП (fallback-режим)" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "Получение напряжения ЦП в fallback-режиме" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "не удалось получить напряжение ЦП (fallback-режим)" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "Получение частоты ЦП в fallback-режиме" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "не удалось получить частоту ЦП (fallback-режим)" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "Запуск графического интерфейса GTK..." #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "не удалось импортировать интерфейс в GtkBuilder" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "Для корректной работы требуются права администратора" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "Невозможно получить некоторые данные" #: gui_gtk.c:103 msgid "Ignore" msgstr "Пропустить" #: gui_gtk.c:107 msgid "Run as root" msgstr "Запустить с правами администратора" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "Доступна новая версия %s!" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "Вы хотите обновить %s до версии %s после выхода?\nБинарный файл (%s) будет заменен новой версией." #: gui_gtk.c:129 msgid "Not now" msgstr "Не сейчас" #: gui_gtk.c:129 msgid "Update" msgstr "Обновить" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "Ядро #%i" #: main.c:62 msgid "Setting label names" msgstr "Установка названий меток" #: main.c:64 msgid "CPU" msgstr "ЦП" #: main.c:65 msgid "Processor" msgstr "Процессор" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "Производитель" #: main.c:67 msgid "Code Name" msgstr "Кодовое название" #: main.c:68 msgid "Package" msgstr "Корпусировка" #: main.c:69 msgid "Technology" msgstr "Технология" #: main.c:70 msgid "Voltage" msgstr "Напряжение" #: main.c:71 msgid "Specification" msgstr "Спецификация" #: main.c:72 msgid "Family" msgstr "Семейство" #: main.c:73 msgid "Ext. Family" msgstr "Доп. семейство" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "Модель" #: main.c:75 msgid "Ext. Model" msgstr "Доп. модель" #: main.c:76 msgid "Temp." msgstr "Темп." #: main.c:77 msgid "Stepping" msgstr "Степпинг" #: main.c:78 msgid "Instructions" msgstr "Инструкции" #: main.c:80 msgid "Clocks" msgstr "Частоты" #: main.c:81 msgid "Core Speed" msgstr "Тактовая частота ядра" #: main.c:82 msgid "Multiplier" msgstr "Множитель" #: main.c:83 msgid "Bus Speed" msgstr "Скорость шины" #: main.c:84 main.c:157 msgid "Usage" msgstr "Использование" #: main.c:86 msgid "Cache" msgstr "Кэш" #: main.c:87 msgid "L1 Data" msgstr "Уровень 1 (данные)" #: main.c:88 msgid "L1 Inst." msgstr "Уровень 1" #: main.c:89 msgid "Level 2" msgstr "Уровень 2" #: main.c:90 msgid "Level 3" msgstr "Уровень 3" #: main.c:92 msgid "Socket(s)" msgstr "Сокет(-ы)" #: main.c:93 msgid "Core(s)" msgstr "Ядро(-а)" #: main.c:94 msgid "Thread(s)" msgstr "Поток(-и)" #: main.c:97 msgid "Caches" msgstr "Кэши" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "Кэш L%i" #: main.c:102 msgid "Size" msgstr "Размер" #: main.c:103 msgid "Speed" msgstr "Скорость" #: main.c:105 msgid "Test" msgstr "Тест" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "Материнская плата" #: main.c:110 msgid "Manufacturer" msgstr "Производитель" #: main.c:112 msgid "Revision" msgstr "Ревизия" #: main.c:114 msgid "BIOS" msgstr "BIOS" #: main.c:115 msgid "Brand" msgstr "Марка" #: main.c:116 msgid "Version" msgstr "Версия" #: main.c:117 msgid "Date" msgstr "Дата" #: main.c:118 msgid "ROM Size" msgstr "Размер ROM" #: main.c:120 msgid "Chipset" msgstr "Чипсет" #: main.c:125 main.c:141 msgid "Memory" msgstr "Оперативная память" #: main.c:128 #, c-format msgid "Bank %i" msgstr "Модуль %i" #: main.c:129 msgid "Reference" msgstr "Описание" #: main.c:133 msgid "System" msgstr "Система" #: main.c:134 msgid "Operating System" msgstr "Операционная система" #: main.c:135 msgid "Kernel" msgstr "Ядро" #: main.c:136 msgid "Distribution" msgstr "Дистрибутив" #: main.c:137 msgid "Hostname" msgstr "Имя хоста" #: main.c:138 msgid "Uptime" msgstr "Время работы" #: main.c:139 msgid "Compiler" msgstr "Компилятор" #: main.c:142 msgid "Used" msgstr "Используется" #: main.c:143 msgid "Buffers" msgstr "Буферы" #: main.c:144 msgid "Cached" msgstr "Кэш" #: main.c:145 msgid "Free" msgstr "Свободно" #: main.c:146 msgid "Swap" msgstr "Подкачка" #: main.c:149 msgid "Graphics" msgstr "Графическая подсистема" #: main.c:153 #, c-format msgid "Card %i" msgstr "Карта %i" #: main.c:156 msgid "Temperature" msgstr "Температура" #: main.c:158 msgid "GPU clock" msgstr "Частота ГП" #: main.c:159 msgid "Memory clock" msgstr "Частота памяти" #: main.c:163 msgid "Bench" msgstr "Бенчмарк" #: main.c:164 msgid "Prime numbers (slow)" msgstr "Простые числа (медленно)" #: main.c:165 msgid "Prime numbers (fast)" msgstr "Простые числа (быстро)" #: main.c:168 msgid "Score" msgstr "Счет" #: main.c:169 msgid "Run" msgstr "Запуск" #: main.c:172 msgid "Parameters" msgstr "Параметры" #: main.c:173 msgid "Duration" msgstr "Продолжительность" #: main.c:174 msgid "Threads" msgstr "Потоки" #: main.c:177 main.c:182 msgid "About" msgstr "О программе" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "%s это свободное программное обеспечение\nдля сбора информации о процессоре, видеокарте и др." #: main.c:183 #, c-format msgid "Version %s" msgstr "Версия %s" #: main.c:184 #, c-format msgid "Author: %s" msgstr "Автор: %s" #: main.c:185 #, c-format msgid "Site: %s" msgstr "Сайт: %s" #: main.c:187 msgid "License" msgstr "Лицензия" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "Данное программное обеспечение распространяется на условиях %s" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "Данное программное обеспечение предоставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ" #: main.c:259 msgid "Dumping data..." msgstr "Сбор данных" #: main.c:301 msgid "Freeing memory" msgstr "Освобождение памяти" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "Проверка обновлений через интернет..." #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "не удалось открыть сессию Curl" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "не удалось выполнить перенос Curl (%s)" #: main.c:362 msgid "wrong write data" msgstr "неверные данные записи" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "(доступна версия %s)" #: main.c:374 main.c:467 msgid "No new version available" msgstr "Обновлений нет" #: main.c:375 msgid "(up-to-date)" msgstr "(последняя версия)" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "ошибка при извлечении архива %s (%s)" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "Доступ к сети отключен переменной окружения (для его включения установите положительное значение CPUX_NETWORK)" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "не удалось открыть архив %s для записи" #: main.c:488 msgid "Downloading new version..." msgstr "Загрузка новой версии..." #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "не удалось загрузить архив %s (%s)" #: main.c:506 msgid "Extracting new version..." msgstr "Извлечение обновлений..." #: main.c:516 msgid "Applying new version..." msgstr "Применение обновлений..." #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "ошибка при удалении/переименовании файлов" #: main.c:529 msgid "Update successful!" msgstr "Обновление завершено!" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "Запустить графический интерфейс (GUI) (по умолчанию)" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "Запустить текстовый интерфейс (TUI)" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "Собрать все данные стандартного вывода и выйти" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "Запустить расширенную команду dmidecode и выйти" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "Запустить расширенную команду bandwidth и выйти" #: main.c:553 msgid "Set default tab (integer)" msgstr "Установить вкладку по умолчанию (целое число)" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "Установить ядро ЦП для мониторинга (целое число)" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "Установить тест пропускной способности для скорости кэша ЦП (целое число)" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "Установить время между обновлениями (в секундах)" #: main.c:557 msgid "Disable colored output" msgstr "Отключить цветной вывод" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "Вывести требуемую информацию для вставки в отчет об ошибке" #: main.c:559 msgid "Verbose output" msgstr "Текстовый вывод" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "Обновить переносную версию (при доступности обновлений)" #: main.c:561 msgid "Print help and exit" msgstr "Показать помощь и выйти" #: main.c:562 msgid "Print version and exit" msgstr "Показать версию и выйти" #: main.c:573 msgid "Temporarily disable network support" msgstr "Временно отключить поддержку сети" #: main.c:574 msgid "Enforce the bus clock" msgstr "Принудительно установить тактовую частоту шины" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "Прочитать сырые данные CPUID из заданного файла" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "Только вывести сообщение, если ЦП не обнаружен в базе данных" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "Использование: %s ДИСПЛЕЙ [ОПЦИИ]\n" #: main.c:586 msgid "Available DISPLAY:" msgstr "Доступный ДИСПЛЕЙ:" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "\nДоступные ОПЦИИ:" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "\nЗатрагиваемые переменные окружения:" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "Это свободное программное обеспечение. Вы можете изменять и распространять его." #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "Посмотреть лицензию %s: <%s>\n" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "Скомпилировано на %s, %s (с помощью %s %s на %s)." #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "-- %-9s версия: %s" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "\n%sОй, что-то пошло не так! %s получил сигнал %d (%s) и прекратил работу.%s" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "Вы можете открыть новую тему и вставить в нее вывод ошибки:" #: main.c:846 msgid "an error occurred while setting locale" msgstr "ошибка при установке локализации" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "Запуск текстового интерфейса NCurses..." #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "Нажмите \"H\" для получения помощи.\n" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "Добро пожаловать в %s помощь NCurses!\n" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "Здесь описано, как использовать текстовый интерфейс.\n" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "\nГлобальные клавиши:\n" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "Нажмите клавишу \"влево\", чтобы перейти на вкладку слева.\n" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "Нажмите клавишу \"вправо\", чтобы перейти на вкладку справа.\n" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "Нажмите клавишу \"H\" для вызова помощи.\n" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "Нажмите \"Q\" для выхода.\n" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "\nВкладка \"ЦП\":\n" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "Нажмите клавишу \"вниз\" для уменьшения номера ядра для мониторинга.\n" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "Нажмите клавишу \"вверх\" для увеличения номера ядра для мониторинга.\n" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "\nВкладка \"Кэши\":\n" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "Нажмите клавишу \"вниз\" для перехода к предыдущему тесту.\n" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "Нажмите клавишу \"вверх\" для перехода к следующему тесту.\n" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "\nВкладка \"Бенчмарк\":\n" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "Нажмите клавишу \"вниз\" для уменьшения длительности бенчмарка.\n" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "Нажмите клавишу \"вверх\" для увеличения длительности бенчмарка.\n" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "Нажмите клавишу \"предыдущая страница\" для уменьшения числа используемых потоков.\n" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "Нажмите клавишу \"следующая страница\" для увеличения числа используемых потоков.\n" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "Нажмите клавишу \"S\" для запуска/остановки бенчмарка \"простые числа (медленно)\".\n" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "Нажмите клавишу \"F\" для запуска/остановки бенчмарка \"простые числа (быстро)\".\n" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "\nНажмите любую клавишу для выхода из помощи.\n" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "Нажмите клавишу \"U\" для обновления или любую другую для пропуска.\n" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "\n\n%s будет обновлен." #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "ошибка при открытии файла '%s' (%s)" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "ошибка при выполнении команды '%s' (%s)" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "не удалось открыть папку %s" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "ошибка при компиляции регулярных выражений" CPU-X-3.2.4/po/zh.po000066400000000000000000000520351341671471500137710ustar00rootroot00000000000000# Chinese translation. # Copyright © 2014-2019 Xorg # This file is distributed under the same license as the CPU-X package. # # Translators: # Xorg, 2018 # 高垚鑫, 2017-2018 msgid "" msgstr "" "Project-Id-Version: CPU-X\n" "Report-Msgid-Bugs-To: https://github.com/X0rg/CPU-X/issues\n" "POT-Creation-Date: 2018-09-16 13:53+0200\n" "PO-Revision-Date: 2018-09-16 11:59+0000\n" "Last-Translator: Xorg\n" "Language-Team: Chinese (http://www.transifex.com/xorg/cpu-x/language/zh/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh\n" "Plural-Forms: nplurals=1; plural=0;\n" #: core.c:147 msgid "could not reallocate memory" msgstr "无法重新分配内存" #: core.c:148 #, c-format msgid "Exiting %s" msgstr "正在退出 %s" #: core.c:175 msgid "Finding CPU technology" msgstr "正在查找 CPU 工艺" #: core.c:194 #, c-format msgid "" "Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext." " family: %i" msgstr "数据库中没有您的 CPU ==> %s,型号: %i,扩展型号: %i,扩展系列: %i" #: core.c:204 #, c-format msgid "%d x %d KB, %d-way" msgstr "%d x %d KB, %d-路" #: core.c:205 #, c-format msgid "%d MB, %d-way" msgstr "%d MB, %d-路" #: core.c:206 #, c-format msgid "%s associative, %d-byte line size" msgstr "%s 关联, %d-byte 最小缓存单元大小" #: core.c:211 msgid "Calling libcpuid for retrieving static data" msgstr "正在调用 libcpuid 以检索静态数据" #: core.c:219 #, c-format msgid "failed to call libcpuid (%s)" msgstr "无法调用 libcpuid (%s)" #: core.c:381 msgid "Calling libcpuid for retrieving dynamic data" msgstr "正在调用 libcpuid 以检索动态数据" #: core.c:393 msgid "Skip CPU MSR opening (need to be root)" msgstr "跳过启用 CPU MSR (需要 root)" #: core.c:400 #, c-format msgid "failed to open CPU MSR (%s)" msgstr "无法启用 CPU MSR (%s)" #: core.c:416 msgid "Calling libcpuid for retrieving CPU MSR static values" msgstr "正在调用 libcpuid 以检索 CPU MSR 静态值" #: core.c:448 msgid "Calling libcpuid for retrieving CPU MSR dynamic values" msgstr "正在调用 libcpuid 以检索 CPU MSR 动态值" #: core.c:469 msgid "Calculating CPU multipliers" msgstr "正在计算 CPU 倍频" #: core.c:508 msgid "Skip call to dmidecode (need to be root)" msgstr "跳过调用 dmidecode (需要 root)" #: core.c:512 msgid "Calling dmidecode" msgstr "正在调用 dmidecode" #: core.c:516 msgid "failed to allocate memory for dmidecode" msgstr "无法为 dmidecode 分配内存" #: core.c:539 msgid "failed to call dmidecode" msgstr "无法调用 dmidecode" #: core.c:554 msgid "Calculating CPU usage" msgstr "正在计算 CPU 使用率" #: core.c:604 msgid "Calling bandwidth" msgstr "正在调用 bandwidth" #: core.c:634 msgid "Finding graphic card driver" msgstr "正在查找显卡驱动程序" #: core.c:659 #, c-format msgid "Your GPU driver is unknown: %s" msgstr "您的 GPU 驱动未知: %s" #: core.c:661 #, c-format msgid "(%s driver)" msgstr "(%s 驱动)" #: core.c:679 #, c-format msgid "failed to find graphic card driver (%s)" msgstr "未找到显卡驱动程序 (%s)" #: core.c:695 msgid "Finding devices" msgstr "正在搜索设备" #: core.c:700 msgid "Skip devices search (need to be root)" msgstr "跳过设备搜索 (需要 root)" #: core.c:729 #, c-format msgid "Your GPU vendor is unknown: %s (%#X)" msgstr "您的 GPU 供应商未知: %s (%#X)" #: core.c:741 msgid "failed to find chipset vendor and model" msgstr "未找到芯片组供应商和型号" #: core.c:743 msgid "failed to find graphic card vendor and model" msgstr "未找到显卡供应商和型号" #: core.c:779 msgid "Retrieving GPU temperature" msgstr "正在检索 GPU 温度" #: core.c:786 msgid "Off" msgstr "" #: core.c:825 msgid "failed to retrieve GPU temperature" msgstr "无法检索 GPU 温度" #: core.c:842 msgid "Skip some GPU values (need to be root)" msgstr "跳过某些 GPU 值 (需要 root)" #: core.c:860 msgid "Retrieving GPU clocks" msgstr "正在检索 GPU 时钟" #: core.c:931 #, c-format msgid "Driver for GPU %i doesn't report frequencies" msgstr "GPU 驱动 %i 无法报告频率" #: core.c:954 msgid "failed to retrieve GPU clocks" msgstr "无法检索 GPU 时钟" #: core.c:969 msgid "Identifying running system" msgstr "正在识别本系统" #: core.c:972 msgid "failed to identify running system" msgstr "未识别本系统" #: core.c:1013 msgid "Calling libprocps" msgstr "正在调用 libprocps" #: core.c:1035 msgid "Calling libstatgrab" msgstr "正在调用 libstatgrab" #: core.c:1065 #, c-format msgid "%i days, %i hours, %i minutes, %i seconds" msgstr "%i 天,%i 小时,%i 分钟,%i 秒" #: core.c:1120 msgid "Updating benchmark status" msgstr "正在更新基准测试状态" #: core.c:1121 tui_ncurses.c:754 #, c-format msgid "%u mins" msgstr "%u 分钟" #: core.c:1123 core.c:1124 msgid "Inactive" msgstr "待用" #: core.c:1128 core.c:1129 msgid "Not started" msgstr "未启动" #: core.c:1134 msgid "Active" msgstr "启用" #: core.c:1139 #, c-format msgid "(%u hours left)" msgstr "(剩余 %u 小时)" #: core.c:1141 #, c-format msgid "(%u minutes left)" msgstr "(剩余 %u 分钟)" #: core.c:1143 #, c-format msgid "(%u seconds left)" msgstr "(剩余 %u 秒)" #: core.c:1148 #, c-format msgid "in %u hours" msgstr "%u 小时后" #: core.c:1150 #, c-format msgid "in %u minutes" msgstr "%u 分钟后" #: core.c:1152 #, c-format msgid "in %u seconds" msgstr "%u 秒后" #: core.c:1168 msgid "Starting benchmark" msgstr "正在启动基准测试" #: core.c:1177 msgid "failed to allocate memory for benchmark" msgstr "无法为基准测试分配内存" #: core.c:1191 msgid "an error occurred while starting benchmark" msgstr "启动基准测试时出错" #: core.c:1208 msgid "Finding CPU package in fallback mode" msgstr "正在故障预置模式下查找 CPU 封装" #: core.c:1226 #, c-format msgid "Your CPU socket does not belong in database ==> %s, codename: %s" msgstr "数据库中没有您的 CPU 插槽 ==> %s,架构:%s" #: core.c:1245 msgid "Calculating CPU multipliers in fallback mode" msgstr "正在应急模式下计算 CPU 倍频" #: core.c:1272 msgid "Retrieving motherboard informations in fallback mode" msgstr "正在应急模式下检索主板信息" #: core.c:1279 msgid "failed to retrieve motherboard informations (fallback mode)" msgstr "无法检索主板信息 (应急模式)" #: core.c:1344 msgid "Retrieving CPU temperature in fallback mode" msgstr "正在应急模式下检索 CPU 温度" #: core.c:1361 msgid "failed to retrieve CPU temperature (fallback mode)" msgstr "未能检索 CPU 温度 (应急模式)" #: core.c:1375 msgid "Retrieving CPU voltage in fallback mode" msgstr "正在应急模式下检索 CPU 电压" #: core.c:1388 msgid "failed to retrieve CPU voltage (fallback mode)" msgstr "未能检索 CPU 电压 (应急模式)" #: core.c:1401 msgid "Retrieving CPU frequency in fallback mode" msgstr "正在应急模式下检索 CPU 频率" #: core.c:1409 msgid "failed to retrieve CPU frequency (fallback mode)" msgstr "未能检索 CPU 频率 (应急模式)" #: gui_gtk.c:49 msgid "Starting GTK GUI..." msgstr "正在启动 GTK 图形用户界面..." #: gui_gtk.c:63 msgid "failed to import UI in GtkBuilder" msgstr "无法在 GtkBuilder 中导入用户界面" #: gui_gtk.c:98 main.c:940 msgid "Root privileges are required to work properly" msgstr "需要 root 权限以正常工作" #: gui_gtk.c:101 main.c:941 msgid "Some informations will not be retrievable" msgstr "某些信息无法检索" #: gui_gtk.c:103 msgid "Ignore" msgstr "忽略" #: gui_gtk.c:107 msgid "Run as root" msgstr "以 root 权限运行" #: gui_gtk.c:123 main.c:368 tui_ncurses.c:422 #, c-format msgid "A new version of %s is available!" msgstr "新版本 %s 可用!" #: gui_gtk.c:126 tui_ncurses.c:424 #, c-format msgid "" "Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version." msgstr "您想在退出后将版本 %s 更新至版本 %s 吗?\n将会用新版本替换该二进制文件 (%s) 。" #: gui_gtk.c:129 msgid "Not now" msgstr "现在不要" #: gui_gtk.c:129 msgid "Update" msgstr "更新" #: gui_gtk.c:515 tui_ncurses.c:480 #, c-format msgid "Core #%i" msgstr "核心 #%i" #: main.c:62 msgid "Setting label names" msgstr "正在设置标签名称" #: main.c:64 msgid "CPU" msgstr "CPU" #: main.c:65 msgid "Processor" msgstr "处理器" #: main.c:66 main.c:121 main.c:154 msgid "Vendor" msgstr "制造商" #: main.c:67 msgid "Code Name" msgstr "架构" #: main.c:68 msgid "Package" msgstr "接口" #: main.c:69 msgid "Technology" msgstr "工艺" #: main.c:70 msgid "Voltage" msgstr "电压" #: main.c:71 msgid "Specification" msgstr "规格" #: main.c:72 msgid "Family" msgstr "系列" #: main.c:73 msgid "Ext. Family" msgstr "扩展系列" #: main.c:74 main.c:111 main.c:122 main.c:155 msgid "Model" msgstr "型号" #: main.c:75 msgid "Ext. Model" msgstr "扩展型号" #: main.c:76 msgid "Temp." msgstr "温度" #: main.c:77 msgid "Stepping" msgstr "步进" #: main.c:78 msgid "Instructions" msgstr "指令集" #: main.c:80 msgid "Clocks" msgstr "时钟" #: main.c:81 msgid "Core Speed" msgstr "核心速度" #: main.c:82 msgid "Multiplier" msgstr "倍频" #: main.c:83 msgid "Bus Speed" msgstr "总线速度" #: main.c:84 main.c:157 msgid "Usage" msgstr "使用率" #: main.c:86 msgid "Cache" msgstr "缓存" #: main.c:87 msgid "L1 Data" msgstr "一级数据缓存" #: main.c:88 msgid "L1 Inst." msgstr "一级指令缓存" #: main.c:89 msgid "Level 2" msgstr "二级缓存" #: main.c:90 msgid "Level 3" msgstr "三级缓存" #: main.c:92 msgid "Socket(s)" msgstr "插槽" #: main.c:93 msgid "Core(s)" msgstr "核心" #: main.c:94 msgid "Thread(s)" msgstr "线程" #: main.c:97 msgid "Caches" msgstr "缓存" #: main.c:101 #, c-format msgid "L%i Cache" msgstr "%i级缓存" #: main.c:102 msgid "Size" msgstr "大小" #: main.c:103 msgid "Speed" msgstr "速度" #: main.c:105 msgid "Test" msgstr "测试" #: main.c:108 main.c:109 msgid "Motherboard" msgstr "主板" #: main.c:110 msgid "Manufacturer" msgstr "制造商" #: main.c:112 msgid "Revision" msgstr "版本修订" #: main.c:114 msgid "BIOS" msgstr "BIOS" #: main.c:115 msgid "Brand" msgstr "品牌" #: main.c:116 msgid "Version" msgstr "版本" #: main.c:117 msgid "Date" msgstr "日期" #: main.c:118 msgid "ROM Size" msgstr "ROM 大小" #: main.c:120 msgid "Chipset" msgstr "芯片组" #: main.c:125 main.c:141 msgid "Memory" msgstr "内存" #: main.c:128 #, c-format msgid "Bank %i" msgstr "插槽 %i" #: main.c:129 msgid "Reference" msgstr "引用" #: main.c:133 msgid "System" msgstr "系统" #: main.c:134 msgid "Operating System" msgstr "操作系统" #: main.c:135 msgid "Kernel" msgstr "内核" #: main.c:136 msgid "Distribution" msgstr "发行版" #: main.c:137 msgid "Hostname" msgstr "主机名" #: main.c:138 msgid "Uptime" msgstr "运行时间" #: main.c:139 msgid "Compiler" msgstr "编译器" #: main.c:142 msgid "Used" msgstr "已用" #: main.c:143 msgid "Buffers" msgstr "缓冲" #: main.c:144 msgid "Cached" msgstr "缓存" #: main.c:145 msgid "Free" msgstr "可用" #: main.c:146 msgid "Swap" msgstr "交换" #: main.c:149 msgid "Graphics" msgstr "显卡" #: main.c:153 #, c-format msgid "Card %i" msgstr "卡 %i" #: main.c:156 msgid "Temperature" msgstr "温度" #: main.c:158 msgid "GPU clock" msgstr "GPU 时钟" #: main.c:159 msgid "Memory clock" msgstr "内存时钟" #: main.c:163 msgid "Bench" msgstr "基准测试" #: main.c:164 msgid "Prime numbers (slow)" msgstr "素数 (慢速)" #: main.c:165 msgid "Prime numbers (fast)" msgstr "素数 (快速)" #: main.c:168 msgid "Score" msgstr "分数" #: main.c:169 msgid "Run" msgstr "运行" #: main.c:172 msgid "Parameters" msgstr "参数" #: main.c:173 msgid "Duration" msgstr "持续时间" #: main.c:174 msgid "Threads" msgstr "线程" #: main.c:177 main.c:182 msgid "About" msgstr "关于" #: main.c:179 #, c-format msgid "" "%s is a Free software that gathers information\n" "on CPU, motherboard and more." msgstr "%s 是一个自由软件,收集有关\n CPU 和主板等的信息。" #: main.c:183 #, c-format msgid "Version %s" msgstr "%s 版" #: main.c:184 #, c-format msgid "Author: %s" msgstr "作者:%s" #: main.c:185 #, c-format msgid "Site: %s" msgstr "网站:%s" #: main.c:187 msgid "License" msgstr "许可证" #: main.c:190 #, c-format msgid "This software is distributed under the terms of %s" msgstr "本软件依照 %s 条款分发" #: main.c:192 main.c:627 msgid "This program comes with ABSOLUTELY NO WARRANTY" msgstr "本软件不作任何保修" #: main.c:259 msgid "Dumping data..." msgstr "正在转储数据..." #: main.c:301 msgid "Freeing memory" msgstr "正在释放内存" #: main.c:344 msgid "Checking on Internet for a new version..." msgstr "正在联网检查新版本..." #: main.c:348 main.c:474 msgid "failed to open a Curl session" msgstr "无法启用 Curl 模块" #: main.c:361 #, c-format msgid "failed to perform the Curl transfer (%s)" msgstr "无法执行 Curl 传输 (%s)" #: main.c:362 msgid "wrong write data" msgstr "写入数据出错" #: main.c:369 #, c-format msgid "(version %s is available)" msgstr "(%s 版目前可用)" #: main.c:374 main.c:467 msgid "No new version available" msgstr "没有新版本可用" #: main.c:375 msgid "(up-to-date)" msgstr "(最新)" #: main.c:445 #, c-format msgid "an error occurred while extracting %s archive (%s)" msgstr "提取 %s 存档时出错 (%s)" #: main.c:460 msgid "" "Network access is disabled by environment variable (set CPUX_NETWORK with a " "positive value to enable it)" msgstr "网络访问被环境变量禁用 (将 CPUX_NETWORK 设置为正值以启用)" #: main.c:482 #, c-format msgid "failed to open %s archive for writing" msgstr "无法写入 %s 存档" #: main.c:488 msgid "Downloading new version..." msgstr "正在下载新版本..." #: main.c:500 #, c-format msgid "failed to download %s archive (%s)" msgstr "无法下载 %s 存档 (%s)" #: main.c:506 msgid "Extracting new version..." msgstr "正在提取新版本..." #: main.c:516 msgid "Applying new version..." msgstr "正在应用新版本..." #: main.c:527 msgid "an error occurred while removing/renaming files" msgstr "移动/重命名文件时出错" #: main.c:529 msgid "Update successful!" msgstr "更新成功!" #: main.c:548 msgid "Start graphical user interface (GUI) (default)" msgstr "启动图形用户界面 (GUI) (默认)" #: main.c:549 msgid "Start text-based user interface (TUI)" msgstr "启动文本用户界面 (TUI)" #: main.c:550 msgid "Dump all data on standard output and exit" msgstr "将所有数据转储到标准输出并退出" #: main.c:551 msgid "Run embedded command dmidecode and exit" msgstr "运行嵌入式命令 dmidecode 并退出" #: main.c:552 msgid "Run embedded command bandwidth and exit" msgstr "运行嵌入的命令 bandwidth 并退出" #: main.c:553 msgid "Set default tab (integer)" msgstr "设置默认选项卡 (整型)" #: main.c:554 msgid "Select CPU core to monitor (integer)" msgstr "选择要监视的 CPU 核心 (整型)" #: main.c:555 msgid "Set custom bandwidth test for CPU caches speed (integer)" msgstr "为 CPU 缓存速度设置自定义 bandwidth 测试 (整型)" #: main.c:556 msgid "Set custom time between two refreshes (in seconds)" msgstr "设置两次刷新之间的自定义时间 (以秒为单位)" #: main.c:557 msgid "Disable colored output" msgstr "禁用彩色输出" #: main.c:558 msgid "Print required informations to paste in an issue" msgstr "输出粘贴在问题反馈中的所需信息" #: main.c:559 msgid "Verbose output" msgstr "详细输出" #: main.c:560 msgid "Update portable version if a new version is available" msgstr "新版本可用时,更新便携式版本" #: main.c:561 msgid "Print help and exit" msgstr "打印帮助并退出。" #: main.c:562 msgid "Print version and exit" msgstr "打印版本并退出。" #: main.c:573 msgid "Temporarily disable network support" msgstr "暂时禁用网络支持" #: main.c:574 msgid "Enforce the bus clock" msgstr "强制执行总线计时器" #: main.c:575 msgid "Read CPUID raw data from a given file" msgstr "从指定文件中读取 CPUID 源数据" #: main.c:576 msgid "Only print a message if CPU does not belong in database" msgstr "CPU 不在数据库时,仅输出消息" #: main.c:585 #, c-format msgid "Usage: %s DISPLAY [OPTIONS]\n" msgstr "用法: %s 显示 [选项]\n" #: main.c:586 msgid "Available DISPLAY:" msgstr "可用显示:" #: main.c:590 msgid "" "\n" "Available OPTIONS:" msgstr "\n可用选项:" #: main.c:595 msgid "" "\n" "Influenceable environment variables:" msgstr "\n可影响的环境变量:" #: main.c:626 msgid "This is free software: you are free to change and redistribute it." msgstr "这是一个自由软件:您可以自由更改和重新分发。" #: main.c:628 #, c-format msgid "See the %s license: <%s>\n" msgstr "查看 %s 许可协议: <%s>\n" #: main.c:629 #, c-format msgid "Built on %s, %s (with %s %s on %s)." msgstr "基于 %s,%s (使用 %s %s 在 %s 上)." #: main.c:636 #, c-format msgid "-- %-9s version: %s" msgstr "-- %-9s 版本:%s" #: main.c:772 #, c-format msgid "" "\n" "%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s" msgstr "\n%s遇到了错误! %s 获得信号 %d (%s) 并崩溃。%s" #: main.c:787 msgid "You can paste this backtrace by opening a new issue here:" msgstr "您可以在这里打开一个新的问题来粘贴该回馈:" #: main.c:846 msgid "an error occurred while setting locale" msgstr "本地化设置时出错" #: main.c:968 #, c-format msgid "" "Sorry, you cannot update %s: 32-bit portable version is no more supported." msgstr "" #: tui_ncurses.c:70 msgid "Starting NCurses TUI..." msgstr "Starting NCurses TUI..." #: tui_ncurses.c:110 msgid "Press 'h' to see help.\n" msgstr "按 'h' 键查看帮助。\n" #: tui_ncurses.c:384 #, c-format msgid "Welcome in %s NCurses help!\n" msgstr "欢迎来到 %s NCurses 帮助!\n" #: tui_ncurses.c:385 msgid "This help describes how to use this Text-based User Interface.\n" msgstr "此帮助介绍如何使用该文本用户界面\n" #: tui_ncurses.c:387 msgid "" "\n" "Global keys:\n" msgstr "\n全局按键:\n" #: tui_ncurses.c:388 msgid "\tPress 'left' key to switch in left tab.\n" msgstr "\t按 '左' 键切换至左选项卡。\n" #: tui_ncurses.c:389 msgid "\tPress 'right' key to switch in right tab.\n" msgstr "\t按 '右' 键切换至右选项卡。\n" #: tui_ncurses.c:390 msgid "\tPress 'h' key to see this help.\n" msgstr "\t按 'h' 键查看此帮助。\n" #: tui_ncurses.c:391 msgid "\tPress 'q' key to exit.\n" msgstr "\t按 'q' 键退出。\n" #: tui_ncurses.c:393 msgid "" "\n" "CPU tab:\n" msgstr "\nCPU 选项卡:\n" #: tui_ncurses.c:394 msgid "\tPress 'down' key to decrease core number to monitor.\n" msgstr "\t按 '下' 键减小要监视的核心数值。\n" #: tui_ncurses.c:395 msgid "\tPress 'up' key to increase core number to monitor.\n" msgstr "\t按 '上' 键增加要监视的核心数值。\n" #: tui_ncurses.c:397 msgid "" "\n" "Caches tab:\n" msgstr "\n缓存选项卡:\n" #: tui_ncurses.c:398 msgid "\tPress 'down' key to switch to previous test.\n" msgstr "\t按 '下' 键切换至上一项测试。\n" #: tui_ncurses.c:399 msgid "\tPress 'up' key' to switch to next test.\n" msgstr "\t按 '上' 键切换至下一项测试。\n" #: tui_ncurses.c:401 msgid "" "\n" "Bench tab:\n" msgstr "\n基准测试选项卡:\n" #: tui_ncurses.c:402 msgid "\tPress 'down' key to decrement benchmark duration.\n" msgstr "\t按 '下' 键减少基准测试持续时间。\n" #: tui_ncurses.c:403 msgid "\tPress 'up' key to increment benchmark duration.\n" msgstr "\t按 '上' 键增加基准测试持续时间。\n" #: tui_ncurses.c:404 msgid "\tPress 'next page' key to decrement number of threads to use.\n" msgstr "\t按 '下一页' 减少要使用的线程数。\n" #: tui_ncurses.c:405 msgid "\tPress 'previous page' key to increment number of threads to use.\n" msgstr "\t按 '上一页' 增加要使用的线程数。\n" #: tui_ncurses.c:406 msgid "\tPress 's' key to start/stop prime numbers (slow) benchmark.\n" msgstr "\t按 's' 键开始/停止素数 (慢速) 基准测试。\n" #: tui_ncurses.c:407 msgid "\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n" msgstr "\t按 'f' 键开始/停止素数 (快速) 基准测试。\n" #: tui_ncurses.c:409 msgid "" "\n" "Press any key to exit this help.\n" msgstr "\n按任意键退出帮助。\n" #: tui_ncurses.c:428 msgid "If you want to update, press 'u' key, or anything else to skip.\n" msgstr "如果您想要更新,请按 'u' 键,否则请按其他按键跳过更新。\n" #: tui_ncurses.c:434 #, c-format msgid "" "\n" "\n" "%s will be updated." msgstr "\n\n%s 将会被更新。" #: util.c:172 #, c-format msgid "an error occurred while opening file '%s' (%s)" msgstr "打开文件 '%s' 时发生错误 (%s)" #: util.c:212 #, c-format msgid "an error occurred while running command '%s' (%s)" msgstr "运行命令 '%s' 时发生错误 (%s)" #: util.c:250 util.c:310 #, c-format msgid "failed to open %s directory" msgstr "无法打开 %s 目录" #: util.c:321 msgid "an error occurred while compiling regex" msgstr "编译正则表达式时出错" CPU-X-3.2.4/run_tests.sh000077500000000000000000000021271341671471500147540ustar00rootroot00000000000000#!/bin/bash # This script is used to test the CPU Technology database TESTS_DIR=$1 CR="\033[0m" # Color reset CB="\033[1m" # Color bold CBR="\033[1;31m" # Color bold red CBG="\033[1;32m" # Color bold green if [[ $# -lt 1 ]] || [[ ! -d "$TESTS_DIR" ]]; then printf "$0: you must provide the libcpuid 'tests' directory." exit 1 fi count=0 for file in $(find $TESTS_DIR -name *.test); do # Cut test file after delimiter (dash line) tmp_file="/tmp/$(basename $file)" while read -r line; do echo $line | grep -q "\-\-\-\-\-\-\-\-\-\-\-\-" && break echo $line >> "$tmp_file" done < $file # Run with CPU-X printf "Test file ${CB}%-32s${CR}: " "$(basename $file)" output=$(sudo LC_ALL=C CPUX_CPUID_RAW="$tmp_file" CPUX_DEBUG_DATABASE=1 cpu-x --dump --nocolor) # Display test status if [[ $? -gt 0 ]]; then printf "${CBR}${output#*"==> "}${CR}\n" ((count++)) else printf "${CBG}OK${CR}\n" fi rm "$tmp_file" done printf "\nDone: " if [[ $count -eq 0 ]]; then printf "${CBG}all test files passed with success!${CR}\n" else printf "${CBR}$count test files failed to pass.${CR}\n" fi CPU-X-3.2.4/src/000077500000000000000000000000001341671471500131545ustar00rootroot00000000000000CPU-X-3.2.4/src/CMakeLists.txt000066400000000000000000000221261341671471500157170ustar00rootroot00000000000000### FIND NEEDED LIBRAIRIES # GTK3+ if(WITH_GTK) set(MINIMUM_GTK_VERSION 3.12.0) pkg_check_modules(GTK3 gtk+-3.0>=${MINIMUM_GTK_VERSION}) if(GTK3_FOUND) include_directories(${GTK3_INCLUDE_DIRS}) link_directories(${GTK3_LIBRARY_DIRS}) add_definitions(${GTK3_CFLAGS_OTHER}) if(PORTABLE_BINARY) execute_process(COMMAND glib-compile-resources --target=${CMAKE_BINARY_DIR}/src/gtk_resources.c --generate-source cpu-x.gresource.xml COMMAND glib-compile-resources --target=${CMAKE_BINARY_DIR}/src/gtk_resources.h --generate-header cpu-x.gresource.xml WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/data ) set(GRESOURCES "gtk_resources.c") include_directories(${CMAKE_BINARY_DIR}/src) endif(PORTABLE_BINARY) add_library(gui_gtk gui_gtk.c gui_gtk.h gui_gtk_id.h ${GRESOURCES} ) set(GTK3_LIBRARIES "gui_gtk" ${GTK3_LIBRARIES}) else(GTK3_FOUND) message("${BoldYellow}GTK3+ GUI will not be build:${ColourReset} ${Yellow}GTK ${MINIMUM_GTK_VERSION} or higher is needed.${ColourReset}") message("${Yellow}Set ${BoldYellow}PKG_CONFIG_PATH${ColourReset}${Yellow} environment variable if development files are installed.${ColourReset}") endif(GTK3_FOUND) endif(WITH_GTK) # NCurses if(WITH_NCURSES) pkg_check_modules(NCURSES ncursesw) if(NCURSES_FOUND) include_directories(${NCURSES_INCLUDE_DIRS}) link_directories(${NCURSES_LIBRARY_DIRS}) add_library(tui_ncurses tui_ncurses.c tui_ncurses.h ) add_embedded_library_linux(NCURSES_LIBRARIES "-l:libncursesw.a") add_embedded_library_others(NCURSES_LIBRARIES "${NCURSES_LIBRARIES} -l:libncursesw.a -l:libtinfo.a") set(NCURSES_LIBRARIES "tui_ncurses" ${NCURSES_LIBRARIES}) endif(NCURSES_FOUND) endif(WITH_NCURSES) # Gettext if(Intl_FOUND) add_embedded_library_others(Intl_LIBRARIES "-l:libintl.a") include_directories(${CMAKE_BINARY_DIR}/po) endif(Intl_FOUND) # Libcurl if(WITH_LIBCURL) pkg_check_modules(LIBCURL libcurl) if(LIBCURL_FOUND) include_directories(${LIBCURL_INCLUDE_DIRS}) link_directories(${LIBCURL_LIBRARY_DIRS}) add_definitions(${LIBCURL_CFLAGS_OTHER}) add_embedded_library(LIBCURL_LIBRARIES "-l:libcurl.a") add_embedded_library_linux(LIBCURL_LIBRARIES "${LIBCURL_LIBRARIES} -l:libssl.a -l:libcrypto.a -lz -ldl -lgssapi_krb5") add_embedded_library_others(LIBCURL_LIBRARIES "${LIBCURL_LIBRARIES} -l:libz.a") endif(LIBCURL_FOUND) endif(WITH_LIBCURL) # Libjson-c if(WITH_LIBJSONC) pkg_check_modules(LIBJSONC json-c) if(LIBJSONC_FOUND) include_directories(${LIBJSONC_INCLUDE_DIRS}) link_directories(${LIBJSONC_LIBRARY_DIRS}) add_definitions(${LIBJSONC_CFLAGS_OTHER}) add_embedded_library(LIBJSONC_LIBRARIES "-l:libjson-c.a") endif(LIBJSONC_FOUND) endif(WITH_LIBJSONC) # Libarchive if(PORTABLE_BINARY) pkg_check_modules(LIBARCHIVE libarchive REQUIRED) if(LIBARCHIVE_FOUND) include_directories(${LIBARCHIVE_INCLUDE_DIRS}) link_directories(${LIBARCHIVE_LIBRARY_DIRS}) add_definitions(${LIBARCHIVE_CFLAGS_OTHER}) add_embedded_library(LIBARCHIVE_LIBRARIES "-l:libarchive.a") add_embedded_library_linux(LIBARCHIVE_LIBRARIES "${LIBARCHIVE_LIBRARIES} -ldl") add_embedded_library_others(LIBARCHIVE_LIBRARIES "${LIBARCHIVE_LIBRARIES} -l:libssl.a -l:libcrypto.a -l:libgssapi.a -l:libbz2.a") endif(LIBARCHIVE_FOUND) endif(PORTABLE_BINARY) # Libcpuid if(WITH_LIBCPUID) pkg_check_modules(LIBCPUID libcpuid>=0.4.0) if(LIBCPUID_FOUND) include_directories(${LIBCPUID_INCLUDE_DIRS}) link_directories(${LIBCPUID_LIBRARY_DIRS}) add_definitions(${LIBCPUID_CFLAGS_OTHER}) add_embedded_library(LIBCPUID_LIBRARIES "-l:libcpuid.a") set(CMAKE_REQUIRED_LIBRARIES ${LIBCPUID_LIBRARIES}) check_symbol_exists(msr_serialize_raw_data "libcpuid/libcpuid.h" HAVE_MSR_SERIALIZE_RAW_DATA) if(HAVE_MSR_SERIALIZE_RAW_DATA) add_definitions(-DHAVE_MSR_SERIALIZE_RAW_DATA) endif(HAVE_MSR_SERIALIZE_RAW_DATA) endif(LIBCPUID_FOUND) endif(WITH_LIBCPUID) # Libpci if(WITH_LIBPCI) pkg_check_modules(LIBPCI libpci) if(LIBPCI_FOUND) include_directories(${LIBPCI_INCLUDE_DIRS}) link_directories(${LIBPCI_LIBRARY_DIRS}) add_definitions(${LIBPCI_CFLAGS_OTHER}) add_embedded_library(LIBPCI_LIBRARIES "-l:libpci.a") add_embedded_library_linux(LIBPCI_LIBRARIES "${LIBPCI_LIBRARIES} -lresolv -ludev") add_embedded_library_others(LIBPCI_LIBRARIES "${LIBPCI_LIBRARIES} -l:libz.a") endif(LIBPCI_FOUND) endif(WITH_LIBPCI) # Libprocps set(LIBSYSTEM 0) if(WITH_LIBPROCPS AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT FORCE_LIBSTATGRAB) pkg_check_modules(LIBPROCPS libprocps) if(LIBPROCPS_FOUND) include_directories(${LIBPROCPS_INCLUDE_DIRS}) link_directories(${LIBPROCPS_LIBRARY_DIRS}) add_definitions(${LIBPROCPS_CFLAGS_OTHER}) add_embedded_library(LIBPROCPS_LIBRARIES "-l:libprocps.a") set(LIBSYSTEM 1) endif(LIBPROCPS_FOUND) endif(WITH_LIBPROCPS AND ${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT FORCE_LIBSTATGRAB) # Libstatgrab if(WITH_LIBSTATGRAB AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR FORCE_LIBSTATGRAB)) pkg_check_modules(LIBSTATGRAB libstatgrab) if(LIBSTATGRAB_FOUND) include_directories(${LIBSTATGRAB_INCLUDE_DIRS}) link_directories(${LIBSTATGRAB_LIBRARY_DIRS}) add_definitions(${LIBSTATGRAB_CFLAGS_OTHER}) add_embedded_library(LIBSTATGRAB_LIBRARIES "-l:libstatgrab.a") add_embedded_library_others(LIBSTATGRAB_LIBRARIES "${LIBSTATGRAB_LIBRARIES} -l:libdevstat.a -l:libkvm.a") set(LIBSYSTEM 2) endif(LIBSTATGRAB_FOUND) endif(WITH_LIBSTATGRAB AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR FORCE_LIBSTATGRAB)) # Dmidecode if(WITH_DMIDECODE) add_subdirectory(dmidecode) include_directories(dmidecode) set(DMIDECODE_LIBRARIES "dmidecode") endif(WITH_DMIDECODE) # Bandwidth if(WITH_BANDWIDTH) add_subdirectory(bandwidth) if(BANDWIDTH_FOUND) include_directories(bandwidth) set(BANDWIDTH_LIBRARIES "bandwidth") endif(BANDWIDTH_FOUND) endif(WITH_BANDWIDTH) ### FINAL CONFIG message("${BoldCyan}** ${CMAKE_PROJECT_NAME} ${PROJECT_VERSION} configuration **${ColourReset}") # UI libraries print_config("GTK" "${GTK3_VERSION}" GTK3_FOUND WITH_GTK) print_config("NCURSES" "${NCURSES_VERSION}" NCURSES_FOUND WITH_NCURSES) # Other libraries print_config("GETTEXT" 0 GETTEXT_FOUND WITH_GETTEXT) print_config("LIBCURL" "${LIBCURL_VERSION}" LIBCURL_FOUND WITH_LIBCURL) print_config("LIBJSONC" "${LIBJSONC_VERSION}" LIBJSONC_FOUND WITH_LIBJSONC) print_config("LIBCPUID" "${LIBCPUID_VERSION}" LIBCPUID_FOUND WITH_LIBCPUID) print_config("LIBPCI" "${LIBPCI_VERSION}" LIBPCI_FOUND WITH_LIBPCI) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND NOT FORCE_LIBSTATGRAB) print_config("LIBPROCPS" "${LIBPROCPS_VERSION}" LIBPROCPS_FOUND WITH_LIBPROCPS) else() print_config("LIBSTATGRAB" "${LIBSTATGRAB_VERSION}" LIBSTATGRAB_FOUND WITH_LIBSTATGRAB) endif() # Subprojects print_config("DMIDECODE" "${DMIDECODE_VERSION}" 1 WITH_DMIDECODE) print_config("BANDWIDTH" "${BANDWIDTH_VERSION}" BANDWIDTH_FOUND WITH_BANDWIDTH) ### MAIN BINARY # Executable add_executable(cpu-x main.c util.c cpu-x.h core.c core.h ) # Portable binary & Gettext stuff if(PORTABLE_BINARY) message("${BoldBlue}${CMAKE_PROJECT_NAME} will be compiled as portable binary.${ColourReset}") add_definitions(-DPORTABLE_BINARY=1) find_path(XXD xxd) if(NOT XXD) message(FATAL_ERROR "${BoldRed}'xxd' command not found, can't perform build!${ColourReset}") endif(NOT XXD) if(WITH_GETTEXT) set(CMAKE_INSTALL_FULL_LOCALEDIR "/tmp/.cpu-x") add_dependencies(cpu-x convertgmo) endif(WITH_GETTEXT) else(PORTABLE_BINARY) add_definitions(-DPORTABLE_BINARY=0) if(GETTEXT_FOUND) add_dependencies(cpu-x potfiles) endif(GETTEXT_FOUND) endif(PORTABLE_BINARY) # OS macro definition if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") add_definitions(-DOS="linux${BITNESS}") elseif(${CMAKE_SYSTEM_NAME} MATCHES FreeBSD OR ${CMAKE_SYSTEM_NAME} MATCHES DragonFly) add_definitions(-DOS="bsd${BITNESS}") else() message("${BoldYellow}Unknown operating system: ${CMAKE_SYSTEM_NAME}${ColourReset}") add_definitions(-DOS="unknown${BITNESS}") endif() # Libsystem extra-definitions if(${LIBSYSTEM} EQUAL 0 OR ${LIBSYSTEM} EQUAL 1) add_definitions(-DHAS_LIBSTATGRAB=0 -DLIBSTATGRAB_VERSION=NULL) endif() if(${LIBSYSTEM} EQUAL 0 OR ${LIBSYSTEM} EQUAL 2) add_definitions(-DHAS_LIBPROCPS=0 -DLIBPROCPS_VERSION=NULL) endif() # Various definitions add_definitions(-DPRGVER="${PROJECT_VERSION}" -DCC="${CMAKE_C_COMPILER_ID}" -DHAS_LIBSYSTEM="${LIBSYSTEM}") add_definitions(-DGETTEXT_PACKAGE="${CMAKE_PROJECT_NAME}" -DLOCALEDIR="${CMAKE_INSTALL_FULL_LOCALEDIR}" -DTERMINFODIR="/lib/terminfo") # Various libraries add_embedded_library_others(OTHER_LIBRARIES "-lelf -l:libnghttp2.a") # Link libraries target_link_libraries(cpu-x m ${Intl_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Backtrace_LIBRARIES} ${GTK3_LIBRARIES} ${NCURSES_LIBRARIES} ${LIBCURL_LIBRARIES} ${LIBJSONC_LIBRARIES} ${LIBARCHIVE_LIBRARIES} ${LIBCPUID_LIBRARIES} ${LIBPCI_LIBRARIES} ${LIBPROCPS_LIBRARIES} ${LIBSTATGRAB_LIBRARIES} ${DMIDECODE_LIBRARIES} ${BANDWIDTH_LIBRARIES} ${OTHER_LIBRARIES} ) ### INSTALLATION install(TARGETS cpu-x DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}/) CPU-X-3.2.4/src/bandwidth/000077500000000000000000000000001341671471500151205ustar00rootroot00000000000000CPU-X-3.2.4/src/bandwidth/BMP.c000066400000000000000000000362751341671471500157170ustar00rootroot00000000000000 /*============================================================================= bmplib, a simple library to create, modify, and write BMP image files. Copyright (C) 2009-2014 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *============================================================================*/ //-------------------------------------------------- // Change Log // 0.8 ZS Added larger font of my own design. // 0.9 ZS Removed attempt at anti-aliasing. //-------------------------------------------------- #include #include #include #include "BMP.h" #include "font.h" #include "minifont.h" // Narrowest possible numbers. static char* narrow_nums [] = { " # ", "# #", "# #", "# #", "# #", "# #", " # ", " #", "##", " #", " #", " #", " #", " #", " # ", "# #", " #", " ##", "# ", "# ", "###", "###", " #", " # ", "## ", " #", "# #", " # ", "# #", "# #", "# #", "###", " #", " #", " #", "###", "# ", "## ", " #", " #", "# #", " # ", " # ", "# ", "# ", "## ", "# #", "# #", " # ", "###", " #", " #", " # ", " # ", " # ", " # ", " # ", "# #", "# #", " # ", "# #", "# #", " # ", " # ", "# #", "# #", " ##", " #", " # ", "# ", " ", "", "", " ", "", "", "#", }; /*--------------------------------------------------------------------------- * Name: BMP_new * Purpose: Creates new image. *-------------------------------------------------------------------------*/ BMP* BMP_new (int w, int h) { unsigned long size; BMP* nu; if (w<1 || h<1) return NULL; //---------- if (w & 3) w += 4 - (w & 3); if (h & 3) h += 4 - (h & 3); nu = (BMP*) malloc (sizeof (BMP)); if (!nu) return NULL; memset (nu, 0, sizeof (BMP)); nu->width = w; nu->height = h; size = w * h * sizeof (long); nu->pixels = (RGB*) malloc (size); if (!nu->pixels) { free (nu); return NULL; } memset (nu->pixels, 0, size); return nu; } /*--------------------------------------------------------------------------- * Name: BMP_destroy * Purpose: Deallocates image. *-------------------------------------------------------------------------*/ void BMP_destroy (BMP* bmp) { if (!bmp) return; //---------- if (bmp->pixels) free (bmp->pixels); free (bmp); } /*--------------------------------------------------------------------------- * Name: BMP_point * Purpose: Writes pixel into image. *-------------------------------------------------------------------------*/ void BMP_point (BMP *bmp, int x, int y, RGB rgb) { if (!bmp || x<0 || y<0) return; if (x >= bmp->width || y >= bmp->height) return; if (!bmp->pixels) return; //---------- bmp->pixels[y*bmp->width + x] = rgb; } /*--------------------------------------------------------------------------- * Name: BMP_line_core * Purpose: Draws a line in a BMP image. *-------------------------------------------------------------------------*/ void BMP_line_core (BMP *bmp, int x0, int y0, int x1, int y1, RGB rgb, int dashed) { if ((rgb >> 24) == 0xff) return; int dot_counter = 0; if (!dashed && x0 == x1 && y0 == y1) BMP_point (bmp, x0, y0, rgb); else if (!dashed && x0 == x1) BMP_vline (bmp, x0, y0, y1, rgb); else if (!dashed && y0 == y1) BMP_hline (bmp, x0, x1, y0, rgb); else { int j, x, y, dx, dy, e, xchange, s1, s2; // DDA, copied from my FramebufferUI project. x = x0; y = y0; s1 = 1; s2 = 1; dx = x1 - x0; if (dx < 0) { dx = -dx; s1 = -1; } dy = y1 - y0; if (dy < 0) { dy = -dy; s2 = -1; } xchange = 0; if (dy > dx) { int tmp = dx; dx = dy; dy = tmp; xchange = 1; } e = (dy<<1) - dx; j = 0; while (j <= dx) { j++; int draw = 1; if (dashed && (1 & (dot_counter >> 2))) draw = 0; if (draw) BMP_point (bmp, x, y, rgb); dot_counter++; if (e >= 0) { if (xchange) x += s1; else y += s2; e -= (dx << 1); } if (xchange) y += s2; else x += s1; e += (dy << 1); } } } /*--------------------------------------------------------------------------- * Name: BMP_line * Purpose: Draws a line in a BMP image. *-------------------------------------------------------------------------*/ void BMP_line (BMP *bmp, int x0, int y0, int x1, int y1, RGB rgb) { BMP_line_core (bmp, x0, y0, x1, y1, rgb, 0); } /*--------------------------------------------------------------------------- * Name: BMP_line_dashed * Purpose: Draws a dashed line in a BMP image. *-------------------------------------------------------------------------*/ void BMP_line_dashed (BMP *bmp, int x0, int y0, int x1, int y1, RGB rgb) { BMP_line_core (bmp, x0, y0, x1, y1, rgb, 1); } /*--------------------------------------------------------------------------- * Name: BMP_rect * Purpose: Fills a rectangle with a color. *-------------------------------------------------------------------------*/ void BMP_rect (BMP *bmp, int x, int y, int w, int h, RGB rgb) { BMP_hline (bmp, x, x+w-1, y, rgb); BMP_hline (bmp, x, x+w-1, y+h-1, rgb); BMP_vline (bmp, x, y, y+h-1, rgb); BMP_vline (bmp, x+w-1, y, y+h-1, rgb); } /*--------------------------------------------------------------------------- * Name: BMP_fillrect * Purpose: Fills a rectangle with a color. *-------------------------------------------------------------------------*/ void BMP_fillrect (BMP *bmp, int x, int y, int w, int h, RGB rgb) { while (h > 0) { BMP_hline (bmp, x, x+w-1, y, rgb); h--; y++; } } /*--------------------------------------------------------------------------- * Name: BMP_clear * Purpose: Sets all pixels to specified color. *-------------------------------------------------------------------------*/ void BMP_clear (BMP *bmp, RGB rgb) { BMP_fillrect (bmp, 0, 0, bmp->width, bmp->height, rgb); } /*--------------------------------------------------------------------------- * Name: BMP_hline * Purpose: Draws horizontal line. *-------------------------------------------------------------------------*/ void BMP_hline (BMP *bmp, int x0, int x1, int y, RGB rgb) { if (x0 > x1) { int tmp=x1; x1=x0; x0=tmp; } while (x0 <= x1) { BMP_point (bmp, x0++, y, rgb); } } /*--------------------------------------------------------------------------- * Name: BMP_vline * Purpose: Draws vertical line. *-------------------------------------------------------------------------*/ void BMP_vline (BMP *bmp, int x, int y0, int y1, RGB rgb) { if (y0 > y1) { int tmp=y1; y1=y0; y0=tmp; } while (y0 <= y1) { BMP_point (bmp, x, y0++, rgb); } } /*--------------------------------------------------------------------------- * Name: BMP_draw_string * Purpose: Draws ature 5x8 characters into the image. *-------------------------------------------------------------------------*/ int BMP_draw_string (BMP *bmp, const char *string, int x, int y, RGB color) { char ch; const char *s; if (!bmp || !string) return 0; if (x >= bmp->width || y >= bmp->height || !*string) return 0; //---------- #if 0 RGB r,g,b; RGB light; RGB dark; r = 0xff & (color >> 16); g = 0xff & (color >> 8); b = 0xff & color; r += 3*0xff; b += 3*0xff; g += 3*0xff; r /= 4; g /= 4; b /= 4; light = b | (g << 8) | (r << 16); r = 0xff & (color >> 16); g = 0xff & (color >> 8); b = 0xff & color; r += 0xff; b += 0xff; g += 0xff; r /= 2; g /= 2; b /= 2; dark = b | (g << 8) | (r << 16); #endif const char **chars = get_font_chars (); s = string; while ((ch = *s++)) { int ix = -1; if (ch == ' ') { x += 10; continue; } if (ch > 'z') continue; if (ch > ' ' && ch <= 'z') ix = FONT_HEIGHT * (ch - 33); if (ix >= 0) { int i; int width = 0; for (i=0; i 'z') continue; if (ch > ' ' && ch <= 'z') ix = FONT_HEIGHT * (ch - 33); if (ix >= 0) { int j; int max_w = 0; for (j = 0; j < FONT_HEIGHT; j++) { const char *ptr = _chars [j+ix]; int w = ptr ? strlen (ptr) : 0; if (max_w < w) max_w = w; } width += max_w + 2/* kerning */; } } return width; } /*--------------------------------------------------------------------------- * Name: BMP_draw_mini_string * Purpose: Draws miniature 5x8 characters into the image. *-------------------------------------------------------------------------*/ int BMP_draw_mini_string (BMP *bmp, const char *string, int x, int y, RGB color) { char ch; const char *s; if (!bmp || !string) return 0; if (x >= bmp->width || y >= bmp->height || !*string) return 0; //---------- #if 0 unsigned long r,g,b; unsigned long light, dark; r = 0xff & (color >> 16); g = 0xff & (color >> 8); b = 0xff & color; r += 3*0xff; b += 3*0xff; g += 3*0xff; r /= 4; g /= 4; b /= 4; light = b | (g << 8) | (r << 16); r = 0xff & (color >> 16); g = 0xff & (color >> 8); b = 0xff & color; r += 0xff; b += 0xff; g += 0xff; r /= 2; g /= 2; b /= 2; dark = b | (g << 8) | (r << 16); #endif const char **mini_chars = get_minifont_chars (); #define MINI_HEIGHT (8) s = string; while ((ch = *s++)) { int ix = -1; if (ch == ' ') { x += 5; continue; } if (ch > 'z') continue; if (ch > ' ' && ch <= 'z') ix = MINI_HEIGHT * (ch - 33); if (ix >= 0) { int i; int width = 0; for (i=0; i 'z') continue; if (ch > ' ' && ch <= 'z') ix = MINI_HEIGHT * (ch - 33); if (ix >= 0) { int max_w = 0; int j; for (j = 0; j < MINI_HEIGHT; j++) { const char *ptr = mini_chars [j+ix]; int w = ptr ? strlen (ptr) : 0; if (max_w < w) max_w = w; } width += max_w + 1/*kerning*/; } } return width; } /*--------------------------------------------------------------------------- * Name: BMP_narrow_numbers * Purpose: Draws miniature 4x7 characters into the image. *-------------------------------------------------------------------------*/ int BMP_draw_narrow_numbers (BMP *bmp, const char *string, int x, int y, RGB color) { char ch; const char *s; if (!bmp || !string) return 0; if (x >= bmp->width || y >= bmp->height || !*string) return 0; //---------- #define NARROW_HEIGHT (7) s = string; while ((ch = *s++)) { int ix = -1; if (ch == ' ') { x += 3; continue; } if (ch >= '0' && ch <= '9') ix = ch - '0'; else if (ch == '.') ix = 10; ix *= NARROW_HEIGHT; if (ix >= 0) { int i; int width = strlen (narrow_nums [ix]); for (i=0; i= bmp->width || y >= bmp->height) return 0; if (!bmp->pixels) return 0; //---------- return bmp->pixels[y*bmp->width + x]; } /*--------------------------------------------------------------------------- * Name: BMP_write * Purpose: Writes image to BMP file. *-------------------------------------------------------------------------*/ int BMP_write (const BMP* bmp, const char *path) { FILE *f; #define HDRLEN (54) unsigned char h[HDRLEN]; unsigned long len; int i, j; if (!bmp || !path) return -1; //---------- memset (h, 0, HDRLEN); //-------------------- // Create the file. // f = fopen (path, "wb"); if (!f) return 0; //-------------------- // Prepare header // len = HDRLEN + 3 * bmp->width * bmp->height; h[0] = 'B'; h[1] = 'M'; h[2] = len & 0xff; h[3] = (len >> 8) & 0xff; h[4] = (len >> 16) & 0xff; h[5] = (len >> 24) & 0xff; h[10] = HDRLEN; h[14] = 40; h[18] = bmp->width & 0xff; h[19] = (bmp->width >> 8) & 0xff; h[20] = (bmp->width >> 16) & 0xff; h[22] = bmp->height & 0xff; h[23] = (bmp->height >> 8) & 0xff; h[24] = (bmp->height >> 16) & 0xff; h[26] = 1; h[28] = 24; h[34] = 16; h[36] = 0x13; // 2835 pixels/meter h[37] = 0x0b; h[42] = 0x13; // 2835 pixels/meter h[43] = 0x0b; //-------------------- // Write header. // if (HDRLEN != fwrite (h, 1, HDRLEN, f)) { fclose (f); return 0; } //---------------------------------------- // Write pixels. // Note that BMP has lower rows first. // for (j=bmp->height-1; j >= 0; j--) { for (i=0; i < bmp->width; i++) { unsigned char rgb[3]; int ix = i + j * bmp->width; unsigned long pixel = bmp->pixels[ix]; rgb[0] = pixel & 0xff; rgb[1] = (pixel >> 8) & 0xff; rgb[2] = (pixel >> 16) & 0xff; if (3 != fwrite (rgb, 1, 3, f)) { fclose (f); return 0; } } } fclose (f); return 1; } CPU-X-3.2.4/src/bandwidth/BMP.h000066400000000000000000000062321341671471500157120ustar00rootroot00000000000000 /*============================================================================= bmplib, a simple library to create, modify, and write BMP image files. Copyright (C) 2009-2014 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *============================================================================*/ #ifndef _BMP_H #define _BMP_H #include #define BMPLIB_RELEASE "0.9" #define BMPLIB_RELEASE_MAJOR 0 #define BMPLIB_RELEASE_MINOR 9 typedef uint32_t RGB; typedef uint32_t RGBA; typedef struct { int width, height; RGB *pixels; } BMP; #define FONT_HEIGHT (17) #define MINIFONT_HEIGHT (8) extern BMP* BMP_new (int, int); extern void BMP_destroy (BMP*); extern void BMP_clear (BMP*, RGB); extern int BMP_write (const BMP*, const char *path); extern void BMP_point (BMP*, int, int, RGB); extern void BMP_line (BMP *, int x0, int y0, int x1, int y1, RGB); extern void BMP_line_dashed (BMP *, int x0, int y0, int x1, int y1, RGB); extern void BMP_hline (BMP *, int x0, int x1, int y, RGB); extern void BMP_vline (BMP *, int x, int y0, int y1, RGB); extern void BMP_rect (BMP *, int x, int y, int w, int h, RGB); extern void BMP_fillrect (BMP *, int x, int y, int w, int h, RGB); extern RGB BMP_getpixel (BMP*, int, int); extern int BMP_draw_string (BMP *, const char *, int x, int y, RGB); extern int BMP_string_width (const char *); extern int BMP_draw_mini_string (BMP *, const char *, int x, int y, RGB); extern int BMP_mini_string_width (const char *); #define RGB_BLACK (0) #define RGB_BLUE (0xff) #define RGB_BRASS (0xc3a368) #define RGB_BROWN (0x8b4513) #define RGB_CADETBLUE (0x5f9ea0) #define RGB_CHARTREUSE (0x7fff00) #define RGB_CORAL (0xff7f50) #define RGB_CYAN (0xffff) #define RGB_DARKGREEN (0x6400) #define RGB_DARKKHAKI (0xbdb76b) #define RGB_DARKOLIVEGREEN (0x556b2f) #define RGB_DARKORANGE (0xff8c00) #define RGB_DODGERBLUE (0x1e90ff) #define RGB_GOLDENROD (0xdaa520) #define RGB_GRAY (0xc0c0c0) #define RGB_GREEN (0xff00) #define RGB_KHAKI (0xf0e68c) #define RGB_LEMONYELLOW (0xfde910) #define RGB_MAGENTA (0xff00ff) #define RGB_MAROON (0x800000) #define RGB_NAVYBLUE (0x80) #define RGB_ORANGE (0xffa500) #define RGB_PINK (0xf77fbe) #define RGB_PURPLE (0xa020f0) #define RGB_RED (0xff0000) #define RGB_ROYALBLUE (0x4169e1) #define RGB_SALMON (0xfa8072) #define RGB_TURQUOISE (0x40e0d0) #define RGB_VIOLET (0xee82ee) #define RGB_WHITE (0xffffff) #define RGB_YELLOW (0xffff00) #define RGB_GRAY6 (0x606060) #define RGB_GRAY8 (0x808080) #define RGB_GRAY10 (0xa0a0a0) #define RGB_GRAY12 (0xc0c0c0) #define RGB_GRAY14 (0xe0e0e0) #endif CPU-X-3.2.4/src/bandwidth/BMPGraphing.c000066400000000000000000000307211341671471500173650ustar00rootroot00000000000000/*============================================================================ BMPGraphing, a library for graphing. Copyright (C) 2005-2017 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *===========================================================================*/ #include #include #include #include #include "BMP.h" #include "BMPGraphing.h" //---------------------------------------------------------------------------- // Name: BMPGraphing_draw_labels_log2 // Purpose: Draw the labels and ticks. //---------------------------------------------------------------------------- void BMPGraphing_draw_labels_log2 (BMPGraph* graph) { if (!graph || !graph->image) return; //---------------------------------------- // Horizontal // // Establish min & max x values. // int i = 0; Value min_x = 0x4000000000000000; Value max_x = 0; for (i = 0; i < graph->data_index; i += 2) { Value type = graph->data[i]; Value value = graph->data[i+1]; if (type == DATUM_X) { if (value < min_x) min_x = value; if (value > max_x) max_x = value; } } graph->min_x = (long long) log2 (min_x); graph->max_x = (long long) ceil (log2 (max_x)); for (i = graph->min_x; i <= graph->max_x; i++) { char str [200]; int x = graph->left_margin + ((i-graph->min_x) * graph->x_span) / (graph->max_x - graph->min_x); int y = graph->height - graph->margin + 10; unsigned long y2 = 1 << i; if (y2 < 1536) snprintf (str, 199, "%ld B", y2); else if (y2 < (1<<20)) { snprintf (str, 199, "%ld kB", y2 >> 10); } else { Value j = y2 >> 20; switch ((y2 >> 18) & 3) { case 0: snprintf (str, 199, "%lld MB", (unsigned long long) j); break; case 1: snprintf (str, 199, "%lld.25 MB", (unsigned long long) j); break; case 2: snprintf (str, 199, "%lld.5 MB", (unsigned long long) j); break; case 3: snprintf (str, 199, "%lld.75 MB", (unsigned long long) j); break; } } BMP_vline (graph->image, x, y, y - 10, RGB_BLACK); BMP_draw_mini_string (graph->image, str, x - 10, y + 8, RGB_BLACK); } //---------------------------------------- // Vertical // // Establish min & max y values. // Value min_y = 0x4000000000000000; Value max_y = 0; for (i = 0; i < graph->data_index; i += 2) { Value type = graph->data[i]; Value value = graph->data[i+1]; if (type == DATUM_Y) { if (value < min_y) min_y = value; if (value > max_y) max_y = value; } } graph->min_y = min_y; graph->max_y = max_y; int font_height = 10; int available_height = graph->y_span; int max_labels = available_height / font_height; int preferred_n_labels = graph->max_y/10000; int actual_n_labels; float multiplier = 1; if (preferred_n_labels < max_labels) { actual_n_labels = preferred_n_labels; } else { actual_n_labels = max_labels; multiplier = preferred_n_labels / (float) actual_n_labels; } for (i = 0; i <= actual_n_labels; i++) { char str [200]; int x = graph->left_margin - 10; int y = graph->height - graph->margin - (i * graph->y_span) / (float)actual_n_labels; BMP_hline (graph->image, x, x+10, y, RGB_BLACK); int value = (int) (i * multiplier); snprintf (str, 199, "%d GB/s", value); BMP_draw_mini_string (graph->image, str, x - 40, y - MINIFONT_HEIGHT/2, RGB_BLACK); } } BMPGraph * BMPGraphing_new (int w, int h, int x_axis_mode) { if (x_axis_mode != MODE_X_AXIS_LINEAR && x_axis_mode != MODE_X_AXIS_LOG2) return NULL; BMPGraph *graph = (BMPGraph*) malloc (sizeof(BMPGraph)); if (!graph) return NULL; bzero (graph, sizeof(BMPGraph)); graph->x_axis_mode = x_axis_mode; if (w <= 0 || h <= 0) { w = 1920; h = 1080; } graph->width = w; graph->height = h; graph->image = BMP_new (w, h); graph->margin = 40; graph->left_margin = 80; BMP_clear (graph->image, RGB_WHITE); BMP_hline (graph->image, graph->left_margin, graph->width - graph->margin, graph->height - graph->margin, RGB_BLACK); BMP_vline (graph->image, graph->left_margin, graph->margin, graph->height - graph->margin, RGB_BLACK); graph->x_span = graph->width - (graph->margin + graph->left_margin); graph->y_span = graph->height - 2 * graph->margin; graph->legend_y = graph->margin; return graph; } void BMPGraphing_set_title (BMPGraph* graph, const char *title) { if (!graph || !title) return; if (graph->title) free (graph->title); graph->title = strdup (title); BMP_draw_string (graph->image, graph->title, graph->left_margin, graph->margin/2, RGB_BLACK); } void BMPGraphing_new_line (BMPGraph *graph, const char *str, RGB color) { if (!graph || !graph->image) return; BMP_draw_string (graph->image, str, graph->width - graph->margin - 370, graph->legend_y, 0xffffff & color); graph->legend_y += 17; graph->fg = 0; graph->last_x = graph->last_y = -1; if (graph->data_index >= MAX_GRAPH_DATA-2) return; // error ("Too many graph data."); graph->data [graph->data_index++] = DATUM_COLOR; graph->data [graph->data_index++] = color; } //---------------------------------------------------------------------------- // Name: BMPGraphing_add_point // Purpose: Adds a point to this list to be drawn. //---------------------------------------------------------------------------- void BMPGraphing_add_point (BMPGraph *graph, Value x, Value y) { if (!graph || !graph->image) return; if (graph->data_index >= MAX_GRAPH_DATA-4) return; // error ("Too many graph data."); graph->data [graph->data_index++] = DATUM_X; graph->data [graph->data_index++] = x; graph->data [graph->data_index++] = DATUM_Y; graph->data [graph->data_index++] = y; } //---------------------------------------------------------------------------- // Name: BMPGraphing_plot_log2 // Purpose: Plots a point on the current graph. //---------------------------------------------------------------------------- void BMPGraphing_plot_log2 (BMPGraph *graph, Value x, Value y) { if (!graph || !graph->image) return; //---------------------------------------- // Plot the point. The x axis is // logarithmic, base 2. // double tmp = log2 (x); tmp -= (double) graph->min_x; tmp *= (double) graph->x_span; tmp /= (double) (graph->max_x - graph->min_x); int x2 = graph->left_margin + (int) tmp; int y2 = graph->height - graph->margin - (y * graph->y_span) / graph->max_y; if (graph->last_x != -1 && graph->last_y != -1) { if (graph->fg & DASHED) BMP_line_dashed (graph->image, graph->last_x, graph->last_y, x2, y2, graph->fg & 0xffffff); else BMP_line (graph->image, graph->last_x, graph->last_y, x2, y2, graph->fg); } graph->last_x = x2; graph->last_y = y2; } //---------------------------------------------------------------------------- // Name: BMPGraphing_plot_linear // Purpose: Plots a point on the current graph. //---------------------------------------------------------------------------- void BMPGraphing_plot_linear (BMPGraph *graph, Value x, Value y, Value max_y) { if (!graph || !graph->image) return; //---------------------------------------- // Plot the point. The x axis is // logarithmic, base 2. The units of the // y value is kB. // double tmp = 10. + log2 (x); tmp -= (double) XVALUE_MIN; tmp *= (double) graph->x_span; tmp /= (double) (XVALUE_MAX - XVALUE_MIN); int x2 = graph->left_margin + (int) tmp; int y2 = graph->height - graph->margin - (y * graph->y_span) / max_y; //printf ("\tx=%d, y=%d\n",x,y); fflush(stdout); if (graph->last_x != -1 && graph->last_y != -1) { if (graph->fg & DASHED) BMP_line_dashed (graph->image, graph->last_x, graph->last_y, x2, y2, graph->fg & 0xffffff); else BMP_line (graph->image, graph->last_x, graph->last_y, x2, y2, graph->fg); } graph->last_x = x2; graph->last_y = y2; } //---------------------------------------------------------------------------- // Name: BMPGraphing_make_log2 // Purpose: Plots all lines. //---------------------------------------------------------------------------- static void BMPGraphing_make_log2 (BMPGraph *graph) { if (!graph || !graph->image) return; BMPGraphing_draw_labels_log2 (graph); //---------------------------------------- // OK, now draw the lines. // int i; int x = -1, y = -1; for (i = 0; i < graph->data_index; i += 2) { Value type = graph->data[i]; Value value = graph->data[i+1]; switch (type) { case DATUM_Y: y = value; break; case DATUM_X: x = value; break; case DATUM_COLOR: graph->fg = (unsigned long) value; graph->last_x = -1; graph->last_y = -1; break; } if (x != -1 && y != -1) { BMPGraphing_plot_log2 (graph, x, y); x = y = -1; } } } //---------------------------------------------------------------------------- // Name: BMPGraphing_make_linear // Purpose: Plots all lines for the network test graph. //---------------------------------------------------------------------------- static void BMPGraphing_make_linear (BMPGraph *graph) { if (!graph || !graph->image) return; int i; // No data if (!graph->data_index) return; //---------------------------------------- // Get the maximum bandwidth in order to // properly scale the graph vertically. // int max_y = 0; for (i = 0; i < graph->data_index; i += 2) { if (graph->data[i] == DATUM_Y) { int y = graph->data [i+1]; if (y > max_y) max_y = y; } } int range = max_y > 10000 ? 2 : (max_y > 1000 ? 1 : 0); int y_spacing = 1; switch (range) { case 2: // Round up to the next 100.00 MB/sec. (=10000). y_spacing = 10000; break; case 1: // Round up to the next 10.00 MB/sec. y_spacing = 1000; break; case 0: // Round up to the next 1.00 MB/sec. y_spacing = 100; break; } max_y /= y_spacing; max_y *= y_spacing; max_y += y_spacing; //---------------------------------------- // Draw the axes, ticks & labels. // // X axis: if (XVALUE_MIN < 10) return; // error ("Minimum y is too small."); for (i = XVALUE_MIN; i <= XVALUE_MAX; i++) { char str[200]; unsigned long y2 = 1 << (i-10); // XX XVALUE_MIN>=10 if (y2 < 1024) snprintf (str, 199, "%u kB", (unsigned int) y2); else snprintf (str, 199, "%lu MB", (unsigned long) (y2 >> 10)); int x = graph->left_margin + ((i - XVALUE_MIN) * graph->x_span) / (XVALUE_MAX - XVALUE_MIN); int y = graph->height - graph->margin + 10; BMP_vline (graph->image, x, y, y-10, RGB_BLACK); BMP_draw_mini_string (graph->image, str, x - 10, y+8, RGB_BLACK); } //---------- // Y axis: // Decide what the tick spacing will be. for (i = 0; i <= max_y; i += y_spacing) { char str[200]; unsigned long whole = i / 100; unsigned long frac = i % 100; snprintf (str, 199, "%lu.%02lu MB/s", whole, frac); int x = graph->left_margin - 10; int y = graph->height - graph->margin - (i * graph->y_span) / max_y; BMP_hline (graph->image, x, x+10, y, RGB_BLACK); BMP_draw_mini_string (graph->image, str, x - 60, y - MINIFONT_HEIGHT/2, RGB_BLACK); } //---------------------------------------- // Draw the data lines. // int x = -1, y = -1; graph->last_x = -1; graph->last_y = -1; for (i = 0; i < graph->data_index; i += 2) { int type = graph->data[i]; long value = graph->data[i+1]; switch (type) { case DATUM_Y: y = value; break; case DATUM_X: x = value; break; case DATUM_COLOR: graph->fg = (unsigned long) value; graph->last_x = -1; graph->last_y = -1; break; } if (x != -1 && y != -1) { BMPGraphing_plot_linear (graph, x, y, max_y); x = y = -1; } } } void BMPGraphing_make (BMPGraph *graph) { if (!graph) return; // XX silent error switch (graph->x_axis_mode) { case MODE_X_AXIS_LOG2: BMPGraphing_make_log2 (graph); break; case MODE_X_AXIS_LINEAR: BMPGraphing_make_linear (graph); break; default: fprintf (stderr, "Invalid graph mode %d.\n", graph->x_axis_mode); break; } } void BMPGraphing_destroy (BMPGraph *graph) { if (!graph) return; if (graph->title) { free (graph->title); graph->title = NULL; } if (graph->image) { BMP_destroy (graph->image); graph->image = NULL; } free (graph); } CPU-X-3.2.4/src/bandwidth/BMPGraphing.h000066400000000000000000000047221341671471500173740ustar00rootroot00000000000000/*============================================================================ BMPGraphing, a library for graphing. Copyright (C) 2005-2017 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *===========================================================================*/ #ifndef _BMPGRAPHING_H #define _BMPGRAPHING_H #ifdef __WIN32__ typedef char bool; enum { true=1, false=0 }; #else #include #endif #include #define BMPGRAPHING_RELEASE "0.3" #define XVALUE_MIN (15) #define XVALUE_MAX (28) enum { DATUM_X=0, DATUM_Y=1, DATUM_COLOR=2, }; typedef uint32_t Coordinate; typedef uint64_t Value; enum { MODE_X_AXIS_LINEAR = 0, MODE_X_AXIS_LOG2 = 1, }; //--------------- // Graphing data. // typedef struct { BMP *image; char *title; unsigned char x_axis_mode; Coordinate width; Coordinate height; Coordinate left_margin; Coordinate margin; Coordinate last_x; Coordinate last_y; Coordinate x_span; Coordinate y_span; Coordinate legend_y; RGB fg; #define MAX_GRAPH_DATA 50000 Value data [MAX_GRAPH_DATA]; int data_index; #define DASHED 0x1000000 // dashed line flag Value max_y; Value min_y; Value min_x; Value max_x; } BMPGraph; extern void BMPGraphing_set_title (BMPGraph*, const char *); extern void BMPGraphing_draw_labels_log2 (BMPGraph*); extern BMPGraph *BMPGraphing_new (int w, int h, int x_axis_mode); extern void BMPGraphing_new_line (BMPGraph *, const char *str, RGB color); extern void BMPGraphing_add_point (BMPGraph *, Value x, Value y); extern void BMPGraphing_plot_log2 (BMPGraph *, Value x, Value y); extern void BMPGraphing_plot_linear (BMPGraph *, Value x, Value y, Value max_amt); extern void BMPGraphing_make (BMPGraph*); extern BMP *BMPGraphing_get_graph (BMPGraph*); extern void BMPGraphing_destroy (BMPGraph*); #endif CPU-X-3.2.4/src/bandwidth/CMakeLists.txt000066400000000000000000000037221341671471500176640ustar00rootroot00000000000000project(bandwidth VERSION "1.5.1" LANGUAGES C ) # Config (bandwidth) set(BANDWIDTH_DEBUG_FLAGS "-Wall -Wextra -Wuninitialized -Wno-strict-prototypes -Wno-unused-parameter -Wno-sign-compare -Wno-format-security") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${BANDWIDTH_DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${BANDWIDTH_DEBUG_FLAGS}") find_program(NASM_FOUND nasm) if(NASM_FOUND) enable_language(ASM_NASM) endif(NASM_FOUND) if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") set(NASM_FLAGS_DEBUG "-gdwarf") endif(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") # Build (bandwidth) if(CMAKE_ASM_NASM_INFOMATION_LOADED) set(BANDWIDTH_FOUND ON PARENT_SCOPE) message(STATUS "Using built-in ${PROJECT_NAME}, version ${PROJECT_VERSION}") if(BITNESS EQUAL 32) set(ROUTINES "routines-x86-32bit") add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ROUTINES}.o COMMAND ${CMAKE_ASM_NASM_COMPILER} ${NASM_FLAGS_DEBUG} -f elf ${ROUTINES}.asm -o ${CMAKE_CURRENT_BINARY_DIR}/${ROUTINES}.o WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) elseif(BITNESS EQUAL 64) set(ROUTINES "routines-x86-64bit") add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ROUTINES}.o COMMAND ${CMAKE_ASM_NASM_COMPILER} ${NASM_FLAGS_DEBUG} -f elf64 ${ROUTINES}.asm -o ${CMAKE_CURRENT_BINARY_DIR}/${ROUTINES}.o WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif() if(LIBCPUID_FOUND AND WITH_LIBCPUID) add_definitions(-DHAS_LIBCPUID=1) else(LIBCPUID_FOUND AND WITH_LIBCPUID) add_definitions(-DHAS_LIBCPUID=0) endif(LIBCPUID_FOUND AND WITH_LIBCPUID) add_library(bandwidth STATIC BMP.c BMPGraphing.c font.c main.c minifont.c libbandwidth.h ${ROUTINES}.o ) target_link_libraries(bandwidth) set(BANDWIDTH_VERSION ${PROJECT_VERSION} PARENT_SCOPE) else(CMAKE_ASM_NASM_INFOMATION_LOADED) set(BANDWIDTH_FOUND OFF PARENT_SCOPE) endif(CMAKE_ASM_NASM_INFOMATION_LOADED) CPU-X-3.2.4/src/bandwidth/COPYING.txt000066400000000000000000000431331341671471500167750ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. CPU-X-3.2.4/src/bandwidth/README.md000066400000000000000000000013321341671471500163760ustar00rootroot00000000000000# Bandwidth: a memory bandwidth benchmark Distributed under the terms of the [GNU GPL v2](https://raw.githubusercontent.com/X0rg/CPU-X/master/src/bandwidth/COPYING.txt). ### CPU-X NOTE This sofware has been patched to be used within CPU-X. You can find the official web page of this project here: https://zsmith.co/bandwidth.html This is based on bandwidth [1.5.1](https://zsmith.co/archives/bandwidth-1.5.1.tar.gz). This software is used to retrieve following data: * Caches tab * L1 cache speed * L2 cache speed * L3 cache speed * L4 cache speed You can reproduce the output of `bandwidth` command by using `cpu-x --bandwidth`. It will produce a graph named `bandwidth.bmp` in the current working directory. CPU-X-3.2.4/src/bandwidth/README.txt000066400000000000000000000127561341671471500166310ustar00rootroot00000000000000 This is the README file for my program, "bandwidth". Bandwidth is a benchmark that attempts to measure memory bandwidth. In December 2010 (and as of release 0.24), I extended 'bandwidth' to measure network bandwidth as well. Bandwidth is useful because both memory bandwidth and network bandwidth need to be measured to give you a clear idea of what your computer(s) can do. Merely relying on specs does not give a full picture and indeed specs can be misleading. -------------------------------------------------- MEMORY BANDWIDTH My program bandwidth performs sequential and random reads and writes of varying sizes. This permits you to infer from the graph how each type of memory is performing. So for instance when bandwidth writes a 256-byte chunk, you know that because caches are normally write-back, this chunk will reside entirely in the L1 cache. Whereas a 512 kB chunk will mainly reside in L2. You could run a non-artificial benchmark and observe that a general performance number is lower on one machine or higher on anotehr, but that may conceal the cause. So the purpose of this program is to help you pinpoint the cause of a performance problem, or to affirm a general impression about a memory- intensive program. It also tells you the best-case scenario e.g. the maximum bandwidth achieved using sequential, 128-bit memory accesses. Release 1.5: - Fixed AVX bug. Added --nice mode and CPU temperature monitoring (OS/X only). Release 1.4: - Added randomized 256-bit AVX reader & writer tests (Intel64 only). Release 1.3: - Added CSV output. Updated ARM code for Raspberry π 3. Release 1.2: - Added ARM code back in. Release 1.1: - Added larger font. Release 1.0: - Moved graphing into BMPGraphing module. - Finally added LODS benchmarking, which proves how badly lodsb/lodsw/lodsd/lodsq perform. - Added switches --faster and --fastest. Release 0.32: - Improved AVX support. Release 0.31: - Adds cache detection for Intel 32-bit CPUs - Adds a little AVX support. - Fixes vector-to/from-main transfer bugs. Release 0.30 adds cache detection for Intel 64-bit CPUs. Release 0.29 improved graph granularity with more 128-byte tests and removes ARM support. Release 0.28 added a proper test of CPU features e.g. SSE 4.1. Release 0.27 added finer-granularity 128-byte tests. Release 0.26 fixed an issue with AMD processors. Release 0.25 maked network bandwidth bidirectional. Release 0.24 added network bandwidth testing. Release 0.23 added: - Mac OS/X 64-bit support. - Vector-to-vector register transfer test. - Main register to/from vector register transfer test. - Main register byte/word/dword/qword to/from vector register test (pinsr*, pextr* instructions). - Memory copy test using SSE2. - Automatic checks under Linux for SSE2 & SSE4. Release 0.22 added: - Register-to-register transfer test. - Register-to/from-stack transfer tests. Release 0.21 added: - Standardized memory chunks to always be a multiple of 256-byte mini-chunks. - Random memory accesses, in which each 256-byte mini-chunk accessed is accessed in a random order, but also, inside each mini-chunk the 32/64/128 data are accessed pseudo-randomly as well. - Now 'bandwidth' includes chunk sizes that are not powers of 2, which increases data points around the key chunk sizes corresponding to common L1 and L2 cache sizes. - Command-line options: --fast for 0.25 seconds per test. --slow for 20 seconds per test. --title for adding a graph title. Release 0.20 added graphing, with the graph stored in a BMP image file. It also adds the --slow option for more precise runs. Release 0.19 added a second 128-bit SSE writer routine that bypasses the caches, in addition to the one that doesn't. Release 0.18 was my Grand Unified bandwidth benchmark that brought together support for four operating systems: - Linux - Windows Mobile - 32-bit Windows - Mac OS/X 64-bit and two processor architectures: - x86 - Intel64 I've written custom assembly routines for each architecture. Total run time for the default speed, which has 5 seconds per test, is about 35 minutes. -------------------------------------------------- NETWORK BANDWIDTH (beginning with release 0.24) [Update: This feature may no longer be working.] In mid-December 2010, I extended bandwidth to measure network bandwidth, which is useful for testing your home or workplace network setup, and in theory could be used to test machines across the Internet. Release 0.25 adds: - Bidirectional network bandwidth testing. - Specifiable port# (default is 49000). In the graph: - Sent data appears as a solid line. - Received data appears as a dashed line. The network test is pretty simple. It sends chunks of data of varying sizes to whatever computers (nodes) that you specify. Each of those must be running 'bandwidth' in transponder mode. The chunks of data range of 32 kB up to 32 MB. These are actually send as a stream of 1 or more 32 kB sub-chunks. Sample output: output/Network-Linux2.6-Celeron-2.8GHz-32bit-loopback.bmp output/Network-MacOSX32-Corei5-2.4GHz-64bit-loopback.bmp output/Network-Mac64-Linux32.bmp How to start a transponder: ./bandwidth-mac64 --transponder Example invocation of the test leader: ./bandwidth64 --network 192.168.1.104 I've tested network mode on: Linux 32-bit Mac OS/X 32- and 64-bit Win/Cygwin 32-bit. -------------------------------------------------- This program is provided without any warranty and AS-IS. See the file COPYING for details. Zack Smith 1@zsmith.co March 2013 CPU-X-3.2.4/src/bandwidth/defs.h000066400000000000000000000160541341671471500162200ustar00rootroot00000000000000/*============================================================================ bandwidth, a benchmark to estimate memory transfer bandwidth. Copyright (C) 2005-2017 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *===========================================================================*/ //--------------------------------------------------------------------------- // Change log // 0.18 Grand unified version supports x86/intel64/arm, linux/win32/winmo. // 0.19 Now have 128-bit writer that goes to cache AND one that bypasses. // 0.20 Added my bmplib and graphing of output. Also added --slow option. // 0.21 Adds random testing. Min chunk size = 256 B. Allows non-2^n chunks. // 0.22 Adds register-to-register and register-to/from-stack transfers. // 0.23 Adds vector-to-vector and register-to-vector transfers, & Mac support. // 0.24 Adds network bandwidth tests from this PC to specified others. // 0.25 Made network tests bidirectional to test asymmetric networks. // 0.26 Fixes to prevent certain vector instructions being used w/AMD chips. // 0.27 Added 128-byte tests for greater precision. // 0.28 Added use of CPUID. // 0.29 Added more 128-byte tests. // 0.30 Adds cache identification for Intel CPUs in 64-bit mode. // 0.31 Adds cache identification for Intel CPUs in 32-bit mode. // 0.32 Added AVX support. // 1.0 Moved graphing logic into BMPGraphing. Added LODS support. // 1.1 Switched to larger font in graphing module. // 1.2 Re-added ARM 32 support. // 1.3 Added CSV output support. Added 32-bit Raspberry π 3 support. // 1.4 Added 256-bit routines RandomReaderAVX, RandomWriterAVX. // 1.4.1 Added --limit parameter. // 1.4.2 Fixed compiler warnings. // 1.5 Fixed AVX writer bug that gave inaccurate results. Added nice mode. // 1.5.1 Fixed crashing bug. //--------------------------------------------------------------------------- #ifndef _DEFS_H #define _DEFS_H #define RELEASE "1.5.1" #ifdef __WIN32__ typedef char bool; enum { true=1, false=0 }; #else #include #endif #define NETWORK_DEFAULT_PORTNUM (49000) #define NETSIZE_MIN (15) #define NETSIZE_MAX (28) #define NETWORK_CHUNK_SIZE (1< #include "BMP.h" // Mini characters, 8 pixels high. static const char *font_chars_ [] = { "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", " ", " ", "##", "##", "", "", "", "## ##", "## ##", "## ##", " # #", "", "", "", "", "", "", "", "", "", "", "", "", "", " ## ## ", " ## ## ", " ## ## ", " ## ## ", " ##########", " ##########", " ## ## ", " ## ## ", " ##########", " ##########", " ## ## ", " ## ## ", " ## ## ", " ## ## ", "", "", "", " ## ", " ## ", " ########", "## ##", "## ## ", "## ## ", " ###### ", " ## ##", " ## ##", " ## ##", " ## ##", "########", " ## ", " ## ", "", "", "", " ## ##", " # # ##", " ## ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "## ## ", "## # #", "## ## ", "", "", "", " #####", "## ##", "## ##", "## ##", "## ##", "## ## ", " ## ## ##", " #### ##", "## ## ##", "## ####", "## ##", "## ##", " ## ## ##", " ##### ##", "", "", "", "###", "###", " ##", " #", " #", "", "", "", "", "", "", "", "", "", "", "", "", " ##", " ##", " ##", " ##", " ##", "##", "##", "##", "##", "##", "##", " ##", " ##", " ##", " ##", " ##", "", "## ", " ## ", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "##", "", " ", "", "", " ##", "## ## ##", " ## ## ##", " ######", " ####", " ######", " ## ## ##", "## ## ##", " ##", "", "", "", "", "", "", "", "", " ##", " ##", " ##", " ##", "##########", " ##", " ##", " ##", " ##", "", "", "", "", "", " ", " ", "", "", "", "", "", "", "", "", "", "", "###", "###", " ##", " #", " #", " ", "", "", "", "", "", "", "#######", "", "", "", "", "", "", "", "", "", " ", " ", "", "", "", "", "", "", "", "", "", "", "###", "###", "", "", "", " ", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "##", "##", "", "", "", " ##### ", " ## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " ##### ", "", "", "", " ##", " ##", " ###", "#####", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ## ", "", "", "", " #### ", " ## ##", "## ##", " ##", " ##", " ##", " ##", " ##", " ##", " ## ", "## ", "## ", "## ", "########", "", "", "", "########", " ##", " ##", " ##", " ## ", " ## ", " #### ", " ##", " ##", " ##", " ##", "## ##", " ## ##", " #### ", "", "", "", " ##", " ###", " ####", " ## ##", " ## ##", "## ##", "#########", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", "########", "## ", "## ", "## ", "## ", "###", " ######", " ##", " ##", " ##", " ##", "## ##", " ## ##", " #### ", "", "", "", " ##### ", " ## #", "##", "##", "##", "##", "#######", "## ## ", "## ##", "## ##", "## ##", "## ##", " ## ##", " ##### ", "", "", "", "########", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", " ##### ", " ## ##", "## ##", "## ##", "## ##", " ## ##", " ##### ", " ## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " ##### ", "", "", "", " ##### ", " ## ##", "## ##", "## ##", "## ##", " ## ##", " #######", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", " ", " ", "", "", "", "###", "###", "", "", "", "", "###", "###", "", "", "", "", " ", "", "", "", "", "###", "###", "", "", "", "", "###", "###", " ##", " ##", "#", "", " ##", " ##", " ##", " ##", " ##", " ##", "##", "##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", " ", "", "", "", "", "", "############", "############", " ", " ", "############", "############", "", "", "", "", "", "##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "##", "", "", "", " ###### ", " ## ##", "## ##", "## ##", " ##", " ##", " ### ", " ##", " ##", " ##", "", "", " ##", " ##", "", "", "", " ###### ", " ## ##", "## ##", "## ##", "## ####", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ####", "## ", "## ", " ## ##", " #######", "", "", "", " ##", " ####", " ####", " ## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ########", " ## ##", " ## ##", "## ##", "## ##", "## ##", "", "", "", "#######", "## ##", "## ##", "## ##", "## ##", "## ##", "#######", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "#######", "", "", "", " ###### ", " ## ##", "## ##", "## ##", "## ", "## ", "## ", "## ", "## ", "## ", "## ##", "## ##", " ## ##", " ######", "", "", "", "########", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ## ", "########", "", "", "", "##########", "##", "##", "##", "##", "##", "########", "##", "##", "##", "##", "##", "##", "##########", "", "", "", "##########", "##", "##", "##", "##", "##", "########", "##", "##", "##", "##", "##", "##", "##", "", "", "", " ###### ", " ## ##", "## ##", "## ##", "## ", "## ", "## ####", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ###", " ###### #", "", "", "", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "##########", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "", "", "", " ## ", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "## ##", "## ##", " ## ##", " ####", "", "", "", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "####", "####", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "", "", "", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "########", "", "", "", "## ##", "### ###", "#### ####", "## ## ## ##", "## ## ## ##", "## ### ##", "## # ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "", "", "", "## ##", "### ##", "#### ##", "#### ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ####", "## ####", "## ###", "## ##", "", "", "", " ###### ", " ## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " ######", "", "", "", "########", "## ##", "## ##", "## ##", "## ##", "## ##", "########", "##", "##", "##", "##", "##", "##", "##", "", "", "", " ######", " ## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ## ##", "## ## ##", "## ## ##", "## ###", " ## ##", " ##### ##", "", "", "", "########", "## ##", "## ##", "## ##", "## ##", "## ##", "########", "####", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "", "", "", " ######", " ## ##", "## ##", "## ##", "##", " ###", " #####", " ##", " ##", " ##", "## ##", "## ##", " ## ##", " ######", "", "", "", "##########", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " ######", "", "", "", "## ##", "## ##", " ## ##", " ## ##", " ## ##", " ## ## ", " ## ## ", " ## ## ", " ## ## ", " ## ## ", " ## ## ", " ### ", " ### ", " # ", "", "", "", "## ## ##", "## ## ##", "## ## ##", " ## #### ##", " ## #### ##", " ## ## ## ##", " ## ## ## ##", " ## ## ## ##", " ## ## ## ##", " ## ## ## ##", " ## ## ## ##", " # # # #", " ### ###", " ### ###", "", "", "", "## ##", "## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ##", " ##", " ## ##", " ## ##", " ## ##", " ## ##", "## ##", "## ##", "", "", "", "## ##", "## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ####", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", "#########", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "#########", "", "", "", "#####", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "#####", "", "##", "##", "##", "##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "", "", "", "#####", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "#####", "", " ##", " ####", " ## ##", " ## ##", "## ##", "## ##", "", "", "", "", "", "", "", "", "", "", "", " ", "", "", "", "", "", "", "", "", "", "", "", "", "########", "", "", "", "####", "####", "##", " ##", " #", "", "", "", "", "", "", "", "", "", "", "", "", " ", "", "", "", " ######", " ## ##", " ##", " ##", " ######", " ## ##", "## ##", "## ##", " ## ##", " ##### ##", "", "", "", "##", "##", "##", "##", "## ####", "### ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "### ##", "## ####", "", "", "", " ", "", "", "", " #####", " ## ##", "## ", "## ", "## ", "## ", "## ", "## ", " ## ##", " #####", "", "", "", " ##", " ##", " ##", " ##", " #### ##", " ## ###", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ###", " #### ##", "", "", "", " ", "", "", "", " #####", " ## ##", "## ##", "## ##", "#########", "##", "##", "##", " ## ##", " ######", "", "", "", " #####", " ##", " ## ", " ## ", "#####", " ## ", " ## ", " ## ", " ## ", " ## ", " ## ", " ## ", " ## ", " ## ", "", "", "", " ", "", "", "", " ##### #", " ## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " #######", " ##", "## ##", " ######", "##", "##", "##", "##", "## ####", "### ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "", "", "", "##", "##", "", "", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "", "", "", " ##", " ##", " ", " ", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", "###", "##", "##", "##", "##", "## ##", "## ##", "## ## ", "## ## ", "#### ", "#### ", "## ## ", "## ## ", "## ##", "## ##", "", "", "", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "##", "", "", "", " ", "", "", "", "## ### ####", "### ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "## ## ##", "", "", "", " ", "", "", "", "## ####", "### ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "", "", "", " ", "", "", "", " #####", " ## ## ", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ## ", " ##### ", "", "", "", " ", "", "", "", "## ####", "### ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "#######", "##", "##", "##", " ", "", "", "", " #### ##", " ## ###", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " #######", " ##", " ##", " ##", " ", "", "", "", "## ####", "#### ##", "###", "##", "##", "##", "##", "##", "##", "##", "", "", "", " ", "", "", "", " ######", "## ##", "##", "##", " ###", " ###", " ##", " ##", "## ##", " ######", "", "", "", " ##", " ##", " ##", " ##", "######", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ##", " ####", "", "", "", " ", "", "", "", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", "## ##", " ## ##", " ##### #", "", "", "", " ", "", "", "", "## ##", "## ##", "## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ## ##", " #####", " ###", "", "", "", " ", "", "", "", "## ## ##", "## ## ##", "## ## ##", " ## #### ##", " ## #### ##", " ## #### ##", " ## ## ## ##", " ## ## ## ##", " ##### #####", " ### ###", "", "", "", " ", "", "", "", "## ##", "## ##", " ## ##", " ## ##", " ##", " ##", " ## ##", " ## ##", "## ##", "## ##", "", "", "", " ", "", "", "", " ## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ## ##", " ####", " ###", " ##", " ##", "###", " ", "", "", "", "#########", " ##", " ##", " ##", " ##", " ##", " ## ", " ## ", "## ", "#########", "", "", "", }; const char **get_font_chars () { return font_chars_; } CPU-X-3.2.4/src/bandwidth/font.h000066400000000000000000000020261341671471500162370ustar00rootroot00000000000000 /*============================================================================= bmplib, a simple library to create, modify, and write BMP image files. Copyright (C) 2009-2014 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *============================================================================*/ #ifndef _FONT_H #define _FONT_H extern const char **get_font_chars (void); #endif CPU-X-3.2.4/src/bandwidth/libbandwidth.h000066400000000000000000000033121341671471500177230ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE libbandwidth.h */ #ifndef _LIBBANDWIDTH_H_ #define _LIBBANDWIDTH_H_ #define BANDWIDTH_MODE (opts->output_type == OUT_BANDWIDTH) enum EnTests { SEQ_128_R, SEQ_256_R, RAND_128_R, SEQ_128_CACHE_W, SEQ_256_CACHE_W, RAND_128_CACHE_W, SEQ_128_BYPASS_R, RAND_128_BYPASS_R, SEQ_128_BYPASS_W, SEQ_256_BYPASS_W, RAND_128_BYPASS_W, SEQ_128_C, SEQ_256_C, SEQ_32_LR, SEQ_16_LR, SEQ_8_LR, #ifdef __x86_64__ SEQ_64_R, RAND_64_R, SEQ_64_W, RAND_64_W, SEQ_64_LR, RAND_256_R, RAND_256_W, #else SEQ_32_R, RAND_32_R, SEQ_32_W, RAND_32_W, #endif LASTTEST }; struct Tests { enum EnTests test; char *name; uint32_t color; bool need_flag; bool need_mask; int (*func_ptr)(unsigned long, int, bool); int mode; bool random; }; int bandwidth_main(int argc, char **argv); int bandwidth_cpux(void *p_data); #endif CPU-X-3.2.4/src/bandwidth/main.c000066400000000000000000002230321341671471500162120ustar00rootroot00000000000000/*============================================================================ bandwidth, a benchmark to estimate memory transfer bandwidth. Copyright (C) 2005-2018 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *===========================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include // gethostbyname #include #include #include #define GRAPH_WIDTH 1440 #define GRAPH_HEIGHT 900 #include "defs.h" #include "BMP.h" #include "BMPGraphing.h" #define VREGISTER_COUNT 3333 #ifndef __arm__ #define x86 #endif #define TITLE_MEMORY_NET "Network benchmark results from bandwidth " RELEASE " by Zack Smith, http://zsmith.co" #define TITLE_MEMORY_GRAPH "Memory benchmark results from bandwidth " RELEASE " by Zack Smith, http://zsmith.co" #ifdef __WIN32__ // #include #endif #ifdef __linux__ #include #include #include #endif /* Needed by CPU-X */ #include "../cpu-x.h" #include "libbandwidth.h" #if HAS_LIBCPUID # include #endif #ifdef __x86_64__ #define IS_64BIT #endif static enum { OUTPUT_MODE_GRAPH=1, OUTPUT_MODE_CSV=2, } outputMode; // Mode to be nice and to keep CPU temperature low. static bool nice_mode = false; #define NICE_DURATION (2) #define MAX_CPU_TEMP (50) static int network_port = NETWORK_DEFAULT_PORTNUM; enum { NO_SSE2, // x86 SSE2, SSE2_BYPASS, AVX, AVX_BYPASS, LODSQ, LODSD, LODSW, LODSB, // ARM NEON_64BIT, NEON_128BIT, }; static BMPGraph *graph = NULL; #ifndef __arm__ static bool use_sse2 = true; static bool use_sse4 = true; #else static bool use_sse2 = false; static bool use_sse4 = false; #endif static bool is_intel = false; static bool is_amd = false; static bool limit_below_100MB = false; static FILE *csv_output_file = NULL; static char *csv_file_path = NULL; static uint32_t cpu_has_mmx = 0; static uint32_t cpu_has_sse = 0; static uint32_t cpu_has_sse2 = 0; static uint32_t cpu_has_sse3 = 0; static uint32_t cpu_has_ssse3 = 0; static uint32_t cpu_has_sse4a = 0; static uint32_t cpu_has_sse41 = 0; static uint32_t cpu_has_sse42 = 0; static uint32_t cpu_has_aes = 0; static uint32_t cpu_has_avx = 0; static uint32_t cpu_has_avx2 = 0; static uint32_t cpu_has_64bit = 0; static uint32_t cpu_has_xd = 0; //---------------------------------------- // Parameters for the tests. // static long usec_per_test = 5000000; // 5 seconds per memory test. static int chunk_sizes[] = { #ifdef x86 128, #endif 256, #ifdef x86 384, #endif 512, #ifdef x86 640, #endif 768, #ifdef x86 896, #endif 1024, 1280, 2048, 3072, 4096, 6144, 8192, // Some processors' L1 data caches are only 8kB. 12288, 16384, 20480, 24576, 28672, 32768, // Common L1 data cache size. 34*1024, 36*1024, 40960, 49152, 65536, 131072, // Old L2 cache size. 192 * 1024, 256 * 1024, // Old L2 cache size. 320 * 1024, 384 * 1024, 512 * 1024, // Old L2 cache size. 768 * 1024, 1 << 20, // 1 MB = common L2 cache size. (1024 + 256) * 1024, // 1.25 (1024 + 512) * 1024, // 1.5 (1024 + 768) * 1024, // 1.75 1 << 21, // 2 MB = common L2 cache size. (2048 + 256) * 1024, // 2.25 (2048 + 512) * 1024, // 2.5 (2048 + 768) * 1024, // 2.75 3072 * 1024, // 3 MB = common L2 cache size. 3407872, // 3.25 MB 3 * 1024 * 1024 + 1024 * 512, // 3.5 MB 1 << 22, // 4 MB 5242880, // 5 megs 6291456, // 6 megs (common L2 cache size) 7 * 1024 * 1024, 8 * 1024 * 1024, // Xeon E3's often has 8MB L3 #ifndef __arm__ 9 * 1024 * 1024, 10 * 1024 * 1024, // Xeon E5-2609 has 10MB L3 12 * 1024 * 1024, 14 * 1024 * 1024, 15 * 1024 * 1024, // Xeon E6-2630 has 15MB L3 16 * 1024 * 1024, 20 * 1024 * 1024, // Xeon E5-2690 has 20MB L3 21 * 1024 * 1024, 32 * 1024 * 1024, 48 * 1024 * 1024, 64 * 1024 * 1024, 72 * 1024 * 1024, 96 * 1024 * 1024, 128 * 1024 * 1024, #define TEST_L4 #ifdef TEST_L4 160 * 1024 * 1024, 192 * 1024 * 1024, 224 * 1024 * 1024, 256 * 1024 * 1024, 320 * 1024 * 1024, 512 * 1024 * 1024, #endif #endif 0 }; static double chunk_sizes_log2 [sizeof(chunk_sizes)/sizeof(int)]; //---------------------------------------------------------------------------- // Name: internal // Purpose: Complain and exit. //---------------------------------------------------------------------------- void internal (char *s) { fprintf (stderr, "Internal error: %s\n", s); exit (2); } //---------------------------------------------------------------------------- // Name: error // Purpose: Complain and exit. //---------------------------------------------------------------------------- void error (char *s) { #ifndef __WIN32__ fprintf (stderr, "Error: %s\n", s); exit (1); #else wchar_t tmp [200]; int i; for (i = 0; s[i]; i++) tmp[i] = s[i]; tmp[i] = 0; MessageBoxW (0, tmp, L"Error", 0); ExitProcess (0); #endif } //============================================================================ // Output multiplexor. //============================================================================ void dataBegins (char *title) { if (!outputMode) { internal ("Bad output mode."); } //========== if (outputMode & OUTPUT_MODE_GRAPH) { if (graph) internal ("Graphing already initialized."); graph = BMPGraphing_new (GRAPH_WIDTH, GRAPH_HEIGHT, MODE_X_AXIS_LOG2); BMPGraphing_set_title (graph, title? title : TITLE_MEMORY_GRAPH); } if (outputMode & OUTPUT_MODE_CSV) { if (csv_output_file) internal ("CSV file already initialized."); csv_output_file = fopen (csv_file_path, "wb"); if (!csv_output_file) { error ("Cannot open CSV output file."); } if (title) fprintf (csv_output_file, "%s\n", title); } } void dataBeginSection (const char *name, uint32_t parameter) { if (!outputMode) { internal ("Bad output mode."); } if (!name) { internal ("dataBeginSection: NULL name."); } //========== if (nice_mode) { sleep (NICE_DURATION); #ifdef __APPLE__ #define POPEN_BUFSIZE (256) // Keep CPU temperature below 50 C. // int cpu_temperature = 0; bool done = true; do { FILE *f = popen ("sysctl machdep.xcpm.cpu_thermal_level | sed '\''s/machdep.xcpm.cpu_thermal_level/CPU temperature/'\''", "r"); if (f) { char buffer [POPEN_BUFSIZE] = {0}; if (0 < fread (buffer, 1, POPEN_BUFSIZE-1, f)) { int i; for (i=0; i < POPEN_BUFSIZE && buffer[i]; i++) { if (isdigit (buffer[i])) break; } if (i < POPEN_BUFSIZE) { cpu_temperature = atoi (buffer + i); printf ("CPU temperature is %d C.\n", cpu_temperature); } else { break; } } pclose (f); } else { break; } done = (cpu_temperature < MAX_CPU_TEMP); if (!done) sleep (10); } while (!done); #endif } if (outputMode & OUTPUT_MODE_GRAPH) { if (!graph) internal ("Graphing not initialized."); BMPGraphing_new_line (graph, name, parameter); } if (outputMode & OUTPUT_MODE_CSV) { if (!csv_output_file) internal ("CSV output not initialized."); fprintf (csv_output_file, "%s\n", name); } } void dataEnds (const char *parameter) { if (!outputMode) { internal ("Bad output mode."); } //========== if (outputMode & OUTPUT_MODE_GRAPH) { if (!graph) internal ("Graphing not initialized."); if (!parameter) internal ("dataEnds: NULL name."); BMPGraphing_make (graph); BMP_write (graph->image, parameter); BMPGraphing_destroy (graph); graph= NULL; puts ("Wrote graph to: bandwidth.bmp"); } if (outputMode & OUTPUT_MODE_CSV) { if (!csv_output_file) internal ("CSV output not initialized."); fclose (csv_output_file); printf ("Wrote %s.\n", csv_file_path); } } void dataAddDatum (Value x, Value y) { if (!outputMode) { internal ("Bad output mode."); } //========== if (outputMode & OUTPUT_MODE_GRAPH) { if (!graph) internal ("Graphing not initialized."); BMPGraphing_add_point (graph, x, y); } if (outputMode & OUTPUT_MODE_CSV) { if (!csv_output_file) internal ("CSV output not initialized."); fprintf (csv_output_file, "%lld, %.1Lf\n", (long long)x, (long double)y/10.); fflush (csv_output_file); } } //============================================================================ // Output buffer logic. //============================================================================ void print (const char *s) { if(BANDWIDTH_MODE) printf ("%s",s); } void newline () { if(BANDWIDTH_MODE) puts (""); } void println (char *s) { print (s); newline (); } void print_int (int d) { if(BANDWIDTH_MODE) printf ("%d", d); } void print_uint (unsigned long d) { if(BANDWIDTH_MODE) printf ("%lu", d); } void println_int (int d) { print_int (d); newline (); } void print_result (long double result) { if(BANDWIDTH_MODE) printf ("%.1Lf MB/s", result); } void flush () { fflush (stdout); } void print_size (unsigned long size) { if (size < 1536) { print_int (size); print (" B"); } else if (size < (1<<20)) { print_int (size >> 10); print (" kB"); } else { print_int (size >> 20); switch ((size >> 18) & 3) { case 1: print (".25"); break; case 2: print (".5"); break; case 3: print (".75"); break; } print (" MB"); } } //============================================================================ // Timing logic. //============================================================================ //---------------------------------------------------------------------------- // Name: mytime // Purpose: Reports time in microseconds. //---------------------------------------------------------------------------- unsigned long mytime () { #ifndef __WIN32__ struct timeval tv; struct timezone tz; memset (&tz, 0, sizeof(struct timezone)); gettimeofday (&tv, &tz); return 1000000 * tv.tv_sec + tv.tv_usec; #else return 1000 * GetTickCount (); // accurate enough. #endif } //---------------------------------------------------------------------------- // Name: calculate_result // Purpose: Calculates and prints a result. // Returns: 10 times the number of megabytes per second. //---------------------------------------------------------------------------- int calculate_result (unsigned long chunk_size, long long total_loops, long diff) { if (!diff) error ("Zero time difference."); // printf ("\nIn calculate_result, chunk_size=%ld, total_loops=%lld, diff=%ld\n", chunk_size, total_loops, diff); long double result = (long double) chunk_size; result *= (long double) total_loops; result *= 1000000.; // Convert to microseconds. result /= 1048576.; result /= (long double) diff; print_result (result); return (long) (10.0 * result); } //============================================================================ // Tests. //============================================================================ //---------------------------------------------------------------------------- // Name: do_write // Purpose: Performs write on chunk of memory of specified size. //---------------------------------------------------------------------------- int do_write (unsigned long size, int mode, bool random) { unsigned char *chunk; unsigned char *chunk0; unsigned long loops; unsigned long long total_count=0; #ifdef IS_64BIT unsigned long value = 0x1234567689abcdef; #else unsigned long value = 0x12345678; #endif unsigned long diff=0, t0; unsigned long tmp; unsigned long **chunk_ptrs = NULL; #ifdef x86 if (size & 127) error ("do_write(): chunk size is not multiple of 128."); #else if (size & 255) error ("do_write(): chunk size is not multiple of 256."); #endif //------------------------------------------------- chunk0 = malloc (size+64); chunk = chunk0; if (!chunk) error ("Out of memory"); tmp = (unsigned long) chunk; if (tmp & 31) { tmp -= (tmp & 31); tmp += 32; chunk = (unsigned char*) tmp; } //---------------------------------------- // Set up random pointers to chunks. // if (random) { tmp = size/256; chunk_ptrs = (unsigned long**) malloc (sizeof (unsigned long*) * tmp); if (!chunk_ptrs) error ("Out of memory."); //---------------------------------------- // Store pointers to all chunks into array. // int i; for (i = 0; i < tmp; i++) { chunk_ptrs [i] = (unsigned long*) (chunk + 256 * i); } //---------------------------------------- // Randomize the array of chunk pointers. // int k = 200; while (k--) { for (i = 0; i < tmp; i++) { int j = rand() % tmp; if (i != j) { unsigned long *ptr = chunk_ptrs [i]; chunk_ptrs [i] = chunk_ptrs [j]; chunk_ptrs [j] = ptr; } } } } //------------------------------------------------- if (random) print ("Random write "); else print ("Sequential write "); switch (mode) { case NEON_64BIT: print ("(64-bit), size = "); break; case NEON_128BIT: print ("(128-bit), size = "); break; case SSE2: print ("(128-bit), size = "); break; case AVX: print ("(256-bit), size = "); break; case AVX_BYPASS: print ("bypassing cache (256-bit), size = "); break; case SSE2_BYPASS: print ("bypassing cache (128-bit), size = "); break; default: #ifdef IS_64BIT print ("(64-bit), size = "); #else print ("(32-bit), size = "); #endif } print_size (size); print (", "); loops = (1 << 26) / size;// XX need to adjust for CPU MHz if (loops < 1) loops = 1; t0 = mytime (); while (diff < usec_per_test) { total_count += loops; switch (mode) { #ifdef __arm__ case NEON_64BIT: if (random) RandomWriterVector (chunk_ptrs, size/256, loops, value); break; case NEON_128BIT: if (!random) WriterVector (chunk, size, loops, value); break; #endif #ifdef x86 case SSE2: if (random) RandomWriterSSE2 (chunk_ptrs, size/256, loops, value); else { if (size & 128) WriterSSE2_128bytes (chunk, size, loops, value); else WriterSSE2 (chunk, size, loops, value); } break; case SSE2_BYPASS: if (random) RandomWriterSSE2_bypass (chunk_ptrs, size/256, loops, value); else { if (size & 128) WriterSSE2_128bytes_bypass (chunk, size, loops, value); else WriterSSE2_bypass (chunk, size, loops, value); } break; case AVX: if (!random) { WriterAVX (chunk, size, loops, value); } else { #ifdef IS_64BIT RandomWriterAVX (chunk_ptrs, size/256, loops, value); #endif } break; case AVX_BYPASS: if (!random) { WriterAVX_bypass (chunk, size, loops, value); } break; #endif default: if (random) RandomWriter (chunk_ptrs, size/256, loops, value); else { #ifdef x86 if (size & 128) Writer_128bytes (chunk, size, loops, value); else #endif Writer (chunk, size, loops, value); } } diff = mytime () - t0; } print ("loops = "); print_uint (total_count); print (", "); flush (); int result = calculate_result (size, total_count, diff); newline (); flush (); free ((void*)chunk0); if (chunk_ptrs) free (chunk_ptrs); return result; } //---------------------------------------------------------------------------- // Name: do_read // Purpose: Performs sequential read on chunk of memory of specified size. //---------------------------------------------------------------------------- int do_read (unsigned long size, int mode, bool random) { unsigned long loops; unsigned long long total_count = 0; unsigned long t0, diff=0; unsigned char *chunk; unsigned char *chunk0; unsigned long tmp; unsigned long **chunk_ptrs = NULL; if (size & 127) error ("do_read(): chunk size is not multiple of 128."); //------------------------------------------------- chunk0 = chunk = malloc (size+64); if (!chunk) error ("Out of memory"); memset (chunk, 0, size); tmp = (unsigned long) chunk; if (tmp & 31) { tmp -= (tmp & 31); tmp += 32; chunk = (unsigned char*) tmp; } //---------------------------------------- // Set up random pointers to chunks. // if (random) { int tmp = size/256; chunk_ptrs = (unsigned long**) malloc (sizeof (unsigned long*) * tmp); if (!chunk_ptrs) error ("Out of memory."); //---------------------------------------- // Store pointers to all chunks into array. // int i; for (i = 0; i < tmp; i++) { chunk_ptrs [i] = (unsigned long*) (chunk + 256 * i); } //---------------------------------------- // Randomize the array of chunk pointers. // int k = 200; while (k--) { for (i = 0; i < tmp; i++) { int j = rand() % tmp; if (i != j) { unsigned long *ptr = chunk_ptrs [i]; chunk_ptrs [i] = chunk_ptrs [j]; chunk_ptrs [j] = ptr; } } } } //------------------------------------------------- if (random) print ("Random read "); else print ("Sequential read "); switch (mode) { #ifdef __arm__ case NEON_64BIT: print ("(64-bit), size = "); break; case NEON_128BIT: print ("(128-bit), size = "); break; #endif #ifdef x86 case SSE2: print ("(128-bit), size = "); break; case LODSB: print ("(8-bit LODSB), size = "); break; case LODSW: print ("(16-bit LODSW), size = "); break; case LODSD: print ("(32-bit LODSD), size = "); break; case LODSQ: print ("(64-bit LODSQ), size = "); break; case AVX: print ("(256-bit), size = "); break; case AVX_BYPASS: print ("bypassing cache (256-bit), size = "); break; case SSE2_BYPASS: print ("bypassing cache (128-bit), size = "); break; #endif default: #ifdef IS_64BIT print ("(64-bit), size = "); #else print ("(32-bit), size = "); #endif } print_size (size); print (", "); flush (); loops = (1 << 26) / size; // XX need to adjust for CPU MHz if (loops < 1) loops = 1; t0 = mytime (); while (diff < usec_per_test) { total_count += loops; switch (mode) { #ifdef __arm__ case NEON_64BIT: if (random) RandomReaderVector (chunk_ptrs, size/256, loops); break; case NEON_128BIT: if (!random) ReaderVector (chunk, size, loops); break; #endif #ifdef x86 case SSE2: if (random) RandomReaderSSE2 (chunk_ptrs, size/256, loops); else { if (size & 128) ReaderSSE2_128bytes (chunk, size, loops); else ReaderSSE2 (chunk, size, loops); } break; case SSE2_BYPASS: // No random reader for bypass. // if (random) RandomReaderSSE2_bypass (chunk_ptrs, size/256, loops); else { if (size & 128) ReaderSSE2_128bytes_bypass (chunk, size, loops); else ReaderSSE2_bypass (chunk, size, loops); } break; case AVX: if (!random) { ReaderAVX (chunk, size, loops); } else { #ifdef IS_64BIT RandomReaderAVX (chunk_ptrs, size/256, loops); #endif } break; case LODSB: if (!random) { ReaderLODSB (chunk, size, loops); } break; case LODSW: if (!random) { ReaderLODSW (chunk, size, loops); } break; case LODSD: if (!random) { ReaderLODSD (chunk, size, loops); } break; case LODSQ: if (!random) { ReaderLODSQ (chunk, size, loops); } break; #endif default: if (random) { RandomReader (chunk_ptrs, size/256, loops); } else { #ifdef x86 if (size & 128) Reader_128bytes (chunk, size, loops); else #endif Reader (chunk, size, loops); } } diff = mytime () - t0; } print ("loops = "); print_uint (total_count); print (", "); int result = calculate_result (size, total_count, diff); newline (); flush (); free (chunk0); if (chunk_ptrs) free (chunk_ptrs); return result; } //---------------------------------------------------------------------------- // Name: do_copy // Purpose: Performs sequential memory copy. //---------------------------------------------------------------------------- int do_copy (unsigned long size, int mode) { #ifdef x86 unsigned long loops; unsigned long long total_count = 0; unsigned long t0, diff=0; unsigned char *chunk_src; unsigned char *chunk_dest; unsigned char *chunk_src0; unsigned char *chunk_dest0; unsigned long tmp; if (size & 127) error ("do_copy(): chunk size is not multiple of 128."); //------------------------------------------------- chunk_src0 = chunk_src = malloc (size+64); if (!chunk_src) error ("Out of memory"); chunk_dest0 = chunk_dest = malloc (size+64); if (!chunk_dest) error ("Out of memory"); memset (chunk_src, 100, size); memset (chunk_dest, 200, size); tmp = (unsigned long) chunk_src; if (tmp & 31) { tmp -= (tmp & 31); tmp += 32; chunk_src = (unsigned char*) tmp; } tmp = (unsigned long) chunk_dest; if (tmp & 31) { tmp -= (tmp & 31); tmp += 32; chunk_dest = (unsigned char*) tmp; } //------------------------------------------------- print ("Sequential copy "); if (mode == SSE2) { print ("(128-bit), size = "); } else if (mode == AVX) { print ("(256-bit), size = "); } else { #ifdef IS_64BIT print ("(64-bit), size = "); #else print ("(32-bit), size = "); #endif } print_size (size); print (", "); flush (); loops = (1 << 26) / size; // XX need to adjust for CPU MHz if (loops < 1) loops = 1; t0 = mytime (); while (diff < usec_per_test) { total_count += loops; if (mode == SSE2) { #ifdef IS_64BIT if (size & 128) CopySSE_128bytes (chunk_dest, chunk_src, size, loops); else CopySSE (chunk_dest, chunk_src, size, loops); #else CopySSE (chunk_dest, chunk_src, size, loops); #endif } else if (mode == AVX) { if (!(size & 128)) CopyAVX (chunk_dest, chunk_src, size, loops); } diff = mytime () - t0; } print ("loops = "); print_uint (total_count); print (", "); int result = calculate_result (size, total_count, diff); newline (); flush (); free (chunk_src0); free (chunk_dest0); return result; #else return 0; #endif } int do_copy2 (unsigned long size, int mode, bool unused __attribute__((unused))) { return do_copy(size, mode); } //---------------------------------------------------------------------------- // Name: fb_readwrite // Purpose: Performs sequential read & write tests on framebuffer memory. //---------------------------------------------------------------------------- #if defined(__linux__) && defined(FBIOGET_FSCREENINFO) void fb_readwrite (bool use_sse2) { unsigned long total_count; unsigned long length; unsigned long diff, t0; static struct fb_fix_screeninfo fi; static struct fb_var_screeninfo vi; unsigned long *fb = NULL; int fd; #ifdef IS_64BIT unsigned long value = 0x1234567689abcdef; #else unsigned long value = 0x12345678; #endif //------------------------------------------------- fd = open ("/dev/fb0", O_RDWR); if (fd < 0) fd = open ("/dev/fb/0", O_RDWR); if (fd < 0) { println ("Cannot open framebuffer device."); return; } if (ioctl (fd, FBIOGET_FSCREENINFO, &fi)) { close (fd); println ("Cannot get framebuffer info"); return; } else if (ioctl (fd, FBIOGET_VSCREENINFO, &vi)) { close (fd); println ("Cannot get framebuffer info"); return; } else { if (fi.visual != FB_VISUAL_TRUECOLOR && fi.visual != FB_VISUAL_DIRECTCOLOR ) { close (fd); println ("Need direct/truecolor framebuffer device."); return; } else { unsigned long fblen; print ("Framebuffer resolution: "); print_int (vi.xres); print ("x"); print_int (vi.yres); print (", "); print_int (vi.bits_per_pixel); println (" bpp\n"); fb = (unsigned long*) fi.smem_start; fblen = fi.smem_len; fb = mmap (fb, fblen, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0); if (fb == MAP_FAILED) { close (fd); println ("Cannot access framebuffer memory."); return; } } } //------------------- // Use only the upper half of the display. // length = FB_SIZE; //------------------- // READ // print ("Framebuffer memory sequential read "); flush (); t0 = mytime (); total_count = FBLOOPS_R; #ifdef x86 if (use_sse2) ReaderSSE2 (fb, length, FBLOOPS_R); else #endif Reader (fb, length, FBLOOPS_R); diff = mytime () - t0; calculate_result (length, total_count, diff); newline (); //------------------- // WRITE // print ("Framebuffer memory sequential write "); flush (); t0 = mytime (); total_count = FBLOOPS_W; #ifdef x86 if (use_sse2) WriterSSE2_bypass (fb, length, FBLOOPS_W, value); else #endif Writer (fb, length, FBLOOPS_W, value); diff = mytime () - t0; calculate_result (length, total_count, diff); newline (); } #endif //---------------------------------------------------------------------------- // Name: register_test // Purpose: Determines bandwidth of register-to-register transfers. //---------------------------------------------------------------------------- void register_test () { long long total_count = 0; unsigned long t0; unsigned long diff = 0; //-------------------------------------- #ifdef IS_64BIT print ("Main register to main register transfers (64-bit) "); #else print ("Main register to main register transfers (32-bit) "); #endif flush (); #define REGISTER_COUNT 10000 t0 = mytime (); while (diff < usec_per_test) { RegisterToRegister (REGISTER_COUNT); total_count += REGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); //-------------------------------------- #ifdef x86 #ifdef IS_64BIT print ("Main register to vector register transfers (64-bit) "); #else print ("Main register to vector register transfers (32-bit) "); #endif flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { RegisterToVector (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); //-------------------------------------- #ifdef IS_64BIT print ("Vector register to main register transfers (64-bit) "); #else print ("Vector register to main register transfers (32-bit) "); #endif flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { VectorToRegister (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); #endif //-------------------------------------- print ("Vector register to vector register transfers (128-bit) "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { VectorToVector (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); #ifdef x86 //-------------------------------------- if (cpu_has_avx) { print ("Vector register to vector register transfers (256-bit) "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { VectorToVectorAVX (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); } //-------------------------------------- if (use_sse4) { print ("Vector 8-bit datum to main register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Vector8ToRegister (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (64, total_count, diff); newline (); flush (); } //-------------------------------------- print ("Vector 16-bit datum to main register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Vector16ToRegister (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (128, total_count, diff); newline (); flush (); //-------------------------------------- if (use_sse4) { print ("Vector 32-bit datum to main register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Vector32ToRegister (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); } //-------------------------------------- if (use_sse4) { print ("Vector 64-bit datum to main register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Vector64ToRegister (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); } //-------------------------------------- if (use_sse4) { print ("Main register 8-bit datum to vector register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Register8ToVector (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (64, total_count, diff); newline (); flush (); } //-------------------------------------- print ("Main register 16-bit datum to vector register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Register16ToVector (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (128, total_count, diff); newline (); flush (); //-------------------------------------- if (use_sse4) { print ("Main register 32-bit datum to vector register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Register32ToVector (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); } //-------------------------------------- if (use_sse4) { print ("Main register 64-bit datum to vector register transfers "); flush (); t0 = mytime (); diff = 0; total_count = 0; while (diff < usec_per_test) { Register64ToVector (VREGISTER_COUNT); total_count += VREGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); } #endif } //---------------------------------------------------------------------------- // Name: stack_test // Purpose: Determines bandwidth of stack-to/from-register transfers. //---------------------------------------------------------------------------- void stack_test () { long long total_count = 0; unsigned long t0; unsigned long diff = 0; #ifdef IS_64BIT print ("Stack-to-register transfers (64-bit) "); #else print ("Stack-to-register transfers (32-bit) "); #endif flush (); //-------------------------------------- diff = 0; total_count = 0; t0 = mytime (); while (diff < usec_per_test) { StackReader (REGISTER_COUNT); total_count += REGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); #ifdef IS_64BIT print ("Register-to-stack transfers (64-bit) "); #else print ("Register-to-stack transfers (32-bit) "); #endif flush (); //-------------------------------------- diff = 0; total_count = 0; t0 = mytime (); while (diff < usec_per_test) { StackWriter (REGISTER_COUNT); total_count += REGISTER_COUNT; diff = mytime () - t0; } calculate_result (256, total_count, diff); newline (); flush (); } //---------------------------------------------------------------------------- // Name: library_test // Purpose: Performs C library tests (memset, memcpy). //---------------------------------------------------------------------------- void library_test () { char *a1, *a2; unsigned long t, t0; int i; #define NT_SIZE (64*1024*1024) #define NT_SIZE2 (100) a1 = malloc (NT_SIZE); if (!a1) error ("Out of memory"); a2 = malloc (NT_SIZE); if (!a2) error ("Out of memory"); //-------------------------------------- t0 = mytime (); for (i=0; ih_addr_list); int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(host_ip); addr.sin_port = htons(network_port); if (connect (sock, (struct sockaddr*) &addr, sizeof (struct sockaddr))) { // perror ("connect"); close (sock); return false; } //------------------------------------ // Start stopwatch just before the send. // It will be stopped on receipt of // the response. // unsigned long t0 = mytime (); //------------------------------------ // Put # of chunks in the chunk. // Send all of our data. // sprintf (chunk, "%lu\n", n_chunks); int i; for (i = 0; i < n_chunks; i++) send (sock, chunk, chunk_size, 0); #if 0 //------------------------------------ // Set nonblocking mode. // int opt = 1; ioctl (sock, FIONBIO, &opt); #endif unsigned long t1 = mytime (); //------------------------------------ // Read the response. // int amount = recv (sock, chunk, chunk_size, 0); if (amount < 16) { close (sock); return false; } unsigned long duration_send = mytime() - t0; //------------------------------------ // Validate the response, which // contains the transponder's // perceived read duration. This value // may be as little as half our number. // unsigned long duration2 = -1; if (strncmp ("OK: ", chunk, 4)) { close (sock); return false; } if (1 != sscanf (4+chunk, "%lu", &duration2)) { close (sock); return false; } unsigned long remaining = chunk_size * n_chunks - amount; while (remaining > 0) { int amount = recv (sock, chunk, chunk_size, 0); if (amount <= 0) { perror ("recv"); close (sock); return false; } remaining -= amount; } unsigned long duration_recv = mytime () - t1; *duration_send_return = duration_send; *duration_recv_return = duration_recv; close (sock); return true; } //---------------------------------------------------------------------------- // Name: ip_to_str //---------------------------------------------------------------------------- void ip_to_str (unsigned long addr, char *str) { if (!str) return; unsigned short a = 0xff & addr; unsigned short b = 0xff & (addr >> 8); unsigned short c = 0xff & (addr >> 16); unsigned short d = 0xff & (addr >> 24); sprintf (str, "%u.%u.%u.%u", a,b,c,d); } //---------------------------------------------------------------------------- // Name: network_transponder // Purpose: Act as a transponder, receiving chunks of data and sending // back an acknowledgement once the enture chunk is read. // Returns: False if a problem occurs setting up the network socket. //---------------------------------------------------------------------------- bool network_transponder () { struct sockaddr_in sin, from; //------------------------------ // Get listening socket for port. // Then listen on given port#. // sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(network_port); int listensock; if ((listensock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); return false; } if (bind (listensock, (struct sockaddr*) &sin, sizeof(sin)) < 0) { perror ("bind"); close (listensock); return false; } if (listen (listensock, 500) < 0) { perror ("listen"); close (listensock); return false; } bool done = false; while (!done) { //---------------------------------------- // Wait for a client to contact us. // socklen_t len = sizeof (struct sockaddr); int sock = accept (listensock, (struct sockaddr*) &from, &len); if (sock < 0) { perror ("accept"); close (listensock); return false; } //---------------------------------------- // Clockwatch starts when we accept the // connection. // unsigned long t0 = mytime (); if (len != sizeof (struct sockaddr_in)) { close (sock); close (listensock); return false; } #if 0 unsigned long ipaddr = from.sin_addr.s_addr; char ipstring[30]; ip_to_str (ipaddr, ipstring); fprintf (stderr, "Incoming connection from %s\n", ipstring); #endif //---------------------------------------- // Read the first chunk only, in order to // get the # of bytes that will be sent. // char chunk [NETWORK_CHUNK_SIZE+1]; long n_chunks = 0; int amount_read = read (sock, chunk, NETWORK_CHUNK_SIZE); chunk [amount_read] = 0; if (1 != sscanf (chunk, "%ld", &n_chunks)) { close (sock); close (listensock); return false; } //---------------------------------------- // If the leader sends us a chunk count of // -99, this indicates that we should exit. // if (n_chunks == -99) { close (sock); close (listensock); return true; } // printf ("Reading %lu chunks of %d bytes...\n", n_chunks, NETWORK_CHUNK_SIZE); unsigned long long remaining = n_chunks; remaining *= NETWORK_CHUNK_SIZE; // printf ("remaining="); dump_hex64(remaining); puts(""); remaining -= amount_read; while (remaining > 0) { amount_read = read (sock, chunk, NETWORK_CHUNK_SIZE); remaining -= amount_read; if (amount_read < 0) { perror ("read"); break; } else if (!amount_read) break; } unsigned long duration = mytime() - t0; //------------------------------------ // Send response of same size. // sprintf (chunk, "OK: %lu\n", duration); chunk[14] = '\n'; //------------------------------------ // Send all of our data. // int i; for (i = 0; i < n_chunks; i++) send (sock, chunk, NETWORK_CHUNK_SIZE, 0); close (sock); } return true; } //---------------------------------------------------------------------------- // Name: network_test //---------------------------------------------------------------------------- bool network_test (char **destinations, int n_destinations) { int i; //---------------------------------------- // The memory chunk starts with a 12-byte // length of the overall send size. // The memory chunk will have a list of // the destinations in it. // In future, there will be a mechanism // for testing bandwidth between all nodes, // not just the leader & each of the // transponders. // char chunk [NETWORK_CHUNK_SIZE]; memset (chunk, 0, NETWORK_CHUNK_SIZE); sprintf (chunk, "000000000000\n%d\n", n_destinations); for (i = 0; i < n_destinations; i++) { char *s = destinations [i]; int chunk_len = strlen (chunk); int len = strlen (s); if (len + chunk_len < NETWORK_CHUNK_SIZE-1) { //---------------------------------------- // "transp" indicates that the given node // has not yet been a leader. // In future, "done" will indicate it has. // sprintf (chunk + chunk_len, "%s %s\n", s, "transp"); } } static unsigned long colors [] = { RGB_RED, RGB_GREEN, RGB_BLUE, RGB_ORANGE, RGB_PURPLE, RGB_BLACK, RGB_CORAL, RGB_CYAN, RGB_NAVYBLUE, RGB_BRASS, RGB_DARKORANGE, RGB_DARKGREEN, RGB_SALMON, RGB_MAGENTA, RGB_LEMONYELLOW, RGB_ROYALBLUE, RGB_DODGERBLUE, RGB_TURQUOISE, RGB_CADETBLUE, RGB_CHARTREUSE, RGB_DARKOLIVEGREEN, RGB_VIOLET, RGB_KHAKI, RGB_DARKKHAKI, RGB_GOLDENROD }; #define NCOLORS (sizeof(colors)/sizeof(unsigned long)) //---------------------------------------- // For each destination, run the test. // for (i = 0; i < n_destinations; i++) { bool problem = false; char *hostname = destinations[i]; printf ("Bandwidth sending to %s:\n", hostname); char title [PATH_MAX]; sprintf (title, "%s send (solid)", hostname); BMPGraphing_new_line (graph, title, i < NCOLORS? colors[i] : RGB_GRAY); //---------------------------------------- // Cache the receive durations for later. // unsigned long recv_rates [NETSIZE_MAX]; int recv_ix = 0; //---------------------------------------- // Send data of increasing sizes. // int j = NETSIZE_MIN; int n_runs = 64; while (!problem && j <= NETSIZE_MAX) { unsigned long chunk_count = 1 << (j-NETSIZE_MIN); unsigned long long amt_to_send = chunk_count; amt_to_send *= NETWORK_CHUNK_SIZE; if (!amt_to_send) // unlikely break; //---------------------------------------- // Send the data; do this n_runs times. // unsigned long long total_duration_send = 0; unsigned long long total_duration_recv = 0; int k = n_runs; while (k--) { long duration_send, duration_recv; if (! network_test_core (hostname, chunk, NETWORK_CHUNK_SIZE, chunk_count, &duration_send, &duration_recv)) { problem = true; fprintf (stderr, "\nCan't connect to %s\n", hostname); break; } total_duration_send += duration_send; total_duration_recv += duration_recv; } if (problem) break; total_duration_send += n_runs/2; // Round up total_duration_send /= n_runs; // Get average long duration = (long) total_duration_send; total_duration_recv += n_runs/2; // Round up total_duration_recv /= n_runs; // Get average unsigned long amt_in_kb = amt_to_send / 1024; unsigned long amt_in_mb = amt_to_send / 1048576; if (!amt_in_mb) { printf ("\r\tChunk %lu kB x %d: \t", amt_in_kb, n_runs); } else { printf ("\r\tChunk %lu MB x %d: \t", amt_in_mb, n_runs); } //------------------------------ // Calculate send rate in MB/sec. // // Get total # bytes. unsigned long long tmp = NETWORK_CHUNK_SIZE; tmp *= chunk_count; // Get total bytes per second. tmp *= 1000000; tmp /= duration; // Bytes to megabytes. tmp /= 1000; tmp /= 10; unsigned long whole = tmp / 100; unsigned long frac = tmp % 100; printf ("%lu.%02lu MB/s (sent)\t", whole, frac); fflush (stdout); dataAddDatum (amt_in_kb, tmp); //------------------------------ // Calculate recv rate in MB/sec. // // Get total # bytes. tmp = NETWORK_CHUNK_SIZE; tmp *= chunk_count; // Get total bytes per second. tmp *= 1000000; tmp /= total_duration_recv; // Bytes to megabytes. tmp /= 1000; tmp /= 10; whole = tmp / 100; frac = tmp % 100; printf ("%lu.%02lu MB/s (received)\n", whole, frac); recv_rates [recv_ix++] = tmp; j++; n_runs >>= 1; if (!n_runs) n_runs = 1; } //---------------------------------------- // Now add the line for the receive rates. // sprintf (title, "%s receive (dashed)", hostname); BMPGraphing_new_line (graph, title, DASHED | (i < NCOLORS? colors[i] : RGB_GRAY)); for (j = NETSIZE_MIN; j <= NETSIZE_MAX; j++) { unsigned long chunk_count = 1 << (j-NETSIZE_MIN); unsigned long long amt_to_send = chunk_count; amt_to_send *= NETWORK_CHUNK_SIZE; unsigned long amt_in_kb = amt_to_send / 1024; // printf ("amt_in_kb=%ld\n",amt_in_kb); dataAddDatum (amt_in_kb, recv_rates[j-NETSIZE_MIN]); } newline (); } return true; } //---------------------------------------------------------------------------- // Name: usage //---------------------------------------------------------------------------- void usage () { printf ("Usage: bandwidth [--slow] [--fast] [--faster] [--fastest] [--limit] [--title string] [--csv file] [--nice]\n"); //printf ("Usage for starting network tests: bandwidth --network []\n"); //printf ("Usage for receiving network tests: bandwidth --transponder [--port ]\n"); exit (0); } //---------------------------------------------------------------------------- // Name: main //---------------------------------------------------------------------------- int bandwidth_main (int argc, char **argv) { int i, chunk_size; outputMode = OUTPUT_MODE_GRAPH; --argc; ++argv; bool network_mode = false; bool network_leader = false; // false => transponder // int network_destinations_size = 0; int n_network_destinations = 0; char **network_destinations = NULL; char graph_title [512] = {0}; i = 0; while (i < argc) { char *s = argv [i++]; #if NETWORK_MODE // unsure if it still works if (!strcmp ("--network", s)) { network_mode = true; network_leader = true; network_destinations_size = 20; network_destinations = (char**) malloc (network_destinations_size * sizeof (char*)); } else if (!strcmp ("--transponder", s)) { network_mode = true; } else if (!strcmp ("--port", s)) { if (i != argc) network_port = atoi (argv[i++]); } else #endif if (!strcmp ("--nice", s)) { nice_mode = true; } else if (!strcmp ("--slow", s)) { usec_per_test=20000000; // 20 seconds per test. } else if (!strcmp ("--limit", s)) { limit_below_100MB= true; } else if (!strcmp ("--fast", s)) { usec_per_test = 500000; // 0.5 seconds per test. } else if (!strcmp ("--faster", s)) { usec_per_test = 50000; // 0.05 seconds per test. } else if (!strcmp ("--fastest", s)) { usec_per_test = 5000; // 0.005 seconds per test. } else if (!strcmp ("--nosse2", s)) { use_sse2 = false; use_sse4 = false; } else if (!strcmp ("--nosse4", s)) { use_sse4 = false; } else if (!strcmp ("--help", s)) { usage (); } else if (!strcmp ("--nograph", s)) { outputMode &= ~OUTPUT_MODE_GRAPH; } else if (!strcmp ("--csv", s) && i != argc) { outputMode |= OUTPUT_MODE_CSV; if (i < argc) csv_file_path = strdup (argv[i++]); else usage (); } else if (!strcmp ("--title", s) && i != argc) { snprintf (graph_title, 511, "%s", argv[i++]); } else { if ('-' == *s) usage (); } } for (i = 0; chunk_sizes[i] && i < sizeof(chunk_sizes)/sizeof(int); i++) { chunk_sizes_log2[i] = log2 (chunk_sizes[i]); } printf ("This is bandwidth version %s.\n", RELEASE); printf ("Copyright (C) 2005-2017 by Zack T Smith.\n\n"); printf ("This software is covered by the GNU Public License.\n"); printf ("It is provided AS-IS, use at your own risk.\n"); printf ("See the file COPYING for more information.\n\n"); fflush (stdout); //---------------------------------------- // If network mode selected, enter it now. // Currently cannot combine memory tests // & network tests. // if (network_mode) { if (network_leader) { graph = BMPGraphing_new (GRAPH_WIDTH, GRAPH_HEIGHT, MODE_X_AXIS_LINEAR); strcpy (graph_title, TITLE_MEMORY_NET); BMPGraphing_set_title (graph, graph_title); network_test (network_destinations, n_network_destinations); BMPGraphing_make (graph); BMP_write (graph->image, "network_bandwidth.bmp"); #if defined(__linux__) || defined(__CYGWIN__) || defined(__APPLE__) puts ("Wrote graph to network_bandwidth.bmp."); newline (); puts ("Done."); #endif BMPGraphing_destroy (graph); } else { network_transponder (); } return 0; } #ifdef x86 uint32_t ecx = get_cpuid1_ecx (); uint32_t edx = get_cpuid1_edx (); cpu_has_mmx = edx & CPUID_EDX_MMX; cpu_has_sse = edx & CPUID_EDX_SSE; cpu_has_sse2 = edx & CPUID_EDX_SSE2; cpu_has_sse3 = ecx & CPUID_ECX_SSE3; cpu_has_ssse3 = ecx & CPUID_ECX_SSSE3; cpu_has_sse41 = ecx & CPUID_ECX_SSE41; cpu_has_sse42 = ecx & CPUID_ECX_SSE42; cpu_has_aes = ecx & CPUID_ECX_AES; cpu_has_avx = ecx & CPUID_ECX_AVX; cpu_has_avx2 = 0; if (cpu_has_avx) { cpu_has_avx2 = get_cpuid7_ebx (); cpu_has_avx2 &= CPUID_EBX_AVX2; } use_sse2 = true; use_sse4 = true; cpu_has_sse4a = 0; cpu_has_64bit = 0; cpu_has_xd = 0; static char family [17]; get_cpuid_family (family); family [16] = 0; printf ("CPU family: %s\n", family); uint32_t ecx2 = get_cpuid_80000001_ecx (); uint32_t edx2 = get_cpuid_80000001_edx (); if (!strcmp ("AuthenticAMD", family)) { is_amd = true; cpu_has_sse4a = ecx2 & CPUID_ECX_SSE4A; } else if (!strcmp ("GenuineIntel", family)) { is_intel = true; } cpu_has_xd = edx2 & CPUID_EDX_XD; cpu_has_64bit = edx2 & CPUID_EDX_INTEL64; printf ("CPU features: "); if (cpu_has_mmx) printf ("MMX "); if (cpu_has_sse) printf ("SSE "); if (cpu_has_sse2) printf ("SSE2 "); if (cpu_has_sse3) printf ("SSE3 "); if (cpu_has_ssse3) printf ("SSSE3 "); if (cpu_has_sse4a) printf ("SSE4A "); if (cpu_has_sse41) printf ("SSE4.1 "); if (cpu_has_sse42) printf ("SSE4.2 "); if (cpu_has_aes) printf ("AES "); if (cpu_has_avx) printf ("AVX "); if (cpu_has_avx2) printf ("AVX2 "); if (cpu_has_xd) printf ("XD "); if (cpu_has_64bit) { if (!is_amd) printf ("Intel64 "); else printf ("LongMode "); } puts ("\n"); if (is_intel) { uint32_t cache_info[4]; i = 0; while (1) { get_cpuid_cache_info (cache_info, i); if (!(cache_info[0] & 31)) break; #if 0 printf ("Cache info %d = 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", i, cache_info [0], cache_info [1], cache_info [2], cache_info [3]); #endif printf ("Cache %d: ", i); switch ((cache_info[0] >> 5) & 7) { case 1: printf ("L1 "); break; case 2: printf ("L2 "); break; case 3: printf ("L3 "); break; } switch (cache_info[0] & 31) { case 1: printf ("data cache, "); break; case 2: printf ("instruction cache, "); break; case 3: printf ("unified cache, "); break; } uint32_t n_ways = 1 + (cache_info[1] >> 22); uint32_t line_size = 1 + (cache_info[1] & 2047); uint32_t n_sets = 1 + cache_info[2]; printf ("line size %d, ", line_size); printf ("%2d-way%s, ", n_ways, n_ways>1 ? "s" : ""); printf ("%5d sets, ", n_sets); unsigned size = (n_ways * line_size * n_sets) >> 10; printf ("size %dk ", size); newline (); i++; } } if (!cpu_has_sse41) use_sse4 = false; if (!cpu_has_sse2) use_sse2 = false; newline (); #endif println ("Notation: B = byte, kB = 1024 B, MB = 1048576 B."); flush (); //------------------------------------------------------------ // Attempt to obtain information about the CPU. // #ifdef __linux__ struct stat st; if (!stat ("/proc/cpuinfo", &st)) { #define TMPFILE "/tmp/bandw_tmp" unlink (TMPFILE); if (-1 == system ("grep MHz /proc/cpuinfo | uniq | sed \"s/[\\t\\n: a-zA-Z]//g\" > "TMPFILE)) perror ("system"); FILE *f = fopen (TMPFILE, "r"); if (f) { float cpu_speed = 0.0; if (1 == fscanf (f, "%g", &cpu_speed)) { newline (); printf ("CPU speed is %g MHz.\n", cpu_speed); } fclose (f); } } else { printf ("CPU information is not available (/proc/cpuinfo).\n"); } fflush (stdout); #endif unsigned long chunk_limit = limit_below_100MB ? 100 << 20 : 1<<31; dataBegins (graph_title); //------------------------------------------------------------ // Sequential non-vector reads. // newline (); #ifdef IS_64BIT dataBeginSection ( "Sequential 64-bit reads", RGB_BLUE); #else dataBeginSection ( "Sequential 32-bit reads", RGB_BLUE); #endif i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, NO_SSE2, false); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // Random non-vector reads. // newline (); #ifdef IS_64BIT dataBeginSection ( "Random 64-bit reads", RGB_CYAN); #else dataBeginSection ( "Random 32-bit reads", RGB_CYAN); #endif srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_read (chunk_size, NO_SSE2, true); dataAddDatum (chunk_size, amount); } } //------------------------------------------------------------ // Sequential non-vector writes. // #ifdef IS_64BIT dataBeginSection ( "Sequential 64-bit writes", RGB_DARKGREEN); #else dataBeginSection ( "Sequential 32-bit writes", RGB_DARKGREEN); #endif newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_write (chunk_size, NO_SSE2, false); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // Random non-vector writes. // #ifdef IS_64BIT dataBeginSection ( "Random 64-bit writes", RGB_GREEN); #else dataBeginSection ( "Random 32-bit writes", RGB_GREEN); #endif newline (); srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_write (chunk_size, NO_SSE2, true); dataAddDatum (chunk_size, amount); } } #ifdef __arm__ //------------------------------------------------------------ // NEON 128 bit sequential reads. // dataBeginSection ("Sequential 128-bit reads", RGB_RED); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, NEON_128BIT, false); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // NEON 128 bit sequential writes. // dataBeginSection ("Sequential 128-bit writes", 0xA04040); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_write (chunk_size, NEON_128BIT, false); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // NEON 64bit random writes. // dataBeginSection ( "Random 64-bit writes", RGB_NAVYBLUE); newline (); srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_write (chunk_size, NEON_64BIT, true); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // NEON 64bit random reads. // dataBeginSection ( "Random 64-bit reads", RGB_MAROON); newline (); srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, NEON_64BIT, true); dataAddDatum (chunk_size, amount); } #endif #ifdef x86 //------------------------------------------------------------ // SSE2 sequential reads. // if (use_sse2) { dataBeginSection ("Sequential 128-bit reads", RGB_RED); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, SSE2, false); dataAddDatum (chunk_size, amount); } } //------------------------------------------------------------ // AVX sequential reads. // if (cpu_has_avx) { dataBeginSection ( "Sequential 256-bit reads", RGB_TURQUOISE); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_read (chunk_size, AVX, false); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // AVX random reads. // #ifdef IS_64BIT if (cpu_has_avx) { dataBeginSection ( "Random 256-bit reads", RGB_BROWN ); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_read (chunk_size, AVX, true); dataAddDatum (chunk_size, amount); } } } #endif //------------------------------------------------------------ // SSE2 random reads. // if (use_sse2) { dataBeginSection ( "Random 128-bit reads", RGB_MAROON); newline (); srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_read (chunk_size, SSE2, true); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // SSE2 sequential writes that do not bypass the caches. // if (use_sse2) { dataBeginSection ( "Sequential 128-bit cache writes", RGB_PURPLE); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_write (chunk_size, SSE2, false); dataAddDatum (chunk_size, amount); } } //------------------------------------------------------------ // AVX sequential writes that do not bypass the caches. // if (cpu_has_avx) { dataBeginSection ( "Sequential 256-bit cache writes", RGB_PINK); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_write (chunk_size, AVX, false); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // AVX randomized writes that do not bypass the caches. // #ifdef IS_64BIT if (cpu_has_avx) { dataBeginSection ( "Random 256-bit cache writes", RGB_RED); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_write (chunk_size, AVX, true); dataAddDatum (chunk_size, amount); } } } #endif //------------------------------------------------------------ // SSE2 random writes that do not bypass the caches. // if (use_sse2) { dataBeginSection ( "Random 128-bit cache writes", RGB_NAVYBLUE); newline (); srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_write (chunk_size, SSE2, true); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // SSE4 sequential reads that do bypass the caches. // if (use_sse4) { dataBeginSection ( "Sequential 128-bit non-temporal reads", 0xA04040); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, SSE2_BYPASS, false); dataAddDatum (chunk_size, amount); } } //------------------------------------------------------------ // SSE4 random reads that do bypass the caches. // if (use_sse4) { dataBeginSection ( "Random 128-bit non-temporal reads", 0x301934 /* dark purple */); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_read (chunk_size, SSE2_BYPASS, true); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // SSE4 sequential writes that do bypass the caches. // if (use_sse4) { dataBeginSection ( "Sequential 128-bit non-temporal writes", RGB_DARKORANGE); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_write (chunk_size, SSE2_BYPASS, false); dataAddDatum (chunk_size, amount); } } //------------------------------------------------------------ // AVX sequential writes that do bypass the caches. // if (cpu_has_avx) { dataBeginSection ( "Sequential 256-bit non-temporal writes", RGB_DARKOLIVEGREEN); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_write (chunk_size, AVX_BYPASS, false); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // SSE4 random writes that bypass the caches. // if (use_sse4) { dataBeginSection ( "Random 128-bit non-temporal writes", RGB_LEMONYELLOW); newline (); srand (time (NULL)); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_write (chunk_size, SSE2_BYPASS, true); dataAddDatum (chunk_size, amount); } } } //------------------------------------------------------------ // SSE2 sequential copy. // if (use_sse2) { dataBeginSection ( "Sequential 128-bit copy", 0x8f8844); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_copy (chunk_size, SSE2); dataAddDatum (chunk_size, amount); } } //------------------------------------------------------------ // AVX sequential copy. // if (cpu_has_avx) { dataBeginSection ( "Sequential 256-bit copy", RGB_CHARTREUSE); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { if (!(chunk_size & 128)) { int amount = do_copy (chunk_size, AVX); dataAddDatum (chunk_size, amount); } } } #ifdef DOING_LODS #ifdef IS_64BIT //------------------------------------------------------------ // LODSQ 64-bit sequential reads. // dataBeginSection ( "Sequential 64-bit LODSQ reads", RGB_GRAY6); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, LODSQ, false); dataAddDatum (chunk_size, amount); } #endif //------------------------------------------------------------ // LODSD 32-bit sequential reads. // dataBeginSection ( "Sequential 32-bit LODSD reads", RGB_GRAY8); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, LODSD, false); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // LODSW 16-bit sequential reads. // dataBeginSection ( "Sequential 16-bit LODSW reads", RGB_GRAY10); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, LODSW, false); dataAddDatum (chunk_size, amount); } //------------------------------------------------------------ // LODSB 64-bit sequential reads. // dataBeginSection ( "Sequential 8-bit LODSB reads", RGB_GRAY12); newline (); i = 0; while ((chunk_size = chunk_sizes [i++]) && chunk_size < chunk_limit) { int amount = do_read (chunk_size, LODSB, false); dataAddDatum (chunk_size, amount); } #endif // lods #endif // x86 //------------------------------------------------------------ // Register to register. // newline (); register_test (); //------------------------------------------------------------ // Stack to/from register. // newline (); stack_test (); #ifndef __arm__ //------------------------------------------------------------ // Register vs stack. // newline (); time_t t0 = mytime (); #ifdef IS_64BIT #define N_INC_OUTER_LOOPS 65537L #define N_INC_INNER_LOOPS 32767L #else #define N_INC_OUTER_LOOPS 9997L #define N_INC_INNER_LOOPS 3337L #endif for (i=0; i 0) { long double d = N_INC_OUTER_LOOPS * 32; d *= N_INC_INNER_LOOPS; d /= diff; d *= 1000000; // usec->sec d /= 1000000000; // billions/sec #ifdef IS_64BIT printf ("64-bit register increments per second: %.2Lf billion\n", d); #else printf ("32-bit register increments per second: %.2Lf billion\n", d); #endif } t0 = mytime (); for (i=0; i < N_INC_INNER_LOOPS; i++) { IncrementStack (N_INC_INNER_LOOPS); } diff = mytime () - t0; if (diff > 0) { long double d = N_INC_OUTER_LOOPS * 32; d *= N_INC_INNER_LOOPS; d /= diff; d *= 1000000; // usec->sec d /= 1000000000; // billions/sec #ifdef IS_64BIT printf ("64-bit stack value increments per second: %.2Lf billion\n", d); #else printf ("32-bit stack value increments per second: %.2Lf billion\n", d); #endif } #endif //------------------------------------------------------------ // C library performance. // newline (); library_test (); //------------------------------------------------------------ // Framebuffer read & write. // #if defined(__linux__) && defined(FBIOGET_FSCREENINFO) newline (); fb_readwrite (true); #endif flush (); newline (); dataEnds ("bandwidth.bmp"); newline (); puts ("Done."); return 0; } int bandwidth_cpux(void *p_data) { int i, chunk_size; outputMode = OUTPUT_MODE_GRAPH; usec_per_test = 5000; char graph_title [512] = {0}; /* Needed by CPU-X */ int count = 0; uint8_t cache_level = 0; double total_amount = 0; Labels *data = p_data; BandwidthData *w_data = data->w_data; for (i = 0; chunk_sizes[i] && i < sizeof(chunk_sizes)/sizeof(int); i++) { chunk_sizes_log2[i] = log2 (chunk_sizes[i]); } uint32_t ecx = get_cpuid1_ecx (); uint32_t edx = get_cpuid1_edx (); uint32_t ecx2 = get_cpuid_80000001_ecx (); uint32_t edx2 = get_cpuid_80000001_edx (); cpu_has_mmx = edx & CPUID_EDX_MMX; cpu_has_sse = edx & CPUID_EDX_SSE; cpu_has_sse2 = edx & CPUID_EDX_SSE2; cpu_has_sse3 = ecx & CPUID_ECX_SSE3; cpu_has_ssse3 = ecx & CPUID_ECX_SSSE3; cpu_has_sse41 = ecx & CPUID_ECX_SSE41; cpu_has_sse42 = ecx & CPUID_ECX_SSE42; cpu_has_aes = ecx & CPUID_ECX_AES; cpu_has_avx = ecx & CPUID_ECX_AVX; cpu_has_avx2 = 0; cpu_has_xd = edx2 & CPUID_EDX_XD; cpu_has_64bit = edx2 & CPUID_EDX_INTEL64; cpu_has_sse4a = 0; if (cpu_has_avx) { cpu_has_avx2 = get_cpuid7_ebx (); cpu_has_avx2 &= CPUID_EBX_AVX2; } /* Needed by CPU-X */ if (!cpu_has_sse41) use_sse4 = false; if (!cpu_has_sse2) use_sse2 = false; const struct Tests tests[] = { /* Test Name Color Flag Mask Func Mode Rand */ { SEQ_128_R, "Sequential 128-bit reads", RGB_RED, use_sse2, false, do_read, SSE2, false }, { SEQ_256_R, "Sequential 256-bit reads", RGB_TURQUOISE, cpu_has_avx, true, do_read, AVX, false }, { RAND_128_R, "Random 128-bit reads", RGB_MAROON, use_sse2, true, do_read, SSE2, true }, { SEQ_128_CACHE_W, "Sequential 128-bit cache writes", RGB_PURPLE, use_sse2, false, do_write, SSE2, false }, { SEQ_256_CACHE_W, "Sequential 256-bit cache writes", RGB_PINK, cpu_has_avx, true, do_write, AVX, false }, { RAND_128_CACHE_W, "Random 128-bit cache writes", RGB_NAVYBLUE, use_sse2, true, do_write, SSE2, true }, { SEQ_128_BYPASS_R, "Sequential 128-bit non-temporal reads", 0xA04040, use_sse4, false, do_read, SSE2_BYPASS, false }, { RAND_128_BYPASS_R, "Random 128-bit non-temporal reads", 0x301934, use_sse4, true, do_read, SSE2_BYPASS, true }, { SEQ_128_BYPASS_W, "Sequential 128-bit non-temporal writes", RGB_DARKORANGE, use_sse4, false, do_write, SSE2_BYPASS, false }, { SEQ_256_BYPASS_W, "Sequential 256-bit non-temporal writes", RGB_DARKOLIVEGREEN, cpu_has_avx, true, do_write, AVX_BYPASS, false }, { RAND_128_BYPASS_W, "Random 128-bit non-temporal writes", RGB_LEMONYELLOW, use_sse4, true, do_write, SSE2_BYPASS, true }, { SEQ_128_C, "Sequential 128-bit copy", 0x8f8844, use_sse2, false, do_copy2, SSE2, false }, { SEQ_256_C, "Sequential 256-bit copy", RGB_CHARTREUSE, cpu_has_avx, true, do_copy2, AVX, false }, { SEQ_32_LR, "Sequential 32-bit LODSD reads", RGB_GRAY8, true, false, do_read, LODSD, false }, { SEQ_16_LR, "Sequential 16-bit LODSW reads", RGB_GRAY10, true, false, do_read, LODSW, false }, { SEQ_8_LR, "Sequential 8-bit LODSB reads", RGB_GRAY12, true, false, do_read, LODSB, false }, #ifdef __x86_64__ { SEQ_64_LR, "Sequential 64-bit LODSQ reads", RGB_GRAY6, true, false, do_read, LODSQ, false }, { SEQ_64_R, "Sequential 64-bit reads", RGB_BLUE, true, false, do_read, NO_SSE2, false }, { RAND_64_R, "Random 64-bit reads", RGB_CYAN, true, true, do_read, NO_SSE2, true }, { SEQ_64_W, "Sequential 64-bit writes", RGB_DARKGREEN, true, false, do_write, NO_SSE2, false }, { RAND_64_W, "Random 64-bit writes", RGB_GREEN, true, true, do_write, NO_SSE2, true }, { RAND_256_R, "Random 256-bit reads", RGB_BROWN, cpu_has_avx, true, do_read, AVX, true }, { RAND_256_W, "Random 256-bit cache writes", RGB_RED, cpu_has_avx, true, do_write, AVX, true }, #else { SEQ_32_R, "Sequential 32-bit reads", RGB_BLUE, true, false, do_read, NO_SSE2, false }, { RAND_32_R, "Random 32-bit reads", RGB_CYAN, true, true, do_read, NO_SSE2, true }, { SEQ_32_W, "Sequential 32-bit writes", RGB_DARKGREEN, true, false, do_write, NO_SSE2, false }, { RAND_32_W, "Random 32-bit writes", RGB_GREEN, true, true, do_write, NO_SSE2, true }, #endif { -1, NULL, 0x0, false, false, NULL, 0, false } }; #if HAS_LIBCPUID /* Fast initialization by using libcpuid */ switch(data->l_data->cpu_vendor_id) { case VENDOR_INTEL: is_intel = true; goto end_initialization; case VENDOR_AMD: is_amd = true; cpu_has_sse4a = ecx2 & CPUID_ECX_SSE4A; goto end_initialization; default: break; } #endif /* HAS_LIBCPUID */ static char family [17]; get_cpuid_family (family); family [16] = 0; printf ("CPU family: %s\n", family); if (!strcmp ("AuthenticAMD", family)) { is_amd = true; cpu_has_sse4a = ecx2 & CPUID_ECX_SSE4A; } else if (!strcmp ("GenuineIntel", family)) { is_intel = true; } printf ("CPU features: "); if (cpu_has_mmx) printf ("MMX "); if (cpu_has_sse) printf ("SSE "); if (cpu_has_sse2) printf ("SSE2 "); if (cpu_has_sse3) printf ("SSE3 "); if (cpu_has_ssse3) printf ("SSSE3 "); if (cpu_has_sse4a) printf ("SSE4A "); if (cpu_has_sse41) printf ("SSE4.1 "); if (cpu_has_sse42) printf ("SSE4.2 "); if (cpu_has_aes) printf ("AES "); if (cpu_has_avx) printf ("AVX "); if (cpu_has_avx2) printf ("AVX2 "); if (cpu_has_xd) printf ("XD "); if (cpu_has_64bit) { if (!is_amd) printf ("Intel64 "); else printf ("LongMode "); } puts ("\n"); if (is_intel) { uint32_t cache_info[4]; i = 0; while (1) { get_cpuid_cache_info (cache_info, i); if (!(cache_info[0] & 31)) break; #if 0 printf ("Cache info %d = 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", i, cache_info [0], cache_info [1], cache_info [2], cache_info [3]); #endif printf ("Cache %d: ", i); switch ((cache_info[0] >> 5) & 7) { case 1: printf ("L1 "); break; case 2: printf ("L2 "); break; case 3: printf ("L3 "); break; } switch (cache_info[0] & 31) { case 1: printf ("data cache, "); break; case 2: printf ("instruction cache, "); break; case 3: printf ("unified cache, "); break; } uint32_t n_ways = 1 + (cache_info[1] >> 22); uint32_t line_size = 1 + (cache_info[1] & 2047); uint32_t n_sets = 1 + cache_info[2]; printf ("line size %d, ", line_size); printf ("%2d-way%s, ", n_ways, n_ways>1 ? "s" : ""); printf ("%5d sets, ", n_sets); unsigned size = (n_ways * line_size * n_sets) >> 10; printf ("size %dk ", size); newline (); i++; } } newline (); println ("Notation: B = byte, kB = 1024 B, MB = 1048576 B."); flush (); //------------------------------------------------------------ // Attempt to obtain information about the CPU. // #ifdef __linux__ struct stat st; if (!stat ("/proc/cpuinfo", &st)) { #define TMPFILE "/tmp/bandw_tmp" unlink (TMPFILE); if (-1 == system ("grep MHz /proc/cpuinfo | uniq | sed \"s/[\\t\\n: a-zA-Z]//g\" > "TMPFILE)) perror ("system"); FILE *f = fopen (TMPFILE, "r"); if (f) { float cpu_speed = 0.0; if (1 == fscanf (f, "%g", &cpu_speed)) { newline (); printf ("CPU speed is %g MHz.\n", cpu_speed); } fclose (f); } } else { printf ("CPU information is not available (/proc/cpuinfo).\n"); } fflush (stdout); #endif dataBegins (graph_title); #if HAS_LIBCPUID end_initialization: #endif /* HAS_LIBCPUID */ /* Check if selectionned test is valid */ if(opts->bw_test >= LASTTEST) opts->bw_test = 0; /* Set test names */ if(w_data->test_count == 0) { w_data->test_name = malloc(LASTTEST * sizeof(char *)); w_data->test_count = (w_data->test_name == NULL) ? 0 : LASTTEST; for(i = 0; i < w_data->test_count; i++) { w_data->test_name[i] = NULL; casprintf(&w_data->test_name[i], false, "#%2i: %s", i, tests[i].name); } } if(tests[opts->bw_test].need_flag) { if(tests[opts->bw_test].random) srand(time (NULL)); i = 0; while((chunk_size = chunk_sizes [i++])) { if(!tests[opts->bw_test].need_mask || (tests[opts->bw_test].need_mask && !(chunk_size & 128))) { if(chunk_size > w_data->size[cache_level] * 1024) { w_data->speed[cache_level] = total_amount / count; count = 0; total_amount = 0; cache_level++; if(cache_level >= data->cache_count || w_data->size[cache_level] < 1) return 0; } int amount = (*tests[opts->bw_test].func_ptr)(chunk_size, tests[opts->bw_test].mode, tests[opts->bw_test].random); total_amount += amount; count++; } } } else { for(i = 0; i < LASTCACHES / CACHEFIELDS; i++) w_data->speed[i] = 0; return 1; } return 0; } CPU-X-3.2.4/src/bandwidth/minifont.c000066400000000000000000000155561341671471500171230ustar00rootroot00000000000000 /*============================================================================= bmplib, a simple library to create, modify, and write BMP image files. Copyright (C) 2009-2014 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *============================================================================*/ #include #include "BMP.h" // Mini characters, 8 pixels high. static const char *mini_chars_ [] = { "#", "#", "#", "#", "#", " ", "#", "", "## ##", " # #", "# #", " ", " ", " ", " ", "", " # # ", " # # ", "#####", " # # ", "#####", " # # ", " # # ", "", " # ", " ####", "# # ", " ### ", " # #", "####", " # ", "", "## #", " #", " #", " #", " #", "#", "# ##", "", " # ", "# # ", "## ", " ## #", "# ## ", "# # ", " ## #", "", "##", " #", "#", "", "", "", "", "", " #", "#", "#", "#", "#", "#", "#", " #", "# ", " #", " #", " #", " #", " #", " #", "#", " ", "# # #", " ###", " #", " ###", "# # #", "", "", " ", " #", " #", "#####", " #", " #", "", "", " ", "", "", "", "", "##", " #", "#", " ", "", "", "#####", "", "", "", "", " ", "", "", "", "", "", "#", "", " #", " #", " #", " #", " #", "#", "#", "", " ## ", "# #", "# #", "# #", "# #", "# #", " ## ", "", " #", "##", " #", " #", " #", " #", " #", "", " ## ", "# #", " #", " ###", "# ", "# ", "####", "", "####", " #", " # ", " ## ", " #", "# #", " ## ", "", "# # ", "# #", "# #", "####", " #", " #", " #", "", "####", "# ", "### ", " #", " #", "# #", " ## ", "", " ## ", "# ", "# ", "### ", "# #", "# #", " ## ", "", "####", " #", " #", " # ", " # ", " # ", " # ", "", " ## ", "# #", "# #", " ## ", "# #", "# #", " ## ", "", " ## ", "# #", "# #", " ###", " #", " # ", " # ", "", " ", "", "", "#", "", "#", "", "", " ", "", " ", "##", " ", "##", " #", "#", " #", " #", " #", "#", " #", " #", " #", "", " ", "", "", "#####", " ", "#####", "", "", "# ", " #", " #", " #", " #", " #", "#", "", " ### ", "# #", " #", " ## ", " #", "", " #", "", " ### ", "# #", "# ##", "# # #", "# ##", "# ", " ###", "", " # ", " # # ", "# #", "# #", "#####", "# #", "# #", "", "### ", "# #", "# #", "### ", "# #", "# #", "###", "", " ### ", "# #", "# ", "# ", "# ", "# #", " ###", "", "#### ", "# #", "# #", "# #", "# #", "# #", "####", "", "#####", "#", "#", "###", "#", "#", "#####", "", "#####", "# ", "# ", "###", "# ", "# ", "#", "", " ### ", "# #", "# ", "# ##", "# #", "# #", " ####", "", "# #", "# #", "# #", "#####", "# #", "# #", "# #", "", "###", " #", " #", " #", " #", " #", "###", "", " ###", " #", " #", " #", " #", "# #", " ##", "", "# #", "# #", "# #", "##", "# #", "# #", "# #", "", "# ", "#", "#", "#", "#", "#", "#####", "", "# #", "## ##", "# # #", "# #", "# #", "# #", "# #", "", "# #", "## #", "# # #", "# ##", "# #", "# #", "# #", "", " ### ", "# #", "# #", "# #", "# #", "# #", " ###", "", "#### ", "# #", "# #", "#### ", "# ", "# ", "# ", "", " ### ", "# #", "# #", "# #", "# # #", "# # ", " ## #", "", "#### ", "# #", "# #", "#### ", "# # ", "# # ", "# #", "", " ### ", "# #", "# ", " ### ", " #", "# #", " ###", "", "#####", " #", " #", " #", " #", " #", " #", "", "# #", "# #", "# #", "# #", "# #", "# #", " ###", "", "# #", "# #", "# #", "# #", "# #", " # # ", " #", "", "# #", "# #", "# #", "# # #", "# # #", "## ##", "# #", "", "# #", "# #", " # #", " #", " # #", "# #", "# #", "", "# #", "# #", "# #", " # #", " #", " #", " #", "", "#####", " #", " #", " #", " #", "#", "#####", "", "##", "#", "#", "#", "#", "#", "#", "##", "#", "#", " #", " #", " #", " #", " #", "", "##", " #", " #", " #", " #", " #", " #", "##", " # ", " # #", "# #", "", "", "", "", "", " ", "", "", "", "", "", "", "####", "##", "#", " #", "", "", "", "", "", " ", " ", " ## ", " #", " ###", "# #", " ###", "", "# ", "# ", "### ", "# #", "# #", "# #", "### ", "", " ", " ", " ###", "# ", "# ", "# ", " ###", "", " #", " #", " ###", "# #", "# #", "# #", " ###", "", " ", " ", " ## ", "# #", "####", "# ", " ###", "", " ##", " # ", "### ", " # ", " # ", " # ", "### ", "", " ", " ", " ###", "# #", "# #", " ###", " #", "### ", "# ", "# ", "### ", "# #", "# #", "# #", "# #", "", " # ", " ", "## ", " # ", " # ", " # ", "###", "", " #", " ", " ##", " #", " #", " #", " #", "## ", "# ", "# ", "# #", "# # ", "## ", "# # ", "# #", "", "## ", " # ", " # ", " # ", " # ", " # ", "###", "", " ", "", "####", "# # #", "# # #", "# # #", "# # #", "", " ", " ", "###", "# #", "# #", "# #", "# #", "", " ", " ", " ## ", "# #", "# #", "# #", " ## ", "", " ", "", "###", "# #", "# #", "###", "#", "#", " ", "", " ###", "# #", "# #", " ###", " #", " # ", " ", " ", "# ##", "## ", "# ", "# ", "# ", "", " ", " ", " ###", "# ", " ##", " #", "### ", "", " # ", " #", "###", " #", " #", " #", " ##", "", " ", "", "# #", "# #", "# #", "# #", " ###", "", " ", "", "# #", "# #", "# #", " # #", " #", "", " ", "", "# # #", "# # #", "# # #", "# # #", " # #", "", " ", "", "# #", " # #", " #", " # #", "# #", "", " ", " ", "# #", "# #", "# #", " ###", " #", "### ", " ", "", "#####", " #", " #", " # ", "#####", "", }; const char **get_minifont_chars () { return mini_chars_; } CPU-X-3.2.4/src/bandwidth/minifont.h000066400000000000000000000020421341671471500171120ustar00rootroot00000000000000 /*============================================================================= bmplib, a simple library to create, modify, and write BMP image files. Copyright (C) 2009-2014 by Zack T Smith. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA The author may be reached at 1@zsmith.co. *============================================================================*/ #ifndef _MINIFONT_H #define _MINIFONT_H extern const char **get_minifont_chars (void); #endif CPU-X-3.2.4/src/bandwidth/routines-x86-32bit.asm000066400000000000000000001654511341671471500210520ustar00rootroot00000000000000;============================================================================ ; bandwidth, a benchmark to estimate memory transfer bandwidth. ; Copyright (C) 2005-2015 by Zack T Smith. ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ; ; The author may be reached at veritas@comcast.net. ;============================================================================= bits 32 cpu ia64 global IncrementRegisters global _IncrementRegisters global IncrementStack global _IncrementStack global ReaderLODSQ global _ReaderLODSQ global ReaderLODSD global _ReaderLODSD global ReaderLODSW global _ReaderLODSW global ReaderLODSB global _ReaderLODSB ; Cygwin requires the underbar-prefixed symbols. global _WriterSSE2 global WriterSSE2 global _WriterAVX global WriterAVX global _WriterSSE2_128bytes global WriterSSE2_128bytes global _ReaderAVX global ReaderAVX global _ReaderSSE2 global ReaderSSE2 global ReaderSSE2_bypass global _ReaderSSE2_bypass global _ReaderSSE2_128bytes global ReaderSSE2_128bytes global ReaderSSE2_128bytes_bypass global _ReaderSSE2_128bytes_bypass global _RandomReaderSSE2 global RandomReaderSSE2 global _RandomReaderSSE2_bypass global RandomReaderSSE2_bypass global WriterAVX_bypass global _WriterAVX_bypass global _WriterSSE2_bypass global WriterSSE2_bypass global _WriterSSE2_128bytes_bypass global WriterSSE2_128bytes_bypass global _RandomWriterSSE2_bypass global RandomWriterSSE2_bypass global Reader global _Reader global Writer global _Writer global Reader_128bytes global _Reader_128bytes global Writer_128bytes global _Writer_128bytes global RandomReader global _RandomReader global RandomWriter global _RandomWriter global RandomWriterSSE2 global _RandomWriterSSE2 global get_cpuid_family global _get_cpuid_family global get_cpuid_cache_info global _get_cpuid_cache_info global get_cpuid1_ecx global _get_cpuid1_ecx global get_cpuid1_edx global _get_cpuid1_edx global get_cpuid7_ebx global _get_cpuid7_ebx global get_cpuid_80000001_ecx global _get_cpuid_80000001_ecx global get_cpuid_80000001_edx global _get_cpuid_80000001_edx global CopySSE global _CopySSE global CopyAVX global _CopyAVX global CopySSE_128bytes global _CopySSE_128bytes global RegisterToRegister global _RegisterToRegister global VectorToVector global _VectorToVector global VectorToVectorAVX global _VectorToVectorAVX global RegisterToVector global _RegisterToVector global VectorToRegister global _VectorToRegister global Register8ToVector global Register16ToVector global Register32ToVector global Register64ToVector global Vector8ToRegister global Vector16ToRegister global Vector32ToRegister global Vector64ToRegister global _Register8ToVector global _Register16ToVector global _Register32ToVector global _Register64ToVector global _Vector8ToRegister global _Vector16ToRegister global _Vector32ToRegister global _Vector64ToRegister global StackReader global _StackReader global StackWriter global _StackWriter section .text ;------------------------------------------------------------------------------ ; Name: ReaderLODSQ ; Purpose: Reads 64-bit values sequentially from an area of memory ; using LODSQ instruction. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSQ: _ReaderLODSQ: ; N/A ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSD ; Purpose: Reads 32-bit values sequentially from an area of memory ; using LODSD instruction. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSD: _ReaderLODSD: shr dword [esp+8], 2 ; length in double words rounded down. push ebx push ecx ; REP counter push edx mov edx, [esp+12+12] .L1: mov esi, [esp+4+12] mov ecx, [esp+8+12] rep lodsd dec edx jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSW ; Purpose: Reads 16-bit values sequentially from an area of memory ; using LODSW instruction. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSW: _ReaderLODSW: shr dword [esp+8], 1 ; length in words rounded down. push ebx push ecx ; REP counter push edx mov edx, [esp+12+12] .L1: mov esi, [esp+4+12] mov ecx, [esp+8+12] rep lodsw dec edx jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSB ; Purpose: Reads 8-bit values sequentially from an area of memory ; using LODSB instruction. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSB: _ReaderLODSB: push ebx push ecx ; REP counter push edx mov edx, [esp+12+12] .L1: mov esi, [esp+4+12] mov ecx, [esp+8+12] rep lodsb dec edx jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: Reader ; Purpose: Reads 32-bit values sequentially from an area of memory. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 Reader: _Reader: push ebx push ecx push edx mov ecx, [esp+12+12] ; loops to do. mov edx, [esp+4+12] ; ptr to memory chunk. mov ebx, edx ; ebx = limit in memory add ebx, [esp+8+12] .L1: mov edx, [esp+4+12] .L2: mov eax, [edx] mov eax, [4+edx] mov eax, [8+edx] mov eax, [12+edx] mov eax, [16+edx] mov eax, [20+edx] mov eax, [24+edx] mov eax, [28+edx] mov eax, [32+edx] mov eax, [36+edx] mov eax, [40+edx] mov eax, [44+edx] mov eax, [48+edx] mov eax, [52+edx] mov eax, [56+edx] mov eax, [60+edx] mov eax, [64+edx] mov eax, [68+edx] mov eax, [72+edx] mov eax, [76+edx] mov eax, [80+edx] mov eax, [84+edx] mov eax, [88+edx] mov eax, [92+edx] mov eax, [96+edx] mov eax, [100+edx] mov eax, [104+edx] mov eax, [108+edx] mov eax, [112+edx] mov eax, [116+edx] mov eax, [120+edx] mov eax, [124+edx] mov eax, [edx+128] mov eax, [edx+132] mov eax, [edx+136] mov eax, [edx+140] mov eax, [edx+144] mov eax, [edx+148] mov eax, [edx+152] mov eax, [edx+156] mov eax, [edx+160] mov eax, [edx+164] mov eax, [edx+168] mov eax, [edx+172] mov eax, [edx+176] mov eax, [edx+180] mov eax, [edx+184] mov eax, [edx+188] mov eax, [edx+192] mov eax, [edx+196] mov eax, [edx+200] mov eax, [edx+204] mov eax, [edx+208] mov eax, [edx+212] mov eax, [edx+216] mov eax, [edx+220] mov eax, [edx+224] mov eax, [edx+228] mov eax, [edx+232] mov eax, [edx+236] mov eax, [edx+240] mov eax, [edx+244] mov eax, [edx+248] mov eax, [edx+252] add edx, 256 cmp edx, ebx jb .L2 sub ecx, 1 jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: Writer ; Purpose: Writes 32-bit value sequentially to an area of memory. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = long to write ;------------------------------------------------------------------------------ align 64 Writer: _Writer: push ebx push ecx push edx mov ecx, [esp+12+12] mov eax, [esp+16+12] mov edx, [esp+4+12] ; edx = ptr to chunk mov ebx, edx add ebx, [esp+8+12] ; ebx = limit in memory .L1: mov edx, [esp+4+12] .L2: mov [edx], eax mov [4+edx], eax mov [8+edx], eax mov [12+edx], eax mov [16+edx], eax mov [20+edx], eax mov [24+edx], eax mov [28+edx], eax mov [32+edx], eax mov [36+edx], eax mov [40+edx], eax mov [44+edx], eax mov [48+edx], eax mov [52+edx], eax mov [56+edx], eax mov [60+edx], eax mov [64+edx], eax mov [68+edx], eax mov [72+edx], eax mov [76+edx], eax mov [80+edx], eax mov [84+edx], eax mov [88+edx], eax mov [92+edx], eax mov [96+edx], eax mov [100+edx], eax mov [104+edx], eax mov [108+edx], eax mov [112+edx], eax mov [116+edx], eax mov [120+edx], eax mov [124+edx], eax mov [edx+128], eax mov [edx+132], eax mov [edx+136], eax mov [edx+140], eax mov [edx+144], eax mov [edx+148], eax mov [edx+152], eax mov [edx+156], eax mov [edx+160], eax mov [edx+164], eax mov [edx+168], eax mov [edx+172], eax mov [edx+176], eax mov [edx+180], eax mov [edx+184], eax mov [edx+188], eax mov [edx+192], eax mov [edx+196], eax mov [edx+200], eax mov [edx+204], eax mov [edx+208], eax mov [edx+212], eax mov [edx+216], eax mov [edx+220], eax mov [edx+224], eax mov [edx+228], eax mov [edx+232], eax mov [edx+236], eax mov [edx+240], eax mov [edx+244], eax mov [edx+248], eax mov [edx+252], eax add edx, 256 cmp edx, ebx jb .L2 sub ecx, 1 jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: Reader_128bytes ; Purpose: Reads 32-bit values sequentially from an area of memory. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 Reader_128bytes: _Reader_128bytes: push ebx push ecx push edx mov ecx, [esp+12+12] ; loops to do. mov edx, [esp+4+12] ; ptr to memory chunk. mov ebx, edx ; ebx = limit in memory add ebx, [esp+8+12] .L1: mov edx, [esp+4+12] .L2: mov eax, [edx] mov eax, [4+edx] mov eax, [8+edx] mov eax, [12+edx] mov eax, [16+edx] mov eax, [20+edx] mov eax, [24+edx] mov eax, [28+edx] mov eax, [32+edx] mov eax, [36+edx] mov eax, [40+edx] mov eax, [44+edx] mov eax, [48+edx] mov eax, [52+edx] mov eax, [56+edx] mov eax, [60+edx] mov eax, [64+edx] mov eax, [68+edx] mov eax, [72+edx] mov eax, [76+edx] mov eax, [80+edx] mov eax, [84+edx] mov eax, [88+edx] mov eax, [92+edx] mov eax, [96+edx] mov eax, [100+edx] mov eax, [104+edx] mov eax, [108+edx] mov eax, [112+edx] mov eax, [116+edx] mov eax, [120+edx] mov eax, [124+edx] add edx, 128 cmp edx, ebx jb .L2 sub ecx, 1 jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: Writer_128bytes ; Purpose: Writes 32-bit value sequentially to an area of memory. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = long to write ;------------------------------------------------------------------------------ align 64 Writer_128bytes: _Writer_128bytes: push ebx push ecx push edx mov ecx, [esp+12+12] mov eax, [esp+16+12] mov edx, [esp+4+12] ; edx = ptr to chunk mov ebx, edx add ebx, [esp+8+12] ; ebx = limit in memory .L1: mov edx, [esp+4+12] .L2: mov [edx], eax mov [4+edx], eax mov [8+edx], eax mov [12+edx], eax mov [16+edx], eax mov [20+edx], eax mov [24+edx], eax mov [28+edx], eax mov [32+edx], eax mov [36+edx], eax mov [40+edx], eax mov [44+edx], eax mov [48+edx], eax mov [52+edx], eax mov [56+edx], eax mov [60+edx], eax mov [64+edx], eax mov [68+edx], eax mov [72+edx], eax mov [76+edx], eax mov [80+edx], eax mov [84+edx], eax mov [88+edx], eax mov [92+edx], eax mov [96+edx], eax mov [100+edx], eax mov [104+edx], eax mov [108+edx], eax mov [112+edx], eax mov [116+edx], eax mov [120+edx], eax mov [124+edx], eax add edx, 128 cmp edx, ebx jb .L2 sub ecx, 1 jnz .L1 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_cache_info ; get_cpuid_cache_info: _get_cpuid_cache_info: push ebp push ebx push ecx push edx mov eax, 4 mov ecx, [esp + 16 + 4 + 4] cpuid mov ebp, eax mov eax, [esp + 16 + 4] mov [eax], ebp mov [eax+4], ebx mov [eax+8], ecx mov [eax+12], edx pop edx pop ecx pop ebx pop ebp ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_family ; get_cpuid_family: _get_cpuid_family: push ebx push ecx push edx xor eax, eax cpuid mov eax, [esp + 12 + 4] mov [eax], ebx mov [eax+4], edx mov [eax+8], ecx mov byte [eax+12], 0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid1_ecx ; get_cpuid1_ecx: _get_cpuid1_ecx: push ebx push ecx push edx mov eax, 1 cpuid mov eax, ecx pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid7_ebx ; get_cpuid7_ebx: _get_cpuid7_ebx: push ebx push ecx push edx mov eax, 7 xor ecx, ecx cpuid mov eax, ebx pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_80000001_ecx ; get_cpuid_80000001_ecx: _get_cpuid_80000001_ecx: push ebx push ecx push edx mov eax, 0x80000001 cpuid mov eax, ecx pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_80000001_edx ; get_cpuid_80000001_edx: _get_cpuid_80000001_edx: push ebx push ecx push edx mov eax, 0x80000001 cpuid mov eax, edx pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid1_edx ; get_cpuid1_edx: _get_cpuid1_edx: push ebx push ecx push edx mov eax, 1 cpuid mov eax, edx pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderAVX ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 ReaderAVX: _ReaderAVX: vzeroupper push ebx push ecx mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: vmovdqa ymm0, [eax] ; Read aligned @ 16-byte boundary. vmovdqa ymm0, [32+eax] vmovdqa ymm0, [64+eax] vmovdqa ymm0, [96+eax] vmovdqa ymm0, [128+eax] vmovdqa ymm0, [160+eax] vmovdqa ymm0, [192+eax] vmovdqa ymm0, [224+eax] add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2 ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2: _ReaderSSE2: push ebx push ecx mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: movdqa xmm0, [eax] ; Read aligned @ 16-byte boundary. movdqa xmm0, [16+eax] movdqa xmm0, [32+eax] movdqa xmm0, [48+eax] movdqa xmm0, [64+eax] movdqa xmm0, [80+eax] movdqa xmm0, [96+eax] movdqa xmm0, [112+eax] movdqa xmm0, [128+eax] movdqa xmm0, [144+eax] movdqa xmm0, [160+eax] movdqa xmm0, [176+eax] movdqa xmm0, [192+eax] movdqa xmm0, [208+eax] movdqa xmm0, [224+eax] movdqa xmm0, [240+eax] add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2_bypass ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2_bypass: _ReaderSSE2_bypass: push ebx push ecx mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: prefetchnta [eax] movntdqa xmm0, [eax] ; Read aligned @ 16-byte boundary. movntdqa xmm0, [16+eax] movntdqa xmm0, [32+eax] movntdqa xmm0, [48+eax] prefetchnta [eax+64] movntdqa xmm0, [64+eax] movntdqa xmm0, [80+eax] movntdqa xmm0, [96+eax] movntdqa xmm0, [112+eax] prefetchnta [eax+128] movntdqa xmm0, [128+eax] movntdqa xmm0, [144+eax] movntdqa xmm0, [160+eax] movntdqa xmm0, [176+eax] prefetchnta [eax+192] movntdqa xmm0, [192+eax] movntdqa xmm0, [208+eax] movntdqa xmm0, [224+eax] movntdqa xmm0, [240+eax] add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2_128bytes_bypass ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2_128bytes_bypass: _ReaderSSE2_128bytes_bypass: push ebx push ecx mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: prefetchnta [eax] movntdqa xmm0, [eax] ; Read aligned @ 16-byte boundary. movntdqa xmm0, [16+eax] movntdqa xmm0, [32+eax] movntdqa xmm0, [48+eax] prefetchnta [eax+64] movntdqa xmm0, [64+eax] movntdqa xmm0, [80+eax] movntdqa xmm0, [96+eax] movntdqa xmm0, [112+eax] add eax, 128 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2_128bytes ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2_128bytes: _ReaderSSE2_128bytes: push ebx push ecx mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: movdqa xmm0, [eax] ; Read aligned @ 16-byte boundary. movdqa xmm0, [16+eax] movdqa xmm0, [32+eax] movdqa xmm0, [48+eax] movdqa xmm0, [64+eax] movdqa xmm0, [80+eax] movdqa xmm0, [96+eax] movdqa xmm0, [112+eax] add eax, 128 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: WriterAVX ; Purpose: Write 256-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = value (ignored) ;------------------------------------------------------------------------------ align 64 WriterAVX: _WriterAVX: vzeroupper push ebx push ecx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: vmovdqa [eax], ymm0 vmovdqa [32+eax], ymm0 vmovdqa [64+eax], ymm0 vmovdqa [96+eax], ymm0 vmovdqa [128+eax], ymm0 vmovdqa [160+eax], ymm0 vmovdqa [192+eax], ymm0 vmovdqa [224+eax], ymm0 add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2 ; Purpose: Write 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = value (ignored) ;------------------------------------------------------------------------------ align 64 WriterSSE2: _WriterSSE2: push ebx push ecx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: movdqa [eax], xmm0 movdqa [16+eax], xmm0 movdqa [32+eax], xmm0 movdqa [48+eax], xmm0 movdqa [64+eax], xmm0 movdqa [80+eax], xmm0 movdqa [96+eax], xmm0 movdqa [112+eax], xmm0 movdqa [128+eax], xmm0 movdqa [144+eax], xmm0 movdqa [160+eax], xmm0 movdqa [176+eax], xmm0 movdqa [192+eax], xmm0 movdqa [208+eax], xmm0 movdqa [224+eax], xmm0 movdqa [240+eax], xmm0 add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2 ; Purpose: Write 128-bit values sequentially from an area of memory. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = value (ignored) ;------------------------------------------------------------------------------ align 64 WriterSSE2_128bytes: _WriterSSE2_128bytes: push ebx push ecx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: movdqa [eax], xmm0 movdqa [16+eax], xmm0 movdqa [32+eax], xmm0 movdqa [48+eax], xmm0 movdqa [64+eax], xmm0 movdqa [80+eax], xmm0 movdqa [96+eax], xmm0 movdqa [112+eax], xmm0 add eax, 128 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: WriterAVX_bypass ; Purpose: Write 256-bit values sequentially from an area of memory, ; bypassing the cache. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = value (ignored) ;------------------------------------------------------------------------------ align 64 WriterAVX_bypass: _WriterAVX_bypass: vzeroupper push ebx push ecx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: vmovntdq [eax], ymm0 ; Write bypassing cache. vmovntdq [32+eax], ymm0 vmovntdq [64+eax], ymm0 vmovntdq [96+eax], ymm0 vmovntdq [128+eax], ymm0 vmovntdq [160+eax], ymm0 vmovntdq [192+eax], ymm0 vmovntdq [224+eax], ymm0 add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2_bypass ; Purpose: Write 128-bit values sequentially from an area of memory, ; bypassing the cache. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = value (ignored) ;------------------------------------------------------------------------------ align 64 WriterSSE2_bypass: _WriterSSE2_bypass: push ebx push ecx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: movntdq [eax], xmm0 ; Write bypassing cache. movntdq [16+eax], xmm0 movntdq [32+eax], xmm0 movntdq [48+eax], xmm0 movntdq [64+eax], xmm0 movntdq [80+eax], xmm0 movntdq [96+eax], xmm0 movntdq [112+eax], xmm0 movntdq [128+eax], xmm0 movntdq [144+eax], xmm0 movntdq [160+eax], xmm0 movntdq [176+eax], xmm0 movntdq [192+eax], xmm0 movntdq [208+eax], xmm0 movntdq [224+eax], xmm0 movntdq [240+eax], xmm0 add eax, 256 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2_128bytes_bypass ; Purpose: Write 128-bit values sequentially from an area of memory, ; bypassing the cache. ; Params: [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = value (ignored) ;------------------------------------------------------------------------------ align 64 WriterSSE2_128bytes_bypass: _WriterSSE2_128bytes_bypass: push ebx push ecx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+8] mov eax, [esp+4+8] mov ebx, eax add ebx, [esp+8+8] ; ebx points to end. .L1: mov eax, [esp+4+8] .L2: movntdq [eax], xmm0 ; Write bypassing cache. movntdq [16+eax], xmm0 movntdq [32+eax], xmm0 movntdq [48+eax], xmm0 movntdq [64+eax], xmm0 movntdq [80+eax], xmm0 movntdq [96+eax], xmm0 movntdq [112+eax], xmm0 add eax, 128 cmp eax, ebx jb .L2 sub ecx, 1 jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RandomReader ; Purpose: Reads 32-bit values randomly from an area of memory. ; Params: ; [esp+4] = ptr to array of chunk pointers ; [esp+8] = # of 128-byte chunks ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 RandomReader: _RandomReader: push ebx push ecx push edx mov ecx, [esp+12+12] ; loops to do. .L0: mov ebx, [esp+8+12] ; # chunks to do .L1: sub ebx, 1 jc .L2 mov edx, [esp+4+12] ; get ptr to memory chunk. mov edx, [edx + 4*ebx] mov eax, [edx+160] mov eax, [edx+232] mov eax, [edx+224] mov eax, [96+edx] mov eax, [edx+164] mov eax, [76+edx] mov eax, [100+edx] mov eax, [edx+220] mov eax, [edx+248] mov eax, [104+edx] mov eax, [4+edx] mov eax, [edx+136] mov eax, [112+edx] mov eax, [edx+200] mov eax, [12+edx] mov eax, [edx+128] mov eax, [edx+148] mov eax, [edx+196] mov eax, [edx+216] mov eax, [edx] mov eax, [84+edx] mov eax, [edx+140] mov eax, [edx+204] mov eax, [edx+184] mov eax, [124+edx] mov eax, [48+edx] mov eax, [64+edx] mov eax, [edx+212] mov eax, [edx+240] mov eax, [edx+236] mov eax, [24+edx] mov eax, [edx+252] mov eax, [68+edx] mov eax, [20+edx] mov eax, [72+edx] mov eax, [32+edx] mov eax, [28+edx] mov eax, [52+edx] mov eax, [edx+244] mov eax, [edx+180] mov eax, [80+edx] mov eax, [60+edx] mov eax, [8+edx] mov eax, [56+edx] mov eax, [edx+208] mov eax, [edx+228] mov eax, [40+edx] mov eax, [edx+172] mov eax, [120+edx] mov eax, [edx+176] mov eax, [108+edx] mov eax, [edx+132] mov eax, [16+edx] mov eax, [44+edx] mov eax, [92+edx] mov eax, [edx+168] mov eax, [edx+152] mov eax, [edx+156] mov eax, [edx+188] mov eax, [36+edx] mov eax, [88+edx] mov eax, [116+edx] mov eax, [edx+192] mov eax, [edx+144] jmp .L1 .L2: sub ecx, 1 jnz .L0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RandomReaderSSE2 ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: ; [esp+4] = ptr to array of chunk pointers ; [esp+8] = # of 128-byte chunks ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 RandomReaderSSE2: _RandomReaderSSE2: push ebx push ecx push edx mov ecx, [esp+12+12] ; loops to do. .L0: mov ebx, [esp+8+12] ; # chunks to do .L1: sub ebx, 1 jc .L2 mov edx, [esp+4+12] ; get ptr to memory chunk. mov edx, [edx + 4*ebx] ; Read aligned @ 16-byte boundary. movdqa xmm0, [240+edx] movdqa xmm0, [128+edx] movdqa xmm0, [64+edx] movdqa xmm0, [208+edx] movdqa xmm0, [112+edx] movdqa xmm0, [176+edx] movdqa xmm0, [144+edx] movdqa xmm0, [edx] movdqa xmm0, [96+edx] movdqa xmm0, [16+edx] movdqa xmm0, [192+edx] movdqa xmm0, [160+edx] movdqa xmm0, [32+edx] movdqa xmm0, [48+edx] movdqa xmm0, [224+edx] movdqa xmm0, [80+edx] jmp .L1 .L2: sub ecx, 1 jnz .L0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RandomReaderSSE2_bypass ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: ; [esp+4] = ptr to array of chunk pointers ; [esp+8] = # of 128-byte chunks ; [esp+12] = loops ;------------------------------------------------------------------------------ align 64 RandomReaderSSE2_bypass: _RandomReaderSSE2_bypass: push ebx push ecx push edx mov ecx, [esp+12+12] ; loops to do. .L0: mov ebx, [esp+8+12] ; # chunks to do .L1: sub ebx, 1 jc .L2 mov edx, [esp+4+12] ; get ptr to memory chunk. mov edx, [edx + 4*ebx] ; Read aligned @ 16-byte boundary. prefetchnta [edx+192] movntdqa xmm0, [240+edx] prefetchnta [edx] movntdqa xmm0, [edx] prefetchnta [edx+128] movntdqa xmm0, [128+edx] prefetchnta [edx+64] movntdqa xmm0, [64+edx] movntdqa xmm0, [208+edx] movntdqa xmm0, [112+edx] movntdqa xmm0, [32+edx] movntdqa xmm0, [176+edx] movntdqa xmm0, [144+edx] movntdqa xmm0, [96+edx] movntdqa xmm0, [16+edx] movntdqa xmm0, [160+edx] movntdqa xmm0, [192+edx] movntdqa xmm0, [48+edx] movntdqa xmm0, [224+edx] movntdqa xmm0, [80+edx] jmp .L1 .L2: sub ecx, 1 jnz .L0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RandomWriter ; Purpose: Writes 32-bit value sequentially to an area of memory. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = long to write ;------------------------------------------------------------------------------ align 64 RandomWriter: _RandomWriter: push ebx push ecx push edx mov eax, [esp+16+12] ; get datum. mov ecx, [esp+12+12] ; loops to do. .L0: mov ebx, [esp+8+12] ; # chunks to do .L1: sub ebx, 1 jc .L2 mov edx, [esp+4+12] ; get ptr to memory chunk. mov edx, [edx + 4*ebx] mov [edx+212], eax mov [edx+156], eax mov [edx+132], eax mov [20+edx], eax mov [edx+172], eax mov [edx+196], eax mov [edx+248], eax mov [edx], eax mov [edx+136], eax mov [edx+228], eax mov [edx+160], eax mov [80+edx], eax mov [76+edx], eax mov [32+edx], eax mov [64+edx], eax mov [68+edx], eax mov [120+edx], eax mov [edx+216], eax mov [124+edx], eax mov [28+edx], eax mov [edx+152], eax mov [36+edx], eax mov [edx+220], eax mov [edx+188], eax mov [48+edx], eax mov [104+edx], eax mov [72+edx], eax mov [96+edx], eax mov [edx+184], eax mov [112+edx], eax mov [edx+236], eax mov [edx+224], eax mov [edx+252], eax mov [88+edx], eax mov [edx+180], eax mov [60+edx], eax mov [24+edx], eax mov [edx+192], eax mov [edx+164], eax mov [edx+204], eax mov [44+edx], eax mov [edx+168], eax mov [92+edx], eax mov [edx+208], eax mov [8+edx], eax mov [edx+144], eax mov [edx+148], eax mov [edx+128], eax mov [52+edx], eax mov [4+edx], eax mov [108+edx], eax mov [12+edx], eax mov [56+edx], eax mov [edx+200], eax mov [edx+232], eax mov [16+edx], eax mov [edx+244], eax mov [40+edx], eax mov [edx+140], eax mov [84+edx], eax mov [100+edx], eax mov [116+edx], eax mov [edx+176], eax mov [edx+240], eax jmp .L1 .L2: sub ecx, 1 jnz .L0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RandomWriterSSE2 ; Purpose: Writes 128-bit value randomly to an area of memory. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = long to write ;------------------------------------------------------------------------------ align 64 RandomWriterSSE2: _RandomWriterSSE2: push ebx push ecx push edx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+12] ; loops to do. .L0: mov ebx, [esp+8+12] ; # chunks to do .L1: sub ebx, 1 jc .L2 mov edx, [esp+4+12] ; get ptr to memory chunk. mov edx, [edx + 4*ebx] movdqa [64+edx], xmm0 movdqa [208+edx], xmm0 movdqa [128+edx], xmm0 movdqa [112+edx], xmm0 movdqa [176+edx], xmm0 movdqa [144+edx], xmm0 movdqa [edx], xmm0 movdqa [96+edx], xmm0 movdqa [48+edx], xmm0 movdqa [16+edx], xmm0 movdqa [192+edx], xmm0 movdqa [160+edx], xmm0 movdqa [32+edx], xmm0 movdqa [240+edx], xmm0 movdqa [224+edx], xmm0 movdqa [80+edx], xmm0 jmp .L1 .L2: sub ecx, 1 jnz .L0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RandomWriterSSE2_bypass ; Purpose: Writes 128-bit value randomly into memory, bypassing caches. ; Params: ; [esp+4] = ptr to memory area ; [esp+8] = length in bytes ; [esp+12] = loops ; [esp+16] = long to write ;------------------------------------------------------------------------------ align 64 RandomWriterSSE2_bypass: _RandomWriterSSE2_bypass: push ebx push ecx push edx mov eax, [esp+16+8] movd xmm0, eax ; Create a 128-bit replication of the 32-bit movd xmm1, eax ; value that was provided. movd xmm2, eax movd xmm3, eax pslldq xmm1, 32 pslldq xmm2, 64 pslldq xmm3, 96 por xmm0, xmm1 por xmm0, xmm2 por xmm0, xmm3 mov ecx, [esp+12+12] ; loops to do. .L0: mov ebx, [esp+8+12] ; # chunks to do .L1: sub ebx, 1 jc .L2 mov edx, [esp+4+12] ; get ptr to memory chunk. mov edx, [edx + 4*ebx] movntdq [128+edx], xmm0 movntdq [240+edx], xmm0 movntdq [112+edx], xmm0 movntdq [64+edx], xmm0 movntdq [176+edx], xmm0 movntdq [144+edx], xmm0 movntdq [edx], xmm0 movntdq [208+edx], xmm0 movntdq [80+edx], xmm0 movntdq [96+edx], xmm0 movntdq [48+edx], xmm0 movntdq [16+edx], xmm0 movntdq [192+edx], xmm0 movntdq [160+edx], xmm0 movntdq [224+edx], xmm0 movntdq [32+edx], xmm0 jmp .L1 .L2: sub ecx, 1 jnz .L0 pop edx pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: RegisterToRegister ; Purpose: Reads/writes 32-bit values between registers of ; the main register set. ; Params: ; dword [esp+4] = loops ;------------------------------------------------------------------------------ align 64 RegisterToRegister: _RegisterToRegister: push ebx push ecx mov ecx, [esp+4+8] ; loops to do. .L1: mov eax, ebx ; 64 transfers by 4 bytes = 256 bytes mov eax, ecx mov eax, edx mov eax, esi mov eax, edi mov eax, ebp mov eax, esp mov eax, ebx mov eax, ebx mov eax, ecx mov eax, edx mov eax, esi mov eax, edi mov eax, ebp mov eax, esp mov eax, ebx mov eax, ebx mov eax, ecx mov eax, edx mov eax, esi mov eax, edi mov eax, ebp mov eax, esp mov eax, ebx mov eax, ebx mov eax, ecx mov eax, edx mov eax, esi mov eax, edi mov eax, ebp mov eax, esp mov eax, ebx mov ebx, eax mov ebx, ecx mov ebx, edx mov ebx, esi mov ebx, edi mov ebx, ebp mov ebx, esp mov ebx, eax mov ebx, eax mov ebx, ecx mov ebx, edx mov ebx, esi mov ebx, edi mov ebx, ebp mov ebx, esp mov ebx, eax mov ebx, eax mov ebx, ecx mov ebx, edx mov ebx, esi mov ebx, edi mov ebx, ebp mov ebx, esp mov ebx, eax mov ebx, eax mov ebx, ecx mov ebx, edx mov ebx, esi mov ebx, edi mov ebx, ebp mov ebx, esp mov ebx, eax dec ecx jnz .L1 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: VectorToVectorAVX ; Purpose: Reads/writes 256-bit values between registers of ; the vector register set, in this case YMM. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 VectorToVectorAVX: _VectorToVectorAVX: vzeroupper mov eax, [esp + 4] .L1: vmovdqa ymm0, ymm1 ; Each move moves 32 bytes, so we need 8 vmovdqa ymm0, ymm2 ; moves to transfer a 256 byte chunk. vmovdqa ymm0, ymm3 vmovdqa ymm2, ymm0 vmovdqa ymm1, ymm2 vmovdqa ymm2, ymm1 vmovdqa ymm0, ymm3 vmovdqa ymm3, ymm1 dec eax jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: VectorToVector ; Purpose: Reads/writes 128-bit values between registers of ; the vector register set, in this case XMM. ; Params: dword [esp + 4] = count. ;------------------------------------------------------------------------------ align 64 VectorToVector: _VectorToVector: mov eax, [esp + 4] .L1: movdqa xmm0, xmm1 movdqa xmm0, xmm2 movdqa xmm0, xmm3 movdqa xmm2, xmm0 movdqa xmm1, xmm2 movdqa xmm2, xmm1 movdqa xmm0, xmm3 movdqa xmm3, xmm1 movdqa xmm3, xmm2 movdqa xmm1, xmm3 movdqa xmm2, xmm1 movdqa xmm0, xmm1 movdqa xmm1, xmm2 movdqa xmm0, xmm1 movdqa xmm0, xmm3 movdqa xmm3, xmm0 dec eax jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: RegisterToVector ; Purpose: Writes 32-bit main register values into 128-bit vector register ; clearing the upper unused bits. ; Params: dword [esp + 4] = count. ;------------------------------------------------------------------------------ align 64 RegisterToVector: _RegisterToVector: mov eax, [esp + 4] add eax, eax ; Double # of loops. .L1: movd xmm1, eax ; 32 transfers of 4 bytes = 128 bytes movd xmm2, eax movd xmm3, eax movd xmm0, eax movd xmm1, eax movd xmm2, eax movd xmm3, eax movd xmm0, eax movd xmm1, eax movd xmm3, eax movd xmm2, eax movd xmm0, eax movd xmm1, eax movd xmm2, eax movd xmm3, eax movd xmm0, eax movd xmm0, eax movd xmm2, eax movd xmm0, eax movd xmm3, eax movd xmm1, eax movd xmm3, eax movd xmm2, eax movd xmm0, eax movd xmm0, eax movd xmm3, eax movd xmm1, eax movd xmm2, eax movd xmm0, eax movd xmm2, eax movd xmm3, eax movd xmm0, eax dec eax jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: VectorToRegister ; Purpose: Writes lowest 32 bits of vector registers into 32-bit main ; register. ; Params: dword [esp + 4] = count. ;------------------------------------------------------------------------------ align 64 VectorToRegister: _VectorToRegister: mov eax, [esp + 4] add eax, eax ; Double # of loops. push ebx .L1: movd ebx, xmm1 ; 4 bytes per transfer therefore need 64 movd ebx, xmm2 ; to transfer 256 bytes. movd ebx, xmm3 movd ebx, xmm0 movd ebx, xmm1 movd ebx, xmm2 movd ebx, xmm3 movd ebx, xmm0 movd ebx, xmm1 movd ebx, xmm3 movd ebx, xmm2 movd ebx, xmm0 movd ebx, xmm1 movd ebx, xmm2 movd ebx, xmm3 movd ebx, xmm0 movd ebx, xmm0 movd ebx, xmm2 movd ebx, xmm0 movd ebx, xmm3 movd ebx, xmm1 movd ebx, xmm3 movd ebx, xmm2 movd ebx, xmm0 movd ebx, xmm0 movd ebx, xmm3 movd ebx, xmm1 movd ebx, xmm2 movd ebx, xmm0 movd ebx, xmm2 movd ebx, xmm3 movd ebx, xmm0 dec eax jnz .L1 pop ebx ret ;------------------------------------------------------------------------------ ; Name: StackReader ; Purpose: Reads 32-bit values off the stack into registers of ; the main register set, effectively testing L1 cache access ; *and* effective-address calculation speed. ; Params: ; dword [esp+4] = loops ;------------------------------------------------------------------------------ align 64 StackReader: _StackReader: push ebx push ecx mov ecx, [esp+4+8] ; loops to do. push dword 7000 ; [esp+24] push dword 6000 ; [esp+20] push dword 5000 ; [esp+16] push dword 4000 ; [esp+12] push dword 3000 ; [esp+8] push dword 2000 ; [esp+4] push dword 1000 ; [esp] .L1: mov eax, [esp] mov eax, [esp+8] mov eax, [esp+12] mov eax, [esp+16] mov eax, [esp+20] mov eax, [esp+4] mov eax, [esp+24] mov eax, [esp] mov eax, [esp] mov eax, [esp+8] mov eax, [esp+12] mov eax, [esp+16] mov eax, [esp+20] mov eax, [esp+4] mov eax, [esp+24] mov eax, [esp] mov eax, [esp] mov eax, [esp+8] mov eax, [esp+12] mov eax, [esp+16] mov eax, [esp+20] mov eax, [esp+4] mov eax, [esp+24] mov eax, [esp+4] mov eax, [esp+4] mov eax, [esp+8] mov eax, [esp+12] mov eax, [esp+16] mov eax, [esp+20] mov eax, [esp+4] mov eax, [esp+24] mov eax, [esp+4] mov ebx, [esp] mov ebx, [esp+8] mov ebx, [esp+12] mov ebx, [esp+16] mov ebx, [esp+20] mov ebx, [esp+4] mov ebx, [esp+24] mov ebx, [esp] mov ebx, [esp] mov ebx, [esp+8] mov ebx, [esp+12] mov ebx, [esp+16] mov ebx, [esp+20] mov ebx, [esp+4] mov ebx, [esp+24] mov ebx, [esp] mov ebx, [esp] mov ebx, [esp+8] mov ebx, [esp+12] mov ebx, [esp+16] mov ebx, [esp+20] mov ebx, [esp+4] mov ebx, [esp+24] mov ebx, [esp+4] mov ebx, [esp+4] mov ebx, [esp+8] mov ebx, [esp+12] mov ebx, [esp+16] mov ebx, [esp+20] mov ebx, [esp+4] mov ebx, [esp+24] mov ebx, [esp+4] dec ecx jnz .L1 add esp, 28 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: StackWriter ; Purpose: Writes 32-bit values into the stack from registers of ; the main register set, effectively testing L1 cache access ; *and* effective-address calculation speed. ; Params: ; dword [esp+4] = loops ;------------------------------------------------------------------------------ align 64 StackWriter: _StackWriter: push ebx push ecx mov ecx, [esp+4+8] ; loops to do. push dword 7000 ; [esp+24] push dword 6000 ; [esp+20] push dword 5000 ; [esp+16] push dword 4000 ; [esp+12] push dword 3000 ; [esp+8] push dword 2000 ; [esp+4] push dword 1000 ; [esp] xor eax, eax mov ebx, 0xffffffff .L1: mov [esp], eax mov [esp+8], eax mov [esp+12], eax mov [esp+16], eax mov [esp+20], eax mov [esp+4], eax mov [esp+24], eax mov [esp], eax mov [esp], eax mov [esp+8], eax mov [esp+12], eax mov [esp+16], eax mov [esp+20], eax mov [esp+4], eax mov [esp+24], eax mov [esp], eax mov [esp], eax mov [esp+8], eax mov [esp+12], eax mov [esp+16], eax mov [esp+20], eax mov [esp+4], eax mov [esp+24], eax mov [esp+4], eax mov [esp+4], eax mov [esp+8], eax mov [esp+12], eax mov [esp+16], eax mov [esp+20], eax mov [esp+4], eax mov [esp+24], eax mov [esp+4], eax mov [esp], ebx mov [esp+8], ebx mov [esp+12], ebx mov [esp+16], ebx mov [esp+20], ebx mov [esp+4], ebx mov [esp+24], ebx mov [esp], ebx mov [esp], ebx mov [esp+8], ebx mov [esp+12], ebx mov [esp+16], ebx mov [esp+20], ebx mov [esp+4], ebx mov [esp+24], ebx mov [esp], ebx mov [esp], ebx mov [esp+8], ebx mov [esp+12], ebx mov [esp+16], ebx mov [esp+20], ebx mov [esp+4], ebx mov [esp+24], ebx mov [esp+4], ebx mov [esp+4], ebx mov [esp+8], ebx mov [esp+12], ebx mov [esp+16], ebx mov [esp+20], ebx mov [esp+4], ebx mov [esp+24], ebx mov [esp+4], ebx sub ecx, 1 jnz .L1 add esp, 28 pop ecx pop ebx ret ;------------------------------------------------------------------------------ ; Name: Register8ToVector ; Purpose: Writes 8-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: dword [esp + 4] ;------------------------------------------------------------------------------ align 64 Register8ToVector: _Register8ToVector: mov eax, [esp + 4] sal eax, 4 ; Force some repetition. .L1: pinsrb xmm1, al, 0 ; 64 transfers x 1 byte = 64 bytes pinsrb xmm2, bl, 1 pinsrb xmm3, cl, 2 pinsrb xmm1, dl, 3 pinsrb xmm2, sil, 4 pinsrb xmm3, dil, 5 pinsrb xmm0, bpl, 6 pinsrb xmm0, spl, 7 pinsrb xmm0, al, 0 pinsrb xmm1, bl, 1 pinsrb xmm2, cl, 2 pinsrb xmm3, dl, 3 pinsrb xmm3, al, 4 pinsrb xmm2, bl, 5 pinsrb xmm1, bpl, 6 pinsrb xmm0, spl, 7 pinsrb xmm1, al, 0 pinsrb xmm2, al, 1 pinsrb xmm3, al, 2 pinsrb xmm1, al, 3 pinsrb xmm2, al, 4 pinsrb xmm3, al, 5 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 pinsrb xmm0, al, 0 pinsrb xmm0, al, 1 pinsrb xmm0, al, 2 pinsrb xmm0, al, 3 pinsrb xmm0, al, 4 pinsrb xmm0, al, 5 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 pinsrb xmm1, al, 0 pinsrb xmm2, bl, 1 pinsrb xmm3, cl, 2 pinsrb xmm1, dl, 3 pinsrb xmm2, sil, 4 pinsrb xmm3, dil, 5 pinsrb xmm0, bpl, 6 pinsrb xmm0, spl, 7 pinsrb xmm0, al, 10 pinsrb xmm1, bl, 11 pinsrb xmm2, cl, 12 pinsrb xmm3, dl, 13 pinsrb xmm3, dil, 14 pinsrb xmm2, cl, 15 pinsrb xmm1, al, 6 pinsrb xmm0, bpl, 7 pinsrb xmm1, al, 10 pinsrb xmm2, al, 11 pinsrb xmm3, al, 12 pinsrb xmm1, al, 13 pinsrb xmm2, al, 14 pinsrb xmm3, al, 15 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 pinsrb xmm0, al, 9 pinsrb xmm0, al, 8 pinsrb xmm0, al, 11 pinsrb xmm0, al, 3 pinsrb xmm0, al, 4 pinsrb xmm0, al, 5 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 dec eax jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register16ToVector ; Purpose: Writes 16-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Register16ToVector: _Register16ToVector: mov eax, [esp + 4] sal eax, 3 ; Force some repetition. .L1: pinsrw xmm1, ax, 0 ; 64 transfers x 2 bytes = 128 bytes pinsrw xmm2, bx, 1 pinsrw xmm3, cx, 2 pinsrw xmm1, dx, 3 pinsrw xmm2, si, 4 pinsrw xmm3, di, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm0, ax, 0 pinsrw xmm1, bx, 1 pinsrw xmm2, cx, 2 pinsrw xmm3, dx, 3 pinsrw xmm3, si, 4 pinsrw xmm2, di, 5 pinsrw xmm1, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm1, ax, 0 pinsrw xmm2, ax, 1 pinsrw xmm3, ax, 2 pinsrw xmm1, ax, 3 pinsrw xmm2, ax, 4 pinsrw xmm3, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 pinsrw xmm0, ax, 0 pinsrw xmm0, ax, 1 pinsrw xmm0, ax, 2 pinsrw xmm0, ax, 3 pinsrw xmm0, ax, 4 pinsrw xmm0, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 pinsrw xmm1, ax, 0 pinsrw xmm2, bx, 1 pinsrw xmm3, cx, 2 pinsrw xmm1, dx, 3 pinsrw xmm2, si, 4 pinsrw xmm3, di, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm0, ax, 0 pinsrw xmm1, bx, 1 pinsrw xmm2, cx, 2 pinsrw xmm3, dx, 3 pinsrw xmm3, si, 4 pinsrw xmm2, di, 5 pinsrw xmm1, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm1, ax, 0 pinsrw xmm2, ax, 1 pinsrw xmm3, ax, 2 pinsrw xmm1, ax, 3 pinsrw xmm2, ax, 4 pinsrw xmm3, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 pinsrw xmm0, ax, 0 pinsrw xmm0, ax, 1 pinsrw xmm0, ax, 2 pinsrw xmm0, ax, 3 pinsrw xmm0, ax, 4 pinsrw xmm0, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 dec eax jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register32ToVector ; Purpose: Writes 32-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Register32ToVector: _Register32ToVector: mov eax, [esp + 4] sal eax, 2 ; Force some repetition. .L1: pinsrd xmm1, eax, 0 ; Each xfer moves 4 bytes so to move 256 bytes pinsrd xmm2, ebx, 1 ; we need 64 transfers. pinsrd xmm3, ecx, 2 pinsrd xmm1, edx, 3 pinsrd xmm2, esi, 0 pinsrd xmm3, edi, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, esp, 3 pinsrd xmm0, eax, 0 pinsrd xmm1, ebx, 1 pinsrd xmm2, ecx, 2 pinsrd xmm3, edx, 3 pinsrd xmm3, esi, 3 pinsrd xmm2, edi, 2 pinsrd xmm1, ebp, 1 pinsrd xmm0, esp, 0 pinsrd xmm1, eax, 0 pinsrd xmm2, eax, 1 pinsrd xmm3, eax, 2 pinsrd xmm1, eax, 3 pinsrd xmm2, eax, 0 pinsrd xmm3, eax, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, ebx, 3 pinsrd xmm0, eax, 0 pinsrd xmm0, eax, 1 pinsrd xmm0, eax, 2 pinsrd xmm0, eax, 3 pinsrd xmm0, eax, 0 pinsrd xmm0, eax, 0 pinsrd xmm0, ebp, 0 pinsrd xmm0, ebx, 0 pinsrd xmm1, eax, 0 pinsrd xmm2, ebx, 1 pinsrd xmm3, ecx, 2 pinsrd xmm1, edx, 3 pinsrd xmm2, esi, 0 pinsrd xmm3, edi, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, esp, 3 pinsrd xmm0, eax, 0 pinsrd xmm1, ebx, 1 pinsrd xmm2, ecx, 2 pinsrd xmm3, edx, 3 pinsrd xmm3, esi, 3 pinsrd xmm2, edi, 2 pinsrd xmm1, ebp, 1 pinsrd xmm0, esp, 0 pinsrd xmm1, eax, 0 pinsrd xmm2, eax, 1 pinsrd xmm3, eax, 2 pinsrd xmm1, eax, 3 pinsrd xmm2, eax, 0 pinsrd xmm3, eax, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, ebx, 3 pinsrd xmm0, eax, 0 pinsrd xmm0, eax, 1 pinsrd xmm0, eax, 2 pinsrd xmm0, eax, 3 pinsrd xmm0, eax, 0 pinsrd xmm0, eax, 0 pinsrd xmm0, ebp, 0 pinsrd xmm0, ebx, 0 pinsrd xmm0, esp, 0 dec eax jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register64ToVector ; Purpose: Writes 64-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ Register64ToVector: _Register64ToVector: ret ;------------------------------------------------------------------------------ ; Name: Vector8ToRegister ; Purpose: Writes 8-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector8ToRegister: _Vector8ToRegister: mov eax, [esp + 4] sal eax, 4 ; Force some repetition. push ebx .L1: pextrb ebx, xmm1, 0 pextrb ebx, xmm2, 1 pextrb ebx, xmm3, 2 pextrb ebx, xmm1, 3 pextrb ebx, xmm2, 4 pextrb ebx, xmm3, 5 pextrb ebx, xmm0, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm0, 0 pextrb ebx, xmm1, 1 pextrb ebx, xmm2, 2 pextrb ebx, xmm3, 3 pextrb ebx, xmm3, 4 pextrb ebx, xmm2, 15 pextrb ebx, xmm1, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm1, 0 pextrb ebx, xmm2, 1 pextrb ebx, xmm3, 2 pextrb ebx, xmm1, 3 pextrb ebx, xmm2, 4 pextrb ebx, xmm3, 5 pextrb ebx, xmm0, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm0, 0 pextrb ebx, xmm1, 1 pextrb ebx, xmm2, 2 pextrb ebx, xmm3, 3 pextrb ebx, xmm3, 4 pextrb ebx, xmm2, 5 pextrb ebx, xmm1, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm1, 0 pextrb ebx, xmm2, 1 pextrb ebx, xmm3, 2 pextrb ebx, xmm1, 13 pextrb ebx, xmm2, 14 pextrb ebx, xmm3, 15 pextrb ebx, xmm0, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm0, 10 pextrb ebx, xmm1, 11 pextrb ebx, xmm2, 12 pextrb ebx, xmm3, 13 pextrb ebx, xmm3, 14 pextrb ebx, xmm2, 15 pextrb ebx, xmm1, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm1, 0 pextrb ebx, xmm2, 1 pextrb ebx, xmm3, 2 pextrb ebx, xmm1, 3 pextrb ebx, xmm2, 4 pextrb ebx, xmm3, 5 pextrb ebx, xmm0, 6 pextrb ebx, xmm0, 7 pextrb ebx, xmm0, 0 pextrb ebx, xmm1, 1 pextrb ebx, xmm2, 2 pextrb ebx, xmm3, 3 pextrb ebx, xmm3, 4 pextrb ebx, xmm2, 5 pextrb ebx, xmm1, 6 pextrb ebx, xmm0, 7 dec eax jnz .L1 pop ebx ret ;------------------------------------------------------------------------------ ; Name: Vector16ToRegister ; Purpose: Writes 16-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector16ToRegister: _Vector16ToRegister: mov eax, [esp + 4] sal eax, 3 ; Force some repetition. push ebx .L1: pextrw ebx, xmm1, 0 pextrw ebx, xmm2, 1 pextrw ebx, xmm3, 2 pextrw ebx, xmm1, 3 pextrw ebx, xmm2, 4 pextrw ebx, xmm3, 5 pextrw ebx, xmm0, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm0, 0 pextrw ebx, xmm1, 1 pextrw ebx, xmm2, 2 pextrw ebx, xmm3, 3 pextrw ebx, xmm3, 4 pextrw ebx, xmm2, 5 pextrw ebx, xmm1, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm1, 0 pextrw ebx, xmm2, 1 pextrw ebx, xmm3, 2 pextrw ebx, xmm1, 3 pextrw ebx, xmm2, 4 pextrw ebx, xmm3, 5 pextrw ebx, xmm0, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm0, 0 pextrw ebx, xmm1, 1 pextrw ebx, xmm2, 2 pextrw ebx, xmm3, 3 pextrw ebx, xmm3, 4 pextrw ebx, xmm2, 5 pextrw ebx, xmm1, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm1, 0 pextrw ebx, xmm2, 1 pextrw ebx, xmm3, 2 pextrw ebx, xmm1, 3 pextrw ebx, xmm2, 4 pextrw ebx, xmm3, 5 pextrw ebx, xmm0, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm0, 0 pextrw ebx, xmm1, 1 pextrw ebx, xmm2, 2 pextrw ebx, xmm3, 3 pextrw ebx, xmm3, 4 pextrw ebx, xmm2, 5 pextrw ebx, xmm1, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm1, 0 pextrw ebx, xmm2, 1 pextrw ebx, xmm3, 2 pextrw ebx, xmm1, 3 pextrw ebx, xmm2, 4 pextrw ebx, xmm3, 5 pextrw ebx, xmm0, 6 pextrw ebx, xmm0, 7 pextrw ebx, xmm0, 0 pextrw ebx, xmm1, 1 pextrw ebx, xmm2, 2 pextrw ebx, xmm3, 3 pextrw ebx, xmm3, 4 pextrw ebx, xmm2, 5 pextrw ebx, xmm1, 6 pextrw ebx, xmm0, 7 dec eax jnz .L1 pop ebx ret ;------------------------------------------------------------------------------ ; Name: Vector32ToRegister ; Purpose: Writes 32-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector32ToRegister: _Vector32ToRegister: mov eax, [esp + 4] sal eax, 2 ; Force some repetition. push ebx .L1: pextrd ebx, xmm1, 0 pextrd ebx, xmm2, 1 pextrd ebx, xmm3, 2 pextrd ebx, xmm1, 3 pextrd ebx, xmm2, 0 pextrd ebx, xmm3, 1 pextrd ebx, xmm0, 2 pextrd ebx, xmm0, 3 pextrd ebx, xmm0, 0 pextrd ebx, xmm1, 1 pextrd ebx, xmm2, 2 pextrd ebx, xmm3, 3 pextrd ebx, xmm3, 3 pextrd ebx, xmm2, 2 pextrd ebx, xmm1, 1 pextrd ebx, xmm0, 0 pextrd ebx, xmm1, 0 pextrd ebx, xmm2, 1 pextrd ebx, xmm3, 2 pextrd ebx, xmm1, 3 pextrd ebx, xmm2, 0 pextrd ebx, xmm3, 1 pextrd ebx, xmm0, 2 pextrd ebx, xmm0, 3 pextrd ebx, xmm0, 0 pextrd ebx, xmm1, 1 pextrd ebx, xmm2, 2 pextrd ebx, xmm3, 3 pextrd ebx, xmm3, 3 pextrd ebx, xmm2, 2 pextrd ebx, xmm1, 1 pextrd ebx, xmm0, 0 dec eax jnz .L1 pop ebx ret ;------------------------------------------------------------------------------ ; Name: Vector64ToRegister ; Purpose: Writes 64-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ Vector64ToRegister: _Vector64ToRegister: ret ;------------------------------------------------------------------------------ ; Name: CopyAVX ; Purpose: Copies memory chunks that are 32-byte aligned. ; Params: [esp + 4] = ptr to destination memory area ; [esp + 8] = ptr to source memory area ; [esp + 12] = length in bytes ; [esp + 16] = loops ;------------------------------------------------------------------------------ align 64 CopyAVX: _CopyAVX: vzeroupper ; Register usage: ; esi = source ; edi = dest ; ecx = loops ; edx = length push esi push edi push ecx push edx mov edi, [esp + 4 + 16] mov esi, [esp + 8 + 16] mov edx, [esp + 12 + 16] mov ecx, [esp + 16 + 16] shr edx, 8 ; Ensure length is multiple of 256. shl edx, 8 .L1: mov eax, edx .L2: vmovdqa ymm0, [esi] vmovdqa ymm1, [32+esi] vmovdqa ymm2, [64+esi] vmovdqa ymm3, [96+esi] vmovdqa [edi], ymm0 vmovdqa [32+edi], ymm1 vmovdqa [64+edi], ymm2 vmovdqa [96+edi], ymm3 vmovdqa ymm0, [128+esi] vmovdqa ymm1, [128+32+esi] vmovdqa ymm2, [128+64+esi] vmovdqa ymm3, [128+96+esi] vmovdqa [128+edi], ymm0 vmovdqa [128+32+edi], ymm1 vmovdqa [128+64+edi], ymm2 vmovdqa [128+96+edi], ymm3 add esi, 256 add edi, 256 sub eax, 256 jnz .L2 sub esi, edx ; rsi now points to start. sub edi, edx ; rdi now points to start. dec ecx jnz .L1 pop edx pop ecx pop edi pop esi ret ;------------------------------------------------------------------------------ ; Name: CopySSE ; Purpose: Copies memory chunks that are 16-byte aligned. ; Params: [esp + 4] = ptr to destination memory area ; [esp + 8] = ptr to source memory area ; [esp + 12] = length in bytes ; [esp + 16] = loops ;------------------------------------------------------------------------------ align 64 CopySSE: _CopySSE: ; Register usage: ; esi = source ; edi = dest ; ecx = loops ; edx = length push esi push edi push ecx push edx mov edi, [esp + 4 + 16] mov esi, [esp + 8 + 16] mov edx, [esp + 12 + 16] mov ecx, [esp + 16 + 16] shr edx, 7 ; Ensure length is multiple of 128. shl edx, 7 ; Save our non-parameter XMM registers. sub esp, 64 movdqu [esp], xmm4 movdqu [16+esp], xmm5 movdqu [32+esp], xmm6 movdqu [48+esp], xmm7 .L1: mov eax, edx .L2: movdqa xmm0, [esi] movdqa xmm1, [16+esi] movdqa xmm2, [32+esi] movdqa xmm3, [48+esi] movdqa xmm4, [64+esi] movdqa xmm5, [80+esi] movdqa xmm6, [96+esi] movdqa xmm7, [112+esi] ; 32-bit lacks xmm8 - xmm15. movdqa [edi], xmm0 movdqa [16+edi], xmm1 movdqa [32+edi], xmm2 movdqa [48+edi], xmm3 movdqa [64+edi], xmm4 movdqa [80+edi], xmm5 movdqa [96+edi], xmm6 movdqa [112+edi], xmm7 add esi, 128 add edi, 128 sub eax, 128 jnz .L2 sub esi, edx ; rsi now points to start. sub edi, edx ; rdi now points to start. dec ecx jnz .L1 movdqu xmm4, [0+esp] movdqu xmm5, [16+esp] movdqu xmm6, [32+esp] movdqu xmm7, [48+esp] add esp, 64 pop edx pop ecx pop edi pop esi ret ;------------------------------------------------------------------------------ ; Name: CopySSE_128bytes ; Purpose: Copies memory chunks that are 16-byte aligned. ; Params: [esp + 4] = ptr to destination memory area ; [esp + 8] = ptr to source memory area ; [esp + 12] = length in bytes ; [esp + 16] = loops ;------------------------------------------------------------------------------ align 64 CopySSE_128bytes: _CopySSE_128bytes: jmp CopySSE ;------------------------------------------------------------------------------ ; Name: IncrementRegisters ; Purpose: Increments 32-bit values in registers. ; Params: [esp + 4] = loops ;------------------------------------------------------------------------------ align 64 IncrementRegisters: _IncrementRegisters: push ebp mov ebp, [esp+4] .L1: inc eax inc ebx inc ecx inc edx inc esi inc edi inc ebp inc esp dec eax dec ebx dec ecx dec edx dec esi dec edi dec ebp dec esp inc eax inc ebx inc ecx inc edx inc esi inc edi inc ebp inc esp dec eax dec ebx dec ecx dec edx dec esi dec edi dec ebp dec esp dec ebp jnz .L1 pop ebp ret ;------------------------------------------------------------------------------ ; Name: IncrementStack ; Purpose: Increments 32-bit values on stack. ; Params: [esp + 4] = loops ;------------------------------------------------------------------------------ align 64 IncrementStack: _IncrementStack: push ebp mov ebp, [esp+4] sub esp, 64 .L1: inc dword [esp] inc dword [esp+4] inc dword [esp+8] inc dword [esp+12] inc dword [esp+16] inc dword [esp+20] inc dword [esp+24] inc dword [esp+28] inc dword [esp+32] inc dword [esp+36] inc dword [esp+40] inc dword [esp+44] inc dword [esp+48] inc dword [esp+52] inc dword [esp+56] inc dword [esp+60] inc dword [esp] inc dword [esp+4] inc dword [esp+8] inc dword [esp+12] inc dword [esp+16] inc dword [esp+20] inc dword [esp+24] inc dword [esp+28] inc dword [esp+32] inc dword [esp+36] inc dword [esp+40] inc dword [esp+44] inc dword [esp+48] inc dword [esp+52] inc dword [esp+56] inc dword [esp+60] dec ebp jnz .L1 add esp, 64 pop ebp ret CPU-X-3.2.4/src/bandwidth/routines-x86-64bit.asm000066400000000000000000001555121341671471500210540ustar00rootroot00000000000000;============================================================================ ; bandwidth, a benchmark to estimate memory transfer bandwidth. ; Copyright (C) 2005-2017 by Zack T Smith. ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ; ; The author may be reached at veritas@comcast.net. ;============================================================================= bits 64 cpu ia64 global CopySSE global CopySSE_128bytes global CopyAVX global _CopyAVX global ReaderLODSQ global _ReaderLODSQ global ReaderLODSD global _ReaderLODSD global ReaderLODSW global _ReaderLODSW global ReaderLODSB global _ReaderLODSB global IncrementRegisters global _IncrementRegisters global IncrementStack global _IncrementStack global RandomReader global RandomReaderSSE2 global RandomReaderSSE2_bypass global RandomWriter global RandomWriterSSE2 global RandomWriterSSE2_bypass global Reader global Reader_128bytes global ReaderAVX global RandomReaderAVX global ReaderSSE2 global ReaderSSE2_128bytes global ReaderSSE2_bypass global ReaderSSE2_128bytes_bypass global Register16ToVector global Register32ToVector global Register64ToVector global Register8ToVector global RegisterToRegister global RegisterToVector global StackReader global StackWriter global Vector16ToRegister global Vector32ToRegister global Vector64ToRegister global Vector8ToRegister global VectorToRegister global VectorToVector global VectorToVectorAVX global Writer global Writer_128bytes global WriterAVX global RandomWriterAVX global WriterSSE2 global WriterSSE2_128bytes global WriterSSE2_bypass global WriterSSE2_128bytes_bypass global WriterAVX_bypass global _WriterAVX_bypass global _CopySSE global _CopySSE_128bytes global _RandomReader global _RandomReaderSSE2 global _RandomReaderSSE2_bypass global _RandomWriter global _RandomWriterSSE2 global _RandomWriterSSE2_bypass global _Reader global _ReaderAVX global _RandomReaderAVX global _Reader_128bytes global _ReaderSSE2 global _ReaderSSE2_bypass global _ReaderSSE2_128bytes global _ReaderSSE2_128bytes_bypass global _Register16ToVector global _Register32ToVector global _Register64ToVector global _Register8ToVector global _RegisterToRegister global _RegisterToVector global _StackReader global _StackWriter global _Vector16ToRegister global _Vector32ToRegister global _Vector64ToRegister global _Vector8ToRegister global _VectorToRegister global _VectorToVector global _VectorToVectorAVX global _Writer global _Writer_128bytes global _WriterSSE2 global _WriterAVX global _RandomWriterAVX global _WriterSSE2_128bytes global _WriterSSE2_bypass global _WriterSSE2_128bytes_bypass global get_cpuid_cache_info global _get_cpuid_cache_info global get_cpuid_family global _get_cpuid_family global get_cpuid1_ecx global _get_cpuid1_ecx global get_cpuid1_edx global _get_cpuid1_edx global get_cpuid7_ebx global _get_cpuid7_ebx global get_cpuid_80000001_ecx global _get_cpuid_80000001_ecx global get_cpuid_80000001_edx global _get_cpuid_80000001_edx ; Note: ; Unix ABI says integer param are put in these registers in this order: ; rdi, rsi, rdx, rcx, r8, r9 section .text ;------------------------------------------------------------------------------ ; Name: get_cpuid_cache_info ; get_cpuid_cache_info: _get_cpuid_cache_info: push rbx push rcx push rdx mov rax, 4 mov rcx, rsi cpuid mov [rdi], eax mov [rdi+4], ebx mov [rdi+8], ecx mov [rdi+12], edx pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_family ; get_cpuid_family: _get_cpuid_family: push rbx push rcx push rdx xor rax, rax cpuid mov [rdi], ebx mov [rdi+4], edx mov [rdi+8], ecx mov byte [rdi+12], 0 pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid1_ecx ; get_cpuid1_ecx: _get_cpuid1_ecx: push rbx push rcx push rdx mov rax, 1 cpuid mov rax, rcx pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid7_ebx ; get_cpuid7_ebx: _get_cpuid7_ebx: push rbx push rcx push rdx mov rax, 7 xor rcx, rcx cpuid mov rax, rbx pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid1_edx ; get_cpuid1_edx: _get_cpuid1_edx: push rbx push rcx push rdx mov rax, 1 cpuid mov rax, rdx pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_80000001_ecx ; get_cpuid_80000001_ecx: _get_cpuid_80000001_ecx: push rbx push rcx push rdx mov rax, 0x80000001 cpuid mov rax, rcx pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: get_cpuid_80000001_edx ; get_cpuid_80000001_edx: _get_cpuid_80000001_edx: push rbx push rcx push rdx mov rax, 0x80000001 cpuid mov rax, rdx pop rdx pop rcx pop rbx ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSQ ; Purpose: Reads 64-bit values sequentially from an area of memory ; using LODSQ instruction. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSQ: _ReaderLODSQ: push rcx ; REP counter push r10 push r11 mov r10, rdi mov r11, rsi shr r11, 3 ; length in quadwords rounded down. .L1: mov rsi, r10 ; buffer start mov rcx, r11 ; # of quadwords rep lodsq dec rdx jnz .L1 pop r11 pop r10 pop rcx ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSD ; Purpose: Reads 32-bit values sequentially from an area of memory ; using LODSD instruction. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSD: _ReaderLODSD: push rcx ; REP counter push r10 push r11 mov r10, rdi mov r11, rsi shr r11, 2 ; length in double words rounded down. .L1: mov rsi, r10 ; buffer start mov rcx, r11 ; # of double words rep lodsd dec rdx jnz .L1 pop r11 pop r10 pop rcx ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSW ; Purpose: Reads 16-bit values sequentially from an area of memory ; using LODSW instruction. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSW: _ReaderLODSW: push rcx ; REP counter push r10 push r11 mov r10, rdi mov r11, rsi shr r11, 1 ; length in words rounded down. .L1: mov rsi, r10 ; buffer start mov rcx, r11 ; # of words rep lodsw dec rdx jnz .L1 pop r11 pop r10 pop rcx ret ;------------------------------------------------------------------------------ ; Name: ReaderLODSB ; Purpose: Reads 8-bit values sequentially from an area of memory ; using LODSB instruction. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 32 ReaderLODSB: _ReaderLODSB: push rcx ; REP counter push r10 push r11 mov r10, rdi mov r11, rsi .L1: mov rsi, r10 ; buffer start mov rcx, r11 ; # of bytes rep lodsb dec rdx jnz .L1 pop r11 pop r10 pop rcx ret ;------------------------------------------------------------------------------ ; Name: Reader ; Purpose: Reads 64-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 Reader: _Reader: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: mov rax, [r10] mov rax, [8+r10] mov rax, [16+r10] mov rax, [24+r10] mov rax, [32+r10] mov rax, [40+r10] mov rax, [48+r10] mov rax, [56+r10] mov rax, [64+r10] mov rax, [72+r10] mov rax, [80+r10] mov rax, [88+r10] mov rax, [96+r10] mov rax, [104+r10] mov rax, [112+r10] mov rax, [120+r10] mov rax, [128+r10] mov rax, [136+r10] mov rax, [144+r10] mov rax, [152+r10] mov rax, [160+r10] mov rax, [168+r10] mov rax, [176+r10] mov rax, [184+r10] mov rax, [192+r10] mov rax, [200+r10] mov rax, [208+r10] mov rax, [216+r10] mov rax, [224+r10] mov rax, [232+r10] mov rax, [240+r10] mov rax, [248+r10] add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: Reader_128bytes ; Purpose: Reads 64-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 Reader_128bytes: _Reader_128bytes: push r10 add rsi, rdi ; rdi now points to end. .L1: mov r10, rdi .L2: mov rax, [r10] mov rax, [8+r10] mov rax, [16+r10] mov rax, [24+r10] mov rax, [32+r10] mov rax, [40+r10] mov rax, [48+r10] mov rax, [56+r10] mov rax, [64+r10] mov rax, [72+r10] mov rax, [80+r10] mov rax, [88+r10] mov rax, [96+r10] mov rax, [104+r10] mov rax, [112+r10] mov rax, [120+r10] add r10, 128 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: RandomReader ; Purpose: Reads 64-bit values randomly from an area of memory. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ;------------------------------------------------------------------------------ align 64 RandomReader: _RandomReader: push r10 push r11 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; Note, 64-bit pointers. mov rax, [96+r10] mov rax, [r10] mov rax, [120+r10] mov rax, [184+r10] mov rax, [160+r10] mov rax, [176+r10] mov rax, [112+r10] mov rax, [80+r10] mov rax, [32+r10] mov rax, [128+r10] mov rax, [88+r10] mov rax, [40+r10] mov rax, [48+r10] mov rax, [72+r10] mov rax, [200+r10] mov rax, [24+r10] mov rax, [152+r10] mov rax, [16+r10] mov rax, [248+r10] mov rax, [56+r10] mov rax, [240+r10] mov rax, [208+r10] mov rax, [104+r10] mov rax, [216+r10] mov rax, [136+r10] mov rax, [232+r10] mov rax, [64+r10] mov rax, [224+r10] mov rax, [144+r10] mov rax, [192+r10] mov rax, [8+r10] mov rax, [168+r10] inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 ret ;------------------------------------------------------------------------------ ; Name: RandomReaderSSE2 ; Purpose: Reads 128-bit values randomly from an area of memory. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ;------------------------------------------------------------------------------ align 64 RandomReaderSSE2: _RandomReaderSSE2: push r10 push r11 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] movdqa xmm0, [240+r10] movdqa xmm0, [128+r10] movdqa xmm0, [64+r10] movdqa xmm0, [208+r10] movdqa xmm0, [112+r10] movdqa xmm0, [176+r10] movdqa xmm0, [144+r10] movdqa xmm0, [r10] movdqa xmm0, [96+r10] movdqa xmm0, [16+r10] movdqa xmm0, [192+r10] movdqa xmm0, [160+r10] movdqa xmm0, [32+r10] movdqa xmm0, [48+r10] movdqa xmm0, [224+r10] movdqa xmm0, [80+r10] inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 ret ;------------------------------------------------------------------------------ ; Name: RandomReaderSSE2_bypass ; Purpose: Reads 128-bit values randomly from an area of memory. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ;------------------------------------------------------------------------------ align 64 RandomReaderSSE2_bypass: _RandomReaderSSE2_bypass: push r10 push r11 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; SSE 4.1 required prefetchnta [r10+192] movntdqa xmm0, [240+r10] prefetchnta [r10] movntdqa xmm0, [r10] prefetchnta [r10+128] movntdqa xmm0, [128+r10] prefetchnta [r10+64] movntdqa xmm0, [64+r10] movntdqa xmm0, [208+r10] movntdqa xmm0, [112+r10] movntdqa xmm0, [48+r10] movntdqa xmm0, [176+r10] movntdqa xmm0, [144+r10] movntdqa xmm0, [96+r10] movntdqa xmm0, [16+r10] movntdqa xmm0, [160+r10] movntdqa xmm0, [32+r10] movntdqa xmm0, [224+r10] movntdqa xmm0, [80+r10] movntdqa xmm0, [192+r10] inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 ret ;------------------------------------------------------------------------------ ; Name: RandomWriter ; Purpose: Writes 64-bit values randomly to an area of memory. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ; rcx = datum to write ;------------------------------------------------------------------------------ align 64 RandomWriter: _RandomWriter: push r10 push r11 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; Note, 64-bit pointers. mov [96+r10], rcx mov [r10], rcx mov [120+r10], rcx mov [184+r10], rcx mov [160+r10], rcx mov [176+r10], rcx mov [112+r10], rcx mov [80+r10], rcx mov [32+r10], rcx mov [128+r10], rcx mov [88+r10], rcx mov [40+r10], rcx mov [48+r10], rcx mov [72+r10], rcx mov [200+r10], rcx mov [24+r10], rcx mov [152+r10], rcx mov [16+r10], rcx mov [248+r10], rcx mov [56+r10], rcx mov [240+r10], rcx mov [208+r10], rcx mov [104+r10], rcx mov [216+r10], rcx mov [136+r10], rcx mov [232+r10], rcx mov [64+r10], rcx mov [224+r10], rcx mov [144+r10], rcx mov [192+r10], rcx mov [8+r10], rcx mov [168+r10], rcx inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 ret ;------------------------------------------------------------------------------ ; Name: RandomWriterSSE2 ; Purpose: Writes 128-bit values randomly to an area of memory. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ; rcx = datum to write ;------------------------------------------------------------------------------ align 64 RandomWriterSSE2: _RandomWriterSSE2: push r10 push r11 movq xmm0, rcx ; Create duplicated 128-bit datum movq xmm1, rcx pslldq xmm1, 64 por xmm0, xmm1 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; Note, 64-bit pointers. movdqa [240+r10], xmm0 movdqa [128+r10], xmm0 movdqa [208+r10], xmm0 movdqa [112+r10], xmm0 movdqa [64+r10], xmm0 movdqa [176+r10], xmm0 movdqa [144+r10], xmm0 movdqa [r10], xmm0 movdqa [96+r10], xmm0 movdqa [16+r10], xmm0 movdqa [192+r10], xmm0 movdqa [160+r10], xmm0 movdqa [32+r10], xmm0 movdqa [48+r10], xmm0 movdqa [224+r10], xmm0 movdqa [80+r10], xmm0 inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 ret ;------------------------------------------------------------------------------ ; Name: RandomWriterSSE2_bypass ; Purpose: Writes 128-bit values randomly into memory, bypassing caches. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ; rcx = datum to write ;------------------------------------------------------------------------------ align 64 RandomWriterSSE2_bypass: _RandomWriterSSE2_bypass: push r10 push r11 movq xmm0, rcx ; Create duplicated 128-bit datum movq xmm1, rcx pslldq xmm1, 64 por xmm0, xmm1 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; Note, 64-bit pointers. movntdq [240+r10], xmm0 movntdq [128+r10], xmm0 movntdq [208+r10], xmm0 movntdq [112+r10], xmm0 movntdq [64+r10], xmm0 movntdq [176+r10], xmm0 movntdq [144+r10], xmm0 movntdq [r10], xmm0 movntdq [96+r10], xmm0 movntdq [16+r10], xmm0 movntdq [192+r10], xmm0 movntdq [160+r10], xmm0 movntdq [32+r10], xmm0 movntdq [48+r10], xmm0 movntdq [224+r10], xmm0 movntdq [80+r10], xmm0 inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2_128bytes ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2_128bytes: _ReaderSSE2_128bytes: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: movdqa xmm0, [r10] ; Read aligned to 16-byte boundary. movdqa xmm0, [16+r10] movdqa xmm0, [32+r10] movdqa xmm0, [48+r10] movdqa xmm0, [64+r10] movdqa xmm0, [80+r10] movdqa xmm0, [96+r10] movdqa xmm0, [112+r10] add r10, 128 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2 ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2: _ReaderSSE2: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: movdqa xmm0, [r10] ; Read aligned to 16-byte boundary. movdqa xmm0, [16+r10] movdqa xmm0, [32+r10] movdqa xmm0, [48+r10] movdqa xmm0, [64+r10] movdqa xmm0, [80+r10] movdqa xmm0, [96+r10] movdqa xmm0, [112+r10] movdqa xmm0, [128+r10] movdqa xmm0, [144+r10] movdqa xmm0, [160+r10] movdqa xmm0, [176+r10] movdqa xmm0, [192+r10] movdqa xmm0, [208+r10] movdqa xmm0, [224+r10] movdqa xmm0, [240+r10] add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: ReaderAVX ; Purpose: Reads 256-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 ReaderAVX: _ReaderAVX: ; vzeroupper sub rsp, 32 vmovdqu [rsp], ymm0 sub rsp, 32 vmovdqu [rsp], ymm1 sub rsp, 32 vmovdqu [rsp], ymm2 sub rsp, 32 vmovdqu [rsp], ymm3 push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: vmovdqa ymm0, [r10] ; Read aligned to 32-byte boundary. vmovdqa ymm1, [32+r10] vmovdqa ymm2, [64+r10] vmovdqa ymm3, [96+r10] vmovdqa ymm0, [128+r10] vmovdqa ymm1, [160+r10] vmovdqa ymm2, [192+r10] vmovdqa ymm3, [224+r10] add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 vmovdqu ymm3, [rsp] add rsp, 32 vmovdqu ymm2, [rsp] add rsp, 32 vmovdqu ymm1, [rsp] add rsp, 32 vmovdqu ymm0, [rsp] add rsp, 32 ret ;------------------------------------------------------------------------------ ; Name: RandomReaderAVX ; Purpose: Reads 256-bit values in somewhat random order from RAM. ; Params: rdi = ptr to chunk pointers ; rsi = # chunks ; rdx = loops ;------------------------------------------------------------------------------ align 64 RandomReaderAVX: _RandomReaderAVX: sub rsp, 32 vmovdqu [rsp], ymm0 sub rsp, 32 vmovdqu [rsp], ymm1 sub rsp, 32 vmovdqu [rsp], ymm2 sub rsp, 32 vmovdqu [rsp], ymm3 push r10 push r11 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; Read aligned to 32-byte boundary. vmovdqa ymm0, [96+r10] vmovdqa ymm1, [192+r10] vmovdqa ymm2, [64+r10] vmovdqa ymm3, [224+r10] vmovdqa ymm0, [r10] vmovdqa ymm1, [160+r10] vmovdqa ymm2, [128+r10] vmovdqa ymm3, [32+r10] inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 vmovdqu ymm3, [rsp] add rsp, 32 vmovdqu ymm2, [rsp] add rsp, 32 vmovdqu ymm1, [rsp] add rsp, 32 vmovdqu ymm0, [rsp] add rsp, 32 ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2_bypass ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2_bypass: _ReaderSSE2_bypass: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: prefetchnta [r10] prefetchnta [r10+64] movntdqa xmm0, [r10] ; Read aligned to 16-byte boundary. movntdqa xmm0, [16+r10] movntdqa xmm0, [32+r10] movntdqa xmm0, [48+r10] movntdqa xmm0, [64+r10] movntdqa xmm0, [80+r10] movntdqa xmm0, [96+r10] movntdqa xmm0, [112+r10] prefetchnta [r10+128] prefetchnta [r10+192] movntdqa xmm0, [128+r10] movntdqa xmm0, [144+r10] movntdqa xmm0, [160+r10] movntdqa xmm0, [176+r10] movntdqa xmm0, [192+r10] movntdqa xmm0, [208+r10] movntdqa xmm0, [224+r10] movntdqa xmm0, [240+r10] add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: ReaderSSE2_128bytes_bypass ; Purpose: Reads 128-bit values sequentially from an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ;------------------------------------------------------------------------------ align 64 ReaderSSE2_128bytes_bypass: _ReaderSSE2_128bytes_bypass: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: prefetchnta [r10] movntdqa xmm0, [r10] ; Read aligned to 16-byte boundary. movntdqa xmm0, [16+r10] movntdqa xmm0, [32+r10] movntdqa xmm0, [48+r10] prefetchnta [r10+64] movntdqa xmm0, [64+r10] movntdqa xmm0, [80+r10] movntdqa xmm0, [96+r10] movntdqa xmm0, [112+r10] add r10, 128 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: Writer ; Purpose: Writes 64-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 Writer: _Writer: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: mov [r10], rcx mov [8+r10], rcx mov [16+r10], rcx mov [24+r10], rcx mov [32+r10], rcx mov [40+r10], rcx mov [48+r10], rcx mov [56+r10], rcx mov [64+r10], rcx mov [72+r10], rcx mov [80+r10], rcx mov [88+r10], rcx mov [96+r10], rcx mov [104+r10], rcx mov [112+r10], rcx mov [120+r10], rcx mov [128+r10], rcx mov [136+r10], rcx mov [144+r10], rcx mov [152+r10], rcx mov [160+r10], rcx mov [168+r10], rcx mov [176+r10], rcx mov [184+r10], rcx mov [192+r10], rcx mov [200+r10], rcx mov [208+r10], rcx mov [216+r10], rcx mov [224+r10], rcx mov [232+r10], rcx mov [240+r10], rcx mov [248+r10], rcx add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: Writer_128bytes ; Purpose: Writes 64-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 Writer_128bytes: _Writer_128bytes: push r10 add rsi, rdi ; rsi now points to end. .L1: mov r10, rdi .L2: mov [r10], rcx mov [8+r10], rcx mov [16+r10], rcx mov [24+r10], rcx mov [32+r10], rcx mov [40+r10], rcx mov [48+r10], rcx mov [56+r10], rcx mov [64+r10], rcx mov [72+r10], rcx mov [80+r10], rcx mov [88+r10], rcx mov [96+r10], rcx mov [104+r10], rcx mov [112+r10], rcx mov [120+r10], rcx add r10, 128 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2 ; Purpose: Writes 128-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 WriterSSE2: _WriterSSE2: push r10 add rsi, rdi ; rsi now points to end. movq xmm0, rcx .L1: mov r10, rdi .L2: movdqa [r10], xmm0 movdqa [16+r10], xmm0 movdqa [32+r10], xmm0 movdqa [48+r10], xmm0 movdqa [64+r10], xmm0 movdqa [80+r10], xmm0 movdqa [96+r10], xmm0 movdqa [112+r10], xmm0 movdqa [128+r10], xmm0 movdqa [144+r10], xmm0 movdqa [160+r10], xmm0 movdqa [176+r10], xmm0 movdqa [192+r10], xmm0 movdqa [208+r10], xmm0 movdqa [224+r10], xmm0 movdqa [240+r10], xmm0 add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: WriterAVX ; Purpose: Writes 256-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 WriterAVX: _WriterAVX: vzeroupper push r10 add rsi, rdi ; rsi now points to end. pinsrq xmm0, rcx, 0 pinsrq xmm0, rcx, 1 .L1: mov r10, rdi .L2: vmovdqa [r10], ymm0 vmovdqa [32+r10], ymm0 vmovdqa [64+r10], ymm0 vmovdqa [96+r10], ymm0 vmovdqa [128+r10], ymm0 vmovdqa [160+r10], ymm0 vmovdqa [192+r10], ymm0 vmovdqa [224+r10], ymm0 add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 vzeroall ret ;------------------------------------------------------------------------------ ; Name: RandomWriterAVX ; Purpose: Writes 256-bit value in somewhat random order to RAM. ; Params: rdi = ptr to array of chunk pointers ; rsi = # of chunks ; rdx = loops ; rcx = datum to write ;------------------------------------------------------------------------------ align 64 RandomWriterAVX: _RandomWriterAVX: push r10 push r11 sub rsp, 32 mov [rsp], rcx mov [rsp+8], rcx mov [rsp+16], rcx mov [rsp+24], rcx vmovdqu ymm0, [rsp] add rsp, 32 .L1: xor r11, r11 .L2: mov r10, [rdi + 8*r11] ; Note, 64-bit pointers. vmovdqa [192+r10], ymm0 vmovdqa [224+r10], ymm0 vmovdqa [64+r10], ymm0 vmovdqa [128+r10], ymm0 vmovdqa [r10], ymm0 vmovdqa [96+r10], ymm0 vmovdqa [160+r10], ymm0 vmovdqa [32+r10], ymm0 inc r11 cmp r11, rsi jb .L2 dec rdx jnz .L1 pop r11 pop r10 vzeroall ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2_128bytes ; Purpose: Writes 128-bit value sequentially to an area of memory, ; chunks are 128 bytes rather than 256. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 WriterSSE2_128bytes: _WriterSSE2_128bytes: push r10 add rsi, rdi ; rsi now points to end. movq xmm0, rcx .L1: mov r10, rdi .L2: movdqa [r10], xmm0 movdqa [16+r10], xmm0 movdqa [32+r10], xmm0 movdqa [48+r10], xmm0 movdqa [64+r10], xmm0 movdqa [80+r10], xmm0 movdqa [96+r10], xmm0 movdqa [112+r10], xmm0 add r10, 128 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2_bypass ; Purpose: Writes 128-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 WriterSSE2_bypass: _WriterSSE2_bypass: push r10 add rsi, rdi ; rsi now points to end. movq xmm0, rcx .L1: mov r10, rdi .L2: movntdq [r10], xmm0 ; Write bypassing cache. movntdq [16+r10], xmm0 movntdq [32+r10], xmm0 movntdq [48+r10], xmm0 movntdq [64+r10], xmm0 movntdq [80+r10], xmm0 movntdq [96+r10], xmm0 movntdq [112+r10], xmm0 movntdq [128+r10], xmm0 movntdq [144+r10], xmm0 movntdq [160+r10], xmm0 movntdq [176+r10], xmm0 movntdq [192+r10], xmm0 movntdq [208+r10], xmm0 movntdq [224+r10], xmm0 movntdq [240+r10], xmm0 add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: WriterAVX_bypass ; Purpose: Writes 256-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 WriterAVX_bypass: _WriterAVX_bypass: vzeroupper push r10 add rsi, rdi ; rsi now points to end. movq xmm0, rcx .L1: mov r10, rdi .L2: vmovntdq [r10], ymm0 ; Write bypassing cache. vmovntdq [32+r10], ymm0 vmovntdq [64+r10], ymm0 vmovntdq [96+r10], ymm0 vmovntdq [128+r10], ymm0 vmovntdq [160+r10], ymm0 vmovntdq [192+r10], ymm0 vmovntdq [224+r10], ymm0 add r10, 256 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 vzeroall ret ;------------------------------------------------------------------------------ ; Name: WriterSSE2_128bytes_bypass ; Purpose: Writes 128-bit value sequentially to an area of memory. ; Params: rdi = ptr to memory area ; rsi = length in bytes ; rdx = loops ; rcx = quad to write ;------------------------------------------------------------------------------ align 64 WriterSSE2_128bytes_bypass: _WriterSSE2_128bytes_bypass: push r10 add rsi, rdi ; rsi now points to end. movq xmm0, rcx .L1: mov r10, rdi .L2: movntdq [r10], xmm0 ; Write bypassing cache. movntdq [16+r10], xmm0 movntdq [32+r10], xmm0 movntdq [48+r10], xmm0 movntdq [64+r10], xmm0 movntdq [80+r10], xmm0 movntdq [96+r10], xmm0 movntdq [112+r10], xmm0 add r10, 128 cmp r10, rsi jb .L2 dec rdx jnz .L1 pop r10 ret ;------------------------------------------------------------------------------ ; Name: StackReader ; Purpose: Reads 64-bit values off the stack into registers of ; the main register set, effectively testing L1 cache access ; *and* effective-address calculation speed. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 StackReader: _StackReader: push qword 7000 ; [rsp+48] push qword 6000 ; [rsp+40] push qword 5000 ; [rsp+32] push qword 4000 ; [rsp+24] push qword 3000 ; [rsp+16] push qword 2000 ; [rsp+8] push qword 1000 ; [rsp] .L1: mov rax, [rsp] mov rax, [rsp+16] mov rax, [rsp+24] mov rax, [rsp+32] mov rax, [rsp+40] mov rax, [rsp+8] mov rax, [rsp+48] mov rax, [rsp] mov rax, [rsp] mov rax, [rsp+16] mov rax, [rsp+24] mov rax, [rsp+32] mov rax, [rsp+40] mov rax, [rsp+8] mov rax, [rsp+48] mov rax, [rsp] mov rax, [rsp] mov rax, [rsp+16] mov rax, [rsp+24] mov rax, [rsp+32] mov rax, [rsp+40] mov rax, [rsp+8] mov rax, [rsp+48] mov rax, [rsp+8] mov rax, [rsp+8] mov rax, [rsp+16] mov rax, [rsp+24] mov rax, [rsp+32] mov rax, [rsp+40] mov rax, [rsp+8] mov rax, [rsp+48] mov rax, [rsp+8] sub rdi, 1 jnz .L1 add rsp, 56 ret ;------------------------------------------------------------------------------ ; Name: StackWriter ; Purpose: Writes 64-bit values into the stack from registers of ; the main register set, effectively testing L1 cache access ; *and* effective-address calculation speed. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 StackWriter: _StackWriter: push qword 7000 ; [rsp+48] push qword 6000 ; [rsp+40] push qword 5000 ; [rsp+32] push qword 4000 ; [rsp+24] push qword 3000 ; [rsp+16] push qword 2000 ; [rsp+8] push qword 1000 ; [rsp] xor rax, rax .L1: mov [rsp], rax mov [rsp+16], rax mov [rsp+24], rax mov [rsp+32], rax mov [rsp+40], rax mov [rsp+8], rax mov [rsp+48], rax mov [rsp], rax mov [rsp], rax mov [rsp+16], rax mov [rsp+24], rax mov [rsp+32], rax mov [rsp+40], rax mov [rsp+8], rax mov [rsp+48], rax mov [rsp], rax mov [rsp], rax mov [rsp+16], rax mov [rsp+24], rax mov [rsp+32], rax mov [rsp+40], rax mov [rsp+8], rax mov [rsp+48], rax mov [rsp+8], rax mov [rsp+8], rax mov [rsp+16], rax mov [rsp+24], rax mov [rsp+32], rax mov [rsp+40], rax mov [rsp+8], rax mov [rsp+48], rax mov [rsp+8], rax sub rdi, 1 jnz .L1 add rsp, 56 ret ;------------------------------------------------------------------------------ ; Name: RegisterToRegister ; Purpose: Reads/writes 64-bit values between registers of ; the main register set. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 RegisterToRegister: _RegisterToRegister: .L1: mov rax, rbx mov rax, rcx mov rax, rdx mov rax, rsi mov rax, rdi mov rax, rbp mov rax, rsp mov rax, rbx mov rax, rbx mov rax, rcx mov rax, rdx mov rax, rsi mov rax, rdi mov rax, rbp mov rax, rsp mov rax, rbx mov rax, rbx mov rax, rcx mov rax, rdx mov rax, rsi mov rax, rdi mov rax, rbp mov rax, rsp mov rax, rbx mov rax, rbx mov rax, rcx mov rax, rdx mov rax, rsi mov rax, rdi mov rax, rbp mov rax, rsp mov rax, rbx sub rdi, 1 jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: VectorToVector ; Purpose: Reads/writes 128-bit values between registers of ; the vector register set, in this case XMM. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 VectorToVector: _VectorToVector: .L1: movq xmm0, xmm1 ; Each move moves 16 bytes, so we need 16 movq xmm14, xmm2 ; moves to transfer a 256 byte chunk. movq xmm0, xmm4 movq xmm9, xmm0 movq xmm1, xmm12 movq xmm7, xmm1 movq xmm8, xmm3 movq xmm3, xmm1 movq xmm13, xmm2 movq xmm11, xmm3 movq xmm2, xmm10 movq xmm6, xmm1 movq xmm1, xmm2 movq xmm15, xmm1 movq xmm0, xmm3 movq xmm3, xmm14 sub rdi, 1 jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: VectorToVectorAVX ; Purpose: Reads/writes 256-bit values between registers of ; the vector register set, in this case YMM. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 VectorToVectorAVX: _VectorToVectorAVX: vzeroupper .L1: vmovdqa ymm0, ymm1 ; Each move moves 32 bytes, so we need 8 vmovdqa ymm0, ymm2 ; moves to transfer a 256 byte chunk. vmovdqa ymm0, ymm3 vmovdqa ymm2, ymm0 vmovdqa ymm1, ymm2 vmovdqa ymm2, ymm1 vmovdqa ymm0, ymm3 vmovdqa ymm3, ymm1 sub rdi, 1 jnz .L1 vzeroall ret ;------------------------------------------------------------------------------ ; Name: RegisterToVector ; Purpose: Writes 64-bit main register values into 128-bit vector register ; clearing the upper unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 RegisterToVector: _RegisterToVector: .L1: movq xmm1, rax ; Each movq transfers 8 bytes, so we need movq xmm2, rsi ; 32 transfers to move a 256-byte chunk. movq xmm3, rbx movq xmm1, rcx movq xmm2, rsi movq xmm3, rsp movq xmm0, rdi movq xmm0, rdx movq xmm0, rax movq xmm1, rsi movq xmm2, rbx movq xmm3, rcx movq xmm0, rsi movq xmm3, rsp movq xmm2, rdi movq xmm1, rdx movq xmm0, rax movq xmm1, rsi movq xmm2, rbx movq xmm3, rcx movq xmm0, rsi movq xmm3, rsp movq xmm2, rdi movq xmm1, rdx movq xmm0, rax movq xmm1, rsi movq xmm2, rbx movq xmm3, rcx movq xmm0, rsi movq xmm3, rsp movq xmm2, rdi movq xmm1, rdx dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: VectorToRegister ; Purpose: Writes lower 64 bits of vector register into 64-bit main ; register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 VectorToRegister: _VectorToRegister: .L1: movq rax, xmm1 movq rax, xmm2 movq rax, xmm3 movq rax, xmm1 movq rax, xmm2 movq rax, xmm3 movq rax, xmm0 movq rax, xmm0 movq rax, xmm0 movq rax, xmm1 movq rax, xmm2 movq rax, xmm3 movq rax, xmm0 movq rax, xmm3 movq rax, xmm2 movq rax, xmm1 movq rax, xmm0 movq rax, xmm1 movq rax, xmm2 movq rax, xmm3 movq rax, xmm0 movq rax, xmm3 movq rax, xmm2 movq rax, xmm1 movq rax, xmm0 movq rax, xmm1 movq rax, xmm2 movq rax, xmm3 movq rax, xmm0 movq rax, xmm3 movq rax, xmm2 movq rax, xmm1 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register8ToVector ; Purpose: Writes 8-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Register8ToVector: _Register8ToVector: sal rdi, 2 ; Force some repetition. .L1: pinsrb xmm1, al, 0 ; 64 transfers x 1 byte = 64 bytes pinsrb xmm2, bl, 1 pinsrb xmm3, cl, 2 pinsrb xmm1, dl, 3 pinsrb xmm2, sil, 4 pinsrb xmm3, dil, 5 pinsrb xmm0, bpl, 6 pinsrb xmm0, spl, 7 pinsrb xmm0, al, 0 pinsrb xmm1, bl, 1 pinsrb xmm2, cl, 2 pinsrb xmm3, dl, 3 pinsrb xmm3, al, 4 pinsrb xmm2, bl, 5 pinsrb xmm1, bpl, 6 pinsrb xmm0, spl, 7 pinsrb xmm1, r8b, 0 pinsrb xmm2, r9b, 1 pinsrb xmm3, r10b, 2 pinsrb xmm1, r11b, 3 pinsrb xmm2, r12b, 4 pinsrb xmm3, al, 5 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 pinsrb xmm0, r8b, 0 pinsrb xmm0, r9b, 1 pinsrb xmm0, r10b, 2 pinsrb xmm0, r11b, 3 pinsrb xmm0, r12b, 4 pinsrb xmm0, al, 5 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 pinsrb xmm1, al, 0 pinsrb xmm2, bl, 1 pinsrb xmm3, cl, 2 pinsrb xmm1, dl, 3 pinsrb xmm2, sil, 4 pinsrb xmm3, dil, 5 pinsrb xmm0, bpl, 6 pinsrb xmm0, spl, 7 pinsrb xmm0, al, 10 pinsrb xmm1, bl, 11 pinsrb xmm2, cl, 12 pinsrb xmm3, dl, 13 pinsrb xmm3, dil, 14 pinsrb xmm2, cl, 15 pinsrb xmm1, al, 6 pinsrb xmm0, bpl, 7 pinsrb xmm1, r8b, 10 pinsrb xmm2, r9b, 11 pinsrb xmm3, r10b, 12 pinsrb xmm1, r11b, 13 pinsrb xmm2, r12b, 14 pinsrb xmm3, al, 15 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 pinsrb xmm0, r8b, 9 pinsrb xmm0, r9b, 8 pinsrb xmm0, r10b, 11 pinsrb xmm0, r11b, 3 pinsrb xmm0, r12b, 4 pinsrb xmm0, al, 5 pinsrb xmm0, cl, 6 pinsrb xmm0, bl, 7 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register16ToVector ; Purpose: Writes 16-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Register16ToVector: _Register16ToVector: sal rdi, 1 ; Force some repetition. .L1: pinsrw xmm1, ax, 0 ; 64 transfers x 2 bytes = 128 bytes pinsrw xmm2, bx, 1 pinsrw xmm3, cx, 2 pinsrw xmm1, dx, 3 pinsrw xmm2, si, 4 pinsrw xmm3, di, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm0, ax, 0 pinsrw xmm1, bx, 1 pinsrw xmm2, cx, 2 pinsrw xmm3, dx, 3 pinsrw xmm3, si, 4 pinsrw xmm2, di, 5 pinsrw xmm1, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm1, r8w, 0 pinsrw xmm2, r9w, 1 pinsrw xmm3, r10w, 2 pinsrw xmm1, r11w, 3 pinsrw xmm2, r12w, 4 pinsrw xmm3, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 pinsrw xmm0, r8w, 0 pinsrw xmm0, r9w, 1 pinsrw xmm0, r10w, 2 pinsrw xmm0, r11w, 3 pinsrw xmm0, r12w, 4 pinsrw xmm0, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 pinsrw xmm1, ax, 0 pinsrw xmm2, bx, 1 pinsrw xmm3, cx, 2 pinsrw xmm1, dx, 3 pinsrw xmm2, si, 4 pinsrw xmm3, di, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm0, ax, 0 pinsrw xmm1, bx, 1 pinsrw xmm2, cx, 2 pinsrw xmm3, dx, 3 pinsrw xmm3, si, 4 pinsrw xmm2, di, 5 pinsrw xmm1, bp, 6 pinsrw xmm0, sp, 7 pinsrw xmm1, r8w, 0 pinsrw xmm2, r9w, 1 pinsrw xmm3, r10w, 2 pinsrw xmm1, r11w, 3 pinsrw xmm2, r12w, 4 pinsrw xmm3, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 pinsrw xmm0, r8w, 0 pinsrw xmm0, r9w, 1 pinsrw xmm0, r10w, 2 pinsrw xmm0, r11w, 3 pinsrw xmm0, r12w, 4 pinsrw xmm0, ax, 5 pinsrw xmm0, bp, 6 pinsrw xmm0, bx, 7 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register32ToVector ; Purpose: Writes 32-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Register32ToVector: _Register32ToVector: .L1: pinsrd xmm1, eax, 0 ; Each xfer moves 4 bytes so to move 256 bytes pinsrd xmm2, ebx, 1 ; we need 64 transfers. pinsrd xmm3, ecx, 2 pinsrd xmm1, edx, 3 pinsrd xmm2, esi, 0 pinsrd xmm3, edi, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, esp, 3 pinsrd xmm0, eax, 0 pinsrd xmm1, ebx, 1 pinsrd xmm2, ecx, 2 pinsrd xmm3, edx, 3 pinsrd xmm3, esi, 3 pinsrd xmm2, edi, 2 pinsrd xmm1, ebp, 1 pinsrd xmm0, esp, 0 pinsrd xmm1, r8d, 0 pinsrd xmm2, r9d, 1 pinsrd xmm3, r10d, 2 pinsrd xmm1, r11d, 3 pinsrd xmm2, r12d, 0 pinsrd xmm3, eax, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, ebx, 3 pinsrd xmm0, r8d, 0 pinsrd xmm0, r9d, 1 pinsrd xmm0, r10d, 2 pinsrd xmm0, r11d, 3 pinsrd xmm0, r12d, 0 pinsrd xmm0, eax, 0 pinsrd xmm0, ebp, 0 pinsrd xmm0, ebx, 0 pinsrd xmm1, eax, 0 pinsrd xmm2, ebx, 1 pinsrd xmm3, ecx, 2 pinsrd xmm1, edx, 3 pinsrd xmm2, esi, 0 pinsrd xmm3, edi, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, esp, 3 pinsrd xmm0, eax, 0 pinsrd xmm1, ebx, 1 pinsrd xmm2, ecx, 2 pinsrd xmm3, edx, 3 pinsrd xmm3, esi, 3 pinsrd xmm2, edi, 2 pinsrd xmm1, ebp, 1 pinsrd xmm0, esp, 0 pinsrd xmm1, r8d, 0 pinsrd xmm2, r9d, 1 pinsrd xmm3, r10d, 2 pinsrd xmm1, r11d, 3 pinsrd xmm2, r12d, 0 pinsrd xmm3, eax, 1 pinsrd xmm0, ebp, 2 pinsrd xmm0, ebx, 3 pinsrd xmm0, r8d, 0 pinsrd xmm0, r9d, 1 pinsrd xmm0, r10d, 2 pinsrd xmm0, r11d, 3 pinsrd xmm0, r12d, 0 pinsrd xmm0, eax, 0 pinsrd xmm0, ebp, 0 pinsrd xmm0, ebx, 0 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Register64ToVector ; Purpose: Writes 64-bit main register values into 128-bit vector register ; without clearing the unused bits. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Register64ToVector: _Register64ToVector: add rdi, rdi .L1: pinsrq xmm1, r8, 0 ; Each xfer moves 8 bytes, therefore to do pinsrq xmm2, r9, 1 ; 256 bytes we need 32 transfers. pinsrq xmm3, r10, 0 pinsrq xmm1, r11, 1 pinsrq xmm2, r12, 0 pinsrq xmm3, rax, 1 pinsrq xmm0, rbp, 0 pinsrq xmm0, rbx, 1 pinsrq xmm0, r8, 0 pinsrq xmm0, r9, 1 pinsrq xmm0, r10, 1 pinsrq xmm0, r11, 1 pinsrq xmm0, r12, 0 pinsrq xmm0, rax, 0 pinsrq xmm0, rbp, 0 pinsrq xmm0, rbx, 0 pinsrq xmm0, r8, 0 pinsrq xmm0, r9, 1 pinsrq xmm0, r10, 1 pinsrq xmm0, r11, 1 pinsrq xmm0, r12, 0 pinsrq xmm0, rax, 0 pinsrq xmm0, rbp, 0 pinsrq xmm0, rbx, 0 pinsrq xmm0, r8, 0 pinsrq xmm0, r9, 1 pinsrq xmm0, r10, 1 pinsrq xmm0, r11, 1 pinsrq xmm0, r12, 0 pinsrq xmm0, rax, 0 pinsrq xmm0, rbp, 0 pinsrq xmm0, rbx, 0 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Vector8ToRegister ; Purpose: Writes 8-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector8ToRegister: _Vector8ToRegister: sal rdi, 3 ; Force some repetition. .L1: pextrb eax, xmm1, 0 ; 64 transfers x 1 bytes = 64 bytes pextrb eax, xmm2, 1 pextrb eax, xmm3, 2 pextrb eax, xmm1, 3 pextrb eax, xmm2, 4 pextrb eax, xmm3, 5 pextrb eax, xmm0, 6 pextrb eax, xmm0, 7 pextrb eax, xmm0, 0 pextrb eax, xmm1, 1 pextrb eax, xmm2, 2 pextrb eax, xmm3, 3 pextrb eax, xmm3, 4 pextrb eax, xmm2, 5 pextrb eax, xmm1, 6 pextrb eax, xmm0, 7 pextrb eax, xmm1, 0 pextrb eax, xmm2, 1 pextrb eax, xmm3, 2 pextrb eax, xmm1, 3 pextrb eax, xmm2, 4 pextrb eax, xmm3, 5 pextrb eax, xmm0, 6 pextrb eax, xmm0, 7 pextrb eax, xmm0, 0 pextrb eax, xmm0, 1 pextrb eax, xmm0, 2 pextrb eax, xmm0, 3 pextrb eax, xmm0, 4 pextrb eax, xmm0, 5 pextrb eax, xmm0, 6 pextrb eax, xmm0, 7 pextrb eax, xmm1, 0 pextrb eax, xmm2, 1 pextrb eax, xmm3, 2 pextrb eax, xmm1, 3 pextrb eax, xmm2, 4 pextrb eax, xmm3, 5 pextrb eax, xmm0, 6 pextrb eax, xmm0, 7 pextrb eax, xmm0, 0 pextrb eax, xmm1, 1 pextrb eax, xmm2, 2 pextrb eax, xmm3, 3 pextrb eax, xmm3, 4 pextrb eax, xmm2, 5 pextrb eax, xmm1, 6 pextrb eax, xmm0, 7 pextrb eax, xmm1, 0 pextrb eax, xmm2, 1 pextrb eax, xmm3, 2 pextrb eax, xmm1, 3 pextrb eax, xmm2, 4 pextrb eax, xmm3, 5 pextrb eax, xmm0, 6 pextrb eax, xmm0, 7 pextrb eax, xmm0, 0 pextrb eax, xmm0, 1 pextrb eax, xmm0, 2 pextrb eax, xmm0, 3 pextrb eax, xmm0, 4 pextrb eax, xmm0, 5 pextrb eax, xmm0, 6 pextrb eax, xmm0, 7 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Vector16ToRegister ; Purpose: Writes 16-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector16ToRegister: _Vector16ToRegister: sal rdi, 2 ; Force some repetition. .L1: pextrw eax, xmm1, 0 ; 64 transfers x 2 bytes = 128 bytes pextrw eax, xmm2, 1 pextrw eax, xmm3, 2 pextrw eax, xmm1, 3 pextrw eax, xmm2, 4 pextrw eax, xmm3, 5 pextrw eax, xmm0, 6 pextrw eax, xmm0, 7 pextrw eax, xmm0, 0 pextrw eax, xmm1, 1 pextrw eax, xmm2, 2 pextrw eax, xmm3, 3 pextrw eax, xmm3, 4 pextrw eax, xmm2, 5 pextrw eax, xmm1, 6 pextrw eax, xmm0, 7 pextrw eax, xmm1, 0 pextrw eax, xmm2, 1 pextrw eax, xmm3, 2 pextrw eax, xmm1, 3 pextrw eax, xmm2, 4 pextrw eax, xmm3, 5 pextrw eax, xmm0, 6 pextrw eax, xmm0, 7 pextrw eax, xmm0, 0 pextrw eax, xmm0, 1 pextrw eax, xmm0, 2 pextrw eax, xmm0, 3 pextrw eax, xmm0, 4 pextrw eax, xmm0, 5 pextrw eax, xmm0, 6 pextrw eax, xmm0, 7 pextrw eax, xmm1, 0 pextrw eax, xmm2, 1 pextrw eax, xmm3, 2 pextrw eax, xmm1, 3 pextrw eax, xmm2, 4 pextrw eax, xmm3, 5 pextrw eax, xmm0, 6 pextrw eax, xmm0, 7 pextrw eax, xmm0, 0 pextrw eax, xmm1, 1 pextrw eax, xmm2, 2 pextrw eax, xmm3, 3 pextrw eax, xmm3, 4 pextrw eax, xmm2, 5 pextrw eax, xmm1, 6 pextrw eax, xmm0, 7 pextrw eax, xmm1, 0 pextrw eax, xmm2, 1 pextrw eax, xmm3, 2 pextrw eax, xmm1, 3 pextrw eax, xmm2, 4 pextrw eax, xmm3, 5 pextrw eax, xmm0, 6 pextrw eax, xmm0, 7 pextrw eax, xmm0, 0 pextrw eax, xmm0, 1 pextrw eax, xmm0, 2 pextrw eax, xmm0, 3 pextrw eax, xmm0, 4 pextrw eax, xmm0, 5 pextrw eax, xmm0, 6 pextrw eax, xmm0, 7 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Vector32ToRegister ; Purpose: Writes 32-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector32ToRegister: _Vector32ToRegister: add rdi, rdi .L1: pextrd eax, xmm1, 0 ; 64 xfers x 4 bytes = 256 bytes pextrd eax, xmm2, 1 pextrd eax, xmm3, 2 pextrd eax, xmm1, 3 pextrd eax, xmm2, 0 pextrd eax, xmm3, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 pextrd eax, xmm0, 0 pextrd eax, xmm1, 1 pextrd eax, xmm2, 2 pextrd eax, xmm3, 3 pextrd eax, xmm3, 3 pextrd eax, xmm2, 2 pextrd eax, xmm1, 1 pextrd eax, xmm0, 0 pextrd eax, xmm1, 0 pextrd eax, xmm2, 1 pextrd eax, xmm3, 2 pextrd eax, xmm1, 3 pextrd eax, xmm2, 0 pextrd eax, xmm3, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 pextrd eax, xmm0, 0 pextrd eax, xmm0, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 pextrd eax, xmm0, 0 pextrd eax, xmm0, 0 pextrd eax, xmm0, 0 pextrd eax, xmm0, 0 pextrd eax, xmm1, 0 pextrd eax, xmm2, 1 pextrd eax, xmm3, 2 pextrd eax, xmm1, 3 pextrd eax, xmm2, 0 pextrd eax, xmm3, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 pextrd eax, xmm0, 0 pextrd eax, xmm1, 1 pextrd eax, xmm2, 2 pextrd eax, xmm3, 3 pextrd eax, xmm3, 3 pextrd eax, xmm2, 2 pextrd eax, xmm1, 1 pextrd eax, xmm0, 0 pextrd eax, xmm1, 0 pextrd eax, xmm2, 1 pextrd eax, xmm3, 2 pextrd eax, xmm1, 3 pextrd eax, xmm2, 0 pextrd eax, xmm3, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 pextrd eax, xmm0, 0 pextrd eax, xmm0, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 pextrd eax, xmm0, 0 pextrd eax, xmm0, 1 pextrd eax, xmm0, 2 pextrd eax, xmm0, 3 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: Vector64ToRegister ; Purpose: Writes 64-bit vector register values into main register. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 Vector64ToRegister: _Vector64ToRegister: add rdi, rdi .L1: pextrq rax, xmm1, 0 ; 32 transfers by 8 bytes = 256 bytes pextrq rax, xmm2, 1 pextrq rax, xmm3, 0 pextrq rax, xmm1, 1 pextrq rax, xmm2, 0 pextrq rax, xmm3, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm1, 0 pextrq rax, xmm2, 1 pextrq rax, xmm3, 0 pextrq rax, xmm1, 1 pextrq rax, xmm2, 0 pextrq rax, xmm3, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 pextrq rax, xmm0, 0 pextrq rax, xmm0, 1 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: CopyAVX ; Purpose: Copies memory chunks that are 32-byte aligned. ; Params: rdi = ptr to destination memory area ; rsi = ptr to source memory area ; rdx = length in bytes ; rcx = loops ;------------------------------------------------------------------------------ align 64 CopyAVX: _CopyAVX: vzeroupper push r10 shr rdx, 8 ; Ensure length is multiple of 256. shl rdx, 8 prefetcht0 [rsi] .L1: mov r10, rdx .L2: vmovdqa ymm0, [rsi] vmovdqa ymm1, [32+rsi] vmovdqa ymm2, [64+rsi] vmovdqa ymm3, [96+rsi] vmovdqa [rdi], ymm0 vmovdqa [32+rdi], ymm1 vmovdqa [64+rdi], ymm2 vmovdqa [96+rdi], ymm3 vmovdqa ymm0, [128+rsi] vmovdqa ymm1, [128+32+rsi] vmovdqa ymm2, [128+64+rsi] vmovdqa ymm3, [128+96+rsi] vmovdqa [128+rdi], ymm0 vmovdqa [128+32+rdi], ymm1 vmovdqa [128+64+rdi], ymm2 vmovdqa [128+96+rdi], ymm3 add rsi, 256 add rdi, 256 sub r10, 256 jnz .L2 sub rsi, rdx ; rsi now points to start. sub rdi, rdx ; rdi now points to start. dec rcx jnz .L1 pop r10 vzeroall ret ;------------------------------------------------------------------------------ ; Name: CopySSE ; Purpose: Copies memory chunks that are 16-byte aligned. ; Params: rdi = ptr to destination memory area ; rsi = ptr to source memory area ; rdx = length in bytes ; rcx = loops ;------------------------------------------------------------------------------ align 64 CopySSE: _CopySSE: push r10 shr rdx, 8 ; Ensure length is multiple of 256. shl rdx, 8 prefetcht0 [rsi] ; Save our non-parameter XMM registers. sub rsp, 192 movdqu [rsp], xmm4 movdqu [16+rsp], xmm5 movdqu [32+rsp], xmm6 movdqu [48+rsp], xmm7 movdqu [64+rsp], xmm8 movdqu [80+rsp], xmm9 movdqu [96+rsp], xmm10 movdqu [112+rsp], xmm11 movdqu [128+rsp], xmm12 movdqu [144+rsp], xmm13 movdqu [160+rsp], xmm14 movdqu [176+rsp], xmm15 .L1: mov r10, rdx .L2: movdqa xmm0, [rsi] movdqa xmm1, [16+rsi] movdqa xmm2, [32+rsi] movdqa xmm3, [48+rsi] movdqa [rdi], xmm0 movdqa [16+rdi], xmm1 movdqa [32+rdi], xmm2 movdqa [48+rdi], xmm3 movdqa xmm4, [64+rsi] movdqa xmm5, [80+rsi] movdqa xmm6, [96+rsi] movdqa xmm7, [112+rsi] movdqa [64+rdi], xmm4 movdqa [80+rdi], xmm5 movdqa [96+rdi], xmm6 movdqa [112+rdi], xmm7 movdqa xmm8, [128+rsi] movdqa xmm9, [144+rsi] movdqa xmm10, [160+rsi] movdqa xmm11, [176+rsi] movdqa [128+rdi], xmm8 movdqa [144+rdi], xmm9 movdqa [160+rdi], xmm10 movdqa [176+rdi], xmm11 movdqa xmm12, [192+rsi] movdqa xmm13, [208+rsi] movdqa xmm14, [224+rsi] movdqa xmm15, [240+rsi] movdqa [192+rdi], xmm12 movdqa [208+rdi], xmm13 movdqa [224+rdi], xmm14 movdqa [240+rdi], xmm15 add rsi, 256 add rdi, 256 sub r10, 256 jnz .L2 sub rsi, rdx ; rsi now points to start. sub rdi, rdx ; rdi now points to start. dec rcx jnz .L1 movdqu xmm4, [rsp] movdqu xmm5, [16+rsp] movdqu xmm6, [32+rsp] movdqu xmm7, [48+rsp] movdqu xmm8, [64+rsp] movdqu xmm9, [80+rsp] movdqu xmm10, [96+rsp] movdqu xmm11, [112+rsp] movdqu xmm12, [128+rsp] movdqu xmm13, [144+rsp] movdqu xmm14, [160+rsp] movdqu xmm15, [176+rsp] add rsp, 192 pop r10 ret ;------------------------------------------------------------------------------ ; Name: CopySSE_128bytes ; Purpose: Copies memory chunks that are 16-byte aligned. ; Params: rdi = ptr to destination memory area ; rsi = ptr to source memory area ; rdx = length in bytes ; rcx = loops ;------------------------------------------------------------------------------ align 64 CopySSE_128bytes: _CopySSE_128bytes: push r10 shr rdx, 7 ; Ensure length is multiple of 128. shl rdx, 7 prefetcht0 [rsi] ; Save our non-parameter XMM registers. sub rsp, 64 movdqu [rsp], xmm4 movdqu [16+rsp], xmm5 movdqu [32+rsp], xmm6 movdqu [48+rsp], xmm7 .L1: mov r10, rdx .L2: movdqa xmm0, [rsi] movdqa xmm1, [16+rsi] movdqa xmm2, [32+rsi] movdqa xmm3, [48+rsi] movdqa [rdi], xmm0 movdqa [16+rdi], xmm1 movdqa [32+rdi], xmm2 movdqa [48+rdi], xmm3 movdqa xmm4, [64+rsi] movdqa xmm5, [80+rsi] movdqa xmm6, [96+rsi] movdqa xmm7, [112+rsi] movdqa [64+rdi], xmm4 movdqa [80+rdi], xmm5 movdqa [96+rdi], xmm6 movdqa [112+rdi], xmm7 add rsi, 128 add rdi, 128 sub r10, 128 jnz .L2 sub rsi, rdx ; rsi now points to start. sub rdi, rdx ; rdi now points to start. dec rcx jnz .L1 movdqu xmm4, [rsp] movdqu xmm5, [16+rsp] movdqu xmm6, [32+rsp] movdqu xmm7, [48+rsp] add rsp, 64 pop r10 ret ;------------------------------------------------------------------------------ ; Name: IncrementRegisters ; Purpose: Increments 64-bit values in registers. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 IncrementRegisters: _IncrementRegisters: .L1: inc rax inc rbx inc rcx inc rdx inc rsi inc rdi inc rbp inc rsp inc r8 inc r9 inc r10 inc r11 inc r12 inc r13 inc r14 inc r15 dec rax dec rbx dec rcx dec rdx dec rsi dec rdi dec rbp dec rsp dec r8 dec r9 dec r10 dec r11 dec r12 dec r13 dec r14 dec r15 dec rdi jnz .L1 ret ;------------------------------------------------------------------------------ ; Name: IncrementStack ; Purpose: Increments 64-bit values on stack. ; Params: rdi = loops ;------------------------------------------------------------------------------ align 64 IncrementStack: _IncrementStack: sub rsp, 128 .L1: inc qword [rsp] inc qword [rsp+8] inc qword [rsp+16] inc qword [rsp+24] inc qword [rsp+32] inc qword [rsp+40] inc qword [rsp+48] inc qword [rsp+56] inc qword [rsp+64] inc qword [rsp+72] inc qword [rsp+80] inc qword [rsp+88] inc qword [rsp+96] inc qword [rsp+104] inc qword [rsp+112] inc qword [rsp+120] dec qword [rsp] dec qword [rsp+8] dec qword [rsp+16] dec qword [rsp+24] dec qword [rsp+32] dec qword [rsp+40] dec qword [rsp+48] dec qword [rsp+56] dec qword [rsp+64] dec qword [rsp+72] dec qword [rsp+80] dec qword [rsp+88] dec qword [rsp+96] dec qword [rsp+104] dec qword [rsp+112] dec qword [rsp+120] dec rdi jnz .L1 add rsp, 128 ret CPU-X-3.2.4/src/core.c000066400000000000000000001273301341671471500142560ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE core.c */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "cpu-x.h" #ifndef __linux__ # include #endif #if HAS_LIBCPUID # include # include "databases.h" #endif #if HAS_DMIDECODE # include "dmidecode/libdmi.h" # include "dmidecode/dmiopt.h" #endif #if HAS_BANDWIDTH # include "bandwidth/libbandwidth.h" #endif #if HAS_LIBPCI # include "pci/pci.h" #endif #if HAS_LIBPROCPS # include #endif #if HAS_LIBSTATGRAB # include #endif /************************* Public functions *************************/ /* Fill labels by calling below functions */ int fill_labels(Labels *data) { int i, err = 0; const uint8_t selected_page = opts->selected_page; if(HAS_LIBCPUID) err += call_libcpuid_static (data); if(HAS_LIBCPUID) err += call_libcpuid_msr_static(data); if(HAS_DMIDECODE) err += call_dmidecode (data); if(HAS_LIBPCI) err += find_devices (data); casprintf(&data->tab_cpu[VALUE][BUSSPEED], true, "%.2f MHz", data->bus_freq); err += system_static (data); err += fallback_mode_static(data); /* Call do_refresh() once to get dynamic values */ for(i = NO_CPU; i < NO_ABOUT; i++) { opts->selected_page = i; err += do_refresh(data); } opts->selected_page = selected_page; return err; } /* Refresh some labels */ int do_refresh(Labels *data) { int err = 0; switch(opts->selected_page) { case NO_CPU: if(HAS_LIBCPUID) err += err_func(call_libcpuid_dynamic, data); if(HAS_LIBCPUID) err += err_func(call_libcpuid_msr_dynamic, data); err += err_func(cpu_usage, data); err += fallback_mode_dynamic(data); err += err_func(cputab_fill_multipliers, data); break; case NO_CACHES: if(HAS_BANDWIDTH) err += err_func(call_bandwidth, data); break; case NO_SYSTEM: if(HAS_LIBSYSTEM) err += err_func(system_dynamic, data); break; case NO_GRAPHICS: err += err_func(gpu_temperature, data); err += err_func(gpu_clocks, data); break; case NO_BENCH: err += err_func(benchmark_status, data); break; } return err; } /************************* Private functions *************************/ /* Avoid to re-run a function if an error was occurred in previous call */ static int err_func(int (*func)(Labels *), Labels *data) { unsigned i = 0; static unsigned last = 0; struct Functions { void *func; int skip_func; } *tmp = NULL; static struct Functions *registered = NULL; for(i = 0; (i < last) && (func != registered[i].func); i++); if(i == last) { if((tmp = realloc(registered, sizeof(struct Functions) * (i + 1))) == NULL) { MSG_ERRNO(_("could not reallocate memory")); MSG_STDERR(_("Exiting %s"), PRGNAME); exit(255); } registered = tmp; registered[last].func = func; registered[last].skip_func = 0; last++; } if(!registered[i].skip_func) registered[i].skip_func = func(data); return registered[i].skip_func; } #if HAS_LIBCPUID #define RETURN_OR_EXIT(e) { if(opts->debug_database) exit(e); else return e; } /* Get CPU technology, in nanometre (nm) */ static int cpu_technology(Labels *data) { int i = -1; const Technology_DB *db; LibcpuidData *l_data = data->l_data; if(l_data->cpu_vendor_id < 0 || l_data->cpu_model < 0 || l_data->cpu_ext_model < 0 || l_data->cpu_ext_family < 0) RETURN_OR_EXIT(1); MSG_VERBOSE(_("Finding CPU technology")); if(l_data->cpu_vendor_id == VENDOR_INTEL) db = technology_intel; else if(l_data->cpu_vendor_id == VENDOR_AMD) db = technology_amd; else db = technology_unknown; while(db[++i].cpu_model != -1) { if((db[i].cpu_model == l_data->cpu_model) && ((db[i].cpu_ext_model < 0) || (db[i].cpu_ext_model == l_data->cpu_ext_model)) && ((db[i].cpu_ext_family < 0) || (db[i].cpu_ext_family == l_data->cpu_ext_family))) { casprintf(&data->tab_cpu[VALUE][TECHNOLOGY], false, "%i nm", db[i].process); RETURN_OR_EXIT(0); } } MSG_WARNING(_("Your CPU does not belong in database ==> %s, model: %i, ext. model: %i, ext. family: %i"), data->tab_cpu[VALUE][SPECIFICATION], l_data->cpu_model, l_data->cpu_ext_model, l_data->cpu_ext_family); RETURN_OR_EXIT(2); } /* Static elements provided by libcpuid */ static int call_libcpuid_static(Labels *data) { int err, i, j = 0; char tmp[MAXSTR * 2] = ""; const char *fmt_cache_kb = _("%d x %d KB, %d-way"); const char *fmt_cache_mb = _("%d MB, %d-way"); const char *fmt_lines = _("%s associative, %d-byte line size"); struct cpu_raw_data_t raw; struct cpu_id_t datanr; /* Call libcpuid */ MSG_VERBOSE(_("Calling libcpuid for retrieving static data")); if(data->l_data->cpuid_raw_file == NULL) err = cpuid_get_raw_data(&raw); else err = cpuid_deserialize_raw_data(&raw, data->l_data->cpuid_raw_file); if(err || cpu_identify(&raw, &datanr)) { MSG_ERROR(_("failed to call libcpuid (%s)"), cpuid_error()); return 1; } /* Some prerequisites */ data->cpu_count = datanr.num_logical_cpus; data->l_data->cpu_model = datanr.model; data->l_data->cpu_ext_model = datanr.ext_model; data->l_data->cpu_ext_family = datanr.ext_family; if(opts->selected_core >= data->cpu_count) opts->selected_core = 0; /* Basically fill CPU tab */ casprintf(&data->tab_cpu[VALUE][CODENAME], false, "%s", datanr.cpu_codename); casprintf(&data->tab_cpu[VALUE][SPECIFICATION], false, "%s", datanr.brand_str); casprintf(&data->tab_cpu[VALUE][FAMILY], false, "%#X", datanr.family); casprintf(&data->tab_cpu[VALUE][EXTFAMILY], false, "%#X", datanr.ext_family); casprintf(&data->tab_cpu[VALUE][MODEL], false, "%#X", datanr.model); casprintf(&data->tab_cpu[VALUE][EXTMODEL], false, "%#X", datanr.ext_model); casprintf(&data->tab_cpu[VALUE][STEPPING], false, "%d", datanr.stepping); casprintf(&data->tab_cpu[VALUE][CORES], true, "%d", datanr.num_cores); casprintf(&data->tab_cpu[VALUE][THREADS], true, "%d", datanr.num_logical_cpus); /* Improve the CPU Vendor label */ const struct CpuVendor { char *standard; char *improved; cpu_vendor_t id; } cpuvendors[] = { { "GenuineIntel", "Intel", VENDOR_INTEL }, { "AuthenticAMD", "AMD", VENDOR_AMD }, { "CyrixInstead", "Cyrix", VENDOR_CYRIX }, { "NexGenDriven", "NexGen", VENDOR_NEXGEN }, { "GenuineTMx86", "Transmeta", VENDOR_TRANSMETA }, { "UMC UMC UMC ", "UMC", VENDOR_UMC }, { "CentaurHauls", "Centaur", VENDOR_CENTAUR }, { "RiseRiseRise", "Rise", VENDOR_RISE }, { "SiS SiS SiS ", "SiS", VENDOR_SIS }, { "Geode by NSC", "National Semiconductor", VENDOR_NSC }, { datanr.vendor_str, datanr.vendor_str, VENDOR_UNKNOWN } }; for(i = 0; strcmp(cpuvendors[i].standard, datanr.vendor_str); i++); casprintf(&data->tab_cpu[VALUE][VENDOR], false, cpuvendors[i].improved); data->l_data->cpu_vendor_id = cpuvendors[i].id; /* Search in DB for CPU technology (depends on data->l_data->cpu_vendor_id) */ err = cpu_technology(data); /* Remove training spaces in Specification label */ for(i = 1; datanr.brand_str[i] != '\0'; i++) { if(!(isspace(datanr.brand_str[i]) && isspace(datanr.brand_str[i - 1]))) data->tab_cpu[VALUE][SPECIFICATION][++j] = datanr.brand_str[i]; } data->tab_cpu[VALUE][SPECIFICATION][++j] = '\0'; /* Cache level 1 (data) */ if(datanr.l1_data_cache > 0) casprintf(&data->tab_cpu[VALUE][LEVEL1D], true, fmt_cache_kb, datanr.num_cores, datanr.l1_data_cache, datanr.l1_assoc); /* Cache level 1 (instruction) */ if(datanr.l1_instruction_cache > 0) { data->cache_count++; data->w_data->size[0] = datanr.l1_instruction_cache; casprintf(&data->tab_cpu[VALUE][LEVEL1I], true, fmt_cache_kb, datanr.num_cores, datanr.l1_instruction_cache, datanr.l1_assoc); casprintf(&data->tab_caches[VALUE][L1SIZE], true, fmt_lines, data->tab_cpu[VALUE][LEVEL1I], datanr.l1_cacheline); } /* Cache level 2 */ if(datanr.l2_cache > 0) { data->cache_count++; data->w_data->size[1] = datanr.l2_cache; casprintf(&data->tab_cpu[VALUE][LEVEL2], true, fmt_cache_kb, datanr.num_cores, datanr.l2_cache, datanr.l2_assoc); casprintf(&data->tab_caches[VALUE][L2SIZE], true, fmt_lines, data->tab_cpu[VALUE][LEVEL2], datanr.l2_cacheline); } /* Cache level 3 */ if(datanr.l3_cache > 0) { data->cache_count++; data->w_data->size[2] = datanr.l3_cache; casprintf(&data->tab_cpu[VALUE][LEVEL3], true, fmt_cache_mb, datanr.l3_cache >> 10, datanr.l3_assoc); casprintf(&data->tab_caches[VALUE][L3SIZE], true, fmt_lines, data->tab_cpu[VALUE][LEVEL3], datanr.l3_cacheline); } /* Cache level 4 */ if(datanr.l4_cache > 0) { data->cache_count++; data->w_data->size[3] = datanr.l4_cache; snprintf(tmp, MAXSTR, fmt_cache_mb, datanr.l4_cache >> 10, datanr.l4_assoc); casprintf(&data->tab_caches[VALUE][L4SIZE], true, fmt_lines, tmp, datanr.l4_cacheline); memset(tmp, 0, MAXSTR); } if(datanr.total_logical_cpus < datanr.num_logical_cpus) casprintf(&data->tab_cpu[VALUE][SOCKETS], true, "%d", 1); else if(datanr.num_logical_cpus > 0) /* Avoid divide by 0 */ casprintf(&data->tab_cpu[VALUE][SOCKETS], true, "%d", datanr.total_logical_cpus / datanr.num_logical_cpus); /* Add string "HT" in CPU Intructions label (if enabled) */ if(datanr.num_cores < datanr.num_logical_cpus) strncat(tmp, "HT", MAXSTR * 2 - strlen(tmp)); /* Fill CPU Intructions label */ const struct { const cpu_feature_t flag; const char *str; } cpu_flags[] = { /* SIMD x86 */ { CPU_FEATURE_MMX, "MMX" }, { CPU_FEATURE_MMXEXT, "(+)" }, { CPU_FEATURE_3DNOW, "3DNOW!" }, { CPU_FEATURE_3DNOWEXT, "(+)" }, { CPU_FEATURE_SSE, "SSE(1" }, { CPU_FEATURE_SSE2, "2" }, { CPU_FEATURE_PNI, "3" }, { CPU_FEATURE_SSSE3, "3S" }, { CPU_FEATURE_SSE4_1, "4.1" }, { CPU_FEATURE_SSE4_2, "4.2" }, { CPU_FEATURE_SSE4A, "4A" }, { CPU_FEATURE_SSE, ")" }, { CPU_FEATURE_XOP, "XOP" }, { CPU_FEATURE_AVX, "AVX(1" }, { CPU_FEATURE_AVX2, "2" }, { CPU_FEATURE_AVX512F, "512" }, { CPU_FEATURE_AVX, ")" }, { CPU_FEATURE_FMA3, "FMA(3" }, { CPU_FEATURE_FMA4, "4" }, { CPU_FEATURE_FMA3, ")" }, /* Security and Cryptography */ { CPU_FEATURE_AES, "AES" }, { CPU_FEATURE_PCLMUL, "CLMUL" }, { CPU_FEATURE_RDRAND, "RdRand" }, { CPU_FEATURE_SHA_NI, "SHA" }, { CPU_FEATURE_SGX, "SGX" }, /* Virtualization */ { CPU_FEATURE_VMX, "VT-x" }, { CPU_FEATURE_SVM, "AMD-V" }, /* Other */ { CPU_FEATURE_LM, "x86-64" }, { NUM_CPU_FEATURES, NULL } }; for(i = 0; cpu_flags[i].flag != NUM_CPU_FEATURES; i++) { if(!datanr.flags[cpu_flags[i].flag]) continue; j = strlen(tmp); if((j > 0) && (cpu_flags[i].str[0] != '(') && (cpu_flags[i].str[0] != ')')) strncat(tmp, ", ", MAXSTR * 2 - j); strncat(tmp, cpu_flags[i].str, MAXSTR * 2 - j); } casprintf(&data->tab_cpu[VALUE][INSTRUCTIONS], false, tmp); if(opts->issue) err += cpuid_serialize_raw_data(&raw, ""); return err; } /* Dynamic elements provided by libcpuid */ static int call_libcpuid_dynamic(Labels *data) { /* CPU frequency */ MSG_VERBOSE(_("Calling libcpuid for retrieving dynamic data")); data->cpu_freq = cpu_clock(); casprintf(&data->tab_cpu[VALUE][CORESPEED], true, "%d MHz", data->cpu_freq); return (data->cpu_freq <= 0); } /* Try to open a CPU MSR */ static int libcpuid_init_msr(struct msr_driver_t **msr) { if(getuid()) { MSG_WARNING(_("Skip CPU MSR opening (need to be root)")); return 1; } *msr = cpu_msr_driver_open_core(opts->selected_core); if(*msr == NULL) { MSG_ERROR(_("failed to open CPU MSR (%s)"), cpuid_error()); return 2; } return 0; } /* MSRs static values provided by libcpuid */ static int call_libcpuid_msr_static(Labels *data) { int min_mult, max_mult, bclk; struct msr_driver_t *msr = NULL; if(libcpuid_init_msr(&msr)) return 1; MSG_VERBOSE(_("Calling libcpuid for retrieving CPU MSR static values")); /* CPU Multipliers (minimum & maximum) */ min_mult = cpu_msrinfo(msr, INFO_MIN_MULTIPLIER); max_mult = cpu_msrinfo(msr, INFO_MAX_MULTIPLIER); if(min_mult != CPU_INVALID_VALUE && max_mult != CPU_INVALID_VALUE) { data->cpu_min_mult = (double) min_mult / 100; data->cpu_max_mult = (double) max_mult / 100; } /* Base clock */ bclk = cpu_msrinfo(msr, INFO_BCLK); if(bclk != CPU_INVALID_VALUE && data->bus_freq == 0.0) data->bus_freq = (double) bclk / 100; #ifdef HAVE_MSR_SERIALIZE_RAW_DATA if(opts->issue) msr_serialize_raw_data(msr, ""); #endif /* HAVE_MSR_SERIALIZE_RAW_DATA */ return cpu_msr_driver_close(msr); } /* MSRs dynamic values provided by libcpuid */ static int call_libcpuid_msr_dynamic(Labels *data) { int voltage, temp; struct msr_driver_t *msr = NULL; if(libcpuid_init_msr(&msr)) return 1; MSG_VERBOSE(_("Calling libcpuid for retrieving CPU MSR dynamic values")); /* CPU Voltage */ voltage = cpu_msrinfo(msr, INFO_VOLTAGE); if(voltage != CPU_INVALID_VALUE) casprintf(&data->tab_cpu[VALUE][VOLTAGE], true, "%.3f V", (double) voltage / 100); /* CPU Temperature */ temp = cpu_msrinfo(msr, INFO_TEMPERATURE); if(temp != CPU_INVALID_VALUE) casprintf(&data->tab_cpu[VALUE][TEMPERATURE], true, "%i°C", temp); return cpu_msr_driver_close(msr); } #endif /* HAS_LIBCPUID */ /* Fill the Multiplier label with the most appropriate format */ static int cputab_fill_multipliers(Labels *data) { if(data->cpu_freq <= 0 || data->bus_freq <= 0.0) return 1; MSG_VERBOSE(_("Calculating CPU multipliers")); const int fmt = (data->cpu_max_mult < 10) ? 1 : 0; const double cur_mult = (double) data->cpu_freq / data->bus_freq; if(data->cpu_min_mult <= 0.0 && data->cpu_max_mult <= 0.0) casprintf(&data->tab_cpu[VALUE][MULTIPLIER], false, "x %.2f", cur_mult); else if(data->cpu_min_mult <= 0.0 && data->cpu_max_mult > 0.0) casprintf(&data->tab_cpu[VALUE][MULTIPLIER], false, "x%.1f (?-%.*f)", cur_mult, fmt, data->cpu_max_mult); else if(data->cpu_min_mult > 0.0 && data->cpu_max_mult <= 0.0) casprintf(&data->tab_cpu[VALUE][MULTIPLIER], false, "x%.1f (%.*f-?)", cur_mult, fmt, data->cpu_min_mult); else casprintf(&data->tab_cpu[VALUE][MULTIPLIER], false, "x%.1f (%.*f-%.*f)", cur_mult, fmt, data->cpu_min_mult, fmt, data->cpu_max_mult); return 0; } #if HAS_DMIDECODE /* Call Dmidecode through CPU-X but do nothing else */ int run_dmidecode(void) { opt.type = NULL; opt.flags = (opts->verbose) ? 0 : FLAG_QUIET; return dmidecode(); } /* Elements provided by dmidecode (need root privileges) */ static int call_dmidecode(Labels *data) { int i, err; /* Dmidecode options */ opt.type = NULL; opt.flags = FLAG_CPU_X | FLAG_QUIET; if(getuid()) { MSG_WARNING(_("Skip call to dmidecode (need to be root)")); return 1; } MSG_VERBOSE(_("Calling dmidecode")); opt.type = calloc(256, sizeof(uint8_t)); if(opt.type == NULL) { MSG_ERRNO(_("failed to allocate memory for dmidecode")); return 2; } /* Tab CPU */ dmidata[DMI_CPU][0] = &data->tab_cpu[VALUE][PACKAGE]; ext_clk = &data->bus_freq; opt.type[4] = 1; /* Tab Motherboard */ for(i = MANUFACTURER; i < LASTMOTHERBOARD; i++) dmidata[DMI_MB][i] = &data->tab_motherboard[VALUE][i]; opt.type[0] = 1; opt.type[2] = 1; /* Tab RAM */ for(i = BANK0; i < LASTMEMORY; i++) dmidata[DMI_RAM][i] = &data->tab_memory[VALUE][i]; bank = &data->dimm_count; opt.type[17] = 1; /* Call built-in dmidecode in CPU-X mode */ if((err = dmidecode())) MSG_ERROR(_("failed to call dmidecode")); free(opt.type); return err; } #endif /* HAS_DMIDECODE */ /* Calculate total CPU usage */ static int cpu_usage(Labels *data) { static long *pre = NULL; long *new = NULL; double loadavg; enum StatType { USER, NICE, SYSTEM, INTR, IDLE, LASTSTAT }; MSG_VERBOSE(_("Calculating CPU usage")); if(pre == NULL) pre = calloc(LASTSTAT, sizeof(long)); new = calloc(LASTSTAT, sizeof(long)); if(new == NULL || pre == NULL) return 1; #ifdef __linux__ FILE *fp; fp = fopen("/proc/stat","r"); fscanf(fp,"%*s %li %li %li %li %*s %*s %*s %*s %*s %*s", &new[USER], &new[NICE], &new[SYSTEM], &new[IDLE]); fclose(fp); #else size_t len = sizeof(new) * LASTSTAT; if(sysctlbyname("kern.cp_time", new, &len, NULL, 0)) return 1; #endif /* __linux__ */ loadavg = (double)((new[USER] + new[NICE] + new[SYSTEM] + new[INTR]) - (pre[USER] + pre[NICE] + pre[SYSTEM] + pre[INTR])) / ((new[USER] + new[NICE] + new[SYSTEM] + new[INTR] + new[IDLE]) - (pre[USER] + pre[NICE] + pre[SYSTEM] + pre[INTR] + pre[IDLE])); casprintf(&data->tab_cpu[VALUE][USAGE], false, "%6.2f %%", loadavg * 100); memcpy(pre, new, LASTSTAT * sizeof(long)); free(new); return 0; } #if HAS_BANDWIDTH /* Call Bandwidth through CPU-X but do nothing else */ int run_bandwidth(void) { char *argv[] = { NULL, "--fastest", NULL }; return bandwidth_main(2, argv); } /* Compute CPU cache speed */ static int call_bandwidth(Labels *data) { static bool first = true; int i, err; pthread_t tid; if(data->w_data->size[0] < 1) return 1; MSG_VERBOSE(_("Calling bandwidth")); /* Run bandwidth in a separated thread */ err = pthread_create(&tid, NULL, (void *)bandwidth_cpux, data); if(first) { err += pthread_join(tid, NULL); first = false; } else err += pthread_detach(tid); /* Speed labels */ for(i = 0; i < LASTCACHES / CACHEFIELDS; i++) casprintf(&data->tab_caches[VALUE][i * CACHEFIELDS + L1SPEED], true, "%.2f MB/s", (double) data->w_data->speed[i] / 10); return err; } #endif /* HAS_BANDWIDTH */ #if HAS_LIBPCI #define DRIVER_IS(str) strstr(buff, str) != NULL /* Find driver name for a device */ static int find_driver(struct pci_dev *dev, char *buff, Labels *data) { /* Taken from http://git.kernel.org/cgit/utils/pciutils/pciutils.git/tree/ls-kernel.c */ int n; char name[MAXSTR], error_str[MAXSTR] = "unknown"; char *base = NULL, *drv = NULL, *tmp = NULL; enum EnGpuDrv *gpu_driver = &data->g_data->gpu_driver[data->gpu_count]; MSG_VERBOSE(_("Finding graphic card driver")); *gpu_driver = GPUDRV_UNKNOWN; if(dev->access->method != PCI_ACCESS_SYS_BUS_PCI) GOTO_ERROR("dev->access->method"); if((base = pci_get_param(dev->access, "sysfs.path")) == NULL) GOTO_ERROR("pci_get_param"); casprintf(&data->g_data->device_path[data->gpu_count], false, "%s/devices/%04x:%02x:%02x.%d", base, dev->domain, dev->bus, dev->dev, dev->func); snprintf(name, MAXSTR, "%s/driver", data->g_data->device_path[data->gpu_count]); if((n = readlink(name, buff, MAXSTR)) <= 0) GOTO_ERROR("readlink"); buff[n] = '\0'; if((drv = strrchr(buff, '/')) != NULL) strcpy(buff, drv + 1); if(DRIVER_IS("fglrx")) *gpu_driver = GPUDRV_FGLRX; else if(DRIVER_IS("amdgpu")) *gpu_driver = GPUDRV_AMDGPU; else if(DRIVER_IS("radeon")) *gpu_driver = GPUDRV_RADEON; else if(DRIVER_IS("i915")) *gpu_driver = GPUDRV_INTEL; else if(DRIVER_IS("nvidia")) *gpu_driver = GPUDRV_NVIDIA; else if(DRIVER_IS("nouveau")) *gpu_driver = GPUDRV_NOUVEAU; else MSG_WARNING(_("Your GPU driver is unknown: %s"), buff); snprintf(name, MAXSTR, _("(%s driver)"), buff); strcpy(buff, name); /* Check for discrete GPU */ switch(*gpu_driver) { case GPUDRV_NVIDIA: if(!popen_to_str(&tmp, "optirun --status") && (strstr(tmp, "Bumblebee status: Ready") != NULL)) *gpu_driver = GPUDRV_NVIDIA_BUMBLEBEE; break; default: break; } free(tmp); return 0; error: MSG_ERROR(_("failed to find graphic card driver (%s)"), error_str); return 1; } #define DEVICE_VENDOR_STR(d) pci_lookup_name(pacc, buff, MAXSTR, PCI_LOOKUP_VENDOR, d->vendor_id, d->device_id) #define DEVICE_PRODUCT_STR(d) pci_lookup_name(pacc, buff, MAXSTR, PCI_LOOKUP_DEVICE, d->vendor_id, d->device_id) /* Find some PCI devices, like chipset and GPU */ static int find_devices(Labels *data) { /* Adapted from http://git.kernel.org/cgit/utils/pciutils/pciutils.git/tree/example.c */ bool chipset_found = false; char *gpu_vendor; char buff[MAXSTR] = ""; struct pci_access *pacc; struct pci_dev *dev; MSG_VERBOSE(_("Finding devices")); pacc = pci_alloc(); /* Get the pci_access structure */ #ifdef __FreeBSD__ if(access(pci_get_param(pacc, "fbsd.path"), W_OK)) { MSG_WARNING(_("Skip devices search (need to be root)")); return 1; } #endif /* __FreeBSD__ */ pci_init(pacc); /* Initialize the PCI library */ pci_scan_bus(pacc); /* We want to get the list of devices */ /* Iterate over all devices */ for(dev = pacc->devices; dev != NULL; dev = dev->next) { pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); /* Looking for chipset */ if(!chipset_found && (dev->device_class == PCI_CLASS_BRIDGE_ISA)) { casprintf(&data->tab_motherboard[VALUE][CHIPVENDOR], false, DEVICE_VENDOR_STR(dev)); casprintf(&data->tab_motherboard[VALUE][CHIPMODEL], false, DEVICE_PRODUCT_STR(dev)); chipset_found = true; } /* Looking for GPU */ if((data->gpu_count < LASTGRAPHICS / GPUFIELDS) && ((dev->device_class >> 8) == PCI_BASE_CLASS_DISPLAY)) { switch(dev->vendor_id) { case 0x1002: gpu_vendor = "AMD"; break; case 0x8086: gpu_vendor = "Intel"; break; case 0x10DE: gpu_vendor = "NVIDIA"; break; default: gpu_vendor = DEVICE_VENDOR_STR(dev); MSG_WARNING(_("Your GPU vendor is unknown: %s (%#X)"), gpu_vendor, dev->vendor_id); } find_driver(dev, buff, data); casprintf(&data->tab_graphics[VALUE][GPU1VENDOR + data->gpu_count * GPUFIELDS], false, "%s %s", gpu_vendor, buff); casprintf(&data->tab_graphics[VALUE][GPU1MODEL + data->gpu_count * GPUFIELDS], false, DEVICE_PRODUCT_STR(dev)); data->gpu_count++; } } pci_cleanup(pacc); if(!chipset_found) MSG_ERROR(_("failed to find chipset vendor and model")); if(!data->gpu_count) MSG_ERROR(_("failed to find graphic card vendor and model")); return !chipset_found + !data->gpu_count; } #endif /* HAS_LIBPCI */ /* Check is GPU is enabled */ static bool gpu_is_on(enum EnGpuDrv gpu_driver) { bool ret = false; char *buff = NULL; switch(gpu_driver) { case GPUDRV_NVIDIA_BUMBLEBEE: ret = !popen_to_str(&buff, "optirun --status") && (strstr(buff, "Discrete video card is on") != NULL); break; default: ret = true; } free(buff); return ret; } /* Retrieve GPU temperature */ static int gpu_temperature(Labels *data) { #ifdef __linux__ int ret; double divisor = 1.0; uint8_t i, failed_count = 0, fglrx_count = 0, nvidia_count = 0; char *buff = NULL; static bool once_error = true; static char *cached_paths[LASTGRAPHICS / GPUFIELDS] = { NULL }; MSG_VERBOSE(_("Retrieving GPU temperature")); for(i = 0; i < data->gpu_count; i++) { ret = 0; if(!gpu_is_on(data->g_data->gpu_driver[i])) { asprintf(&data->tab_graphics[VALUE][GPU1TEMPERATURE + i * GPUFIELDS], _("Off")); continue; } switch(data->g_data->gpu_driver[i]) { case GPUDRV_FGLRX: ret = popen_to_str(&buff, "aticonfig --adapter=%1u --odgt | awk '/Sensor/ { print $5 }'", fglrx_count++); break; case GPUDRV_NVIDIA: ret = popen_to_str(&buff, "nvidia-settings -tq [gpu:%1u]/GPUCoreTemp", nvidia_count++); break; case GPUDRV_NVIDIA_BUMBLEBEE: ret = popen_to_str(&buff, "optirun -b none nvidia-settings -c :8 -tq [gpu:%1u]/GPUCoreTemp", nvidia_count++); break; case GPUDRV_AMDGPU: case GPUDRV_RADEON: case GPUDRV_NOUVEAU: divisor = 1000.0; if(cached_paths[i] == NULL) ret = request_sensor_path(format("%s/hwmon", data->g_data->device_path[i]), &cached_paths[i], RQT_GPU_TEMPERATURE); if(!ret && (cached_paths[i] != NULL)) ret = fopen_to_str(&buff, cached_paths[i]); break; default: // Unsupported feature, like GPUDRV_INTEL continue; } if(!ret) casprintf(&data->tab_graphics[VALUE][GPU1TEMPERATURE + i * GPUFIELDS], true, "%.2f°C", atof(buff) / divisor); else failed_count++; free(buff); buff = NULL; } if(once_error && failed_count) MSG_ERROR(_("failed to retrieve GPU temperature")); once_error = false; return (failed_count == data->gpu_count); #else return 0; #endif /* __linux__ */ } #ifdef __linux__ /* Perform functions if run as root, else print warning message once */ static bool gpu_do_if_root(void) { const bool is_root = !getuid(); static bool init = false; if(!is_root && !init) MSG_WARNING(_("Skip some GPU values (need to be root)")); init = true; return is_root; } #endif /* __linux__ */ /* Retrieve GPU clocks */ static int gpu_clocks(Labels *data) { #ifdef __linux__ int ret, ret_load, ret_gclk, ret_mclk; uint8_t i, failed_count = 0, fglrx_count = 0, nvidia_count = 0; char card_number; char *gclk = NULL, *mclk = NULL, *load = NULL; static bool once_error = true; static char *cached_paths[LASTGRAPHICS / GPUFIELDS] = { NULL }; MSG_VERBOSE(_("Retrieving GPU clocks")); for(i = 0; i < data->gpu_count; i++) { ret = 0; ret_load = 0; ret_gclk = 0; ret_mclk = 0; if(!gpu_is_on(data->g_data->gpu_driver[i])) { free(data->tab_graphics[VALUE][GPU1USAGE + i * GPUFIELDS]); free(data->tab_graphics[VALUE][GPU1CORECLOCK + i * GPUFIELDS]); free(data->tab_graphics[VALUE][GPU1MEMCLOCK + i * GPUFIELDS]); data->tab_graphics[VALUE][GPU1USAGE + i * GPUFIELDS] = NULL; data->tab_graphics[VALUE][GPU1CORECLOCK + i * GPUFIELDS] = NULL; data->tab_graphics[VALUE][GPU1MEMCLOCK + i * GPUFIELDS] = NULL; continue; } switch(data->g_data->gpu_driver[i]) { case GPUDRV_AMDGPU: case GPUDRV_INTEL: case GPUDRV_RADEON: if(cached_paths[i] == NULL) ret = request_sensor_path(format("%s/drm", data->g_data->device_path[i]), &cached_paths[i], RQT_GPU_DRM); if(ret || (cached_paths[i] == NULL)) continue; break; default: break; } switch(data->g_data->gpu_driver[i]) { case GPUDRV_AMDGPU: card_number = cached_paths[i][strlen(cached_paths[i]) - 1]; ret_load = gpu_do_if_root() ? popen_to_str(&load, "awk '/GPU Load/ { print $3 }' %s/%c/amdgpu_pm_info", SYS_DRI, card_number) : -1; ret_gclk = popen_to_str(&gclk, "awk -v FS='(: |Mhz)' '/*/ { print $2 }' %s/device/pp_dpm_sclk", cached_paths[i]); ret_mclk = popen_to_str(&mclk, "awk -v FS='(: |Mhz)' '/*/ { print $2 }' %s/device/pp_dpm_mclk", cached_paths[i]); break; case GPUDRV_FGLRX: ret_load = popen_to_str(&load, "aticonfig --adapter=%1u --odgc | awk '/GPU load/ { print $4 }'", fglrx_count); ret_gclk = popen_to_str(&gclk, "aticonfig --adapter=%1u --odgc | awk '/Current Clocks/ { print $4 }'", fglrx_count); ret_mclk = popen_to_str(&mclk, "aticonfig --adapter=%1u --odgc | awk '/Current Clocks/ { print $5 }'", fglrx_count++); break; case GPUDRV_INTEL: ret_load = -1; ret_gclk = fopen_to_str(&gclk, "%s/gt_cur_freq_mhz", cached_paths[i]); ret_mclk = -1; break; case GPUDRV_RADEON: card_number = cached_paths[i][strlen(cached_paths[i]) - 1]; ret_load = -1; ret_gclk = gpu_do_if_root() ? popen_to_str(&gclk, "awk -v FS='(sclk: | mclk:)' 'NR==2{print $2}' %s/%c/radeon_pm_info", SYS_DRI, card_number) : -1; ret_mclk = gpu_do_if_root() ? popen_to_str(&mclk, "awk -v FS='(mclk: | vddc:)' 'NR==2{print $2}' %s/%c/radeon_pm_info", SYS_DRI, card_number) : -1; if((gclk != NULL) && (strlen(gclk) >= 2)) gclk[strlen(gclk) - 2] = '\0'; if((mclk != NULL) && (strlen(mclk) >= 2)) mclk[strlen(mclk) - 2] = '\0'; break; case GPUDRV_NVIDIA: ret_load = popen_to_str(&load, "nvidia-settings -tq [gpu:%1u]/GPUUtilization | awk -F '[,= ]' '{ print $2 }'", nvidia_count); ret_gclk = popen_to_str(&gclk, "nvidia-settings -tq [gpu:%1u]/GPUCurrentClockFreqs | awk -F '[,]' '{ print $1 }'", nvidia_count); ret_mclk = popen_to_str(&mclk, "nvidia-settings -tq [gpu:%1u]/GPUCurrentClockFreqs | awk -F '[,]' '{ print $2 }'", nvidia_count++); break; case GPUDRV_NVIDIA_BUMBLEBEE: ret_load = popen_to_str(&load, "optirun -b none nvidia-settings -c :8 -tq [gpu:%1u]/GPUUtilization | awk -F '[,= ]' '{ print $2 }'", nvidia_count); ret_gclk = popen_to_str(&gclk, "optirun -b none nvidia-settings -c :8 -tq [gpu:%1u]/GPUCurrentClockFreqs | awk -F '[,]' '{ print $1 }'", nvidia_count); ret_mclk = popen_to_str(&mclk, "optirun -b none nvidia-settings -c :8 -tq [gpu:%1u]/GPUCurrentClockFreqs | awk -F '[,]' '{ print $2 }'", nvidia_count++); break; default: if(once_error) MSG_WARNING(_("Driver for GPU %i doesn't report frequencies"), i); continue; } if(!ret_load) casprintf(&data->tab_graphics[VALUE][GPU1USAGE + i * GPUFIELDS], false, "%s%%", load); if(!ret_gclk) casprintf(&data->tab_graphics[VALUE][GPU1CORECLOCK + i * GPUFIELDS], true, "%s MHz", gclk); if(!ret_mclk) casprintf(&data->tab_graphics[VALUE][GPU1MEMCLOCK + i * GPUFIELDS], true, "%s MHz", mclk); if(ret_load && ret_gclk && ret_mclk) failed_count++; free(load); free(gclk); free(mclk); load = NULL; gclk = NULL; mclk = NULL; } if(once_error && failed_count) MSG_ERROR(_("failed to retrieve GPU clocks")); once_error = false; return (failed_count == data->gpu_count); #else return 0; #endif /* __linux__ */ } /* Satic elements for System tab, OS specific */ static int system_static(Labels *data) { int err = 0; struct utsname name; MSG_VERBOSE(_("Identifying running system")); err = uname(&name); if(err) MSG_ERRNO(_("failed to identify running system")); else { casprintf(&data->tab_system[VALUE][KERNEL], false, "%s %s", name.sysname, name.release); /* Kernel label */ casprintf(&data->tab_system[VALUE][HOSTNAME], false, "%s", name.nodename); /* Hostname label */ } /* Compiler label */ err += popen_to_str(&data->tab_system[VALUE][COMPILER], "cc --version"); #ifdef __linux__ /* Distribution label */ err += popen_to_str(&data->tab_system[VALUE][DISTRIBUTION], "grep PRETTY_NAME= /etc/os-release | awk -F '\"|\"' '{print $2}'"); #else char tmp[MAXSTR]; size_t len = sizeof(tmp); /* Overwrite Kernel label */ err += sysctlbyname("kern.osrelease", &tmp, &len, NULL, 0); casprintf(&data->tab_system[VALUE][KERNEL], false, tmp); /* Distribution label */ err += sysctlbyname("kern.ostype", &tmp, &len, NULL, 0); casprintf(&data->tab_system[VALUE][DISTRIBUTION], false, tmp); #endif /* __linux__ */ return err; } /* Dynamic elements for System tab, provided by libprocps/libstatgrab */ static int system_dynamic(Labels *data) { int err = 0, i, j = 0; time_t uptime_s = 0; struct tm *tm; MemoryData *m_data = data->m_data; #if HAS_LIBPROCPS const int div = 1e3; MSG_VERBOSE(_("Calling libprocps")); /* System uptime */ uptime_s = (time_t) uptime(NULL, NULL); /* Memory variables */ meminfo(); m_data->mem_usage[BARUSED] = kb_main_used / div; m_data->mem_usage[BARBUFFERS] = kb_main_buffers / div; m_data->mem_usage[BARCACHED] = kb_main_cached / div; m_data->mem_usage[BARFREE] = kb_main_free / div; m_data->mem_usage[BARSWAP] = kb_swap_used / div; m_data->mem_total = kb_main_total / div; m_data->swap_total = kb_swap_total / div; #endif /* HAS_LIBPROCPS */ #if HAS_LIBSTATGRAB static bool called = false; const int div = 1e6; sg_mem_stats *mem; /* Memory labels */ sg_swap_stats *swap; sg_host_info *info; MSG_VERBOSE(_("Calling libstatgrab")); /* Libstatgrab initialization */ if(!called) { err += sg_init(0); called = true; } mem = sg_get_mem_stats(NULL); swap = sg_get_swap_stats(NULL); info = sg_get_host_info(NULL); /* System uptime */ uptime_s = info->uptime; /* Memory variables */ m_data->mem_usage[BARUSED] = mem->used / div; m_data->mem_usage[BARBUFFERS] = 0; m_data->mem_usage[BARCACHED] = mem->cache / div; m_data->mem_usage[BARFREE] = mem->free / div; m_data->mem_usage[BARSWAP] = swap->used / div; m_data->mem_total = mem->total / div; m_data->swap_total = swap->total / div; #endif /* HAS_LIBSTATGRAB */ /* Memory labels */ for(i = USED; i < SWAP; i++) casprintf(&data->tab_system[VALUE][i], false, "%5u MB / %5u MB", m_data->mem_usage[j++], m_data->mem_total); casprintf(&data->tab_system[VALUE][SWAP], false, "%5u MB / %5u MB", m_data->mem_usage[j], m_data->swap_total); /* Uptime label */ tm = gmtime(&uptime_s); casprintf(&data->tab_system[VALUE][UPTIME], false, _("%i days, %i hours, %i minutes, %i seconds"), tm->tm_yday, tm->tm_hour, tm->tm_min, tm->tm_sec); return err; } /* Compute all prime numbers in 'duration' seconds */ static void *primes_bench(void *p_data) { uint64_t i, num, sup; Labels *data = p_data; BenchData *b_data = data->b_data; while(b_data->elapsed < b_data->duration * 60 && b_data->run) { /* b_data->num is shared by all threads */ pthread_mutex_lock(&b_data->mutex_num); b_data->num++; num = b_data->num; pthread_mutex_unlock(&b_data->mutex_num); /* Slow mode: loop from i to num, prime if num == i Fast mode: loop from i to sqrt(num), prime if num mod i != 0 */ sup = b_data->fast_mode ? sqrt(num) : num; for(i = 2; (i < sup) && (num % i != 0); i++); if((b_data->fast_mode && num % i) || (!b_data->fast_mode && num == i)) { pthread_mutex_lock(&b_data->mutex_primes); b_data->primes++; pthread_mutex_unlock(&b_data->mutex_primes); } /* Only the first thread compute elapsed time */ if(b_data->first_thread == pthread_self()) b_data->elapsed = (clock() - b_data->start) / CLOCKS_PER_SEC / b_data->threads; } if(b_data->first_thread == pthread_self()) { b_data->run = false; pthread_mutex_destroy(&b_data->mutex_num); pthread_mutex_destroy(&b_data->mutex_primes); } return NULL; } /* Report score of benchmarks */ static int benchmark_status(Labels *data) { char *buff = NULL; BenchData *b_data = data->b_data; enum EnTabBench ind = b_data->fast_mode ? PRIMEFASTSCORE : PRIMESLOWSCORE; MSG_VERBOSE(_("Updating benchmark status")); asprintf(&data->tab_bench[VALUE][PARAMDURATION], _("%u mins"), data->b_data->duration); asprintf(&data->tab_bench[VALUE][PARAMTHREADS], "%u", data->b_data->threads); asprintf(&data->tab_bench[VALUE][PRIMESLOWRUN], _("Inactive")); asprintf(&data->tab_bench[VALUE][PRIMEFASTRUN], _("Inactive")); if(b_data->primes == 0) { asprintf(&data->tab_bench[VALUE][PRIMESLOWSCORE], _("Not started")); asprintf(&data->tab_bench[VALUE][PRIMEFASTSCORE], _("Not started")); return 0; } if(b_data->run) asprintf(&data->tab_bench[VALUE][ind + 1], _("Active")); if(b_data->run) { if(b_data->duration * 60 - b_data->elapsed > 60 * 59) asprintf(&buff, _("(%u hours left)"), (b_data->duration - b_data->elapsed / 60) / 60); else if(b_data->duration * 60 - b_data->elapsed >= 60) asprintf(&buff, _("(%u minutes left)"), b_data->duration - b_data->elapsed / 60); else asprintf(&buff, _("(%u seconds left)"), b_data->duration * 60 - b_data->elapsed); } else { if(b_data->elapsed >= 60 * 60) asprintf(&buff, _("in %u hours"), b_data->elapsed / 60 / 60); else if(b_data->elapsed >= 60) asprintf(&buff, _("in %u minutes"), b_data->elapsed / 60); else asprintf(&buff, _("in %u seconds"), b_data->elapsed); } asprintf(&data->tab_bench[VALUE][ind], "%'u %s", b_data->primes, buff); free(buff); return 0; } /* Perform a multithreaded benchmark (compute prime numbers) */ void start_benchmarks(Labels *data) { int err = 0; unsigned i; pthread_t *t_id = NULL; BenchData *b_data = data->b_data; MSG_VERBOSE(_("Starting benchmark")); b_data->run = true; b_data->elapsed = 0; b_data->num = 2; b_data->primes = 1; b_data->start = clock(); t_id = malloc(sizeof(pthread_t) * b_data->threads); if(t_id == NULL) { MSG_ERRNO(_("failed to allocate memory for benchmark")); return; } err += pthread_mutex_init(&b_data->mutex_num, NULL); err += pthread_mutex_init(&b_data->mutex_primes, NULL); for(i = 0; i < b_data->threads; i++) err += pthread_create(&t_id[i], NULL, primes_bench, data); b_data->first_thread = t_id[0]; free(t_id); if(err) MSG_ERROR(_("an error occurred while starting benchmark")); } /************************* Fallback functions (static) *************************/ #if HAS_LIBCPUID /* If dmidecode fails to find CPU package, check in database */ static int cputab_package_fallback(Labels *data) { int i = -1; const Package_DB *db; LibcpuidData *l_data = data->l_data; if(l_data->cpu_vendor_id < 0 || data->tab_cpu[VALUE][CODENAME] == NULL || data->tab_cpu[VALUE][SPECIFICATION] == NULL) return 1; MSG_VERBOSE(_("Finding CPU package in fallback mode")); if(l_data->cpu_vendor_id == VENDOR_INTEL) db = package_intel; else if(l_data->cpu_vendor_id == VENDOR_AMD) db = package_amd; else db = package_unknown; while(db[++i].codename != NULL) { if((strstr(data->tab_cpu[VALUE][CODENAME], db[i].codename) != NULL) && ((db[i].model == NULL) || (strstr(data->tab_cpu[VALUE][SPECIFICATION], db[i].model) != NULL))) { casprintf(&data->tab_cpu[VALUE][PACKAGE], false, db[i].socket); return 0; } } MSG_WARNING(_("Your CPU socket does not belong in database ==> %s, codename: %s"), data->tab_cpu[VALUE][SPECIFICATION], data->tab_cpu[VALUE][CODENAME]); data->tab_cpu[VALUE][PACKAGE][0] = '\0'; return 2; } #endif /* HAS_LIBCPUID */ /* Get minimum and maximum CPU multipliers */ static int cputab_multipliers_fallback(Labels *data) { int err = 0; if(data->bus_freq <= 0) return 1; #ifdef __linux__ char *min_freq_str = NULL; char *max_freq_str = NULL; MSG_VERBOSE(_("Calculating CPU multipliers in fallback mode")); /* Minimum multiplier */ if(!(err = fopen_to_str(&min_freq_str, "%s%i/cpufreq/cpuinfo_min_freq", SYS_CPU, opts->selected_core))) { data->cpu_min_mult = round((strtod(min_freq_str, NULL) / 1000) / data->bus_freq); free(min_freq_str); } /* Maximum multiplier */ if(!(err = fopen_to_str(&max_freq_str, "%s%i/cpufreq/cpuinfo_max_freq", SYS_CPU, opts->selected_core))) { data->cpu_max_mult = round((strtod(max_freq_str, NULL) / 1000) / data->bus_freq); free(max_freq_str); } #endif /* __linux__ */ return err; } /* Retrieve missing Motherboard data if run as regular user */ static int motherboardtab_fallback(Labels *data) { int err = 0; #ifdef __linux__ int i; const char *id[] = { "board_vendor", "board_name", "board_version", "bios_vendor", "bios_version", "bios_date", NULL }; MSG_VERBOSE(_("Retrieving motherboard informations in fallback mode")); /* Tab Motherboard */ for(i = 0; id[i] != NULL; i++) err += fopen_to_str(&data->tab_motherboard[VALUE][i], "%s/%s", SYS_DMI, id[i]); #endif /* __linux__ */ if(err) MSG_ERROR(_("failed to retrieve motherboard informations (fallback mode)")); return err; } /* Check is string is empty (e.g. contains only non printable characters) */ static bool string_is_empty(char *str) { int i; if(str == NULL) return true; for(i = 0; (!isalnum(str[i])) && (str[i] != '\0'); i++); return (str[i] == '\0'); } /* Retrieve static data if other functions failed */ static int fallback_mode_static(Labels *data) { int err = 0; if(HAS_LIBCPUID && (string_is_empty(data->tab_cpu[VALUE][PACKAGE]) || strstr(data->tab_cpu[VALUE][PACKAGE], "CPU") != NULL || strstr(data->tab_cpu[VALUE][PACKAGE], "Microprocessor") != NULL)) err += cputab_package_fallback(data); if(data->cpu_min_mult <= 0.0 || data->cpu_max_mult <= 0.0) err += cputab_multipliers_fallback(data); if(string_is_empty(data->tab_motherboard[VALUE][MANUFACTURER]) || string_is_empty(data->tab_motherboard[VALUE][MBMODEL]) || string_is_empty(data->tab_motherboard[VALUE][REVISION]) || string_is_empty(data->tab_motherboard[VALUE][BRAND]) || string_is_empty(data->tab_motherboard[VALUE][BIOSVERSION]) || string_is_empty(data->tab_motherboard[VALUE][DATE])) err += motherboardtab_fallback(data); return err; } /************************* Fallback functions (dynamic) *************************/ /* Retrieve CPU temperature if run as regular user */ static int cputab_temp_fallback(Labels *data) { int err = 0; #ifdef __linux__ char *temp; static bool module_loaded = false; static char **cached_paths = NULL; # if HAS_LIBCPUID /* Load kernel modules */ if(!module_loaded && (data->l_data->cpu_vendor_id == VENDOR_INTEL)) module_loaded = load_module("coretemp"); else if(!module_loaded && (data->l_data->cpu_vendor_id == VENDOR_AMD) && (data->l_data->cpu_ext_family <= 0x8)) module_loaded = load_module("k8temp"); else if(!module_loaded && (data->l_data->cpu_vendor_id == VENDOR_AMD) && (data->l_data->cpu_ext_family >= 0x10)) module_loaded = load_module("k10temp"); # endif /* HAS_LIBCPUID */ MSG_VERBOSE(_("Retrieving CPU temperature in fallback mode")); /* Filenames are cached */ if(cached_paths == NULL) cached_paths = calloc(data->cpu_count, sizeof(char *)); if(!cached_paths[opts->selected_core]) if((err = request_sensor_path(SYS_HWMON, &cached_paths[opts->selected_core], RQT_CPU_TEMPERATURE))) err = request_sensor_path(SYS_HWMON, &cached_paths[opts->selected_core], RQT_CPU_TEMPERATURE_OTHERS); if(!err && cached_paths[opts->selected_core]) { if(!(err = fopen_to_str(&temp, cached_paths[opts->selected_core]))) { casprintf(&data->tab_cpu[VALUE][TEMPERATURE], true, "%.2f°C", atof(temp) / 1000.0); free(temp); } } else MSG_ERROR(_("failed to retrieve CPU temperature (fallback mode)")); #endif /* __linux__ */ return err; } /* Retrieve CPU voltage if run as regular user */ static int cputab_volt_fallback(Labels *data) { int err = 0; #ifdef __linux__ char *voltage; static char *cached_path = NULL; MSG_VERBOSE(_("Retrieving CPU voltage in fallback mode")); if(cached_path == NULL) err = request_sensor_path(SYS_HWMON, &cached_path, RQT_CPU_VOLTAGE); if(!err && (cached_path != NULL)) { if(!(err = fopen_to_str(&voltage, cached_path))) { casprintf(&data->tab_cpu[VALUE][VOLTAGE], true, "%.3f V", atof(voltage) / 1000.0); free(voltage); } } else MSG_ERROR(_("failed to retrieve CPU voltage (fallback mode)")); #endif /* __linux__ */ return err; } /* Retrieve CPU frequency if Libcpuid is missing */ static int cputab_freq_fallback(Labels *data) { int err = 0; #ifdef __linux__ char *freq; MSG_VERBOSE(_("Retrieving CPU frequency in fallback mode")); if(!(err = fopen_to_str(&freq, "%s%i/cpufreq/scaling_cur_freq", SYS_CPU, opts->selected_core))) { data->cpu_freq = (int) round(strtod(freq, NULL) / 1000.0); casprintf(&data->tab_cpu[VALUE][CORESPEED], true, "%d MHz", data->cpu_freq); free(freq); } else MSG_ERROR(_("failed to retrieve CPU frequency (fallback mode)")); #endif /* __linux__ */ return err; } /* Retrieve dynamic data if other functions failed */ static int fallback_mode_dynamic(Labels *data) { enum FallbackDynamic { TEMP, VOLT, FREQ, LASTFALLBACK }; static bool use_fallback[LASTFALLBACK] = { false }; int err = 0; if(string_is_empty(data->tab_cpu[VALUE][TEMPERATURE]) || use_fallback[TEMP]) { use_fallback[TEMP] = true; err += err_func(cputab_temp_fallback, data); } if(string_is_empty(data->tab_cpu[VALUE][VOLTAGE]) || use_fallback[VOLT]) { use_fallback[VOLT] = true; err += err_func(cputab_volt_fallback, data); } if(string_is_empty(data->tab_cpu[VALUE][CORESPEED]) || use_fallback[FREQ] || opts->freq_fallback) { use_fallback[FREQ] = true; err += err_func(cputab_freq_fallback, data); } return err; } CPU-X-3.2.4/src/core.h000066400000000000000000000060571341671471500142650ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE core.h */ #ifndef _CORE_H_ #define _CORE_H_ #include "cpu-x.h" #if HAS_LIBPCI # include "pci/pci.h" #endif /* Avoid to re-run a function if an error was occurred in previous call */ static int err_func(int (*func)(Labels *), Labels *data); /* Static elements provided by libcpuid */ static int call_libcpuid_static(Labels *data); /* Required: HAS_LIBCPUID */ /* Dynamic elements provided by libcpuid */ static int call_libcpuid_dynamic(Labels *data); /* Required: HAS_LIBCPUID */ /* MSRs static values provided by libcpuid */ static int call_libcpuid_msr_static(Labels *data); /* Required: HAS_LIBCPUID && root privileges */ /* MSRs dynamic values provided by libcpuid */ static int call_libcpuid_msr_dynamic(Labels *data); /* Required: HAS_LIBCPUID && root privileges */ /* Fill the Multiplier label with the most appropriate format */ static int cputab_fill_multipliers(Labels *data); /* Required: none Both normal and fallback mode provide CPU multipliers, need to be call after */ /* Elements provided by dmidecode (need root privileges) */ static int call_dmidecode(Labels *data); /* Required: HAS_DMIDECODE && root privileges */ /* Compute CPU cache speed */ static int call_bandwidth(Labels *data); /* Required: HAS_BANDWIDTH */ /* Calculate total CPU usage */ static int cpu_usage(Labels *data); /* Required: none */ /* Find some PCI devices, like chipset and GPU */ static int find_devices(Labels *data); /* Required: HAS_LIBPCI */ /* Retrieve GPU temperature */ static int gpu_temperature(Labels *data); /* Required: none */ /* Retrieve GPU clocks */ static int gpu_clocks(Labels *data); /* Required: none */ /* Satic elements for System tab, OS specific */ static int system_static(Labels *data); /* Required: none */ /* Dynamic elements for System tab, provided by libprocps/libstatgrab */ static int system_dynamic(Labels *data); /* Required: HAS_LIBPROCPS || HAS_LIBSTATGRAB */ /* Report score of benchmarks */ static int benchmark_status(Labels *data); /* Required: none */ /* Retrieve static data if other functions failed */ static int fallback_mode_static(Labels *data); /* Retrieve dynamic data if other functions failed */ static int fallback_mode_dynamic(Labels *data); #endif /* _CORE_H_ */ CPU-X-3.2.4/src/cpu-x.h000066400000000000000000000235411341671471500143660ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE core.h */ #ifndef _CPUX_H_ #define _CPUX_H_ #include #include #include #include #define HAVE_STDINT_H /* Skip conflicts with */ /* Software definition */ #define PRGNAME "CPU-X" #define PRGAUTH "X0rg" #define PRGURL "https://X0rg.github.io/CPU-X" #define UPDURL "https://api.github.com/repos/"PRGAUTH"/"PRGNAME"/releases/latest" #define DOWNLOAD "https://github.com/"PRGAUTH"/"PRGNAME"/releases/latest" #define PRGCPRGHT "Copyright © 2014-2019 Xorg" #define PRGLCNS "GNU GPL v3" #define LCNSURL "https://www.gnu.org/licenses/gpl.txt" /* Colors definition */ #define DEFAULT "\x1b[0m" #define BOLD_RED "\x1b[1;31m" #define BOLD_GREEN "\x1b[1;32m" #define BOLD_YELLOW "\x1b[1;33m" #define BOLD_BLUE "\x1b[1;34m" /* Utilities macro */ #define LOCATION PRGNAME, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__ #define GOTO_ERROR(str) { snprintf(error_str, MAXSTR, str); goto error; } /* Formatted messages definition */ #define MSG_STDOUT(fmt, ...) fprintf(stdout, colorized_msg(DEFAULT, "%s", fmt), ##__VA_ARGS__) #define MSG_STDERR(fmt, ...) fprintf(stderr, colorized_msg(DEFAULT, "%s", fmt), ##__VA_ARGS__) #define MSG_VERBOSE(fmt, ...) opts->verbose ? fprintf(stdout, colorized_msg(BOLD_GREEN, "%s", fmt), ##__VA_ARGS__) : 0 #define MSG_WARNING(fmt, ...) fprintf(stdout, colorized_msg(BOLD_YELLOW, "%s", fmt), ##__VA_ARGS__) #define MSG_ERROR(fmt, ...) fprintf(stderr, colorized_msg(BOLD_RED, "%s:%s:%i: %s", LOCATION, fmt), ##__VA_ARGS__) #define MSG_ERRNO(fmt, ...) fprintf(stderr, colorized_msg(BOLD_RED, "%s:%s:%i: %s (%s)", LOCATION, fmt, strerror(errno)), ##__VA_ARGS__) #define _(msg) gettext(msg) #define N_(msg) msg /* Options definition */ #define OUT_GTK (1 << 0) #define OUT_NCURSES (1 << 1) #define OUT_DUMP (1 << 2) #define OUT_NO_CPUX (1 << 10) #define OUT_DMIDECODE (1 << 11) #define OUT_BANDWIDTH (1 << 12) /* Arrays definition */ #define NAME 0 #define VALUE 1 #define MAXSTR 80 /* Max string */ #define CACHEFIELDS 2 /* Nb of fields by cache frame */ #define RAMFIELDS 2 /* Nb of fields by bank */ #define GPUFIELDS 6 /* Nb of fields by GPU frame */ #define BENCHFIELDS 2 /* Nb of fields by bench frame */ /* Linux-specific paths definition */ #define SYS_DMI "/sys/devices/virtual/dmi/id" #define SYS_CPU "/sys/devices/system/cpu/cpu" #define SYS_DRM "/sys/class/drm/card" #define SYS_HWMON "/sys/class/hwmon" #define SYS_DRI "/sys/kernel/debug/dri" enum EnTabNumber { NO_CPU, NO_CACHES, NO_MOTHERBOARD, NO_MEMORY, NO_SYSTEM, NO_GRAPHICS, NO_BENCH, NO_ABOUT }; enum EnObjects { TABCPU, TABCACHES, TABMOTHERBOARD, TABMEMORY, TABSYSTEM, TABGRAPHICS, TABBENCH, TABABOUT, FRAMPROCESSOR, FRAMCLOCKS, FRAMCACHE, FRAML1CACHE, FRAML2CACHE, FRAML3CACHE, FRAML4CACHE, FRAMTEST, FRAMMOTHERBOARD, FRAMBIOS, FRAMCHIPSET, FRAMBANK0, FRAMBANK1, FRAMBANK2, FRAMBANK3, FRAMBANK4, FRAMBANK5, FRAMBANK6, FRAMBANK7, FRAMOPERATINGSYSTEM, FRAMMEMORY, FRAMGPU1, FRAMGPU2, FRAMGPU3, FRAMGPU4, FRAMPRIMESLOW, FRAMPRIMEFAST, FRAMPARAM, FRAMABOUT, FRAMLICENSE, LASTOBJ }; enum EnTabCpu { VENDOR, CODENAME, PACKAGE, TECHNOLOGY, VOLTAGE, SPECIFICATION, FAMILY, EXTFAMILY, MODEL, EXTMODEL, TEMPERATURE, STEPPING, INSTRUCTIONS, CORESPEED, MULTIPLIER, BUSSPEED, USAGE, LEVEL1D, LEVEL1I, LEVEL2, LEVEL3, SOCKETS, CORES, THREADS, LASTCPU }; enum EnTabCaches { L1SIZE, L1SPEED, L2SIZE, L2SPEED, L3SIZE, L3SPEED, L4SIZE, L4SPEED, LASTCACHES }; enum EnTabMotherboard { MANUFACTURER, MBMODEL, REVISION, BRAND, BIOSVERSION, DATE, ROMSIZE, CHIPVENDOR, CHIPMODEL, LASTMOTHERBOARD }; enum EnTabMemory { BANK0, BANK1, BANK2, BANK3, BANK4, BANK5, BANK6, BANK7, LASTMEMORY }; enum EnTabSystem { KERNEL, DISTRIBUTION, HOSTNAME, UPTIME, COMPILER, USED, BUFFERS, CACHED, FREE, SWAP, LASTSYSTEM }; enum EnTabSystemExtra { BARUSED, BARBUFFERS, BARCACHED, BARFREE, BARSWAP, LASTBAR }; enum EnTabGraphics { GPU1VENDOR, GPU1MODEL, GPU1TEMPERATURE, GPU1USAGE, GPU1CORECLOCK, GPU1MEMCLOCK, GPU2VENDOR, GPU2MODEL, GPU2TEMPERATURE, GPU2USAGE, GPU2CORECLOCK, GPU2MEMCLOCK, GPU3VENDOR, GPU3MODEL, GPU3TEMPERATURE, GPU3USAGE, GPU3CORECLOCK, GPU3MEMCLOCK, GPU4VENDOR, GPU4MODEL, GPU4TEMPERATURE, GPU4USAGE, GPU4CORECLOCK, GPU4MEMCLOCK, LASTGRAPHICS }; enum EnGpuDrv { GPUDRV_FGLRX, GPUDRV_AMDGPU, GPUDRV_RADEON, // AMD GPUDRV_INTEL, // Intel GPUDRV_NVIDIA, GPUDRV_NVIDIA_BUMBLEBEE, GPUDRV_NOUVEAU, // NVIDIA GPUDRV_UNKNOWN }; enum EnTabBench { PRIMESLOWSCORE, PRIMESLOWRUN, PRIMEFASTSCORE, PRIMEFASTRUN, PARAMDURATION, PARAMTHREADS, LASTBENCH }; enum EnTabAbout { DESCRIPTION, VERSIONSTR, AUTHOR, SITE, COPYRIGHT, LICENSE, NOWARRANTY, LASTABOUT }; typedef struct { int8_t cpu_vendor_id; int32_t cpu_model, cpu_ext_model, cpu_ext_family; char *cpuid_raw_file; } LibcpuidData; typedef struct { uint8_t test_count; uint32_t size[LASTCACHES / CACHEFIELDS]; uint32_t speed[LASTCACHES / CACHEFIELDS]; char **test_name; } BandwidthData; typedef struct { uint32_t mem_usage[SWAP - USED + 1]; uint32_t mem_total; uint32_t swap_total; } MemoryData; typedef struct { enum EnGpuDrv gpu_driver[LASTGRAPHICS / GPUFIELDS]; char *device_path[LASTGRAPHICS / GPUFIELDS]; } GraphicsData; typedef struct { bool run, fast_mode; unsigned duration, threads; uint32_t primes, start, elapsed; uint64_t num; pthread_t first_thread; pthread_mutex_t mutex_num, mutex_primes; } BenchData; typedef struct { char *objects[LASTOBJ]; char *tab_cpu[2][LASTCPU]; char *tab_caches[2][LASTCACHES]; char *tab_motherboard[2][LASTMOTHERBOARD]; char *tab_memory[2][LASTMEMORY]; char *tab_system[2][LASTSYSTEM]; char *tab_graphics[2][LASTGRAPHICS]; char *tab_bench[2][LASTBENCH]; char *tab_about[LASTABOUT]; int cpu_freq; uint8_t cpu_count, cache_count, dimm_count, gpu_count; double bus_freq, cpu_min_mult, cpu_max_mult; LibcpuidData *l_data; BandwidthData *w_data; MemoryData *m_data; GraphicsData *g_data; BenchData *b_data; } Labels; typedef struct { bool color, verbose, issue, use_network, update, debug_database, freq_fallback; uint8_t selected_page, selected_core, bw_test; uint16_t output_type, refr_time; } Options; typedef struct { char **dim_names; char **dim_values; int last; } Arrays; extern Options *opts; extern char *binary_name, *new_version[2]; /***************************** Defined in main.c *****************************/ /* Free memory after display labels */ void labels_free(Labels *data); /***************************** Defined in util.c *****************************/ /* An asprintf-like function, but which can clean some parts of 'str' if 'clean_str' is true * - It calls vasprintf if 'fmt' is a valid string * - If 'clean_str' is true, it removes "unvalid args" from 'str' until next "valid arg" E.g.: casprintf(&str, false, "%i nm", 0): str = "0 nm" casprintf(&str, true, "%i nm", 0): str = "" casprintf(&str, true, "%i nm", 32): str = "32 nm" casprintf(&str, true, "%i KB %i-way", -1, 12): str = "12-way" */ int casprintf(char **str, bool clean_str, const char *fmt, ...); /* Return a formatted string */ char *format(char *str, ...); /* Similar to format(), but string can be colorized */ char *colorized_msg(const char *color, const char *str, ...); /* Check if a command exists */ bool command_exists(char *command); /* Open a file and put its content in a variable ('str' accept printf-like format) */ int fopen_to_str(char **buffer, char *str, ...); /* Run a command and put output in a variable ('str' accept printf-like format) */ int popen_to_str(char **buffer, char *str, ...); /* Load a kernel module */ bool load_module(char *module); /* Get a filename located in a directory corresponding to given request */ enum RequestSensor { RQT_CPU_TEMPERATURE, RQT_CPU_TEMPERATURE_OTHERS, RQT_CPU_VOLTAGE, RQT_GPU_TEMPERATURE, RQT_GPU_DRM }; int request_sensor_path(char *base_dir, char **cached_path, enum RequestSensor which); /***************************** External headers *****************************/ /* Fill labels by calling core functions */ int fill_labels(Labels *data); /* Refresh some labels */ int do_refresh(Labels *data); /* Call Dmidecode through CPU-X but do nothing else */ int run_dmidecode(void); /* Call Bandwidth through CPU-X but do nothing else */ int run_bandwidth(void); /* Perform a multithreaded benchmark (compute prime numbers) */ void start_benchmarks(Labels *data); /* Start CPU-X in GTK mode */ void start_gui_gtk(int *argc, char **argv[], Labels *data); /* Start CPU-X in NCurses mode */ void start_tui_ncurses(Labels *data); #endif /* _CPUX_H_ */ CPU-X-3.2.4/src/databases.h000066400000000000000000000204121341671471500152530ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE databases.h */ #ifndef _DATABASES_H_ #define _DATABASES_H_ /****************************** CPU Technology ******************************/ typedef struct { const int32_t cpu_model; const int32_t cpu_ext_model; const int32_t cpu_ext_family; const int process; } Technology_DB; const Technology_DB technology_unknown[] = { { -1, -1, -1, -1 } }; const Technology_DB technology_intel[] = { //Model E. Model E. Family Process { 0, 0, -1, 180 }, // P4 Willamette { 1, 1, 6, 350 }, // Pentium Pro { 1, 1, 15, 180 }, // P4 Willamette { 2, 2, -1, 130 }, // P4 Northwood / Gallatin { 3, 3, 5, 350 }, // PII Overdrive { 3, 3, 6, 350 }, // PII Klamath { 3, 3, 15, 90 }, // P4 Prescott { 4, 4, -1, 90 }, // P4 Prescott/Irwindale / PD Smithfield { 5, 5, 6, 250 }, // PII Deschutes / Tonga / Xeon Drake / Celeron Covington { 5, 37, -1, 32 }, // Westmere { 5, 53, -1, 32 }, // Atom Cloverview { 5, 69, -1, 22 }, // Haswell { 5, 85, -1, 14 }, // Skylake (Xeon Scalable) { 6, 6, 6, 250 }, // PII Dixon / Celeron Mendocino { 6, 6, 15, 65 }, // P4 Cedar Mill / PD Presler { 6, 22, -1, 65 }, // C2 Conroe-L { 6, 54, -1, 32 }, // Atom Cedarview { 6, 70, -1, 22 }, // Haswell (Crystalwell, L4 cache) { 7, 7, -1, 250 }, // PIII Katmai { 7, 23, -1, 45 }, // C2 Wolfdale / Yorkfield / Penryn { 7, 55, -1, 22 }, // Atom Bay Trail { 7, 71, -1, 14 }, // Broadwell { 8, 0, 0, 180 }, // PIII Coppermine-T { 8, 8, -1, 180 }, // PIII Coppermine { 9, 9, -1, 130 }, // Pentium M Banias { 10, 26, -1, 45 }, // Nehalem { 10, 30, -1, 45 }, // Nehalem { 10, 42, -1, 32 }, // Sandy Bridge { 10, 58, -1, 22 }, // Ivy Bridge { 11, 11, -1, 130 }, // PIII Tualatine { 12, 28, -1, 45 }, // Atom Diamondville / Pineview / Silverthorne { 12, 44, -1, 32 }, // Westmere { 12, 60, -1, 22 }, // Haswell { 12, 76, -1, 14 }, // Atom Cherry Trail { 13, 13, -1, 90 }, // Pentium M Dothan { 13, 45, -1, 32 }, // Sandy Bridge-E { 13, 61, -1, 14 }, // Broadwell-U { 14, 14, -1, 65 }, // Yonah (Core Solo) { 14, 30, -1, 45 }, // Nehalem (Lynnfield) { 14, 62, -1, 22 }, // Ivy Bridge-E { 14, 78, -1, 14 }, // Skylake { 14, 94, -1, 14 }, // Skylake { 14, 158, -1, 14 }, // Kaby Lake / Coffee Lake { 15, 15, -1, 65 }, // C2 Conroe / Allendale / Kentsfield / Merom { 15, 63, -1, 22 }, // Haswell-E { 15, 79, -1, 14 }, // Broadwell-E { -1, -1, -1, -1 } //Model E. Model E. Family Process }; const Technology_DB technology_amd[] = { //Model E. Model E. Family Process { 0, 16, 21, 32 }, // Bulldozer (Piledriver: Trinity) { 0, 48, 21, 28 }, // Bulldozer (Steamroller: Kaveri) { 0, 112, 21, 28 }, // Bulldozer (Excavator: Stoney Ridge) { 0, -1, 22, 28 }, // Jaguar (Kabini/Mullins) { 1, -1, 18, 32 }, // K10 (Llano) { 1, -1, 20, 40 }, // Bobcat (Brazos Zacate) { 1, 1, 21, 32 }, // Bulldozer { 1, 96, 21, 28 }, // Bulldozer (Excavator: Carrizo) { 1, -1, 23, 14 }, // Zen (Summit Ridge/Raven Ridge) { 2, -1, 16, 65 }, // K10 (Kuma/Agena) { 2, -1, 20, 40 }, // Bobcat (Brazos Desna/Ontario) { 2, -1, 21, 32 }, // Bulldozer (Piledriver: Vishera) { 3, -1, 15, 90 }, // K8 (Toledo) { 3, -1, 21, 32 }, // Bulldozer (Piledriver: Richland) { 4, -1, 15, 90 }, // K8 (Lancaster) { 4, -1, 16, 45 }, // K10 (Deneb/Heka) { 5, -1, 16, 45 }, // K10 (Propus) { 5, -1, 21, 28 }, // Bulldozer (Excavator: Bristol Ridge) { 6, -1, 16, 45 }, // K10 (Champlain/Sargas/Regor) { 8, -1, 6, 130 }, // K7 (Thoroughbred/Applebred) { 8, -1, 15, 65 }, // K8 (Tyler) { 8, -1, 21, 28 }, // Bulldozer (Steamroller: Godavari) { 8, -1, 23, 12 }, // Zen+ (Pinnacle Ridge) { 9, -1, 16, 45 }, // Magny-Cours (Opteron) { 10, -1, 6, 130 }, // K7 (Barton) { 10, -1, 16, 45 }, // K10 (Thuban) { 11, -1, 15, 65 }, // K8 (Brisbane) { 12, -1, 15, 90 }, // K8 (Venice/Sonora) { 15, 79, 15, 90 }, // K8 (Manila) { 15, 127, 15, 65 }, // K8 (Sparta) { -1, -1, -1, -1 } //Model E. Model E. Family Process }; /****************************** CPU Package ******************************/ typedef struct { const char *codename; const char *model; const char *socket; } Package_DB; const Package_DB package_unknown[] = { { NULL, NULL, NULL } }; const Package_DB package_intel[] = { //Codename Model Socket { "Atom (Diamondville)", NULL, "BGA 437" }, { "Pentium D (SmithField)", NULL, "LGA 775" }, { "Pentium D (Presler)", NULL, "LGA 775" }, { "Bloomfield (Core i7)", NULL, "LGA 1366" }, { NULL, NULL, NULL } //Codename Model Socket }; const Package_DB package_amd[] = { //Codename Model Socket { "Athlon 64 FX X2 (Toledo)", NULL, "939 (PGA-ZIF)" }, { "Kabini X4", "Athlon", "AM1 (PGA-ZIF)" }, { "Kabini X4", "Sempron", "AM1 (PGA-ZIF)" }, { "Trinity X4", NULL, "FM2 (PGA-ZIF)" }, { "Turion X2", "TL", "S1g1 (PGA-ZIF)" }, { "Turion X2", "TK", "S1g1 (PGA-ZIF)" }, { NULL, NULL, NULL } //Codename Model Socket }; #endif /* _DATABASES_H_ */ CPU-X-3.2.4/src/dmidecode/000077500000000000000000000000001341671471500150715ustar00rootroot00000000000000CPU-X-3.2.4/src/dmidecode/AUTHORS000066400000000000000000000032651341671471500161470ustar00rootroot00000000000000DEVELOPER AND MAINTAINER Jean Delvare ORIGINAL AUTHORS Alan Cox Jean Delvare CODE CONTRIBUTORS (IN CHRONOLOGICAL ORDER) Matt Domsch Arjan van de Ven Mark D. Studebaker Larry Lile Dave Johnson Petter Reinholdtsen Roberto Nibali John Cagle Jens Elkner Jarod Wilson Anton Arapov Roy Franz Tyler Bell Xie XiuQi Petr Oros MANY THANKS TO (IN CHRONOLOGICAL ORDER) Werner Heuser Alexandre Duret-Lutz Xavier Roche Pamela Huntley Gael Stephan Sebastian Henschel Richard Sharpe David Wilson Glen Foster Chad Smith Joshua Goldenhar Luc Van de Velde Mario Lang Hugues Lepesant Sergey Leonovich Mike Cooper Marc Rieffel Jeff Moyer Josef Moellers Zing Zing Shishak Rafael Avila de Espindola Roger Koot Martin Pool Doug Brenner Alex Williamson Durval Menezes Raphael Raimbault Raul Nunez de Arenas Coronado Francois Revol Dominik Klein Erwan Velu Don Howard Frans Pop Tomek Mateja Myke Olson Torsten Seemann Garry Belka Klaus Muth Antoine Fuselier Matthew Garrett Landry Breuil Luke Suchocki Attila Nagy Alex Iribarren Sebastien Douche William Lallemand Olivier Guerrier Pascal Terjan Stuart Hayes Sofian Brabez Vincent Pelletier Andreas Gruenbacher Lin Li Thomas Hiller Paul Flo Williams Olof Johansson Alexandre Lissy Michal Svec Vojtech Pavlik Murlin Wenzel Harald Mueller-Ney Lars Mueller Thomas Mingarelli Andrey Matveyev Stefan Tauner Naga Chumbalkar Jens Rosenboom CPU-X-3.2.4/src/dmidecode/CMakeLists.txt000066400000000000000000000012511341671471500176300ustar00rootroot00000000000000project(dmidecode VERSION "3.1.20180620" LANGUAGES C ) # Config (dmidecode) set(DMIDECODE_DEBUG_FLAGS "-Wall -Wextra -Wuninitialized -Wno-shift-count-overflow") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DMIDECODE_DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DMIDECODE_DEBUG_FLAGS}") message(STATUS "Using built-in ${PROJECT_NAME}, version ${PROJECT_VERSION}") # Build (dmidecode) add_definitions(-DVERSION="${PROJECT_VERSION}") add_library(dmidecode STATIC types.h util.c util.h dmiopt.h dmioem.c dmioem.h dmidecode.c dmidecode.h libdmi.h ) target_link_libraries(dmidecode) set(DMIDECODE_VERSION ${PROJECT_VERSION} PARENT_SCOPE) CPU-X-3.2.4/src/dmidecode/LICENSE000066400000000000000000000432541341671471500161060ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. CPU-X-3.2.4/src/dmidecode/NEWS000066400000000000000000000123411341671471500155710ustar00rootroot00000000000000Version 3.1 (Tue May 23 2017) - Support for SMBIOS 3.1.0 and 3.1.1. This includes new chassis types, new processor family names, new processor family upgrade names, and new slot types, as well as support of larger BIOS ROM sizes and cache sizes, and a new structure type (43, TPM Device.) - A new command line option to query OEM strings. - All error messages are now printed on stderr (#47274, #48158.) - Several bug fixes related to 64-bit entry points (#50037 and more.) - Important bug fixes: #46176 (Unexpected end of file error) #46066 (Crash with SIGBUS) - Various minor fixes, improvements and cleanups. Version 3.0 (Thu Sep 03 2015) - Support for SMBIOS 3.0. This includes new chassis types, new processor family names, new processor family upgrade names, new slot types, and new memory device types. - Support for the new 64-bit entry point (_SM3_) defined in SMBIOS 3.0. - Support for the new kernel interface (as of Linux v4.2) as an alternative to relying /dev/mem to access the entry point and DMI table. - Decoding of Acer-specific DMI type 170. - Decoding of HP-specific DMI types 212, 219 and 233. - Various minor fixes and output format cleanups. Version 2.12 (Wed Apr 17 2013) - Support of the SMBIOS 2.8.0 specification. Version 2.11 (Wed Jan 19 2011) - Support of the SMBIOS 2.7.0 specification: - UEFI support - Virtual machine flags in BIOS characteristics - Limited support for the Management Controller Host Interface - Various fixes that address stability. Version 2.10 (Sun Nov 23 2008) - Support for Solaris (x86 only, of course). - Possibility to dump the SMBIOS/DMI table to a small binary file (option --dump-bin). - Possibility to read the SMBIOS/DMI table from such binary files (option --from-dump). - Support for SMBIOS 2.6. This includes new chassis types, new processor family names, new processor family upgrade names, bus address for system slots, and a new entry type for on-board devices, amongst many other minor changes. - Support for DMI entry type 31 (Boot integrity services). - Many processor family names taken from the CIM Schema document. - (vpddecode) No longer ask users to report broken records. - (vpddecode) Fix --quiet option. Version 2.9 (Mon Feb 26 2007) - Support of the SMBIOS 2.5 specification. It adds many enumerated values for recent hardware, as well as CPU core and thread count reporting. - Decoding of 3 HP-specific entries. More vendor-specific entries can be supported later if vendors contribute code or documentation. - Run-time detection of EFI, so that a single binary can support Intel-based Macintosh machines and regular x86 machines. - Better IA-64 support. - Fixes to the decoding of individual fields, including the CPU signature of recent CPU models. - (biosdecode) Support of the FJKEYINF entry point type (for Fujitsu laptops). - (vpddecode) The product name look-up table was dropped. It was unreliable and a burden to maintain. - biosdecode, ownership and vpddecode are no longer built on IA-64. Version 2.8 (Sat Feb 04 2006) - Option --string has four additional keywords available: system-uuid, chassis-type, processor-family and processor-frequency. These needed additional work because, technically speaking, they are not DMI strings. - IPMI interface type SSIF was added. This is a new interface type defined by IPMI 2.0. - (vpddecode) New --string option, much similar in spirit to dmidecode's. Available keywords are bios-build-id, box-serial-number, motherboard-serial-number, machine-type-model and bios-release-date. - (vpddecode) 9 product names were added to the lookup table. - A few bug fixes, cleanups and minor improvements all around the place. Version 2.7 (Thu Aug 04 2005) - New command line interface. For example, it is now possible to limit the output of dmidecode to a given DMI type, or to extract a single string from the DMI table. The documentation has been updated accordingly. - The default output of dmidecode was slightly modified to be more easily readable by humans. This might break tools parsing its output. Such tools may benefit from the new command line interface, although this interface shouldn't be considered stable until version 2.8. - (vpddecode) New command line interface. - (vpddecode) 6 product names were added. Version 2.6 (Mon Feb 28 2005) - Fixes a 2 GB memory limit regression. - Basic command-line handling. - BeOS and Cygwin support. Version 2.5 (Thu Nov 11 2004) - Code cleanups. - Compatibility fixes. - Documentation updates. Version 2.4 (Fri Mar 19 2004) - Manual pages added. - (vpddecode) Many improvements. - A few fixes and minor improvements. Version 2.3 (Sun Oct 19 2003) - Support of x86_64 systems. - Support of systems with 2 GB and more memory. - Loads of bug fixes and corrections. - New tool "vpddecode" added. Version 2.2 (Fri Aug 08 2003) - Support of IA-64 systems. - Support of IBM and Fujitsu-Siemens laptops. - Many minor bug fixes. - New tool "ownership" added. Version 2.1 (Tue Jun 10 2003) - Support of the SMBIOS 2.3.4 specification. - Better support of IPMI. - Minor bugs fixed. - Documentation added. CPU-X-3.2.4/src/dmidecode/README000066400000000000000000000110521341671471500157500ustar00rootroot00000000000000** INTRODUCTION ** Dmidecode reports information about your system's hardware as described in your system BIOS according to the SMBIOS/DMI standard. This information typically includes system manufacturer, model name, serial number, BIOS version, asset tag as well as a lot of other details of varying level of interest and reliability depending on the manufacturer. This will often include usage status for the CPU sockets, expansion slots (e.g. AGP, PCI, ISA) and memory module slots, and the list of I/O ports (e.g. serial, parallel, USB). DMI data can be used to enable or disable specific portions of kernel code depending on the specific hardware. Thus, one use of dmidecode is for kernel developers to detect system "signatures" and add them to the kernel source code when needed. Beware that DMI data have proven to be too unreliable to be blindly trusted. Dmidecode does not scan your hardware, it only reports what the BIOS told it to. ** INSTALLATION ** The home web page for dmidecode is hosted on Savannah: http://www.nongnu.org/dmidecode/ You will find the latest version (including CVS) there, as well as fresh news and other interesting material, such as a list of related projects and articles. This program was first written for Linux, and has since been reported to work on FreeBSD, NetBSD, OpenBSD, BeOS and Solaris as well. There's no configure script, so simply run "make" to build dmidecode, and "make install" to install it. You also can use "make uninstall" to remove all the files you installed. By default, files are installed in /usr/local but you can change this behavior by editing the Makefile file and setting prefix to wherever you want. You may change the C compiler and the compilation flags as well. Optionally, you can run "make strip" prior to "make install" if you want smaller binaries. However, be aware that this will prevent any further attempt to debug the programs. Two parameters can be set in the Makefile file to make dmidecode work on non-i386 systems. They should be used if your system uses the big endian byte ordering (Motorola) or doesn't support unaligned memory accesses, respectively. For example, compiling for a SPARC processor would require both (but I am not aware of SPARC-based systems implementing SMBIOS). Compiling for an IA64 processor requires the memory alignment workaround, and it is enabled automatically. ** DOCUMENTATION ** Each tool has a manual page, found in the "man" subdirectory. Manual pages are installed by "make install". See these manual pages for command line interface details and tool specific information. For an history of the changes made to dmidecode, see the NEWS file. If you need help, your best chances are to visit the web page (see the INSTALLATION section above) or to get in touch with the developers directly. Have a look at the AUTHORS file and contact one of the maintainers. If you want to help with the development of dmidecode, please consider joining the dmidecode-devel discussion list: http://lists.nongnu.org/mailman/listinfo/dmidecode-devel ** COMMON PROBLEMS ** IA-64 Non-Linux systems are not yet supported. MMAP Note that mmap() is now used by default wherever possible, since this seems to solve a number of problems. This default behavior can be changed in config.h. Just to make sure this is clear, mmap() is not used for performance reasons but to increase the number of systems on which dmidecode can be successfully run. CYGWIN Dmidecode used to work under Cygwin. However the /dev/mem interface was removed at some point in time so it no longer works. ** MISCELLANEOUS TOOLS ** Three other tools come along with dmidecode: biosdecode, ownership and vpddecode. These tools are only useful on systems with a BIOS, so they are not built on IA-64 by default. BIOSDECODE This one prints all BIOS related information it can find in /dev/mem. It used to be part of dmidecode itself, but as dmidecode was growing, we felt that the non-DMI part had to be moved to a separate tool. OWNERSHIP This tool was written on a request by Luc Van de Velde for use with Novell tools in his company. It retrieves the "ownership tag" that can be set on most Compaq computers. Since it uses the same mechanisms dmidecode and biosdecode use, and could be of some use for other people as well, we decided to make it part of the project. VPDDECODE This tool prints the contents of the "vital product data" structure as found in most IBM and Lenovo computers. It used to have a lookup table for the machine name, but it was unreliable and hard to maintain so it was ultimately dropped. It has a command line interface. CPU-X-3.2.4/src/dmidecode/README.md000066400000000000000000000017261341671471500163560ustar00rootroot00000000000000# Dmidecode: Desktop Management Interface table related utilities Distributed under the terms of the [GNU GPL v2](https://github.com/X0rg/CPU-X/blob/master/src/dmidecode/LICENSE). ### CPU-X NOTE This sofware has been patched to be used within CPU-X. You can find the official web page of this project here: https://savannah.nongnu.org/projects/dmidecode/ This is based on dmidecode 3.1+[r16.29e626f](https://git.savannah.gnu.org/cgit/dmidecode.git/commit/?id=29e626f6ed3edb72ebd2ca3fe0e1fbd956ab71a1). This software is used to retrieve following data: - CPU tab - Package - Bus speed (fallback) - Motherboard tab - Motherboard manufacturer - Motherboard model - Motherboard revision - BIOS brand - BIOS version - BIOS date - BIOS ROM size You can reproduce the output of `dmidecode` command by using `cpu-x --dmidecode`. It will dump all DMI data on standard output. Note: you can increase dmidecode verbosity by using `cpu-x --verbose --dmidecode`. CPU-X-3.2.4/src/dmidecode/config.h000066400000000000000000000007111341671471500165060ustar00rootroot00000000000000/* * Configuration */ #ifndef CONFIG_H #define CONFIG_H /* Default memory device file */ #if defined(__BEOS__) || defined(__HAIKU__) #define DEFAULT_MEM_DEV "/dev/misc/mem" #else #ifdef __sun #define DEFAULT_MEM_DEV "/dev/xsvc" #else #define DEFAULT_MEM_DEV "/dev/mem" #endif #endif /* Use mmap or not */ #ifndef __BEOS__ #define USE_MMAP #endif /* Use memory alignment workaround or not */ #ifdef __ia64__ #define ALIGNMENT_WORKAROUND #endif #endif CPU-X-3.2.4/src/dmidecode/dmidecode.c000066400000000000000000003742131341671471500171640ustar00rootroot00000000000000/* * DMI Decode * * Copyright (C) 2000-2002 Alan Cox * Copyright (C) 2002-2017 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For the avoidance of doubt the "preferred form" of this code is one which * is in an open unpatent encumbered format. Where cryptographic key signing * forms part of the process of creating an executable the information * including keys needed to generate an equivalently functional executable * are deemed to be part of the source code. * * Unless specified otherwise, all references are aimed at the "System * Management BIOS Reference Specification, Version 3.1.1" document, * available from http://www.dmtf.org/standards/smbios. * * Note to contributors: * Please reference every value you add or modify, especially if the * information does not come from the above mentioned specification. * * Additional references: * - Intel AP-485 revision 36 * "Intel Processor Identification and the CPUID Instruction" * http://www.intel.com/support/processors/sb/cs-009861.htm * - DMTF Common Information Model * CIM Schema version 2.19.1 * http://www.dmtf.org/standards/cim/ * - IPMI 2.0 revision 1.0 * "Intelligent Platform Management Interface Specification" * http://developer.intel.com/design/servers/ipmi/spec.htm * - AMD publication #25481 revision 2.28 * "CPUID Specification" * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf * - BIOS Integrity Services Application Programming Interface version 1.0 * http://www.intel.com/design/archives/wfm/downloads/bisspec.htm * - DMTF DSP0239 version 1.1.0 * "Management Component Transport Protocol (MCTP) IDs and Codes" * http://www.dmtf.org/standards/pmci * - "TPM Main, Part 2 TPM Structures" * Specification version 1.2, level 2, revision 116 * https://trustedcomputinggroup.org/tpm-main-specification/ * - "PC Client Platform TPM Profile (PTP) Specification" * Family "2.0", Level 00, Revision 00.43, January 26, 2015 * https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/ */ #include #include #include #include #include #ifdef __FreeBSD__ #include #include #endif #include "config.h" #include "types.h" #include "util.h" #include "dmidecode.h" #include "dmiopt.h" #include "dmioem.h" #include "libdmi.h" #define out_of_spec "" static const char *bad_index = ""; #define SUPPORTED_SMBIOS_VER 0x030101 #define FLAG_NO_FILE_OFFSET (1 << 0) #define FLAG_STOP_AT_EOT (1 << 1) #define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" #define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" #define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" /* Options are global */ struct opt opt; double *ext_clk; u8 *bank; char **dmidata[LASTDMI][16]; /* * Type-independant Stuff */ /* Returns 1 if the buffer contains only printable ASCII characters */ int is_printable(const u8 *data, int len) { int i; for (i = 0; i < len; i++) if (data[i] < 32 || data[i] >= 127) return 0; return 1; } const char *dmi_string(const struct dmi_header *dm, u8 s) { char *bp = (char *)dm->data; size_t i, len; if (s == 0) return "Not Specified"; bp += dm->length; while (s > 1 && *bp) { bp += strlen(bp); bp++; s--; } if (!*bp) return bad_index; if (!(opt.flags & FLAG_DUMP)) { /* ASCII filtering */ len = strlen(bp); for (i = 0; i < len; i++) if (bp[i] < 32 || bp[i] == 127) bp[i] = '.'; } return bp; } static const char *dmi_smbios_structure_type(u8 code) { static const char *type[] = { "BIOS", /* 0 */ "System", "Base Board", "Chassis", "Processor", "Memory Controller", "Memory Module", "Cache", "Port Connector", "System Slots", "On Board Devices", "OEM Strings", "System Configuration Options", "BIOS Language", "Group Associations", "System Event Log", "Physical Memory Array", "Memory Device", "32-bit Memory Error", "Memory Array Mapped Address", "Memory Device Mapped Address", "Built-in Pointing Device", "Portable Battery", "System Reset", "Hardware Security", "System Power Controls", "Voltage Probe", "Cooling Device", "Temperature Probe", "Electrical Current Probe", "Out-of-band Remote Access", "Boot Integrity Services", "System Boot", "64-bit Memory Error", "Management Device", "Management Device Component", "Management Device Threshold Data", "Memory Channel", "IPMI Device", "Power Supply", "Additional Information", "Onboard Device", "Management Controller Host Interface", "TPM Device", /* 43 */ }; if (code >= 128) return "OEM-specific"; if (code <= 43) return type[code]; return out_of_spec; } static int dmi_bcd_range(u8 value, u8 low, u8 high) { if (value > 0x99 || (value & 0x0F) > 0x09) return 0; if (value < low || value > high) return 0; return 1; } static void dmi_dump(const struct dmi_header *h, const char *prefix) { int row, i; const char *s; printf("%sHeader and Data:\n", prefix); for (row = 0; row < ((h->length - 1) >> 4) + 1; row++) { printf("%s\t", prefix); for (i = 0; i < 16 && i < h->length - (row << 4); i++) printf("%s%02X", i ? " " : "", (h->data)[(row << 4) + i]); printf("\n"); } if ((h->data)[h->length] || (h->data)[h->length + 1]) { printf("%sStrings:\n", prefix); i = 1; while ((s = dmi_string(h, i++)) != bad_index) { if (opt.flags & FLAG_DUMP) { int j, l = strlen(s) + 1; for (row = 0; row < ((l - 1) >> 4) + 1; row++) { printf("%s\t", prefix); for (j = 0; j < 16 && j < l - (row << 4); j++) printf("%s%02X", j ? " " : "", (unsigned char)s[(row << 4) + j]); printf("\n"); } /* String isn't filtered yet so do it now */ printf("%s\t\"", prefix); while (*s) { if (*s < 32 || *s == 127) fputc('.', stdout); else fputc(*s, stdout); s++; } printf("\"\n"); } else printf("%s\t%s\n", prefix, s); } } } /* shift is 0 if the value is in bytes, 1 if it is in kilobytes */ static void dmi_print_memory_size(u64 code, int shift) { unsigned long capacity; u16 split[7]; static const char *unit[8] = { "bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB" }; int i; /* * We split the overall size in powers of thousand: EB, PB, TB, GB, * MB, kB and B. In practice, it is expected that only one or two * (consecutive) of these will be non-zero. */ split[0] = code.l & 0x3FFUL; split[1] = (code.l >> 10) & 0x3FFUL; split[2] = (code.l >> 20) & 0x3FFUL; split[3] = ((code.h << 2) & 0x3FCUL) | (code.l >> 30); split[4] = (code.h >> 8) & 0x3FFUL; split[5] = (code.h >> 18) & 0x3FFUL; split[6] = code.h >> 28; /* * Now we find the highest unit with a non-zero value. If the following * is also non-zero, we use that as our base. If the following is zero, * we simply display the highest unit. */ for (i = 6; i > 0; i--) { if (split[i]) break; } if (i > 0 && split[i - 1]) { i--; capacity = split[i] + (split[i + 1] << 10); } else capacity = split[i]; printf(" %lu %s", capacity, unit[i + shift]); } /* * 7.1 BIOS Information (Type 0) */ static void dmi_bios_runtime_size(u32 code) { if (code & 0x000003FF) printf(" %u bytes", code); else printf(" %u kB", code >> 10); } static char *dmi_bios_runtime_size_str(u32 code) { static char size[24]; if (code & 0x000003FF) sprintf(size, "%u bytes", code); else sprintf(size, "%u kB", code >> 10); return size; } static void dmi_bios_rom_size(u8 code1, u16 code2) { static const char *unit[4] = { "MB", "GB", out_of_spec, out_of_spec }; if (code1 != 0xFF) printf(" %u kB", (code1 + 1) << 6); else printf(" %u %s", code2 & 0x3FFF, unit[code2 >> 14]); } static char *dmi_bios_rom_size_str(u8 code1, u16 code2) { static char size[16]; static const char *unit[4] = { "MB", "GB", out_of_spec, out_of_spec }; if (code1 != 0xFF) sprintf(size, "%u kB", (code1 + 1) << 6); else sprintf(size, "%u %s", code2 & 0x3FFF, unit[code2 >> 14]); return size; } static void dmi_bios_characteristics(u64 code, const char *prefix) { /* 7.1.1 */ static const char *characteristics[] = { "BIOS characteristics not supported", /* 3 */ "ISA is supported", "MCA is supported", "EISA is supported", "PCI is supported", "PC Card (PCMCIA) is supported", "PNP is supported", "APM is supported", "BIOS is upgradeable", "BIOS shadowing is allowed", "VLB is supported", "ESCD support is available", "Boot from CD is supported", "Selectable boot is supported", "BIOS ROM is socketed", "Boot from PC Card (PCMCIA) is supported", "EDD is supported", "Japanese floppy for NEC 9800 1.2 MB is supported (int 13h)", "Japanese floppy for Toshiba 1.2 MB is supported (int 13h)", "5.25\"/360 kB floppy services are supported (int 13h)", "5.25\"/1.2 MB floppy services are supported (int 13h)", "3.5\"/720 kB floppy services are supported (int 13h)", "3.5\"/2.88 MB floppy services are supported (int 13h)", "Print screen service is supported (int 5h)", "8042 keyboard services are supported (int 9h)", "Serial services are supported (int 14h)", "Printer services are supported (int 17h)", "CGA/mono video services are supported (int 10h)", "NEC PC-98" /* 31 */ }; int i; /* * This isn't very clear what this bit is supposed to mean */ if (code.l & (1 << 3)) { printf("%s%s\n", prefix, characteristics[0]); return; } for (i = 4; i <= 31; i++) if (code.l & (1 << i)) printf("%s%s\n", prefix, characteristics[i - 3]); } static void dmi_bios_characteristics_x1(u8 code, const char *prefix) { /* 7.1.2.1 */ static const char *characteristics[] = { "ACPI is supported", /* 0 */ "USB legacy is supported", "AGP is supported", "I2O boot is supported", "LS-120 boot is supported", "ATAPI Zip drive boot is supported", "IEEE 1394 boot is supported", "Smart battery is supported" /* 7 */ }; int i; for (i = 0; i <= 7; i++) if (code & (1 << i)) printf("%s%s\n", prefix, characteristics[i]); } static void dmi_bios_characteristics_x2(u8 code, const char *prefix) { /* 37.1.2.2 */ static const char *characteristics[] = { "BIOS boot specification is supported", /* 0 */ "Function key-initiated network boot is supported", "Targeted content distribution is supported", "UEFI is supported", "System is a virtual machine" /* 4 */ }; int i; for (i = 0; i <= 4; i++) if (code & (1 << i)) printf("%s%s\n", prefix, characteristics[i]); } /* * 7.2 System Information (Type 1) */ static void dmi_system_uuid(const u8 *p, u16 ver) { int only0xFF = 1, only0x00 = 1; int i; for (i = 0; i < 16 && (only0x00 || only0xFF); i++) { if (p[i] != 0x00) only0x00 = 0; if (p[i] != 0xFF) only0xFF = 0; } if (only0xFF) { printf("Not Present"); return; } if (only0x00) { printf("Not Settable"); return; } /* * As of version 2.6 of the SMBIOS specification, the first 3 * fields of the UUID are supposed to be encoded on little-endian. * The specification says that this is the defacto standard, * however I've seen systems following RFC 4122 instead and use * network byte order, so I am reluctant to apply the byte-swapping * for older versions. */ if (ver >= 0x0206) printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p[3], p[2], p[1], p[0], p[5], p[4], p[7], p[6], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); else printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } static const char *dmi_system_wake_up_type(u8 code) { /* 7.2.2 */ static const char *type[] = { "Reserved", /* 0x00 */ "Other", "Unknown", "APM Timer", "Modem Ring", "LAN Remote", "Power Switch", "PCI PME#", "AC Power Restored" /* 0x08 */ }; if (code <= 0x08) return type[code]; return out_of_spec; } /* * 7.3 Base Board Information (Type 2) */ static void dmi_base_board_features(u8 code, const char *prefix) { /* 7.3.1 */ static const char *features[] = { "Board is a hosting board", /* 0 */ "Board requires at least one daughter board", "Board is removable", "Board is replaceable", "Board is hot swappable" /* 4 */ }; if ((code & 0x1F) == 0) printf(" None\n"); else { int i; printf("\n"); for (i = 0; i <= 4; i++) if (code & (1 << i)) printf("%s%s\n", prefix, features[i]); } } static const char *dmi_base_board_type(u8 code) { /* 7.3.2 */ static const char *type[] = { "Unknown", /* 0x01 */ "Other", "Server Blade", "Connectivity Switch", "System Management Module", "Processor Module", "I/O Module", "Memory Module", "Daughter Board", "Motherboard", "Processor+Memory Module", "Processor+I/O Module", "Interconnect Board" /* 0x0D */ }; if (code >= 0x01 && code <= 0x0D) return type[code - 0x01]; return out_of_spec; } static void dmi_base_board_handles(u8 count, const u8 *p, const char *prefix) { int i; printf("%sContained Object Handles: %u\n", prefix, count); for (i = 0; i < count; i++) printf("%s\t0x%04X\n", prefix, WORD(p + sizeof(u16) * i)); } /* * 7.4 Chassis Information (Type 3) */ static const char *dmi_chassis_type(u8 code) { /* 7.4.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Desktop", "Low Profile Desktop", "Pizza Box", "Mini Tower", "Tower", "Portable", "Laptop", "Notebook", "Hand Held", "Docking Station", "All In One", "Sub Notebook", "Space-saving", "Lunch Box", "Main Server Chassis", /* CIM_Chassis.ChassisPackageType says "Main System Chassis" */ "Expansion Chassis", "Sub Chassis", "Bus Expansion Chassis", "Peripheral Chassis", "RAID Chassis", "Rack Mount Chassis", "Sealed-case PC", "Multi-system", "CompactPCI", "AdvancedTCA", "Blade", "Blade Enclosing", "Tablet", "Convertible", "Detachable", "IoT Gateway", "Embedded PC", "Mini PC", "Stick PC" /* 0x24 */ }; code &= 0x7F; /* bits 6:0 are chassis type, 7th bit is the lock bit */ if (code >= 0x01 && code <= 0x24) return type[code - 0x01]; return out_of_spec; } static const char *dmi_chassis_lock(u8 code) { static const char *lock[] = { "Not Present", /* 0x00 */ "Present" /* 0x01 */ }; return lock[code]; } static const char *dmi_chassis_state(u8 code) { /* 7.4.2 */ static const char *state[] = { "Other", /* 0x01 */ "Unknown", "Safe", "Warning", "Critical", "Non-recoverable" /* 0x06 */ }; if (code >= 0x01 && code <= 0x06) return state[code - 0x01]; return out_of_spec; } static const char *dmi_chassis_security_status(u8 code) { /* 7.4.3 */ static const char *status[] = { "Other", /* 0x01 */ "Unknown", "None", "External Interface Locked Out", "External Interface Enabled" /* 0x05 */ }; if (code >= 0x01 && code <= 0x05) return status[code - 0x01]; return out_of_spec; } static void dmi_chassis_height(u8 code) { if (code == 0x00) printf(" Unspecified"); else printf(" %u U", code); } static void dmi_chassis_power_cords(u8 code) { if (code == 0x00) printf(" Unspecified"); else printf(" %u", code); } static void dmi_chassis_elements(u8 count, u8 len, const u8 *p, const char *prefix) { int i; printf("%sContained Elements: %u\n", prefix, count); for (i = 0; i < count; i++) { if (len >= 0x03) { printf("%s\t%s (", prefix, p[i * len] & 0x80 ? dmi_smbios_structure_type(p[i * len] & 0x7F) : dmi_base_board_type(p[i * len] & 0x7F)); if (p[1 + i * len] == p[2 + i * len]) printf("%u", p[1 + i * len]); else printf("%u-%u", p[1 + i * len], p[2 + i * len]); printf(")\n"); } } } /* * 7.5 Processor Information (Type 4) */ static const char *dmi_processor_type(u8 code) { /* 7.5.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Central Processor", "Math Processor", "DSP Processor", "Video Processor" /* 0x06 */ }; if (code >= 0x01 && code <= 0x06) return type[code - 0x01]; return out_of_spec; } static const char *dmi_processor_family(const struct dmi_header *h, u16 ver) { const u8 *data = h->data; unsigned int i, low, high; u16 code; /* 7.5.2 */ static struct { int value; const char *name; } family2[] = { { 0x01, "Other" }, { 0x02, "Unknown" }, { 0x03, "8086" }, { 0x04, "80286" }, { 0x05, "80386" }, { 0x06, "80486" }, { 0x07, "8087" }, { 0x08, "80287" }, { 0x09, "80387" }, { 0x0A, "80487" }, { 0x0B, "Pentium" }, { 0x0C, "Pentium Pro" }, { 0x0D, "Pentium II" }, { 0x0E, "Pentium MMX" }, { 0x0F, "Celeron" }, { 0x10, "Pentium II Xeon" }, { 0x11, "Pentium III" }, { 0x12, "M1" }, { 0x13, "M2" }, { 0x14, "Celeron M" }, { 0x15, "Pentium 4 HT" }, { 0x18, "Duron" }, { 0x19, "K5" }, { 0x1A, "K6" }, { 0x1B, "K6-2" }, { 0x1C, "K6-3" }, { 0x1D, "Athlon" }, { 0x1E, "AMD29000" }, { 0x1F, "K6-2+" }, { 0x20, "Power PC" }, { 0x21, "Power PC 601" }, { 0x22, "Power PC 603" }, { 0x23, "Power PC 603+" }, { 0x24, "Power PC 604" }, { 0x25, "Power PC 620" }, { 0x26, "Power PC x704" }, { 0x27, "Power PC 750" }, { 0x28, "Core Duo" }, { 0x29, "Core Duo Mobile" }, { 0x2A, "Core Solo Mobile" }, { 0x2B, "Atom" }, { 0x2C, "Core M" }, { 0x2D, "Core m3" }, { 0x2E, "Core m5" }, { 0x2F, "Core m7" }, { 0x30, "Alpha" }, { 0x31, "Alpha 21064" }, { 0x32, "Alpha 21066" }, { 0x33, "Alpha 21164" }, { 0x34, "Alpha 21164PC" }, { 0x35, "Alpha 21164a" }, { 0x36, "Alpha 21264" }, { 0x37, "Alpha 21364" }, { 0x38, "Turion II Ultra Dual-Core Mobile M" }, { 0x39, "Turion II Dual-Core Mobile M" }, { 0x3A, "Athlon II Dual-Core M" }, { 0x3B, "Opteron 6100" }, { 0x3C, "Opteron 4100" }, { 0x3D, "Opteron 6200" }, { 0x3E, "Opteron 4200" }, { 0x3F, "FX" }, { 0x40, "MIPS" }, { 0x41, "MIPS R4000" }, { 0x42, "MIPS R4200" }, { 0x43, "MIPS R4400" }, { 0x44, "MIPS R4600" }, { 0x45, "MIPS R10000" }, { 0x46, "C-Series" }, { 0x47, "E-Series" }, { 0x48, "A-Series" }, { 0x49, "G-Series" }, { 0x4A, "Z-Series" }, { 0x4B, "R-Series" }, { 0x4C, "Opteron 4300" }, { 0x4D, "Opteron 6300" }, { 0x4E, "Opteron 3300" }, { 0x4F, "FirePro" }, { 0x50, "SPARC" }, { 0x51, "SuperSPARC" }, { 0x52, "MicroSPARC II" }, { 0x53, "MicroSPARC IIep" }, { 0x54, "UltraSPARC" }, { 0x55, "UltraSPARC II" }, { 0x56, "UltraSPARC IIi" }, { 0x57, "UltraSPARC III" }, { 0x58, "UltraSPARC IIIi" }, { 0x60, "68040" }, { 0x61, "68xxx" }, { 0x62, "68000" }, { 0x63, "68010" }, { 0x64, "68020" }, { 0x65, "68030" }, { 0x66, "Athlon X4" }, { 0x67, "Opteron X1000" }, { 0x68, "Opteron X2000" }, { 0x69, "Opteron A-Series" }, { 0x6A, "Opteron X3000" }, { 0x6B, "Zen" }, { 0x70, "Hobbit" }, { 0x78, "Crusoe TM5000" }, { 0x79, "Crusoe TM3000" }, { 0x7A, "Efficeon TM8000" }, { 0x80, "Weitek" }, { 0x82, "Itanium" }, { 0x83, "Athlon 64" }, { 0x84, "Opteron" }, { 0x85, "Sempron" }, { 0x86, "Turion 64" }, { 0x87, "Dual-Core Opteron" }, { 0x88, "Athlon 64 X2" }, { 0x89, "Turion 64 X2" }, { 0x8A, "Quad-Core Opteron" }, { 0x8B, "Third-Generation Opteron" }, { 0x8C, "Phenom FX" }, { 0x8D, "Phenom X4" }, { 0x8E, "Phenom X2" }, { 0x8F, "Athlon X2" }, { 0x90, "PA-RISC" }, { 0x91, "PA-RISC 8500" }, { 0x92, "PA-RISC 8000" }, { 0x93, "PA-RISC 7300LC" }, { 0x94, "PA-RISC 7200" }, { 0x95, "PA-RISC 7100LC" }, { 0x96, "PA-RISC 7100" }, { 0xA0, "V30" }, { 0xA1, "Quad-Core Xeon 3200" }, { 0xA2, "Dual-Core Xeon 3000" }, { 0xA3, "Quad-Core Xeon 5300" }, { 0xA4, "Dual-Core Xeon 5100" }, { 0xA5, "Dual-Core Xeon 5000" }, { 0xA6, "Dual-Core Xeon LV" }, { 0xA7, "Dual-Core Xeon ULV" }, { 0xA8, "Dual-Core Xeon 7100" }, { 0xA9, "Quad-Core Xeon 5400" }, { 0xAA, "Quad-Core Xeon" }, { 0xAB, "Dual-Core Xeon 5200" }, { 0xAC, "Dual-Core Xeon 7200" }, { 0xAD, "Quad-Core Xeon 7300" }, { 0xAE, "Quad-Core Xeon 7400" }, { 0xAF, "Multi-Core Xeon 7400" }, { 0xB0, "Pentium III Xeon" }, { 0xB1, "Pentium III Speedstep" }, { 0xB2, "Pentium 4" }, { 0xB3, "Xeon" }, { 0xB4, "AS400" }, { 0xB5, "Xeon MP" }, { 0xB6, "Athlon XP" }, { 0xB7, "Athlon MP" }, { 0xB8, "Itanium 2" }, { 0xB9, "Pentium M" }, { 0xBA, "Celeron D" }, { 0xBB, "Pentium D" }, { 0xBC, "Pentium EE" }, { 0xBD, "Core Solo" }, /* 0xBE handled as a special case */ { 0xBF, "Core 2 Duo" }, { 0xC0, "Core 2 Solo" }, { 0xC1, "Core 2 Extreme" }, { 0xC2, "Core 2 Quad" }, { 0xC3, "Core 2 Extreme Mobile" }, { 0xC4, "Core 2 Duo Mobile" }, { 0xC5, "Core 2 Solo Mobile" }, { 0xC6, "Core i7" }, { 0xC7, "Dual-Core Celeron" }, { 0xC8, "IBM390" }, { 0xC9, "G4" }, { 0xCA, "G5" }, { 0xCB, "ESA/390 G6" }, { 0xCC, "z/Architecture" }, { 0xCD, "Core i5" }, { 0xCE, "Core i3" }, { 0xD2, "C7-M" }, { 0xD3, "C7-D" }, { 0xD4, "C7" }, { 0xD5, "Eden" }, { 0xD6, "Multi-Core Xeon" }, { 0xD7, "Dual-Core Xeon 3xxx" }, { 0xD8, "Quad-Core Xeon 3xxx" }, { 0xD9, "Nano" }, { 0xDA, "Dual-Core Xeon 5xxx" }, { 0xDB, "Quad-Core Xeon 5xxx" }, { 0xDD, "Dual-Core Xeon 7xxx" }, { 0xDE, "Quad-Core Xeon 7xxx" }, { 0xDF, "Multi-Core Xeon 7xxx" }, { 0xE0, "Multi-Core Xeon 3400" }, { 0xE4, "Opteron 3000" }, { 0xE5, "Sempron II" }, { 0xE6, "Embedded Opteron Quad-Core" }, { 0xE7, "Phenom Triple-Core" }, { 0xE8, "Turion Ultra Dual-Core Mobile" }, { 0xE9, "Turion Dual-Core Mobile" }, { 0xEA, "Athlon Dual-Core" }, { 0xEB, "Sempron SI" }, { 0xEC, "Phenom II" }, { 0xED, "Athlon II" }, { 0xEE, "Six-Core Opteron" }, { 0xEF, "Sempron M" }, { 0xFA, "i860" }, { 0xFB, "i960" }, { 0x100, "ARMv7" }, { 0x101, "ARMv8" }, { 0x104, "SH-3" }, { 0x105, "SH-4" }, { 0x118, "ARM" }, { 0x119, "StrongARM" }, { 0x12C, "6x86" }, { 0x12D, "MediaGX" }, { 0x12E, "MII" }, { 0x140, "WinChip" }, { 0x15E, "DSP" }, { 0x1F4, "Video Processor" }, }; /* * Note to developers: when adding entries to this list, check if * function dmi_processor_id below needs updating too. */ /* Special case for ambiguous value 0x30 (SMBIOS 2.0 only) */ if (ver == 0x0200 && data[0x06] == 0x30 && h->length >= 0x08) { const char *manufacturer = dmi_string(h, data[0x07]); if (strstr(manufacturer, "Intel") != NULL || strncasecmp(manufacturer, "Intel", 5) == 0) return "Pentium Pro"; } code = (data[0x06] == 0xFE && h->length >= 0x2A) ? WORD(data + 0x28) : data[0x06]; /* Special case for ambiguous value 0xBE */ if (code == 0xBE) { if (h->length >= 0x08) { const char *manufacturer = dmi_string(h, data[0x07]); /* Best bet based on manufacturer string */ if (strstr(manufacturer, "Intel") != NULL || strncasecmp(manufacturer, "Intel", 5) == 0) return "Core 2"; if (strstr(manufacturer, "AMD") != NULL || strncasecmp(manufacturer, "AMD", 3) == 0) return "K7"; } return "Core 2 or K7"; } /* Perform a binary search */ low = 0; high = ARRAY_SIZE(family2) - 1; while (1) { i = (low + high) / 2; if (family2[i].value == code) return family2[i].name; if (low == high) /* Not found */ return out_of_spec; if (code < family2[i].value) high = i; else low = i + 1; } } static void dmi_processor_id(const struct dmi_header *h, const char *prefix) { /* Intel AP-485 revision 36, table 2-4 */ static const char *flags[32] = { "FPU (Floating-point unit on-chip)", /* 0 */ "VME (Virtual mode extension)", "DE (Debugging extension)", "PSE (Page size extension)", "TSC (Time stamp counter)", "MSR (Model specific registers)", "PAE (Physical address extension)", "MCE (Machine check exception)", "CX8 (CMPXCHG8 instruction supported)", "APIC (On-chip APIC hardware supported)", NULL, /* 10 */ "SEP (Fast system call)", "MTRR (Memory type range registers)", "PGE (Page global enable)", "MCA (Machine check architecture)", "CMOV (Conditional move instruction supported)", "PAT (Page attribute table)", "PSE-36 (36-bit page size extension)", "PSN (Processor serial number present and enabled)", "CLFSH (CLFLUSH instruction supported)", NULL, /* 20 */ "DS (Debug store)", "ACPI (ACPI supported)", "MMX (MMX technology supported)", "FXSR (FXSAVE and FXSTOR instructions supported)", "SSE (Streaming SIMD extensions)", "SSE2 (Streaming SIMD extensions 2)", "SS (Self-snoop)", "HTT (Multi-threading)", "TM (Thermal monitor supported)", NULL, /* 30 */ "PBE (Pending break enabled)" /* 31 */ }; const u8 *data = h->data; const u8 *p = data + 0x08; u32 eax, edx; int sig = 0; u16 type; type = (data[0x06] == 0xFE && h->length >= 0x2A) ? WORD(data + 0x28) : data[0x06]; /* * This might help learn about new processors supporting the * CPUID instruction or another form of identification. */ printf("%sID: %02X %02X %02X %02X %02X %02X %02X %02X\n", prefix, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); if (type == 0x05) /* 80386 */ { u16 dx = WORD(p); /* * 80386 have a different signature. */ printf("%sSignature: Type %u, Family %u, Major Stepping %u, Minor Stepping %u\n", prefix, dx >> 12, (dx >> 8) & 0xF, (dx >> 4) & 0xF, dx & 0xF); return; } if (type == 0x06) /* 80486 */ { u16 dx = WORD(p); /* * Not all 80486 CPU support the CPUID instruction, we have to find * wether the one we have here does or not. Note that this trick * works only because we know that 80486 must be little-endian. */ if ((dx & 0x0F00) == 0x0400 && ((dx & 0x00F0) == 0x0040 || (dx & 0x00F0) >= 0x0070) && ((dx & 0x000F) >= 0x0003)) sig = 1; else { printf("%sSignature: Type %u, Family %u, Model %u, Stepping %u\n", prefix, (dx >> 12) & 0x3, (dx >> 8) & 0xF, (dx >> 4) & 0xF, dx & 0xF); return; } } else if ((type >= 0x100 && type <= 0x101) /* ARM */ || (type >= 0x118 && type <= 0x119)) /* ARM */ { u32 midr = DWORD(p); /* * The format of this field was not defined for ARM processors * before version 3.1.0 of the SMBIOS specification, so we * silently skip it if it reads all zeroes. */ if (midr == 0) return; printf("%sSignature: Implementor 0x%02x, Variant 0x%x, Architecture %u, Part 0x%03x, Revision %u\n", prefix, midr >> 24, (midr >> 20) & 0xF, (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF); return; } else if ((type >= 0x0B && type <= 0x15) /* Intel, Cyrix */ || (type >= 0x28 && type <= 0x2F) /* Intel */ || (type >= 0xA1 && type <= 0xB3) /* Intel */ || type == 0xB5 /* Intel */ || (type >= 0xB9 && type <= 0xC7) /* Intel */ || (type >= 0xCD && type <= 0xCE) /* Intel */ || (type >= 0xD2 && type <= 0xDB) /* VIA, Intel */ || (type >= 0xDD && type <= 0xE0)) /* Intel */ sig = 1; else if ((type >= 0x18 && type <= 0x1D) /* AMD */ || type == 0x1F /* AMD */ || (type >= 0x38 && type <= 0x3F) /* AMD */ || (type >= 0x46 && type <= 0x4F) /* AMD */ || (type >= 0x66 && type <= 0x6B) /* AMD */ || (type >= 0x83 && type <= 0x8F) /* AMD */ || (type >= 0xB6 && type <= 0xB7) /* AMD */ || (type >= 0xE4 && type <= 0xEF)) /* AMD */ sig = 2; else if (type == 0x01 || type == 0x02) { const char *version = dmi_string(h, data[0x10]); /* * Some X86-class CPU have family "Other" or "Unknown". In this case, * we use the version string to determine if they are known to * support the CPUID instruction. */ if (strncmp(version, "Pentium III MMX", 15) == 0 || strncmp(version, "Intel(R) Core(TM)2", 18) == 0 || strncmp(version, "Intel(R) Pentium(R)", 19) == 0 || strcmp(version, "Genuine Intel(R) CPU U1400") == 0) sig = 1; else if (strncmp(version, "AMD Athlon(TM)", 14) == 0 || strncmp(version, "AMD Opteron(tm)", 15) == 0 || strncmp(version, "Dual-Core AMD Opteron(tm)", 25) == 0) sig = 2; else return; } else /* neither X86 nor ARM */ return; /* * Extra flags are now returned in the ECX register when one calls * the CPUID instruction. Their meaning is explained in table 3-5, but * DMI doesn't support this yet. */ eax = DWORD(p); edx = DWORD(p + 4); switch (sig) { case 1: /* Intel */ printf("%sSignature: Type %u, Family %u, Model %u, Stepping %u\n", prefix, (eax >> 12) & 0x3, ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F), ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F), eax & 0xF); break; case 2: /* AMD, publication #25481 revision 2.28 */ printf("%sSignature: Family %u, Model %u, Stepping %u\n", prefix, ((eax >> 8) & 0xF) + (((eax >> 8) & 0xF) == 0xF ? (eax >> 20) & 0xFF : 0), ((eax >> 4) & 0xF) | (((eax >> 8) & 0xF) == 0xF ? (eax >> 12) & 0xF0 : 0), eax & 0xF); break; } edx = DWORD(p + 4); printf("%sFlags:", prefix); if ((edx & 0xBFEFFBFF) == 0) printf(" None\n"); else { int i; printf("\n"); for (i = 0; i <= 31; i++) if (flags[i] != NULL && edx & (1 << i)) printf("%s\t%s\n", prefix, flags[i]); } } static void dmi_processor_voltage(u8 code) { /* 7.5.4 */ static const char *voltage[] = { "5.0 V", /* 0 */ "3.3 V", "2.9 V" /* 2 */ }; int i; if (code & 0x80) printf(" %.1f V", (float)(code & 0x7f) / 10); else { for (i = 0; i <= 2; i++) if (code & (1 << i)) printf(" %s", voltage[i]); if (code == 0x00) printf(" Unknown"); } } static void dmi_processor_frequency(const u8 *p) { u16 code = WORD(p); if (code) printf("%u MHz", code); else printf("Unknown"); } /* code is assumed to be a 3-bit value */ static const char *dmi_processor_status(u8 code) { static const char *status[] = { "Unknown", /* 0x00 */ "Enabled", "Disabled By User", "Disabled By BIOS", "Idle", /* 0x04 */ out_of_spec, out_of_spec, "Other" /* 0x07 */ }; return status[code]; } static const char *dmi_processor_upgrade(u8 code) { /* 7.5.5 */ static const char *upgrade[] = { "Other", /* 0x01 */ "Unknown", "Daughter Board", "ZIF Socket", "Replaceable Piggy Back", "None", "LIF Socket", "Slot 1", "Slot 2", "370-pin Socket", "Slot A", "Slot M", "Socket 423", "Socket A (Socket 462)", "Socket 478", "Socket 754", "Socket 940", "Socket 939", "Socket mPGA604", "Socket LGA771", "Socket LGA775", "Socket S1", "Socket AM2", "Socket F (1207)", "Socket LGA1366", "Socket G34", "Socket AM3", "Socket C32", "Socket LGA1156", "Socket LGA1567", "Socket PGA988A", "Socket BGA1288", "Socket rPGA988B", "Socket BGA1023", "Socket BGA1224", "Socket BGA1155", "Socket LGA1356", "Socket LGA2011", "Socket FS1", "Socket FS2", "Socket FM1", "Socket FM2", "Socket LGA2011-3", "Socket LGA1356-3", "Socket LGA1150", "Socket BGA1168", "Socket BGA1234", "Socket BGA1364", "Socket AM4", "Socket LGA1151", "Socket BGA1356", "Socket BGA1440", "Socket BGA1515", "Socket LGA3647-1", "Socket SP3", "Socket SP3r2" /* 0x38 */ }; if (code >= 0x01 && code <= 0x38) return upgrade[code - 0x01]; return out_of_spec; } static void dmi_processor_cache(u16 code, const char *level, u16 ver) { if (code == 0xFFFF) { if (ver >= 0x0203) printf(" Not Provided"); else printf(" No %s Cache", level); } else printf(" 0x%04X", code); } static void dmi_processor_characteristics(u16 code, const char *prefix) { /* 7.5.9 */ static const char *characteristics[] = { "64-bit capable", /* 2 */ "Multi-Core", "Hardware Thread", "Execute Protection", "Enhanced Virtualization", "Power/Performance Control" /* 7 */ }; if ((code & 0x00FC) == 0) printf(" None\n"); else { int i; printf("\n"); for (i = 2; i <= 7; i++) if (code & (1 << i)) printf("%s%s\n", prefix, characteristics[i - 2]); } } /* * 7.6 Memory Controller Information (Type 5) */ static const char *dmi_memory_controller_ed_method(u8 code) { /* 7.6.1 */ static const char *method[] = { "Other", /* 0x01 */ "Unknown", "None", "8-bit Parity", "32-bit ECC", "64-bit ECC", "128-bit ECC", "CRC" /* 0x08 */ }; if (code >= 0x01 && code <= 0x08) return method[code - 0x01]; return out_of_spec; } static void dmi_memory_controller_ec_capabilities(u8 code, const char *prefix) { /* 7.6.2 */ static const char *capabilities[] = { "Other", /* 0 */ "Unknown", "None", "Single-bit Error Correcting", "Double-bit Error Correcting", "Error Scrubbing" /* 5 */ }; if ((code & 0x3F) == 0) printf(" None\n"); else { int i; printf("\n"); for (i = 0; i <= 5; i++) if (code & (1 << i)) printf("%s%s\n", prefix, capabilities[i]); } } static const char *dmi_memory_controller_interleave(u8 code) { /* 7.6.3 */ static const char *interleave[] = { "Other", /* 0x01 */ "Unknown", "One-way Interleave", "Two-way Interleave", "Four-way Interleave", "Eight-way Interleave", "Sixteen-way Interleave" /* 0x07 */ }; if (code >= 0x01 && code <= 0x07) return interleave[code - 0x01]; return out_of_spec; } static void dmi_memory_controller_speeds(u16 code, const char *prefix) { /* 7.6.4 */ const char *speeds[] = { "Other", /* 0 */ "Unknown", "70 ns", "60 ns", "50 ns" /* 4 */ }; if ((code & 0x001F) == 0) printf(" None\n"); else { int i; printf("\n"); for (i = 0; i <= 4; i++) if (code & (1 << i)) printf("%s%s\n", prefix, speeds[i]); } } static void dmi_memory_controller_slots(u8 count, const u8 *p, const char *prefix) { int i; printf("%sAssociated Memory Slots: %u\n", prefix, count); for (i = 0; i < count; i++) printf("%s\t0x%04X\n", prefix, WORD(p + sizeof(u16) * i)); } /* * 7.7 Memory Module Information (Type 6) */ static void dmi_memory_module_types(u16 code, const char *sep) { /* 7.7.1 */ static const char *types[] = { "Other", /* 0 */ "Unknown", "Standard", "FPM", "EDO", "Parity", "ECC", "SIMM", "DIMM", "Burst EDO", "SDRAM" /* 10 */ }; if ((code & 0x07FF) == 0) printf(" None"); else { int i; for (i = 0; i <= 10; i++) if (code & (1 << i)) printf("%s%s", sep, types[i]); } } static void dmi_memory_module_connections(u8 code) { if (code == 0xFF) printf(" None"); else { if ((code & 0xF0) != 0xF0) printf(" %u", code >> 4); if ((code & 0x0F) != 0x0F) printf(" %u", code & 0x0F); } } static void dmi_memory_module_speed(u8 code) { if (code == 0) printf(" Unknown"); else printf(" %u ns", code); } static void dmi_memory_module_size(u8 code) { /* 7.7.2 */ switch (code & 0x7F) { case 0x7D: printf(" Not Determinable"); break; case 0x7E: printf(" Disabled"); break; case 0x7F: printf(" Not Installed"); return; default: printf(" %u MB", 1 << (code & 0x7F)); } if (code & 0x80) printf(" (Double-bank Connection)"); else printf(" (Single-bank Connection)"); } static void dmi_memory_module_error(u8 code, const char *prefix) { if (code & (1 << 2)) printf(" See Event Log\n"); else { if ((code & 0x03) == 0) printf(" OK\n"); if (code & (1 << 0)) printf("%sUncorrectable Errors\n", prefix); if (code & (1 << 1)) printf("%sCorrectable Errors\n", prefix); } } /* * 7.8 Cache Information (Type 7) */ static const char *dmi_cache_mode(u8 code) { static const char *mode[] = { "Write Through", /* 0x00 */ "Write Back", "Varies With Memory Address", "Unknown" /* 0x03 */ }; return mode[code]; } /* code is assumed to be a 2-bit value */ static const char *dmi_cache_location(u8 code) { static const char *location[4] = { "Internal", /* 0x00 */ "External", out_of_spec, /* 0x02 */ "Unknown" /* 0x03 */ }; return location[code]; } static void dmi_cache_size(u16 code) { if (code & 0x8000) printf(" %u kB", (code & 0x7FFF) << 6); else printf(" %u kB", code); } static void dmi_cache_size_2(u32 code) { if (code & 0x80000000) { code &= 0x7FFFFFFFLU; /* Use a more convenient unit for large cache size */ if (code >= 0x8000) printf(" %u MB", code >> 4); else printf(" %u kB", code << 6); } else printf(" %u kB", code); } static void dmi_cache_types(u16 code, const char *sep) { /* 7.8.2 */ static const char *types[] = { "Other", /* 0 */ "Unknown", "Non-burst", "Burst", "Pipeline Burst", "Synchronous", "Asynchronous" /* 6 */ }; if ((code & 0x007F) == 0) printf(" None"); else { int i; for (i = 0; i <= 6; i++) if (code & (1 << i)) printf("%s%s", sep, types[i]); } } static const char *dmi_cache_ec_type(u8 code) { /* 7.8.3 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "None", "Parity", "Single-bit ECC", "Multi-bit ECC" /* 0x06 */ }; if (code >= 0x01 && code <= 0x06) return type[code - 0x01]; return out_of_spec; } static const char *dmi_cache_type(u8 code) { /* 7.8.4 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Instruction", "Data", "Unified" /* 0x05 */ }; if (code >= 0x01 && code <= 0x05) return type[code - 0x01]; return out_of_spec; } static const char *dmi_cache_associativity(u8 code) { /* 7.8.5 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Direct Mapped", "2-way Set-associative", "4-way Set-associative", "Fully Associative", "8-way Set-associative", "16-way Set-associative", "12-way Set-associative", "24-way Set-associative", "32-way Set-associative", "48-way Set-associative", "64-way Set-associative", "20-way Set-associative" /* 0x0E */ }; if (code >= 0x01 && code <= 0x0E) return type[code - 0x01]; return out_of_spec; } /* * 7.9 Port Connector Information (Type 8) */ static const char *dmi_port_connector_type(u8 code) { /* 7.9.2 */ static const char *type[] = { "None", /* 0x00 */ "Centronics", "Mini Centronics", "Proprietary", "DB-25 male", "DB-25 female", "DB-15 male", "DB-15 female", "DB-9 male", "DB-9 female", "RJ-11", "RJ-45", "50 Pin MiniSCSI", "Mini DIN", "Micro DIN", "PS/2", "Infrared", "HP-HIL", "Access Bus (USB)", "SSA SCSI", "Circular DIN-8 male", "Circular DIN-8 female", "On Board IDE", "On Board Floppy", "9 Pin Dual Inline (pin 10 cut)", "25 Pin Dual Inline (pin 26 cut)", "50 Pin Dual Inline", "68 Pin Dual Inline", "On Board Sound Input From CD-ROM", "Mini Centronics Type-14", "Mini Centronics Type-26", "Mini Jack (headphones)", "BNC", "IEEE 1394", "SAS/SATA Plug Receptacle" /* 0x22 */ }; static const char *type_0xA0[] = { "PC-98", /* 0xA0 */ "PC-98 Hireso", "PC-H98", "PC-98 Note", "PC-98 Full" /* 0xA4 */ }; if (code <= 0x22) return type[code]; if (code >= 0xA0 && code <= 0xA4) return type_0xA0[code - 0xA0]; if (code == 0xFF) return "Other"; return out_of_spec; } static const char *dmi_port_type(u8 code) { /* 7.9.3 */ static const char *type[] = { "None", /* 0x00 */ "Parallel Port XT/AT Compatible", "Parallel Port PS/2", "Parallel Port ECP", "Parallel Port EPP", "Parallel Port ECP/EPP", "Serial Port XT/AT Compatible", "Serial Port 16450 Compatible", "Serial Port 16550 Compatible", "Serial Port 16550A Compatible", "SCSI Port", "MIDI Port", "Joystick Port", "Keyboard Port", "Mouse Port", "SSA SCSI", "USB", "Firewire (IEEE P1394)", "PCMCIA Type I", "PCMCIA Type II", "PCMCIA Type III", "Cardbus", "Access Bus Port", "SCSI II", "SCSI Wide", "PC-98", "PC-98 Hireso", "PC-H98", "Video Port", "Audio Port", "Modem Port", "Network Port", "SATA", "SAS" /* 0x21 */ }; static const char *type_0xA0[] = { "8251 Compatible", /* 0xA0 */ "8251 FIFO Compatible" /* 0xA1 */ }; if (code <= 0x21) return type[code]; if (code >= 0xA0 && code <= 0xA1) return type_0xA0[code - 0xA0]; if (code == 0xFF) return "Other"; return out_of_spec; } /* * 7.10 System Slots (Type 9) */ static const char *dmi_slot_type(u8 code) { /* 7.10.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "ISA", "MCA", "EISA", "PCI", "PC Card (PCMCIA)", "VLB", "Proprietary", "Processor Card", "Proprietary Memory Card", "I/O Riser Card", "NuBus", "PCI-66", "AGP", "AGP 2x", "AGP 4x", "PCI-X", "AGP 8x", "M.2 Socket 1-DP", "M.2 Socket 1-SD", "M.2 Socket 2", "M.2 Socket 3", "MXM Type I", "MXM Type II", "MXM Type III", "MXM Type III-HE", "MXM Type IV", "MXM 3.0 Type A", "MXM 3.0 Type B", "PCI Express 2 SFF-8639", "PCI Express 3 SFF-8639", "PCI Express Mini 52-pin with bottom-side keep-outs", "PCI Express Mini 52-pin without bottom-side keep-outs", "PCI Express Mini 76-pin" /* 0x23 */ }; static const char *type_0xA0[] = { "PC-98/C20", /* 0xA0 */ "PC-98/C24", "PC-98/E", "PC-98/Local Bus", "PC-98/Card", "PCI Express", "PCI Express x1", "PCI Express x2", "PCI Express x4", "PCI Express x8", "PCI Express x16", "PCI Express 2", "PCI Express 2 x1", "PCI Express 2 x2", "PCI Express 2 x4", "PCI Express 2 x8", "PCI Express 2 x16", "PCI Express 3", "PCI Express 3 x1", "PCI Express 3 x2", "PCI Express 3 x4", "PCI Express 3 x8", "PCI Express 3 x16" /* 0xB6 */ }; /* * Note to developers: when adding entries to these lists, check if * function dmi_slot_id below needs updating too. */ if (code >= 0x01 && code <= 0x23) return type[code - 0x01]; if (code >= 0xA0 && code <= 0xB6) return type_0xA0[code - 0xA0]; return out_of_spec; } static const char *dmi_slot_bus_width(u8 code) { /* 7.10.2 */ static const char *width[] = { "", /* 0x01, "Other" */ "", /* "Unknown" */ "8-bit ", "16-bit ", "32-bit ", "64-bit ", "128-bit ", "x1 ", "x2 ", "x4 ", "x8 ", "x12 ", "x16 ", "x32 " /* 0x0E */ }; if (code >= 0x01 && code <= 0x0E) return width[code - 0x01]; return out_of_spec; } static const char *dmi_slot_current_usage(u8 code) { /* 7.10.3 */ static const char *usage[] = { "Other", /* 0x01 */ "Unknown", "Available", "In Use" /* 0x04 */ }; if (code >= 0x01 && code <= 0x04) return usage[code - 0x01]; return out_of_spec; } static const char *dmi_slot_length(u8 code) { /* 7.1O.4 */ static const char *length[] = { "Other", /* 0x01 */ "Unknown", "Short", "Long" /* 0x04 */ }; if (code >= 0x01 && code <= 0x04) return length[code - 0x01]; return out_of_spec; } static void dmi_slot_id(u8 code1, u8 code2, u8 type, const char *prefix) { /* 7.10.5 */ switch (type) { case 0x04: /* MCA */ printf("%sID: %u\n", prefix, code1); break; case 0x05: /* EISA */ printf("%sID: %u\n", prefix, code1); break; case 0x06: /* PCI */ case 0x0E: /* PCI */ case 0x0F: /* AGP */ case 0x10: /* AGP */ case 0x11: /* AGP */ case 0x12: /* PCI-X */ case 0x13: /* AGP */ case 0x1F: /* PCI Express 2 */ case 0x20: /* PCI Express 3 */ case 0x21: /* PCI Express Mini */ case 0x22: /* PCI Express Mini */ case 0x23: /* PCI Express Mini */ case 0xA5: /* PCI Express */ case 0xA6: /* PCI Express */ case 0xA7: /* PCI Express */ case 0xA8: /* PCI Express */ case 0xA9: /* PCI Express */ case 0xAA: /* PCI Express */ case 0xAB: /* PCI Express 2 */ case 0xAC: /* PCI Express 2 */ case 0xAD: /* PCI Express 2 */ case 0xAE: /* PCI Express 2 */ case 0xAF: /* PCI Express 2 */ case 0xB0: /* PCI Express 2 */ case 0xB1: /* PCI Express 3 */ case 0xB2: /* PCI Express 3 */ case 0xB3: /* PCI Express 3 */ case 0xB4: /* PCI Express 3 */ case 0xB5: /* PCI Express 3 */ case 0xB6: /* PCI Express 3 */ printf("%sID: %u\n", prefix, code1); break; case 0x07: /* PCMCIA */ printf("%sID: Adapter %u, Socket %u\n", prefix, code1, code2); break; } } static void dmi_slot_characteristics(u8 code1, u8 code2, const char *prefix) { /* 7.10.6 */ static const char *characteristics1[] = { "5.0 V is provided", /* 1 */ "3.3 V is provided", "Opening is shared", "PC Card-16 is supported", "Cardbus is supported", "Zoom Video is supported", "Modem ring resume is supported" /* 7 */ }; /* 7.10.7 */ static const char *characteristics2[] = { "PME signal is supported", /* 0 */ "Hot-plug devices are supported", "SMBus signal is supported" /* 2 */ }; if (code1 & (1 << 0)) printf(" Unknown\n"); else if ((code1 & 0xFE) == 0 && (code2 & 0x07) == 0) printf(" None\n"); else { int i; printf("\n"); for (i = 1; i <= 7; i++) if (code1 & (1 << i)) printf("%s%s\n", prefix, characteristics1[i - 1]); for (i = 0; i <= 2; i++) if (code2 & (1 << i)) printf("%s%s\n", prefix, characteristics2[i]); } } static void dmi_slot_segment_bus_func(u16 code1, u8 code2, u8 code3, const char *prefix) { /* 7.10.8 */ if (!(code1 == 0xFFFF && code2 == 0xFF && code3 == 0xFF)) printf("%sBus Address: %04x:%02x:%02x.%x\n", prefix, code1, code2, code3 >> 3, code3 & 0x7); } /* * 7.11 On Board Devices Information (Type 10) */ static const char *dmi_on_board_devices_type(u8 code) { /* 7.11.1 and 7.42.2 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Video", "SCSI Controller", "Ethernet", "Token Ring", "Sound", "PATA Controller", "SATA Controller", "SAS Controller" /* 0x0A */ }; if (code >= 0x01 && code <= 0x0A) return type[code - 0x01]; return out_of_spec; } static void dmi_on_board_devices(const struct dmi_header *h, const char *prefix) { u8 *p = h->data + 4; u8 count = (h->length - 0x04) / 2; int i; for (i = 0; i < count; i++) { if (count == 1) printf("%sOn Board Device Information\n", prefix); else printf("%sOn Board Device %d Information\n", prefix, i + 1); printf("%s\tType: %s\n", prefix, dmi_on_board_devices_type(p[2 * i] & 0x7F)); printf("%s\tStatus: %s\n", prefix, p[2 * i] & 0x80 ? "Enabled" : "Disabled"); printf("%s\tDescription: %s\n", prefix, dmi_string(h, p[2 * i + 1])); } } /* * 7.12 OEM Strings (Type 11) */ static void dmi_oem_strings(const struct dmi_header *h, const char *prefix) { u8 *p = h->data + 4; u8 count = p[0x00]; int i; for (i = 1; i <= count; i++) printf("%sString %d: %s\n", prefix, i, dmi_string(h, i)); } /* * 7.13 System Configuration Options (Type 12) */ static void dmi_system_configuration_options(const struct dmi_header *h, const char *prefix) { u8 *p = h->data + 4; u8 count = p[0x00]; int i; for (i = 1; i <= count; i++) printf("%sOption %d: %s\n", prefix, i, dmi_string(h, i)); } /* * 7.14 BIOS Language Information (Type 13) */ static void dmi_bios_languages(const struct dmi_header *h, const char *prefix) { u8 *p = h->data + 4; u8 count = p[0x00]; int i; for (i = 1; i <= count; i++) printf("%s%s\n", prefix, dmi_string(h, i)); } static const char *dmi_bios_language_format(u8 code) { if (code & 0x01) return "Abbreviated"; else return "Long"; } /* * 7.15 Group Associations (Type 14) */ static void dmi_group_associations_items(u8 count, const u8 *p, const char *prefix) { int i; for (i = 0; i < count; i++) { printf("%s0x%04X (%s)\n", prefix, WORD(p + 3 * i + 1), dmi_smbios_structure_type(p[3 * i])); } } /* * 7.16 System Event Log (Type 15) */ static const char *dmi_event_log_method(u8 code) { static const char *method[] = { "Indexed I/O, one 8-bit index port, one 8-bit data port", /* 0x00 */ "Indexed I/O, two 8-bit index ports, one 8-bit data port", "Indexed I/O, one 16-bit index port, one 8-bit data port", "Memory-mapped physical 32-bit address", "General-purpose non-volatile data functions" /* 0x04 */ }; if (code <= 0x04) return method[code]; if (code >= 0x80) return "OEM-specific"; return out_of_spec; } static void dmi_event_log_status(u8 code) { static const char *valid[] = { "Invalid", /* 0 */ "Valid" /* 1 */ }; static const char *full[] = { "Not Full", /* 0 */ "Full" /* 1 */ }; printf(" %s, %s", valid[(code >> 0) & 1], full[(code >> 1) & 1]); } static void dmi_event_log_address(u8 method, const u8 *p) { /* 7.16.3 */ switch (method) { case 0x00: case 0x01: case 0x02: printf(" Index 0x%04X, Data 0x%04X", WORD(p), WORD(p + 2)); break; case 0x03: printf(" 0x%08X", DWORD(p)); break; case 0x04: printf(" 0x%04X", WORD(p)); break; default: printf(" Unknown"); } } static const char *dmi_event_log_header_type(u8 code) { static const char *type[] = { "No Header", /* 0x00 */ "Type 1" /* 0x01 */ }; if (code <= 0x01) return type[code]; if (code >= 0x80) return "OEM-specific"; return out_of_spec; } static const char *dmi_event_log_descriptor_type(u8 code) { /* 7.16.6.1 */ static const char *type[] = { NULL, /* 0x00 */ "Single-bit ECC memory error", "Multi-bit ECC memory error", "Parity memory error", "Bus timeout", "I/O channel block", "Software NMI", "POST memory resize", "POST error", "PCI parity error", "PCI system error", "CPU failure", "EISA failsafe timer timeout", "Correctable memory log disabled", "Logging disabled", NULL, /* 0x0F */ "System limit exceeded", "Asynchronous hardware timer expired", "System configuration information", "Hard disk information", "System reconfigured", "Uncorrectable CPU-complex error", "Log area reset/cleared", "System boot" /* 0x17 */ }; if (code <= 0x17 && type[code] != NULL) return type[code]; if (code >= 0x80 && code <= 0xFE) return "OEM-specific"; if (code == 0xFF) return "End of log"; return out_of_spec; } static const char *dmi_event_log_descriptor_format(u8 code) { /* 7.16.6.2 */ static const char *format[] = { "None", /* 0x00 */ "Handle", "Multiple-event", "Multiple-event handle", "POST results bitmap", "System management", "Multiple-event system management" /* 0x06 */ }; if (code <= 0x06) return format[code]; if (code >= 0x80) return "OEM-specific"; return out_of_spec; } static void dmi_event_log_descriptors(u8 count, u8 len, const u8 *p, const char *prefix) { /* 7.16.1 */ int i; for (i = 0; i < count; i++) { if (len >= 0x02) { printf("%sDescriptor %u: %s\n", prefix, i + 1, dmi_event_log_descriptor_type(p[i * len])); printf("%sData Format %u: %s\n", prefix, i + 1, dmi_event_log_descriptor_format(p[i * len + 1])); } } } /* * 7.17 Physical Memory Array (Type 16) */ static const char *dmi_memory_array_location(u8 code) { /* 7.17.1 */ static const char *location[] = { "Other", /* 0x01 */ "Unknown", "System Board Or Motherboard", "ISA Add-on Card", "EISA Add-on Card", "PCI Add-on Card", "MCA Add-on Card", "PCMCIA Add-on Card", "Proprietary Add-on Card", "NuBus" /* 0x0A */ }; static const char *location_0xA0[] = { "PC-98/C20 Add-on Card", /* 0xA0 */ "PC-98/C24 Add-on Card", "PC-98/E Add-on Card", "PC-98/Local Bus Add-on Card" /* 0xA3 */ }; if (code >= 0x01 && code <= 0x0A) return location[code - 0x01]; if (code >= 0xA0 && code <= 0xA3) return location_0xA0[code - 0xA0]; return out_of_spec; } static const char *dmi_memory_array_use(u8 code) { /* 7.17.2 */ static const char *use[] = { "Other", /* 0x01 */ "Unknown", "System Memory", "Video Memory", "Flash Memory", "Non-volatile RAM", "Cache Memory" /* 0x07 */ }; if (code >= 0x01 && code <= 0x07) return use[code - 0x01]; return out_of_spec; } static const char *dmi_memory_array_ec_type(u8 code) { /* 7.17.3 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "None", "Parity", "Single-bit ECC", "Multi-bit ECC", "CRC" /* 0x07 */ }; if (code >= 0x01 && code <= 0x07) return type[code - 0x01]; return out_of_spec; } static void dmi_memory_array_error_handle(u16 code) { if (code == 0xFFFE) printf(" Not Provided"); else if (code == 0xFFFF) printf(" No Error"); else printf(" 0x%04X", code); } /* * 7.18 Memory Device (Type 17) */ static void dmi_memory_device_width(u16 code) { /* * If no memory module is present, width may be 0 */ if (code == 0xFFFF || code == 0) printf(" Unknown"); else printf(" %u bits", code); } static void dmi_memory_device_size(u16 code) { if (code == 0) printf(" No Module Installed"); else if (code == 0xFFFF) printf(" Unknown"); else { if (code & 0x8000) printf(" %u kB", code & 0x7FFF); else printf(" %u MB", code); } } static char *dmi_memory_device_size_str(u16 code) { static char size[16]; if (code == 0) strcpy(size, "Empty"); else if (code == 0xFFFF) strcpy(size, "Unknown"); else { if (code & 0x8000) sprintf(size, "%u kB", code & 0x7FFF); else sprintf(size, "%u MB", code); } return size; } static void dmi_memory_device_extended_size(u32 code) { code &= 0x7FFFFFFFUL; /* * Use the greatest unit for which the exact value can be displayed * as an integer without rounding */ if (code & 0x3FFUL) printf(" %lu MB", (unsigned long)code); else if (code & 0xFFC00UL) printf(" %lu GB", (unsigned long)code >> 10); else printf(" %lu TB", (unsigned long)code >> 20); } static void dmi_memory_voltage_value(u16 code) { if (code == 0) printf(" Unknown"); else printf(code % 100 ? " %g V" : " %.1f V", (float)code / 1000); } static const char *dmi_memory_device_form_factor(u8 code) { /* 7.18.1 */ static const char *form_factor[] = { "Other", /* 0x01 */ "Unknown", "SIMM", "SIP", "Chip", "DIP", "ZIP", "Proprietary Card", "DIMM", "TSOP", "Row Of Chips", "RIMM", "SODIMM", "SRIMM", "FB-DIMM" /* 0x0F */ }; if (code >= 0x01 && code <= 0x0F) return form_factor[code - 0x01]; return out_of_spec; } static void dmi_memory_device_set(u8 code) { if (code == 0) printf(" None"); else if (code == 0xFF) printf(" Unknown"); else printf(" %u", code); } static const char *dmi_memory_device_type(u8 code) { /* 7.18.2 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "Flash", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR2", "DDR2 FB-DIMM", "Reserved", "Reserved", "Reserved", "DDR3", "FBD2", "DDR4", "LPDDR", "LPDDR2", "LPDDR3", "LPDDR4" /* 0x1E */ }; if (code >= 0x01 && code <= 0x1E) return type[code - 0x01]; return out_of_spec; } static void dmi_memory_device_type_detail(u16 code) { /* 7.18.3 */ static const char *detail[] = { "Other", /* 1 */ "Unknown", "Fast-paged", "Static Column", "Pseudo-static", "RAMBus", "Synchronous", "CMOS", "EDO", "Window DRAM", "Cache DRAM", "Non-Volatile", "Registered (Buffered)", "Unbuffered (Unregistered)", "LRDIMM" /* 15 */ }; if ((code & 0xFFFE) == 0) printf(" None"); else { int i; for (i = 1; i <= 15; i++) if (code & (1 << i)) printf(" %s", detail[i - 1]); } } static void dmi_memory_device_speed(u16 code) { if (code == 0) printf(" Unknown"); else printf(" %u MT/s", code); } static void dmi_memory_technology(u8 code) { /* 7.18.6 */ static const char * const technology[] = { "Other", /* 0x01 */ "Unknown", "DRAM", "NVDIMM-N", "NVDIMM-F", "NVDIMM-P", "Intel persistent memory" /* 0x07 */ }; if (code >= 0x01 && code <= 0x07) printf(" %s", technology[code - 0x01]); else printf(" %s", out_of_spec); } static void dmi_memory_operating_mode_capability(u16 code) { /* 7.18.7 */ static const char * const mode[] = { "Other", /* 1 */ "Unknown", "Volatile memory", "Byte-accessible persistent memory", "Block-accessible persistent memory" /* 5 */ }; if ((code & 0xFFFE) == 0) printf(" None"); else { int i; for (i = 1; i <= 5; i++) if (code & (1 << i)) printf(" %s", mode[i - 1]); } } static void dmi_memory_manufacturer_id(u16 code) { /* 7.18.8 */ /* 7.18.10 */ /* LSB is 7-bit Odd Parity number of continuation codes */ if (code == 0) printf(" Unknown"); else printf(" Bank %d, Hex 0x%02X", (code & 0x7F) + 1, code >> 8); } static void dmi_memory_product_id(u16 code) { /* 7.18.9 */ /* 7.18.11 */ if (code == 0) printf(" Unknown"); else printf(" 0x%04X", code); } static void dmi_memory_size(u64 code) { /* 7.18.12 */ /* 7.18.13 */ if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF) printf(" Unknown"); else if (code.h == 0x0 && code.l == 0x0) printf(" None"); else dmi_print_memory_size(code, 0); } /* * 7.19 32-bit Memory Error Information (Type 18) */ static const char *dmi_memory_error_type(u8 code) { /* 7.19.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "OK", "Bad Read", "Parity Error", "Single-bit Error", "Double-bit Error", "Multi-bit Error", "Nibble Error", "Checksum Error", "CRC Error", "Corrected Single-bit Error", "Corrected Error", "Uncorrectable Error" /* 0x0E */ }; if (code >= 0x01 && code <= 0x0E) return type[code - 0x01]; return out_of_spec; } static const char *dmi_memory_error_granularity(u8 code) { /* 7.19.2 */ static const char *granularity[] = { "Other", /* 0x01 */ "Unknown", "Device Level", "Memory Partition Level" /* 0x04 */ }; if (code >= 0x01 && code <= 0x04) return granularity[code - 0x01]; return out_of_spec; } static const char *dmi_memory_error_operation(u8 code) { /* 7.19.3 */ static const char *operation[] = { "Other", /* 0x01 */ "Unknown", "Read", "Write", "Partial Write" /* 0x05 */ }; if (code >= 0x01 && code <= 0x05) return operation[code - 0x01]; return out_of_spec; } static void dmi_memory_error_syndrome(u32 code) { if (code == 0x00000000) printf(" Unknown"); else printf(" 0x%08X", code); } static void dmi_32bit_memory_error_address(u32 code) { if (code == 0x80000000) printf(" Unknown"); else printf(" 0x%08X", code); } /* * 7.20 Memory Array Mapped Address (Type 19) */ static void dmi_mapped_address_size(u32 code) { if (code == 0) printf(" Invalid"); else { u64 size; size.h = 0; size.l = code; dmi_print_memory_size(size, 1); } } static void dmi_mapped_address_extended_size(u64 start, u64 end) { if (start.h == end.h && start.l == end.l) printf(" Invalid"); else dmi_print_memory_size(u64_range(start, end), 0); } /* * 7.21 Memory Device Mapped Address (Type 20) */ static void dmi_mapped_address_row_position(u8 code) { if (code == 0) printf(" %s", out_of_spec); else if (code == 0xFF) printf(" Unknown"); else printf(" %u", code); } static void dmi_mapped_address_interleave_position(u8 code, const char *prefix) { if (code != 0) { printf("%sInterleave Position:", prefix); if (code == 0xFF) printf(" Unknown"); else printf(" %u", code); printf("\n"); } } static void dmi_mapped_address_interleaved_data_depth(u8 code, const char *prefix) { if (code != 0) { printf("%sInterleaved Data Depth:", prefix); if (code == 0xFF) printf(" Unknown"); else printf(" %u", code); printf("\n"); } } /* * 7.22 Built-in Pointing Device (Type 21) */ static const char *dmi_pointing_device_type(u8 code) { /* 7.22.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Mouse", "Track Ball", "Track Point", "Glide Point", "Touch Pad", "Touch Screen", "Optical Sensor" /* 0x09 */ }; if (code >= 0x01 && code <= 0x09) return type[code - 0x01]; return out_of_spec; } static const char *dmi_pointing_device_interface(u8 code) { /* 7.22.2 */ static const char *interface[] = { "Other", /* 0x01 */ "Unknown", "Serial", "PS/2", "Infrared", "HIP-HIL", "Bus Mouse", "ADB (Apple Desktop Bus)" /* 0x08 */ }; static const char *interface_0xA0[] = { "Bus Mouse DB-9", /* 0xA0 */ "Bus Mouse Micro DIN", "USB" /* 0xA2 */ }; if (code >= 0x01 && code <= 0x08) return interface[code - 0x01]; if (code >= 0xA0 && code <= 0xA2) return interface_0xA0[code - 0xA0]; return out_of_spec; } /* * 7.23 Portable Battery (Type 22) */ static const char *dmi_battery_chemistry(u8 code) { /* 7.23.1 */ static const char *chemistry[] = { "Other", /* 0x01 */ "Unknown", "Lead Acid", "Nickel Cadmium", "Nickel Metal Hydride", "Lithium Ion", "Zinc Air", "Lithium Polymer" /* 0x08 */ }; if (code >= 0x01 && code <= 0x08) return chemistry[code - 0x01]; return out_of_spec; } static void dmi_battery_capacity(u16 code, u8 multiplier) { if (code == 0) printf(" Unknown"); else printf(" %u mWh", code * multiplier); } static void dmi_battery_voltage(u16 code) { if (code == 0) printf(" Unknown"); else printf(" %u mV", code); } static void dmi_battery_maximum_error(u8 code) { if (code == 0xFF) printf(" Unknown"); else printf(" %u%%", code); } /* * 7.24 System Reset (Type 23) */ /* code is assumed to be a 2-bit value */ static const char *dmi_system_reset_boot_option(u8 code) { static const char *option[] = { out_of_spec, /* 0x0 */ "Operating System", /* 0x1 */ "System Utilities", "Do Not Reboot" /* 0x3 */ }; return option[code]; } static void dmi_system_reset_count(u16 code) { if (code == 0xFFFF) printf(" Unknown"); else printf(" %u", code); } static void dmi_system_reset_timer(u16 code) { if (code == 0xFFFF) printf(" Unknown"); else printf(" %u min", code); } /* * 7.25 Hardware Security (Type 24) */ static const char *dmi_hardware_security_status(u8 code) { static const char *status[] = { "Disabled", /* 0x00 */ "Enabled", "Not Implemented", "Unknown" /* 0x03 */ }; return status[code]; } /* * 7.26 System Power Controls (Type 25) */ static void dmi_power_controls_power_on(const u8 *p) { /* 7.26.1 */ if (dmi_bcd_range(p[0], 0x01, 0x12)) printf(" %02X", p[0]); else printf(" *"); if (dmi_bcd_range(p[1], 0x01, 0x31)) printf("-%02X", p[1]); else printf("-*"); if (dmi_bcd_range(p[2], 0x00, 0x23)) printf(" %02X", p[2]); else printf(" *"); if (dmi_bcd_range(p[3], 0x00, 0x59)) printf(":%02X", p[3]); else printf(":*"); if (dmi_bcd_range(p[4], 0x00, 0x59)) printf(":%02X", p[4]); else printf(":*"); } /* * 7.27 Voltage Probe (Type 26) */ static const char *dmi_voltage_probe_location(u8 code) { /* 7.27.1 */ static const char *location[] = { "Other", /* 0x01 */ "Unknown", "Processor", "Disk", "Peripheral Bay", "System Management Module", "Motherboard", "Memory Module", "Processor Module", "Power Unit", "Add-in Card" /* 0x0B */ }; if (code >= 0x01 && code <= 0x0B) return location[code - 0x01]; return out_of_spec; } static const char *dmi_probe_status(u8 code) { /* 7.27.1 */ static const char *status[] = { "Other", /* 0x01 */ "Unknown", "OK", "Non-critical", "Critical", "Non-recoverable" /* 0x06 */ }; if (code >= 0x01 && code <= 0x06) return status[code - 0x01]; return out_of_spec; } static void dmi_voltage_probe_value(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.3f V", (float)(i16)code / 1000); } static void dmi_voltage_probe_resolution(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.1f mV", (float)code / 10); } static void dmi_probe_accuracy(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.2f%%", (float)code / 100); } /* * 7.28 Cooling Device (Type 27) */ static const char *dmi_cooling_device_type(u8 code) { /* 7.28.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Fan", "Centrifugal Blower", "Chip Fan", "Cabinet Fan", "Power Supply Fan", "Heat Pipe", "Integrated Refrigeration" /* 0x09 */ }; static const char *type_0x10[] = { "Active Cooling", /* 0x10 */ "Passive Cooling" /* 0x11 */ }; if (code >= 0x01 && code <= 0x09) return type[code - 0x01]; if (code >= 0x10 && code <= 0x11) return type_0x10[code - 0x10]; return out_of_spec; } static void dmi_cooling_device_speed(u16 code) { if (code == 0x8000) printf(" Unknown Or Non-rotating"); else printf(" %u rpm", code); } /* * 7.29 Temperature Probe (Type 28) */ static const char *dmi_temperature_probe_location(u8 code) { /* 7.29.1 */ static const char *location[] = { "Other", /* 0x01 */ "Unknown", "Processor", "Disk", "Peripheral Bay", "System Management Module", "Motherboard", "Memory Module", "Processor Module", "Power Unit", "Add-in Card", "Front Panel Board", "Back Panel Board", "Power System Board", "Drive Back Plane" /* 0x0F */ }; if (code >= 0x01 && code <= 0x0F) return location[code - 0x01]; return out_of_spec; } static void dmi_temperature_probe_value(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.1f deg C", (float)(i16)code / 10); } static void dmi_temperature_probe_resolution(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.3f deg C", (float)code / 1000); } /* * 7.30 Electrical Current Probe (Type 29) */ static void dmi_current_probe_value(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.3f A", (float)(i16)code / 1000); } static void dmi_current_probe_resolution(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %.1f mA", (float)code / 10); } /* * 7.33 System Boot Information (Type 32) */ static const char *dmi_system_boot_status(u8 code) { static const char *status[] = { "No errors detected", /* 0 */ "No bootable media", "Operating system failed to load", "Firmware-detected hardware failure", "Operating system-detected hardware failure", "User-requested boot", "System security violation", "Previously-requested image", "System watchdog timer expired" /* 8 */ }; if (code <= 8) return status[code]; if (code >= 128 && code <= 191) return "OEM-specific"; if (code >= 192) return "Product-specific"; return out_of_spec; } /* * 7.34 64-bit Memory Error Information (Type 33) */ static void dmi_64bit_memory_error_address(u64 code) { if (code.h == 0x80000000 && code.l == 0x00000000) printf(" Unknown"); else printf(" 0x%08X%08X", code.h, code.l); } /* * 7.35 Management Device (Type 34) */ /* * Several boards have a bug where some type 34 structures have their * length incorrectly set to 0x10 instead of 0x0B. This causes the * first 5 characters of the device name to be trimmed. It's easy to * check and fix, so do it, but warn. */ static void dmi_fixup_type_34(struct dmi_header *h, int display) { u8 *p = h->data; /* Make sure the hidden data is ASCII only */ if (h->length == 0x10 && is_printable(p + 0x0B, 0x10 - 0x0B)) { if (!(opt.flags & FLAG_QUIET) && display) fprintf(stderr, "Invalid entry length (%u). Fixed up to %u.\n", 0x10, 0x0B); h->length = 0x0B; } } static const char *dmi_management_device_type(u8 code) { /* 7.35.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "LM75", "LM78", "LM79", "LM80", "LM81", "ADM9240", "DS1780", "MAX1617", "GL518SM", "W83781D", "HT82H791" /* 0x0D */ }; if (code >= 0x01 && code <= 0x0D) return type[code - 0x01]; return out_of_spec; } static const char *dmi_management_device_address_type(u8 code) { /* 7.35.2 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "I/O Port", "Memory", "SMBus" /* 0x05 */ }; if (code >= 0x01 && code <= 0x05) return type[code - 0x01]; return out_of_spec; } /* * 7.38 Memory Channel (Type 37) */ static const char *dmi_memory_channel_type(u8 code) { /* 7.38.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "RamBus", "SyncLink" /* 0x04 */ }; if (code >= 0x01 && code <= 0x04) return type[code - 0x01]; return out_of_spec; } static void dmi_memory_channel_devices(u8 count, const u8 *p, const char *prefix) { int i; for (i = 1; i <= count; i++) { printf("%sDevice %u Load: %u\n", prefix, i, p[3 * i]); if (!(opt.flags & FLAG_QUIET)) printf("%sDevice %u Handle: 0x%04X\n", prefix, i, WORD(p + 3 * i + 1)); } } /* * 7.39 IPMI Device Information (Type 38) */ static const char *dmi_ipmi_interface_type(u8 code) { /* 7.39.1 and IPMI 2.0, appendix C1, table C1-2 */ static const char *type[] = { "Unknown", /* 0x00 */ "KCS (Keyboard Control Style)", "SMIC (Server Management Interface Chip)", "BT (Block Transfer)", "SSIF (SMBus System Interface)" /* 0x04 */ }; if (code <= 0x04) return type[code]; return out_of_spec; } static void dmi_ipmi_base_address(u8 type, const u8 *p, u8 lsb) { if (type == 0x04) /* SSIF */ { printf("0x%02X (SMBus)", (*p) >> 1); } else { u64 address = QWORD(p); printf("0x%08X%08X (%s)", address.h, (address.l & ~1) | lsb, address.l & 1 ? "I/O" : "Memory-mapped"); } } /* code is assumed to be a 2-bit value */ static const char *dmi_ipmi_register_spacing(u8 code) { /* IPMI 2.0, appendix C1, table C1-1 */ static const char *spacing[] = { "Successive Byte Boundaries", /* 0x00 */ "32-bit Boundaries", "16-byte Boundaries", /* 0x02 */ out_of_spec /* 0x03 */ }; return spacing[code]; } /* * 7.40 System Power Supply (Type 39) */ static void dmi_power_supply_power(u16 code) { if (code == 0x8000) printf(" Unknown"); else printf(" %u W", (unsigned int)code); } static const char *dmi_power_supply_type(u8 code) { /* 7.40.1 */ static const char *type[] = { "Other", /* 0x01 */ "Unknown", "Linear", "Switching", "Battery", "UPS", "Converter", "Regulator" /* 0x08 */ }; if (code >= 0x01 && code <= 0x08) return type[code - 0x01]; return out_of_spec; } static const char *dmi_power_supply_status(u8 code) { /* 7.40.1 */ static const char *status[] = { "Other", /* 0x01 */ "Unknown", "OK", "Non-critical", "Critical" /* 0x05 */ }; if (code >= 0x01 && code <= 0x05) return status[code - 0x01]; return out_of_spec; } static const char *dmi_power_supply_range_switching(u8 code) { /* 7.40.1 */ static const char *switching[] = { "Other", /* 0x01 */ "Unknown", "Manual", "Auto-switch", "Wide Range", "N/A" /* 0x06 */ }; if (code >= 0x01 && code <= 0x06) return switching[code - 0x01]; return out_of_spec; } /* * 7.41 Additional Information (Type 40) * * Proper support of this entry type would require redesigning a large part of * the code, so I am waiting to see actual implementations of it to decide * whether it's worth the effort. */ static void dmi_additional_info(const struct dmi_header *h, const char *prefix) { u8 *p = h->data + 4; u8 count = *p++; u8 length; int i, offset = 5; for (i = 0; i < count; i++) { printf("%sAdditional Information %d\n", prefix, i + 1); /* Check for short entries */ if (h->length < offset + 1) break; length = p[0x00]; if (length < 0x05 || h->length < offset + length) break; printf("%s\tReferenced Handle: 0x%04x\n", prefix, WORD(p + 0x01)); printf("%s\tReferenced Offset: 0x%02x\n", prefix, p[0x03]); printf("%s\tString: %s\n", prefix, dmi_string(h, p[0x04])); printf("%s\tValue: ", prefix); switch (length - 0x05) { case 1: printf("0x%02x", p[0x05]); break; case 2: printf("0x%04x", WORD(p + 0x05)); break; case 4: printf("0x%08x", DWORD(p + 0x05)); break; default: printf("Unexpected size"); break; } printf("\n"); p += length; offset += length; } } /* * 7.43 Management Controller Host Interface (Type 42) */ static const char *dmi_management_controller_host_type(u8 code) { /* DMTF DSP0239 (MCTP) version 1.1.0 */ static const char *type[] = { "KCS: Keyboard Controller Style", /* 0x02 */ "8250 UART Register Compatible", "16450 UART Register Compatible", "16550/16550A UART Register Compatible", "16650/16650A UART Register Compatible", "16750/16750A UART Register Compatible", "16850/16850A UART Register Compatible" /* 0x08 */ }; if (code >= 0x02 && code <= 0x08) return type[code - 0x02]; if (code == 0xF0) return "OEM"; return out_of_spec; } /* * 7.44 TPM Device (Type 43) */ static void dmi_tpm_vendor_id(const u8 *p) { char vendor_id[5]; int i; /* ASCII filtering */ for (i = 0; i < 4 && p[i] != 0; i++) { if (p[i] < 32 || p[i] >= 127) vendor_id[i] = '.'; else vendor_id[i] = p[i]; } /* Terminate the string */ vendor_id[i] = '\0'; printf(" %s", vendor_id); } static void dmi_tpm_characteristics(u64 code, const char *prefix) { /* 7.1.1 */ static const char *characteristics[] = { "TPM Device characteristics not supported", /* 2 */ "Family configurable via firmware update", "Family configurable via platform software support", "Family configurable via OEM proprietary mechanism" /* 5 */ }; int i; /* * This isn't very clear what this bit is supposed to mean */ if (code.l & (1 << 2)) { printf("%s%s\n", prefix, characteristics[0]); return; } for (i = 3; i <= 5; i++) if (code.l & (1 << i)) printf("%s%s\n", prefix, characteristics[i - 2]); } /* * Main */ static void dmi_decode(const struct dmi_header *h, u16 ver) { const u8 *data = h->data; /* * Note: DMI types 37 and 42 are untested */ switch (h->type) { case 0: /* 7.1 BIOS Information */ if(opt.flags & FLAG_CPU_X) { casprintf(dmidata[DMI_MB][BRAND], false, "%s", dmi_string(h, data[0x04])); casprintf(dmidata[DMI_MB][BIOSVERSION], false, "%s", dmi_string(h, data[0x05])); casprintf(dmidata[DMI_MB][DATE], false, "%s", dmi_string(h, data[0x08])); casprintf(dmidata[DMI_MB][ROMSIZE], true, "%s / %s", dmi_bios_runtime_size_str((0x10000 - WORD(data + 0x06)) << 4), dmi_bios_rom_size_str(data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18))); } else { printf("BIOS Information\n"); if (h->length < 0x12) break; printf("\tVendor: %s\n", dmi_string(h, data[0x04])); printf("\tVersion: %s\n", dmi_string(h, data[0x05])); printf("\tRelease Date: %s\n", dmi_string(h, data[0x08])); /* * On IA-64, the BIOS base address will read 0 because * there is no BIOS. Skip the base address and the * runtime size in this case. */ if (WORD(data + 0x06) != 0) { printf("\tAddress: 0x%04X0\n", WORD(data + 0x06)); printf("\tRuntime Size:"); dmi_bios_runtime_size((0x10000 - WORD(data + 0x06)) << 4); printf("\n"); } printf("\tROM Size:"); dmi_bios_rom_size(data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18)); printf("\n"); printf("\tCharacteristics:\n"); dmi_bios_characteristics(QWORD(data + 0x0A), "\t\t"); if (h->length < 0x13) break; dmi_bios_characteristics_x1(data[0x12], "\t\t"); if (h->length < 0x14) break; dmi_bios_characteristics_x2(data[0x13], "\t\t"); if (h->length < 0x18) break; if (data[0x14] != 0xFF && data[0x15] != 0xFF) printf("\tBIOS Revision: %u.%u\n", data[0x14], data[0x15]); if (data[0x16] != 0xFF && data[0x17] != 0xFF) printf("\tFirmware Revision: %u.%u\n", data[0x16], data[0x17]); } break; case 1: /* 7.2 System Information */ printf("System Information\n"); if (h->length < 0x08) break; printf("\tManufacturer: %s\n", dmi_string(h, data[0x04])); printf("\tProduct Name: %s\n", dmi_string(h, data[0x05])); printf("\tVersion: %s\n", dmi_string(h, data[0x06])); printf("\tSerial Number: %s\n", dmi_string(h, data[0x07])); if (h->length < 0x19) break; printf("\tUUID: "); dmi_system_uuid(data + 0x08, ver); printf("\n"); printf("\tWake-up Type: %s\n", dmi_system_wake_up_type(data[0x18])); if (h->length < 0x1B) break; printf("\tSKU Number: %s\n", dmi_string(h, data[0x19])); printf("\tFamily: %s\n", dmi_string(h, data[0x1A])); break; case 2: /* 7.3 Base Board Information */ if(opt.flags & FLAG_CPU_X) { casprintf(dmidata[DMI_MB][MANUFACTURER], false, "%s", dmi_string(h, data[0x04])); casprintf(dmidata[DMI_MB][MBMODEL], false, "%s", dmi_string(h, data[0x05])); casprintf(dmidata[DMI_MB][REVISION], false, "%s", dmi_string(h, data[0x06])); } else { printf("Base Board Information\n"); if (h->length < 0x08) break; printf("\tManufacturer: %s\n", dmi_string(h, data[0x04])); printf("\tProduct Name: %s\n", dmi_string(h, data[0x05])); printf("\tVersion: %s\n", dmi_string(h, data[0x06])); printf("\tSerial Number: %s\n", dmi_string(h, data[0x07])); if (h->length < 0x09) break; printf("\tAsset Tag: %s\n", dmi_string(h, data[0x08])); if (h->length < 0x0A) break; printf("\tFeatures:"); dmi_base_board_features(data[0x09], "\t\t"); if (h->length < 0x0E) break; printf("\tLocation In Chassis: %s\n", dmi_string(h, data[0x0A])); if (!(opt.flags & FLAG_QUIET)) printf("\tChassis Handle: 0x%04X\n", WORD(data + 0x0B)); printf("\tType: %s\n", dmi_base_board_type(data[0x0D])); if (h->length < 0x0F) break; if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break; if (!(opt.flags & FLAG_QUIET)) dmi_base_board_handles(data[0x0E], data + 0x0F, "\t"); } break; case 3: /* 7.4 Chassis Information */ printf("Chassis Information\n"); if (h->length < 0x09) break; printf("\tManufacturer: %s\n", dmi_string(h, data[0x04])); printf("\tType: %s\n", dmi_chassis_type(data[0x05])); printf("\tLock: %s\n", dmi_chassis_lock(data[0x05] >> 7)); printf("\tVersion: %s\n", dmi_string(h, data[0x06])); printf("\tSerial Number: %s\n", dmi_string(h, data[0x07])); printf("\tAsset Tag: %s\n", dmi_string(h, data[0x08])); if (h->length < 0x0D) break; printf("\tBoot-up State: %s\n", dmi_chassis_state(data[0x09])); printf("\tPower Supply State: %s\n", dmi_chassis_state(data[0x0A])); printf("\tThermal State: %s\n", dmi_chassis_state(data[0x0B])); printf("\tSecurity Status: %s\n", dmi_chassis_security_status(data[0x0C])); if (h->length < 0x11) break; printf("\tOEM Information: 0x%08X\n", DWORD(data + 0x0D)); if (h->length < 0x13) break; printf("\tHeight:"); dmi_chassis_height(data[0x11]); printf("\n"); printf("\tNumber Of Power Cords:"); dmi_chassis_power_cords(data[0x12]); printf("\n"); if (h->length < 0x15) break; if (h->length < 0x15 + data[0x13] * data[0x14]) break; dmi_chassis_elements(data[0x13], data[0x14], data + 0x15, "\t"); if (h->length < 0x16 + data[0x13] * data[0x14]) break; printf("\tSKU Number: %s\n", dmi_string(h, data[0x15 + data[0x13] * data[0x14]])); break; case 4: /* 7.5 Processor Information */ if(opt.flags & FLAG_CPU_X) { casprintf(dmidata[DMI_CPU][0], false, "%s", dmi_string(h, data[0x04])); if(*ext_clk == 0.0) *ext_clk = (double) WORD(data + 0x12); } else { printf("Processor Information\n"); if (h->length < 0x1A) break; printf("\tSocket Designation: %s\n", dmi_string(h, data[0x04])); printf("\tType: %s\n", dmi_processor_type(data[0x05])); printf("\tFamily: %s\n", dmi_processor_family(h, ver)); printf("\tManufacturer: %s\n", dmi_string(h, data[0x07])); dmi_processor_id(h, "\t"); printf("\tVersion: %s\n", dmi_string(h, data[0x10])); printf("\tVoltage:"); dmi_processor_voltage(data[0x11]); printf("\n"); printf("\tExternal Clock: "); dmi_processor_frequency(data + 0x12); printf("\n"); printf("\tMax Speed: "); dmi_processor_frequency(data + 0x14); printf("\n"); printf("\tCurrent Speed: "); dmi_processor_frequency(data + 0x16); printf("\n"); if (data[0x18] & (1 << 6)) printf("\tStatus: Populated, %s\n", dmi_processor_status(data[0x18] & 0x07)); else printf("\tStatus: Unpopulated\n"); printf("\tUpgrade: %s\n", dmi_processor_upgrade(data[0x19])); if (h->length < 0x20) break; if (!(opt.flags & FLAG_QUIET)) { printf("\tL1 Cache Handle:"); dmi_processor_cache(WORD(data + 0x1A), "L1", ver); printf("\n"); printf("\tL2 Cache Handle:"); dmi_processor_cache(WORD(data + 0x1C), "L2", ver); printf("\n"); printf("\tL3 Cache Handle:"); dmi_processor_cache(WORD(data + 0x1E), "L3", ver); printf("\n"); } if (h->length < 0x23) break; printf("\tSerial Number: %s\n", dmi_string(h, data[0x20])); printf("\tAsset Tag: %s\n", dmi_string(h, data[0x21])); printf("\tPart Number: %s\n", dmi_string(h, data[0x22])); if (h->length < 0x28) break; if (data[0x23] != 0) printf("\tCore Count: %u\n", h->length >= 0x2C && data[0x23] == 0xFF ? WORD(data + 0x2A) : data[0x23]); if (data[0x24] != 0) printf("\tCore Enabled: %u\n", h->length >= 0x2E && data[0x24] == 0xFF ? WORD(data + 0x2C) : data[0x24]); if (data[0x25] != 0) printf("\tThread Count: %u\n", h->length >= 0x30 && data[0x25] == 0xFF ? WORD(data + 0x2E) : data[0x25]); printf("\tCharacteristics:"); dmi_processor_characteristics(WORD(data + 0x26), "\t\t"); } break; case 5: /* 7.6 Memory Controller Information */ printf("Memory Controller Information\n"); if (h->length < 0x0F) break; printf("\tError Detecting Method: %s\n", dmi_memory_controller_ed_method(data[0x04])); printf("\tError Correcting Capabilities:"); dmi_memory_controller_ec_capabilities(data[0x05], "\t\t"); printf("\tSupported Interleave: %s\n", dmi_memory_controller_interleave(data[0x06])); printf("\tCurrent Interleave: %s\n", dmi_memory_controller_interleave(data[0x07])); printf("\tMaximum Memory Module Size: %u MB\n", 1 << data[0x08]); printf("\tMaximum Total Memory Size: %u MB\n", data[0x0E] * (1 << data[0x08])); printf("\tSupported Speeds:"); dmi_memory_controller_speeds(WORD(data + 0x09), "\t\t"); printf("\tSupported Memory Types:"); dmi_memory_module_types(WORD(data + 0x0B), "\n\t\t"); printf("\n"); printf("\tMemory Module Voltage:"); dmi_processor_voltage(data[0x0D]); printf("\n"); if (h->length < 0x0F + data[0x0E] * sizeof(u16)) break; dmi_memory_controller_slots(data[0x0E], data + 0x0F, "\t"); if (h->length < 0x10 + data[0x0E] * sizeof(u16)) break; printf("\tEnabled Error Correcting Capabilities:"); dmi_memory_controller_ec_capabilities(data[0x0F + data[0x0E] * sizeof(u16)], "\t\t"); break; case 6: /* 7.7 Memory Module Information */ printf("Memory Module Information\n"); if (h->length < 0x0C) break; printf("\tSocket Designation: %s\n", dmi_string(h, data[0x04])); printf("\tBank Connections:"); dmi_memory_module_connections(data[0x05]); printf("\n"); printf("\tCurrent Speed:"); dmi_memory_module_speed(data[0x06]); printf("\n"); printf("\tType:"); dmi_memory_module_types(WORD(data + 0x07), " "); printf("\n"); printf("\tInstalled Size:"); dmi_memory_module_size(data[0x09]); printf("\n"); printf("\tEnabled Size:"); dmi_memory_module_size(data[0x0A]); printf("\n"); printf("\tError Status:"); dmi_memory_module_error(data[0x0B], "\t\t"); break; case 7: /* 7.8 Cache Information */ printf("Cache Information\n"); if (h->length < 0x0F) break; printf("\tSocket Designation: %s\n", dmi_string(h, data[0x04])); printf("\tConfiguration: %s, %s, Level %u\n", WORD(data + 0x05) & 0x0080 ? "Enabled" : "Disabled", WORD(data + 0x05) & 0x0008 ? "Socketed" : "Not Socketed", (WORD(data + 0x05) & 0x0007) + 1); printf("\tOperational Mode: %s\n", dmi_cache_mode((WORD(data + 0x05) >> 8) & 0x0003)); printf("\tLocation: %s\n", dmi_cache_location((WORD(data + 0x05) >> 5) & 0x0003)); printf("\tInstalled Size:"); if (h->length >= 0x1B) dmi_cache_size_2(DWORD(data + 0x17)); else dmi_cache_size(WORD(data + 0x09)); printf("\n"); printf("\tMaximum Size:"); if (h->length >= 0x17) dmi_cache_size_2(DWORD(data + 0x13)); else dmi_cache_size(WORD(data + 0x07)); printf("\n"); printf("\tSupported SRAM Types:"); dmi_cache_types(WORD(data + 0x0B), "\n\t\t"); printf("\n"); printf("\tInstalled SRAM Type:"); dmi_cache_types(WORD(data + 0x0D), " "); printf("\n"); if (h->length < 0x13) break; printf("\tSpeed:"); dmi_memory_module_speed(data[0x0F]); printf("\n"); printf("\tError Correction Type: %s\n", dmi_cache_ec_type(data[0x10])); printf("\tSystem Type: %s\n", dmi_cache_type(data[0x11])); printf("\tAssociativity: %s\n", dmi_cache_associativity(data[0x12])); break; case 8: /* 7.9 Port Connector Information */ printf("Port Connector Information\n"); if (h->length < 0x09) break; printf("\tInternal Reference Designator: %s\n", dmi_string(h, data[0x04])); printf("\tInternal Connector Type: %s\n", dmi_port_connector_type(data[0x05])); printf("\tExternal Reference Designator: %s\n", dmi_string(h, data[0x06])); printf("\tExternal Connector Type: %s\n", dmi_port_connector_type(data[0x07])); printf("\tPort Type: %s\n", dmi_port_type(data[0x08])); break; case 9: /* 7.10 System Slots */ printf("System Slot Information\n"); if (h->length < 0x0C) break; printf("\tDesignation: %s\n", dmi_string(h, data[0x04])); printf("\tType: %s%s\n", dmi_slot_bus_width(data[0x06]), dmi_slot_type(data[0x05])); printf("\tCurrent Usage: %s\n", dmi_slot_current_usage(data[0x07])); printf("\tLength: %s\n", dmi_slot_length(data[0x08])); dmi_slot_id(data[0x09], data[0x0A], data[0x05], "\t"); printf("\tCharacteristics:"); if (h->length < 0x0D) dmi_slot_characteristics(data[0x0B], 0x00, "\t\t"); else dmi_slot_characteristics(data[0x0B], data[0x0C], "\t\t"); if (h->length < 0x11) break; dmi_slot_segment_bus_func(WORD(data + 0x0D), data[0x0F], data[0x10], "\t"); break; case 10: /* 7.11 On Board Devices Information */ dmi_on_board_devices(h, ""); break; case 11: /* 7.12 OEM Strings */ printf("OEM Strings\n"); if (h->length < 0x05) break; dmi_oem_strings(h, "\t"); break; case 12: /* 7.13 System Configuration Options */ printf("System Configuration Options\n"); if (h->length < 0x05) break; dmi_system_configuration_options(h, "\t"); break; case 13: /* 7.14 BIOS Language Information */ printf("BIOS Language Information\n"); if (h->length < 0x16) break; if (ver >= 0x0201) { printf("\tLanguage Description Format: %s\n", dmi_bios_language_format(data[0x05])); } printf("\tInstallable Languages: %u\n", data[0x04]); dmi_bios_languages(h, "\t\t"); printf("\tCurrently Installed Language: %s\n", dmi_string(h, data[0x15])); break; case 14: /* 7.15 Group Associations */ printf("Group Associations\n"); if (h->length < 0x05) break; printf("\tName: %s\n", dmi_string(h, data[0x04])); printf("\tItems: %u\n", (h->length - 0x05) / 3); dmi_group_associations_items((h->length - 0x05) / 3, data + 0x05, "\t\t"); break; case 15: /* 7.16 System Event Log */ printf("System Event Log\n"); if (h->length < 0x14) break; printf("\tArea Length: %u bytes\n", WORD(data + 0x04)); printf("\tHeader Start Offset: 0x%04X\n", WORD(data + 0x06)); if (WORD(data + 0x08) - WORD(data + 0x06)) printf("\tHeader Length: %u byte%s\n", WORD(data + 0x08) - WORD(data + 0x06), WORD(data + 0x08) - WORD(data + 0x06) > 1 ? "s" : ""); printf("\tData Start Offset: 0x%04X\n", WORD(data + 0x08)); printf("\tAccess Method: %s\n", dmi_event_log_method(data[0x0A])); printf("\tAccess Address:"); dmi_event_log_address(data[0x0A], data + 0x10); printf("\n"); printf("\tStatus:"); dmi_event_log_status(data[0x0B]); printf("\n"); printf("\tChange Token: 0x%08X\n", DWORD(data + 0x0C)); if (h->length < 0x17) break; printf("\tHeader Format: %s\n", dmi_event_log_header_type(data[0x14])); printf("\tSupported Log Type Descriptors: %u\n", data[0x15]); if (h->length < 0x17 + data[0x15] * data[0x16]) break; dmi_event_log_descriptors(data[0x15], data[0x16], data + 0x17, "\t"); break; case 16: /* 7.17 Physical Memory Array */ printf("Physical Memory Array\n"); if (h->length < 0x0F) break; printf("\tLocation: %s\n", dmi_memory_array_location(data[0x04])); printf("\tUse: %s\n", dmi_memory_array_use(data[0x05])); printf("\tError Correction Type: %s\n", dmi_memory_array_ec_type(data[0x06])); printf("\tMaximum Capacity:"); if (DWORD(data + 0x07) == 0x80000000) { if (h->length < 0x17) printf(" Unknown"); else dmi_print_memory_size(QWORD(data + 0x0F), 0); } else { u64 capacity; capacity.h = 0; capacity.l = DWORD(data + 0x07); dmi_print_memory_size(capacity, 1); } printf("\n"); if (!(opt.flags & FLAG_QUIET)) { printf("\tError Information Handle:"); dmi_memory_array_error_handle(WORD(data + 0x0B)); printf("\n"); } printf("\tNumber Of Devices: %u\n", WORD(data + 0x0D)); break; case 17: /* 7.18 Memory Device */ if((opt.flags & FLAG_CPU_X) && *bank < LASTMEMORY) { if((strstr(dmi_string(h, data[0x17]), "Empty") != NULL) || (strstr(dmi_string(h, data[0x17]), "Not Specified") != NULL) || (WORD(data + 0x0C) == 0)) casprintf(dmidata[DMI_RAM][*bank], false, "- - - - - - - - - - - - - - - - - - -"); else { casprintf(dmidata[DMI_RAM][*bank], true, "%s %s, %s @ %uMHz (%s %s)", dmi_string(h, data[0x17]), dmi_string(h, data[0x1A]), dmi_memory_device_size_str(WORD(data + 0x0C)), (WORD(data + 0x15)), dmi_memory_device_form_factor(data[0x0E]), dmi_memory_device_type(data[0x12])); } (*bank)++; } else { printf("Memory Device\n"); if (h->length < 0x15) break; if (!(opt.flags & FLAG_QUIET)) { printf("\tArray Handle: 0x%04X\n", WORD(data + 0x04)); printf("\tError Information Handle:"); dmi_memory_array_error_handle(WORD(data + 0x06)); printf("\n"); } printf("\tTotal Width:"); dmi_memory_device_width(WORD(data + 0x08)); printf("\n"); printf("\tData Width:"); dmi_memory_device_width(WORD(data + 0x0A)); printf("\n"); printf("\tSize:"); if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF) dmi_memory_device_extended_size(DWORD(data + 0x1C)); else dmi_memory_device_size(WORD(data + 0x0C)); printf("\n"); printf("\tForm Factor: %s\n", dmi_memory_device_form_factor(data[0x0E])); printf("\tSet:"); dmi_memory_device_set(data[0x0F]); printf("\n"); printf("\tLocator: %s\n", dmi_string(h, data[0x10])); printf("\tBank Locator: %s\n", dmi_string(h, data[0x11])); printf("\tType: %s\n", dmi_memory_device_type(data[0x12])); printf("\tType Detail:"); dmi_memory_device_type_detail(WORD(data + 0x13)); printf("\n"); if (h->length < 0x17) break; printf("\tSpeed:"); dmi_memory_device_speed(WORD(data + 0x15)); printf("\n"); if (h->length < 0x1B) break; printf("\tManufacturer: %s\n", dmi_string(h, data[0x17])); printf("\tSerial Number: %s\n", dmi_string(h, data[0x18])); printf("\tAsset Tag: %s\n", dmi_string(h, data[0x19])); printf("\tPart Number: %s\n", dmi_string(h, data[0x1A])); if (h->length < 0x1C) break; printf("\tRank: "); if ((data[0x1B] & 0x0F) == 0) printf("Unknown"); else printf("%u", data[0x1B] & 0x0F); printf("\n"); if (h->length < 0x22) break; printf("\tConfigured Clock Speed:"); dmi_memory_device_speed(WORD(data + 0x20)); printf("\n"); if (h->length < 0x28) break; printf("\tMinimum Voltage:"); dmi_memory_voltage_value(WORD(data + 0x22)); printf("\n"); printf("\tMaximum Voltage:"); dmi_memory_voltage_value(WORD(data + 0x24)); printf("\n"); printf("\tConfigured Voltage:"); dmi_memory_voltage_value(WORD(data + 0x26)); printf("\n"); } break; case 18: /* 7.19 32-bit Memory Error Information */ printf("32-bit Memory Error Information\n"); if (h->length < 0x17) break; printf("\tType: %s\n", dmi_memory_error_type(data[0x04])); printf("\tGranularity: %s\n", dmi_memory_error_granularity(data[0x05])); printf("\tOperation: %s\n", dmi_memory_error_operation(data[0x06])); printf("\tVendor Syndrome:"); dmi_memory_error_syndrome(DWORD(data + 0x07)); printf("\n"); printf("\tMemory Array Address:"); dmi_32bit_memory_error_address(DWORD(data + 0x0B)); printf("\n"); printf("\tDevice Address:"); dmi_32bit_memory_error_address(DWORD(data + 0x0F)); printf("\n"); printf("\tResolution:"); dmi_32bit_memory_error_address(DWORD(data + 0x13)); printf("\n"); if (h->length < 0x34) break; printf("\tMemory Technology:"); dmi_memory_technology(data[0x28]); printf("\n"); printf("\tMemory Operating Mode Capability:"); dmi_memory_operating_mode_capability(WORD(data + 0x29)); printf("\n"); printf("\tFirmware Version: %s\n", dmi_string(h, data[0x2B])); printf("\tModule Manufacturer ID:"); dmi_memory_manufacturer_id(WORD(data + 0x2C)); printf("\n"); printf("\tModule Product ID:"); dmi_memory_product_id(WORD(data + 0x2E)); printf("\n"); printf("\tMemory Subsystem Controller Manufacturer ID:"); dmi_memory_manufacturer_id(WORD(data + 0x30)); printf("\n"); printf("\tMemory Subsystem Controller Product ID:"); dmi_memory_product_id(WORD(data + 0x32)); printf("\n"); if (h->length < 0x3C) break; printf("\tNon-Volatile Size:"); dmi_memory_size(QWORD(data + 0x34)); printf("\n"); if (h->length < 0x44) break; printf("\tVolatile Size:"); dmi_memory_size(QWORD(data + 0x3C)); printf("\n"); if (h->length < 0x4C) break; printf("\tCache Size:"); dmi_memory_size(QWORD(data + 0x44)); printf("\n"); if (h->length < 0x54) break; printf("\tLogical Size:"); dmi_memory_size(QWORD(data + 0x4C)); printf("\n"); break; case 19: /* 7.20 Memory Array Mapped Address */ printf("Memory Array Mapped Address\n"); if (h->length < 0x0F) break; if (h->length >= 0x1F && DWORD(data + 0x04) == 0xFFFFFFFF) { u64 start, end; start = QWORD(data + 0x0F); end = QWORD(data + 0x17); printf("\tStarting Address: 0x%08X%08Xk\n", start.h, start.l); printf("\tEnding Address: 0x%08X%08Xk\n", end.h, end.l); printf("\tRange Size:"); dmi_mapped_address_extended_size(start, end); } else { printf("\tStarting Address: 0x%08X%03X\n", DWORD(data + 0x04) >> 2, (DWORD(data + 0x04) & 0x3) << 10); printf("\tEnding Address: 0x%08X%03X\n", DWORD(data + 0x08) >> 2, ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); printf("\tRange Size:"); dmi_mapped_address_size(DWORD(data + 0x08) - DWORD(data + 0x04) + 1); } printf("\n"); if (!(opt.flags & FLAG_QUIET)) printf("\tPhysical Array Handle: 0x%04X\n", WORD(data + 0x0C)); printf("\tPartition Width: %u\n", data[0x0E]); break; case 20: /* 7.21 Memory Device Mapped Address */ printf("Memory Device Mapped Address\n"); if (h->length < 0x13) break; if (h->length >= 0x23 && DWORD(data + 0x04) == 0xFFFFFFFF) { u64 start, end; start = QWORD(data + 0x13); end = QWORD(data + 0x1B); printf("\tStarting Address: 0x%08X%08Xk\n", start.h, start.l); printf("\tEnding Address: 0x%08X%08Xk\n", end.h, end.l); printf("\tRange Size:"); dmi_mapped_address_extended_size(start, end); } else { printf("\tStarting Address: 0x%08X%03X\n", DWORD(data + 0x04) >> 2, (DWORD(data + 0x04) & 0x3) << 10); printf("\tEnding Address: 0x%08X%03X\n", DWORD(data + 0x08) >> 2, ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); printf("\tRange Size:"); dmi_mapped_address_size(DWORD(data + 0x08) - DWORD(data + 0x04) + 1); } printf("\n"); if (!(opt.flags & FLAG_QUIET)) { printf("\tPhysical Device Handle: 0x%04X\n", WORD(data + 0x0C)); printf("\tMemory Array Mapped Address Handle: 0x%04X\n", WORD(data + 0x0E)); } printf("\tPartition Row Position:"); dmi_mapped_address_row_position(data[0x10]); printf("\n"); dmi_mapped_address_interleave_position(data[0x11], "\t"); dmi_mapped_address_interleaved_data_depth(data[0x12], "\t"); break; case 21: /* 7.22 Built-in Pointing Device */ printf("Built-in Pointing Device\n"); if (h->length < 0x07) break; printf("\tType: %s\n", dmi_pointing_device_type(data[0x04])); printf("\tInterface: %s\n", dmi_pointing_device_interface(data[0x05])); printf("\tButtons: %u\n", data[0x06]); break; case 22: /* 7.23 Portable Battery */ printf("Portable Battery\n"); if (h->length < 0x10) break; printf("\tLocation: %s\n", dmi_string(h, data[0x04])); printf("\tManufacturer: %s\n", dmi_string(h, data[0x05])); if (data[0x06] || h->length < 0x1A) printf("\tManufacture Date: %s\n", dmi_string(h, data[0x06])); if (data[0x07] || h->length < 0x1A) printf("\tSerial Number: %s\n", dmi_string(h, data[0x07])); printf("\tName: %s\n", dmi_string(h, data[0x08])); if (data[0x09] != 0x02 || h->length < 0x1A) printf("\tChemistry: %s\n", dmi_battery_chemistry(data[0x09])); printf("\tDesign Capacity:"); if (h->length < 0x16) dmi_battery_capacity(WORD(data + 0x0A), 1); else dmi_battery_capacity(WORD(data + 0x0A), data[0x15]); printf("\n"); printf("\tDesign Voltage:"); dmi_battery_voltage(WORD(data + 0x0C)); printf("\n"); printf("\tSBDS Version: %s\n", dmi_string(h, data[0x0E])); printf("\tMaximum Error:"); dmi_battery_maximum_error(data[0x0F]); printf("\n"); if (h->length < 0x1A) break; if (data[0x07] == 0) printf("\tSBDS Serial Number: %04X\n", WORD(data + 0x10)); if (data[0x06] == 0) printf("\tSBDS Manufacture Date: %u-%02u-%02u\n", 1980 + (WORD(data + 0x12) >> 9), (WORD(data + 0x12) >> 5) & 0x0F, WORD(data + 0x12) & 0x1F); if (data[0x09] == 0x02) printf("\tSBDS Chemistry: %s\n", dmi_string(h, data[0x14])); printf("\tOEM-specific Information: 0x%08X\n", DWORD(data + 0x16)); break; case 23: /* 7.24 System Reset */ printf("System Reset\n"); if (h->length < 0x0D) break; printf("\tStatus: %s\n", data[0x04] & (1 << 0) ? "Enabled" : "Disabled"); printf("\tWatchdog Timer: %s\n", data[0x04] & (1 << 5) ? "Present" : "Not Present"); if (!(data[0x04] & (1 << 5))) break; printf("\tBoot Option: %s\n", dmi_system_reset_boot_option((data[0x04] >> 1) & 0x3)); printf("\tBoot Option On Limit: %s\n", dmi_system_reset_boot_option((data[0x04] >> 3) & 0x3)); printf("\tReset Count:"); dmi_system_reset_count(WORD(data + 0x05)); printf("\n"); printf("\tReset Limit:"); dmi_system_reset_count(WORD(data + 0x07)); printf("\n"); printf("\tTimer Interval:"); dmi_system_reset_timer(WORD(data + 0x09)); printf("\n"); printf("\tTimeout:"); dmi_system_reset_timer(WORD(data + 0x0B)); printf("\n"); break; case 24: /* 7.25 Hardware Security */ printf("Hardware Security\n"); if (h->length < 0x05) break; printf("\tPower-On Password Status: %s\n", dmi_hardware_security_status(data[0x04] >> 6)); printf("\tKeyboard Password Status: %s\n", dmi_hardware_security_status((data[0x04] >> 4) & 0x3)); printf("\tAdministrator Password Status: %s\n", dmi_hardware_security_status((data[0x04] >> 2) & 0x3)); printf("\tFront Panel Reset Status: %s\n", dmi_hardware_security_status(data[0x04] & 0x3)); break; case 25: /* 7.26 System Power Controls */ printf("\tSystem Power Controls\n"); if (h->length < 0x09) break; printf("\tNext Scheduled Power-on:"); dmi_power_controls_power_on(data + 0x04); printf("\n"); break; case 26: /* 7.27 Voltage Probe */ printf("Voltage Probe\n"); if (h->length < 0x14) break; printf("\tDescription: %s\n", dmi_string(h, data[0x04])); printf("\tLocation: %s\n", dmi_voltage_probe_location(data[0x05] & 0x1f)); printf("\tStatus: %s\n", dmi_probe_status(data[0x05] >> 5)); printf("\tMaximum Value:"); dmi_voltage_probe_value(WORD(data + 0x06)); printf("\n"); printf("\tMinimum Value:"); dmi_voltage_probe_value(WORD(data + 0x08)); printf("\n"); printf("\tResolution:"); dmi_voltage_probe_resolution(WORD(data + 0x0A)); printf("\n"); printf("\tTolerance:"); dmi_voltage_probe_value(WORD(data + 0x0C)); printf("\n"); printf("\tAccuracy:"); dmi_probe_accuracy(WORD(data + 0x0E)); printf("\n"); printf("\tOEM-specific Information: 0x%08X\n", DWORD(data + 0x10)); if (h->length < 0x16) break; printf("\tNominal Value:"); dmi_voltage_probe_value(WORD(data + 0x14)); printf("\n"); break; case 27: /* 7.28 Cooling Device */ printf("Cooling Device\n"); if (h->length < 0x0C) break; if (!(opt.flags & FLAG_QUIET) && WORD(data + 0x04) != 0xFFFF) printf("\tTemperature Probe Handle: 0x%04X\n", WORD(data + 0x04)); printf("\tType: %s\n", dmi_cooling_device_type(data[0x06] & 0x1f)); printf("\tStatus: %s\n", dmi_probe_status(data[0x06] >> 5)); if (data[0x07] != 0x00) printf("\tCooling Unit Group: %u\n", data[0x07]); printf("\tOEM-specific Information: 0x%08X\n", DWORD(data + 0x08)); if (h->length < 0x0E) break; printf("\tNominal Speed:"); dmi_cooling_device_speed(WORD(data + 0x0C)); printf("\n"); if (h->length < 0x0F) break; printf("\tDescription: %s\n", dmi_string(h, data[0x0E])); break; case 28: /* 7.29 Temperature Probe */ printf("Temperature Probe\n"); if (h->length < 0x14) break; printf("\tDescription: %s\n", dmi_string(h, data[0x04])); printf("\tLocation: %s\n", dmi_temperature_probe_location(data[0x05] & 0x1F)); printf("\tStatus: %s\n", dmi_probe_status(data[0x05] >> 5)); printf("\tMaximum Value:"); dmi_temperature_probe_value(WORD(data + 0x06)); printf("\n"); printf("\tMinimum Value:"); dmi_temperature_probe_value(WORD(data + 0x08)); printf("\n"); printf("\tResolution:"); dmi_temperature_probe_resolution(WORD(data + 0x0A)); printf("\n"); printf("\tTolerance:"); dmi_temperature_probe_value(WORD(data + 0x0C)); printf("\n"); printf("\tAccuracy:"); dmi_probe_accuracy(WORD(data + 0x0E)); printf("\n"); printf("\tOEM-specific Information: 0x%08X\n", DWORD(data + 0x10)); if (h->length < 0x16) break; printf("\tNominal Value:"); dmi_temperature_probe_value(WORD(data + 0x14)); printf("\n"); break; case 29: /* 7.30 Electrical Current Probe */ printf("Electrical Current Probe\n"); if (h->length < 0x14) break; printf("\tDescription: %s\n", dmi_string(h, data[0x04])); printf("\tLocation: %s\n", dmi_voltage_probe_location(data[5] & 0x1F)); printf("\tStatus: %s\n", dmi_probe_status(data[0x05] >> 5)); printf("\tMaximum Value:"); dmi_current_probe_value(WORD(data + 0x06)); printf("\n"); printf("\tMinimum Value:"); dmi_current_probe_value(WORD(data + 0x08)); printf("\n"); printf("\tResolution:"); dmi_current_probe_resolution(WORD(data + 0x0A)); printf("\n"); printf("\tTolerance:"); dmi_current_probe_value(WORD(data + 0x0C)); printf("\n"); printf("\tAccuracy:"); dmi_probe_accuracy(WORD(data + 0x0E)); printf("\n"); printf("\tOEM-specific Information: 0x%08X\n", DWORD(data + 0x10)); if (h->length < 0x16) break; printf("\tNominal Value:"); dmi_current_probe_value(WORD(data + 0x14)); printf("\n"); break; case 30: /* 7.31 Out-of-band Remote Access */ printf("Out-of-band Remote Access\n"); if (h->length < 0x06) break; printf("\tManufacturer Name: %s\n", dmi_string(h, data[0x04])); printf("\tInbound Connection: %s\n", data[0x05] & (1 << 0) ? "Enabled" : "Disabled"); printf("\tOutbound Connection: %s\n", data[0x05] & (1 << 1) ? "Enabled" : "Disabled"); break; case 31: /* 7.32 Boot Integrity Services Entry Point */ printf("Boot Integrity Services Entry Point\n"); if (h->length < 0x1C) break; printf("\tChecksum: %s\n", checksum(data, h->length) ? "OK" : "Invalid"); printf("\t16-bit Entry Point Address: %04X:%04X\n", DWORD(data + 0x08) >> 16, DWORD(data + 0x08) & 0xFFFF); printf("\t32-bit Entry Point Address: 0x%08X\n", DWORD(data + 0x0C)); break; case 32: /* 7.33 System Boot Information */ printf("System Boot Information\n"); if (h->length < 0x0B) break; printf("\tStatus: %s\n", dmi_system_boot_status(data[0x0A])); break; case 33: /* 7.34 64-bit Memory Error Information */ if (h->length < 0x1F) break; printf("64-bit Memory Error Information\n"); printf("\tType: %s\n", dmi_memory_error_type(data[0x04])); printf("\tGranularity: %s\n", dmi_memory_error_granularity(data[0x05])); printf("\tOperation: %s\n", dmi_memory_error_operation(data[0x06])); printf("\tVendor Syndrome:"); dmi_memory_error_syndrome(DWORD(data + 0x07)); printf("\n"); printf("\tMemory Array Address:"); dmi_64bit_memory_error_address(QWORD(data + 0x0B)); printf("\n"); printf("\tDevice Address:"); dmi_64bit_memory_error_address(QWORD(data + 0x13)); printf("\n"); printf("\tResolution:"); dmi_32bit_memory_error_address(DWORD(data + 0x1B)); printf("\n"); break; case 34: /* 7.35 Management Device */ printf("Management Device\n"); if (h->length < 0x0B) break; printf("\tDescription: %s\n", dmi_string(h, data[0x04])); printf("\tType: %s\n", dmi_management_device_type(data[0x05])); printf("\tAddress: 0x%08X\n", DWORD(data + 0x06)); printf("\tAddress Type: %s\n", dmi_management_device_address_type(data[0x0A])); break; case 35: /* 7.36 Management Device Component */ printf("Management Device Component\n"); if (h->length < 0x0B) break; printf("\tDescription: %s\n", dmi_string(h, data[0x04])); if (!(opt.flags & FLAG_QUIET)) { printf("\tManagement Device Handle: 0x%04X\n", WORD(data + 0x05)); printf("\tComponent Handle: 0x%04X\n", WORD(data + 0x07)); if (WORD(data + 0x09) != 0xFFFF) printf("\tThreshold Handle: 0x%04X\n", WORD(data + 0x09)); } break; case 36: /* 7.37 Management Device Threshold Data */ printf("Management Device Threshold Data\n"); if (h->length < 0x10) break; if (WORD(data + 0x04) != 0x8000) printf("\tLower Non-critical Threshold: %d\n", (i16)WORD(data + 0x04)); if (WORD(data + 0x06) != 0x8000) printf("\tUpper Non-critical Threshold: %d\n", (i16)WORD(data + 0x06)); if (WORD(data + 0x08) != 0x8000) printf("\tLower Critical Threshold: %d\n", (i16)WORD(data + 0x08)); if (WORD(data + 0x0A) != 0x8000) printf("\tUpper Critical Threshold: %d\n", (i16)WORD(data + 0x0A)); if (WORD(data + 0x0C) != 0x8000) printf("\tLower Non-recoverable Threshold: %d\n", (i16)WORD(data + 0x0C)); if (WORD(data + 0x0E) != 0x8000) printf("\tUpper Non-recoverable Threshold: %d\n", (i16)WORD(data + 0x0E)); break; case 37: /* 7.38 Memory Channel */ printf("Memory Channel\n"); if (h->length < 0x07) break; printf("\tType: %s\n", dmi_memory_channel_type(data[0x04])); printf("\tMaximal Load: %u\n", data[0x05]); printf("\tDevices: %u\n", data[0x06]); if (h->length < 0x07 + 3 * data[0x06]) break; dmi_memory_channel_devices(data[0x06], data + 0x07, "\t"); break; case 38: /* 7.39 IPMI Device Information */ /* * We use the word "Version" instead of "Revision", conforming to * the IPMI specification. */ printf("IPMI Device Information\n"); if (h->length < 0x10) break; printf("\tInterface Type: %s\n", dmi_ipmi_interface_type(data[0x04])); printf("\tSpecification Version: %u.%u\n", data[0x05] >> 4, data[0x05] & 0x0F); printf("\tI2C Slave Address: 0x%02x\n", data[0x06] >> 1); if (data[0x07] != 0xFF) printf("\tNV Storage Device Address: %u\n", data[0x07]); else printf("\tNV Storage Device: Not Present\n"); printf("\tBase Address: "); dmi_ipmi_base_address(data[0x04], data + 0x08, h->length < 0x11 ? 0 : (data[0x10] >> 4) & 1); printf("\n"); if (h->length < 0x12) break; if (data[0x04] != 0x04) { printf("\tRegister Spacing: %s\n", dmi_ipmi_register_spacing(data[0x10] >> 6)); if (data[0x10] & (1 << 3)) { printf("\tInterrupt Polarity: %s\n", data[0x10] & (1 << 1) ? "Active High" : "Active Low"); printf("\tInterrupt Trigger Mode: %s\n", data[0x10] & (1 << 0) ? "Level" : "Edge"); } } if (data[0x11] != 0x00) { printf("\tInterrupt Number: %u\n", data[0x11]); } break; case 39: /* 7.40 System Power Supply */ printf("System Power Supply\n"); if (h->length < 0x10) break; if (data[0x04] != 0x00) printf("\tPower Unit Group: %u\n", data[0x04]); printf("\tLocation: %s\n", dmi_string(h, data[0x05])); printf("\tName: %s\n", dmi_string(h, data[0x06])); printf("\tManufacturer: %s\n", dmi_string(h, data[0x07])); printf("\tSerial Number: %s\n", dmi_string(h, data[0x08])); printf("\tAsset Tag: %s\n", dmi_string(h, data[0x09])); printf("\tModel Part Number: %s\n", dmi_string(h, data[0x0A])); printf("\tRevision: %s\n", dmi_string(h, data[0x0B])); printf("\tMax Power Capacity:"); dmi_power_supply_power(WORD(data + 0x0C)); printf("\n"); printf("\tStatus:"); if (WORD(data + 0x0E) & (1 << 1)) printf(" Present, %s", dmi_power_supply_status((WORD(data + 0x0E) >> 7) & 0x07)); else printf(" Not Present"); printf("\n"); printf("\tType: %s\n", dmi_power_supply_type((WORD(data + 0x0E) >> 10) & 0x0F)); printf("\tInput Voltage Range Switching: %s\n", dmi_power_supply_range_switching((WORD(data + 0x0E) >> 3) & 0x0F)); printf("\tPlugged: %s\n", WORD(data + 0x0E) & (1 << 2) ? "No" : "Yes"); printf("\tHot Replaceable: %s\n", WORD(data + 0x0E) & (1 << 0) ? "Yes" : "No"); if (h->length < 0x16) break; if (!(opt.flags & FLAG_QUIET)) { if (WORD(data + 0x10) != 0xFFFF) printf("\tInput Voltage Probe Handle: 0x%04X\n", WORD(data + 0x10)); if (WORD(data + 0x12) != 0xFFFF) printf("\tCooling Device Handle: 0x%04X\n", WORD(data + 0x12)); if (WORD(data + 0x14) != 0xFFFF) printf("\tInput Current Probe Handle: 0x%04X\n", WORD(data + 0x14)); } break; case 40: /* 7.41 Additional Information */ if (h->length < 0x0B) break; if (opt.flags & FLAG_QUIET) return; dmi_additional_info(h, ""); break; case 41: /* 7.42 Onboard Device Extended Information */ printf("Onboard Device\n"); if (h->length < 0x0B) break; printf("\tReference Designation: %s\n", dmi_string(h, data[0x04])); printf("\tType: %s\n", dmi_on_board_devices_type(data[0x05] & 0x7F)); printf("\tStatus: %s\n", data[0x05] & 0x80 ? "Enabled" : "Disabled"); printf("\tType Instance: %u\n", data[0x06]); dmi_slot_segment_bus_func(WORD(data + 0x07), data[0x09], data[0x0A], "\t"); break; case 42: /* 7.43 Management Controller Host Interface */ printf("Management Controller Host Interface\n"); if (h->length < 0x05) break; printf("\tInterface Type: %s\n", dmi_management_controller_host_type(data[0x04])); /* * There you have a type-dependent, variable-length * part in the middle of the structure, with no * length specifier, so no easy way to decode the * common, final part of the structure. What a pity. */ if (h->length < 0x09) break; if (data[0x04] == 0xF0) /* OEM */ { printf("\tVendor ID: 0x%02X%02X%02X%02X\n", data[0x05], data[0x06], data[0x07], data[0x08]); } break; case 43: /* 7.44 TPM Device */ printf("TPM Device\n"); if (h->length < 0x1B) break; printf("\tVendor ID:"); dmi_tpm_vendor_id(data + 0x04); printf("\n"); printf("\tSpecification Version: %d.%d", data[0x08], data[0x09]); switch (data[0x08]) { case 0x01: /* * We skip the first 2 bytes, which are * redundant with the above, and uncoded * in a silly way. */ printf("\tFirmware Revision: %u.%u\n", data[0x0C], data[0x0D]); break; case 0x02: printf("\tFirmware Revision: %u.%u\n", DWORD(data + 0x0A) >> 16, DWORD(data + 0x0A) & 0xFFFF); /* * We skip the next 4 bytes, as their * format is not standardized and their * usefulness seems limited anyway. */ break; } printf("\tDescription: %s", dmi_string(h, data[0x12])); printf("\tCharacteristics:\n"); dmi_tpm_characteristics(QWORD(data + 0x13), "\t\t"); if (h->length < 0x1F) break; printf("\tOEM-specific Information: 0x%08X\n", DWORD(data + 0x1B)); break; case 126: /* 7.44 Inactive */ printf("Inactive\n"); break; case 127: /* 7.45 End Of Table */ printf("End Of Table\n"); break; default: if (dmi_decode_oem(h)) break; if (opt.flags & FLAG_QUIET) return; printf("%s Type\n", h->type >= 128 ? "OEM-specific" : "Unknown"); dmi_dump(h, "\t"); } if(!(opt.flags & FLAG_CPU_X)) printf("\n"); } static void to_dmi_header(struct dmi_header *h, u8 *data) { h->type = data[0]; h->length = data[1]; h->handle = WORD(data + 2); h->data = data; } static void dmi_table_string(const struct dmi_header *h, const u8 *data, u16 ver) { int key; u8 offset = opt.string->offset; if (opt.string->type == 11) /* OEM strings */ { if (h->length < 5 || offset > data[4]) { fprintf(stderr, "No OEM string number %u\n", offset); return; } if (offset) printf("%s\n", dmi_string(h, offset)); else printf("%u\n", data[4]); /* count */ return; } if (offset >= h->length) return; key = (opt.string->type << 8) | offset; switch (key) { case 0x108: dmi_system_uuid(data + offset, ver); printf("\n"); break; case 0x305: printf("%s\n", dmi_chassis_type(data[offset])); break; case 0x406: printf("%s\n", dmi_processor_family(h, ver)); break; case 0x416: dmi_processor_frequency(data + offset); printf("\n"); break; default: printf("%s\n", dmi_string(h, data[offset])); } } static void dmi_table_dump(const u8 *buf, u32 len) { if (!(opt.flags & FLAG_QUIET)) printf("# Writing %d bytes to %s.\n", len, opt.dumpfile); write_dump(32, len, buf, opt.dumpfile, 0); } static void dmi_table_decode(u8 *buf, u32 len, u16 num, u16 ver, u32 flags) { u8 *data; int i = 0; data = buf; while ((i < num || !num) && data + 4 <= buf + len) /* 4 is the length of an SMBIOS structure header */ { u8 *next; struct dmi_header h; int display; to_dmi_header(&h, data); display = ((opt.type == NULL || opt.type[h.type]) && !((opt.flags & FLAG_QUIET) && (h.type == 126 || h.type == 127)) && !opt.string); /* * If a short entry is found (less than 4 bytes), not only it * is invalid, but we cannot reliably locate the next entry. * Better stop at this point, and let the user know his/her * table is broken. */ if (h.length < 4) { if (!(opt.flags & FLAG_QUIET)) { fprintf(stderr, "Invalid entry length (%u). DMI table " "is broken! Stop.\n\n", (unsigned int)h.length); opt.flags |= FLAG_QUIET; } break; } /* In quiet mode, stop decoding at end of table marker */ if ((opt.flags & FLAG_QUIET) && h.type == 127) break; if (display && (!(opt.flags & FLAG_QUIET) || (opt.flags & FLAG_DUMP))) printf("Handle 0x%04X, DMI type %d, %d bytes\n", h.handle, h.type, h.length); /* assign vendor for vendor-specific decodes later */ if (h.type == 1 && h.length >= 5) dmi_set_vendor(dmi_string(&h, data[0x04])); /* Fixup a common mistake */ if (h.type == 34) dmi_fixup_type_34(&h, display); /* look for the next handle */ next = data + h.length; while ((unsigned long)(next - buf + 1) < len && (next[0] != 0 || next[1] != 0)) next++; next += 2; if (display) { if ((unsigned long)(next - buf) <= len) { if (opt.flags & FLAG_DUMP) { dmi_dump(&h, "\t"); printf("\n"); } else dmi_decode(&h, ver); } else if (!(opt.flags & FLAG_QUIET)) printf("\t\n\n"); } else if (opt.string != NULL && opt.string->type == h.type) dmi_table_string(&h, data, ver); data = next; i++; /* SMBIOS v3 requires stopping at this marker */ if (h.type == 127 && (flags & FLAG_STOP_AT_EOT)) break; } /* * SMBIOS v3 64-bit entry points do not announce a structures count, * and only indicate a maximum size for the table. */ if (!(opt.flags & FLAG_QUIET)) { if (num && i != num) fprintf(stderr, "Wrong DMI structures count: %d announced, " "only %d decoded.\n", num, i); if ((unsigned long)(data - buf) > len || (num && (unsigned long)(data - buf) < len)) fprintf(stderr, "Wrong DMI structures length: %u bytes " "announced, structures occupy %lu bytes.\n", len, (unsigned long)(data - buf)); } } static void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, u32 flags) { u8 *buf; if (ver > SUPPORTED_SMBIOS_VER && !(opt.flags & FLAG_QUIET)) { printf("# SMBIOS implementations newer than version %u.%u.%u are not\n" "# fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 16, (SUPPORTED_SMBIOS_VER >> 8) & 0xFF, SUPPORTED_SMBIOS_VER & 0xFF); } if (!(opt.flags & FLAG_QUIET)) { if (opt.type == NULL) { if (num) printf("%u structures occupying %u bytes.\n", num, len); if (!(opt.flags & FLAG_FROM_DUMP)) printf("Table at 0x%08llX.\n", (unsigned long long)base); } printf("\n"); } if ((flags & FLAG_NO_FILE_OFFSET) || (opt.flags & FLAG_FROM_DUMP)) { /* * When reading from sysfs or from a dump file, the file may be * shorter than announced. For SMBIOS v3 this is expcted, as we * only know the maximum table size, not the actual table size. * For older implementations (and for SMBIOS v3 too), this * would be the result of the kernel truncating the table on * parse error. */ size_t size = len; buf = read_file(flags & FLAG_NO_FILE_OFFSET ? 0 : base, &size, devmem); if (!(opt.flags & FLAG_QUIET) && num && size != (size_t)len) { fprintf(stderr, "Wrong DMI structures length: %u bytes " "announced, only %lu bytes available.\n", len, (unsigned long)size); } len = size; } else buf = mem_chunk(base, len, devmem); if (buf == NULL) { fprintf(stderr, "Failed to read table, sorry.\n"); #ifndef USE_MMAP if (!(flags & FLAG_NO_FILE_OFFSET)) fprintf(stderr, "Try compiling dmidecode with -DUSE_MMAP.\n"); #endif return; } if (opt.flags & FLAG_DUMP_BIN) dmi_table_dump(buf, len); else dmi_table_decode(buf, len, num, ver >> 8, flags); free(buf); } /* * Build a crafted entry point with table address hard-coded to 32, * as this is where we will put it in the output file. We adjust the * DMI checksum appropriately. The SMBIOS checksum needs no adjustment. */ static void overwrite_dmi_address(u8 *buf) { buf[0x05] += buf[0x08] + buf[0x09] + buf[0x0A] + buf[0x0B] - 32; buf[0x08] = 32; buf[0x09] = 0; buf[0x0A] = 0; buf[0x0B] = 0; } /* Same thing for SMBIOS3 entry points */ static void overwrite_smbios3_address(u8 *buf) { buf[0x05] += buf[0x10] + buf[0x11] + buf[0x12] + buf[0x13] + buf[0x14] + buf[0x15] + buf[0x16] + buf[0x17] - 32; buf[0x10] = 32; buf[0x11] = 0; buf[0x12] = 0; buf[0x13] = 0; buf[0x14] = 0; buf[0x15] = 0; buf[0x16] = 0; buf[0x17] = 0; } static int smbios3_decode(u8 *buf, const char *devmem, u32 flags) { u32 ver; u64 offset; if (!checksum(buf, buf[0x06])) return 0; ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; if (!(opt.flags & FLAG_QUIET)) printf("SMBIOS %u.%u.%u present.\n", buf[0x07], buf[0x08], buf[0x09]); offset = QWORD(buf + 0x10); if (!(flags & FLAG_NO_FILE_OFFSET) && offset.h && sizeof(off_t) < 8) { fprintf(stderr, "64-bit addresses not supported, sorry.\n"); return 0; } dmi_table(((off_t)offset.h << 32) | offset.l, DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT); if (opt.flags & FLAG_DUMP_BIN) { u8 crafted[32]; memcpy(crafted, buf, 32); overwrite_smbios3_address(crafted); if (!(opt.flags & FLAG_QUIET)) printf("# Writing %d bytes to %s.\n", crafted[0x06], opt.dumpfile); write_dump(0, crafted[0x06], crafted, opt.dumpfile, 1); } return 1; } static int smbios_decode(u8 *buf, const char *devmem, u32 flags) { u16 ver; if (!checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || !checksum(buf + 0x10, 0x0F)) return 0; ver = (buf[0x06] << 8) + buf[0x07]; /* Some BIOS report weird SMBIOS version, fix that up */ switch (ver) { case 0x021F: case 0x0221: if (!(opt.flags & FLAG_QUIET)) fprintf(stderr, "SMBIOS version fixup (2.%d -> 2.%d).\n", ver & 0xFF, 3); ver = 0x0203; break; case 0x0233: if (!(opt.flags & FLAG_QUIET)) fprintf(stderr, "SMBIOS version fixup (2.%d -> 2.%d).\n", 51, 6); ver = 0x0206; break; } if (!(opt.flags & FLAG_QUIET)) printf("SMBIOS %u.%u present.\n", ver >> 8, ver & 0xFF); dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), ver << 8, devmem, flags); if (opt.flags & FLAG_DUMP_BIN) { u8 crafted[32]; memcpy(crafted, buf, 32); overwrite_dmi_address(crafted + 0x10); if (!(opt.flags & FLAG_QUIET)) printf("# Writing %d bytes to %s.\n", crafted[0x05], opt.dumpfile); write_dump(0, crafted[0x05], crafted, opt.dumpfile, 1); } return 1; } static int legacy_decode(u8 *buf, const char *devmem, u32 flags) { if (!checksum(buf, 0x0F)) return 0; if (!(opt.flags & FLAG_QUIET)) printf("Legacy DMI %u.%u present.\n", buf[0x0E] >> 4, buf[0x0E] & 0x0F); dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8), devmem, flags); if (opt.flags & FLAG_DUMP_BIN) { u8 crafted[16]; memcpy(crafted, buf, 16); overwrite_dmi_address(crafted); if (!(opt.flags & FLAG_QUIET)) printf("# Writing %d bytes to %s.\n", 0x0F, opt.dumpfile); write_dump(0, 0x0F, crafted, opt.dumpfile, 1); } return 1; } /* * Probe for EFI interface */ #define EFI_NOT_FOUND (-1) #define EFI_NO_SMBIOS (-2) static int address_from_efi(off_t *address) { #if defined(__linux__) FILE *efi_systab; const char *filename; char linebuf[64]; #elif defined(__FreeBSD__) char addrstr[KENV_MVALLEN + 1]; #endif const char *eptype; int ret; *address = 0; /* Prevent compiler warning */ #if defined(__linux__) /* * Linux up to 2.6.6: /proc/efi/systab * Linux 2.6.7 and up: /sys/firmware/efi/systab */ if ((efi_systab = fopen(filename = "/sys/firmware/efi/systab", "r")) == NULL && (efi_systab = fopen(filename = "/proc/efi/systab", "r")) == NULL) { /* No EFI interface, fallback to memory scan */ return EFI_NOT_FOUND; } ret = EFI_NO_SMBIOS; while ((fgets(linebuf, sizeof(linebuf) - 1, efi_systab)) != NULL) { char *addrp = strchr(linebuf, '='); *(addrp++) = '\0'; if (strcmp(linebuf, "SMBIOS3") == 0 || strcmp(linebuf, "SMBIOS") == 0) { *address = strtoull(addrp, NULL, 0); eptype = linebuf; ret = 0; break; } } if (fclose(efi_systab) != 0) perror(filename); if (ret == EFI_NO_SMBIOS) fprintf(stderr, "%s: SMBIOS entry point missing\n", filename); #elif defined(__FreeBSD__) /* * On FreeBSD, SMBIOS anchor base address in UEFI mode is exposed * via kernel environment: * https://svnweb.freebsd.org/base?view=revision&revision=307326 */ ret = kenv(KENV_GET, "hint.smbios.0.mem", addrstr, sizeof(addrstr)); if (ret == -1) { if (errno != ENOENT) perror("kenv"); return EFI_NOT_FOUND; } *address = strtoull(addrstr, NULL, 0); eptype = "SMBIOS"; ret = 0; #else ret = EFI_NOT_FOUND; #endif if (ret == 0 && !(opt.flags & FLAG_QUIET)) printf("# %s entry point at 0x%08llx\n", eptype, (unsigned long long)*address); return ret; } int dmidecode(void) { int ret = 0; /* Returned value */ int found = 0; off_t fp; size_t size; int efi; u8 *buf; char *argv[] = { "dmidecode (built-in with CPU-X)", NULL }; /* * We don't want stdout and stderr to be mixed up if both are * redirected to the same file. */ setlinebuf(stdout); setlinebuf(stderr); if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0) { fprintf(stderr, "%s: compiler incompatibility\n", argv[0]); exit(255); } /* Set default option values */ opt.devmem = DEFAULT_MEM_DEV; #if 0 opt.flags = 0; if (parse_command_line(argc, argv)<0) { ret = 2; goto exit_free; } if (opt.flags & FLAG_HELP) { print_help(); goto exit_free; } if (opt.flags & FLAG_VERSION) { printf("%s\n", VERSION); goto exit_free; } #endif if (!(opt.flags & FLAG_CPU_X)) printf("# %s %s\n", argv[0], VERSION); /* Read from dump if so instructed */ if (opt.flags & FLAG_FROM_DUMP) { if (!(opt.flags & FLAG_QUIET)) printf("Reading SMBIOS/DMI data from file %s.\n", opt.dumpfile); if ((buf = mem_chunk(0, 0x20, opt.dumpfile)) == NULL) { ret = 1; goto exit_free; } if (memcmp(buf, "_SM3_", 5) == 0) { if (smbios3_decode(buf, opt.dumpfile, 0)) found++; } else if (memcmp(buf, "_SM_", 4) == 0) { if (smbios_decode(buf, opt.dumpfile, 0)) found++; } else if (memcmp(buf, "_DMI_", 5) == 0) { if (legacy_decode(buf, opt.dumpfile, 0)) found++; } goto done; } /* * First try reading from sysfs tables. The entry point file could * contain one of several types of entry points, so read enough for * the largest one, then determine what type it contains. */ size = 0x20; if (!(opt.flags & FLAG_NO_SYSFS) && (buf = read_file(0, &size, SYS_ENTRY_FILE)) != NULL) { if (!(opt.flags & FLAG_QUIET)) printf("Getting SMBIOS data from sysfs.\n"); if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0) { if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET)) found++; } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0) { if (smbios_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET)) found++; } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0) { if (legacy_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET)) found++; } if (found) goto done; if (!(opt.flags & FLAG_QUIET)) printf("Failed to get SMBIOS data from sysfs.\n"); } /* Next try EFI (ia64, Intel-based Mac) */ efi = address_from_efi(&fp); switch (efi) { case EFI_NOT_FOUND: goto memory_scan; case EFI_NO_SMBIOS: ret = 1; goto exit_free; } if (!(opt.flags & FLAG_QUIET)) printf("Found SMBIOS entry point in EFI, reading table from %s.\n", opt.devmem); if ((buf = mem_chunk(fp, 0x20, opt.devmem)) == NULL) { ret = 1; goto exit_free; } if (memcmp(buf, "_SM3_", 5) == 0) { if (smbios3_decode(buf, opt.devmem, 0)) found++; } else if (memcmp(buf, "_SM_", 4) == 0) { if (smbios_decode(buf, opt.devmem, 0)) found++; } goto done; memory_scan: if (!(opt.flags & FLAG_QUIET)) printf("Scanning %s for entry point.\n", opt.devmem); /* Fallback to memory scan (x86, x86_64) */ if ((buf = mem_chunk(0xF0000, 0x10000, opt.devmem)) == NULL) { ret = 1; goto exit_free; } /* Look for a 64-bit entry point first */ for (fp = 0; fp <= 0xFFE0; fp += 16) { if (memcmp(buf + fp, "_SM3_", 5) == 0) { if (smbios3_decode(buf + fp, opt.devmem, 0)) { found++; goto done; } } } /* If none found, look for a 32-bit entry point */ for (fp = 0; fp <= 0xFFF0; fp += 16) { if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { if (smbios_decode(buf + fp, opt.devmem, 0)) { found++; goto done; } } else if (memcmp(buf + fp, "_DMI_", 5) == 0) { if (legacy_decode(buf + fp, opt.devmem, 0)) { found++; goto done; } } } done: if (!found && !(opt.flags & FLAG_QUIET)) printf("# No SMBIOS nor DMI entry point found, sorry.\n"); free(buf); exit_free: free(opt.type); opt.type = NULL; return ret; } CPU-X-3.2.4/src/dmidecode/dmidecode.h000066400000000000000000000020301341671471500171520ustar00rootroot00000000000000/* * This file is part of the dmidecode project. * * Copyright (C) 2005-2008 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "types.h" struct dmi_header { u8 type; u8 length; u16 handle; u8 *data; }; int is_printable(const u8 *data, int len); const char *dmi_string(const struct dmi_header *dm, u8 s); CPU-X-3.2.4/src/dmidecode/dmioem.c000066400000000000000000000204361341671471500165140ustar00rootroot00000000000000/* * Decoding of OEM-specific entries * This file is part of the dmidecode project. * * Copyright (C) 2007-2008 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "types.h" #include "dmidecode.h" #include "dmioem.h" /* * Globals for vendor-specific decodes */ enum DMI_VENDORS { VENDOR_UNKNOWN, VENDOR_ACER, VENDOR_HP, VENDOR_HPE, }; static enum DMI_VENDORS dmi_vendor = VENDOR_UNKNOWN; /* * Remember the system vendor for later use. We only actually store the * value if we know how to decode at least one specific entry type for * that vendor. */ void dmi_set_vendor(const char *s) { int len; /* * Often DMI strings have trailing spaces. Ignore these * when checking for known vendor names. */ len = strlen(s); while (len && s[len - 1] == ' ') len--; if (strncmp(s, "Acer", len) == 0) dmi_vendor = VENDOR_ACER; else if (strncmp(s, "HP", len) == 0 || strncmp(s, "Hewlett-Packard", len) == 0) dmi_vendor = VENDOR_HP; else if (strncmp(s, "HPE", len) == 0 || strncmp(s, "Hewlett Packard Enterprise", len) == 0) dmi_vendor = VENDOR_HPE; } /* * Acer-specific data structures are decoded here. */ static int dmi_decode_acer(const struct dmi_header *h) { u8 *data = h->data; u16 cap; switch (h->type) { case 170: /* * Vendor Specific: Acer Hotkey Function * * Source: acer-wmi kernel driver * * Probably applies to some laptop models of other * brands, including Fujitsu-Siemens, Medion, Lenovo, * and eMachines. */ printf("Acer Hotkey Function\n"); if (h->length < 0x0F) break; cap = WORD(data + 0x04); printf("\tFunction bitmap for Communication Button: 0x%04hx\n", cap); printf("\t\tWiFi: %s\n", cap & 0x0001 ? "Yes" : "No"); printf("\t\t3G: %s\n", cap & 0x0040 ? "Yes" : "No"); printf("\t\tWiMAX: %s\n", cap & 0x0080 ? "Yes" : "No"); printf("\t\tBluetooth: %s\n", cap & 0x0800 ? "Yes" : "No"); printf("\tFunction bitmap for Application Button: 0x%04hx\n", WORD(data + 0x06)); printf("\tFunction bitmap for Media Button: 0x%04hx\n", WORD(data + 0x08)); printf("\tFunction bitmap for Display Button: 0x%04hx\n", WORD(data + 0x0A)); printf("\tFunction bitmap for Others Button: 0x%04hx\n", WORD(data + 0x0C)); printf("\tCommunication Function Key Number: %d\n", data[0x0E]); break; default: return 0; } return 1; } /* * HPE-specific data structures are decoded here. * * Code contributed by John Cagle and Tyler Bell. */ static void dmi_print_hp_net_iface_rec(u8 id, u8 bus, u8 dev, const u8 *mac) { /* Some systems do not provide an id. nic_ctr provides an artificial * id, and assumes the records will be provided "in order". Also, * using 0xFF marker is not future proof. 256 NICs is a lot, but * 640K ought to be enough for anybody(said no one, ever). * */ static u8 nic_ctr; if (id == 0xFF) id = ++nic_ctr; if (dev == 0x00 && bus == 0x00) printf("\tNIC %d: Disabled\n", id); else if (dev == 0xFF && bus == 0xFF) printf("\tNIC %d: Not Installed\n", id); else { printf("\tNIC %d: PCI device %02x:%02x.%x, " "MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", id, bus, dev >> 3, dev & 7, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } } static int dmi_decode_hp(const struct dmi_header *h) { u8 *data = h->data; int nic, ptr; u32 feat; const char *company = (dmi_vendor == VENDOR_HP) ? "HP" : "HPE"; switch (h->type) { case 204: /* * Vendor Specific: HPE ProLiant System/Rack Locator */ printf("%s ProLiant System/Rack Locator\n", company); if (h->length < 0x0B) break; printf("\tRack Name: %s\n", dmi_string(h, data[0x04])); printf("\tEnclosure Name: %s\n", dmi_string(h, data[0x05])); printf("\tEnclosure Model: %s\n", dmi_string(h, data[0x06])); printf("\tEnclosure Serial: %s\n", dmi_string(h, data[0x0A])); printf("\tEnclosure Bays: %d\n", data[0x08]); printf("\tServer Bay: %s\n", dmi_string(h, data[0x07])); printf("\tBays Filled: %d\n", data[0x09]); break; case 209: case 221: /* * Vendor Specific: HPE ProLiant NIC MAC Information * * This prints the BIOS NIC number, * PCI bus/device/function, and MAC address * * Type 209: * Offset | Name | Width | Description * ------------------------------------- * 0x00 | Type | BYTE | 0xD1, MAC Info * 0x01 | Length | BYTE | Length of structure * 0x02 | Handle | WORD | Unique handle * 0x04 | Dev No | BYTE | PCI Device/Function No * 0x05 | Bus No | BYTE | PCI Bus * 0x06 | MAC | 6B | MAC addr * 0x0C | NIC #2 | 8B | Repeat 0x04-0x0B * * Type 221: is deprecated in the latest docs */ printf("%s %s\n", company, h->type == 221 ? "BIOS iSCSI NIC PCI and MAC Information" : "BIOS PXE NIC PCI and MAC Information"); nic = 1; ptr = 4; while (h->length >= ptr + 8) { dmi_print_hp_net_iface_rec(nic, data[ptr + 0x01], data[ptr], &data[ptr + 0x02]); nic++; ptr += 8; } break; case 233: /* * Vendor Specific: HPE ProLiant NIC MAC Information * * This prints the BIOS NIC number, * PCI bus/device/function, and MAC address * * Offset | Name | Width | Description * ------------------------------------- * 0x00 | Type | BYTE | 0xE9, NIC structure * 0x01 | Length | BYTE | Length of structure * 0x02 | Handle | WORD | Unique handle * 0x04 | Grp No | WORD | 0 for single segment * 0x06 | Bus No | BYTE | PCI Bus * 0x07 | Dev No | BYTE | PCI Device/Function No * 0x08 | MAC | 32B | MAC addr padded w/ 0s * 0x28 | Port No| BYTE | Each NIC maps to a Port */ printf("%s BIOS PXE NIC PCI and MAC Information\n", company); if (h->length < 0x0E) break; /* If the record isn't long enough, we don't have an ID * use 0xFF to use the internal counter. * */ nic = h->length > 0x28 ? data[0x28] : 0xFF; dmi_print_hp_net_iface_rec(nic, data[0x06], data[0x07], &data[0x08]); break; case 212: /* * Vendor Specific: HPE 64-bit CRU Information * * Source: hpwdt kernel driver */ printf("%s 64-bit CRU Information\n", company); if (h->length < 0x18) break; printf("\tSignature: 0x%08x", DWORD(data + 0x04)); if (is_printable(data + 0x04, 4)) printf(" (%c%c%c%c)", data[0x04], data[0x05], data[0x06], data[0x07]); printf("\n"); if (DWORD(data + 0x04) == 0x55524324) { u64 paddr = QWORD(data + 0x08); paddr.l += DWORD(data + 0x14); if (paddr.l < DWORD(data + 0x14)) paddr.h++; printf("\tPhysical Address: 0x%08x%08x\n", paddr.h, paddr.l); printf("\tLength: 0x%08x\n", DWORD(data + 0x10)); } break; case 219: /* * Vendor Specific: HPE ProLiant Information * * Source: hpwdt kernel driver */ printf("%s ProLiant Information\n", company); if (h->length < 0x08) break; printf("\tPower Features: 0x%08x\n", DWORD(data + 0x04)); if (h->length < 0x0C) break; printf("\tOmega Features: 0x%08x\n", DWORD(data + 0x08)); if (h->length < 0x14) break; feat = DWORD(data + 0x10); printf("\tMisc. Features: 0x%08x\n", feat); printf("\t\tiCRU: %s\n", feat & 0x0001 ? "Yes" : "No"); printf("\t\tUEFI: %s\n", feat & 0x1400 ? "Yes" : "No"); break; default: return 0; } return 1; } /* * Dispatch vendor-specific entries decoding * Return 1 if decoding was successful, 0 otherwise */ int dmi_decode_oem(const struct dmi_header *h) { switch (dmi_vendor) { case VENDOR_HP: case VENDOR_HPE: return dmi_decode_hp(h); case VENDOR_ACER: return dmi_decode_acer(h); default: return 0; } } CPU-X-3.2.4/src/dmidecode/dmioem.h000066400000000000000000000017441341671471500165220ustar00rootroot00000000000000/* * Decoding of OEM-specific entries * This file is part of the dmidecode project. * * Copyright (C) 2007-2008 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ struct dmi_header; void dmi_set_vendor(const char *s); int dmi_decode_oem(const struct dmi_header *h); CPU-X-3.2.4/src/dmidecode/dmiopt.c000066400000000000000000000216331341671471500165360ustar00rootroot00000000000000/* * Command line handling of dmidecode * This file is part of the dmidecode project. * * Copyright (C) 2005-2008 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "config.h" #include "types.h" #include "util.h" #include "dmidecode.h" #include "dmiopt.h" /* Options are global */ struct opt opt; /* * Handling of option --type */ struct type_keyword { const char *keyword; const u8 *type; }; static const u8 opt_type_bios[] = { 0, 13, 255 }; static const u8 opt_type_system[] = { 1, 12, 15, 23, 32, 255 }; static const u8 opt_type_baseboard[] = { 2, 10, 41, 255 }; static const u8 opt_type_chassis[] = { 3, 255 }; static const u8 opt_type_processor[] = { 4, 255 }; static const u8 opt_type_memory[] = { 5, 6, 16, 17, 255 }; static const u8 opt_type_cache[] = { 7, 255 }; static const u8 opt_type_connector[] = { 8, 255 }; static const u8 opt_type_slot[] = { 9, 255 }; static const struct type_keyword opt_type_keyword[] = { { "bios", opt_type_bios }, { "system", opt_type_system }, { "baseboard", opt_type_baseboard }, { "chassis", opt_type_chassis }, { "processor", opt_type_processor }, { "memory", opt_type_memory }, { "cache", opt_type_cache }, { "connector", opt_type_connector }, { "slot", opt_type_slot }, }; static void print_opt_type_list(void) { unsigned int i; fprintf(stderr, "Valid type keywords are:\n"); for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++) { fprintf(stderr, " %s\n", opt_type_keyword[i].keyword); } } static u8 *parse_opt_type(u8 *p, const char *arg) { unsigned int i; /* Allocate memory on first call only */ if (p == NULL) { p = (u8 *)calloc(256, sizeof(u8)); if (p == NULL) { perror("calloc"); return NULL; } } /* First try as a keyword */ for (i = 0; i < ARRAY_SIZE(opt_type_keyword); i++) { if (!strcasecmp(arg, opt_type_keyword[i].keyword)) { int j = 0; while (opt_type_keyword[i].type[j] != 255) p[opt_type_keyword[i].type[j++]] = 1; goto found; } } /* Else try as a number */ while (*arg != '\0') { unsigned long val; char *next; val = strtoul(arg, &next, 0); if (next == arg) { fprintf(stderr, "Invalid type keyword: %s\n", arg); print_opt_type_list(); goto exit_free; } if (val > 0xff) { fprintf(stderr, "Invalid type number: %lu\n", val); goto exit_free; } p[val] = 1; arg = next; while (*arg == ',' || *arg == ' ') arg++; } found: return p; exit_free: free(p); return NULL; } /* * Handling of option --string */ /* This lookup table could admittedly be reworked for improved performance. Due to the low count of items in there at the moment, it did not seem worth the additional code complexity though. */ static const struct string_keyword opt_string_keyword[] = { { "bios-vendor", 0, 0x04 }, { "bios-version", 0, 0x05 }, { "bios-release-date", 0, 0x08 }, { "system-manufacturer", 1, 0x04 }, { "system-product-name", 1, 0x05 }, { "system-version", 1, 0x06 }, { "system-serial-number", 1, 0x07 }, { "system-uuid", 1, 0x08 }, /* dmi_system_uuid() */ { "system-family", 1, 0x1a }, { "baseboard-manufacturer", 2, 0x04 }, { "baseboard-product-name", 2, 0x05 }, { "baseboard-version", 2, 0x06 }, { "baseboard-serial-number", 2, 0x07 }, { "baseboard-asset-tag", 2, 0x08 }, { "chassis-manufacturer", 3, 0x04 }, { "chassis-type", 3, 0x05 }, /* dmi_chassis_type() */ { "chassis-version", 3, 0x06 }, { "chassis-serial-number", 3, 0x07 }, { "chassis-asset-tag", 3, 0x08 }, { "processor-family", 4, 0x06 }, /* dmi_processor_family() */ { "processor-manufacturer", 4, 0x07 }, { "processor-version", 4, 0x10 }, { "processor-frequency", 4, 0x16 }, /* dmi_processor_frequency() */ }; /* This is a template, 3rd field is set at runtime. */ static struct string_keyword opt_oem_string_keyword = { NULL, 11, 0x00 }; static void print_opt_string_list(void) { unsigned int i; fprintf(stderr, "Valid string keywords are:\n"); for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) { fprintf(stderr, " %s\n", opt_string_keyword[i].keyword); } } static int parse_opt_string(const char *arg) { unsigned int i; if (opt.string) { fprintf(stderr, "Only one string can be specified\n"); return -1; } for (i = 0; i < ARRAY_SIZE(opt_string_keyword); i++) { if (!strcasecmp(arg, opt_string_keyword[i].keyword)) { opt.string = &opt_string_keyword[i]; return 0; } } fprintf(stderr, "Invalid string keyword: %s\n", arg); print_opt_string_list(); return -1; } static int parse_opt_oem_string(const char *arg) { unsigned long val; char *next; if (opt.string) { fprintf(stderr, "Only one string can be specified\n"); return -1; } /* Return the number of OEM strings */ if (strcmp(arg, "count") == 0) goto done; val = strtoul(arg, &next, 10); if (next == arg || val == 0x00 || val > 0xff) { fprintf(stderr, "Invalid OEM string number: %s\n", arg); return -1; } opt_oem_string_keyword.offset = val; done: opt.string = &opt_oem_string_keyword; return 0; } /* * Command line options handling */ /* Return -1 on error, 0 on success */ int parse_command_line(int argc, char * const argv[]) { int option; const char *optstring = "d:hqs:t:uV"; struct option longopts[] = { { "dev-mem", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "quiet", no_argument, NULL, 'q' }, { "string", required_argument, NULL, 's' }, { "type", required_argument, NULL, 't' }, { "dump", no_argument, NULL, 'u' }, { "dump-bin", required_argument, NULL, 'B' }, { "from-dump", required_argument, NULL, 'F' }, { "oem-string", required_argument, NULL, 'O' }, { "no-sysfs", no_argument, NULL, 'S' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; while ((option = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) switch (option) { case 'B': opt.flags |= FLAG_DUMP_BIN; opt.dumpfile = optarg; break; case 'F': opt.flags |= FLAG_FROM_DUMP; opt.dumpfile = optarg; break; case 'd': opt.devmem = optarg; break; case 'h': opt.flags |= FLAG_HELP; break; case 'q': opt.flags |= FLAG_QUIET; break; case 's': if (parse_opt_string(optarg) < 0) return -1; opt.flags |= FLAG_QUIET; break; case 'O': if (parse_opt_oem_string(optarg) < 0) return -1; opt.flags |= FLAG_QUIET; break; case 't': opt.type = parse_opt_type(opt.type, optarg); if (opt.type == NULL) return -1; break; case 'u': opt.flags |= FLAG_DUMP; break; case 'S': opt.flags |= FLAG_NO_SYSFS; break; case 'V': opt.flags |= FLAG_VERSION; break; case '?': switch (optopt) { case 's': fprintf(stderr, "String keyword expected\n"); print_opt_string_list(); break; case 't': fprintf(stderr, "Type number or keyword expected\n"); print_opt_type_list(); break; } return -1; } /* Check for mutually exclusive output format options */ if ((opt.string != NULL) + (opt.type != NULL) + !!(opt.flags & FLAG_DUMP_BIN) > 1) { fprintf(stderr, "Options --string, --type and --dump-bin are mutually exclusive\n"); return -1; } if ((opt.flags & FLAG_FROM_DUMP) && (opt.flags & FLAG_DUMP_BIN)) { fprintf(stderr, "Options --from-dump and --dump-bin are mutually exclusive\n"); return -1; } return 0; } void print_help(void) { static const char *help = "Usage: dmidecode [OPTIONS]\n" "Options are:\n" " -d, --dev-mem FILE Read memory from device FILE (default: " DEFAULT_MEM_DEV ")\n" " -h, --help Display this help text and exit\n" " -q, --quiet Less verbose output\n" " -s, --string KEYWORD Only display the value of the given DMI string\n" " -t, --type TYPE Only display the entries of given type\n" " -u, --dump Do not decode the entries\n" " --dump-bin FILE Dump the DMI data to a binary file\n" " --from-dump FILE Read the DMI data from a binary file\n" " --no-sysfs Do not attempt to read DMI data from sysfs files\n" " --oem-string N Only display the value of the given OEM string\n" " -V, --version Display the version and exit\n"; printf("%s", help); } CPU-X-3.2.4/src/dmidecode/dmiopt.h000066400000000000000000000030371341671471500165410ustar00rootroot00000000000000/* * Command line handling of dmidecode * This file is part of the dmidecode project. * * Copyright (C) 2005-2008 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #if !HAS_LIBPCI # include "types.h" #endif struct string_keyword { const char *keyword; u8 type; u8 offset; }; struct opt { const char *devmem; unsigned int flags; u8 *type; const struct string_keyword *string; char *dumpfile; }; extern struct opt opt; #define FLAG_VERSION (1 << 0) #define FLAG_HELP (1 << 1) #define FLAG_DUMP (1 << 2) #define FLAG_QUIET (1 << 3) #define FLAG_DUMP_BIN (1 << 4) #define FLAG_FROM_DUMP (1 << 5) #define FLAG_NO_SYSFS (1 << 6) #define FLAG_CPU_X (1 << 10) int parse_command_line(int argc, char * const argv[]); void print_help(void); CPU-X-3.2.4/src/dmidecode/libdmi.h000066400000000000000000000021771341671471500165110ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE libdmi.h */ #ifndef _LIBDMI_H_ #define _LIBDMI_H_ #include #include "../cpu-x.h" enum EnDmidecode { DMI_CPU, DMI_MB, DMI_RAM, LASTDMI }; extern double *ext_clk; extern uint8_t *bank; extern char **dmidata[LASTDMI][16]; int dmidecode(void); #endif CPU-X-3.2.4/src/dmidecode/types.h000066400000000000000000000027611341671471500164140ustar00rootroot00000000000000#ifndef TYPES_H #define TYPES_H #include "config.h" typedef unsigned char u8; typedef unsigned short u16; typedef signed short i16; typedef unsigned int u32; /* * You may use the following defines to adjust the type definitions * depending on the architecture: * - Define BIGENDIAN on big-endian systems. Untested, as all target * systems to date are little-endian. * - Define ALIGNMENT_WORKAROUND if your system doesn't support * non-aligned memory access. In this case, we use a slower, but safer, * memory access method. This should be done automatically in config.h * for architectures which need it. */ #ifdef BIGENDIAN typedef struct { u32 h; u32 l; } u64; #else typedef struct { u32 l; u32 h; } u64; #endif #ifdef ALIGNMENT_WORKAROUND static inline u64 U64(u32 low, u32 high) { u64 self; self.l = low; self.h = high; return self; } #endif #ifdef ALIGNMENT_WORKAROUND # ifdef BIGENDIAN # define WORD(x) (u16)((x)[1] + ((x)[0] << 8)) # define DWORD(x) (u32)((x)[3] + ((x)[2] << 8) + ((x)[1] << 16) + ((x)[0] << 24)) # define QWORD(x) (U64(DWORD(x + 4), DWORD(x))) # else /* BIGENDIAN */ # define WORD(x) (u16)((x)[0] + ((x)[1] << 8)) # define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24)) # define QWORD(x) (U64(DWORD(x), DWORD(x + 4))) # endif /* BIGENDIAN */ #else /* ALIGNMENT_WORKAROUND */ #define WORD(x) (u16)(*(const u16 *)(x)) #define DWORD(x) (u32)(*(const u32 *)(x)) #define QWORD(x) (*(const u64 *)(x)) #endif /* ALIGNMENT_WORKAROUND */ #endif CPU-X-3.2.4/src/dmidecode/util.c000066400000000000000000000133031341671471500162120ustar00rootroot00000000000000/* * Common "util" functions * This file is part of the dmidecode project. * * Copyright (C) 2002-2017 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For the avoidance of doubt the "preferred form" of this code is one which * is in an open unpatent encumbered format. Where cryptographic key signing * forms part of the process of creating an executable the information * including keys needed to generate an equivalently functional executable * are deemed to be part of the source code. */ #include #include #include "config.h" #ifdef USE_MMAP #include #ifndef MAP_FAILED #define MAP_FAILED ((void *) -1) #endif /* !MAP_FAILED */ #endif /* USE MMAP */ #include #include #include #include #include #include #include "types.h" #include "util.h" static int myread(int fd, u8 *buf, size_t count, const char *prefix) { ssize_t r = 1; size_t r2 = 0; while (r2 != count && r != 0) { r = read(fd, buf + r2, count - r2); if (r == -1) { if (errno != EINTR) { close(fd); perror(prefix); return -1; } } else r2 += r; } if (r2 != count) { close(fd); fprintf(stderr, "%s: Unexpected end of file\n", prefix); return -1; } return 0; } int checksum(const u8 *buf, size_t len) { u8 sum = 0; size_t a; for (a = 0; a < len; a++) sum += buf[a]; return (sum == 0); } /* * Reads all of file from given offset, up to max_len bytes. * A buffer of max_len bytes is allocated by this function, and * needs to be freed by the caller. * This provides a similar usage model to mem_chunk() * * Returns pointer to buffer of max_len bytes, or NULL on error, and * sets max_len to the length actually read. * */ void *read_file(off_t base, size_t *max_len, const char *filename) { int fd; size_t r2 = 0; ssize_t r; u8 *p; /* * Don't print error message on missing file, as we will try to read * files that may or may not be present. */ if ((fd = open(filename, O_RDONLY)) == -1) { if (errno != ENOENT) perror(filename); return NULL; } if (lseek(fd, base, SEEK_SET) == -1) { fprintf(stderr, "%s: ", filename); perror("lseek"); p = NULL; goto out; } if ((p = malloc(*max_len)) == NULL) { perror("malloc"); goto out; } do { r = read(fd, p + r2, *max_len - r2); if (r == -1) { if (errno != EINTR) { perror(filename); free(p); p = NULL; goto out; } } else r2 += r; } while (r != 0); *max_len = r2; out: close(fd); return p; } /* * Copy a physical memory chunk into a memory buffer. * This function allocates memory. */ void *mem_chunk(off_t base, size_t len, const char *devmem) { void *p; int fd; #ifdef USE_MMAP struct stat statbuf; off_t mmoffset; void *mmp; #endif if ((fd = open(devmem, O_RDONLY)) == -1) { perror(devmem); return NULL; } if ((p = malloc(len)) == NULL) { perror("malloc"); goto out; } #ifdef USE_MMAP if (fstat(fd, &statbuf) == -1) { fprintf(stderr, "%s: ", devmem); perror("stat"); goto err_free; } /* * mmap() will fail with SIGBUS if trying to map beyond the end of * the file. */ if (S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size) { fprintf(stderr, "mmap: Can't map beyond end of file %s\n", devmem); goto err_free; } #ifdef _SC_PAGESIZE mmoffset = base % sysconf(_SC_PAGESIZE); #else mmoffset = base % getpagesize(); #endif /* _SC_PAGESIZE */ /* * Please note that we don't use mmap() for performance reasons here, * but to workaround problems many people encountered when trying * to read from /dev/mem using regular read() calls. */ mmp = mmap(NULL, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); if (mmp == MAP_FAILED) goto try_read; memcpy(p, (u8 *)mmp + mmoffset, len); if (munmap(mmp, mmoffset + len) == -1) { fprintf(stderr, "%s: ", devmem); perror("munmap"); } goto out; try_read: #endif /* USE_MMAP */ if (lseek(fd, base, SEEK_SET) == -1) { fprintf(stderr, "%s: ", devmem); perror("lseek"); goto err_free; } if (myread(fd, p, len, devmem) == 0) goto out; err_free: free(p); p = NULL; out: if (close(fd) == -1) perror(devmem); return p; } int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) { FILE *f; f = fopen(dumpfile, add ? "r+b" : "wb"); if (!f) { fprintf(stderr, "%s: ", dumpfile); perror("fopen"); return -1; } if (fseek(f, base, SEEK_SET) != 0) { fprintf(stderr, "%s: ", dumpfile); perror("fseek"); goto err_close; } if (fwrite(data, len, 1, f) != 1) { fprintf(stderr, "%s: ", dumpfile); perror("fwrite"); goto err_close; } if (fclose(f)) { fprintf(stderr, "%s: ", dumpfile); perror("fclose"); return -1; } return 0; err_close: fclose(f); return -1; } /* Returns end - start + 1, assuming start < end */ u64 u64_range(u64 start, u64 end) { u64 res; res.h = end.h - start.h; res.l = end.l - start.l; if (end.l < start.l) res.h--; if (++res.l == 0) res.h++; return res; } CPU-X-3.2.4/src/dmidecode/util.h000066400000000000000000000023311341671471500162160ustar00rootroot00000000000000/* * This file is part of the dmidecode project. * * Copyright (C) 2003-2017 Jean Delvare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "types.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) int checksum(const u8 *buf, size_t len); void *read_file(off_t base, size_t *len, const char *filename); void *mem_chunk(off_t base, size_t len, const char *devmem); int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add); u64 u64_range(u64 start, u64 end); CPU-X-3.2.4/src/gui_gtk.c000066400000000000000000000644721341671471500147660ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE gui_gtk.c */ #include #include #include #include #include "cpu-x.h" #include "gui_gtk.h" #include "gui_gtk_id.h" #if PORTABLE_BINARY # include "gtk_resources.h" #endif /************************* Public function *************************/ /* Start CPU-X in GTK mode */ void start_gui_gtk(int *argc, char **argv[], Labels *data) { int i; GtkLabels glab; GThrd refr = { &glab, data }; GtkBuilder *builder = gtk_builder_new(); gchar *prgname = g_ascii_strdown(PRGNAME, -1); const gchar *ui_files[] = { "cpu-x-gtk-3.12.ui", NULL }; MSG_VERBOSE(_("Starting GTK GUI...")); gtk_init(argc, argv); g_set_prgname(prgname); g_free(prgname); /* Build UI from Glade file */ #if PORTABLE_BINARY g_resources_register(cpu_x_get_resource()); for(i = 0; (ui_files[i] != NULL) && (!gtk_builder_add_from_resource(builder, GRESOURCE_UI(ui_files[i]), NULL)); i++); #else for(i = 0; (ui_files[i] != NULL) && (!gtk_builder_add_from_file(builder, data_path(ui_files[i]), NULL)); i++); #endif /* PORTABLE_BINARY */ if(ui_files[i] == NULL) { MSG_ERROR(_("failed to import UI in GtkBuilder")); exit(EXIT_FAILURE); } get_widgets(builder, &glab); g_object_unref(G_OBJECT(builder)); set_colors (&glab); set_logos (&glab, data); set_labels (&glab, data); set_signals(&glab, data, &refr); labels_free(data); if(getuid()) warning_window(glab.mainwindow); #ifdef __x86_64__ if(PORTABLE_BINARY && (new_version[0] != NULL) && !opts->update) new_version_window(glab.mainwindow); #endif /* __x86_64__ */ g_timeout_add_seconds(opts->refr_time, (gpointer)grefresh, &refr); gtk_main(); } /************************* Private functions *************************/ /* Print a window which allows to restart CPU-X as root */ static void warning_window(GtkWidget *mainwindow) { char *const cmd[] = { "cpu-x_polkit", NULL }; GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, _("Root privileges are required to work properly")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), _("Some informations will not be retrievable")); gtk_dialog_add_button(GTK_DIALOG(dialog), _("Ignore"), GTK_RESPONSE_REJECT); #if !(PORTABLE_BINARY) if(!getenv("APPIMAGE") && command_exists("pkexec") && command_exists("cpu-x_polkit")) gtk_dialog_add_button(GTK_DIALOG(dialog), _("Run as root"), GTK_RESPONSE_ACCEPT); #endif /* !(PORTABLE_BINARY) */ if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) execvp(cmd[0], cmd); gtk_widget_destroy(dialog); } /* In portable version, inform when a new version is available and ask for update */ static void new_version_window(GtkWidget *mainwindow) { GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, _("A new version of %s is available!"), PRGNAME); #if 0 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), _("Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version."), PRGNAME, new_version[0], binary_name); gtk_dialog_add_buttons(GTK_DIALOG(dialog), _("Not now"), GTK_RESPONSE_REJECT, _("Update"), GTK_RESPONSE_ACCEPT, NULL); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) opts->update = true; #else gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), _("Version %s is available. Unfortunately, this portable format is now deprecated in favor of AppImage.\n" "You can download %s AppImage on the official download page.\n"), new_version[0], PRGNAME); GtkWidget *link = gtk_link_button_new_with_label(DOWNLOAD, _("Download page")); gtk_widget_show(link); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), GTK_WIDGET(link), GTK_RESPONSE_OK); gtk_dialog_add_button(GTK_DIALOG(dialog), _("Ok"), GTK_RESPONSE_CLOSE); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(link); #endif gtk_widget_destroy(dialog); } /* Refresh dynamic values */ static gboolean grefresh(GThrd *refr) { int i; Labels *(data) = refr->data; GtkLabels *(glab) = refr->glab; opts->selected_page = gtk_notebook_get_current_page(GTK_NOTEBOOK(glab->notebook)); do_refresh(data); switch(opts->selected_page) { case NO_CPU: gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][VOLTAGE]), data->tab_cpu[VALUE][VOLTAGE]); gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][TEMPERATURE]), data->tab_cpu[VALUE][TEMPERATURE]); gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][MULTIPLIER]), data->tab_cpu[VALUE][MULTIPLIER]); gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][CORESPEED]), data->tab_cpu[VALUE][CORESPEED]); gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][USAGE]), data->tab_cpu[VALUE][USAGE]); break; case NO_CACHES: for(i = L1SPEED; i < data->cache_count * CACHEFIELDS; i += CACHEFIELDS) gtk_label_set_text(GTK_LABEL(glab->gtktab_caches[VALUE][i]), data->tab_caches[VALUE][i]); break; case NO_SYSTEM: gtk_label_set_text(GTK_LABEL(glab->gtktab_system[VALUE][UPTIME]), data->tab_system[VALUE][UPTIME]); for(i = USED; i < LASTSYSTEM; i++) gtk_label_set_text(GTK_LABEL(glab->gtktab_system[VALUE][i]), data->tab_system[VALUE][i]); break; case NO_GRAPHICS: for(i = 0; i < data->gpu_count; i += GPUFIELDS) { gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1TEMPERATURE + i]), data->tab_graphics[VALUE][GPU1TEMPERATURE + i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1USAGE + i]), data->tab_graphics[VALUE][GPU1USAGE + i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1CORECLOCK + i]), data->tab_graphics[VALUE][GPU1CORECLOCK + i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][GPU1MEMCLOCK + i]), data->tab_graphics[VALUE][GPU1MEMCLOCK + i]); } break; case NO_BENCH: for(i = PRIMESLOWSCORE; i <= PRIMEFASTSCORE; i += BENCHFIELDS) gtk_progress_bar_set_text(GTK_PROGRESS_BAR(glab->gtktab_bench[VALUE][i]), data->tab_bench[VALUE][i]); change_benchsensitive(glab, data); break; default: break; } return G_SOURCE_CONTINUE; } /* Event in CPU tab when Core number is changed */ static void change_activecore(GtkComboBox *box, Labels *data) { const gint core = gtk_combo_box_get_active(GTK_COMBO_BOX(box)); if(0 <= core && core < data->cpu_count) opts->selected_core = core; } /* Event in Caches tab when Test number is changed */ static void change_activetest(GtkComboBox *box, Labels *data) { const gint test = gtk_combo_box_get_active(GTK_COMBO_BOX(box)); if(0 <= test && test < data->w_data->test_count) opts->bw_test = test; } /* Events in Bench tab when a benchmark start/stop */ static void start_benchmark_bg(GtkSwitch *gswitch, GdkEvent *event, GThrd *refr) { Labels *data = refr->data; if(!data->b_data->run) { change_benchsensitive(refr->glab, data); data->b_data->fast_mode = !strcmp(gtk_widget_get_name(GTK_WIDGET(gswitch)), objectbench[PRIMEFASTRUN]); start_benchmarks(data); } else data->b_data->run = false; } /* Events in Bench tab when Duration/Threads SpinButtons are changed */ static void change_benchparam(GtkSpinButton *spinbutton, Labels *data) { const gint val = gtk_spin_button_get_value_as_int(spinbutton); if(!g_strcmp0(gtk_widget_get_name (GTK_WIDGET(spinbutton)), objectbench[PARAMDURATION])) data->b_data->duration = val; else if(!g_strcmp0(gtk_widget_get_name(GTK_WIDGET(spinbutton)), objectbench[PARAMTHREADS])) data->b_data->threads = val; gtk_spin_button_update(spinbutton); } /* Set/Unset widgets sensitive when a benchmark start/stop */ static void change_benchsensitive(GtkLabels *glab, Labels *data) { static gboolean skip = false; const enum EnTabBench indP = data->b_data->fast_mode ? PRIMEFASTSCORE : PRIMESLOWSCORE; const enum EnTabBench indS = data->b_data->fast_mode ? PRIMESLOWRUN : PRIMEFASTRUN; const enum EnTabBench indA = data->b_data->fast_mode ? PRIMEFASTRUN : PRIMESLOWRUN; if(data->b_data->run) { skip = false; #if GTK_CHECK_VERSION(3, 15, 0) || PORTABLE_BINARY if(gtk_check_version(3, 15, 0) == NULL) gtk_switch_set_state(GTK_SWITCH(glab->gtktab_bench[VALUE][indA]), true); #endif /* GTK_CHECK_VERSION(3, 15, 0) || PORTABLE_BINARY */ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(glab->gtktab_bench[VALUE][indP]), (double) data->b_data->elapsed / (data->b_data->duration * 60)); gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][indS], false); gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][PARAMTHREADS], false); } else if(!data->b_data->run && !skip) { skip = true; #if GTK_CHECK_VERSION(3, 15, 0) || PORTABLE_BINARY if(gtk_check_version(3, 15, 0) == NULL) gtk_switch_set_state(GTK_SWITCH(glab->gtktab_bench[VALUE][indA]), false); #endif /* GTK_CHECK_VERSION(3, 15, 0) || PORTABLE_BINARY */ gtk_switch_set_active(GTK_SWITCH(glab->gtktab_bench[VALUE][indA]), false); gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][indS], true); gtk_widget_set_sensitive(glab->gtktab_bench[VALUE][PARAMTHREADS], true); } } /* Get label ID ('type' must be "lab" or "val") */ static gchar *get_id(const gchar *objectstr, gchar *type) { static gchar *buff = NULL; gchar **split; g_free(buff); split = g_strsplit(objectstr, "_", 2); buff = g_strconcat(split[0], "_", type, split[1], NULL); g_strfreev(split); return buff; } /* Search file location in standard paths */ static gchar *data_path(const gchar *file) { int i; gboolean file_exists = false; static gchar *path = NULL; const gchar *prgname = g_get_prgname(); const gchar *const *paths = g_get_system_data_dirs(); for(i = 0; (!file_exists) && (paths[i] != NULL); i++) { g_free(path); path = g_build_filename(paths[i], prgname, file, NULL); file_exists = g_file_test(path, G_FILE_TEST_EXISTS); } return path; } /* Retrieve widgets from GtkBuilder */ static void get_widgets(GtkBuilder *builder, GtkLabels *glab) { int i; glab->mainwindow = GTK_WIDGET(gtk_builder_get_object(builder, "mainwindow")); glab->closebutton = GTK_WIDGET(gtk_builder_get_object(builder, "closebutton")); glab->labprgver = GTK_WIDGET(gtk_builder_get_object(builder, "labprgver")); glab->footer = GTK_WIDGET(gtk_builder_get_object(builder, "footer_box")); glab->notebook = GTK_WIDGET(gtk_builder_get_object(builder, "header_notebook")); glab->logocpu = GTK_WIDGET(gtk_builder_get_object(builder, "proc_logocpu")); glab->activecore = GTK_WIDGET(gtk_builder_get_object(builder, "trg_activecore")); glab->activetest = GTK_WIDGET(gtk_builder_get_object(builder, "test_activetest")); glab->logoprg = GTK_WIDGET(gtk_builder_get_object(builder, "about_logoprg")); glab->butcol = GTK_WIDGET(gtk_builder_get_object(builder, "colorbutton")); gtk_widget_set_name(glab->footer, "footer_box"); gtk_notebook_set_current_page(GTK_NOTEBOOK(glab->notebook), opts->selected_page); /* Various labels to translate */ for(i = TABCPU; i < LASTOBJ; i++) glab->gtktrad[i] = GTK_WIDGET(gtk_builder_get_object(builder, trad[i])); /* Tab CPU */ for(i = VENDOR; i < LASTCPU; i++) { glab->gtktab_cpu[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcpu[i], "lab"))); glab->gtktab_cpu[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcpu[i], "val"))); gtk_widget_set_name(glab->gtktab_cpu[VALUE][i], "value"); } /* Tab Caches */ for(i = L1SIZE; i < LASTCACHES; i++) { glab->gtktab_caches[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcache[i], "lab"))); glab->gtktab_caches[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectcache[i], "val"))); gtk_widget_set_name(glab->gtktab_caches[VALUE][i], "value"); } glab->gridcaches = GTK_WIDGET(gtk_builder_get_object(builder, "caches_grid")); /* Tab Motherboard */ for(i = MANUFACTURER; i < LASTMOTHERBOARD; i++) { glab->gtktab_motherboard[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectmb[i], "lab"))); glab->gtktab_motherboard[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectmb[i], "val"))); gtk_widget_set_name(glab->gtktab_motherboard[VALUE][i], "value"); } /* Tab RAM */ for(i = BANK0; i < LASTMEMORY; i++) { glab->gtktab_memory[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectram[i], "lab"))); glab->gtktab_memory[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectram[i], "val"))); gtk_widget_set_name(glab->gtktab_memory[VALUE][i], "value"); } glab->gridbanks = GTK_WIDGET(gtk_builder_get_object(builder, "memory_grid")); glab->scrollbanks = GTK_WIDGET(gtk_builder_get_object(builder, "memory_scrolledwindow")); /* Tab System */ for(i = KERNEL; i < LASTSYSTEM; i++) { glab->gtktab_system[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectsys[i], "lab"))); glab->gtktab_system[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectsys[i], "val"))); gtk_widget_set_name(glab->gtktab_system[VALUE][i], "value"); } for(i = BARUSED; i < LASTBAR; i++) { glab->bar[i] = GTK_WIDGET(gtk_builder_get_object(builder, objectsys_bar[i])); gtk_widget_set_name(GTK_WIDGET(glab->bar[i]), format("%i", i)); } /* Tab Graphics */ for(i = GPU1VENDOR; i < LASTGRAPHICS; i++) { glab->gtktab_graphics[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectgpu[i], "lab"))); glab->gtktab_graphics[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectgpu[i], "val"))); gtk_widget_set_name(glab->gtktab_graphics[VALUE][i], "value"); } glab->gridcards = GTK_WIDGET(gtk_builder_get_object(builder, "graphics_box")); /* Tab Bench */ for(i = PRIMESLOWSCORE; i < LASTBENCH; i++) { glab->gtktab_bench[NAME][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectbench[i], "lab"))); glab->gtktab_bench[VALUE][i] = GTK_WIDGET(gtk_builder_get_object(builder, get_id(objectbench[i], "val"))); gtk_widget_set_name(glab->gtktab_bench[VALUE][i], objectbench[i]); } /* Tab About */ for(i = DESCRIPTION; i < LASTABOUT; i++) glab->gtktab_about[i] = GTK_WIDGET(gtk_builder_get_object(builder, objectabout[i])); } #if PORTABLE_BINARY /* Backport gtk_css_provider_load_from_resource() for GTK < 3.16 https://github.com/GNOME/gtk/blob/master/gtk/gtkcssprovider.c#L1943 */ void __builtin_gtk_css_provider_load_from_resource(GtkCssProvider *css_provider, const gchar *resource_path) { GFile *file; gchar *uri, *escaped; g_return_if_fail (GTK_IS_CSS_PROVIDER (css_provider)); g_return_if_fail (resource_path != NULL); escaped = g_uri_escape_string (resource_path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE); uri = g_strconcat ("resource://", escaped, NULL); g_free (escaped); file = g_file_new_for_uri (uri); g_free (uri); gtk_css_provider_load_from_file (css_provider, file, NULL); g_object_unref (file); } #endif /* PORTABLE_BINARY */ static gboolean is_dark_theme(GtkLabels *glab) { gdouble contrast; GdkRGBA *fg, *bg; GtkStyleContext *context; context = gtk_widget_get_style_context(GTK_WIDGET(glab->mainwindow)); gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_COLOR, &fg, GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &bg, NULL); contrast = bg->red - fg->red + bg->green - fg->green + bg->blue - fg->blue; gdk_rgba_free(fg); gdk_rgba_free(bg); return (contrast < -1); } /* Set custom GTK theme */ static void set_colors(GtkLabels *glab) { gchar *filename = NULL; GtkCssProvider *provider = gtk_css_provider_new(); if(gtk_check_version(3, 19, 2) == NULL) // GTK 3.20 or newer filename = is_dark_theme(glab) ? g_strdup("cpu-x-gtk-3.20-dark.css") : g_strdup("cpu-x-gtk-3.20.css"); else // GTK 3.12 to 3.18 filename = is_dark_theme(glab) ? g_strdup("cpu-x-gtk-3.12-dark.css") : g_strdup("cpu-x-gtk-3.12.css"); gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); #if PORTABLE_BINARY if(gtk_check_version(3, 15, 0) == NULL) // GTK 3.16 or newer gtk_css_provider_load_from_resource(provider, GRESOURCE_CSS(filename)); else // GTK 3.12 to 3.14 __builtin_gtk_css_provider_load_from_resource(provider, GRESOURCE_CSS(filename)); #else gtk_css_provider_load_from_path(provider, data_path(filename), NULL); #endif /* PORTABLE_BINARY */ g_free(filename); g_object_unref(provider); } /* Set CPU vendor logo and program logo */ static void set_logos(GtkLabels *glab, Labels *data) { int width, height, prg_size = 72; GdkPixbuf *cpu_pixbuf = NULL, *unknown_pixbuf = NULL, *prg_pixbuf = NULL; GError *error = NULL; width = gtk_widget_get_allocated_width(glab->gtktab_cpu[VALUE][SPECIFICATION]) - gtk_widget_get_allocated_width(glab->gtktab_cpu[VALUE][VENDOR]) - 6; height = (gtk_widget_get_allocated_height(glab->gtktab_cpu[VALUE][VENDOR]) + 4) * 4; if(PORTABLE_BINARY) { cpu_pixbuf = gdk_pixbuf_new_from_resource_at_scale(format(GRESOURCE_LOGOS("%s.png"), data->tab_cpu[VALUE][VENDOR]), width, height, TRUE, &error); unknown_pixbuf = gdk_pixbuf_new_from_resource_at_scale(GRESOURCE_LOGOS("Unknown.png"), width, height, TRUE, NULL); prg_pixbuf = gdk_pixbuf_new_from_resource_at_scale(GRESOURCE_LOGOS("CPU-X.png"), prg_size, prg_size, TRUE, NULL); } else { cpu_pixbuf = gdk_pixbuf_new_from_file_at_scale(data_path(format("%s.png", data->tab_cpu[VALUE][VENDOR])), width, height, TRUE, &error); unknown_pixbuf = gdk_pixbuf_new_from_file_at_scale(data_path("Unknown.png"), width, height, TRUE, NULL); prg_pixbuf = gdk_pixbuf_new_from_file_at_scale(data_path("CPU-X.png"), prg_size, prg_size, TRUE, NULL); } gtk_window_set_icon(GTK_WINDOW(glab->mainwindow), prg_pixbuf); gtk_image_set_from_pixbuf(GTK_IMAGE(glab->logocpu), cpu_pixbuf); gtk_image_set_from_pixbuf(GTK_IMAGE(glab->logoprg), prg_pixbuf); g_object_unref(cpu_pixbuf); g_object_unref(prg_pixbuf); if(error != NULL) gtk_image_set_from_pixbuf(GTK_IMAGE(glab->logocpu), unknown_pixbuf); g_object_unref(unknown_pixbuf); } /* Filling all labels */ static void set_labels(GtkLabels *glab, Labels *data) { int i; const gint width1 = gtk_widget_get_allocated_width(glab->gtktab_system[VALUE][COMPILER]); const gint width2 = width1 - gtk_widget_get_allocated_width(glab->gtktab_system[VALUE][USED]) - 6; GtkRequisition requisition; /* Footer label */ gtk_label_set_text(GTK_LABEL(glab->labprgver), data->tab_about[VERSIONSTR]); /* Various labels to translate */ for(i = TABCPU; i < LASTOBJ; i++) gtk_label_set_text(GTK_LABEL(glab->gtktrad[i]), data->objects[i]); /* Tab CPU */ for(i = VENDOR; i < LASTCPU; i++) { gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[NAME][i]), data->tab_cpu[NAME][i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_cpu[VALUE][i]), data->tab_cpu[VALUE][i]); } for(i = 0; i < data->cpu_count; i++) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(glab->activecore), format(_("Core #%i"), i)); gtk_combo_box_set_active(GTK_COMBO_BOX(glab->activecore), opts->selected_core); /* Tab Caches */ for(i = L1SIZE; i < LASTCACHES; i++) { gtk_label_set_text(GTK_LABEL(glab->gtktab_caches[NAME][i]), data->tab_caches[NAME][i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_caches[VALUE][i]), data->tab_caches[VALUE][i]); } for(i = LASTCACHES / CACHEFIELDS; i > data->cache_count; i--) gtk_grid_remove_row(GTK_GRID(glab->gridcaches), i - 1); for(i = 0; i < data->w_data->test_count; i++) gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(glab->activetest), data->w_data->test_name[i]); gtk_combo_box_set_active(GTK_COMBO_BOX(glab->activetest), opts->bw_test); if(!data->cache_count) gtk_widget_hide(GTK_WIDGET(glab->gridcaches)); /* Tab Motherboard */ for(i = MANUFACTURER; i < LASTMOTHERBOARD; i++) { gtk_label_set_text(GTK_LABEL(glab->gtktab_motherboard[NAME][i]), data->tab_motherboard[NAME][i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_motherboard[VALUE][i]), data->tab_motherboard[VALUE][i]); } /* Tab RAM */ for(i = BANK0; i < data->dimm_count; i++) { g_strdelimit(data->tab_memory[VALUE][i], ",", '\n'); gtk_label_set_text(GTK_LABEL(glab->gtktab_memory[NAME][i]), data->tab_memory[NAME][i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_memory[VALUE][i]), data->tab_memory[VALUE][i]); } for(i = BANK7; i >= data->dimm_count; i--) gtk_grid_remove_row(GTK_GRID(glab->gridbanks), i); if(!data->dimm_count) gtk_widget_hide(GTK_WIDGET(glab->scrollbanks)); /* Tab System */ for(i = KERNEL; i < LASTSYSTEM; i++) { gtk_label_set_text(GTK_LABEL(glab->gtktab_system[NAME][i]), data->tab_system[NAME][i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_system[VALUE][i]), data->tab_system[VALUE][i]); } for(i = BARUSED; i < LASTBAR; i++) { gtk_widget_get_preferred_size(glab->gtktab_system[VALUE][USED], NULL, &requisition); gtk_widget_set_size_request(glab->bar[i], width2, requisition.height); } /* Tab Graphics */ for(i = GPU1VENDOR; i < LASTGRAPHICS; i++) { gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[NAME][i]), data->tab_graphics[NAME][i]); gtk_label_set_text(GTK_LABEL(glab->gtktab_graphics[VALUE][i]), data->tab_graphics[VALUE][i]); } for(i = LASTGRAPHICS / GPUFIELDS; i >= data->gpu_count; i--) gtk_grid_remove_row(GTK_GRID(glab->gridcards), i); if(!data->gpu_count) gtk_widget_hide(GTK_WIDGET(glab->gridcards)); /* Tab Bench */ for(i = PRIMESLOWSCORE; i < LASTBENCH; i++) gtk_label_set_text(GTK_LABEL(glab->gtktab_bench[NAME][i]), data->tab_bench[NAME][i]); for(i = PRIMESLOWSCORE; i <= PRIMEFASTSCORE; i += BENCHFIELDS) { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(glab->gtktab_bench[VALUE][i]), data->tab_bench[VALUE][i]); gtk_widget_set_size_request(glab->gtktab_bench[VALUE][i], width1, -1); } gtk_spin_button_set_increments(GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMDURATION]), 1, 60); gtk_spin_button_set_increments(GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMTHREADS]), 1, 1); gtk_spin_button_set_range (GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMDURATION]), 1, 60 * 24); gtk_spin_button_set_range (GTK_SPIN_BUTTON(glab->gtktab_bench[VALUE][PARAMTHREADS]), 1, data->cpu_count); /* Tab About */ for(i = DESCRIPTION; i < LASTABOUT; i++) gtk_label_set_text(GTK_LABEL(glab->gtktab_about[i]), data->tab_about[i]); } /* Call defined functions on signals */ static void set_signals(GtkLabels *glab, Labels *data, GThrd *refr) { int i; g_signal_connect(glab->mainwindow, "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(glab->closebutton, "clicked", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(glab->activecore, "changed", G_CALLBACK(change_activecore), data); g_signal_connect(glab->activetest, "changed", G_CALLBACK(change_activetest), data); g_signal_connect(glab->gtktab_bench[VALUE][PRIMESLOWRUN], "button-press-event", G_CALLBACK(start_benchmark_bg), refr); g_signal_connect(glab->gtktab_bench[VALUE][PRIMEFASTRUN], "button-press-event", G_CALLBACK(start_benchmark_bg), refr); g_signal_connect(glab->gtktab_bench[VALUE][PARAMDURATION], "value-changed", G_CALLBACK(change_benchparam), data); g_signal_connect(glab->gtktab_bench[VALUE][PARAMTHREADS], "value-changed", G_CALLBACK(change_benchparam), data); for(i = BARUSED; i < LASTBAR; i++) g_signal_connect(G_OBJECT(glab->bar[i]), "draw", G_CALLBACK(fill_frame), refr); } /* Draw bars in Memory tab */ void fill_frame(GtkWidget *widget, cairo_t *cr, GThrd *refr) { int i = USED, page; guint width, height; double before = 0, percent = 0; const gchar *widget_name; cairo_pattern_t *pat; PangoLayout *reflayout, *newlayout; Labels *(data) = refr->data; GtkLabels *(glab) = refr->glab; widget_name = gtk_widget_get_name(widget); width = gtk_widget_get_allocated_width(widget); height = gtk_widget_get_allocated_height(widget); page = atoi(widget_name); reflayout = gtk_label_get_layout(GTK_LABEL(glab->gtktab_system[VALUE][page + USED])); newlayout = pango_layout_copy(reflayout); if((page == BARSWAP && data->m_data->swap_total == 0) || (page != BARSWAP && data->m_data->mem_total == 0)) return; for(i = BARUSED; (i <= page) && (page != BARSWAP); i++) /* Get value to start */ { before += percent; percent = (double) data->m_data->mem_usage[i] / data->m_data->mem_total * 100; } if(page == BARSWAP) percent = (double) data->m_data->mem_usage[BARSWAP] / data->m_data->swap_total * 100; pat = cairo_pattern_create_linear(before / 100 * width, 0, percent / 100 * width, height); switch(page) /* Set differents level bar color */ { case BARUSED: cairo_pattern_add_color_stop_rgba(pat, 0, 1.00, 1.00, 0.15, 1); cairo_pattern_add_color_stop_rgba(pat, 1, 1.00, 0.75, 0.15, 1); break; case BARBUFFERS: cairo_pattern_add_color_stop_rgba(pat, 0, 0.00, 0.30, 0.75, 1); cairo_pattern_add_color_stop_rgba(pat, 1, 0.25, 0.55, 1.00, 1); break; case BARCACHED: cairo_pattern_add_color_stop_rgba(pat, 0, 1.00, 0.25, 0.90, 1); cairo_pattern_add_color_stop_rgba(pat, 1, 0.75, 0.00, 0.65, 1); break; case BARFREE: cairo_pattern_add_color_stop_rgba(pat, 0, 0.20, 1.00, 0.25, 1); cairo_pattern_add_color_stop_rgba(pat, 1, 0.00, 0.75, 0.05, 1); break; case BARSWAP: cairo_pattern_add_color_stop_rgba(pat, 0, 1.00, 0.35, 0.15, 1); cairo_pattern_add_color_stop_rgba(pat, 1, 0.75, 0.15, 0.00, 1); break; } cairo_rectangle(cr, before / 100 * width, 0, percent / 100 * width, height); /* Print a colored rectangle */ cairo_set_source(cr, pat); cairo_fill(cr); cairo_pattern_destroy(pat); /* Print percentage */ if(is_dark_theme(glab)) cairo_set_source_rgb(cr, 0.8080, 0.8080, 0.0); else cairo_set_source_rgb(cr, 0.0, 0.0, 0.8080); cairo_move_to(cr, -40, 0); pango_layout_set_text(newlayout, format("%.2f%%", percent), -1); pango_cairo_show_layout(cr, newlayout); cairo_fill(cr); g_object_unref(newlayout); } CPU-X-3.2.4/src/gui_gtk.h000066400000000000000000000100641341671471500147570ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE gui_gtk.h */ #ifndef _GUI_GTK_H_ #define _GUI_GTK_H_ #include #include #include #define GRESOURCE_UI(file) g_strconcat("/cpu-x/ui/", file, NULL) #define GRESOURCE_CSS(file) g_strconcat("/cpu-x/css/", file, NULL) #define GRESOURCE_LOGOS(file) g_strconcat("/cpu-x/logos/", file, NULL) typedef struct { /* Common */ GtkWidget *mainwindow; GtkWidget *notebook; GtkWidget *footer; GtkWidget *labprgver; GtkWidget *closebutton; GtkWidget *gtktrad[LASTOBJ]; /* Tab CPU */ GtkWidget *logocpu; GtkWidget *gtktab_cpu[2][LASTCPU]; GtkWidget *activecore; /* Tab Caches */ GtkWidget *gridcaches; GtkWidget *gtktab_caches[2][LASTCACHES]; GtkWidget *activetest; /* Tab Motherboard */ GtkWidget *gtktab_motherboard[2][LASTMOTHERBOARD]; /* Tab RAM */ GtkWidget *scrollbanks; GtkWidget *gridbanks; GtkWidget *gtktab_memory[2][LASTMEMORY]; /* Tab System */ GtkWidget *bar[LASTBAR]; GtkWidget *gtktab_system[2][LASTSYSTEM]; /* Tab Graphics */ GtkWidget *gridcards; GtkWidget *gtktab_graphics[2][LASTGRAPHICS]; /* Tab Bench */ GtkWidget *gtktab_bench[2][LASTBENCH]; /* Tab About */ GtkWidget *logoprg; GtkWidget *butcol; GtkWidget *gtktab_about[LASTABOUT]; } GtkLabels; /* Useful GtkWidgets */ typedef struct { GtkLabels *glab; Labels *data; } GThrd; /* Used to refresh GUI */ /********************************** GUI **********************************/ /* Start CPU-X in GTK mode */ void start_gui_gtk(int *argc, char **argv[], Labels *data); /* Print a window which allows to restart CPU-X as root */ static void warning_window(GtkWidget *mainwindow); /* In portable version, inform when a new version is available and ask for update */ static void new_version_window(GtkWidget *mainwindow); /* Refresh dynamic values */ static gboolean grefresh(GThrd *refr); /* Event in CPU tab when Core number is changed */ static void change_activecore(GtkComboBox *box, Labels *data); /* Event in Caches tab when Test number is changed */ static void change_activetest(GtkComboBox *box, Labels *data); /* Events in Bench tab when a benchmark start/stop */ static void start_benchmark_bg(GtkSwitch *gswitch, GdkEvent *event, GThrd *refr); /* Events in Bench tab when Duration/Threads SpinButtons are changed */ static void change_benchparam(GtkSpinButton *spinbutton, Labels *data); /* Set/Unset widgets sensitive when a benchmark start/stop */ static void change_benchsensitive(GtkLabels *glab, Labels *data); /* Get label ID ('type' must be "lab" or "val") */ static gchar *get_id(const gchar *objectstr, gchar *type); /* Search file location in standard paths */ static gchar *data_path(const gchar *file); /* Retrieve widgets from GtkBuilder */ static void get_widgets(GtkBuilder *builder, GtkLabels *glab); /* Set custom GTK theme */ static void set_colors(GtkLabels *glab); /* Set CPU vendor logo and program logo */ static void set_logos(GtkLabels *glab, Labels *data); /* Filling all labels */ static void set_labels(GtkLabels *glab, Labels *data); /* Call defined functions on signals */ static void set_signals(GtkLabels *glab, Labels *data, GThrd *refr); /* Draw bars in Memory tab */ void fill_frame(GtkWidget *widget, cairo_t *cr, GThrd *refr); #endif /* _GUI_GTK_H_ */ CPU-X-3.2.4/src/gui_gtk_id.h000066400000000000000000000070561341671471500154420ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE gui_gtk_id.h */ #ifndef _GUI_GTK_ID_H_ #define _GUI_GTK_ID_H_ /* Translation */ static const char *trad[LASTOBJ] = { "cpulabel", "cacheslabel", "motherboardlabel", "ramlabel", "systemlabel", "graphicslabel", "benchlabel", "aboutlabel", "proc_lab", "clock_lab", "cache_lab", "l1cache_lab", "l2cache_lab", "l3cache_lab", "l4cache_lab", "test_lab", "motherboard_lab", "bios_lab", "chip_lab", "bank0_lab", "bank1_lab", "bank2_lab", "bank3_lab", "bank4_lab", "bank5_lab", "bank6_lab", "bank7_lab", "os_lab", "mem_lab", "card0_lab", "card1_lab", "card2_lab", "card3_lab", "primeslow_lab", "primefast_lab", "param_lab", "about_lab", "license_lab" }; /* Tab CPU */ static const char *objectcpu[LASTCPU] = { "proc_vendor", "proc_cdename", "proc_pkg", "proc_tech", "proc_volt", "proc_spec", "proc_fam", "proc_extfam", "proc_mod", "proc_extmod", "proc_temp", "proc_step", "proc_instr", "clock_core", "clock_mult", "clock_bus", "clock_usage", "cache_l1d", "cache_l1i", "cache_l2", "cache_l3", "trg_sock", "trg_core", "trg_thrd" }; /* Tab Caches */ static const char *objectcache[LASTCACHES] = { "l1cache_size", "l1cache_speed", "l2cache_size", "l2cache_speed", "l3cache_size", "l3cache_speed", "l4cache_size", "l4cache_speed" }; /* Tab Motherboard */ static const char *objectmb[LASTMOTHERBOARD] = { "motherboard_manu", "motherboard_mod", "motherboard_rev", "bios_brand", "bios_vers", "bios_date", "bios_rom", "chip_vend", "chip_name" }; /* Tab RAM */ static const char *objectram[LASTMEMORY] = { "bank0_ref", "bank1_ref", "bank2_ref", "bank3_ref", "bank4_ref", "bank5_ref", "bank6_ref", "bank7_ref" }; /* Tab System */ static const char *objectsys[LASTSYSTEM] = { "os_kern", "os_distro", "os_host", "os_uptime", "os_comp", "mem_used", "mem_buff", "mem_cache", "mem_free", "mem_swap" }; static const char *objectsys_bar[LASTBAR] = { "mem_barused", "mem_barbuff", "mem_barcache", "mem_barfree", "mem_barswap" }; /* Tab Graphics */ static const char *objectgpu[LASTGRAPHICS] = { "card0_vend", "card0_mod", "card0_temp", "card0_usage", "card0_gclk", "card0_mclk", "card1_vend", "card1_mod", "card1_temp", "card1_usage", "card1_gclk", "card1_mclk", "card2_vend", "card2_mod", "card2_temp", "card2_usage", "card2_gclk", "card2_mclk", "card3_vend", "card3_mod", "card3_temp", "card3_usage", "card3_gclk", "card3_mclk" }; /* Tab Bench */ static const char *objectbench[LASTBENCH] = { "primeslow_score", "primeslow_run", "primefast_score", "primefast_run", "param_duration", "param_threads" }; /* Tab About */ static const char *objectabout[LASTABOUT] = { "about_descr", "about_version", "about_author", "about_site", "license_labcopyright", "license_lablicense", "license_nowarranty" }; #endif /* _GUI_GTK_ID_H_ */ CPU-X-3.2.4/src/main.c000066400000000000000000001025521341671471500142510ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE main.c */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "cpu-x.h" #define HAS_WEB_SUPPORT (HAS_LIBCURL && HAS_LIBJSONC) #if HAS_WEB_SUPPORT # include # include #endif #if PORTABLE_BINARY # include # include # include # if HAS_GETTEXT # include "../po/mo.h" # endif #endif char *binary_name, *new_version[2] = { NULL, NULL }; Options *opts; /************************* Arrays management functions *************************/ /* Set labels name */ static void labels_setname(Labels *data) { int i, j; MSG_VERBOSE(_("Setting label names")); /* CPU tab */ asprintf(&data->objects[TABCPU], _("CPU")); // Tab label asprintf(&data->objects[FRAMPROCESSOR], _("Processor")); // Frame label asprintf(&data->tab_cpu[NAME][VENDOR], _("Vendor")); asprintf(&data->tab_cpu[NAME][CODENAME], _("Code Name")); asprintf(&data->tab_cpu[NAME][PACKAGE], _("Package")); asprintf(&data->tab_cpu[NAME][TECHNOLOGY], _("Technology")); asprintf(&data->tab_cpu[NAME][VOLTAGE], _("Voltage")); asprintf(&data->tab_cpu[NAME][SPECIFICATION], _("Specification")); asprintf(&data->tab_cpu[NAME][FAMILY], _("Family")); asprintf(&data->tab_cpu[NAME][EXTFAMILY], _("Ext. Family")); asprintf(&data->tab_cpu[NAME][MODEL], _("Model")); asprintf(&data->tab_cpu[NAME][EXTMODEL], _("Ext. Model")); asprintf(&data->tab_cpu[NAME][TEMPERATURE], _("Temp.")); asprintf(&data->tab_cpu[NAME][STEPPING], _("Stepping")); asprintf(&data->tab_cpu[NAME][INSTRUCTIONS], _("Instructions")); asprintf(&data->objects[FRAMCLOCKS], _("Clocks")); // Frame label asprintf(&data->tab_cpu[NAME][CORESPEED], _("Core Speed")); asprintf(&data->tab_cpu[NAME][MULTIPLIER], _("Multiplier")); asprintf(&data->tab_cpu[NAME][BUSSPEED], _("Bus Speed")); asprintf(&data->tab_cpu[NAME][USAGE], _("Usage")); asprintf(&data->objects[FRAMCACHE], _("Cache")); // Frame label asprintf(&data->tab_cpu[NAME][LEVEL1D], _("L1 Data")); asprintf(&data->tab_cpu[NAME][LEVEL1I], _("L1 Inst.")); asprintf(&data->tab_cpu[NAME][LEVEL2], _("Level 2")); asprintf(&data->tab_cpu[NAME][LEVEL3], _("Level 3")); asprintf(&data->tab_cpu[NAME][SOCKETS], _("Socket(s)")); asprintf(&data->tab_cpu[NAME][CORES], _("Core(s)")); asprintf(&data->tab_cpu[NAME][THREADS], _("Thread(s)")); /* Caches tab */ asprintf(&data->objects[TABCACHES], _("Caches")); // Tab label for(i = L1SIZE; i < LASTCACHES; i += CACHEFIELDS) { j = i / CACHEFIELDS; asprintf(&data->objects[FRAML1CACHE + j], _("L%i Cache"), j + 1); // Frame label asprintf(&data->tab_caches[NAME][L1SIZE + i], _("Size")); asprintf(&data->tab_caches[NAME][L1SPEED + i], _("Speed")); } asprintf(&data->objects[FRAMTEST], _("Test")); /* Motherboard tab */ asprintf(&data->objects[TABMOTHERBOARD], _("Motherboard")); // Tab label asprintf(&data->objects[FRAMMOTHERBOARD], _("Motherboard")); // Frame label asprintf(&data->tab_motherboard[NAME][MANUFACTURER], _("Manufacturer")); asprintf(&data->tab_motherboard[NAME][MBMODEL], _("Model")); asprintf(&data->tab_motherboard[NAME][REVISION], _("Revision")); asprintf(&data->objects[FRAMBIOS], _("BIOS")); // Frame label asprintf(&data->tab_motherboard[NAME][BRAND], _("Brand")); asprintf(&data->tab_motherboard[NAME][BIOSVERSION], _("Version")); asprintf(&data->tab_motherboard[NAME][DATE], _("Date")); asprintf(&data->tab_motherboard[NAME][ROMSIZE], _("ROM Size")); asprintf(&data->objects[FRAMCHIPSET], _("Chipset")); // Frame label asprintf(&data->tab_motherboard[NAME][CHIPVENDOR], _("Vendor")); asprintf(&data->tab_motherboard[NAME][CHIPMODEL], _("Model")); /* Memory tab */ asprintf(&data->objects[TABMEMORY], _("Memory")); // Tab label for(i = BANK0; i < LASTMEMORY; i++) { asprintf(&data->objects[FRAMBANK0 + i], _("Bank %i"), i); asprintf(&data->tab_memory[NAME][i], _("Reference")); } /* System tab */ asprintf(&data->objects[TABSYSTEM], _("System")); // Tab label asprintf(&data->objects[FRAMOPERATINGSYSTEM], _("Operating System")); // Frame label asprintf(&data->tab_system[NAME][KERNEL], _("Kernel")); asprintf(&data->tab_system[NAME][DISTRIBUTION], _("Distribution")); asprintf(&data->tab_system[NAME][HOSTNAME], _("Hostname")); asprintf(&data->tab_system[NAME][UPTIME], _("Uptime")); asprintf(&data->tab_system[NAME][COMPILER], _("Compiler")); asprintf(&data->objects[FRAMMEMORY], _("Memory")); // Frame label asprintf(&data->tab_system[NAME][USED], _("Used")); asprintf(&data->tab_system[NAME][BUFFERS], _("Buffers")); asprintf(&data->tab_system[NAME][CACHED], _("Cached")); asprintf(&data->tab_system[NAME][FREE], _("Free")); asprintf(&data->tab_system[NAME][SWAP], _("Swap")); /* Graphics tab */ asprintf(&data->objects[TABGRAPHICS], _("Graphics")); // Tab label for(i = GPU1VENDOR; i < LASTGRAPHICS; i += GPUFIELDS) { j = i / GPUFIELDS; asprintf(&data->objects[FRAMGPU1 + j], _("Card %i"), j); // Frame label asprintf(&data->tab_graphics[NAME][GPU1VENDOR + i], _("Vendor")); asprintf(&data->tab_graphics[NAME][GPU1MODEL + i], _("Model")); asprintf(&data->tab_graphics[NAME][GPU1TEMPERATURE + i], _("Temperature")); asprintf(&data->tab_graphics[NAME][GPU1USAGE + i], _("Usage")); asprintf(&data->tab_graphics[NAME][GPU1CORECLOCK + i], _("GPU clock")); asprintf(&data->tab_graphics[NAME][GPU1MEMCLOCK + i], _("Memory clock")); } /* Bench tab */ asprintf(&data->objects[TABBENCH], _("Bench")); // Tab label asprintf(&data->objects[FRAMPRIMESLOW], _("Prime numbers (slow)")); // Frame label asprintf(&data->objects[FRAMPRIMEFAST], _("Prime numbers (fast)")); // Frame label for(i = PRIMESLOWSCORE; i < PARAMDURATION; i += BENCHFIELDS) { asprintf(&data->tab_bench[NAME][PRIMESLOWSCORE + i], _("Score")); asprintf(&data->tab_bench[NAME][PRIMESLOWRUN + i], _("Run")); } asprintf(&data->objects[FRAMPARAM], _("Parameters")); // Frame label asprintf(&data->tab_bench[NAME][PARAMDURATION], _("Duration")); asprintf(&data->tab_bench[NAME][PARAMTHREADS], _("Threads")); /* About tab */ asprintf(&data->objects[TABABOUT], _("About")); // Tab label asprintf(&data->tab_about[DESCRIPTION], _( "%s is a Free software that gathers information\n" "on CPU, motherboard and more."), PRGNAME); asprintf(&data->objects[FRAMABOUT], _("About")); // Frame label asprintf(&data->tab_about[VERSIONSTR], _("Version %s"), PRGVER); asprintf(&data->tab_about[AUTHOR], _("Author: %s"), PRGAUTH); asprintf(&data->tab_about[SITE], _("Site: %s"), PRGURL); asprintf(&data->objects[FRAMLICENSE], _("License")); // Frame label asprintf(&data->tab_about[COPYRIGHT], PRGCPRGHT); asprintf(&data->tab_about[LICENSE], _( "This software is distributed under the terms of %s"), PRGLCNS); asprintf(&data->tab_about[NOWARRANTY], _( "This program comes with ABSOLUTELY NO WARRANTY")); /* Initialize all values */ Arrays arrays[] = { { data->tab_cpu[NAME], data->tab_cpu[VALUE], LASTCPU }, { data->tab_caches[NAME], data->tab_caches[VALUE], LASTCACHES }, { data->tab_motherboard[NAME], data->tab_motherboard[VALUE], LASTMOTHERBOARD }, { data->tab_memory[NAME], data->tab_memory[VALUE], LASTMEMORY }, { data->tab_system[NAME], data->tab_system[VALUE], LASTSYSTEM }, { data->tab_graphics[NAME], data->tab_graphics[VALUE], LASTGRAPHICS }, { data->tab_bench[NAME], data->tab_bench[VALUE], LASTBENCH }, { NULL, NULL, 0 } }; for(i = 0; arrays[i].dim_names != NULL; i++) { for(j = 0; j < arrays[i].last; j++) casprintf(&arrays[i].dim_values[j], false, "%c", '\0'); } } /* Dump all data in stdout */ static void dump_data(Labels *data) { int i, j, k = 0; const char *col_start = opts->color ? BOLD_BLUE : ""; const char *col_end = opts->color ? DEFAULT : ""; const Arrays arrays[] = { { data->tab_cpu[NAME], data->tab_cpu[VALUE], LASTCPU }, { data->tab_caches[NAME], data->tab_caches[VALUE], data->cache_count * CACHEFIELDS }, { data->tab_motherboard[NAME], data->tab_motherboard[VALUE], LASTMOTHERBOARD }, { data->tab_memory[NAME], data->tab_memory[VALUE], data->dimm_count }, { data->tab_system[NAME], data->tab_system[VALUE], LASTSYSTEM }, { data->tab_graphics[NAME], data->tab_graphics[VALUE], data->gpu_count * GPUFIELDS }, { NULL, NULL, 0 } }; const struct { int tab_nb, lab_nb, frame_nb; } frames[] = { { NO_CPU, VENDOR, FRAMPROCESSOR }, { NO_CPU, CORESPEED, FRAMCLOCKS }, { NO_CPU, LEVEL1D, FRAMCACHE }, { NO_CPU, SOCKETS, -1 }, { NO_CACHES, L1SIZE, FRAML1CACHE }, { NO_CACHES, L2SIZE, FRAML2CACHE }, { NO_CACHES, L3SIZE, FRAML3CACHE }, { NO_CACHES, L4SIZE, FRAML4CACHE }, { NO_MOTHERBOARD, MANUFACTURER, FRAMMOTHERBOARD }, { NO_MOTHERBOARD, BRAND, FRAMBIOS }, { NO_MOTHERBOARD, CHIPVENDOR, FRAMCHIPSET }, { NO_MEMORY, BANK0, FRAMBANK0 }, { NO_MEMORY, BANK1, FRAMBANK1 }, { NO_MEMORY, BANK2, FRAMBANK2 }, { NO_MEMORY, BANK3, FRAMBANK3 }, { NO_MEMORY, BANK4, FRAMBANK4 }, { NO_MEMORY, BANK5, FRAMBANK5 }, { NO_MEMORY, BANK6, FRAMBANK6 }, { NO_MEMORY, BANK7, FRAMBANK7 }, { NO_SYSTEM, KERNEL, FRAMOPERATINGSYSTEM }, { NO_SYSTEM, USED, FRAMMEMORY }, { NO_GRAPHICS, GPU1VENDOR, FRAMGPU1 }, { NO_GRAPHICS, GPU2VENDOR, FRAMGPU2 }, { NO_GRAPHICS, GPU3VENDOR, FRAMGPU3 }, { NO_GRAPHICS, GPU4VENDOR, FRAMGPU4 } }; MSG_VERBOSE(_("Dumping data...")); for(i = 0; arrays[i].dim_names != NULL; i++) { MSG_STDOUT(" %s>>>>>>>>>> %s <<<<<<<<<<%s", col_start, data->objects[i], col_end); while(frames[k].tab_nb != i) k++; for(j = 0; j < arrays[i].last; j++) { if(frames[k].tab_nb == i && frames[k].lab_nb == j) { MSG_STDOUT("\n\t%s***** %s *****%s", col_start, (frames[k].frame_nb >= 0) ? data->objects[frames[k].frame_nb] : "*", col_end); k++; } MSG_STDOUT("%16s: %s", arrays[i].dim_names[j], arrays[i].dim_values[j]); } MSG_STDOUT("\n"); } labels_free(data); } /* Free memory after display labels */ void labels_free(Labels *data) { int i, j; Arrays arrays[] = { { data->objects, NULL, LASTOBJ }, { data->tab_cpu[NAME], data->tab_cpu[VALUE], LASTCPU }, { data->tab_caches[NAME], data->tab_caches[VALUE], data->cache_count * CACHEFIELDS }, { data->w_data->test_name, NULL, data->w_data->test_count }, { data->tab_motherboard[NAME], data->tab_motherboard[VALUE], LASTMOTHERBOARD }, { data->tab_memory[NAME], data->tab_memory[VALUE], data->dimm_count }, { data->tab_system[NAME], data->tab_system[VALUE], LASTSYSTEM }, { data->tab_graphics[NAME], data->tab_graphics[VALUE], data->gpu_count * GPUFIELDS }, { data->tab_bench[NAME], data->tab_bench[VALUE], LASTBENCH }, { data->tab_about, NULL, LASTABOUT }, { NULL, NULL, 0 } }; MSG_VERBOSE(_("Freeing memory")); for(i = 0; arrays[i].dim_names != NULL; i++) { for(j = 0; j < arrays[i].last; j++) { free(arrays[i].dim_names[j]); arrays[i].dim_names[j] = NULL; if(arrays[i].dim_values != NULL) { free(arrays[i].dim_values[j]); arrays[i].dim_values[j] = NULL; } } } } /************************* Update-related functions *************************/ #if HAS_WEB_SUPPORT /* Write function for Curl */ static size_t writefunc(void *ptr, size_t size, size_t nmemb, void **stream) { char **buff = (char**) stream; char *old_buff = *buff; char *tmp = NULL; const size_t len = size * nmemb; const size_t old_len = (old_buff == NULL) ? 0 : strlen(old_buff); const size_t new_len = old_len + len; if((tmp = realloc(old_buff, new_len + 1)) == NULL) { MSG_ERRNO(_("could not reallocate memory")); MSG_STDERR(_("Exiting %s"), PRGNAME); exit(255); } *buff = tmp; memcpy(&((*buff)[old_len]), ptr, len); (*buff)[new_len] = '\0'; return len; } /* Check if running version is latest */ static bool check_new_version(void) { char *json = NULL; CURL *curl; CURLcode code; json_object *jobj; if(!opts->use_network) { asprintf(&new_version[1], "%c", '\0'); return false; } MSG_VERBOSE(_("Checking on Internet for a new version...")); curl = curl_easy_init(); if(!curl) { MSG_ERROR(_("failed to open a Curl session")); return 1; } curl_easy_setopt(curl, CURLOPT_URL, UPDURL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/" LIBCURL_VERSION); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &json); code = curl_easy_perform(curl); curl_easy_cleanup(curl); if(code == CURLE_OK) { jobj = json_tokener_parse(json); const char *tag_name = json_object_get_string(json_object_object_get(jobj, "tag_name")); if((tag_name != NULL) && (strlen(tag_name) > 1)) asprintf(&new_version[0], &(tag_name[1])); // Remove the 'v' at beginning json_object_put(jobj); } free(json); if(new_version[0] == NULL) { MSG_ERROR(_("failed to perform the Curl transfer (%s)"), (new_version[0] != NULL) ? curl_easy_strerror(code) : _("wrong write data")); opts->use_network = false; asprintf(&new_version[1], "%c", '\0'); } else if(strcmp(new_version[0], PRGVER)) { MSG_VERBOSE(_("A new version of %s is available!"), PRGNAME); asprintf(&new_version[1], _("(version %s is available)"), new_version[0]); return true; } else { MSG_VERBOSE(_("No new version available")); asprintf(&new_version[1], _("(up-to-date)")); } free(new_version[0]); new_version[0] = NULL; return false; } # if 0 //PORTABLE_BINARY /* Copy function for libarchive */ static int copy_data(struct archive *ar, struct archive *aw) { int ret; const void *buff; size_t size; la_int64_t offset; while(true) { ret = archive_read_data_block(ar, &buff, &size, &offset); if(ret == ARCHIVE_EOF) return ARCHIVE_OK; if(ret < ARCHIVE_OK) return ret; if((ret = archive_write_data_block(aw, buff, size, offset)) < ARCHIVE_OK) return ret; } } /* Extract a .tar.gz archive */ static int extract_archive(const char *filename, const char *needed) { int ret; const int flags = ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM; struct archive *archive, *ext, *archive_ptr; struct archive_entry *entry; archive = archive_read_new(); archive_read_support_format_tar(archive); archive_read_support_filter_gzip(archive); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); archive_ptr = archive; if((ret = archive_read_open_filename(archive, filename, 10240))) goto error; do { if((ret = archive_read_next_header(archive, &entry)) != ARCHIVE_OK) goto error; } while(strcmp(archive_entry_pathname(entry), needed)); archive_ptr = ext; if((ret = archive_write_header(ext, entry)) != ARCHIVE_OK) goto error; if((ret = copy_data(archive, ext)) != ARCHIVE_OK) goto error; if((ret = archive_write_finish_entry(ext)) != ARCHIVE_OK) goto error; archive_read_close(archive); archive_read_free(archive); archive_write_close(ext); archive_write_free(ext); return 0; error: MSG_ERROR(_("an error occurred while extracting %s archive (%s)"), filename, archive_error_string(archive_ptr)); return 1; } /* Apply new portable version if available */ static int update_prg(void) { int err; char *archive = NULL, *new_binary = NULL; CURL *curl; CURLcode code; FILE *file_descr = NULL; if(!opts->use_network) { MSG_WARNING(_("Network access is disabled by environment variable" " (set CPUX_NETWORK with a positive value to enable it)")); return 1; } if(new_version[0] == NULL) { MSG_WARNING(_("No new version available")); return 2; } curl = curl_easy_init(); if(!curl) { MSG_ERROR(_("failed to open a Curl session")); return 3; } asprintf(&archive, "%s_v%s_portable%s.tar.gz", PRGNAME, new_version[0], HAS_GTK ? "" : "_noGTK"); file_descr = fopen(archive, "wb"); if(file_descr == NULL) { MSG_ERRNO(_("failed to open %s archive for writing"), archive); free(archive); return 4; } /* Download archive */ MSG_VERBOSE(_("Downloading new version...")); curl_easy_setopt(curl, CURLOPT_URL, format("%s/v%s/%s", TARBALL, new_version[0], archive)); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2 * 60L); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L); curl_easy_setopt(curl, CURLOPT_WRITEDATA, file_descr); code = curl_easy_perform(curl); curl_easy_cleanup(curl); fclose(file_descr); if(code != CURLE_OK) { MSG_ERROR(_("failed to download %s archive (%s)"), archive, curl_easy_strerror(code)); free(archive); return 5; } /* Extract archive */ MSG_VERBOSE(_("Extracting new version...")); asprintf(&new_binary, "%s_v%s_portable%s.%s", PRGNAME, new_version[0], HAS_GTK ? "" : "_noGTK", OS); err = extract_archive(archive, new_binary); if(err) { remove(archive); return err; } /* Rename new binary */ MSG_VERBOSE(_("Applying new version...")); if(strstr(binary_name, PRGVER) != NULL) // If binary name contains version { err = remove(binary_name); // Delete old version and keep new version err += rename(new_binary, format("%s_v%s", PRGNAME, new_version[0])); } else err = rename(new_binary, binary_name); // Erase old version by new version err += remove(archive); if(err) MSG_ERROR(_("an error occurred while removing/renaming files")); else MSG_VERBOSE(_("Update successful!")); return err; } # endif /* PORTABLE_BINARY */ #endif /* HAS_WEB_SUPPORT */ /************************* Options-related functions *************************/ static const struct { const bool has_mod; const char short_opt; const char *long_opt; const int need_arg; char *description; } cpux_options[] = { { HAS_GTK, 'g', "gtk", no_argument, N_("Start graphical user interface (GUI) (default)") }, { HAS_NCURSES, 'n', "ncurses", no_argument, N_("Start text-based user interface (TUI)") }, { true, 'd', "dump", no_argument, N_("Dump all data on standard output and exit") }, { HAS_DMIDECODE, 'D', "dmidecode", no_argument, N_("Run embedded command dmidecode and exit") }, { HAS_BANDWIDTH, 'B', "bandwidth", no_argument, N_("Run embedded command bandwidth and exit") }, { true, 'a', "tab", required_argument, N_("Set default tab (integer)") }, { HAS_LIBCPUID, 'c', "core", required_argument, N_("Select CPU core to monitor (integer)") }, { HAS_BANDWIDTH, 't', "cachetest", required_argument, N_("Set custom bandwidth test for CPU caches speed (integer)") }, { true, 'r', "refresh", required_argument, N_("Set custom time between two refreshes (in seconds)") }, { true, 'o', "nocolor", no_argument, N_("Disable colored output") }, { true, 'i', "issue-fmt", no_argument, N_("Print required informations to paste in an issue") }, { true, 'v', "verbose", no_argument, N_("Verbose output") }, { PORTABLE_BINARY, 'u', "update", no_argument, N_("Update portable version if a new version is available") }, { true, 'h', "help", no_argument, N_("Print help and exit") }, { true, 'V', "version", no_argument, N_("Print version and exit") }, { true, '0', NULL, 0, NULL } }; static const struct { const bool has_mod; const char *var_name; char *description; } cpux_env_vars[] = { { HAS_WEB_SUPPORT, "CPUX_NETWORK", N_("Temporarily disable network support") }, { true, "CPUX_BCLK", N_("Enforce the bus clock") }, { HAS_LIBCPUID, "CPUX_CPUID_RAW", N_("Read CPUID raw data from a given file") }, { HAS_LIBCPUID, "CPUX_DEBUG_DATABASE", N_("Only print a message if CPU does not belong in database") }, { true, NULL, NULL } }; /* This is help display with --help option */ static void help(void) { int i; MSG_STDOUT(_("Usage: %s DISPLAY [OPTIONS]\n"), binary_name); MSG_STDOUT(_("Available DISPLAY:")); for(i = 0; cpux_options[i].long_opt != NULL; i++) { if(cpux_options[i].short_opt == 'a') MSG_STDOUT(_("\nAvailable OPTIONS:")); if(cpux_options[i].has_mod) MSG_STDOUT(" -%c, --%-10s %s", cpux_options[i].short_opt, cpux_options[i].long_opt, _(cpux_options[i].description)); } MSG_STDOUT(_("\nInfluenceable environment variables:")); for(i = 0; cpux_env_vars[i].var_name != NULL; i++) { if(cpux_env_vars[i].has_mod) MSG_STDOUT(" %-20s %s", cpux_env_vars[i].var_name, _(cpux_env_vars[i].description)); } } /* This is the --version option */ static void version(void) { int i; const struct { const bool has_mod; const char *lib, *version; } libs_ver[] = { { HAS_GTK, "GTK", GTK_VERSION }, { HAS_NCURSES, "NCURSES", NCURSES_VERSION }, { HAS_LIBCURL, "LIBCURL", LIBCURL_VERSION }, { HAS_LIBJSONC, "LIBJSONC", LIBJSONC_VERSION }, { HAS_LIBCPUID, "LIBCPUID", LIBCPUID_VERSION }, { HAS_LIBPCI, "LIBPCI", LIBPCI_VERSION }, { HAS_LIBPROCPS, "LIBPROCPS", LIBPROCPS_VERSION }, { HAS_LIBSTATGRAB, "LIBSTATGRAB", LIBSTATGRAB_VERSION }, { HAS_DMIDECODE, "DMIDECODE", DMIDECODE_VERSION }, { HAS_BANDWIDTH, "BANDWIDTH", BANDWIDTH_VERSION }, { false, NULL, NULL } }; if(HAS_WEB_SUPPORT) check_new_version(); MSG_STDOUT("%s %s %s", PRGNAME, PRGVER, new_version[1]); MSG_STDOUT("%s\n", PRGCPRGHT); MSG_STDOUT(_("This is free software: you are free to change and redistribute it.")); MSG_STDOUT(_("This program comes with ABSOLUTELY NO WARRANTY")); MSG_STDOUT(_("See the %s license: <%s>\n"), PRGLCNS, LCNSURL); MSG_STDOUT(_("Built on %s, %s (with %s %s on %s)."), __DATE__, __TIME__, CC, __VERSION__, OS); free(new_version[1]); /* Print features version */ for(i = 0; libs_ver[i].lib != NULL; i++) { if(libs_ver[i].has_mod) MSG_STDOUT(_("-- %-9s version: %s"), libs_ver[i].lib, libs_ver[i].version); } } /* Parse arguments and set some flags */ #define OPTIONS_COUNT (sizeof(cpux_options) / sizeof(cpux_options[0]) - 1) static void parse_arguments(int argc, char *argv[]) { int i, j = 0, c, tmp_arg = -1; char shortopts[OPTIONS_COUNT * 2] = ""; struct option longopts[OPTIONS_COUNT]; /* Filling longopts structure */ for(i = 0; cpux_options[i].long_opt != NULL; i++) { while(!cpux_options[i].has_mod) i++; longopts[j++] = (struct option) { .name = cpux_options[i].long_opt, .has_arg = cpux_options[i].need_arg, .flag = 0, .val = cpux_options[i].short_opt }; strcat(shortopts, format("%c%s", cpux_options[i].short_opt, cpux_options[i].need_arg ? ":" : "")); } /* Avoid uninitialized members */ c = OPTIONS_COUNT - 1; for(i = j; i < (int) OPTIONS_COUNT; i++) longopts[i] = (struct option) { .name = cpux_options[c].long_opt, .has_arg = cpux_options[c].need_arg, .flag = 0, .val = cpux_options[c].short_opt }; /* Set the default mode */ if(HAS_GTK && (getenv("DISPLAY") != NULL || getenv("WAYLAND_DISPLAY") != NULL)) opts->output_type = OUT_GTK; else if(HAS_NCURSES) opts->output_type = OUT_NCURSES; else opts->output_type = OUT_DUMP; /* Parse options */ while((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(c) { case 'g': opts->output_type = OUT_GTK; break; case 'n': opts->output_type = OUT_NCURSES; break; case 'd': opts->output_type = OUT_DUMP; break; case 'r': tmp_arg = atoi(optarg); if(tmp_arg >= 1) opts->refr_time = tmp_arg; break; case 'a': tmp_arg = atoi(optarg); if(NO_CPU < tmp_arg && tmp_arg <= NO_ABOUT) opts->selected_page = tmp_arg; break; case 'c': tmp_arg = atoi(optarg); if(tmp_arg >= 0) opts->selected_core = tmp_arg; break; case 't': tmp_arg = atoi(optarg); if(tmp_arg >= 0) opts->bw_test = atoi(optarg); break; case 'D': opts->output_type = OUT_DMIDECODE; break; case 'B': opts->output_type = OUT_BANDWIDTH; break; case 'o': opts->color = false; break; case 'i': opts->color = false; opts->verbose = true; opts->issue = true; opts->use_network = 0; opts->output_type = OUT_DUMP; setlocale(LC_ALL, "C"); version(); break; case 'v': opts->verbose = true; break; case 'u': opts->update = true; break; case 'h': help(); exit(EXIT_SUCCESS); case 'V': version(); exit(EXIT_SUCCESS); case '?': default: help(); exit(EXIT_FAILURE); } } } /* Check for influenceable environment variables */ static void check_environment_variables(Labels *data) { if(getenv("CPUX_NETWORK")) opts->use_network = ((atoi(getenv("CPUX_NETWORK"))) > 0); if(getenv("CPUX_BCLK")) data->bus_freq = atof(getenv("CPUX_BCLK")); if(getenv("CPUX_CPUID_RAW")) data->l_data->cpuid_raw_file = getenv("CPUX_CPUID_RAW"); if(getenv("CPUX_DEBUG_DATABASE")) opts->debug_database = ((atoi(getenv("CPUX_DEBUG_DATABASE"))) > 0); if(getenv("CPUX_FORCE_FREQ_FALLBACK")) opts->freq_fallback = ((atoi(getenv("CPUX_FORCE_FREQ_FALLBACK"))) > 0); } /************************* Main-related functions *************************/ /* Action on SIGSEV/SIGFPE */ static void sighandler(int signum) { int bt_size, i; char **bt_syms, *buff = NULL; void *bt[16]; /* Get the backtrace */ bt_size = backtrace(bt, 16); bt_syms = backtrace_symbols(bt, bt_size); /* Print the backtrace */ MSG_STDERR(_("\n%sOops, something was wrong! %s has received signal %d (%s) and has crashed.%s"), BOLD_RED, PRGNAME, signum, strsignal(signum), DEFAULT); MSG_STDERR("========================= Backtrace ========================="); MSG_STDERR("%s %s (%s, %s)", PRGNAME, PRGVER, CC, OS); for(i = 1; i < bt_size; i++) { char *address = strtok(strrchr(strdup(bt_syms[i]), '[') + 1, "]"); popen_to_str(&buff, "addr2line %s -e /proc/%d/exe", address, getpid()); if(strstr(buff, "??") == NULL) MSG_STDERR("#%2i %s %s", i, strrchr(buff, '/') + 1, bt_syms[i]); else MSG_STDERR("#%2i %s", i, bt_syms[i]); free(buff); } MSG_STDERR("======================== End Backtrace =======================\n"); MSG_STDERR(_("You can paste this backtrace by opening a new issue here:")); MSG_STDERR("https://github.com/X0rg/CPU-X/issues/new\n"); /* Stop program */ free(bt_syms); signal(signum, SIG_DFL); kill(getpid(), signum); } /* Enable internationalization support */ static int set_locales(void) { int err; char *TEXTDOMAINDIR = getenv("TEXTDOMAINDIR"); if(TEXTDOMAINDIR == NULL || TEXTDOMAINDIR[0] == '\0') TEXTDOMAINDIR = LOCALEDIR; #if PORTABLE_BINARY && HAS_GETTEXT int i; FILE *mofile = NULL; if(!access(LOCALEDIR, R_OK)) goto end_extraction; /* Write .mo files in temporary directory */ err = mkdir(LOCALEDIR, ACCESSPERMS); for(i = 0; ptrlen[i] != NULL; i++) { err += mkdir(format("%s/%s/", LOCALEDIR, lang[i]), ACCESSPERMS); err += mkdir(format("%s/%s/LC_MESSAGES/", LOCALEDIR, lang[i]), ACCESSPERMS); mofile = fopen(format("%s/%s/LC_MESSAGES/%s.mo", LOCALEDIR, lang[i], GETTEXT_PACKAGE), "w"); if(mofile != NULL) { err += fwrite(ptrlang[i], sizeof(unsigned char), *(ptrlen)[i], mofile) > 0 ? 0 : 1; err += fclose(mofile); } else err++; } /* Override TEXTDOMAINDIR in portable binary */ TEXTDOMAINDIR = LOCALEDIR; if(err) MSG_ERROR("an error occurred while extracting translations"); end_extraction: #endif /* PORTABLE_BINARY && HAS_GETTEXT */ /* Apply locale */ setlocale(LC_ALL, ""); err = bindtextdomain(GETTEXT_PACKAGE, TEXTDOMAINDIR) ? 0 : 1; err += bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8") ? 0 : 1; err += textdomain(GETTEXT_PACKAGE) ? 0 : 1; /* Check if something is wrong */ if(err) { MSG_ERROR(_("an error occurred while setting locale")); return 1; } else return 0; } int main(int argc, char *argv[]) { /* Init variables */ binary_name = argv[0]; Labels *data = &(Labels) { .tab_cpu = { { NULL } }, .tab_caches = { { NULL } }, .tab_motherboard = { { NULL } }, .tab_memory = { { NULL } }, .tab_system = { { NULL } }, .tab_graphics = { { NULL } }, .tab_bench = { { NULL } }, .cpu_freq = 0, .cpu_count = 0, .cache_count = 0, .dimm_count = 0, .gpu_count = 0, .bus_freq = 0.0, .cpu_min_mult = 0.0, .cpu_max_mult = 0.0 }; data->l_data = &(LibcpuidData) { .cpu_vendor_id = -1, .cpu_model = -1, .cpu_ext_model = -1, .cpu_ext_family = -1, .cpuid_raw_file = NULL }; data->w_data = &(BandwidthData) { .test_count = 0, .size = { 0 }, .speed = { 0 }, .test_name = NULL }; data->m_data = &(MemoryData) { .mem_usage = { 0 }, .mem_total = 0, .swap_total = 0 }; data->g_data = &(GraphicsData) { .gpu_driver = { GPUDRV_UNKNOWN }, .device_path = { NULL }, }; data->b_data = &(BenchData) { .run = false, .duration = 1, .threads = 1, .primes = 0, .start = 0, .elapsed = 0, .num = 0 }; opts = &(Options) { .color = true, .verbose = false, .issue = false, .use_network = true, .update = false, .debug_database = false, .freq_fallback = false, .selected_page = 0, .selected_core = 0, .bw_test = 0, .refr_time = 1 }; set_locales(); signal(SIGSEGV, sighandler); signal(SIGFPE, sighandler); signal(SIGABRT, sighandler); /* Parse options */ parse_arguments(argc, argv); check_environment_variables(data); if(opts->output_type > OUT_NO_CPUX) goto skip_init; /* Retrieve data */ if(getuid()) { MSG_WARNING(_("Root privileges are required to work properly")); MSG_WARNING(_("Some informations will not be retrievable")); } labels_setname(data); fill_labels (data); if(HAS_WEB_SUPPORT) check_new_version(); /* Show data */ if(HAS_GTK && (opts->output_type == OUT_GTK)) start_gui_gtk(&argc, &argv, data); if(HAS_NCURSES && (opts->output_type == OUT_NCURSES)) start_tui_ncurses(data); if(opts->output_type == OUT_DUMP) dump_data(data); skip_init: if(HAS_DMIDECODE && (opts->output_type == OUT_DMIDECODE)) return run_dmidecode(); if(HAS_BANDWIDTH && (opts->output_type == OUT_BANDWIDTH)) return run_bandwidth(); #if 0 //PORTABLE_BINARY /* Only 64-bit portable binary can be updated since v3.2.1 */ if(PORTABLE_BINARY && HAS_WEB_SUPPORT && opts->update) { # ifdef __x86_64__ update_prg(); # else MSG_ERROR(_("Sorry, you cannot update %s: 32-bit portable version is no more supported."), PRGNAME); # endif } #endif /* PORTABLE_BINARY */ return EXIT_SUCCESS; } CPU-X-3.2.4/src/tui_ncurses.c000066400000000000000000000641241341671471500156720ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE tui_ncurses.c */ #include #include #include #include #include #include "cpu-x.h" #include "tui_ncurses.h" static void (*func_ptr[])(WINDOW*, const SizeInfo, Labels*) = { ntab_cpu, ntab_caches, ntab_motherboard, ntab_memory, ntab_system, ntab_graphics, ntab_bench, ntab_about }; static const Colors color[] = { { 0, 0, 0, 0 }, { DEFAULT_COLOR, COLOR_BLACK, COLOR_WHITE, A_NORMAL }, { TITLE_COLOR, COLOR_BLUE, COLOR_WHITE, A_BOLD }, { ACTIVE_TAB_COLOR, COLOR_WHITE, COLOR_BLUE, A_BOLD }, { INACTIVE_TAB_COLOR, COLOR_WHITE, COLOR_BLUE, A_NORMAL }, { LABEL_NAME_COLOR, COLOR_BLACK, COLOR_WHITE, A_NORMAL }, { LABEL_VALUE_COLOR, COLOR_BLUE, COLOR_WHITE, A_NORMAL }, { YELLOW_BAR_COLOR, COLOR_YELLOW, COLOR_YELLOW, A_NORMAL }, { BLUE_BAR_COLOR, COLOR_BLUE, COLOR_BLUE, A_NORMAL }, { MAGENTA_BAR_COLOR, COLOR_MAGENTA, COLOR_MAGENTA, A_NORMAL }, { GREEN_BAR_COLOR, COLOR_GREEN, COLOR_GREEN, A_NORMAL }, { RED_BAR_COLOR, COLOR_RED, COLOR_RED, A_NORMAL } }; /************************* Public function *************************/ /* Start CPU-X in NCurses mode */ void start_tui_ncurses(Labels *data) { int startx, starty, ch = 0; const SizeInfo info = { .height = LINE_COUNT, .width = 70, .start = 1, .tb = 2, .tm = 26, .te = 48 }; NThrd refr = { .data = data, .info = info }; WINDOW *win; MSG_VERBOSE(_("Starting NCurses TUI...")); if(!getenv("TERMINFO")) setenv("TERMINFO", TERMINFODIR, 0); freopen("/dev/null", "a", stderr); initscr(); cbreak(); noecho(); curs_set(0); halfdelay(0); nodelay(stdscr, TRUE); keypad(stdscr, TRUE); if(opts->color) { start_color(); opts->color = has_colors(); } if(opts->color) { enum EnColors pair; for(pair = DEFAULT_COLOR; pair < LAST_COLOR; pair++) init_pair(pair, color[pair].foreground, color[pair].background); } #ifdef __x86_64__ if(PORTABLE_BINARY && (new_version[0] != NULL) && !opts->update) { print_new_version(); erase(); } #endif /* __x86_64__ */ starty = (LINES - info.height) / 2; /* Calculating for a center placement of the window */ startx = (COLS - info.width) / 2; win = newwin(info.height, info.width, starty, startx); refr.win = win; refresh(); main_win(win, info, data); (*func_ptr[opts->selected_page])(win, info, data); timeout(opts->refr_time * 1000); printw(_("Press 'h' to see help.\n")); while(ch != 'q') { ch = getch(); switch(ch) { case KEY_LEFT: /* Switch to left tab */ if(opts->selected_page > NO_CPU) { opts->selected_page--; main_win(win, info, data); (*func_ptr[opts->selected_page])(win, info, data); } break; case KEY_RIGHT: /* Switch to right tab */ if(opts->selected_page < NO_ABOUT) { opts->selected_page++; main_win(win, info, data); (*func_ptr[opts->selected_page])(win, info, data); } break; case KEY_DOWN: if(opts->selected_page == NO_CPU && opts->selected_core > 0) { opts->selected_core--; print_activecore(win); } else if(opts->selected_page == NO_CACHES && opts->bw_test > 0) { opts->bw_test--; print_activetest(win, info, data); } else if(opts->selected_page == NO_BENCH && data->b_data->duration > 1) { data->b_data->duration--; print_paramduration(win, info, data); } break; case KEY_NPAGE: if(opts->selected_page == NO_BENCH && data->b_data->threads > 1 && !data->b_data->run) { data->b_data->threads--; print_paramthreads(win, info, data); } break; case KEY_UP: if(opts->selected_page == NO_CPU && (int) opts->selected_core < data->cpu_count - 1) { opts->selected_core++; print_activecore(win); } else if(opts->selected_page == NO_CACHES && (int) opts->bw_test < data->w_data->test_count - 1) { opts->bw_test++; print_activetest(win, info, data); } else if(opts->selected_page == NO_BENCH && data->b_data->duration < 60 * 24) { data->b_data->duration++; print_paramduration(win, info, data); } break; case KEY_PPAGE: if(opts->selected_page == NO_BENCH && data->b_data->threads < data->cpu_count && !data->b_data->run) { data->b_data->threads++; print_paramthreads(win, info, data); } break; case 'f': if(opts->selected_page == NO_BENCH && !data->b_data->run) { data->b_data->fast_mode = true; start_benchmarks(data); } else if(opts->selected_page == NO_BENCH && data->b_data->run) data->b_data->run = false; break; case 's': if(opts->selected_page == NO_BENCH && !data->b_data->run) { data->b_data->fast_mode = false; start_benchmarks(data); } else if(opts->selected_page == NO_BENCH && data->b_data->run) data->b_data->run = false; break; case 'h': erase(); print_help(); erase(); refresh(); main_win(win, info, data); (*func_ptr[opts->selected_page])(win, info, data); break; case ERR: /* Refresh dynamic labels */ if(opts->selected_page == NO_CPU || opts->selected_page == NO_CACHES || opts->selected_page == NO_SYSTEM || opts->selected_page == NO_GRAPHICS || opts->selected_page == NO_BENCH) nrefresh(&refr); break; case KEY_RESIZE: /* Resize window */ erase(); starty = (LINES - info.height) / 2; startx = (COLS - info.width) / 2; mvwin(win, starty, startx); refresh(); main_win(win, info, data); (*func_ptr[opts->selected_page])(win, info, data); break; default: break; } } endwin(); labels_free(data); } /************************* Private functions *************************/ /* Clean window */ static void wclrscr(WINDOW *pwin) { int y, x, maxy, maxx; getmaxyx(pwin, maxy, maxx); for(y = 0; y < maxy; y++) { for(x = 0; x < maxx; x++) mvwaddch(pwin, y, x, ' '); } } /* Clean line */ static void wclrline(WINDOW *pwin, enum EnLines line, unsigned start, unsigned end) { unsigned x; for(x = start; x < end; x++) mvwprintwc(pwin, line, x, DEFAULT_COLOR, " "); } /* Similar to mvwprintw, but specify a color pair */ static int mvwprintwc(WINDOW *win, int y, int x, enum EnColors pair, const char *fmt, ...) { int ret; va_list args; va_start(args, fmt); wmove(win, y, x); if(opts->color) wattron(win, COLOR_PAIR(pair) | color[pair].attrs); ret = vwprintw(win, fmt, args); if(opts->color) wattroff(win, COLOR_PAIR(pair) | color[pair].attrs); va_end(args); return ret; } /* Similar to mvwprintw, but print first string in black and second string in blue */ static int mvwprintw2c(WINDOW *win, int y, int x, const char *fmt, ...) { int ret = 0; char *s1, *s2, *f1, *f2, *ptr = strdup(fmt); enum EnColors pair; va_list args; /* Retrive args */ va_start(args, fmt); f2 = strstr(fmt, ": ") + 1; f1 = strcat(strtok(ptr, ": "), ":"); s1 = va_arg(args, char *); s2 = va_arg(args, char *); /* Print label name */ wmove(win, y, x); pair = LABEL_NAME_COLOR; if(opts->color) wattron(win, COLOR_PAIR(pair) | color[pair].attrs); ret += wprintw(win, f1, s1); free(f1); if(opts->color) wattroff(win, COLOR_PAIR(pair) | color[pair].attrs); /* Print label value */ pair = LABEL_VALUE_COLOR; if(opts->color) wattron(win, COLOR_PAIR(pair) | color[pair].attrs); ret += wprintw(win, f2, s2); if(opts->color) wattroff(win, COLOR_PAIR(pair) | color[pair].attrs); va_end(args); return ret; } /* Refresh dynamic values */ static void nrefresh(NThrd *refr) { int i, line = 0; WINDOW *(win) = refr->win; Labels *(data) = refr->data; SizeInfo info = refr->info; do_refresh(data); switch(opts->selected_page) { case NO_CPU: mvwprintw2c(win, LINE_4, info.tm, "%11s: %s", data->tab_cpu[NAME][VOLTAGE], data->tab_cpu[VALUE][VOLTAGE]); mvwprintw2c(win, LINE_6, info.te, "%9s: %s", data->tab_cpu[NAME][TEMPERATURE], data->tab_cpu[VALUE][TEMPERATURE]); mvwprintw2c(win, LINE_12, info.tb, "%14s: %s", data->tab_cpu[NAME][CORESPEED], data->tab_cpu[VALUE][CORESPEED]); mvwprintw2c(win, LINE_13, info.tb, "%14s: %s", data->tab_cpu[NAME][MULTIPLIER], data->tab_cpu[VALUE][MULTIPLIER]); mvwprintw2c(win, LINE_15, info.tb, "%14s: %s", data->tab_cpu[NAME][USAGE], data->tab_cpu[VALUE][USAGE]); break; case NO_CACHES: line = LINE_2; for(i = L1SPEED; i < data->cache_count * CACHEFIELDS; i += CACHEFIELDS) { mvwprintw2c(win, line, info.tb, "%13s: %s", data->tab_caches[NAME][i], data->tab_caches[VALUE][i]); line += CACHEFIELDS + 2; } break; case NO_SYSTEM: mvwprintw2c(win, LINE_4, info.tb, "%13s: %s", data->tab_system[NAME][UPTIME], data->tab_system[VALUE][UPTIME]); for(i = USED; i < LASTSYSTEM; i++) { mvwprintw2c(win, LINE_8 + line++, info.tb, "%13s: %s", data->tab_system[NAME][i], data->tab_system[VALUE][i]); draw_bar(win, info, data, i); } break; case NO_GRAPHICS: line = LINE_3; for(i = 0; i < data->gpu_count * GPUFIELDS; i += GPUFIELDS) { mvwprintw2c(win, line, info.tb, "%13s: %s", data->tab_graphics[NAME][GPU1TEMPERATURE + i], data->tab_graphics[VALUE][GPU1TEMPERATURE + i]); mvwprintw2c(win, line, info.tm, "%18s: %s", data->tab_graphics[NAME][GPU1USAGE + i], data->tab_graphics[VALUE][GPU1USAGE + i]); line++; mvwprintw2c(win, line, info.tb, "%13s: %s", data->tab_graphics[NAME][GPU1CORECLOCK + i], data->tab_graphics[VALUE][GPU1CORECLOCK + i]); mvwprintw2c(win, line, info.tm, "%18s: %s", data->tab_graphics[NAME][GPU1MEMCLOCK + i], data->tab_graphics[VALUE][GPU1MEMCLOCK + i]); line += GPUFIELDS - 1; } break; case NO_BENCH: for(i = LINE_1; i < LINE_3; i++) wclrline(win, i, info.tb, info.te); mvwprintw2c(win, LINE_1, info.tb, "%13s: %s", data->tab_bench[NAME][PRIMESLOWSCORE], data->tab_bench[VALUE][PRIMESLOWSCORE]); mvwprintw2c(win, LINE_2, info.tb, "%13s: %s", data->tab_bench[NAME][PRIMESLOWRUN], data->tab_bench[VALUE][PRIMESLOWRUN]); for(i = LINE_5; i < LINE_7; i++) wclrline(win, i, info.tb, info.te); mvwprintw2c(win, LINE_5, info.tb, "%13s: %s", data->tab_bench[NAME][PRIMEFASTSCORE], data->tab_bench[VALUE][PRIMEFASTSCORE]); mvwprintw2c(win, LINE_6, info.tb, "%13s: %s", data->tab_bench[NAME][PRIMEFASTRUN], data->tab_bench[VALUE][PRIMEFASTRUN]); break; default: break; } wrefresh(win); } /* Print how to use this TUI */ static void print_help() { nodelay(stdscr, FALSE); timeout(99999); printw(_("Welcome in %s NCurses help!\n"), PRGNAME); printw(_("This help describes how to use this Text-based User Interface.\n")); printw(_("\nGlobal keys:\n")); printw(_("\tPress 'left' key to switch in left tab.\n")); printw(_("\tPress 'right' key to switch in right tab.\n")); printw(_("\tPress 'h' key to see this help.\n")); printw(_("\tPress 'q' key to exit.\n")); printw(_("\nCPU tab:\n")); printw(_("\tPress 'down' key to decrease core number to monitor.\n")); printw(_("\tPress 'up' key to increase core number to monitor.\n")); printw(_("\nCaches tab:\n")); printw(_("\tPress 'down' key to switch to previous test.\n")); printw(_("\tPress 'up' key' to switch to next test.\n")); printw(_("\nBench tab:\n")); printw(_("\tPress 'down' key to decrement benchmark duration.\n")); printw(_("\tPress 'up' key to increment benchmark duration.\n")); printw(_("\tPress 'next page' key to decrement number of threads to use.\n")); printw(_("\tPress 'previous page' key to increment number of threads to use.\n")); printw(_("\tPress 's' key to start/stop prime numbers (slow) benchmark.\n")); printw(_("\tPress 'f' key to start/stop prime numbers (fast) benchmark.\n")); printw(_("\nPress any key to exit this help.\n")); refresh(); getch(); nodelay(stdscr, TRUE); timeout(opts->refr_time * 1000); } /* Ask for update when a new version is available (portable version only) */ static void print_new_version() { nodelay(stdscr, FALSE); printw(_("A new version of %s is available!"), PRGNAME); printw("\n\n"); #if 0 printw(_("Do you want to update %s to version %s after exit?\n" "It will erase this binary file (%s) by the new version."), PRGNAME, new_version[0], binary_name); printw("\n"); printw(_("If you want to update, press 'u' key, or anything else to skip.\n"), PRGNAME); refresh(); if(getch() == 'u') { opts->update = true; printw(_("\n\n%s will be updated."), PRGNAME); refresh(); napms(1000); } #else printw(_("Version %s is available. Unfortunately, this portable format is now deprecated in favor of AppImage.\n" "You can download %s AppImage on the official download page.\n"), new_version[0], PRGNAME); printw("\n"); printw(_("Download page: %s\n"), DOWNLOAD); refresh(); getch(); #endif nodelay(stdscr, TRUE); } /* The main window (title, tabs, footer) */ static void main_win(WINDOW *win, const SizeInfo info, Labels *data) { int i, cpt = 2; if(opts->color) { init_pair(DEFAULT_COLOR, COLOR_BLACK, COLOR_WHITE); wattrset(win, COLOR_PAIR(DEFAULT_COLOR)); } wclrscr(win); box(win, 0 , 0); mvwprintwc(win, TITLE_LINE, info.width / 2 - strlen(PRGNAME) / 2, TITLE_COLOR, PRGNAME); mvwprintwc(win, HEADER_LINE, 2, DEFAULT_COLOR, PRGNAME); mvwprintwc(win, HEADER_LINE, info.width / 2, DEFAULT_COLOR, data->tab_about[VERSIONSTR]); for(i = 1; i < info.width - 1; i++) mvwprintwc(win, TABS_LINE, i, INACTIVE_TAB_COLOR, " "); for(i = NO_CPU; i <= NO_ABOUT; i++) { if(i == (int) opts->selected_page && opts->color) mvwprintwc(win, TABS_LINE, cpt, ACTIVE_TAB_COLOR, data->objects[i]); else if(i == (int) opts->selected_page && !opts->color) mvwprintw(win, TABS_LINE, cpt++, "[%s]", data->objects[i]); else mvwprintwc(win, TABS_LINE, cpt, INACTIVE_TAB_COLOR, data->objects[i]); cpt += strlen(data->objects[i]) + 2; } wrefresh(win); } /* Display active Core in CPU tab */ static void print_activecore(WINDOW *win) { char buff[16]; sprintf(buff, _("Core #%i"), opts->selected_core); mvwprintwc(win, LINE_17, 4, DEFAULT_COLOR, buff); } /* CPU tab */ static void ntab_cpu(WINDOW *win, const SizeInfo info, Labels *data) { int i, line; const int length = info.width - (info.tb + 18); const int middle = info.width - 38; int index = length - 1; /* Split Intructions label in two parts */ for(i = 0; i < length; i++) if(data->tab_cpu[VALUE][INSTRUCTIONS][i] == ',') index = i; data->tab_cpu[VALUE][INSTRUCTIONS][index + 1] = '\0'; /* Processor frame */ frame(win, LINE_0, info.start , LINE_10, info.width - 1, data->objects[FRAMPROCESSOR]); line = LINE_1; for(i = VENDOR; i < CORESPEED; i++) { switch(i) { case VOLTAGE: mvwprintw2c(win, LINE_4, info.tm, "%11s: %s", data->tab_cpu[NAME][VOLTAGE], data->tab_cpu[VALUE][VOLTAGE]); break; case MODEL: mvwprintw2c(win, LINE_6, info.tm, "%11s: %s", data->tab_cpu[NAME][MODEL], data->tab_cpu[VALUE][MODEL]); break; case EXTMODEL: mvwprintw2c(win, LINE_7, info.tm, "%11s: %s", data->tab_cpu[NAME][EXTMODEL], data->tab_cpu[VALUE][EXTMODEL]); break; case TEMPERATURE: mvwprintw2c(win, LINE_6, info.te, "%9s: %s", data->tab_cpu[NAME][TEMPERATURE], data->tab_cpu[VALUE][TEMPERATURE]); break; case STEPPING: mvwprintw2c(win, LINE_7, info.te, "%9s: %s", data->tab_cpu[NAME][STEPPING], data->tab_cpu[VALUE][STEPPING]); break; case INSTRUCTIONS: mvwprintw2c(win, line++, info.tb, "%14s: %s", data->tab_cpu[NAME][INSTRUCTIONS], data->tab_cpu[VALUE][INSTRUCTIONS]); mvwprintwc (win, line++, info.tb + 16, LABEL_VALUE_COLOR, &(data->tab_cpu[VALUE][INSTRUCTIONS][index + 2])); break; default: mvwprintw2c(win, line++, info.tb, "%14s: %s", data->tab_cpu[NAME][i], data->tab_cpu[VALUE][i]); } } /* Clocks frame */ frame(win, LINE_11, info.start, LINE_16, middle, data->objects[FRAMCLOCKS]); line = LINE_12; for(i = CORESPEED; i < LEVEL1D; i++) mvwprintw2c(win, line++, info.tb, "%14s: %s", data->tab_cpu[NAME][i], data->tab_cpu[VALUE][i]); /* Cache frame */ frame(win, LINE_11, middle, LINE_16, info.width - 1, data->objects[FRAMCACHE]); line = LINE_12; for(i = LEVEL1D; i < SOCKETS; i++) mvwprintw2c(win, line++, middle + 1, "%12s: %s", data->tab_cpu[NAME][i], data->tab_cpu[VALUE][i]); /* Last frame */ frame(win, LINE_17, info.start, LINE_19, info.width - 1, ""); print_activecore(win); mvwprintw2c(win, LINE_18, 18, "%s: %2s", data->tab_cpu[NAME][SOCKETS], data->tab_cpu[VALUE][SOCKETS]); mvwprintw2c(win, LINE_18, 36, "%s: %2s", data->tab_cpu[NAME][CORES], data->tab_cpu[VALUE][CORES]); mvwprintw2c(win, LINE_18, 54, "%s: %2s", data->tab_cpu[NAME][THREADS], data->tab_cpu[VALUE][THREADS]); wrefresh(win); } /* Display active Test in Caches tab */ static void print_activetest(WINDOW *win, const SizeInfo info, Labels *data) { const int line = LINE_1 + (CACHEFIELDS + 2) * data->cache_count; if(!data->cache_count) return; if(HAS_BANDWIDTH) { wclrline(win, line, info.tb, info.width - 2); mvwprintwc(win, line, 12, DEFAULT_COLOR, "%s", data->w_data->test_name[opts->bw_test]); } wrefresh(win); } /* Caches tab */ static void ntab_caches(WINDOW *win, const SizeInfo info, Labels *data) { int i, line = LINE_1, start = LINE_0, end = LINE_3; if(!data->cache_count) return; /* Cache frames */ for(i = L1SIZE; i < data->cache_count * CACHEFIELDS; i++) { if(i % CACHEFIELDS == 0) { frame(win, start, info.start, end, info.width - 1, data->objects[FRAML1CACHE + i / CACHEFIELDS]); start = end + 1; end += 4; if(i > 0) line += 2; } mvwprintw2c(win, line++, 2, "%13s: %s", data->tab_caches[NAME][i], data->tab_caches[VALUE][i]); } /* Test frame */ line++; frame(win, line, info.start , line + 2, info.width - 1, data->objects[FRAMTEST]); print_activetest(win, info, data); wrefresh(win); } /* Motherboard tab */ static void ntab_motherboard(WINDOW *win, const SizeInfo info, Labels *data) { int i, line; /* Motherboard frame */ frame(win, LINE_0, info.start , LINE_4, info.width - 1, data->objects[FRAMMOTHERBOARD]); line = LINE_1; for(i = MANUFACTURER; i < BRAND; i++) mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_motherboard[NAME][i], data->tab_motherboard[VALUE][i]); /* BIOS frame */ frame(win, LINE_5, info.start , LINE_10, info.width - 1, data->objects[FRAMBIOS]); line = LINE_6; for(i = BRAND; i < CHIPVENDOR; i++) mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_motherboard[NAME][i], data->tab_motherboard[VALUE][i]); /* Chipset frame */ frame(win, LINE_11, info.start , LINE_14, info.width - 1, data->objects[FRAMCHIPSET]); line = LINE_12; for(i = CHIPVENDOR; i < LASTMOTHERBOARD; i++) mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_motherboard[NAME][i], data->tab_motherboard[VALUE][i]); wrefresh(win); } /* Memory tab */ static void ntab_memory(WINDOW *win, const SizeInfo info, Labels *data) { int i, line = LINE_0; if(!data->dimm_count) return; /* Banks frame */ for(i = BANK0; i < data->dimm_count; i++) { frame(win, line, info.start, line + 2, info.width - 1, data->objects[FRAMBANK0 + i]); line++; mvwprintw2c(win, line, info.tb, "%13s: %s", data->tab_memory[NAME][i], data->tab_memory[VALUE][i]); line += 2; } wrefresh(win); } /* System tab */ static void ntab_system(WINDOW *win, const SizeInfo info, Labels *data) { int i, line; /* OS frame */ frame(win, LINE_0, info.start , LINE_6, info.width - 1, data->objects[FRAMOPERATINGSYSTEM]); line = LINE_1; for(i = KERNEL; i < USED; i++) mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_system[NAME][i], data->tab_system[VALUE][i]); /* Memory frame */ frame(win, LINE_7, info.start , LINE_13, info.width - 1, data->objects[FRAMMEMORY]); line = LINE_8; for(i = USED; i < LASTSYSTEM; i++) { mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_system[NAME][i], data->tab_system[VALUE][i]); draw_bar(win, info, data, i); } wrefresh(win); } /* Draw an usage bar in System tab */ static void draw_bar(WINDOW *win, const SizeInfo info, Labels *data, int bar) { int i, line, color, bar_count, adjust = 0; static int before = 0; const int val = 39, start = 46, end = info.width - 3, size = end - start; double percent; if((bar == SWAP && data->m_data->swap_total == 0) || (bar != SWAP && data->m_data->mem_total == 0)) return; line = bar - USED + LINE_8; color = YELLOW_BAR_COLOR + bar - USED; before = ((bar == USED) || (bar == SWAP)) ? 0 : before; percent = (double) data->m_data->mem_usage[bar - USED] / ((bar == SWAP) ? data->m_data->swap_total : data->m_data->mem_total); bar_count = (int) roundf(percent * (size - 1)); if(0.0 < percent && bar_count < 1) { bar_count = 1; adjust = 1; } /* Write percentage + delimiters */ mvwprintwc(win, line, val, LABEL_VALUE_COLOR, "%.2f%%", percent * 100); mvwprintwc(win, line, start, DEFAULT_COLOR, "["); mvwprintwc(win, line, end, DEFAULT_COLOR, "]"); /* Clean existing bar */ wclrline(win, line, start + 1, end); /* Draw bar */ for(i = 0; i < bar_count; i++) { if(opts->color) mvwprintwc(win, line, start + 1 + before + i, color, " "); else mvwprintw(win, line, start + 1 + before + i, "|"); } before += bar_count - adjust; } /* Graphics tab */ static void ntab_graphics(WINDOW *win, const SizeInfo info, Labels *data) { int i, line, start = LINE_0, end = LINE_5; if(!data->gpu_count) return; /* Card frames */ line = LINE_1; for(i = GPU1VENDOR; i < data->gpu_count * GPUFIELDS; i++) { if(i % GPUFIELDS == 0) { frame(win, start, info.start, end, info.width - 1, data->objects[FRAMGPU1 + i / GPUFIELDS]); start = end + 1; end += 6; if(i > 0) line += 2; } switch(i) { case GPU1USAGE: case GPU2USAGE: case GPU3USAGE: case GPU4USAGE: case GPU1MEMCLOCK: case GPU2MEMCLOCK: case GPU3MEMCLOCK: case GPU4MEMCLOCK: mvwprintw2c(win, line - 1, info.tm, "%18s: %s", data->tab_graphics[NAME][i], data->tab_graphics[VALUE][i]); break; default: mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_graphics[NAME][i], data->tab_graphics[VALUE][i]); } } wrefresh(win); } /* Display Duration parameter in Bench tab */ static void print_paramduration(WINDOW *win, const SizeInfo info, Labels *data) { wclrline(win, LINE_9, info.tb, info.tm); casprintf(&data->tab_bench[VALUE][PARAMDURATION], true, _("%u mins"), data->b_data->duration); mvwprintw2c(win, LINE_9, info.tb, "%13s: %s", data->tab_bench[NAME][PARAMDURATION], data->tab_bench[VALUE][PARAMDURATION]); wrefresh(win); } /* Display Threads parameter in Bench tab */ static void print_paramthreads(WINDOW *win, const SizeInfo info, Labels *data) { casprintf(&data->tab_bench[VALUE][PARAMTHREADS], true, "%u", data->b_data->threads); mvwprintw2c(win, LINE_9, info.tm, "%13s: %s", data->tab_bench[NAME][PARAMTHREADS], data->tab_bench[VALUE][PARAMTHREADS]); wrefresh(win); } /* Bench tab */ static void ntab_bench(WINDOW *win, const SizeInfo info, Labels *data) { int i, line; /* Prime numbers (slow) frame */ frame(win, LINE_0, info.start , LINE_3, info.width - 1, data->objects[FRAMPRIMESLOW]); line = LINE_1; for(i = PRIMESLOWSCORE; i < PRIMEFASTSCORE; i++) mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_bench[NAME][i], data->tab_bench[VALUE][i]); /* Prime numbers (fast) frame */ frame(win, LINE_4, info.start , LINE_7, info.width - 1, data->objects[FRAMPRIMEFAST]); line = LINE_5; for(i = PRIMEFASTSCORE; i < PARAMDURATION; i++) mvwprintw2c(win, line++, info.tb, "%13s: %s", data->tab_bench[NAME][i], data->tab_bench[VALUE][i]); /* Parameters frame */ frame(win, LINE_8, info.start , LINE_10, info.width - 1, data->objects[FRAMPARAM]); print_paramduration(win, info, data); print_paramthreads (win, info, data); wrefresh(win); } /* About tab */ static void ntab_about(WINDOW *win, const SizeInfo info, Labels *data) { char *part2 = strdup(data->tab_about[DESCRIPTION]); const char *part1 = strsep(&part2, "\n"); /* About CPU-X frame */ frame(win, LINE_0, info.start, LINE_5, info.width - 1, ""); mvwprintwc(win, LINE_2, 4, DEFAULT_COLOR, "%s", part1); mvwprintwc(win, LINE_3, 4, DEFAULT_COLOR, "%s", part2); frame(win, LINE_6, info.start, LINE_10, info.width - 1, data->objects[FRAMABOUT]); mvwprintwc(win, LINE_7, 20, DEFAULT_COLOR, "%s", data->tab_about[VERSIONSTR]); mvwprintwc(win, LINE_8, 20, DEFAULT_COLOR, "%s", data->tab_about[AUTHOR]); mvwprintwc(win, LINE_9, 20, DEFAULT_COLOR, "%s", data->tab_about[SITE]); frame(win, LINE_11, info.start, LINE_16, info.width - 1, data->objects[FRAMLICENSE]); mvwprintwc(win, LINE_12, 20, DEFAULT_COLOR, "%s", data->tab_about[COPYRIGHT]); mvwprintwc(win, LINE_14, 6, DEFAULT_COLOR, "%s", data->tab_about[LICENSE]); mvwprintwc(win, LINE_15, 10, DEFAULT_COLOR, "%s", data->tab_about[NOWARRANTY]); wrefresh(win); } /* Draw a frame */ static void frame(WINDOW *win, int starty, int startx, int endy, int endx, char *label) { if(opts->color) { init_pair(DEFAULT_COLOR, COLOR_BLACK, COLOR_WHITE); wattron(win, COLOR_PAIR(DEFAULT_COLOR)); } /* Horizontal lines */ mvwhline(win, starty, startx, 0, endx - startx); mvwhline(win, endy, startx, 0, endx - startx); /* Vertical lines */ mvwvline(win, starty, startx, 0, endy - starty); mvwvline(win, starty, endx - 1, 0, endy - starty); /* Corners */ mvwhline(win, starty, startx, ACS_ULCORNER, 1); mvwhline(win, endy, startx, ACS_LLCORNER, 1); mvwhline(win, starty, endx - 1, ACS_URCORNER, 1); mvwhline(win, endy, endx - 1, ACS_LRCORNER, 1); /* Title */ mvwprintwc(win, starty, startx + 2, DEFAULT_COLOR, "%s", label); if(opts->color) wattroff(win, COLOR_PAIR(DEFAULT_COLOR)); } CPU-X-3.2.4/src/tui_ncurses.h000066400000000000000000000077261341671471500157040ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE tui_ncurses.h */ #ifndef _TUI_NCURSES_H_ #define _TUI_NCURSES_H_ #include enum EnLines { WINDOW_TOP_LINE, TITLE_LINE, TABS_LINE, LINE_0, LINE_1, LINE_2, LINE_3, LINE_4, LINE_5, LINE_6, LINE_7, LINE_8, LINE_9, LINE_10, LINE_11, LINE_12, LINE_13, LINE_14, LINE_15, LINE_16, LINE_17, LINE_18, LINE_19, HEADER_LINE, WINDOW_BOTTOM_LINE, LINE_COUNT }; enum EnColors { DEFAULT_COLOR = 1, TITLE_COLOR, ACTIVE_TAB_COLOR, INACTIVE_TAB_COLOR, LABEL_NAME_COLOR, LABEL_VALUE_COLOR, YELLOW_BAR_COLOR, BLUE_BAR_COLOR, RED_BAR_COLOR, GREEN_BAR_COLOR, MAGENTA_BAR_COLOR, LAST_COLOR }; typedef struct { const short pair, foreground, background; const int attrs; } Colors; typedef struct { int height, width, start; int tb, tm, te; } SizeInfo; typedef struct { WINDOW *win; Labels *data; SizeInfo info; } NThrd; /********************************** TUI **********************************/ /* Clean window */ static void wclrscr(WINDOW *pwin); /* Clean line */ static void wclrline(WINDOW *pwin, enum EnLines line, unsigned start, unsigned end); /* Similar to mvwprintw, but specify a color pair */ static int mvwprintwc(WINDOW *win, int y, int x, enum EnColors pair, const char *fmt, ...); /* Similar to mvwprintw, but print first string in black and second string in blue */ static int mvwprintw2c(WINDOW *win, int y, int x, const char *fmt, ...); /* Refresh dynamic values */ static void nrefresh(NThrd *refr); /* Print how to use this TUI */ static void print_help(void); /* Ask for update when a new version is available (portable version only) */ static void print_new_version(void); /* The main window (title, tabs, footer) */ static void main_win(WINDOW *win, const SizeInfo info, Labels *data); /* Display active Core in CPU tab */ static void print_activecore(WINDOW *win); /* CPU tab */ static void ntab_cpu(WINDOW *win, const SizeInfo info, Labels *data); /* Display active Test in Caches tab */ static void print_activetest(WINDOW *win, const SizeInfo info, Labels *data); /* Caches tab */ static void ntab_caches(WINDOW *win, const SizeInfo info, Labels *data); /* Motherboard tab */ static void ntab_motherboard(WINDOW *win, const SizeInfo info, Labels *data); /* Memory tab */ static void ntab_memory(WINDOW *win, const SizeInfo info, Labels *data); /* System tab */ static void ntab_system(WINDOW *win, const SizeInfo info, Labels *data); static void draw_bar(WINDOW *win, const SizeInfo info, Labels *data, int bar); /* Graphics tab */ static void ntab_graphics(WINDOW *win, const SizeInfo info, Labels *data); /* Display Duration parameter in Bench tab */ static void print_paramduration(WINDOW *win, const SizeInfo info, Labels *data); /* Display Threads parameter in Bench tab */ static void print_paramthreads(WINDOW *win, const SizeInfo info, Labels *data); /* Bench tab */ static void ntab_bench(WINDOW *win, const SizeInfo info, Labels *data); /* About tab */ static void ntab_about(WINDOW *win, const SizeInfo info, Labels *data); /* Draw a frame */ static void frame(WINDOW *local_win, int starty, int startx, int endy, int endx, char *label); #endif /* _TUI_NCURSES_H_ */ CPU-X-3.2.4/src/util.c000066400000000000000000000250641341671471500143040ustar00rootroot00000000000000/**************************************************************************** * Copyright © 2014-2019 Xorg * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ****************************************************************************/ /* * PROJECT CPU-X * FILE util.c */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "cpu-x.h" /************************* Public function *************************/ /* An asprintf-like function, but which can clean some parts of 'str' if 'clean_str' is true * - It calls vasprintf if 'fmt' is a valid string * - If 'clean_str' is true, it removes "unvalid args" from 'str' until next "valid arg" E.g.: casprintf(&str, false, "%i nm", 0): str = "0 nm" casprintf(&str, true, "%i nm", 0): str = "" casprintf(&str, true, "%i nm", 32): str = "32 nm" casprintf(&str, true, "%i KB %i-way", -1, 12): str = "12-way" */ int casprintf(char **str, bool clean_str, const char *fmt, ...) { bool remove; int i, j, ret; char *tmp = NULL; va_list aptr; if(*str != NULL) { free(*str); *str = NULL; } if(fmt == NULL) return 0; va_start(aptr, fmt); ret = vasprintf(str, fmt, aptr); va_end(aptr); if(!clean_str) return ret; remove = (((*str)[0] == '0') && (atof(*str) == 0.0)) || (atoi(*str) < 0); j = remove ? -1 : 0; for(i = 1; (*str)[i] != '\0'; i++) { if(((((*str)[i] == '0') && (atof(*str + i) == 0.0)) || (atoi(*str + i) < 0)) && (isspace((*str)[i - 1]))) remove = true; if(!remove) (*str)[++j] = (*str)[i]; if((isspace((*str)[i])) && !(isdigit((*str)[i - 1]))) remove = false; } (*str)[++j] = '\0'; if((tmp = realloc(*str, j + 1)) != NULL) *str = tmp; return j; } /* Return a formatted string */ #define BUFFER_COUNT 5 char *format(char *str, ...) { static unsigned count = 0; static char *buff[BUFFER_COUNT] = { NULL }; va_list aptr; count++; const unsigned index = count % BUFFER_COUNT; if(count >= BUFFER_COUNT) free(buff[index]); va_start(aptr, str); vasprintf(&buff[index], str, aptr); va_end(aptr); return buff[index]; } /* Similar to format(), but string can be colorized */ char *colorized_msg(const char *color, const char *str, ...) { static char *buff; va_list aptr; free(buff); va_start(aptr, str); vasprintf(&buff, format("%s%s%s\n", opts->color ? color : DEFAULT, str, DEFAULT), aptr); va_end(aptr); return buff; } /* Check if a command exists */ bool command_exists(char *command) { bool exists = false; char *dir; char *save_path = strdup(getenv("PATH")); char *path = save_path; while(((dir = strsep(&path, ":")) != NULL) && !exists) exists = !access(format("%s/%s", dir, command), X_OK); free(save_path); return exists; } /* Open a file and put its content in a variable ('str' accept printf-like format) */ int fopen_to_str(char **buffer, char *str, ...) { char tmp[MAXSTR], error_str[MAXSTR] = "unknown"; char *file_str = NULL; FILE *file_descr = NULL; va_list aptr; va_start(aptr, str); vasprintf(&file_str, str, aptr); va_end(aptr); if(access(file_str, R_OK)) { free(file_str); return -1; } if((file_descr = fopen(file_str, "r")) == NULL) GOTO_ERROR("fopen"); if(fgets(tmp, MAXSTR, file_descr) == NULL) GOTO_ERROR("fgets"); tmp[strlen(tmp) - 1] = '\0'; asprintf(buffer, tmp); free(file_str); return fclose(file_descr); error: MSG_ERROR(_("an error occurred while opening file '%s' (%s)"), file_str, error_str); free(file_str); return (file_descr == NULL) ? 1 : 2 + fclose(file_descr); } /* Run a command and put output in a variable ('str' accept printf-like format) */ int popen_to_str(char **buffer, char *str, ...) { bool command_ok; char tmp[MAXSTR], error_str[MAXSTR] = "unknown"; char *cmd_str = NULL, *test_command = NULL; FILE *pipe_descr = NULL; va_list aptr; va_start(aptr, str); vasprintf(&cmd_str, str, aptr); va_end(aptr); test_command = strdup(cmd_str); command_ok = command_exists(strtok(test_command, " ")); free(test_command); if(!command_ok) { free(cmd_str); return -1; } if((pipe_descr = popen(cmd_str, "r")) == NULL) GOTO_ERROR("popen"); if(fgets(tmp, MAXSTR, pipe_descr) == NULL) GOTO_ERROR("fgets"); tmp[strlen(tmp) - 1] = '\0'; asprintf(buffer, tmp); free(cmd_str); return pclose(pipe_descr); error: MSG_ERROR(_("an error occurred while running command '%s' (%s)"), cmd_str, error_str); free(cmd_str); return (pipe_descr == NULL) ? 1 : 2 + pclose(pipe_descr); } /* Load a kernel module */ bool load_module(char *module) { #if defined (__linux__) if(!system(format("grep -wq %s /proc/modules 2> /dev/null", module))) return true; else if(getuid()) return false; else return !system(format("modprobe %s 2> /dev/null", module)); #elif defined (__DragonFly__) || defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) if(!system(format("kldstat | grep %s > /dev/null", module))) return true; else if(getuid()) return false; else return !system(format("kldload -n %s 2> /dev/null", module)); #else return false; #endif } /* Search a sensor filename in a given directory corresponding to regex */ static int get_sensor_path(char *dir_path, regex_t *regex_filename, regex_t *regex_label, char **cached_path) { int err = 1; char *label = NULL; DIR *dp = NULL; struct dirent *dir; /* Open given directory */ if((dp = opendir(dir_path)) == NULL) { MSG_ERROR(_("failed to open %s directory"), dir_path); return 1; } while(((dir = readdir(dp)) != NULL) && err) { /* Ignore hidden files and files not mathing pattern */ if((dir->d_name[0] == '.') || regexec(regex_filename, dir->d_name, 0, NULL, 0)) continue; if(regex_label != NULL) { /* Open the label file */ if(fopen_to_str(&label, "%s/%s", dir_path, dir->d_name)) continue; /* Check if label matchs with pattern */ if(regexec(regex_label, label, 0, NULL, 0)) continue; } /* Try to open the corresponding file */ strtok(dir->d_name, "_"); casprintf(cached_path, false, "%s/%s_input", dir_path, dir->d_name); err = access(*cached_path, R_OK); } closedir(dp); free(label); return err; } /* Search a directory path corresponding to regex */ static int get_directory_path(char *dir_path, regex_t *regex_dirname, char **cached_path) { int err = regexec(regex_dirname, dir_path, 0, NULL, 0); if(!err) { casprintf(cached_path, false, "%s", dir_path); err = access(*cached_path, R_OK); } return err; } /* Get a filename located in a directory corresponding to given request */ int request_sensor_path(char *base_dir, char **cached_path, enum RequestSensor which) { int err = 1; char *sensor = NULL; char *path = NULL; DIR *dp = NULL; struct dirent *dir; regex_t regex_filename_temp_in, regex_filename_temp_lab, regex_filename_in_in, regex_dirname_cardN; regex_t regex_label_coreN, regex_label_other; if((dp = opendir(base_dir)) == NULL) { MSG_ERROR(_("failed to open %s directory"), base_dir); return 1; } if(regcomp(®ex_filename_temp_in, "temp1_input", REG_NOSUB) || regcomp(®ex_filename_temp_lab, "temp[[:digit:]]_label", REG_NOSUB) || regcomp(®ex_filename_in_in, "in0_input", REG_NOSUB) || regcomp(®ex_dirname_cardN, "card[[:digit:]]", REG_NOSUB) || regcomp(®ex_label_coreN, format("Core[[:space:]]*%u", opts->selected_core), REG_NOSUB | REG_ICASE) || regcomp(®ex_label_other, "CPU", REG_NOSUB | REG_ICASE)) { MSG_ERROR(_("an error occurred while compiling regex")); return 2; } while(((dir = readdir(dp)) != NULL) && err) { /* Ignore hidden files */ if(dir->d_name[0] == '.') continue; /* Find sensor name */ if((which != RQT_GPU_DRM) && fopen_to_str(&sensor, "%s/%s/name", base_dir, dir->d_name)) continue; /* Browse files in directory */ casprintf(&path, false, "%s/%s", base_dir, dir->d_name); switch(which) { case RQT_CPU_TEMPERATURE: if(strstr(sensor, "coretemp") != NULL) /* 'sensors' output: Package id 0: +37.0°C (high = +80.0°C, crit = +98.0°C) Core 0: +33.0°C (high = +80.0°C, crit = +98.0°C) Core 1: +34.0°C (high = +80.0°C, crit = +98.0°C) Core 2: +36.0°C (high = +80.0°C, crit = +98.0°C) Core 3: +37.0°C (high = +80.0°C, crit = +98.0°C) */ err = get_sensor_path(path, ®ex_filename_temp_lab, ®ex_label_coreN, cached_path); else if(strstr(sensor, "k8temp") != NULL) /* 'sensors' output: Core0 Temp: +64.0°C Core0 Temp: +63.0°C Core1 Temp: +64.0°C Core1 Temp: +64.0°C */ err = get_sensor_path(path, ®ex_filename_temp_lab, ®ex_label_coreN, cached_path); else if(strstr(sensor, "k10temp") != NULL) /* 'sensors' output: temp1: +29.5°C (high = +70.0°C, crit = +90.0°C, hyst = +87.0°C) */ err = get_sensor_path(path, ®ex_filename_temp_in, NULL, cached_path); break; case RQT_CPU_TEMPERATURE_OTHERS: err = get_sensor_path(path, ®ex_filename_temp_lab, ®ex_label_other, cached_path); break; case RQT_CPU_VOLTAGE: /* 'sensors' output: Vcore: +0.88 V (min = +0.80 V, max = +1.38 V) */ err = get_sensor_path(path, ®ex_filename_in_in, NULL, cached_path); break; case RQT_GPU_TEMPERATURE: err = get_sensor_path(path, ®ex_filename_temp_in, NULL, cached_path); break; case RQT_GPU_DRM: err = get_directory_path(path, ®ex_dirname_cardN, cached_path); break; } } closedir(dp); free(sensor); free(path); regfree(®ex_filename_temp_in); regfree(®ex_filename_temp_lab); regfree(®ex_filename_in_in); regfree(®ex_dirname_cardN); regfree(®ex_label_coreN); regfree(®ex_label_other); return err; }